From 59c42422b5d79d6a12628010c8a58026d2b0701e Mon Sep 17 00:00:00 2001 From: Timur Demin Date: Tue, 11 Jun 2019 22:57:20 +0500 Subject: [PATCH] Add the API to work with tasks --- project_amber/app.py | 9 ++++- project_amber/handlers/task.py | 69 ++++++++++++++++++++++++++++++---- project_amber/helpers/task.py | 39 ++++++++++++++----- project_amber/models/task.py | 5 ++- 4 files changed, 103 insertions(+), 19 deletions(-) diff --git a/project_amber/app.py b/project_amber/app.py index a2d347a..7e1c771 100644 --- a/project_amber/app.py +++ b/project_amber/app.py @@ -6,6 +6,8 @@ from project_amber.db import db from project_amber.errors import HTTPError from project_amber.handlers.auth import login, logout, login_check +from project_amber.handlers.task import handle_task_id_request, \ + handle_task_request from project_amber.handlers.users import signup app = Flask(__name__) @@ -14,8 +16,13 @@ app.add_url_rule("/api/login", "login", login, methods=["POST"]) app.add_url_rule("/api/logout", "logout", logout, methods=["POST"]) -app.add_url_rule("/api/login_check", "login_check", login_check, methods=["GET"]) +app.add_url_rule("/api/login_check", "login_check", login_check, \ + methods=["GET"]) app.add_url_rule("/api/signup", "signup", signup, methods=["POST"]) +app.add_url_rule("/api/task", "task", handle_task_request, \ + methods=["GET", "POST"]) +app.add_url_rule("/api/task/", "task_id", handle_task_id_request, \ + methods=["GET", "PATCH", "DELETE"]) @app.before_first_request def create_tables(): diff --git a/project_amber/handlers/task.py b/project_amber/handlers/task.py index 28fe22f..28b8703 100644 --- a/project_amber/handlers/task.py +++ b/project_amber/handlers/task.py @@ -3,8 +3,10 @@ from flask import request from project_amber.const import EMPTY_RESP +from project_amber.errors import BadRequest from project_amber.helpers.auth import handleChecks -from project_amber.helpers.task import addTask, updateTask, removeTask +from project_amber.helpers.task import addTask, getTask, getTasks, \ + updateTask, removeTask def handle_task_request(): """ @@ -18,11 +20,13 @@ def handle_task_request(): { "id": 123, "text": "Some task", + "status:": 1, "last_mod": 12345 // timestamp }, { "id": 456, "text": "Some text", + "status": 0, "last_mod": 12346 } ] @@ -34,21 +38,72 @@ def handle_task_request(): "text": "Some task" } ``` + with a task ID. """ user = handleChecks() if request.method == "GET": - pass - elif request.method == "POST": - pass + query = None + if "query" in request.json: + query = request.json["query"] + tasks = getTasks(user.id, query) + tasksList = [] + for task in tasks: + tasksList.append({ + "id": task.id, + "text": task.text, + "status": task.status, + "last_mod": task.last_mod_time + }) + return dumps({ + "tasks": tasksList + }) + if request.method == "POST": + if not "text" in request.json: + raise BadRequest("No text specified") + text = request.json["text"] + new_id = addTask(text, user.id) + return dumps({ "id": new_id }) def handle_task_id_request(task_id: int): """ Handles requests to `/api/task/`. Accepts GET, PATCH, and DELETE. + On GET, the user gets this response with HTTP 200 (or 404, if the task + does not exist): + ``` + { + "id": 1, + "text": "Some text", + "status": 1, + "last_mod": 123456 // timestamp + } + ``` + On PATCH and DELETE the user will get HTTP 200 with an empty response. On + PATCH, this request body is expected (all of the parameters are optional): + ``` + { + "text": "New task text", + "status": 1 // new status + } + ``` """ user = handleChecks() if request.method == "GET": - pass + task = getTask(task_id, user.id) + return dumps({ + "id": task.id, + "text": task.text, + "status": task.status, + "last_mod": task.last_mod_time + }) elif request.method == "PATCH": - pass + text = None + status = None + if "text" in request.json: + text = request.json["text"] + if "status" in request.json: + status = request.json["status"] + updateTask(task_id, user.id, text=text, status=status) + return EMPTY_RESP elif request.method == "DELETE": - pass + removeTask(task_id, user.id) + return EMPTY_RESP diff --git a/project_amber/helpers/task.py b/project_amber/helpers/task.py index 909545a..b08c88f 100644 --- a/project_amber/helpers/task.py +++ b/project_amber/helpers/task.py @@ -5,36 +5,57 @@ from project_amber.errors import NotFound from project_amber.models.task import Task -def addTask(text: str, uid: int) -> int: +def addTask(text: str, uid: int, **kwargs) -> int: """ Creates a new task. Returns its ID. """ + status = 0 + if "status" in kwargs: + status = kwargs["status"] task = Task(owner=uid, text=text, creation_time=time(), \ - last_mod_time=time()) + last_mod_time=time(), status=status) db.session.add(task) db.session.commit() return task.id -def updateTask(new_text: str, task_id: int, uid: int) -> int: +def getTask(task_id: int, uid: int) -> Task: """ - Updates the task text. Returns its ID. + Returns an instance of `Task`, given the ID and the owner UID. """ task = db.session.query(Task).filter_by(id=task_id, owner=uid).one_or_none() if task is None: raise NotFound(MSG_TASK_NOT_FOUND) - task.text = new_text + return task + +def getTasks(uid: int, text: str = None) -> list: + """ + Returns a list containing tasks from a certain user. If the second + parameter is specified, this will return the tasks that have this text in + their description (`text in Task.text`). + """ + req = db.session.query(Task).filter_by(owner=uid) + if text is None: + return req.all() + return req.filter(text in Task.text).all() + +def updateTask(task_id: int, uid: int, **kwargs) -> int: + """ + Updates the task details. Returns its ID. + """ + task = getTask(task_id, uid) + if "text" in kwargs and not kwargs["text"] is None: + task.text = kwargs["text"] + if "status" in kwargs and not kwargs["status"] is None: + task.status = kwargs["status"] task.last_mod_time = time() db.session.commit() return task_id - def removeTask(task_id: int, uid: int) -> int: """ Removes a task. Returns its ID on success. """ - task = db.session.query(Task).filter_by(id=task_id, owner=uid).one_or_none() - if task is None: - raise NotFound(MSG_TASK_NOT_FOUND) + task = getTask(task_id, uid) db.session.delete(task) db.session.commit() return task_id diff --git a/project_amber/models/task.py b/project_amber/models/task.py index f0d34f3..475de28 100644 --- a/project_amber/models/task.py +++ b/project_amber/models/task.py @@ -8,8 +8,9 @@ class Task(db.Model): id = db.Column(db.Integer, primary_key=True) owner = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False) text = db.Column(db.String(65536)) # TODO: probably subject to increase + status = db.Column(db.Integer, nullable=False) creation_time = db.Column(db.Integer, nullable=False) last_mod_time = db.Column(db.Integer, nullable=False) def __repr__(self): - return "" \ - % self.id, self.owner, self.text, self.creation_time + return "" \ + % self.id, self.owner, self.text, self.status, self.creation_time