aboutsummaryrefslogtreecommitdiff
path: root/gn3/auth/authorisation/groups
diff options
context:
space:
mode:
Diffstat (limited to 'gn3/auth/authorisation/groups')
-rw-r--r--gn3/auth/authorisation/groups/models.py60
-rw-r--r--gn3/auth/authorisation/groups/views.py27
2 files changed, 81 insertions, 6 deletions
diff --git a/gn3/auth/authorisation/groups/models.py b/gn3/auth/authorisation/groups/models.py
index 49b5066..f78aedd 100644
--- a/gn3/auth/authorisation/groups/models.py
+++ b/gn3/auth/authorisation/groups/models.py
@@ -8,11 +8,11 @@ from pymonad.maybe import Just, Maybe, Nothing
from gn3.auth import db
from gn3.auth.dictify import dictify
-from gn3.auth.authentication.users import User
+from gn3.auth.authentication.users import User, user_by_id, DUMMY_USER
from ..checks import authorised_p
from ..privileges import Privilege
-from ..errors import NotFoundError, AuthorisationError
+from ..errors import NotFoundError, AuthorisationError, InconsistencyError
from ..roles.models import (
Role, create_role, revoke_user_role_by_name, assign_user_role_by_name)
@@ -29,6 +29,13 @@ class Group(NamedTuple):
"group_metadata": self.group_metadata
}
+DUMMY_GROUP = Group(
+ group_id=UUID("77cee65b-fe29-4383-ae41-3cb3b480cc70"),
+ group_name="GN3_DUMMY_GROUP",
+ group_metadata={
+ "group-description": "This is a dummy group to use as a placeholder"
+ })
+
class GroupRole(NamedTuple):
"""Class representing a role tied/belonging to a group."""
group_role_id: UUID
@@ -242,3 +249,52 @@ def group_by_id(conn: db.DbConnection, group_id: UUID) -> Group:
json.loads(row["group_metadata"]))
raise NotFoundError(f"Could not find group with ID '{group_id}'.")
+
+@authorised_p(("system:group:view-group", "system:group:edit-group"),
+ error_description=("You do not have the appropriate authorisation"
+ " to act upon the join requests."),
+ oauth2_scope="profile group")
+def join_requests(conn: db.DbConnection, user: User):
+ """List all the join requests for the user's group."""
+ with db.cursor(conn) as cursor:
+ group = user_group(cursor, user).maybe(DUMMY_GROUP, lambda grp: grp)# type: ignore[misc]
+ if group != DUMMY_GROUP and is_group_leader(cursor, user, group):
+ cursor.execute(
+ "SELECT gjr.*, u.email, u.name FROM group_join_requests AS gjr "
+ "INNER JOIN users AS u ON gjr.requester_id=u.user_id "
+ "WHERE gjr.group_id=? AND gjr.status='PENDING'",
+ (str(group.group_id),))
+ return tuple(dict(row)for row in cursor.fetchall())
+
+ raise AuthorisationError(
+ "You do not have the appropriate authorisation to access the "
+ "group's join requests.")
+
+@authorised_p(("system:group:view-group", "system:group:edit-group"),
+ error_description=("You do not have the appropriate authorisation"
+ " to act upon the join requests."),
+ oauth2_scope="profile group")
+def accept_join_request(conn: db.DbConnection, request_id: UUID, user: User):
+ """Accept a join request."""
+ with db.cursor(conn) as cursor:
+ group = user_group(cursor, user).maybe(DUMMY_GROUP, lambda grp: grp) # type: ignore[misc]
+ cursor.execute("SELECT * FROM group_join_requests WHERE request_id=?",
+ (str(request_id),))
+ row = cursor.fetchone()
+ if row:
+ if group.group_id == UUID(row["group_id"]):
+ the_user = user_by_id(conn, UUID(row["requester_id"])).maybe(# type: ignore[misc]
+ DUMMY_USER, lambda usr: usr)
+ if the_user == DUMMY_USER:
+ raise InconsistencyError(
+ "Could not find user associated with join request.")
+ add_user_to_group(cursor, group, the_user)
+ revoke_user_role_by_name(cursor, the_user, "group-creator")
+ cursor.execute(
+ "UPDATE group_join_requests SET status='ACCEPTED' "
+ "WHERE request_id=?",
+ (str(request_id),))
+ return {"request_id": request_id, "status": "ACCEPTED"}
+ raise AuthorisationError(
+ "You cannot act on other groups join requests")
+ raise NotFoundError(f"Could not find request with ID '{request_id}'")
diff --git a/gn3/auth/authorisation/groups/views.py b/gn3/auth/authorisation/groups/views.py
index f6675ab..f12c75c 100644
--- a/gn3/auth/authorisation/groups/views.py
+++ b/gn3/auth/authorisation/groups/views.py
@@ -10,7 +10,8 @@ from gn3.auth.dictify import dictify
from gn3.auth.db_utils import with_db_connection
from .models import (
- user_group, all_groups, GroupCreationError, group_users as _group_users,
+ user_group, all_groups, join_requests, accept_join_request,
+ GroupCreationError, group_users as _group_users,
create_group as _create_group)
from ..errors import AuthorisationError
@@ -76,14 +77,14 @@ def request_to_join(group_id: uuid.UUID) -> Response:
raise error
request_id = uuid.uuid4()
cursor.execute(
- "INSERT INTO group_requests VALUES "
- "(:request_id, :group_id, :user_id, :ts, :type, :msg)",
+ "INSERT INTO group_join_requests VALUES "
+ "(:request_id, :group_id, :user_id, :ts, :status, :msg)",
{
"request_id": str(request_id),
"group_id": str(group_id),
"user_id": str(user.user_id),
"ts": datetime.datetime.now().timestamp(),
- "type": "JOIN",
+ "status": "PENDING",
"msg": message
})
return {
@@ -97,3 +98,21 @@ def request_to_join(group_id: uuid.UUID) -> Response:
__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)
+
+@groups.route("/requests/join/list", methods=["GET"])
+@require_oauth("profile group")
+def list_join_requests() -> Response:
+ """List the pending join requests."""
+ with require_oauth.acquire("profile group") as the_token:
+ return jsonify(with_db_connection(partial(
+ join_requests, user=the_token.user)))
+
+@groups.route("/requests/join/accept", methods=["POST"])
+@require_oauth("profile group")
+def accept_join_requests() -> Response:
+ """Accept a join request."""
+ with require_oauth.acquire("profile group") as the_token:
+ form = request.form
+ request_id = uuid.UUID(form.get("request_id"))
+ return jsonify(with_db_connection(partial(
+ accept_join_request, request_id=request_id, user=the_token.user)))