Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Routes project refactor #80

Open
wants to merge 20 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ Run the server:

Your `.env` file should now look something like [example.env](https://github.com/ProgrammingBuddies/programmingbuddies-api/blob/develop/example.env)

- Optionally you can set the JWT token timeout
- `JWT_ACCESS_TOKEN_EXPIRES` - time in seconds

### Testing

- to run multiple tests just specify the directory which contains them for example `pipenv run pytest tests/`
Expand Down
77 changes: 49 additions & 28 deletions src/api/controllers/projectController.py
Original file line number Diff line number Diff line change
@@ -1,60 +1,80 @@
from api.models import db, Project, UserHasProject, ProjectLink, ProjectFeedback
from api.models import db, User, Project, UserHasProject, ProjectLink, ProjectFeedback

class ProjectController:
session = db.session()
# TODO: remove this (also from userController)?
session = db.session

# Project
def create_project(self, **kwargs):
def create_project(self, user_id, **kwargs):
try:
user = User.query.filter_by(id=user_id).first()

if user == None:
return None, "User not found", 404

project = Project(**kwargs)
self.session.add(project)

userHasProject = UserHasProject(role=1)
userHasProject.project = project
userHasProject.user = user
Comment on lines +17 to +19
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

userHasProject table is not filled automatically?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I followed the example in the documentation: https://docs.sqlalchemy.org/en/13/orm/basic_relationships.html#association-object

Didn't find any other way to create the relationship.


self.session.add(userHasProject)
self.session.commit()

return project
return project, "OK", 201
except:
return None
self.session.rollback()
return None, "Project creation failed", 400

def update_project(self, id, **kwargs):
project = Project.query.filter_by(id=id).first()
def update_project(self, user_id, **kwargs):
if 'user_id' in kwargs:
return None, "Failed to update project. Request body can not specify user's id.", 400

if project == None:
return None
if 'id' not in kwargs:
return None, "Failed to update project. Request body must specify project's id.", 400

for key, value in kwargs.items():
if not hasattr(project, key):
return None
user = User.query.filter_by(id=user_id).first()

for key, value in kwargs.items():
setattr(project, key, value)

db.session.commit()

return project
if user == None:
return None, "User not found", 404

def update_project(self, id, **kwargs):
project = Project.query.filter_by(id=id).first()
project = Project.query.filter_by(id=kwargs["id"]).first()

if project == None:
return project
return None, "Project not found", 404

# Note that we are updating the id too, but to the same id because we used it to query the user with it
for key, value in kwargs.items():
if not hasattr(project, key):
return None, f"Forbidden attribute '{key}'", 400

for key, value in kwargs.items():
setattr(project, key, value)

db.session.commit()

return project
return project, "OK", 200

def get_project(self, **kwargs):
project = Project.query.filter_by(**kwargs).first()

return project
if project:
return project, "OK", 200
else:
return None, "Project not found", 404

def get_all_projects(self, **kwargs):
all_projects = Project.query.all()

return all_projects
return all_projects, "OK", 200

def delete_project(self, user_id, id):

userHasProject = UserHasProject.query.filter_by(user_id=user_id, project_id=id).first()
# TODO: verify that the user owns the project (or has neccessary rights)
if not userHasProject:
return None, "Failed to delete project. Current user does not belong to specified project, or the project does not exist.", 404

def delete_project(self, id):
# Remove all project's links
for link in ProjectLink.query.filter_by(project_id=id).all():
db.session.delete(link)
Expand All @@ -66,12 +86,13 @@ def delete_project(self, id):
project = Project.query.filter_by(id=id).first()

if project == None:
return project
# TODO: db.session.rollback?
return None, "Project not found", 404

db.session.delete(project)
db.session.commit()

return project
return project, "OK", 200

# Project Link
def create_link(self, project_id, **kwargs):
Expand Down
16 changes: 8 additions & 8 deletions src/api/controllers/userController.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from flask import jsonify

class UserController:
session = db.session()
session = db.session

# User
def create_user(self, **kwargs):
Expand All @@ -16,17 +16,17 @@ def create_user(self, **kwargs):
return user, "OK", 200
except:
self.session.rollback()
return None, "Forbidden Attributes", 400
return None, "Forbidden attributes", 400

def update_user(self, id, **kwargs):
user = User.query.filter_by(id=id).first()

if user == None:
return None, "user not found", 404
return None, "User not found", 404

for key, value in kwargs.items():
if not hasattr(user, key):
return None, "forbidden attribute", 400
return None, f"Forbidden attribute '{key}'", 400

for key, value in kwargs.items():
setattr(user, key, value)
Expand All @@ -39,7 +39,7 @@ def get_user(self, **kwargs):
user = User.query.filter_by(**kwargs).first()

if user is None:
return None, "User Not Found", 404
return None, "User not found", 404

return user, "OK", 200

Expand All @@ -60,7 +60,7 @@ def delete_user(self, id):
user = User.query.filter_by(id=id).first()

if user == None:
return None, "user not found", 404
return None, "User not found", 404

db.session.delete(user)
db.session.commit()
Expand All @@ -81,7 +81,7 @@ def create_link(self, user_id, **kwargs):
return None, "Forbidden attributes used in request. only name and url allowed.", 400
except:
self.session.rollback()
return None, "link creation failed", 500
return None, "Link creation failed", 500

def update_link(self, user_id, **kwargs):
if not 'id' in kwargs:
Expand All @@ -108,7 +108,7 @@ def get_all_links(self, user_id):
user = User.query.filter_by(id=user_id).first()
if user is None:
return None, "User not found", 404

return user.links, "OK", 200

def delete_link(self, user_id, **kwargs):
Expand Down
81 changes: 33 additions & 48 deletions src/api/views/projectView.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
from flask import request, jsonify
from flask_jwt_extended import get_jwt_identity, jwt_required
from api import app
from api.utils import wrap_response, body_required
from api.controllers import projectController

# Project
@app.route("/projects", methods=['POST'])
@app.route("/project", methods=['POST'])
@jwt_required
@body_required
def create_project():
"""
Create project
Current user creates project
---
tags:
- Project
Expand All @@ -32,16 +37,16 @@ def create_project():
description: Description of the project
languages:
type: string
description: List of programming languages the project uses
description: (Optional) List of programming languages the project uses
development_status:
type: integer
description: Development status of the project
creation_date:
type: string
description: Creation date of the project
description: (Optional) Creation date of the project
release_date:
type: string
description: Release date of the project
description: (Optional) Release date of the project
repository:
type: string
description: Url of the project's repository
Expand All @@ -65,28 +70,22 @@ def create_project():
description: Project created successfully
400:
description: Failed to create project
404:
description: User doesn't exist
"""
project = projectController.create_project(**request.get_json())

if project == None:
return "Failed to create project.", 400
else:
return jsonify(project.as_dict()), 201
return wrap_response(*projectController.create_project(user_id=get_jwt_identity(), **request.get_json()))

@app.route("/projects/<id>", methods=['PUT'])
def update_project(id):
@app.route("/project", methods=['PUT'])
@jwt_required
@body_required
def update_project():
"""
Update project
Updates project with `id` using the data in request body
Updates current user's project with the data in request body
---
tags:
- Project
parameters:
- in: path
name: id
type: integer
required: true
description: Id of project to update
- in: body
name: Project
required: true
Expand All @@ -98,18 +97,15 @@ def update_project(id):
description: Project updated successfully
400:
description: Failed to update project
404:
description: Current user or requested project not found
"""
if 'id' in request.get_json():
return "Failed to update project. Request body can not specify project's id.", 501
if "user_id" in request.get_json():
return wrap_response(None, "Failed to update project. Request body must not contain 'user_id'.", 400)

project = projectController.update_project(id, **request.get_json())

if project == None:
return "Failed to update project.", 400
else:
return jsonify(project.as_dict()), 200
return wrap_response(*projectController.update_project(user_id=get_jwt_identity(), **request.get_json()))

@app.route("/projects/<id>", methods=['GET'])
@app.route("/project/<id>", methods=['GET'])
def get_project(id):
"""
Get project
Expand All @@ -129,14 +125,9 @@ def get_project(id):
404:
description: Project not found
"""
project = projectController.get_project(id=id)
return wrap_response(*projectController.get_project(id=id))

if project:
return jsonify(project.as_dict()), 200
else:
return "", 404

@app.route("/projects", methods=['GET'])
@app.route("/project/all", methods=['GET'])
def get_all_projects():
"""
Get all projects
Expand All @@ -148,17 +139,14 @@ def get_all_projects():
200:
description: List of projects
"""
all_projects = projectController.get_all_projects()

projects = [ project.as_dict() for project in all_projects ]

return jsonify(projects), 200
return wrap_response(*projectController.get_all_projects())

@app.route("/projects/<id>", methods=['DELETE'])
@app.route("/project/<id>", methods=['DELETE'])
@jwt_required
def delete_project(id):
"""
Delete project
Deletes project with `id`
Deletes current user's project with the `id`
---
tags:
- Project
Expand All @@ -172,14 +160,11 @@ def delete_project(id):
200:
description: Project deleted successfully
400:
description: Project not found
description: Failed to delete project
404:
description: Current user is not a member of requested project or the project was not found
"""
project = projectController.delete_project(id)

if project:
return "", 202
else:
return "", 404
return wrap_response(*projectController.delete_project(user_id=get_jwt_identity(), id=id))

# Project Link
@app.route("/projects/<project_id>/links", methods=['POST'])
Expand Down
4 changes: 2 additions & 2 deletions src/api/views/userView.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def delete_user():
404:
description: User the token belonged to doesn't exist anymore
"""

return wrap_response(*userController.delete_user(get_jwt_identity()))

# User Link
Expand Down Expand Up @@ -152,7 +152,7 @@ def update_user_link():
description: (optional) Name of the user link
url:
type: string
description: (optional)Url of the user link
description: (optional) Url of the user link
responses:
200:
description: User link updated successfully
Expand Down
2 changes: 1 addition & 1 deletion tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@

from api import app
from api.models import db
from api.models import User, Project, UserFeedback, ProjectFeedback, UserLink, ProjectLink
from api.models import User, Project, UserHasProject, UserFeedback, ProjectFeedback, UserLink, ProjectLink

sys.path.insert(0, os.getcwd()+'/tests')
Loading