From b95e0fc459d2423c9ac07a35d52ad5659bb7c745 Mon Sep 17 00:00:00 2001 From: petak5 Date: Mon, 29 Jun 2020 19:52:38 +0200 Subject: [PATCH 01/36] Optionally can get JWT timeout time from environment file --- src/api/views/oauthView.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/api/views/oauthView.py b/src/api/views/oauthView.py index d6c89c5..77d720e 100644 --- a/src/api/views/oauthView.py +++ b/src/api/views/oauthView.py @@ -16,6 +16,9 @@ app.register_blueprint(github_blueprint, url_prefix="/login") app.config['JWT_SECRET_KEY'] = environ.get("JWT_SECRET_KEY") +# JWT token expiration time in seconds - default is 15 minutes +if environ.get("JWT_ACCESS_TOKEN_EXPIRES"): + app.config["JWT_ACCESS_TOKEN_EXPIRES"] = environ.get("JWT_ACCESS_TOKEN_EXPIRES") jwt = JWTManager(app) @jwt.user_identity_loader @@ -80,7 +83,7 @@ def register_callback(blueprint): redirect_token = f"?state={session.pop('state')}" if user is None: user, msg, code = userController.create_user(github_id=id, name=session.pop('username', "Anton")) - + if user is None: redirect_token += f"&msg={msg}&code={code}" else: From 22954665a8238ab9fbd2166587c41e64a5597bc1 Mon Sep 17 00:00:00 2001 From: petak5 Date: Mon, 29 Jun 2020 19:53:06 +0200 Subject: [PATCH 02/36] Formatting fixes --- src/api/controllers/userController.py | 2 +- src/api/views/userView.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/controllers/userController.py b/src/api/controllers/userController.py index da4f01e..59032e4 100644 --- a/src/api/controllers/userController.py +++ b/src/api/controllers/userController.py @@ -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): diff --git a/src/api/views/userView.py b/src/api/views/userView.py index c21143e..b126432 100644 --- a/src/api/views/userView.py +++ b/src/api/views/userView.py @@ -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 From 27571b53bfa23f9c0be4b5022b27017fee5b9c7d Mon Sep 17 00:00:00 2001 From: petak5 Date: Mon, 29 Jun 2020 19:54:19 +0200 Subject: [PATCH 03/36] Don't create new DB session --- src/api/controllers/userController.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/controllers/userController.py b/src/api/controllers/userController.py index 59032e4..0c54a65 100644 --- a/src/api/controllers/userController.py +++ b/src/api/controllers/userController.py @@ -4,7 +4,7 @@ from flask import jsonify class UserController: - session = db.session() + session = db.session # User def create_user(self, **kwargs): From 1a7feea8ce0ac0f9b6ab472533c3f7cc219380aa Mon Sep 17 00:00:00 2001 From: petak5 Date: Mon, 29 Jun 2020 19:57:41 +0200 Subject: [PATCH 04/36] Add info about setting JWT token timeout to README --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 78cccd5..6a5d4d9 100644 --- a/README.md +++ b/README.md @@ -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/` From 38b6c9958814d38fb1d76d8d3b7d48005ada7a09 Mon Sep 17 00:00:00 2001 From: petak5 Date: Mon, 29 Jun 2020 21:49:33 +0200 Subject: [PATCH 05/36] Fixed and made more verbose JWT token timeout environment variable setting --- src/api/views/oauthView.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/views/oauthView.py b/src/api/views/oauthView.py index 77d720e..b69ed9b 100644 --- a/src/api/views/oauthView.py +++ b/src/api/views/oauthView.py @@ -17,8 +17,8 @@ app.config['JWT_SECRET_KEY'] = environ.get("JWT_SECRET_KEY") # JWT token expiration time in seconds - default is 15 minutes -if environ.get("JWT_ACCESS_TOKEN_EXPIRES"): - app.config["JWT_ACCESS_TOKEN_EXPIRES"] = environ.get("JWT_ACCESS_TOKEN_EXPIRES") +if environ.get("JWT_ACCESS_TOKEN_EXPIRES").isdigit(): + app.config["JWT_ACCESS_TOKEN_EXPIRES"] = int(environ.get("JWT_ACCESS_TOKEN_EXPIRES")) jwt = JWTManager(app) @jwt.user_identity_loader From 23d8aecd85574cd998966d3a510a3fc5780ae56c Mon Sep 17 00:00:00 2001 From: petak5 Date: Mon, 29 Jun 2020 21:56:20 +0200 Subject: [PATCH 06/36] Refactored create project route --- src/api/controllers/projectController.py | 22 ++++++++++++++++------ src/api/views/projectView.py | 15 ++++++++------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/api/controllers/projectController.py b/src/api/controllers/projectController.py index c8d69f9..294d21d 100644 --- a/src/api/controllers/projectController.py +++ b/src/api/controllers/projectController.py @@ -1,18 +1,28 @@ -from api.models import db, Project, UserHasProject, ProjectLink, ProjectFeedback +from api.models import db, User, Project, UserHasProject, ProjectLink, ProjectFeedback class ProjectController: - session = db.session() + 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 + + self.session.add(userHasProject) self.session.commit() - return project + return project, "OK", 201 except: - return None + return None, "Project creation failed", 400 def update_project(self, id, **kwargs): project = Project.query.filter_by(id=id).first() diff --git a/src/api/views/projectView.py b/src/api/views/projectView.py index 587a6f4..f10ba0d 100644 --- a/src/api/views/projectView.py +++ b/src/api/views/projectView.py @@ -1,9 +1,13 @@ 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 @@ -65,13 +69,10 @@ 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(get_jwt_identity(), **request.get_json())) @app.route("/projects/", methods=['PUT']) def update_project(id): From 5536927e75a0364b60ebd5ea7375cc2a121e9773 Mon Sep 17 00:00:00 2001 From: petak5 Date: Fri, 3 Jul 2020 07:30:39 +0200 Subject: [PATCH 07/36] Fix typos in response messages --- src/api/controllers/userController.py | 12 ++++++------ src/api/views/userView.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/api/controllers/userController.py b/src/api/controllers/userController.py index 0c54a65..aa165c2 100644 --- a/src/api/controllers/userController.py +++ b/src/api/controllers/userController.py @@ -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) @@ -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 @@ -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() @@ -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: diff --git a/src/api/views/userView.py b/src/api/views/userView.py index b126432..c9b77e8 100644 --- a/src/api/views/userView.py +++ b/src/api/views/userView.py @@ -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 From f266f5e398bbafa1aa837d0756ed50f427c41df2 Mon Sep 17 00:00:00 2001 From: petak5 Date: Fri, 3 Jul 2020 07:35:55 +0200 Subject: [PATCH 08/36] Update project route refactor --- src/api/controllers/projectController.py | 33 +++++++++++------------ src/api/views/projectView.py | 34 +++++++++--------------- 2 files changed, 29 insertions(+), 38 deletions(-) diff --git a/src/api/controllers/projectController.py b/src/api/controllers/projectController.py index 294d21d..f867309 100644 --- a/src/api/controllers/projectController.py +++ b/src/api/controllers/projectController.py @@ -24,35 +24,34 @@ def create_project(self, user_id, **kwargs): except: 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 - - for key, value in kwargs.items(): - if not hasattr(project, key): - return None - - for key, value in kwargs.items(): - setattr(project, key, value) + if 'id' not in kwargs: + return None, "Failed to update project. Request body must specify project's id.", 400 - db.session.commit() + user = User.query.filter_by(id=user_id).first() - 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() diff --git a/src/api/views/projectView.py b/src/api/views/projectView.py index f10ba0d..c46ac5b 100644 --- a/src/api/views/projectView.py +++ b/src/api/views/projectView.py @@ -11,6 +11,7 @@ def create_project(): """ Create project + Current user creates project --- tags: - Project @@ -36,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 @@ -72,22 +73,19 @@ def create_project(): 404: description: User doesn't exist """ - return wrap_response(*projectController.create_project(get_jwt_identity(), **request.get_json())) + return wrap_response(*projectController.create_project(user_id=get_jwt_identity(), **request.get_json())) -@app.route("/projects/", 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 @@ -99,16 +97,10 @@ 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 - - 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/", methods=['GET']) def get_project(id): From beccc654d8f96bad47879ba7fe7bc2ed87855a28 Mon Sep 17 00:00:00 2001 From: petak5 Date: Fri, 3 Jul 2020 07:56:53 +0200 Subject: [PATCH 09/36] Get projects routes refactor --- src/api/controllers/projectController.py | 7 +++++-- src/api/views/projectView.py | 13 ++----------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/api/controllers/projectController.py b/src/api/controllers/projectController.py index f867309..96b6554 100644 --- a/src/api/controllers/projectController.py +++ b/src/api/controllers/projectController.py @@ -56,12 +56,15 @@ def update_project(self, user_id, **kwargs): 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, id): # Remove all project's links diff --git a/src/api/views/projectView.py b/src/api/views/projectView.py index c46ac5b..e8d645d 100644 --- a/src/api/views/projectView.py +++ b/src/api/views/projectView.py @@ -122,12 +122,7 @@ def get_project(id): 404: description: Project not found """ - project = projectController.get_project(id=id) - - if project: - return jsonify(project.as_dict()), 200 - else: - return "", 404 + return wrap_response(*projectController.get_project(id=id)) @app.route("/projects", methods=['GET']) def get_all_projects(): @@ -141,11 +136,7 @@ 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/", methods=['DELETE']) def delete_project(id): From 8f4a0423b7f362c01a65a377901cd5c65d42ea63 Mon Sep 17 00:00:00 2001 From: petak5 Date: Fri, 3 Jul 2020 08:44:50 +0200 Subject: [PATCH 10/36] Delete project refactor --- src/api/controllers/projectController.py | 27 ++++++++++++++++++------ src/api/views/projectView.py | 21 +++++++++--------- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/api/controllers/projectController.py b/src/api/controllers/projectController.py index 96b6554..260c121 100644 --- a/src/api/controllers/projectController.py +++ b/src/api/controllers/projectController.py @@ -1,6 +1,7 @@ from api.models import db, User, Project, UserHasProject, ProjectLink, ProjectFeedback class ProjectController: + # TODO: remove this (also from userController)? session = db.session # Project @@ -66,24 +67,38 @@ def get_all_projects(self, **kwargs): return all_projects, "OK", 200 - def delete_project(self, id): + def delete_project(self, user_id, **kwargs): + if len(kwargs) != 1: + return None, "Failed to update project. Request body must contain only project's id.", 400 + + if 'id' not in kwargs: + return None, "Failed to update project. Request body must specify project's id.", 400 + + project_id = kwargs["id"] + + userHasProject = UserHasProject.query.filter_by(user_id=user_id, project_id=project_id).first() + # TODO: verify that the user owns the project (or has neccessary rights) + if not userHasProject: + return None, "Failed to update project. Current user does not belong to specified project, or the project does not exist.", 404 + # Remove all project's links - for link in ProjectLink.query.filter_by(project_id=id).all(): + for link in ProjectLink.query.filter_by(project_id=project_id).all(): db.session.delete(link) # Remove project from all users - for project in UserHasProject.query.filter_by(project_id=id).all(): + for project in UserHasProject.query.filter_by(project_id=project_id).all(): db.session.delete(project) - project = Project.query.filter_by(id=id).first() + project = Project.query.filter_by(id=project_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): diff --git a/src/api/views/projectView.py b/src/api/views/projectView.py index e8d645d..f28010a 100644 --- a/src/api/views/projectView.py +++ b/src/api/views/projectView.py @@ -138,16 +138,18 @@ def get_all_projects(): """ return wrap_response(*projectController.get_all_projects()) -@app.route("/projects/", methods=['DELETE']) -def delete_project(id): +@app.route("/project", methods=['DELETE']) +@jwt_required +@body_required +def delete_project(): """ Delete project - Deletes project with `id` + Deletes current user's project with the id in request body --- tags: - Project parameters: - - in: path + - in: body name: id type: integer required: true @@ -156,14 +158,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(), **request.get_json())) # Project Link @app.route("/projects//links", methods=['POST']) From 8716f16178ece0d7c947738161db82d937edb5fb Mon Sep 17 00:00:00 2001 From: petak5 Date: Fri, 3 Jul 2020 08:49:59 +0200 Subject: [PATCH 11/36] Fix possible error with multiple parameters with the same name being passed to function --- src/api/controllers/projectController.py | 6 +++--- src/api/views/projectView.py | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/api/controllers/projectController.py b/src/api/controllers/projectController.py index 260c121..fb7a5b8 100644 --- a/src/api/controllers/projectController.py +++ b/src/api/controllers/projectController.py @@ -69,17 +69,17 @@ def get_all_projects(self, **kwargs): def delete_project(self, user_id, **kwargs): if len(kwargs) != 1: - return None, "Failed to update project. Request body must contain only project's id.", 400 + return None, "Failed to delete project. Request body must contain only project's id.", 400 if 'id' not in kwargs: - return None, "Failed to update project. Request body must specify project's id.", 400 + return None, "Failed to delete project. Request body must specify project's id.", 400 project_id = kwargs["id"] userHasProject = UserHasProject.query.filter_by(user_id=user_id, project_id=project_id).first() # TODO: verify that the user owns the project (or has neccessary rights) if not userHasProject: - return None, "Failed to update project. Current user does not belong to specified project, or the project does not exist.", 404 + return None, "Failed to delete project. Current user does not belong to specified project, or the project does not exist.", 404 # Remove all project's links for link in ProjectLink.query.filter_by(project_id=project_id).all(): diff --git a/src/api/views/projectView.py b/src/api/views/projectView.py index f28010a..339b60d 100644 --- a/src/api/views/projectView.py +++ b/src/api/views/projectView.py @@ -100,6 +100,9 @@ def update_project(): 404: description: Current user or requested project not found """ + if "user_id" in request.get_json(): + return wrap_response(None, "Failed to update project. Request body must not contain 'user_id'.", 400) + return wrap_response(*projectController.update_project(user_id=get_jwt_identity(), **request.get_json())) @app.route("/projects/", methods=['GET']) @@ -162,6 +165,9 @@ def delete_project(): 404: description: Current user is not a member of requested project or the project was not found """ + if "user_id" in request.get_json(): + return wrap_response(None, "Failed to delete project. Request body must not contain 'user_id'.", 400) + return wrap_response(*projectController.delete_project(user_id=get_jwt_identity(), **request.get_json())) # Project Link From 90575b22dc0f748e7914068dc2d3297980050ab9 Mon Sep 17 00:00:00 2001 From: petak5 Date: Fri, 3 Jul 2020 12:53:40 +0200 Subject: [PATCH 12/36] Add session rollback to create project controller when failed --- src/api/controllers/projectController.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/controllers/projectController.py b/src/api/controllers/projectController.py index fb7a5b8..07c6d99 100644 --- a/src/api/controllers/projectController.py +++ b/src/api/controllers/projectController.py @@ -23,6 +23,7 @@ def create_project(self, user_id, **kwargs): return project, "OK", 201 except: + self.session.rollback() return None, "Project creation failed", 400 def update_project(self, user_id, **kwargs): From bce06a14f1501389475b732129ea029301f49cdf Mon Sep 17 00:00:00 2001 From: petak5 Date: Fri, 3 Jul 2020 13:13:10 +0200 Subject: [PATCH 13/36] Update project tests after routes refactor --- tests/api/views/test_projectView.py | 73 ++++++++++++++++++----------- 1 file changed, 46 insertions(+), 27 deletions(-) diff --git a/tests/api/views/test_projectView.py b/tests/api/views/test_projectView.py index eb328d4..9990572 100644 --- a/tests/api/views/test_projectView.py +++ b/tests/api/views/test_projectView.py @@ -1,72 +1,91 @@ from tests.conftest import client from tests import db, Project, ProjectLink -from tests.api import create_project_for_test_cases, create_project_link_for_test_cases +from tests.api import create_project_for_test_cases, create_project_link_for_test_cases, create_access_token_for_test_cases class TestProjectView(object): - valid_data = { + # valid data for user creation + valid_user_data = { + 'name': 'L Jone', + 'bio': 'coding...', + 'languages': 'FR', + 'interests': 'Nothing', + 'location': 'X', + 'occupation': 'cashier' + } + + valid_project_data = { 'name': 'PB api', 'description': 'A cool project', + 'development_status': 1, 'repository': 'http://github.xy.com' } def test_create_project(self, client): - response = client.post('/projects', json={"name": "Project"}) + token, _ = create_access_token_for_test_cases(self.valid_user_data) + + response = client.post('/project', headers={"Authorization": f"Bearer {token}"}, json={"name": "Project"}) assert response.status_code == 400 - response = client.post('/projects', json=self.valid_data) - assert response.status_code == 201 + response = client.post('/project', headers={"Authorization": f"Bearer {token}"}) + assert response.status_code == 400 - # response = client.post('/projects') - # assert response.status_code == 400 + response = client.post('/project') + assert response.status_code == 401 + + response = client.post('/project', headers={"Authorization": f"Bearer {token}"}, json=self.valid_project_data) + assert response.status_code == 201 def test_update_project(self, client): + token, _ = create_access_token_for_test_cases(self.valid_user_data) # project id doesn't exist - response = client.post('/projects/0', json={'name': 'Updated PB'}) - - # notice: should return 404 when doesen't exist insted of 400 + response = client.put('/project', headers={"Authorization": f"Bearer {token}"}, json={'id': 0, 'name': 'Updated PB'}) assert response.status_code == 404 - project_id = create_project_for_test_cases(self.valid_data) - response = client.post('/projects/{}'.format(project_id), json={'description': 'updated desc'}) + project = create_project_for_test_cases(self.valid_project_data) + project_id = project["id"] + + response = client.put('/project', headers={"Authorization": f"Bearer {token}"}, json={'id': project_id, 'description': 'updated desc'}) project = Project.query.filter_by(id=project_id).first() assert project.description == 'updated desc' def test_delete_project(self, client): - response = client.delete('/projects/0') + token, _ = create_access_token_for_test_cases(self.valid_user_data) + + response = client.delete('/project', headers={"Authorization": f"Bearer {token}"}, json={"id": 0}) assert response.status_code == 404 - project1 = create_project_for_test_cases(self.valid_data) + project1 = create_project_for_test_cases(self.valid_project_data) - self.valid_data["name"] = "p2 name" - project2 = create_project_for_test_cases(self.valid_data) + self.valid_project_data["name"] = "p2 name" + project2 = create_project_for_test_cases(self.valid_project_data) - response = client.delete('/projects/{}'.format(project1["id"])) + response = client.delete('/project', headers={"Authorization": f"Bearer {token}"}, json={"id": project1["id"]}) assert response.status_code == 202 def test_get_project(self, client): response = client.get('/projects/{}'.format(0)) assert response.status_code == 404 - project = create_project_for_test_cases(self.valid_data) + project = create_project_for_test_cases(self.valid_project_data) response = client.get('/projects/{}'.format(project["id"])) assert response.status_code == 200 - assert response.get_json()["name"] == project["name"] + assert response.get_json()["data"]["name"] == project["name"] def test_get_all_projects(self, client): - project1 = create_project_for_test_cases(self.valid_data) + project1 = create_project_for_test_cases(self.valid_project_data) - self.valid_data["name"] = "allproject2" - project2 = create_project_for_test_cases(self.valid_data) + self.valid_project_data["name"] = "allproject2" + project2 = create_project_for_test_cases(self.valid_project_data) response = client.get('/projects') assert response.status_code == 200 r = response.get_json() - assert [r[0]["name"], r[1]["name"]] == [project1["name"], project2["name"]] + assert [r["data"][0]["name"], r["data"][1]["name"]] == [project1["name"], project2["name"]] def test_create_project_link(self, client): - project = create_project_for_test_cases(self.valid_data) + project = create_project_for_test_cases(self.valid_project_data) url = '/projects/{}/links'.format(project["id"]) response = client.post(url, json={"user_id": 0}) @@ -76,7 +95,7 @@ def test_create_project_link(self, client): assert response.status_code == 201 def test_update_project_link(self, client): - p1 = create_project_for_test_cases(self.valid_data) + p1 = create_project_for_test_cases(self.valid_project_data) p1_link = create_project_link_for_test_cases( { "name": "Plink", @@ -99,7 +118,7 @@ def test_update_project_link(self, client): assert response.get_json()["name"] == "Nlink" def test_get_all_project_links(self, client): - p1 = create_project_for_test_cases(self.valid_data) + p1 = create_project_for_test_cases(self.valid_project_data) p_link1 = create_project_link_for_test_cases( { "name": "Plink", @@ -123,7 +142,7 @@ def test_delete_project_link(self, client): response = client.delete(url.format(0, 0)) assert response.status_code == 404 - p1 = create_project_for_test_cases(self.valid_data) + p1 = create_project_for_test_cases(self.valid_project_data) p_link1 = create_project_link_for_test_cases( { "name": "Plink", From 6fc6801387bed2c010df0d893e2059e6ba44341a Mon Sep 17 00:00:00 2001 From: petak5 Date: Fri, 3 Jul 2020 15:58:55 +0200 Subject: [PATCH 14/36] Fixed delete project test --- tests/__init__.py | 2 +- tests/api/__init__.py | 12 +++++++++++- tests/api/views/test_projectView.py | 8 +++++--- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/tests/__init__.py b/tests/__init__.py index 56f3d94..25d093a 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -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') diff --git a/tests/api/__init__.py b/tests/api/__init__.py index bd7fb7c..814b07e 100644 --- a/tests/api/__init__.py +++ b/tests/api/__init__.py @@ -11,7 +11,17 @@ """ from flask_jwt_extended import create_access_token -from tests import db, Project, User, UserLink, ProjectLink, UserFeedback +from tests import db, Project, User, UserHasProject, UserLink, ProjectLink, UserFeedback + +""" Create relationship between user and project """ +def user_join_project_for_test_cases(user, project): + userHasProject = UserHasProject(role=1) + userHasProject.project = Project.query.filter_by(id=project["id"]).first() + userHasProject.user = user + # This line is not needed for some reason + # SQLAlchemy is doing some magic and I don't know shit about fuck + #user.projects.append(userHasProject) + db.session.commit() def create_project_for_test_cases(data): new_project = Project(**data) diff --git a/tests/api/views/test_projectView.py b/tests/api/views/test_projectView.py index 9990572..5cb48f1 100644 --- a/tests/api/views/test_projectView.py +++ b/tests/api/views/test_projectView.py @@ -1,6 +1,6 @@ from tests.conftest import client from tests import db, Project, ProjectLink -from tests.api import create_project_for_test_cases, create_project_link_for_test_cases, create_access_token_for_test_cases +from tests.api import create_project_for_test_cases, create_project_link_for_test_cases, create_access_token_for_test_cases, user_join_project_for_test_cases class TestProjectView(object): @@ -51,18 +51,20 @@ def test_update_project(self, client): assert project.description == 'updated desc' def test_delete_project(self, client): - token, _ = create_access_token_for_test_cases(self.valid_user_data) + token, user = create_access_token_for_test_cases(self.valid_user_data) response = client.delete('/project', headers={"Authorization": f"Bearer {token}"}, json={"id": 0}) assert response.status_code == 404 project1 = create_project_for_test_cases(self.valid_project_data) + user_join_project_for_test_cases(user, project1) self.valid_project_data["name"] = "p2 name" project2 = create_project_for_test_cases(self.valid_project_data) + user_join_project_for_test_cases(user, project2) response = client.delete('/project', headers={"Authorization": f"Bearer {token}"}, json={"id": project1["id"]}) - assert response.status_code == 202 + assert response.status_code == 200 def test_get_project(self, client): response = client.get('/projects/{}'.format(0)) From 946bebcae68f05f34ef3f4b991acfb470b61a27d Mon Sep 17 00:00:00 2001 From: petak5 Date: Sat, 4 Jul 2020 09:11:32 +0200 Subject: [PATCH 15/36] Fix usage message for tests --- tests/runtests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/runtests.py b/tests/runtests.py index 82a6c8b..70d7f78 100644 --- a/tests/runtests.py +++ b/tests/runtests.py @@ -1,6 +1,6 @@ response = """ -Use: pipenv run pytest src/tests/ +Usage: pipenv run pytest tests/ """ From 2326e613ee92efffb345586c611e0d0ca86c083f Mon Sep 17 00:00:00 2001 From: petak5 Date: Sun, 5 Jul 2020 10:41:41 +0200 Subject: [PATCH 16/36] Remove get all users test --- src/api/controllers/userController.py | 5 ---- tests/api/views/test_userView.py | 38 +++------------------------ 2 files changed, 3 insertions(+), 40 deletions(-) diff --git a/src/api/controllers/userController.py b/src/api/controllers/userController.py index aa165c2..24bd906 100644 --- a/src/api/controllers/userController.py +++ b/src/api/controllers/userController.py @@ -43,11 +43,6 @@ def get_user(self, **kwargs): return user, "OK", 200 - def get_all_users(self, **kwargs): - all_users = User.query.all() - - return all_users - def delete_user(self, id): # Remove all user's links for link in UserLink.query.filter_by(user_id=id).all(): diff --git a/tests/api/views/test_userView.py b/tests/api/views/test_userView.py index ad6908d..72a3c75 100644 --- a/tests/api/views/test_userView.py +++ b/tests/api/views/test_userView.py @@ -15,7 +15,6 @@ class TestUserView(object): 'occupation': 'cashier' } - def test_update_user(self, client): token, _ = create_access_token_for_test_cases(self.valid_data) @@ -36,51 +35,20 @@ def test_delete_user(self, client): response = client.delete('/user', headers={"Authorization": f"Bearer {token}"}) assert response.status_code == 404 - + def test_get_user(self, client): token, user = create_access_token_for_test_cases(self.valid_data) - + response = client.get('/user', headers={"Authorization": f"Bearer {token}"}) assert response.status_code == 200 assert response.get_json() == {"data": user.as_dict(), "msg": "OK"} delete_user_for_test_cases(user) - + response = client.get('/user', headers={"Authorization": f"Bearer {token}"}) assert response.status_code == 404 - - - - def test_get_all_users(self, client): - create_user_for_test_cases(self.valid_data) - - self.valid_data = { - 'name': 'Valid', - 'bio': 'new', - 'languages': 'DE', - 'interests': 'e', - 'location': 'nowhere', - 'occupation': 'cashier2.1' - } - - create_user_for_test_cases(self.valid_data) - - response = client.get('/users') - assert response.status_code == 200 - - users_list = User.query.all() - users_dict = [users_list[0].as_dict(), users_list[1].as_dict()] - assert response.get_json() == [users_list[0].as_dict(), users_list[1].as_dict()] - - db.session.delete(users_list[0]) - db.session.commit() - - response = client.get('/users') - assert response.status_code == 200 - assert response.get_json() == [users_dict[1]] - def test_create_user_link(self, client): token, user = create_access_token_for_test_cases(self.valid_data) url = '/user/link' From c6290ab4e14e759c5c7bfd624638f3b01ba2e031 Mon Sep 17 00:00:00 2001 From: petak5 Date: Sun, 5 Jul 2020 11:25:03 +0200 Subject: [PATCH 17/36] Create project link --- src/api/controllers/projectController.py | 22 +++++++++++++++------- src/api/views/projectView.py | 22 ++++++++++++---------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/api/controllers/projectController.py b/src/api/controllers/projectController.py index 07c6d99..61bca07 100644 --- a/src/api/controllers/projectController.py +++ b/src/api/controllers/projectController.py @@ -102,16 +102,24 @@ def delete_project(self, user_id, **kwargs): return project, "OK", 200 # Project Link - def create_link(self, project_id, **kwargs): - try: - link = ProjectLink(project_id=project_id, **kwargs) - self.session.add(link) - self.session.commit() + def create_link(self, user_id, **kwargs): + if "project_id" not in kwargs: + return None, "Failed to create project link. Request body must specify link's 'project_id'.", 400 - return link + try: + if "link" in kwargs and "project_id" in kwargs and "name" in kwargs["link"] and "url" in kwargs["link"] and len(kwargs) == 2: + if kwargs["link"]["name"] is None or kwargs["link"]["url"] is None or kwargs["project_id"] is None: + return None, "Arguments can't be empty", 400 + link = ProjectLink(project_id=kwargs["project_id"], **kwargs["link"]) + self.session.add(link) + self.session.commit() + + return link, "OK", 201 + else: + return None, "Forbidden attributes used in request. Only 'project_id' and 'link' object containing 'name' and 'url' allowed.", 400 except: self.session.rollback() - return None + return None, "Failed to create project link.", 400 def update_link(self, project_id, link_id, **kwargs): link = ProjectLink.query.filter_by(project_id=project_id, id=link_id).first() diff --git a/src/api/views/projectView.py b/src/api/views/projectView.py index 339b60d..e7e20e1 100644 --- a/src/api/views/projectView.py +++ b/src/api/views/projectView.py @@ -171,14 +171,21 @@ def delete_project(): return wrap_response(*projectController.delete_project(user_id=get_jwt_identity(), **request.get_json())) # Project Link -@app.route("/projects//links", methods=['POST']) -def create_project_link(project_id): +@app.route("/project/link", methods=['POST']) +@jwt_required +@body_required +def create_project_link(): """ Create project link --- tags: - ProjectLink parameters: + - in: body + name: project_id + type: integer + required: true + description: Id of project for which link shall be created - in: body name: ProjectLink required: true @@ -207,15 +214,10 @@ def create_project_link(project_id): 400: description: Failed to create project link """ - if 'project_id' in request.get_json(): - return "Failed to create project link. Request body can not specify link's project_id.", 400 - - link = projectController.create_link(project_id, **request.get_json()) + if "user_id" in request.get_json(): + return wrap_response(None, "Failed to create project link. Request body must not contain 'user_id'.", 400) - if link == None: - return "Failed to create project link.", 400 - else: - return jsonify(link.as_dict()), 201 + return wrap_response(*projectController.create_link(user_id=get_jwt_identity(), **request.get_json())) @app.route("/projects//links/", methods=['PUT']) def update_project_link(project_id, link_id): From 312c6bf760fcaeea54a8d1762bdacb5bca4b719d Mon Sep 17 00:00:00 2001 From: petak5 Date: Sun, 5 Jul 2020 12:21:13 +0200 Subject: [PATCH 18/36] Update project link --- src/api/controllers/projectController.py | 30 +++++++++++++++--------- src/api/views/projectView.py | 28 +++++++--------------- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/src/api/controllers/projectController.py b/src/api/controllers/projectController.py index 61bca07..5544c59 100644 --- a/src/api/controllers/projectController.py +++ b/src/api/controllers/projectController.py @@ -121,22 +121,30 @@ def create_link(self, user_id, **kwargs): self.session.rollback() return None, "Failed to create project link.", 400 - def update_link(self, project_id, link_id, **kwargs): - link = ProjectLink.query.filter_by(project_id=project_id, id=link_id).first() + def update_link(self, user_id, **kwargs): + if "project_id" not in kwargs: + return None, "Failed to update project link. Request body must specify link's 'project_id'.", 400 - if link == None: - return None + if "link" in kwargs and "project_id" in kwargs and "id" in kwargs["link"] and len(kwargs) == 2: + if kwargs["link"]["id"] is None or kwargs["project_id"] is None: + return None, "Arguments can't be empty", 400 + link = ProjectLink.query.filter_by(project_id=kwargs["project_id"], id=kwargs["link"]["id"]).first() - for key, value in kwargs.items(): - if not hasattr(link, key): - return None + if link == None: + return None, "Failed to update project link. Project link not found.", 404 - for key, value in kwargs.items(): - setattr(link, key, value) + for key, value in kwargs["link"].items(): + if not hasattr(link, key): + return None, f"Failed to update project link. Forbidden attribute '{key}'.", 400 - db.session.commit() + for key, value in kwargs["link"].items(): + setattr(link, key, value) - return link + db.session.commit() + + return link, "OK", 200 + else: + return None, "Forbidden attributes used in request. Only 'project_id' and 'link' object containing 'id', 'name' and 'url' allowed.", 400 def get_all_links(self, project_id): all_links = ProjectLink.query.filter_by(project_id=project_id).all() diff --git a/src/api/views/projectView.py b/src/api/views/projectView.py index e7e20e1..39f1381 100644 --- a/src/api/views/projectView.py +++ b/src/api/views/projectView.py @@ -219,25 +219,20 @@ def create_project_link(): return wrap_response(*projectController.create_link(user_id=get_jwt_identity(), **request.get_json())) -@app.route("/projects//links/", methods=['PUT']) -def update_project_link(project_id, link_id): +@app.route("/project/link", methods=['PUT']) +def update_project_link(): """ Update project link - Updates project link with `project_id` and `link_id` using the data in request body + Updates project link with data in the request body --- tags: - ProjectLink parameters: - - in: path + - in: body name: project_id type: integer required: true description: Id of the project - - in: path - name: link_id - type: integer - required: true - description: Id of the project link to update - in: body name: ProjectLink required: true @@ -249,18 +244,13 @@ def update_project_link(project_id, link_id): description: Project link updated successfully 400: description: Failed to update project link + 404: + description: Project link not found """ - if 'project_id' in request.get_json(): - return "Failed to update project link. Request body can not specify link's project_id.", 400 - elif 'link_id' in request.get_json(): - return "Failed to update project link. Request body can not specify link's link_id.", 400 - - link = projectController.update_link(project_id, link_id, **request.get_json()) + if "user_id" in request.get_json(): + return wrap_response(None, "Failed to create project link. Request body must not contain 'user_id'.", 400) - if link == None: - return "Failed to update project link.", 400 - else: - return jsonify(link.as_dict()), 200 + return wrap_response(*projectController.update_link(user_id=get_jwt_identity(), **request.get_json())) @app.route("/projects//links", methods=['GET']) def get_all_project_links(project_id): From 7f249575535dc043b25a343487ce9ad54d0bcbfe Mon Sep 17 00:00:00 2001 From: petak5 Date: Sun, 5 Jul 2020 12:34:33 +0200 Subject: [PATCH 19/36] Delete project link --- src/api/controllers/projectController.py | 29 ++++++++++++++---------- src/api/views/projectView.py | 22 +++++++++--------- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/src/api/controllers/projectController.py b/src/api/controllers/projectController.py index 5544c59..4725931 100644 --- a/src/api/controllers/projectController.py +++ b/src/api/controllers/projectController.py @@ -110,6 +110,7 @@ def create_link(self, user_id, **kwargs): if "link" in kwargs and "project_id" in kwargs and "name" in kwargs["link"] and "url" in kwargs["link"] and len(kwargs) == 2: if kwargs["link"]["name"] is None or kwargs["link"]["url"] is None or kwargs["project_id"] is None: return None, "Arguments can't be empty", 400 + link = ProjectLink(project_id=kwargs["project_id"], **kwargs["link"]) self.session.add(link) self.session.commit() @@ -122,12 +123,10 @@ def create_link(self, user_id, **kwargs): return None, "Failed to create project link.", 400 def update_link(self, user_id, **kwargs): - if "project_id" not in kwargs: - return None, "Failed to update project link. Request body must specify link's 'project_id'.", 400 - - if "link" in kwargs and "project_id" in kwargs and "id" in kwargs["link"] and len(kwargs) == 2: - if kwargs["link"]["id"] is None or kwargs["project_id"] is None: + if "project_id" in kwargs and "link" in kwargs and "id" in kwargs["link"] and len(kwargs) == 2: + if kwargs["project_id"] is None or kwargs["link"]["id"] is None: return None, "Arguments can't be empty", 400 + link = ProjectLink.query.filter_by(project_id=kwargs["project_id"], id=kwargs["link"]["id"]).first() if link == None: @@ -151,16 +150,22 @@ def get_all_links(self, project_id): return all_links - def delete_link(self, project_id, link_id): - link = ProjectLink.query.filter_by(project_id=project_id, id=link_id).first() + def delete_link(self, user_id, **kwargs): + if "project_id" in kwargs and "link" in kwargs and "id" in kwargs["link"] and len(kwargs) == 2 and len(kwargs["link"]) == 1: + if kwargs["project_id"] is None or kwargs["link"]["id"] is None: + return None, "Arguments can't be empty", 400 - if link == None: - return None + link = ProjectLink.query.filter_by(project_id=kwargs["project_id"], id=kwargs["link"]["id"]).first() - db.session.delete(link) - db.session.commit() + if link == None: + return None, "Failed to delete project link. Project link not found.", 404 - return link + db.session.delete(link) + db.session.commit() + + return link, "OK", 200 + else: + return None, "Forbidden attributes used in request. Only 'project_id' and 'link' object containing 'id' allowed.", 400 # Project Feedback def create_feedback(self, project_id, **kwargs): diff --git a/src/api/views/projectView.py b/src/api/views/projectView.py index 39f1381..1d50941 100644 --- a/src/api/views/projectView.py +++ b/src/api/views/projectView.py @@ -248,7 +248,7 @@ def update_project_link(): description: Project link not found """ if "user_id" in request.get_json(): - return wrap_response(None, "Failed to create project link. Request body must not contain 'user_id'.", 400) + return wrap_response(None, "Failed to update project link. Request body must not contain 'user_id'.", 400) return wrap_response(*projectController.update_link(user_id=get_jwt_identity(), **request.get_json())) @@ -276,21 +276,21 @@ def get_all_project_links(project_id): return jsonify(links), 200 -@app.route("/projects//links/", methods=['DELETE']) -def delete_project_link(project_id, link_id): +@app.route("/project/link", methods=['DELETE']) +def delete_project_link(): """ Delete project link - Deletes project link with `project_id` and `link_id` + Deletes project link with data in the request body --- tags: - ProjectLink parameters: - - in: path + - in: body name: project_id type: integer required: true description: Id of the project - - in: path + - in: body name: link_id type: integer required: true @@ -298,15 +298,15 @@ def delete_project_link(project_id, link_id): responses: 200: description: Project link deleted successfully + 400: + description: Failed to delete project link 404: description: Project link not found """ - link = projectController.delete_link(project_id, link_id) + if "user_id" in request.get_json(): + return wrap_response(None, "Failed to delete project link. Request body must not contain 'user_id'.", 400) - if link == None: - return "", 404 - else: - return "", 200 + return wrap_response(*projectController.delete_link(user_id=get_jwt_identity(), **request.get_json())) # Project Feedback @app.route("/projects//feedbacks", methods=['POST']) From 8673dfa16b31a428764e984b1dc7a1490afc27d6 Mon Sep 17 00:00:00 2001 From: petak5 Date: Sun, 5 Jul 2020 20:37:30 +0200 Subject: [PATCH 20/36] Remove get all project links route and related code --- src/api/controllers/projectController.py | 5 ----- src/api/views/projectView.py | 28 ++++-------------------- tests/api/views/test_projectView.py | 19 ---------------- 3 files changed, 4 insertions(+), 48 deletions(-) diff --git a/src/api/controllers/projectController.py b/src/api/controllers/projectController.py index 4725931..fd26b8e 100644 --- a/src/api/controllers/projectController.py +++ b/src/api/controllers/projectController.py @@ -145,11 +145,6 @@ def update_link(self, user_id, **kwargs): else: return None, "Forbidden attributes used in request. Only 'project_id' and 'link' object containing 'id', 'name' and 'url' allowed.", 400 - def get_all_links(self, project_id): - all_links = ProjectLink.query.filter_by(project_id=project_id).all() - - return all_links - def delete_link(self, user_id, **kwargs): if "project_id" in kwargs and "link" in kwargs and "id" in kwargs["link"] and len(kwargs) == 2 and len(kwargs["link"]) == 1: if kwargs["project_id"] is None or kwargs["link"]["id"] is None: diff --git a/src/api/views/projectView.py b/src/api/views/projectView.py index 1d50941..56dfdc7 100644 --- a/src/api/views/projectView.py +++ b/src/api/views/projectView.py @@ -220,6 +220,8 @@ def create_project_link(): return wrap_response(*projectController.create_link(user_id=get_jwt_identity(), **request.get_json())) @app.route("/project/link", methods=['PUT']) +@jwt_required +@body_required def update_project_link(): """ Update project link @@ -252,31 +254,9 @@ def update_project_link(): return wrap_response(*projectController.update_link(user_id=get_jwt_identity(), **request.get_json())) -@app.route("/projects//links", methods=['GET']) -def get_all_project_links(project_id): - """ - Get all project links - Retreives all project links with `project_id` - --- - tags: - - ProjectLink - parameters: - - in: path - name: project_id - type: integer - required: true - description: Id of the project - responses: - 200: - description: List of project links - """ - all_links = projectController.get_all_links(project_id) - - links = [ link.as_dict() for link in all_links ] - - return jsonify(links), 200 - @app.route("/project/link", methods=['DELETE']) +@jwt_required +@body_required def delete_project_link(): """ Delete project link diff --git a/tests/api/views/test_projectView.py b/tests/api/views/test_projectView.py index 5cb48f1..2dfa574 100644 --- a/tests/api/views/test_projectView.py +++ b/tests/api/views/test_projectView.py @@ -119,25 +119,6 @@ def test_update_project_link(self, client): assert response.status_code == 200 assert response.get_json()["name"] == "Nlink" - def test_get_all_project_links(self, client): - p1 = create_project_for_test_cases(self.valid_project_data) - p_link1 = create_project_link_for_test_cases( - { - "name": "Plink", - "url": "https://xll.com", - "project_id": p1["id"] - }) - p_link2 = create_project_link_for_test_cases( - { - "name": "Other", - "url": "https://pp.com", - "project_id": p1["id"] - }) - - response = client.get('/projects/{}/links'.format(p1["id"])) - assert response.status_code == 200 - assert response.get_json() == [p_link1, p_link2] - def test_delete_project_link(self, client): url = '/projects/{0}/links/{1}' From 002f832b13badd36928619a0f885c8a2d616c104 Mon Sep 17 00:00:00 2001 From: petak5 Date: Thu, 9 Jul 2020 17:51:59 +0200 Subject: [PATCH 21/36] Remove get all project feedbacks route --- src/api/controllers/projectController.py | 5 ----- src/api/views/projectView.py | 24 ------------------------ 2 files changed, 29 deletions(-) diff --git a/src/api/controllers/projectController.py b/src/api/controllers/projectController.py index fd26b8e..b626f2b 100644 --- a/src/api/controllers/projectController.py +++ b/src/api/controllers/projectController.py @@ -174,11 +174,6 @@ def create_feedback(self, project_id, **kwargs): self.session.rollback() return None - def get_all_feedbacks(self, project_id): - all_feedbacks = ProjectFeedback.query.filter_by(project_id=project_id).all() - - return all_feedbacks - def delete_feedback(self, project_id, feedback_id): feedback = ProjectFeedback.query.filter_by(project_id=project_id, id=feedback_id).first() diff --git a/src/api/views/projectView.py b/src/api/views/projectView.py index 56dfdc7..62ffd1a 100644 --- a/src/api/views/projectView.py +++ b/src/api/views/projectView.py @@ -338,30 +338,6 @@ def create_project_feedback(project_id): else: return jsonify(feedback.as_dict()), 201 -@app.route("/projects//feedbacks", methods=['GET']) -def get_all_project_feedbacks(project_id): - """ - Get all project feedbacks - Retreives all project feedbacks with `project_id` - --- - tags: - - ProjectFeedback - parameters: - - in: path - name: project_id - type: integer - required: true - description: Id of the project - responses: - 200: - description: List of project feedbacks - """ - all_feedbacks = projectController.get_all_feedbacks(project_id) - - feedbacks = [ feedback.as_dict() for feedback in all_feedbacks ] - - return jsonify(feedbacks), 200 - @app.route("/projects//feedbacks/", methods=['DELETE']) def delete_project_feedback(project_id, feedback_id): """ From 0434d6ffe2fd69fc94d0c36b4c8479dc477cb3bc Mon Sep 17 00:00:00 2001 From: petak5 Date: Thu, 9 Jul 2020 18:07:34 +0200 Subject: [PATCH 22/36] Create project feedback --- src/api/controllers/projectController.py | 21 +++++++++++++++------ src/api/views/projectView.py | 19 ++++++++----------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/api/controllers/projectController.py b/src/api/controllers/projectController.py index b626f2b..f67c97a 100644 --- a/src/api/controllers/projectController.py +++ b/src/api/controllers/projectController.py @@ -163,16 +163,25 @@ def delete_link(self, user_id, **kwargs): return None, "Forbidden attributes used in request. Only 'project_id' and 'link' object containing 'id' allowed.", 400 # Project Feedback - def create_feedback(self, project_id, **kwargs): + def create_feedback(self, user_id, **kwargs): + if 'project_id' not in kwargs: + return None, "Failed to create feedback. Request body must specify feedback's project_id.", 400 + try: - feedback = ProjectFeedback(project_id=project_id, **kwargs) - self.session.add(feedback) - self.session.commit() + if "project_id" in kwargs and "rating" in kwargs and "description" in kwargs and len(kwargs) == 3: + if kwargs["project_id"] is None or kwargs["rating"] is None or kwargs["description"] is None: + return None, "Arguments can't be empty", 400 - return feedback + feedback = ProjectFeedback(user_id=user_id, **kwargs) + self.session.add(feedback) + self.session.commit() + + return feedback, "OK", 201 + else: + return None, "Forbidden attributes used in request. Only 'project_id', 'rating' and 'description' allowed.", 400 except: self.session.rollback() - return None + return None, "Failed to create project feedback.", 400 def delete_feedback(self, project_id, feedback_id): feedback = ProjectFeedback.query.filter_by(project_id=project_id, id=feedback_id).first() diff --git a/src/api/views/projectView.py b/src/api/views/projectView.py index 62ffd1a..17ef387 100644 --- a/src/api/views/projectView.py +++ b/src/api/views/projectView.py @@ -289,8 +289,10 @@ def delete_project_link(): return wrap_response(*projectController.delete_link(user_id=get_jwt_identity(), **request.get_json())) # Project Feedback -@app.route("/projects//feedbacks", methods=['POST']) -def create_project_feedback(project_id): +@app.route("/project/feedback", methods=['POST']) +@jwt_required +@body_required +def create_project_feedback(): """ Create project feedback --- @@ -300,7 +302,7 @@ def create_project_feedback(project_id): - in: body name: ProjectFeedback required: true - description: Project feedback object containing data to update + description: Project feedback object containing data to create schema: $ref: "#/definitions/ProjectFeedback" definitions: @@ -328,15 +330,10 @@ def create_project_feedback(project_id): 400: description: Failed to create project feedback """ - if 'project_id' in request.get_json(): - return "Failed to create feedback. Request body can not specify feedback's project_id.", 400 - - feedback = projectController.create_feedback(project_id, **request.get_json()) + if "user_id" in request.get_json(): + return wrap_response(None, "Failed to create project feedback. Request body must not contain 'user_id'.", 400) - if feedback == None: - return "Failed to create feedback.", 400 - else: - return jsonify(feedback.as_dict()), 201 + return wrap_response(*projectController.create_feedback(user_id=get_jwt_identity(), **request.get_json())) @app.route("/projects//feedbacks/", methods=['DELETE']) def delete_project_feedback(project_id, feedback_id): From 4c54d7a130747daa6763ea453a82ebdb6a9d3a01 Mon Sep 17 00:00:00 2001 From: petak5 Date: Thu, 9 Jul 2020 21:53:04 +0200 Subject: [PATCH 23/36] Delete project feedback --- src/api/controllers/projectController.py | 12 +++++++----- src/api/views/projectView.py | 21 +++++++-------------- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/src/api/controllers/projectController.py b/src/api/controllers/projectController.py index f67c97a..db642d8 100644 --- a/src/api/controllers/projectController.py +++ b/src/api/controllers/projectController.py @@ -1,7 +1,6 @@ from api.models import db, User, Project, UserHasProject, ProjectLink, ProjectFeedback class ProjectController: - # TODO: remove this (also from userController)? session = db.session # Project @@ -183,15 +182,18 @@ def create_feedback(self, user_id, **kwargs): self.session.rollback() return None, "Failed to create project feedback.", 400 - def delete_feedback(self, project_id, feedback_id): - feedback = ProjectFeedback.query.filter_by(project_id=project_id, id=feedback_id).first() + def delete_feedback(self, user_id, feedback_id): + feedback = ProjectFeedback.query.filter_by(id=feedback_id).first() + + if feedback.user_id != user_id: + return None, "Failed to delete project feedback. Cannot delete project feedback that you did not create.", 400 if feedback == None: - return None + return None, "Failed to delete project feedback. Project feedback not found.", 404 db.session.delete(feedback) db.session.commit() - return feedback + return feedback, "OK", 200 projectController = ProjectController() diff --git a/src/api/views/projectView.py b/src/api/views/projectView.py index 17ef387..0b1597a 100644 --- a/src/api/views/projectView.py +++ b/src/api/views/projectView.py @@ -335,20 +335,16 @@ def create_project_feedback(): return wrap_response(*projectController.create_feedback(user_id=get_jwt_identity(), **request.get_json())) -@app.route("/projects//feedbacks/", methods=['DELETE']) -def delete_project_feedback(project_id, feedback_id): +@app.route("/project/feedback/", methods=['DELETE']) +@jwt_required +def delete_project_feedback(feedback_id): """ Delete project feedback - Deletes project feedback with `project_id` and `feedback_id` + Deletes project feedback with `feedback_id` --- tags: - ProjectFeedback parameters: - - in: path - name: project_id - type: integer - required: true - description: Id of the project - in: path name: feedback_id type: integer @@ -357,12 +353,9 @@ def delete_project_feedback(project_id, feedback_id): responses: 200: description: Project feedback deleted successfully + 400: + description: Failed to delete project feedback 404: description: Project feedback not found """ - feedback = projectController.delete_feedback(project_id, feedback_id) - - if feedback == None: - return "", 404 - else: - return "", 200 + return wrap_response(*projectController.delete_feedback(user_id=get_jwt_identity(), feedback_id=feedback_id)) From 0937e9aa3727b154cafde41ef73e491e66642aa0 Mon Sep 17 00:00:00 2001 From: petak5 Date: Thu, 9 Jul 2020 22:05:45 +0200 Subject: [PATCH 24/36] Rename user_id to author_id in ProjectFeedback --- src/api/controllers/projectController.py | 12 ++++++------ src/api/models/projectFeedbackModel.py | 4 ++-- src/api/views/projectView.py | 12 ++++++------ 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/api/controllers/projectController.py b/src/api/controllers/projectController.py index db642d8..6d222a4 100644 --- a/src/api/controllers/projectController.py +++ b/src/api/controllers/projectController.py @@ -162,7 +162,7 @@ def delete_link(self, user_id, **kwargs): return None, "Forbidden attributes used in request. Only 'project_id' and 'link' object containing 'id' allowed.", 400 # Project Feedback - def create_feedback(self, user_id, **kwargs): + def create_feedback(self, author_id, **kwargs): if 'project_id' not in kwargs: return None, "Failed to create feedback. Request body must specify feedback's project_id.", 400 @@ -171,7 +171,7 @@ def create_feedback(self, user_id, **kwargs): if kwargs["project_id"] is None or kwargs["rating"] is None or kwargs["description"] is None: return None, "Arguments can't be empty", 400 - feedback = ProjectFeedback(user_id=user_id, **kwargs) + feedback = ProjectFeedback(author_id=author_id, **kwargs) self.session.add(feedback) self.session.commit() @@ -182,15 +182,15 @@ def create_feedback(self, user_id, **kwargs): self.session.rollback() return None, "Failed to create project feedback.", 400 - def delete_feedback(self, user_id, feedback_id): + def delete_feedback(self, author_id, feedback_id): feedback = ProjectFeedback.query.filter_by(id=feedback_id).first() - if feedback.user_id != user_id: - return None, "Failed to delete project feedback. Cannot delete project feedback that you did not create.", 400 - if feedback == None: return None, "Failed to delete project feedback. Project feedback not found.", 404 + if feedback.author_id != author_id: + return None, "Failed to delete project feedback. Cannot delete project feedback that you did not create.", 400 + db.session.delete(feedback) db.session.commit() diff --git a/src/api/models/projectFeedbackModel.py b/src/api/models/projectFeedbackModel.py index 19f484e..db1c7dd 100644 --- a/src/api/models/projectFeedbackModel.py +++ b/src/api/models/projectFeedbackModel.py @@ -2,7 +2,7 @@ class ProjectFeedback(db.Model): id = db.Column(db.Integer, primary_key=True) - user_id = db.Column(db.Integer, db.ForeignKey('user.id')) + author_id = db.Column(db.Integer, db.ForeignKey('user.id')) project_id = db.Column(db.Integer, db.ForeignKey('project.id')) rating = db.Column(db.Integer, nullable=False) description = db.Column(db.String(255), nullable=True) @@ -10,7 +10,7 @@ class ProjectFeedback(db.Model): def as_dict(self): obj_d = { 'id': self.id, - 'user_id': self.user_id, + 'author_id': self.author_id, 'project_id': self.project_id, 'rating': self.rating, 'description': self.description, diff --git a/src/api/views/projectView.py b/src/api/views/projectView.py index 0b1597a..003509a 100644 --- a/src/api/views/projectView.py +++ b/src/api/views/projectView.py @@ -312,9 +312,9 @@ def create_project_feedback(): id: type: integer description: Id of the project feedback. This property will be assigned a value returned by the database - user_id: + author_id: type: integer - description: Id of the user + description: Id of the author (user) project_id: type: integer description: Id of the project @@ -330,10 +330,10 @@ def create_project_feedback(): 400: description: Failed to create project feedback """ - if "user_id" in request.get_json(): - return wrap_response(None, "Failed to create project feedback. Request body must not contain 'user_id'.", 400) + if "author_id" in request.get_json(): + return wrap_response(None, "Failed to create project feedback. Request body must not contain 'author_id'.", 400) - return wrap_response(*projectController.create_feedback(user_id=get_jwt_identity(), **request.get_json())) + return wrap_response(*projectController.create_feedback(author_id=get_jwt_identity(), **request.get_json())) @app.route("/project/feedback/", methods=['DELETE']) @jwt_required @@ -358,4 +358,4 @@ def delete_project_feedback(feedback_id): 404: description: Project feedback not found """ - return wrap_response(*projectController.delete_feedback(user_id=get_jwt_identity(), feedback_id=feedback_id)) + return wrap_response(*projectController.delete_feedback(author_id=get_jwt_identity(), feedback_id=feedback_id)) From a25807f0d5926b0ef18f44f582efc610c4fd6151 Mon Sep 17 00:00:00 2001 From: petak5 Date: Thu, 9 Jul 2020 22:20:08 +0200 Subject: [PATCH 25/36] Get link_id from path in delete project feedback route --- src/api/controllers/projectController.py | 20 +++++++------------- src/api/views/projectView.py | 19 +++++-------------- 2 files changed, 12 insertions(+), 27 deletions(-) diff --git a/src/api/controllers/projectController.py b/src/api/controllers/projectController.py index 6d222a4..bd02882 100644 --- a/src/api/controllers/projectController.py +++ b/src/api/controllers/projectController.py @@ -144,22 +144,16 @@ def update_link(self, user_id, **kwargs): else: return None, "Forbidden attributes used in request. Only 'project_id' and 'link' object containing 'id', 'name' and 'url' allowed.", 400 - def delete_link(self, user_id, **kwargs): - if "project_id" in kwargs and "link" in kwargs and "id" in kwargs["link"] and len(kwargs) == 2 and len(kwargs["link"]) == 1: - if kwargs["project_id"] is None or kwargs["link"]["id"] is None: - return None, "Arguments can't be empty", 400 + def delete_link(self, user_id, link_id): + link = ProjectLink.query.filter_by(id=link_id).first() - link = ProjectLink.query.filter_by(project_id=kwargs["project_id"], id=kwargs["link"]["id"]).first() - - if link == None: - return None, "Failed to delete project link. Project link not found.", 404 + if link == None: + return None, "Failed to delete project link. Project link not found.", 404 - db.session.delete(link) - db.session.commit() + db.session.delete(link) + db.session.commit() - return link, "OK", 200 - else: - return None, "Forbidden attributes used in request. Only 'project_id' and 'link' object containing 'id' allowed.", 400 + return link, "OK", 200 # Project Feedback def create_feedback(self, author_id, **kwargs): diff --git a/src/api/views/projectView.py b/src/api/views/projectView.py index 003509a..7d18d43 100644 --- a/src/api/views/projectView.py +++ b/src/api/views/projectView.py @@ -254,23 +254,17 @@ def update_project_link(): return wrap_response(*projectController.update_link(user_id=get_jwt_identity(), **request.get_json())) -@app.route("/project/link", methods=['DELETE']) +@app.route("/project/link/", methods=['DELETE']) @jwt_required -@body_required -def delete_project_link(): +def delete_project_link(link_id): """ Delete project link - Deletes project link with data in the request body + Deletes project link with `link_id` --- tags: - ProjectLink parameters: - - in: body - name: project_id - type: integer - required: true - description: Id of the project - - in: body + - in: path name: link_id type: integer required: true @@ -283,10 +277,7 @@ def delete_project_link(): 404: description: Project link not found """ - if "user_id" in request.get_json(): - return wrap_response(None, "Failed to delete project link. Request body must not contain 'user_id'.", 400) - - return wrap_response(*projectController.delete_link(user_id=get_jwt_identity(), **request.get_json())) + return wrap_response(*projectController.delete_link(user_id=get_jwt_identity(), link_id=link_id)) # Project Feedback @app.route("/project/feedback", methods=['POST']) From 056f7a0244b4371c354bf2c1371d37dfc0b838eb Mon Sep 17 00:00:00 2001 From: petak5 Date: Thu, 9 Jul 2020 22:26:12 +0200 Subject: [PATCH 26/36] Fix update project link route request body structure --- src/api/controllers/projectController.py | 12 ++++++------ src/api/views/projectView.py | 5 ----- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/api/controllers/projectController.py b/src/api/controllers/projectController.py index bd02882..ca31935 100644 --- a/src/api/controllers/projectController.py +++ b/src/api/controllers/projectController.py @@ -122,27 +122,27 @@ def create_link(self, user_id, **kwargs): return None, "Failed to create project link.", 400 def update_link(self, user_id, **kwargs): - if "project_id" in kwargs and "link" in kwargs and "id" in kwargs["link"] and len(kwargs) == 2: - if kwargs["project_id"] is None or kwargs["link"]["id"] is None: + if "project_id" in kwargs and "id" in kwargs and len(kwargs) >= 2: + if kwargs["project_id"] is None or kwargs["id"] is None: return None, "Arguments can't be empty", 400 - link = ProjectLink.query.filter_by(project_id=kwargs["project_id"], id=kwargs["link"]["id"]).first() + link = ProjectLink.query.filter_by(project_id=kwargs["project_id"], id=kwargs["id"]).first() if link == None: return None, "Failed to update project link. Project link not found.", 404 - for key, value in kwargs["link"].items(): + for key, value in kwargs.items(): if not hasattr(link, key): return None, f"Failed to update project link. Forbidden attribute '{key}'.", 400 - for key, value in kwargs["link"].items(): + for key, value in kwargs.items(): setattr(link, key, value) db.session.commit() return link, "OK", 200 else: - return None, "Forbidden attributes used in request. Only 'project_id' and 'link' object containing 'id', 'name' and 'url' allowed.", 400 + return None, "Forbidden attributes used in request. Only 'project_id', 'id', 'name' and 'url' allowed.", 400 def delete_link(self, user_id, link_id): link = ProjectLink.query.filter_by(id=link_id).first() diff --git a/src/api/views/projectView.py b/src/api/views/projectView.py index 7d18d43..51cc0a1 100644 --- a/src/api/views/projectView.py +++ b/src/api/views/projectView.py @@ -230,11 +230,6 @@ def update_project_link(): tags: - ProjectLink parameters: - - in: body - name: project_id - type: integer - required: true - description: Id of the project - in: body name: ProjectLink required: true From af528e2089b0966747a1b997d960b03eb986da82 Mon Sep 17 00:00:00 2001 From: petak5 Date: Thu, 9 Jul 2020 22:30:05 +0200 Subject: [PATCH 27/36] Fix create project link route request body structure --- src/api/controllers/projectController.py | 11 ++++------- src/api/views/projectView.py | 5 ----- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/api/controllers/projectController.py b/src/api/controllers/projectController.py index ca31935..27d5318 100644 --- a/src/api/controllers/projectController.py +++ b/src/api/controllers/projectController.py @@ -102,21 +102,18 @@ def delete_project(self, user_id, **kwargs): # Project Link def create_link(self, user_id, **kwargs): - if "project_id" not in kwargs: - return None, "Failed to create project link. Request body must specify link's 'project_id'.", 400 - try: - if "link" in kwargs and "project_id" in kwargs and "name" in kwargs["link"] and "url" in kwargs["link"] and len(kwargs) == 2: - if kwargs["link"]["name"] is None or kwargs["link"]["url"] is None or kwargs["project_id"] is None: + if "project_id" in kwargs and "name" in kwargs and "url" in kwargs and len(kwargs) == 3: + if kwargs["project_id"] is None or kwargs["name"] is None or kwargs["url"] is None: return None, "Arguments can't be empty", 400 - link = ProjectLink(project_id=kwargs["project_id"], **kwargs["link"]) + link = ProjectLink(**kwargs) self.session.add(link) self.session.commit() return link, "OK", 201 else: - return None, "Forbidden attributes used in request. Only 'project_id' and 'link' object containing 'name' and 'url' allowed.", 400 + return None, "Forbidden attributes used in request. Only 'project_id', 'name' and 'url' allowed.", 400 except: self.session.rollback() return None, "Failed to create project link.", 400 diff --git a/src/api/views/projectView.py b/src/api/views/projectView.py index 51cc0a1..0876e07 100644 --- a/src/api/views/projectView.py +++ b/src/api/views/projectView.py @@ -181,11 +181,6 @@ def create_project_link(): tags: - ProjectLink parameters: - - in: body - name: project_id - type: integer - required: true - description: Id of project for which link shall be created - in: body name: ProjectLink required: true From da079a9e64b8611e7b42250640b46412fd27d063 Mon Sep 17 00:00:00 2001 From: petak5 Date: Thu, 9 Jul 2020 22:38:13 +0200 Subject: [PATCH 28/36] Get project id from path in delete project route --- src/api/controllers/projectController.py | 17 +++++------------ src/api/views/projectView.py | 14 +++++--------- 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/src/api/controllers/projectController.py b/src/api/controllers/projectController.py index 07c6d99..b957bfc 100644 --- a/src/api/controllers/projectController.py +++ b/src/api/controllers/projectController.py @@ -68,29 +68,22 @@ def get_all_projects(self, **kwargs): return all_projects, "OK", 200 - def delete_project(self, user_id, **kwargs): - if len(kwargs) != 1: - return None, "Failed to delete project. Request body must contain only project's id.", 400 + def delete_project(self, user_id, id): - if 'id' not in kwargs: - return None, "Failed to delete project. Request body must specify project's id.", 400 - - project_id = kwargs["id"] - - userHasProject = UserHasProject.query.filter_by(user_id=user_id, project_id=project_id).first() + 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 # Remove all project's links - for link in ProjectLink.query.filter_by(project_id=project_id).all(): + for link in ProjectLink.query.filter_by(project_id=id).all(): db.session.delete(link) # Remove project from all users - for project in UserHasProject.query.filter_by(project_id=project_id).all(): + for project in UserHasProject.query.filter_by(project_id=id).all(): db.session.delete(project) - project = Project.query.filter_by(id=project_id).first() + project = Project.query.filter_by(id=id).first() if project == None: # TODO: db.session.rollback? diff --git a/src/api/views/projectView.py b/src/api/views/projectView.py index 339b60d..af20275 100644 --- a/src/api/views/projectView.py +++ b/src/api/views/projectView.py @@ -141,18 +141,17 @@ def get_all_projects(): """ return wrap_response(*projectController.get_all_projects()) -@app.route("/project", methods=['DELETE']) +@app.route("/project/", methods=['DELETE']) @jwt_required -@body_required -def delete_project(): +def delete_project(id): """ Delete project - Deletes current user's project with the id in request body + Deletes current user's project with the `id` --- tags: - Project parameters: - - in: body + - in: path name: id type: integer required: true @@ -165,10 +164,7 @@ def delete_project(): 404: description: Current user is not a member of requested project or the project was not found """ - if "user_id" in request.get_json(): - return wrap_response(None, "Failed to delete project. Request body must not contain 'user_id'.", 400) - - return wrap_response(*projectController.delete_project(user_id=get_jwt_identity(), **request.get_json())) + return wrap_response(*projectController.delete_project(user_id=get_jwt_identity(), id=id)) # Project Link @app.route("/projects//links", methods=['POST']) From 93196a56ad6756e82ce3165f67b6f64acda6d6ac Mon Sep 17 00:00:00 2001 From: petak5 Date: Thu, 9 Jul 2020 22:39:44 +0200 Subject: [PATCH 29/36] Change get project(s) routes to `/project/` and `/project/all` --- src/api/views/projectView.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/views/projectView.py b/src/api/views/projectView.py index af20275..ccb4bae 100644 --- a/src/api/views/projectView.py +++ b/src/api/views/projectView.py @@ -105,7 +105,7 @@ def update_project(): return wrap_response(*projectController.update_project(user_id=get_jwt_identity(), **request.get_json())) -@app.route("/projects/", methods=['GET']) +@app.route("/project/", methods=['GET']) def get_project(id): """ Get project @@ -127,7 +127,7 @@ def get_project(id): """ return wrap_response(*projectController.get_project(id=id)) -@app.route("/projects", methods=['GET']) +@app.route("/project/all", methods=['GET']) def get_all_projects(): """ Get all projects From 51f91a2160d74cab66308257ef6d292cb813e9fc Mon Sep 17 00:00:00 2001 From: petak5 Date: Thu, 9 Jul 2020 22:46:06 +0200 Subject: [PATCH 30/36] Merge branch 'develop' into routes_project_refactor --- tests/api/views/test_projectView.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/api/views/test_projectView.py b/tests/api/views/test_projectView.py index 2dfa574..b204af7 100644 --- a/tests/api/views/test_projectView.py +++ b/tests/api/views/test_projectView.py @@ -120,9 +120,11 @@ def test_update_project_link(self, client): assert response.get_json()["name"] == "Nlink" def test_delete_project_link(self, client): - url = '/projects/{0}/links/{1}' + token, _ = create_access_token_for_test_cases(self.valid_user_data) + + url = '/project/link' - response = client.delete(url.format(0, 0)) + response = client.delete(url, headers={"Authorization": f"Bearer {token}"}, json={"project_id": 0, "id": 0}) assert response.status_code == 404 p1 = create_project_for_test_cases(self.valid_project_data) @@ -140,7 +142,7 @@ def test_delete_project_link(self, client): }) - response = client.delete(url.format(p1["id"], p_link1["id"])) + response = client.delete(url, headers={"Authorization": f"Bearer {token}"}, json={"project_id": p1["id"], "id": p_link1["id"]}) assert response.status_code == 200 items = ProjectLink.query.all() assert len(items) == 1 From 13c9edc9ba3ead5330ed9fd64d243c2ea8641301 Mon Sep 17 00:00:00 2001 From: petak5 Date: Thu, 9 Jul 2020 23:01:59 +0200 Subject: [PATCH 31/36] Fix changed get project(s) route URL path in test --- tests/api/views/test_projectView.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/api/views/test_projectView.py b/tests/api/views/test_projectView.py index b204af7..efc9299 100644 --- a/tests/api/views/test_projectView.py +++ b/tests/api/views/test_projectView.py @@ -67,11 +67,11 @@ def test_delete_project(self, client): assert response.status_code == 200 def test_get_project(self, client): - response = client.get('/projects/{}'.format(0)) + response = client.get('/project/{}'.format(0)) assert response.status_code == 404 project = create_project_for_test_cases(self.valid_project_data) - response = client.get('/projects/{}'.format(project["id"])) + response = client.get('/project/{}'.format(project["id"])) assert response.status_code == 200 assert response.get_json()["data"]["name"] == project["name"] @@ -80,7 +80,7 @@ def test_get_all_projects(self, client): self.valid_project_data["name"] = "allproject2" project2 = create_project_for_test_cases(self.valid_project_data) - response = client.get('/projects') + response = client.get('/project/all') assert response.status_code == 200 r = response.get_json() From 837cce50a9947227b91da26c3221e587c1fde501 Mon Sep 17 00:00:00 2001 From: petak5 Date: Thu, 9 Jul 2020 23:14:08 +0200 Subject: [PATCH 32/36] Fix changed delete project route URL path in test --- tests/api/views/test_projectView.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/api/views/test_projectView.py b/tests/api/views/test_projectView.py index efc9299..e634257 100644 --- a/tests/api/views/test_projectView.py +++ b/tests/api/views/test_projectView.py @@ -53,7 +53,7 @@ def test_update_project(self, client): def test_delete_project(self, client): token, user = create_access_token_for_test_cases(self.valid_user_data) - response = client.delete('/project', headers={"Authorization": f"Bearer {token}"}, json={"id": 0}) + response = client.delete('/project/{}'.format(0), headers={"Authorization": f"Bearer {token}"}) assert response.status_code == 404 project1 = create_project_for_test_cases(self.valid_project_data) @@ -63,7 +63,7 @@ def test_delete_project(self, client): project2 = create_project_for_test_cases(self.valid_project_data) user_join_project_for_test_cases(user, project2) - response = client.delete('/project', headers={"Authorization": f"Bearer {token}"}, json={"id": project1["id"]}) + response = client.delete('/project/{}'.format(project1["id"]), headers={"Authorization": f"Bearer {token}"}) assert response.status_code == 200 def test_get_project(self, client): From e1495600d65ffe2ba106c04fdee23ec9c6ce933e Mon Sep 17 00:00:00 2001 From: petak5 Date: Thu, 9 Jul 2020 23:22:31 +0200 Subject: [PATCH 33/36] Fix create project link test --- tests/api/views/test_projectView.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/api/views/test_projectView.py b/tests/api/views/test_projectView.py index e634257..29f5571 100644 --- a/tests/api/views/test_projectView.py +++ b/tests/api/views/test_projectView.py @@ -87,13 +87,15 @@ def test_get_all_projects(self, client): assert [r["data"][0]["name"], r["data"][1]["name"]] == [project1["name"], project2["name"]] def test_create_project_link(self, client): + token, _ = create_access_token_for_test_cases(self.valid_user_data) + project = create_project_for_test_cases(self.valid_project_data) - url = '/projects/{}/links'.format(project["id"]) + url = '/project/link' - response = client.post(url, json={"user_id": 0}) + response = client.post(url, headers={"Authorization": f"Bearer {token}"}, json={"user_id": 0}) assert response.status_code == 400 - response = client.post(url, json={"name": "Main link", "url": "http://main.link"}) + response = client.post(url, headers={"Authorization": f"Bearer {token}"}, json={"project_id": project["id"], "name": "Main link", "url": "http://main.link"}) assert response.status_code == 201 def test_update_project_link(self, client): From 43db39bcb364e937f259d152e5bf573dc3ceacf5 Mon Sep 17 00:00:00 2001 From: petak5 Date: Thu, 9 Jul 2020 23:32:19 +0200 Subject: [PATCH 34/36] Fix update project link test --- tests/api/views/test_projectView.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/api/views/test_projectView.py b/tests/api/views/test_projectView.py index 29f5571..984c886 100644 --- a/tests/api/views/test_projectView.py +++ b/tests/api/views/test_projectView.py @@ -99,6 +99,8 @@ def test_create_project_link(self, client): assert response.status_code == 201 def test_update_project_link(self, client): + token, _ = create_access_token_for_test_cases(self.valid_user_data) + p1 = create_project_for_test_cases(self.valid_project_data) p1_link = create_project_link_for_test_cases( { @@ -107,19 +109,17 @@ def test_update_project_link(self, client): "project_id": p1["id"] }) - url = '/projects/{0}/links/{1}' + url = '/project/link' - # notice: this shouldn't give 500 error - # response = client.post(url.format(p1["id"], 0)) - # assert response.status_code == 404 + response = client.put(url, headers={"Authorization": f"Bearer {token}"}, json={"project_id": p1["id"], "id": 0}) + assert response.status_code == 404 - # notice: this shouldn't give 500 error - # response = client.post(url.format(0, p1_link["id"])) - # assert response.status_code == 404 + response = client.put(url, headers={"Authorization": f"Bearer {token}"}, json={"project_id": 0, "id": p1_link["id"]}) + assert response.status_code == 404 - response = client.post(url.format(p1["id"], p1_link["id"]), json={"name": "Nlink"}) + response = client.put(url, headers={"Authorization": f"Bearer {token}"}, json={"project_id": p1["id"], "id": p1_link["id"], "name": "Nlink"}) assert response.status_code == 200 - assert response.get_json()["name"] == "Nlink" + assert response.get_json()["data"]["name"] == "Nlink" def test_delete_project_link(self, client): token, _ = create_access_token_for_test_cases(self.valid_user_data) From 6ad32de2a1560bfb4f72befabcdb28ea0bb08903 Mon Sep 17 00:00:00 2001 From: petak5 Date: Fri, 10 Jul 2020 07:17:39 +0200 Subject: [PATCH 35/36] Fix delete project link test --- tests/api/views/test_projectView.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/api/views/test_projectView.py b/tests/api/views/test_projectView.py index 984c886..ef558a7 100644 --- a/tests/api/views/test_projectView.py +++ b/tests/api/views/test_projectView.py @@ -124,9 +124,9 @@ def test_update_project_link(self, client): def test_delete_project_link(self, client): token, _ = create_access_token_for_test_cases(self.valid_user_data) - url = '/project/link' + url = '/project/link/{}' - response = client.delete(url, headers={"Authorization": f"Bearer {token}"}, json={"project_id": 0, "id": 0}) + response = client.delete(url.format(0), headers={"Authorization": f"Bearer {token}"}) assert response.status_code == 404 p1 = create_project_for_test_cases(self.valid_project_data) @@ -144,7 +144,7 @@ def test_delete_project_link(self, client): }) - response = client.delete(url, headers={"Authorization": f"Bearer {token}"}, json={"project_id": p1["id"], "id": p_link1["id"]}) + response = client.delete(url.format(p_link1["id"]), headers={"Authorization": f"Bearer {token}"}) assert response.status_code == 200 items = ProjectLink.query.all() assert len(items) == 1 From 336a61154311c289596ead7b011399a228525466 Mon Sep 17 00:00:00 2001 From: petak5 Date: Fri, 10 Jul 2020 07:40:47 +0200 Subject: [PATCH 36/36] Add project feedback tests --- tests/api/__init__.py | 9 +++++- tests/api/views/test_projectView.py | 50 +++++++++++++++++++++++++++-- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/tests/api/__init__.py b/tests/api/__init__.py index 814b07e..db64e86 100644 --- a/tests/api/__init__.py +++ b/tests/api/__init__.py @@ -11,7 +11,7 @@ """ from flask_jwt_extended import create_access_token -from tests import db, Project, User, UserHasProject, UserLink, ProjectLink, UserFeedback +from tests import db, Project, User, UserHasProject, UserLink, ProjectLink, UserFeedback, ProjectFeedback """ Create relationship between user and project """ def user_join_project_for_test_cases(user, project): @@ -41,6 +41,13 @@ def create_project_link_for_test_cases(data): return new_project_link.as_dict() +def create_project_feedback_for_test_cases(data): + new_project_feedback = ProjectFeedback(**data) + db.session.add(new_project_feedback) + db.session.commit() + + return new_project_feedback.as_dict() + def create_access_token_for_test_cases(data): new_user = User(**data) db.session.add(new_user) diff --git a/tests/api/views/test_projectView.py b/tests/api/views/test_projectView.py index ef558a7..4d58672 100644 --- a/tests/api/views/test_projectView.py +++ b/tests/api/views/test_projectView.py @@ -1,6 +1,6 @@ from tests.conftest import client -from tests import db, Project, ProjectLink -from tests.api import create_project_for_test_cases, create_project_link_for_test_cases, create_access_token_for_test_cases, user_join_project_for_test_cases +from tests import db, Project, ProjectLink, ProjectFeedback +from tests.api import create_project_for_test_cases, create_project_link_for_test_cases, create_project_feedback_for_test_cases, create_access_token_for_test_cases, user_join_project_for_test_cases class TestProjectView(object): @@ -21,6 +21,7 @@ class TestProjectView(object): 'repository': 'http://github.xy.com' } + # Project def test_create_project(self, client): token, _ = create_access_token_for_test_cases(self.valid_user_data) @@ -86,6 +87,7 @@ def test_get_all_projects(self, client): r = response.get_json() assert [r["data"][0]["name"], r["data"][1]["name"]] == [project1["name"], project2["name"]] + # Project Link def test_create_project_link(self, client): token, _ = create_access_token_for_test_cases(self.valid_user_data) @@ -149,3 +151,47 @@ def test_delete_project_link(self, client): items = ProjectLink.query.all() assert len(items) == 1 assert items[0].name == "Other" + + # Projet Feedback + def test_create_project_feedback(self, client): + token, user = create_access_token_for_test_cases(self.valid_user_data) + + project = create_project_for_test_cases(self.valid_project_data) + url = '/project/feedback' + + response = client.post(url, headers={"Authorization": f"Bearer {token}"}, json={"user_id": 0}) + assert response.status_code == 400 + + response = client.post(url, headers={"Authorization": f"Bearer {token}"}, json={"project_id": project["id"], "rating": 3, "description": "A feedback"}) + assert response.status_code == 201 + + def test_delete_project_feedback(self, client): + token, user = create_access_token_for_test_cases(self.valid_user_data) + + url = '/project/feedback/{}' + + response = client.delete(url.format(0), headers={"Authorization": f"Bearer {token}"}) + assert response.status_code == 404 + + p1 = create_project_for_test_cases(self.valid_project_data) + p_feedback1 = create_project_feedback_for_test_cases( + { + "rating": 1, + "description": "A feedback", + "project_id": p1["id"], + "author_id": user.id + }) + p_feedback2 = create_project_feedback_for_test_cases( + { + "rating": 5, + "description": "Other", + "project_id": p1["id"], + "author_id": user.id + }) + + + response = client.delete(url.format(p_feedback1["id"]), headers={"Authorization": f"Bearer {token}"}) + assert response.status_code == 200 + items = ProjectFeedback.query.all() + assert len(items) == 1 + assert items[0].description == "Other"