aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gn3/auth/authorisation/groups/views.py47
-rw-r--r--gn3/auth/db_utils.py14
-rw-r--r--migrations/auth/20230207_01_r0bkZ-create-group-requests-table.py27
-rw-r--r--tests/unit/auth/test_migrations_create_tables.py3
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)