diff --git a/backend/ibutsu_server/__init__.py b/backend/ibutsu_server/__init__.py index 8f2e82bc..e5c9c6d7 100644 --- a/backend/ibutsu_server/__init__.py +++ b/backend/ibutsu_server/__init__.py @@ -1,4 +1,5 @@ import os +from http import HTTPStatus from importlib import import_module from pathlib import Path from typing import Any, Optional @@ -130,38 +131,38 @@ def get_app(**extra_config): @app.route("/") def index(): - return redirect("/api/ui/", code=302) + return redirect("/api/ui/", code=HTTPStatus.FOUND) @app.route("/admin/run-task", methods=["POST"]) def run_task(): # get params params = request.get_json(force=True, silent=True) if not params: - return "Bad request", 400 + return HTTPStatus.BAD_REQUEST.phrase, HTTPStatus.BAD_REQUEST # get user info token = params.get("token") if not token: - return "Unauthorized", 401 + return HTTPStatus.UNAUTHORIZED.phrase, HTTPStatus.UNAUTHORIZED user_id = decode_token(token).get("sub") if not user_id: - return "Unauthorized", 401 + return HTTPStatus.UNAUTHORIZED.phrase, HTTPStatus.UNAUTHORIZED user = User.query.get(user_id) if not user or not user.is_superadmin: - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN # get task info task_path = params.get("task") task_params = params.get("params", {}) if not task_path: - return "Bad request", 400 + return HTTPStatus.BAD_REQUEST.phrase, HTTPStatus.BAD_REQUEST task_module, task_name = task_path.split(".", 2) try: mod = import_module(f"ibutsu_server.tasks.{task_module}") except ImportError: - return "Not found", 404 + return HTTPStatus.NOT_FOUND.phrase, HTTPStatus.NOT_FOUND if not hasattr(mod, task_name): - return "Not found", 404 + return HTTPStatus.NOT_FOUND.phrase, HTTPStatus.NOT_FOUND task = getattr(mod, task_name) task.delay(**task_params) - return "Accepted", 202 + return HTTPStatus.ACCEPTED.phrase, HTTPStatus.ACCEPTED return app.app diff --git a/backend/ibutsu_server/constants.py b/backend/ibutsu_server/constants.py index 8be33a60..c274d01b 100644 --- a/backend/ibutsu_server/constants.py +++ b/backend/ibutsu_server/constants.py @@ -1,4 +1,5 @@ from http import HTTPStatus + LOCALHOST = "127.0.0.1" OAUTH_CONFIG = { @@ -396,4 +397,4 @@ }, } -RESPONSE_JSON_REQ = f"{HTTPStatus.BAD_REQUEST.phrase} JSON required", HTTPStatus.BAD_REQUEST \ No newline at end of file +RESPONSE_JSON_REQ = f"{HTTPStatus.BAD_REQUEST.phrase} JSON required", HTTPStatus.BAD_REQUEST diff --git a/backend/ibutsu_server/controllers/admin/project_controller.py b/backend/ibutsu_server/controllers/admin/project_controller.py index 89168fe0..dad5d6a2 100644 --- a/backend/ibutsu_server/controllers/admin/project_controller.py +++ b/backend/ibutsu_server/controllers/admin/project_controller.py @@ -1,13 +1,15 @@ +from http import HTTPStatus + import connexion from flask import abort +from ibutsu_server.constants import RESPONSE_JSON_REQ from ibutsu_server.db.base import session from ibutsu_server.db.models import Group, Project, User from ibutsu_server.filters import convert_filter from ibutsu_server.util.admin import check_user_is_admin from ibutsu_server.util.query import get_offset from ibutsu_server.util.uuid import convert_objectid_to_uuid, is_uuid, validate_uuid -from ibutsu_server.constants import RESPONSE_JSON_REQ def admin_add_project(project=None, token_info=None, user=None): @@ -24,19 +26,19 @@ def admin_add_project(project=None, token_info=None, user=None): project = Project.from_dict(**connexion.request.get_json()) # check if project already exists if project.id and Project.query.get(project.id): - return f"Project id {project.id} already exist", 400 + return f"Project id {project.id} already exist", HTTPStatus.BAD_REQUEST user = User.query.get(user) if project.group_id: # check if the group exists group = Group.query.get(project.group_id) if not group: - return f"Group id {project.group_id} doesn't exist", 400 + return f"Group id {project.group_id} doesn't exist", HTTPStatus.BAD_REQUEST if user: project.owner = user project.users.append(user) session.add(project) session.commit() - return project.to_dict(), 201 + return project.to_dict(), HTTPStatus.CREATED @validate_uuid @@ -53,7 +55,7 @@ def admin_get_project(id_, token_info=None, user=None): if not project: project = Project.query.filter(Project.name == id_).first() if not project: - abort(404) + abort(HTTPStatus.NOT_FOUND) return project.to_dict(with_owner=True) @@ -96,7 +98,7 @@ def admin_get_project_list( total_items = query.count() total_pages = (total_items // page_size) + (1 if total_items % page_size > 0 else 0) if offset > 9223372036854775807: # max value of bigint - return "The page number is too big.", 400 + return "The page number is too big.", HTTPStatus.BAD_REQUEST projects = query.offset(offset).limit(page_size).all() return { "projects": [project.to_dict(with_owner=True) for project in projects], @@ -128,7 +130,7 @@ def admin_update_project(id_, project=None, body=None, token_info=None, user=Non project = Project.query.get(id_) if not project: - abort(404) + abort(HTTPStatus.NOT_FOUND) # Grab the fields from the request project_dict = connexion.request.get_json() @@ -160,10 +162,10 @@ def admin_delete_project(id_, token_info=None, user=None): """Delete a single project""" check_user_is_admin(user) if not is_uuid(id_): - return f"Project ID {id_} is not in UUID format", 400 + return f"Project ID {id_} is not in UUID format", HTTPStatus.BAD_REQUEST project = Project.query.get(id_) if not project: - abort(404) + abort(HTTPStatus.NOT_FOUND) session.delete(project) session.commit() - return "OK", 200 + return HTTPStatus.OK.phrase, HTTPStatus.OK diff --git a/backend/ibutsu_server/controllers/admin/user_controller.py b/backend/ibutsu_server/controllers/admin/user_controller.py index 7a718c43..e537fba2 100644 --- a/backend/ibutsu_server/controllers/admin/user_controller.py +++ b/backend/ibutsu_server/controllers/admin/user_controller.py @@ -1,13 +1,15 @@ +from http import HTTPStatus + import connexion from flask import abort +from ibutsu_server.constants import RESPONSE_JSON_REQ from ibutsu_server.db.base import session from ibutsu_server.db.models import Project, User from ibutsu_server.filters import convert_filter from ibutsu_server.util.admin import check_user_is_admin from ibutsu_server.util.query import get_offset from ibutsu_server.util.uuid import validate_uuid -from ibutsu_server.constants import RESPONSE_JSON_REQ HIDDEN_FIELDS = ["_password", "password", "activation_code"] @@ -28,7 +30,7 @@ def admin_get_user(id_, token_info=None, user=None): check_user_is_admin(user) requested_user = User.query.get(id_) if not requested_user: - abort(404) + abort(HTTPStatus.NOT_FOUND) return _hide_sensitive_fields(requested_user.to_dict(with_projects=True)) @@ -68,10 +70,10 @@ def admin_add_user(new_user=None, token_info=None, user=None): new_user = User.from_dict(**connexion.request.get_json()) user_exists = User.query.filter_by(email=new_user.email).first() if user_exists: - return f"The user with email {new_user.email} already exists", 400 + return f"The user with email {new_user.email} already exists", HTTPStatus.BAD_REQUEST session.add(new_user) session.commit() - return _hide_sensitive_fields(new_user.to_dict()), 201 + return _hide_sensitive_fields(new_user.to_dict()), HTTPStatus.CREATED @validate_uuid @@ -84,7 +86,7 @@ def admin_update_user(id_, body=None, user_info=None, token_info=None, user=None projects = user_dict.pop("projects", []) requested_user = User.query.get(id_) if not requested_user: - abort(404) + abort(HTTPStatus.NOT_FOUND) requested_user.update(user_dict) requested_user.projects = [Project.query.get(project["id"]) for project in projects] session.add(requested_user) @@ -98,7 +100,7 @@ def admin_delete_user(id_, token_info=None, user=None): check_user_is_admin(user) requested_user = User.query.get(id_) if not requested_user: - abort(404) + abort(HTTPStatus.NOT_FOUND) session.delete(requested_user) session.commit() - return "OK", 200 + return HTTPStatus.OK.phrase, HTTPStatus.OK diff --git a/backend/ibutsu_server/controllers/artifact_controller.py b/backend/ibutsu_server/controllers/artifact_controller.py index 97f94a94..501b8e3a 100644 --- a/backend/ibutsu_server/controllers/artifact_controller.py +++ b/backend/ibutsu_server/controllers/artifact_controller.py @@ -1,5 +1,6 @@ import json from datetime import datetime +from http import HTTPStatus import connexion import magic @@ -16,9 +17,9 @@ def _build_artifact_response(id_): """Build a response for the artifact""" artifact = Artifact.query.get(id_) if not artifact: - return "Not Found", 404 + return HTTPStatus.NOT_FOUND.phrase, HTTPStatus.NOT_FOUND # Create a response with the contents of this file - response = make_response(artifact.content, 200) + response = make_response(artifact.content, HTTPStatus.OK) # Set the content type and the file name file_type = magic.from_buffer(artifact.content, mime=True) response.headers["Content-Type"] = file_type @@ -36,9 +37,9 @@ def view_artifact(id_, token_info=None, user=None): """ artifact, response = _build_artifact_response(id_) if artifact.result and not project_has_user(artifact.result.project, user): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN elif artifact.run and not project_has_user(artifact.run.project, user): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN return response @@ -53,7 +54,7 @@ def download_artifact(id_, token_info=None, user=None): """ artifact, response = _build_artifact_response(id_) if not project_has_user(artifact.result.project, user): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN response.headers["Content-Disposition"] = f"attachment; filename={artifact.filename}" return response @@ -69,9 +70,9 @@ def get_artifact(id_, token_info=None, user=None): """ artifact = Artifact.query.get(id_) if not artifact: - return "Not Found", 404 + return HTTPStatus.NOT_FOUND.phrase, HTTPStatus.NOT_FOUND if not project_has_user(artifact.result.project, user): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN return artifact.to_dict() @@ -129,12 +130,12 @@ def upload_artifact(body, token_info=None, user=None): result_id = body.get("result_id") or body.get("resultId") run_id = body.get("run_id") or body.get("runId") if result_id and not is_uuid(result_id): - return f"Result ID {result_id} is not in UUID format", 400 + return f"Result ID {result_id} is not in UUID format", HTTPStatus.BAD_REQUEST if run_id and not is_uuid(run_id): - return f"Run ID {run_id} is not in UUID format", 400 + return f"Run ID {run_id} is not in UUID format", HTTPStatus.BAD_REQUEST result = Result.query.get(result_id) if result and not project_has_user(result.project, user): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN filename = body.get("filename") additional_metadata = body.get("additional_metadata", {}) file_ = connexion.request.files["file"] @@ -150,9 +151,9 @@ def upload_artifact(body, token_info=None, user=None): try: additional_metadata = json.loads(additional_metadata) except (ValueError, TypeError): - return "Bad request, additionalMetadata is not valid JSON", 400 + return "Bad request, additionalMetadata is not valid JSON", HTTPStatus.BAD_REQUEST if not isinstance(additional_metadata, dict): - return "Bad request, additionalMetadata is not a JSON object", 400 + return "Bad request, additionalMetadata is not a JSON object", HTTPStatus.BAD_REQUEST data["additionalMetadata"] = additional_metadata # Reset the file pointer file_.seek(0) @@ -175,7 +176,7 @@ def upload_artifact(body, token_info=None, user=None): session.add(artifact) session.commit() - return artifact.to_dict(), 201 + return artifact.to_dict(), HTTPStatus.CREATED @validate_uuid @@ -189,9 +190,9 @@ def delete_artifact(id_, token_info=None, user=None): """ artifact = Artifact.query.get(id_) if not artifact: - return "Not Found", 404 + return HTTPStatus.NOT_FOUND.phrase, HTTPStatus.NOT_FOUND if not project_has_user(artifact.result.project, user): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN session.delete(artifact) session.commit() - return "OK", 200 + return HTTPStatus.OK.phrase, HTTPStatus.OK diff --git a/backend/ibutsu_server/controllers/dashboard_controller.py b/backend/ibutsu_server/controllers/dashboard_controller.py index d2d80603..24037752 100644 --- a/backend/ibutsu_server/controllers/dashboard_controller.py +++ b/backend/ibutsu_server/controllers/dashboard_controller.py @@ -1,12 +1,14 @@ +from http import HTTPStatus + import connexion +from ibutsu_server.constants import RESPONSE_JSON_REQ from ibutsu_server.db.base import session from ibutsu_server.db.models import Dashboard, Project, User, WidgetConfig from ibutsu_server.filters import convert_filter from ibutsu_server.util.projects import project_has_user from ibutsu_server.util.query import get_offset from ibutsu_server.util.uuid import validate_uuid -from ibutsu_server.constants import RESPONSE_JSON_REQ def add_dashboard(dashboard=None, token_info=None, user=None): @@ -21,12 +23,12 @@ def add_dashboard(dashboard=None, token_info=None, user=None): return RESPONSE_JSON_REQ dashboard = Dashboard.from_dict(**connexion.request.get_json()) if dashboard.project_id and not project_has_user(dashboard.project_id, user): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN if dashboard.user_id and not User.query.get(dashboard.user_id): - return f"User with ID {dashboard.user_id} doesn't exist", 400 + return f"User with ID {dashboard.user_id} doesn't exist", HTTPStatus.BAD_REQUEST session.add(dashboard) session.commit() - return dashboard.to_dict(), 201 + return dashboard.to_dict(), HTTPStatus.CREATED @validate_uuid @@ -40,9 +42,9 @@ def get_dashboard(id_, token_info=None, user=None): """ dashboard = Dashboard.query.get(id_) if not dashboard: - return "Dashboard not found", 404 + return "Dashboard not found", HTTPStatus.NOT_FOUND if dashboard and dashboard.project and not project_has_user(dashboard.project, user): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN return dashboard.to_dict() @@ -68,7 +70,7 @@ def get_dashboard_list( project = Project.query.get(connexion.request.args["project_id"]) if project: if not project_has_user(project, user): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN query = query.filter(Dashboard.project_id == project_id) if filter_: @@ -110,12 +112,12 @@ def update_dashboard(id_, dashboard=None, token_info=None, user=None): if dashboard_dict.get("metadata", {}).get("project") and not project_has_user( dashboard_dict["metadata"]["project"], user ): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN dashboard = Dashboard.query.get(id_) if not dashboard: - return "Dashboard not found", 404 + return "Dashboard not found", HTTPStatus.NOT_FOUND if project_has_user(dashboard.project, user): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN dashboard.update(connexion.request.get_json()) session.add(dashboard) session.commit() @@ -133,12 +135,12 @@ def delete_dashboard(id_, token_info=None, user=None): """ dashboard = Dashboard.query.get(id_) if not dashboard: - return "Not Found", 404 + return HTTPStatus.NOT_FOUND.phrase, HTTPStatus.NOT_FOUND if not project_has_user(dashboard.project, user): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN widget_configs = WidgetConfig.query.filter(WidgetConfig.dashboard_id == dashboard.id).all() for widget_config in widget_configs: session.delete(widget_config) session.delete(dashboard) session.commit() - return "OK", 200 + return HTTPStatus.OK.phrase, HTTPStatus.OK diff --git a/backend/ibutsu_server/controllers/group_controller.py b/backend/ibutsu_server/controllers/group_controller.py index aac501b6..3abfdb90 100644 --- a/backend/ibutsu_server/controllers/group_controller.py +++ b/backend/ibutsu_server/controllers/group_controller.py @@ -1,10 +1,12 @@ +from http import HTTPStatus + import connexion +from ibutsu_server.constants import RESPONSE_JSON_REQ from ibutsu_server.db.base import session from ibutsu_server.db.models import Group from ibutsu_server.util.query import get_offset from ibutsu_server.util.uuid import is_uuid, validate_uuid -from ibutsu_server.constants import RESPONSE_JSON_REQ def add_group(group=None): @@ -19,12 +21,12 @@ def add_group(group=None): return RESPONSE_JSON_REQ group = Group.from_dict(**connexion.request.get_json()) if group.id and Group.query.get(group.id): - return f"The group with ID {group.id} already exists", 400 + return f"The group with ID {group.id} already exists", HTTPStatus.BAD_REQUEST if not is_uuid(group.id): - return f"Group ID {group.id} is not in UUID format", 400 + return f"Group ID {group.id} is not in UUID format", HTTPStatus.BAD_REQUEST session.add(group) session.commit() - return group.to_dict(), 201 + return group.to_dict(), HTTPStatus.CREATED @validate_uuid @@ -40,7 +42,7 @@ def get_group(id_, token_info=None, user=None): if group: return group.to_dict() else: - return "Group not found", 404 + return "Group not found", HTTPStatus.NOT_FOUND def get_group_list(page=1, page_size=25, token_info=None, user=None): @@ -88,7 +90,7 @@ def update_group(id_, group=None, **kwargs): return RESPONSE_JSON_REQ group = Group.query.get(id_) if not group: - return "Group not found", 404 + return "Group not found", HTTPStatus.NOT_FOUND group.update(connexion.request.get_json()) session.add(group) session.commit() diff --git a/backend/ibutsu_server/controllers/health_controller.py b/backend/ibutsu_server/controllers/health_controller.py index ed582ce9..5f5d8d2f 100644 --- a/backend/ibutsu_server/controllers/health_controller.py +++ b/backend/ibutsu_server/controllers/health_controller.py @@ -1,3 +1,5 @@ +from http import HTTPStatus + from flask import current_app from sqlalchemy.exc import InterfaceError, OperationalError @@ -24,29 +26,29 @@ def get_database_health(token_info=None, user=None): :rtype: Health """ - response = ({"status": "Pending", "message": "Fetching service status"}, 200) + response = ({"status": "Pending", "message": "Fetching service status"}, HTTPStatus.OK) # Try to connect to the database, and handle various responses try: if not IS_CONNECTED: response = ( {"status": "Error", "message": "Incomplete database configuration"}, - 503, + HTTPStatus.SERVICE_UNAVAILABLE, ) else: Result.query.first() - response = ({"status": "OK", "message": "Service is running"}, 200) + response = ({"status": "OK", "message": "Service is running"}, HTTPStatus.OK) except OperationalError: response = ( {"status": "Error", "message": "Unable to connect to the database"}, - 503, + HTTPStatus.SERVICE_UNAVAILABLE, ) except InterfaceError: response = ( {"status": "Error", "message": "Incorrect connection configuration"}, - 503, + HTTPStatus.SERVICE_UNAVAILABLE, ) except Exception as e: - response = ({"status": "Error", "message": str(e)}, 500) + response = ({"status": "Error", "message": str(e)}, HTTPStatus.INTERNAL_SERVER_ERROR) return response diff --git a/backend/ibutsu_server/controllers/import_controller.py b/backend/ibutsu_server/controllers/import_controller.py index 6ab6596f..26998134 100644 --- a/backend/ibutsu_server/controllers/import_controller.py +++ b/backend/ibutsu_server/controllers/import_controller.py @@ -1,4 +1,5 @@ import json +from http import HTTPStatus from typing import Optional import connexion @@ -24,9 +25,9 @@ def get_import(id_, token_info=None, user=None): if import_ and import_.data.get("project_id"): project = get_project(import_.data["project_id"]) if project and not project_has_user(project, user): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN if not import_: - return "Not Found", 404 + return HTTPStatus.NOT_FOUND.phrase, HTTPStatus.NOT_FOUND return import_.to_dict() @@ -54,16 +55,16 @@ def add_import( if "importFile" in connexion.request.files: import_file = connexion.request.files["importFile"] if not import_file: - return "Bad request, no file uploaded", 400 + return "Bad request, no file uploaded", HTTPStatus.BAD_REQUEST data = {} if connexion.request.form.get("project"): project = connexion.request.form["project"] if project: project_obj = get_project(project) if not project_obj: - return f"Project {project} doesn't exist", 400 + return f"Project {project} doesn't exist", HTTPStatus.BAD_REQUEST if not project_has_user(project, user): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN data["project_id"] = project_obj.id if connexion.request.form.get("metadata"): metadata = json.loads(connexion.request.form.get("metadata")) @@ -89,4 +90,4 @@ def add_import( run_archive_import.delay(new_import.to_dict()) else: return "Unsupported Media Type", 415 - return new_import.to_dict(), 202 + return new_import.to_dict(), 2 diff --git a/backend/ibutsu_server/controllers/login_controller.py b/backend/ibutsu_server/controllers/login_controller.py index 1c503b81..9a70c486 100644 --- a/backend/ibutsu_server/controllers/login_controller.py +++ b/backend/ibutsu_server/controllers/login_controller.py @@ -1,5 +1,6 @@ import json from base64 import urlsafe_b64encode +from http import HTTPStatus from urllib.parse import urlencode from uuid import uuid4 @@ -9,7 +10,7 @@ from google.auth.transport.requests import Request from google.oauth2 import id_token -from ibutsu_server.constants import LOCALHOST +from ibutsu_server.constants import LOCALHOST, RESPONSE_JSON_REQ from ibutsu_server.db.base import session from ibutsu_server.db.models import Token, User from ibutsu_server.util.jwt import generate_token @@ -60,7 +61,7 @@ def _get_user_from_provider(provider, provider_config, code): user = get_user_from_provider(provider, id_info) except ValueError: # Invalid token - return "Unauthorized", 401 + return HTTPStatus.UNAUTHORIZED.phrase, HTTPStatus.UNAUTHORIZED else: # For everyone else payload = { @@ -106,11 +107,14 @@ def login(email=None, password=None): :rtype: LoginToken """ if not connexion.request.is_json: - return "Bad request, JSON is required", 400 + return RESPONSE_JSON_REQ login = connexion.request.get_json() if not login.get("email") or not login.get("password"): - return {"code": "EMPTY", "message": "Username and/or password are empty"}, 401 + return { + "code": "EMPTY", + "message": "Username and/or password are empty", + }, HTTPStatus.UNAUTHORIZED user = User.query.filter_by(email=login["email"]).first() # superadmins can login even if local login is disabled @@ -119,7 +123,7 @@ def login(email=None, password=None): "code": "INVALID", "message": "Username/password auth is disabled. " "Please login via one of the links below.", - }, 401 + }, HTTPStatus.UNAUTHORIZED if user and user.check_password(login["password"]): login_token = generate_token(user.id) @@ -135,12 +139,12 @@ def login(email=None, password=None): "code": "INVALID", "message": "Username/password auth is disabled. " "Please login via one of the links below.", - }, 401 + }, HTTPStatus.UNAUTHORIZED else: return { "code": "INVALID", "message": "Username and/or password are invalid", - }, 401 + }, HTTPStatus.UNAUTHORIZED def support(): @@ -166,7 +170,7 @@ def config(provider): def auth(provider): """Auth redirect URL""" if not connexion.request.args.get("code"): - return "Bad request", 400 + return HTTPStatus.BAD_REQUEST.phrase, HTTPStatus.BAD_REQUEST code = connexion.request.args["code"] frontend_url = build_url( current_app.config.get("FRONTEND_URL", f"http://{LOCALHOST}:3000"), "login" @@ -174,7 +178,7 @@ def auth(provider): provider_config = _get_provider_config(provider) user = _get_user_from_provider(provider, provider_config, code) if not user: - return "Unauthorized", 401 + return HTTPStatus.UNAUTHORIZED.phrase, HTTPStatus.UNAUTHORIZED jwt_token = generate_token(user.id) token = _find_or_create_token("login-token", user) token.token = jwt_token @@ -202,10 +206,13 @@ def register(email=None, password=None): :type password: str """ if not connexion.request.is_json: - return "Bad request, JSON is required", 400 + return RESPONSE_JSON_REQ details = connexion.request.get_json() if not details.get("email") or not details.get("password"): - return {"code": "EMPTY", "message": "Username and/or password are empty"}, 401 + return { + "code": "EMPTY", + "message": "Username and/or password are empty", + }, HTTPStatus.UNAUTHORIZED # Create a random activation code. Base64 just for funsies activation_code = urlsafe_b64encode(str(uuid4()).encode("utf8")).strip(b"=").decode() @@ -217,7 +224,7 @@ def register(email=None, password=None): ) user_exists = User.query.filter_by(email=user.email).first() if user_exists: - return f"The user with email {user.email} already exists", 400 + return f"The user with email {user.email} already exists", HTTPStatus.BAD_REQUEST session.add(user) session.commit() @@ -238,7 +245,7 @@ def register(email=None, password=None): ) else: print(f"No e-mail configuration. Email: {email} - activation URL: {activation_url}") - return {}, 201 + return {}, HTTPStatus.CREATED def recover(email=None): @@ -247,18 +254,18 @@ def recover(email=None): :param email: The e-mail address of the user """ if not connexion.request.is_json: - return "Bad request, JSON is required", 400 + return RESPONSE_JSON_REQ login = connexion.request.get_json() if not login.get("email"): - return "Bad request", 400 + return HTTPStatus.BAD_REQUEST.phrase, HTTPStatus.BAD_REQUEST user = User.query.filter(User.email == login["email"]).first() if not user: - return "Bad request", 400 + return HTTPStatus.BAD_REQUEST.phrase, HTTPStatus.BAD_REQUEST # Create a random activation code. Base64 just for funsies user.activation_code = urlsafe_b64encode(str(uuid4()).encode("utf8")).strip(b"=") session.add(user) session.commit() - return {}, 201 + return {}, HTTPStatus.CREATED def reset_password(activation_code=None, password=None): @@ -269,20 +276,20 @@ def reset_password(activation_code=None, password=None): :param password: The new password for the user """ if not connexion.request.is_json: - return "Bad request, JSON is required", 400 + return RESPONSE_JSON_REQ login = connexion.request.get_json() if result := validate_activation_code(login.get("activation_code")): return result if not login.get("activation_code") or not login.get("password"): - return "Bad request", 400 + return HTTPStatus.BAD_REQUEST.phrase, HTTPStatus.BAD_REQUEST user = User.query.filter(User.activation_code == login["activation_code"]).first() if not user: - return "Invalid activation code", 400 + return "Invalid activation code", HTTPStatus.BAD_REQUEST user.password = login["password"] user.activation_code = None session.add(user) session.commit() - return {}, 201 + return {}, HTTPStatus.CREATED def activate(activation_code=None): diff --git a/backend/ibutsu_server/controllers/project_controller.py b/backend/ibutsu_server/controllers/project_controller.py index 25b0b6e1..c580ba65 100644 --- a/backend/ibutsu_server/controllers/project_controller.py +++ b/backend/ibutsu_server/controllers/project_controller.py @@ -1,13 +1,15 @@ +from http import HTTPStatus + import connexion import flatdict +from ibutsu_server.constants import RESPONSE_JSON_REQ from ibutsu_server.db.base import session from ibutsu_server.db.models import Project, Result, User from ibutsu_server.filters import convert_filter from ibutsu_server.util.projects import add_user_filter, project_has_user from ibutsu_server.util.query import get_offset from ibutsu_server.util.uuid import convert_objectid_to_uuid, is_uuid, validate_uuid -from ibutsu_server.constants import RESPONSE_JSON_REQ def add_project(project=None, token_info=None, user=None): @@ -23,14 +25,14 @@ def add_project(project=None, token_info=None, user=None): project = Project.from_dict(**connexion.request.get_json()) # check if project already exists if project.id and Project.query.get(project.id): - return f"Project id {project.id} already exist", 400 + return f"Project id {project.id} already exist", HTTPStatus.BAD_REQUEST user = User.query.get(user) if user: project.owner = user project.users.append(user) session.add(project) session.commit() - return project.to_dict(), 201 + return project.to_dict(), HTTPStatus.CREATED @validate_uuid @@ -48,9 +50,9 @@ def get_project(id_, token_info=None, user=None): if not project: project = Project.query.get(id_) if project and not project_has_user(project, user): - return "Unauthorized", 401 + return HTTPStatus.UNAUTHORIZED.phrase, HTTPStatus.UNAUTHORIZED if not project: - return "Project not found", 404 + return "Project not found", HTTPStatus.NOT_FOUND return project.to_dict() @@ -121,11 +123,11 @@ def update_project(id_, project=None, token_info=None, user=None, **kwargs): project = Project.query.get(id_) if not project: - return "Project not found", 404 + return "Project not found", HTTPStatus.NOT_FOUND user = User.query.get(user) if not user.is_superadmin and (not project.owner or project.owner.id != user.id): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN # handle updating users separately updates = connexion.request.get_json() @@ -153,9 +155,9 @@ def get_filter_params(id_, user=None, token_info=None): project = Project.query.get(id_) if not project: - return "Project not found", 404 + return "Project not found", HTTPStatus.NOT_FOUND if project and not project_has_user(project, user): - return "Unauthorized", 401 + return HTTPStatus.UNAUTHORIZED.phrase, HTTPStatus.UNAUTHORIZED result = ( session.query(Result) diff --git a/backend/ibutsu_server/controllers/report_controller.py b/backend/ibutsu_server/controllers/report_controller.py index 28e89a8b..5170da01 100644 --- a/backend/ibutsu_server/controllers/report_controller.py +++ b/backend/ibutsu_server/controllers/report_controller.py @@ -1,15 +1,16 @@ from datetime import datetime +from http import HTTPStatus import connexion from flask import make_response +from ibutsu_server.constants import RESPONSE_JSON_REQ from ibutsu_server.db.base import session from ibutsu_server.db.models import Report, ReportFile from ibutsu_server.tasks.reports import REPORTS from ibutsu_server.util.projects import get_project_id from ibutsu_server.util.query import get_offset from ibutsu_server.util.uuid import validate_uuid -from ibutsu_server.constants import RESPONSE_JSON_REQ def _build_report_response(id_): @@ -19,11 +20,11 @@ def _build_report_response(id_): """ report = Report.query.get(id_) if not report: - return "Report not found", 404 + return "Report not found", HTTPStatus.NOT_FOUND report_file = ReportFile.query.filter(ReportFile.report_id == id_).first() if not report_file: - return "File not found", 404 - response = make_response(report_file.content, 200) + return "File not found", HTTPStatus.NOT_FOUND + response = make_response(report_file.content, HTTPStatus.OK) response.headers["Content-Type"] = report.mimetype return report, response @@ -48,7 +49,7 @@ def add_report(report_parameters=None): return RESPONSE_JSON_REQ report_parameters = connexion.request.json if report_parameters["type"] not in REPORTS: - return "Bad request, report type does not exist", 400 + return "Bad request, report type does not exist", HTTPStatus.BAD_REQUEST report_dict = { "filename": "", @@ -68,7 +69,7 @@ def add_report(report_parameters=None): session.commit() report_dict.update(report.to_dict()) REPORTS[report_parameters["type"]]["func"].delay(report_dict) - return report_dict, 201 + return report_dict, HTTPStatus.CREATED @validate_uuid @@ -124,14 +125,14 @@ def delete_report(id_, user=None, token_info=None): """ report = Report.query.get(id_) if not report: - return "Not Found", 404 + return HTTPStatus.NOT_FOUND.phrase, HTTPStatus.NOT_FOUND report_file = ReportFile.query.filter(ReportFile.report_id == report.id).first() session.delete(report_file) session.delete(report) session.commit() - return "OK", 200 + return HTTPStatus.OK.phrase, HTTPStatus.OK @validate_uuid diff --git a/backend/ibutsu_server/controllers/result_controller.py b/backend/ibutsu_server/controllers/result_controller.py index 1fe130a8..ff0d5bc6 100644 --- a/backend/ibutsu_server/controllers/result_controller.py +++ b/backend/ibutsu_server/controllers/result_controller.py @@ -1,7 +1,9 @@ from datetime import datetime +from http import HTTPStatus import connexion +from ibutsu_server.constants import RESPONSE_JSON_REQ from ibutsu_server.db.base import session from ibutsu_server.db.models import Result, User from ibutsu_server.filters import convert_filter @@ -10,7 +12,6 @@ from ibutsu_server.util.projects import add_user_filter, get_project, project_has_user from ibutsu_server.util.query import get_offset, query_as_task from ibutsu_server.util.uuid import validate_uuid -from ibutsu_server.constants import RESPONSE_JSON_REQ def add_result(result=None, token_info=None, user=None): @@ -26,15 +27,15 @@ def add_result(result=None, token_info=None, user=None): result = Result.from_dict(**connexion.request.get_json()) if result.id and Result.query.get(result.id): - return f"Result id {result.id} already exist", 400 + return f"Result id {result.id} already exist", HTTPStatus.BAD_REQUEST if result.data and not (result.data.get("project") or result.project_id): - return "Bad request, project or project_id is required", 400 + return "Bad request, project or project_id is required", HTTPStatus.BAD_REQUEST if not result.project: project = get_project(result.data["project"]) if not project_has_user(project, user): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN result.project = project # promote user_properties to the level of metadata @@ -50,7 +51,7 @@ def add_result(result=None, token_info=None, user=None): session.add(result) session.commit() - return result.to_dict(), 201 + return result.to_dict(), HTTPStatus.CREATED @query_as_task @@ -143,9 +144,9 @@ def get_result(id_, token_info=None, user=None): """ result = Result.query.get(id_) if not result: - return "Result not found", 404 + return "Result not found", HTTPStatus.NOT_FOUND if not project_has_user(result.project, user): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN return result.to_dict() @@ -166,7 +167,7 @@ def update_result(id_, result=None, token_info=None, user=None, **kwargs): if result_dict.get("metadata", {}).get("project"): project = get_project(result_dict["metadata"]["project"]) if not project_has_user(project, user): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN if project: result_dict["project_id"] = project.id @@ -177,9 +178,9 @@ def update_result(id_, result=None, token_info=None, user=None, **kwargs): result = Result.query.get(id_) if not result: - return "Result not found", 404 + return "Result not found", HTTPStatus.NOT_FOUND if not project_has_user(result.project, user): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN result.update(result_dict) result.env = result.data.get("env") if result.data else None result.component = result.data.get("component") if result.data else None diff --git a/backend/ibutsu_server/controllers/run_controller.py b/backend/ibutsu_server/controllers/run_controller.py index a1f82bf6..9b5d655a 100644 --- a/backend/ibutsu_server/controllers/run_controller.py +++ b/backend/ibutsu_server/controllers/run_controller.py @@ -1,7 +1,9 @@ from datetime import datetime +from http import HTTPStatus import connexion +from ibutsu_server.constants import RESPONSE_JSON_REQ from ibutsu_server.db.base import session from ibutsu_server.db.models import Run, User from ibutsu_server.filters import convert_filter @@ -16,7 +18,7 @@ ) from ibutsu_server.util.query import get_offset, query_as_task from ibutsu_server.util.uuid import validate_uuid -from ibutsu_server.constants import RESPONSE_JSON_REQ + @query_as_task def get_run_list(filter_=None, page=1, page_size=25, estimate=False, token_info=None, user=None): @@ -104,9 +106,9 @@ def get_run(id_, token_info=None, user=None): """ run = Run.query.get(id_) if not run: - return "Run not found", 404 + return "Run not found", HTTPStatus.NOT_FOUND if not project_has_user(run.project, user): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN return run.to_dict() @@ -119,20 +121,20 @@ def add_run(run=None, token_info=None, user=None): :rtype: Run """ if not connexion.request.is_json: - return "Bad request, JSON is required", 400 + return RESPONSE_JSON_REQ run = Run.from_dict(**connexion.request.get_json()) if not run.data: - return "Bad request, no data supplied", 400 + return "Bad request, no data supplied", HTTPStatus.BAD_REQUEST if run.data and not (run.data.get("project") or run.project_id): - return "Bad request, project or project_id is required", 400 + return "Bad request, project or project_id is required", HTTPStatus.BAD_REQUEST project = get_project(run.data["project"]) if not project: - return "Invalid project", 400 + return "Invalid project", HTTPStatus.BAD_REQUEST if not project_has_user(project, user): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN run.project = project run.env = run.data.get("env") if run.data else None run.component = run.data.get("component") if run.data else None @@ -144,7 +146,7 @@ def add_run(run=None, token_info=None, user=None): session.add(run) session.commit() update_run_task.apply_async((run.id,), countdown=5) - return run.to_dict(), 201 + return run.to_dict(), HTTPStatus.CREATED @validate_uuid @@ -164,12 +166,12 @@ def update_run(id_, run=None, body=None, token_info=None, user=None): if run_dict.get("metadata", {}).get("project"): run_dict["project_id"] = get_project_id(run_dict["metadata"]["project"]) if not project_has_user(run_dict["project_id"], user): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN run = Run.query.get(id_) if run and not project_has_user(run.project, user): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN if not run: - return "Run not found", 404 + return "Run not found", HTTPStatus.NOT_FOUND run.update(run_dict) session.add(run) session.commit() @@ -193,24 +195,27 @@ def bulk_update(filter_=None, page_size=1, token_info=None, user=None): run_dict = connexion.request.get_json() if not run_dict.get("metadata"): - return "Bad request, can only update metadata", 401 + return "Bad request, can only update metadata", HTTPStatus.UNAUTHORIZED # ensure only metadata is updated run_dict = {"metadata": run_dict.pop("metadata")} if page_size > 25: - return "Bad request, cannot update more than 25 runs at a time", 405 + return ( + "Bad request, cannot update more than 25 runs at a time", + HTTPStatus.METHOD_NOT_ALLOWED, + ) if run_dict.get("metadata", {}).get("project"): project = get_project(run_dict["metadata"]["project"]) if not project_has_user(project, user): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN run_dict["project_id"] = project.id runs = get_run_list(filter_=filter_, page_size=page_size, estimate=True).get("runs") if not runs: - return f"No runs found with {filter_}", 404 + return f"No runs found with {filter_}", HTTPStatus.NOT_FOUND model_runs = [] for run_json in runs: diff --git a/backend/ibutsu_server/controllers/task_controller.py b/backend/ibutsu_server/controllers/task_controller.py index 2170efe8..e2d68b5e 100644 --- a/backend/ibutsu_server/controllers/task_controller.py +++ b/backend/ibutsu_server/controllers/task_controller.py @@ -1,13 +1,15 @@ +from http import HTTPStatus + from celery.result import AsyncResult from ibutsu_server.util.uuid import validate_uuid _STATE_TO_CODE = { - "SUCCESS": 200, - "PENDING": 206, - "STARTED": 206, - "RETRY": 206, - "FAILURE": 203, + "SUCCESS": HTTPStatus.OK, + "PENDING": HTTPStatus.PARTIAL_CONTENT, + "STARTED": HTTPStatus.PARTIAL_CONTENT, + "RETRY": HTTPStatus.PARTIAL_CONTENT, + "FAILURE": HTTPStatus.NON_AUTHORITATIVE_INFORMATION, } diff --git a/backend/ibutsu_server/controllers/user_controller.py b/backend/ibutsu_server/controllers/user_controller.py index 88055e04..4822861d 100644 --- a/backend/ibutsu_server/controllers/user_controller.py +++ b/backend/ibutsu_server/controllers/user_controller.py @@ -1,7 +1,9 @@ from datetime import datetime +from http import HTTPStatus import connexion +from ibutsu_server.constants import RESPONSE_JSON_REQ from ibutsu_server.db.base import session from ibutsu_server.db.models import Token, User from ibutsu_server.util.jwt import generate_token @@ -25,7 +27,7 @@ def get_current_user(token_info=None, user=None): """Return the current user""" user = User.query.get(user) if not user: - return "Not authorized", 401 + return HTTPStatus.UNAUTHORIZED.phrase, HTTPStatus.UNAUTHORIZED return _hide_sensitive_fields(user.to_dict()) @@ -34,7 +36,7 @@ def update_current_user(token_info=None, user=None): """Return the current user""" user = User.query.get(user) if not user: - return "Not authorized", 401 + return HTTPStatus.UNAUTHORIZED.phrase, HTTPStatus.UNAUTHORIZED user_dict = connexion.request.get_json() user_dict.pop("is_superadmin", None) user.update(user_dict) @@ -54,7 +56,7 @@ def get_token_list(page=1, page_size=25, token_info=None, user=None): """ user = User.query.get(user) if not user: - return "Not authorized", 401 + return HTTPStatus.UNAUTHORIZED.phrase, HTTPStatus.UNAUTHORIZED query = Token.query.filter(Token.user == user, Token.name != "login-token") total_items = query.count() @@ -84,8 +86,8 @@ def get_token(id_, token_info=None, user=None): user = User.query.get(user) token = Token.query.get(id_) if token.user != user: - return "Forbidden", 403 - return token.to_dict() if token else ("Token not found", 404) + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN + return token.to_dict() if token else ("Token not found", HTTPStatus.NOT_FOUND) @validate_uuid @@ -100,10 +102,10 @@ def delete_token(id_, token_info=None, user=None): user = User.query.get(user) token = Token.query.get(id_) if token.user != user: - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN session.delete(token) session.commit() - return "OK", 200 + return HTTPStatus.OK.phrase, HTTPStatus.OK def add_token(token=None, token_info=None, user=None): @@ -115,10 +117,10 @@ def add_token(token=None, token_info=None, user=None): :rtype: Token """ if not connexion.request.is_json: - return "Bad request, JSON is required", 400 + return RESPONSE_JSON_REQ user = User.query.get(user) if not user: - return "Not authorized", 401 + return HTTPStatus.UNAUTHORIZED.phrase, HTTPStatus.UNAUTHORIZED token = Token.from_dict(**connexion.request.get_json()) token.user = user token.expires = datetime.fromisoformat(token.expires.replace("Z", "+00:00")) @@ -126,4 +128,4 @@ def add_token(token=None, token_info=None, user=None): session.add(token) session.commit() - return token.to_dict(), 201 + return token.to_dict(), HTTPStatus.CREATED diff --git a/backend/ibutsu_server/controllers/widget_config_controller.py b/backend/ibutsu_server/controllers/widget_config_controller.py index b10f776a..53a3c1ff 100644 --- a/backend/ibutsu_server/controllers/widget_config_controller.py +++ b/backend/ibutsu_server/controllers/widget_config_controller.py @@ -1,8 +1,9 @@ +from http import HTTPStatus + import connexion from sqlalchemy import or_ -from http import HTTPStatus -from ibutsu_server.constants import ALLOWED_TRUE_BOOLEANS, WIDGET_TYPES, RESPONSE_JSON_REQ +from ibutsu_server.constants import ALLOWED_TRUE_BOOLEANS, RESPONSE_JSON_REQ, WIDGET_TYPES from ibutsu_server.db.base import session from ibutsu_server.db.models import WidgetConfig from ibutsu_server.filters import convert_filter @@ -31,7 +32,7 @@ def add_widget_config(widget_config=None, token_info=None, user=None): if data.get("project"): project = get_project(data.pop("project")) if not project_has_user(project, user): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN data["project_id"] = project.id # default to make views navigable if data.get("navigable") and isinstance(data["navigable"], str): @@ -41,7 +42,7 @@ def add_widget_config(widget_config=None, token_info=None, user=None): widget_config = WidgetConfig.from_dict(**data) session.add(widget_config) session.commit() - return widget_config.to_dict(), 201 + return widget_config.to_dict(), HTTPStatus.CREATED @validate_uuid @@ -55,7 +56,7 @@ def get_widget_config(id_, token_info=None, user=None): """ widget_config = WidgetConfig.query.get(id_) if not widget_config: - return "Widget config not found", 404 + return "Widget config not found", HTTPStatus.NOT_FOUND return widget_config.to_dict() @@ -118,11 +119,11 @@ def update_widget_config(id_, body=None, widget_config=None, token_info=None, us if data.get("project"): project = get_project(data.pop("project")) if not project_has_user(project, user): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN data["project_id"] = project.id widget_config = WidgetConfig.query.get(id_) if not widget_config: - return "Widget config not found", 404 + return "Widget config not found", HTTPStatus.NOT_FOUND # add default weight of 10 if not widget_config.weight: widget_config.weight = 10 @@ -148,10 +149,10 @@ def delete_widget_config(id_, token_info=None, user=None): """ widget_config = WidgetConfig.query.get(id_) if not widget_config: - return "Not Found", 404 + return HTTPStatus.NOT_FOUND.phrase, HTTPStatus.NOT_FOUND else: if widget_config.project and not project_has_user(widget_config.project, user): - return "Forbidden", 403 + return HTTPStatus.FORBIDDEN.phrase, HTTPStatus.FORBIDDEN session.delete(widget_config) session.commit() - return "OK", 200 + return HTTPStatus.OK.phrase, HTTPStatus.OK diff --git a/backend/ibutsu_server/controllers/widget_controller.py b/backend/ibutsu_server/controllers/widget_controller.py index c78cef33..49cb5a53 100644 --- a/backend/ibutsu_server/controllers/widget_controller.py +++ b/backend/ibutsu_server/controllers/widget_controller.py @@ -1,3 +1,5 @@ +from http import HTTPStatus + import connexion from ibutsu_server.constants import ALLOWED_TRUE_BOOLEANS, WIDGET_TYPES @@ -105,7 +107,7 @@ def get_widget(id_): :rtype: object """ if id_ not in WIDGET_TYPES.keys(): - return "Widget not found", 404 + return "Widget not found", HTTPStatus.NOT_FOUND params = {} for key in connexion.request.args.keys(): params[key] = connexion.request.args.getlist(key) diff --git a/backend/ibutsu_server/test/__init__.py b/backend/ibutsu_server/test/__init__.py index 3b2af7e9..9d1e24e3 100644 --- a/backend/ibutsu_server/test/__init__.py +++ b/backend/ibutsu_server/test/__init__.py @@ -1,4 +1,5 @@ import logging +from http import HTTPStatus from inspect import isfunction from flask_testing import TestCase @@ -73,7 +74,7 @@ def assert_201(self, response, message=None): :param response: Flask response :param message: Message to display on test failure """ - self.assert_status(response, 201, message) + self.assert_status(response, HTTPStatus.CREATED, message) def assert_503(self, response, message=None): """ @@ -81,7 +82,7 @@ def assert_503(self, response, message=None): :param response: Flask response :param message: Message to display on test failure """ - self.assert_status(response, 503, message) + self.assert_status(response, HTTPStatus.SERVICE_UNAVAILABLE, message) def assert_equal(self, first, second, msg=None): """Alias""" diff --git a/backend/ibutsu_server/test/test_login_controller.py b/backend/ibutsu_server/test/test_login_controller.py index 3a879377..af380172 100644 --- a/backend/ibutsu_server/test/test_login_controller.py +++ b/backend/ibutsu_server/test/test_login_controller.py @@ -1,3 +1,4 @@ +from http import HTTPStatus from unittest.mock import patch from flask import json @@ -64,8 +65,8 @@ def test_login_empty_request(self): login_details = {"email": "", "password": ""} expected_response = { "detail": "'' is not a 'email' - 'email'", - "status": 400, - "title": "Bad Request", + "status": HTTPStatus.BAD_REQUEST, + "title": HTTPStatus.BAD_REQUEST.phrase, "type": "about:blank", } headers = {"Accept": "application/json", "Content-Type": "application/json"} diff --git a/backend/ibutsu_server/util/admin.py b/backend/ibutsu_server/util/admin.py index 7d024b26..42743c58 100644 --- a/backend/ibutsu_server/util/admin.py +++ b/backend/ibutsu_server/util/admin.py @@ -1,3 +1,5 @@ +from http import HTTPStatus + from flask import abort from ibutsu_server.db.models import User @@ -9,4 +11,4 @@ def check_user_is_admin(user_id): if not user: abort(401) if not user.is_superadmin: - abort(403) + abort(HTTPStatus.FORBIDDEN) diff --git a/backend/ibutsu_server/util/login.py b/backend/ibutsu_server/util/login.py index 32a6059f..c912b88d 100644 --- a/backend/ibutsu_server/util/login.py +++ b/backend/ibutsu_server/util/login.py @@ -1,5 +1,6 @@ import base64 import binascii +from http import HTTPStatus def validate_activation_code(activation_code): @@ -7,10 +8,10 @@ def validate_activation_code(activation_code): activation code must be present and base64 encoded """ if not activation_code: - return "Not Found", 404 + return HTTPStatus.NOT_FOUND.phrase, HTTPStatus.NOT_FOUND try: decoded_value = base64.urlsafe_b64decode(activation_code) except (binascii.Error, ValueError): - return f"Activation code {activation_code} is not valid", 400 + return f"Activation code {activation_code} is not valid", HTTPStatus.BAD_REQUEST if not decoded_value: - return f"Activation code {activation_code} is not valid", 400 + return f"Activation code {activation_code} is not valid", HTTPStatus.BAD_REQUEST diff --git a/backend/ibutsu_server/util/query.py b/backend/ibutsu_server/util/query.py index 1c6545fd..24c53c90 100644 --- a/backend/ibutsu_server/util/query.py +++ b/backend/ibutsu_server/util/query.py @@ -1,6 +1,7 @@ """Query utilities""" import re +from http import HTTPStatus from ibutsu_server.constants import MAX_PAGE_SIZE from ibutsu_server.tasks.query import query_task @@ -46,7 +47,7 @@ def query(**kwargs): f"/task/{async_result.id}", "query_endpoint": f"/task/{async_result.id}", } - return response, 201 + return response, HTTPStatus.CREATED else: return function(**kwargs) diff --git a/backend/ibutsu_server/util/uuid.py b/backend/ibutsu_server/util/uuid.py index 369fac2e..905dab3b 100644 --- a/backend/ibutsu_server/util/uuid.py +++ b/backend/ibutsu_server/util/uuid.py @@ -1,4 +1,5 @@ from datetime import datetime, timezone +from http import HTTPStatus from uuid import UUID from bson import ObjectId @@ -21,7 +22,7 @@ def validate_uuid(function): def validate(**kwargs): candidate = kwargs.get("id_") if not is_uuid(candidate): - return f"ID: {candidate} is not a valid UUID", 400 + return f"ID: {candidate} is not a valid UUID", HTTPStatus.BAD_REQUEST else: return function(**kwargs) diff --git a/scripts/ibutsu-pod.sh b/scripts/ibutsu-pod.sh index b5ce7380..1584b4eb 100755 --- a/scripts/ibutsu-pod.sh +++ b/scripts/ibutsu-pod.sh @@ -190,8 +190,8 @@ podman run -d \ -w /mnt \ -v./frontend:/mnt/:Z \ node:18 \ - /bin/bash -c "npm install --no-save --no-package-lock yarn && - yarn install && + /bin/bash -c "npm install --no-save --no-package-lock yarn && + yarn install && CI=1 yarn devserver" echo "done." echo -n "Waiting for frontend to respond: "