From 866a4480c1d9d47401fcfcff138983f57b09203d Mon Sep 17 00:00:00 2001 From: Sam Date: Sat, 12 Feb 2022 14:30:59 +0100 Subject: [PATCH] API - add command to set an admin after fresh install --- Makefile | 3 +++ fittrackee/__main__.py | 14 ++++++++++ fittrackee/tests/users/test_users_utils.py | 30 ++++++++++++++++++++++ fittrackee/tests/utils.py | 12 +++++++++ fittrackee/users/exceptions.py | 2 ++ fittrackee/users/utils.py | 12 ++++++++- pyproject.toml | 1 + 7 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 fittrackee/tests/users/test_users_utils.py create mode 100644 fittrackee/tests/utils.py create mode 100644 fittrackee/users/exceptions.py diff --git a/Makefile b/Makefile index ffd7a1fc..c79bb87f 100644 --- a/Makefile +++ b/Makefile @@ -161,6 +161,9 @@ serve-python-dev: echo 'Running on https://$(HOST):$(PORT)' $(FLASK) run --with-threads -h $(HOST) -p $(PORT) --cert=adhoc +set-admin: + $(FLASK) set-admin $(USERNAME) + test-e2e: init-db $(PYTEST) e2e --driver firefox $(PYTEST_ARGS) diff --git a/fittrackee/__main__.py b/fittrackee/__main__.py index 27bdde0b..ba56e991 100644 --- a/fittrackee/__main__.py +++ b/fittrackee/__main__.py @@ -4,12 +4,15 @@ import os import shutil from typing import Dict, Optional +import click import gunicorn.app.base from flask import Flask from flask_dramatiq import worker from flask_migrate import upgrade from fittrackee import create_app, db +from fittrackee.users.exceptions import UserNotFoundException +from fittrackee.users.utils import set_admin_rights HOST = os.getenv('HOST', '0.0.0.0') PORT = os.getenv('PORT', '5000') @@ -56,6 +59,17 @@ def drop_db() -> None: print('Uploaded files deleted.') +@app.cli.command('set-admin') +@click.argument('username') +def set_admin(username: str) -> None: + """Set admin rights for given user""" + try: + set_admin_rights(username) + print(f"User '{username}' updated.") + except UserNotFoundException: + print(f"User '{username}' not found.") + + def main() -> None: options = {'bind': f'{HOST}:{PORT}', 'workers': WORKERS} StandaloneApplication(app, options).run() diff --git a/fittrackee/tests/users/test_users_utils.py b/fittrackee/tests/users/test_users_utils.py new file mode 100644 index 00000000..f54a4370 --- /dev/null +++ b/fittrackee/tests/users/test_users_utils.py @@ -0,0 +1,30 @@ +import pytest +from flask import Flask + +from fittrackee.users.exceptions import UserNotFoundException +from fittrackee.users.models import User +from fittrackee.users.utils import set_admin_rights + +from ..utils import random_string + + +class TestSetAdminRights: + def test_it_raises_exception_if_user_does_not_exist( + self, app: Flask + ) -> None: + with pytest.raises(UserNotFoundException): + set_admin_rights(random_string()) + + def test_it_sets_admin_right_for_a_given_user( + self, app: Flask, user_1: User + ) -> None: + set_admin_rights(user_1.username) + + assert user_1.admin is True + + def test_it_does_not_raise_exception_when_user_has_already_admin_right( + self, app: Flask, user_1_admin: User + ) -> None: + set_admin_rights(user_1_admin.username) + + assert user_1_admin.admin is True diff --git a/fittrackee/tests/utils.py b/fittrackee/tests/utils.py new file mode 100644 index 00000000..ac0989f0 --- /dev/null +++ b/fittrackee/tests/utils.py @@ -0,0 +1,12 @@ +import random +import string +from typing import Optional + + +def random_string(length: Optional[int] = None) -> str: + if length is None: + length = 10 + return ''.join( + random.choice(string.ascii_letters + string.digits) + for _ in range(length) + ) diff --git a/fittrackee/users/exceptions.py b/fittrackee/users/exceptions.py new file mode 100644 index 00000000..08d04537 --- /dev/null +++ b/fittrackee/users/exceptions.py @@ -0,0 +1,2 @@ +class UserNotFoundException(Exception): + ... diff --git a/fittrackee/users/utils.py b/fittrackee/users/utils.py index 9905657b..ec238332 100644 --- a/fittrackee/users/utils.py +++ b/fittrackee/users/utils.py @@ -3,12 +3,14 @@ from typing import Optional, Tuple from flask import Request +from fittrackee import db from fittrackee.responses import ( ForbiddenErrorResponse, HttpResponse, UnauthorizedErrorResponse, ) +from .exceptions import UserNotFoundException from .models import User @@ -39,7 +41,7 @@ def register_controls( username: str, email: str, password: str, password_conf: str ) -> str: """ - Verify if user name, email and passwords are valid + Verify if username, email and passwords are valid If not, it returns not empty string """ @@ -84,3 +86,11 @@ def can_view_workout( if auth_user_id != workout_user_id: return ForbiddenErrorResponse() return None + + +def set_admin_rights(username: str) -> None: + user = User.query.filter_by(username=username).first() + if not user: + raise UserNotFoundException() + user.admin = True + db.session.commit() diff --git a/pyproject.toml b/pyproject.toml index 658d89ef..253113a9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,6 +62,7 @@ Sphinx = "^4.4.0" [tool.poetry.scripts] fittrackee = 'fittrackee.__main__:main' +fittrackee_set_admin = 'fittrackee.__main__:set_admin' fittrackee_upgrade_db = 'fittrackee.__main__:upgrade_db' fittrackee_worker = 'fittrackee.__main__:dramatiq_worker'