diff --git a/code/backend/nest_backend/__main__.py b/code/backend/nest_backend/__main__.py index bb8b1e1..2b32c79 100644 --- a/code/backend/nest_backend/__main__.py +++ b/code/backend/nest_backend/__main__.py @@ -33,6 +33,11 @@ app.config['CORS_HEADERS'] = 'Content-Type' app.add_url_rule("/doa", view_func=page_doa, methods=["GET", "POST"]) app.add_url_rule("/api/login", view_func=page_login, methods=["POST"]) app.add_url_rule("/api/user/create", view_func=page_user_create, methods=["POST"]) +app.add_url_rule("/api/user/remove", view_func=page_user_delete, methods=["POST"]) +app.add_url_rule("/api/repository/list", view_func=page_repository_list, methods=["POST"]) +app.add_url_rule("/api/repository/create", view_func=page_repository_create, methods=["POST"]) +app.add_url_rule("/api/repository/edit", view_func=page_repository_edit, methods=["POST"]) +app.add_url_rule("/api/repository/add_condition", view_func=page_repository_add_condition, methods=["POST"]) if __name__ == "__main__": Base.create_all() diff --git a/code/backend/nest_backend/database/tables/Repository.py b/code/backend/nest_backend/database/tables/Repository.py index d01c1ed..7089a73 100644 --- a/code/backend/nest_backend/database/tables/Repository.py +++ b/code/backend/nest_backend/database/tables/Repository.py @@ -9,8 +9,9 @@ class Repository(Base.Model): __tablename__ = "repository" id = Base.Column(Base.Integer, primary_key=True) name = Base.Column(Base.String, nullable=False) - start = Base.Column(Base.DateTime, nullable=False) + start = Base.Column(Base.DateTime, nullable=True) end = Base.Column(Base.DateTime, nullable=True) + isActive = Base.Column(Base.Boolean, nullable=False, default=False) # Foreign Keys owner_id = Base.Column(Base.String, Base.ForeignKey("user.email"), nullable=False) # Relationships diff --git a/code/backend/nest_backend/database/tables/__init__.py b/code/backend/nest_backend/database/tables/__init__.py index 1b80d7b..1408a55 100644 --- a/code/backend/nest_backend/database/tables/__init__.py +++ b/code/backend/nest_backend/database/tables/__init__.py @@ -13,3 +13,4 @@ from .Repository import Repository from .Tweet import Tweet from .User import User from .Uses import Uses +from .Enums import ConditionType, OperationType \ No newline at end of file diff --git a/code/backend/nest_backend/gestione.py b/code/backend/nest_backend/gestione.py index 170d630..02c1afa 100644 --- a/code/backend/nest_backend/gestione.py +++ b/code/backend/nest_backend/gestione.py @@ -9,6 +9,7 @@ from .database import * import bcrypt import functools from flask_jwt_extended import get_jwt_identity +from flask import request, jsonify def authenticate(username, password): @@ -60,4 +61,21 @@ def admin_or_403(f): current_user = get_jwt_identity() return f(*args, **kwargs) + return func + + +def repository_auth(f): + @functools.wraps(f) + def func(*args, **kwargs): + user = find_user(get_jwt_identity()) + repository_id = request.json.get("id") + if not repository_id: + return jsonify({"result": "failure", "msg": "Missing one or more parameters."}), 400 + repository = Repository.query.filter_by(id=repository_id) + if not repository: + return jsonify({"result": "failure", "msg": "Can't find repository."}), 404 + if repository.owner_id != user.email: + return jsonify({"result": "failure", + "msg": "Stop right there, criminal scum! Nobody accesses protected data under MY watch!"}), 403 + return f(*args, **kwargs) return func \ No newline at end of file diff --git a/code/backend/nest_backend/routes/__init__.py b/code/backend/nest_backend/routes/__init__.py index 6752c31..1424720 100644 --- a/code/backend/nest_backend/routes/__init__.py +++ b/code/backend/nest_backend/routes/__init__.py @@ -3,4 +3,5 @@ This module imports all the routes that return something to the frontend. """ from .doa import page_doa -from .users import * \ No newline at end of file +from .users import * +from .repository import * diff --git a/code/backend/nest_backend/routes/repository/__init__.py b/code/backend/nest_backend/routes/repository/__init__.py index e69de29..66d676a 100644 --- a/code/backend/nest_backend/routes/repository/__init__.py +++ b/code/backend/nest_backend/routes/repository/__init__.py @@ -0,0 +1,4 @@ +from .repository_add_condition import page_repository_add_condition +from .repository_edit import page_repository_edit +from .repository_create import page_repository_create +from .repository_list import page_repository_list \ No newline at end of file diff --git a/code/backend/nest_backend/routes/repository/repository_add_condition.py b/code/backend/nest_backend/routes/repository/repository_add_condition.py new file mode 100644 index 0000000..8b8439d --- /dev/null +++ b/code/backend/nest_backend/routes/repository/repository_add_condition.py @@ -0,0 +1,34 @@ +from flask import render_template, abort, jsonify, request +from ...database import * +from flask_jwt_extended import jwt_required +from ...gestione import * +from flask_cors import cross_origin + + +@cross_origin() +@jwt_required() +@repository_auth +def page_repository_add_condition(): + """ + API call that allows to add conditions to a repository. + :form id: Repository ID + :form type: The type of the condition. It can either be an 'hashtag', a 'location' or 'time' + :form content: The content of the condition (#PdS2021, Roma, 18:00) + :returns: a JSON string that tells whether or not the procedure was a success. + """ + type = request.json.get("type") + if not type or type not in dir(ConditionType): + return jsonify({"result": "failure", "msg": "Could not understand the type of the condition."}), 400 + content = request.json.get("content") + if not content: + return jsonify({"result": "failure", "msg": "Could not find the content"}), 400 + condition = Condition.query.filter(Condition.content.ilike(str(content))).filter_by(type=ConditionType.__getattr__(str(type)).value).first() + if not condition: + condition = Condition(content=content, type=ConditionType.__getattr__(str(type)).value) + Base.session.add(condition) + repository = Repository.query.filter_by(request.json.get("id")) + if Uses.query.filter_by(cid=condition.id, rid=repository.id): + return jsonify({"result": "failure", "msg": "This condition is already connected to the repository."}), 406 + Base.session.add(Uses(cid=condition.id, rid=repository.id)) + Base.session.commit() + return jsonify({"result": "success", "content": "Condition added successfully."}), 200 \ No newline at end of file diff --git a/code/backend/nest_backend/routes/repository/repository_create.py b/code/backend/nest_backend/routes/repository/repository_create.py index c96264b..820c3e4 100644 --- a/code/backend/nest_backend/routes/repository/repository_create.py +++ b/code/backend/nest_backend/routes/repository/repository_create.py @@ -12,13 +12,14 @@ def page_repository_create(): """ API call that allows an user to create a new repository. :form name: The name of the repository. - :returns: If the user is logged in and + :returns: If the user is logged in and has provided the repository name, a JSON string is returned containing + the return status of the operation and the repository in json format. """ user = find_user(get_jwt_identity()) name = request.json.get("name") if not name: - return jsonify({"result": "failure", "msg": "Missing one or more parameters"}), 40 - repository = Repository(name=name, start=datetime.datetime.now(), owner_id=user.email) + return jsonify({"result": "failure", "msg": "Missing one or more parameters"}), 400 + repository = Repository(name=name, owner_id=user.email) Base.session.add(repository) Base.session.commit() - return jsonify({"result":"success", "content":repository.to_json()}), 200 \ No newline at end of file + return jsonify({"result": "success", "content": repository.to_json()}), 200 diff --git a/code/backend/nest_backend/routes/repository/repository_edit.py b/code/backend/nest_backend/routes/repository/repository_edit.py new file mode 100644 index 0000000..527bd5e --- /dev/null +++ b/code/backend/nest_backend/routes/repository/repository_edit.py @@ -0,0 +1,28 @@ +from flask import render_template, abort, jsonify, request +from ...database import * +from flask_jwt_extended import jwt_required +from ...gestione import * +from flask_cors import cross_origin +import datetime + + +@cross_origin() +@jwt_required() +@repository_auth +def page_repository_edit(): + """ + This API call allows to edit a repository. + :form name: If present, it changes the repository name. + :form close: If present, it closes the repository. + :returns: A JSON formatted string that either contains an error or the updated representation of the repository. + """ + repository = Repository.query.filter_by(id=request.json['id']) + if 'name' in request.json: + repository.name = request.json['name'] + if 'close' in request.json and not repository.end and repository.isActive: + repository.end = datetime.datetime.now() + repository.isActive = False + if 'open' in request.json and not repository.isActive and not repository.end: + repository.isActive = True + Base.session.commit() + return jsonify({"result": "success", "content":repository.to_json()}) \ No newline at end of file diff --git a/code/backend/nest_backend/routes/repository/repository_list.py b/code/backend/nest_backend/routes/repository/repository_list.py new file mode 100644 index 0000000..534fe6e --- /dev/null +++ b/code/backend/nest_backend/routes/repository/repository_list.py @@ -0,0 +1,18 @@ +from flask import render_template, abort, jsonify, request +from ...database import * +from flask_jwt_extended import jwt_required +from ...gestione import * +from flask_cors import cross_origin + + +@cross_origin() +@jwt_required() +def page_repository_list(): + """ + API call that returns the list of repositories. + :returns: a JSON-formatted string that contains under the "content" field the list of repositories that belong to + the user ("owner") and a list of repositories that he can spectate ("spectator"). + """ + user = find_user(get_jwt_identity()) + return {"result": "success", "content": {"owner": [r.to_json() for r in user.owner_of], + "spectator": [r.repository.to_json() for r in user.authorizations]}}