diff options
-rw-r--r-- | gn3/auth/authorisation/groups/views.py | 47 | ||||
-rw-r--r-- | gn3/auth/db_utils.py | 14 | ||||
-rw-r--r-- | migrations/auth/20230207_01_r0bkZ-create-group-requests-table.py | 27 | ||||
-rw-r--r-- | tests/unit/auth/test_migrations_create_tables.py | 3 |
4 files changed, 89 insertions, 2 deletions
diff --git a/gn3/auth/authorisation/groups/views.py b/gn3/auth/authorisation/groups/views.py index 02b3162..f6675ab 100644 --- a/gn3/auth/authorisation/groups/views.py +++ b/gn3/auth/authorisation/groups/views.py @@ -1,15 +1,21 @@ """The views/routes for the `gn3.auth.authorisation.groups` package.""" import uuid +import datetime +from functools import partial from flask import request, jsonify, Response, Blueprint, current_app from gn3.auth import db from gn3.auth.dictify import dictify +from gn3.auth.db_utils import with_db_connection from .models import ( - all_groups, GroupCreationError, group_users as _group_users, + user_group, all_groups, GroupCreationError, group_users as _group_users, create_group as _create_group) +from ..errors import AuthorisationError + +from ...authentication.users import User from ...authentication.oauth2.resource_server import require_oauth groups = Blueprint("groups", __name__) @@ -52,3 +58,42 @@ def group_members(group_id: uuid.UUID) -> Response: with db.connection(db_uri) as conn: return jsonify(tuple( dictify(user) for user in _group_users(conn, group_id))) + +@groups.route("/requests/join/<uuid:group_id>", methods=["POST"]) +@require_oauth("profile group") +def request_to_join(group_id: uuid.UUID) -> Response: + """Request to join a group.""" + def __request__(conn: db.DbConnection, user: User, group_id: uuid.UUID, + message: str): + with db.cursor(conn) as cursor: + group = user_group(cursor, user).maybe(# type: ignore[misc] + False, lambda grp: grp)# type: ignore[arg-type] + if group: + error = AuthorisationError( + "You cannot request to join a new group while being a " + "member of an existing group.") + error.error_code = 400 + raise error + request_id = uuid.uuid4() + cursor.execute( + "INSERT INTO group_requests VALUES " + "(:request_id, :group_id, :user_id, :ts, :type, :msg)", + { + "request_id": str(request_id), + "group_id": str(group_id), + "user_id": str(user.user_id), + "ts": datetime.datetime.now().timestamp(), + "type": "JOIN", + "msg": message + }) + return { + "request_id": request_id, + "message": "Successfully sent the join request." + } + + with require_oauth.acquire("profile group") as the_token: + form = request.form + results = with_db_connection(partial( + __request__, user=the_token.user, group_id=group_id, message=form.get( + "message", "I hereby request that you add me to your group."))) + return jsonify(results) diff --git a/gn3/auth/db_utils.py b/gn3/auth/db_utils.py new file mode 100644 index 0000000..c06b026 --- /dev/null +++ b/gn3/auth/db_utils.py @@ -0,0 +1,14 @@ +"""Some common auth db utilities""" +from typing import Any, Callable +from flask import current_app + +from . import db + +def with_db_connection(func: Callable[[db.DbConnection], Any]) -> Any: + """ + Takes a function of one argument `func`, whose one argument is a database + connection. + """ + db_uri = current_app.config["AUTH_DB"] + with db.connection(db_uri) as conn: + return func(conn) diff --git a/migrations/auth/20230207_01_r0bkZ-create-group-requests-table.py b/migrations/auth/20230207_01_r0bkZ-create-group-requests-table.py new file mode 100644 index 0000000..d2cf786 --- /dev/null +++ b/migrations/auth/20230207_01_r0bkZ-create-group-requests-table.py @@ -0,0 +1,27 @@ +""" +Create group_requests table +""" + +from yoyo import step + +__depends__ = {'20230116_01_KwuJ3-rework-privileges-schema'} + +steps = [ + step( + """ + CREATE TABLE IF NOT EXISTS group_requests( + request_id TEXT NOT NULL, + group_id TEXT NOT NULL, + requester_id TEXT NOT NULL, + request_type TEXT NOT NULL, + timestamp REAL NOT NULL, + message TEXT, + PRIMARY KEY(request_id, group_id), + FOREIGN KEY(group_id) REFERENCES groups(group_id) + ON UPDATE CASCADE ON DELETE CASCADE, + FOREIGN KEY (requester_id) REFERENCES users(user_id) + ON UPDATE CASCADE ON DELETE CASCADE + ) WITHOUT ROWID + """, + "DROP TABLE IF EXISTS group_requests") +] diff --git a/tests/unit/auth/test_migrations_create_tables.py b/tests/unit/auth/test_migrations_create_tables.py index 0fda718..55d51aa 100644 --- a/tests/unit/auth/test_migrations_create_tables.py +++ b/tests/unit/auth/test_migrations_create_tables.py @@ -30,7 +30,8 @@ migrations_and_tables = ( ("20221219_01_CI3tN-create-oauth2-clients-table.py", "oauth2_clients"), ("20221219_02_buSEU-create-oauth2-tokens-table.py", "oauth2_tokens"), ("20221219_03_PcTrb-create-authorisation-code-table.py", - "authorisation_code")) + "authorisation_code"), + ("20230207_01_r0bkZ-create-group-requests-table.py", "group_requests")) @pytest.mark.unit_test @pytest.mark.parametrize("migration_file,the_table", migrations_and_tables) |