From 3119a77963f1780b64f8461520b141f465f2eaa2 Mon Sep 17 00:00:00 2001 From: Timur Demin Date: Fri, 27 Dec 2019 19:01:43 +0500 Subject: [PATCH] Use blueprints instead of manually adding URI rules --- project_amber/app.py | 40 ++++++++++--------------------- project_amber/const.py | 1 + project_amber/handlers/auth.py | 6 ++++- project_amber/handlers/const.py | 2 ++ project_amber/handlers/misc.py | 5 ++++ project_amber/handlers/session.py | 10 +++++--- project_amber/handlers/task.py | 10 +++++--- project_amber/handlers/users.py | 22 ++++++++++++----- 8 files changed, 55 insertions(+), 41 deletions(-) diff --git a/project_amber/app.py b/project_amber/app.py index 7142872..d2076e4 100644 --- a/project_amber/app.py +++ b/project_amber/app.py @@ -6,14 +6,13 @@ from project_amber.config import config from project_amber.db import db from project_amber.errors import HTTPError -from project_amber.helpers import handleLogin, middleware as checkRequest -from project_amber.handlers.auth import login, logout -from project_amber.handlers.session import handle_session_req, \ - handle_session_id_req -from project_amber.handlers.misc import version as handle_version_request -from project_amber.handlers.task import handle_task_id_request, \ - handle_task_request -from project_amber.handlers.users import signup, update_user_data +from project_amber.helpers import handleLogin, middleware as check_request +from project_amber.handlers.const import API_V0 +from project_amber.handlers.auth import auth_handlers as auth +from project_amber.handlers.session import session_handlers as session +from project_amber.handlers.misc import misc_handlers as misc +from project_amber.handlers.task import task_handlers as task +from project_amber.handlers.users import user_handlers as user app = Flask(__name__) app.config["SQLALCHEMY_DATABASE_URI"] = config["database"] @@ -23,26 +22,11 @@ @app.before_request def middleware(): - if checkRequest().authenticated: request.user = handleLogin() - - -app.add_url_rule("/v0/login", "login", login, methods=["POST"]) -app.add_url_rule("/v0/logout", "logout", logout, methods=["POST"]) -app.add_url_rule("/v0/task", "task", handle_task_request, \ - methods=["GET", "POST"]) -app.add_url_rule("/v0/task/", "task_id", handle_task_id_request, \ - methods=["GET", "PATCH", "DELETE"]) -app.add_url_rule("/v0/user", "user", update_user_data, methods=["PATCH"]) -app.add_url_rule( - "/v0/session", "session", handle_session_req, methods=["GET"] -) -app.add_url_rule("/v0/session/", "session_id", \ - handle_session_id_req, methods=["GET", "DELETE"]) -app.add_url_rule("/v0/version", "version", handle_version_request, \ - methods=["GET"]) - -if config["allow_signup"]: - app.add_url_rule("/v0/signup", "signup", signup, methods=["POST"]) + if check_request().authenticated: request.user = handleLogin() + + +for blueprint in (auth, session, misc, task, user): + app.register_blueprint(blueprint, url_prefix=API_V0) @app.before_first_request diff --git a/project_amber/const.py b/project_amber/const.py index c7a24d3..07d327a 100644 --- a/project_amber/const.py +++ b/project_amber/const.py @@ -13,6 +13,7 @@ MSG_USER_NOT_FOUND = "This user does not exist" MSG_USER_EXISTS = "The user with this name already exists" MSG_IMMATURE_SESSION = "This session is too new, and cannot remove others" +MSG_SIGNUP_FORBIDDEN = "Signup is disabled on this server" MSG_TASK_NOT_FOUND = "This task does not exist" MSG_TEXT_NOT_SPECIFIED = "No text specified" diff --git a/project_amber/handlers/auth.py b/project_amber/handlers/auth.py index ad512f0..faa1185 100644 --- a/project_amber/handlers/auth.py +++ b/project_amber/handlers/auth.py @@ -1,6 +1,6 @@ from json import dumps -from flask import request +from flask import request, Blueprint from project_amber.const import EMPTY_RESP, MSG_MISSING_AUTH_INFO from project_amber.errors import BadRequest @@ -8,7 +8,10 @@ from project_amber.helpers.auth import removeSession, createSession from project_amber.logging import log +auth_handlers = Blueprint("auth_handlers", __name__) + +@auth_handlers.route("/login", methods=["POST"]) def login(): """ Login handler. Accepts this JSON: @@ -32,6 +35,7 @@ def login(): return dumps({API_TOKEN: token}) +@auth_handlers.route("/logout", methods=["POST"]) def logout(): """ Logout handler. Accepts empty JSON. Returns HTTP 200 on success. diff --git a/project_amber/handlers/const.py b/project_amber/handlers/const.py index bfc0502..6da2b14 100644 --- a/project_amber/handlers/const.py +++ b/project_amber/handlers/const.py @@ -14,3 +14,5 @@ API_QUERY = "query" API_VERSION = "version" API_SIGNUP = "signup" + +API_V0 = "/v0" diff --git a/project_amber/handlers/misc.py b/project_amber/handlers/misc.py index 90d9ed0..1db70b1 100644 --- a/project_amber/handlers/misc.py +++ b/project_amber/handlers/misc.py @@ -1,5 +1,7 @@ from json import dumps +from flask import Blueprint + from project_amber.config import config from project_amber.const import VERSION from project_amber.handlers.const import API_VERSION, API_SIGNUP @@ -7,6 +9,9 @@ signup_allowed = False if config["allow_signup"]: signup_allowed = True +misc_handlers = Blueprint("misc_handlers", __name__) + +@misc_handlers.route("/version", methods=["GET"]) def version(): return dumps({API_VERSION: VERSION, API_SIGNUP: signup_allowed}) diff --git a/project_amber/handlers/session.py b/project_amber/handlers/session.py index f4689cb..a2959a1 100644 --- a/project_amber/handlers/session.py +++ b/project_amber/handlers/session.py @@ -1,6 +1,6 @@ from json import dumps -from flask import request +from flask import request, Blueprint from project_amber.const import MATURE_SESSION, MSG_IMMATURE_SESSION, EMPTY_RESP from project_amber.errors import Forbidden @@ -9,8 +9,11 @@ from project_amber.helpers.auth import getSessions, getSession, removeSessionById from project_amber.logging import log +session_handlers = Blueprint("session_handlers", __name__) -def handle_session_req(): + +@session_handlers.route("/session", methods=["GET"]) +def session(): """ Request handler for `/api/session`. Only accepts GET requests. Returns a list of sessions like the one below: @@ -40,7 +43,8 @@ def handle_session_req(): return dumps(sessionList) -def handle_session_id_req(session_id: int): +@session_handlers.route("/session/", methods=["GET", "DELETE"]) +def session_by_id(session_id: int): """ Login handler for `/api/session/`. Accepts GET and DELETE requests. Returns 404 if this session does not exist. On successful diff --git a/project_amber/handlers/task.py b/project_amber/handlers/task.py index e7f458e..71326a0 100644 --- a/project_amber/handlers/task.py +++ b/project_amber/handlers/task.py @@ -1,14 +1,17 @@ from json import dumps -from flask import request +from flask import request, Blueprint from project_amber.const import EMPTY_RESP from project_amber.handlers.const import API_QUERY from project_amber.helpers.task import addTask, getTask, getTasks, \ updateTask, removeTask +task_handlers = Blueprint("task_handlers", __name__) -def handle_task_request(): + +@task_handlers.route("/task", methods=["GET", "POST"]) +def task_request(): """ Handles requests to `/api/task`. Accepts GET and POST. The request JSON may contain a `query` parameter in a GET request, in this @@ -57,7 +60,8 @@ def handle_task_request(): return EMPTY_RESP -def handle_task_id_request(task_id: int): +@task_handlers.route("/task/", methods=["GET", "PATCH", "DELETE"]) +def 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 diff --git a/project_amber/handlers/users.py b/project_amber/handlers/users.py index ef22b4a..5d3eb1a 100644 --- a/project_amber/handlers/users.py +++ b/project_amber/handlers/users.py @@ -1,12 +1,19 @@ -from flask import request +from flask import request, Blueprint -from project_amber.const import EMPTY_RESP, MSG_MISSING_AUTH_INFO -from project_amber.errors import BadRequest +from project_amber.config import config +from project_amber.const import EMPTY_RESP, MSG_MISSING_AUTH_INFO, MSG_SIGNUP_FORBIDDEN +from project_amber.errors import BadRequest, Forbidden from project_amber.handlers.const import API_PASSWORD, API_USER from project_amber.helpers.auth import addUser, updateUser +user_handlers = Blueprint("user_handlers", __name__) -def update_user_data(): +signup_allowed = False +if config["allow_signup"]: signup_allowed = True + + +@user_handlers.route("/user", methods=["PATCH"]) +def user_data(): """ User data PATCH request handler. Accepts JSON with these parameters: ``` @@ -21,6 +28,7 @@ def update_user_data(): return EMPTY_RESP +@user_handlers.route("/signup", methods=["POST"]) def signup(): """ Signup request handler. Accepts this JSON: @@ -30,9 +38,11 @@ def signup(): "password": "some_password" } ``` - Returns HTTP 200 with empty JSON on success, 400 on missing params, 500 - otherwise. + Returns HTTP 200 with empty JSON on success, 400 on missing params, 403 if + the method is disabled by a config parameter. """ + if not signup_allowed: + raise Forbidden(MSG_SIGNUP_FORBIDDEN) if not API_USER in request.json or not API_PASSWORD in request.json: raise BadRequest(MSG_MISSING_AUTH_INFO) addUser(request.json[API_USER], request.json[API_PASSWORD])