about summary refs log tree commit diff
path: root/gn3/auth
diff options
context:
space:
mode:
Diffstat (limited to 'gn3/auth')
-rw-r--r--gn3/auth/authorisation/resources/views.py70
1 files changed, 69 insertions, 1 deletions
diff --git a/gn3/auth/authorisation/resources/views.py b/gn3/auth/authorisation/resources/views.py
index cac904c..1da93d0 100644
--- a/gn3/auth/authorisation/resources/views.py
+++ b/gn3/auth/authorisation/resources/views.py
@@ -1,19 +1,25 @@
 """The views/routes for the resources package"""
 import uuid
+import json
+from functools import reduce
 
 from flask import request, jsonify, Response, Blueprint, current_app as app
 
 from gn3.auth.db_utils import with_db_connection
 
+from .checks import authorised_for
 from .models import (
     resource_by_id, resource_categories, link_data_to_resource,
     resource_category_by_id, unlink_data_from_resource,
     create_resource as _create_resource)
 
-from ..errors import InvalidData
+from ..roles import Role
+from ..errors import InvalidData, AuthorisationError
+from ..groups.models import Group, GroupRole, user_group, DUMMY_GROUP
 
 from ... import db
 from ...dictify import dictify
+from ...authentication.users import User
 from ...authentication.oauth2.resource_server import require_oauth
 
 resources = Blueprint("resources", __name__)
@@ -94,3 +100,65 @@ def unlink_data():
             return jsonify(with_db_connection(__unlink__))
     except AssertionError as aserr:
         raise InvalidData(aserr.args[0]) from aserr
+
+@resources.route("<uuid:resource_id>/users", methods=["GET"])
+@require_oauth("profile group resource")
+def resource_users(resource_id: uuid.UUID):
+    """Retrieve all users with access to the given resource."""
+    with require_oauth.acquire("profile group resource") as the_token:
+        def __the_users__(conn: db.DbConnection):
+            authorised = authorised_for(
+                conn, the_token.user, ("group:resource:edit-resource",),
+                (resource_id,))
+            if authorised.get(resource_id, False):
+                with db.cursor(conn) as cursor:
+                    group = user_group(cursor, the_token.user).maybe(
+                        DUMMY_GROUP, lambda grp: grp)
+                    if group == DUMMY_GROUP:
+                        raise AuthorisationError(
+                            "Users who are not members of groups cannot access "
+                            "resource details.")
+                    def __organise_users_n_roles__(users_n_roles, row):
+                        user_id = uuid.UUID(row["user_id"])
+                        user = users_n_roles.get(
+                            user_id, User(user_id, row["email"], row["name"]))
+                        role = GroupRole(
+                            uuid.UUID(row["group_role_id"]),
+                            group,
+                            Role(uuid.UUID(row["role_id"]), row["role_name"],
+                                 tuple()))
+                        return {
+                            **users_n_roles,
+                            user_id: {
+                                "user": user,
+                                "user_group": Group(
+                                    uuid.UUID(row["group_id"]), row["group_name"],
+                                    json.loads(row["group_metadata"])),
+                                "roles": users_n_roles.get(
+                                    user_id, {}).get("roles", tuple()) + (role,)
+                            }
+                        }
+                    cursor.execute(
+                        "SELECT g.*, u.*, r.*, gr.group_role_id "
+                        "FROM groups AS g INNER JOIN "
+                        "group_users AS gu ON g.group_id=gu.group_id "
+                        "INNER JOIN users AS u ON gu.user_id=u.user_id "
+                        "INNER JOIN group_user_roles_on_resources AS guror "
+                        "ON u.user_id=guror.user_id INNER JOIN roles AS r "
+                        "ON guror.role_id=r.role_id "
+                        "INNER JOIN group_roles AS gr ON r.role_id=gr.role_id "
+                        "WHERE guror.resource_id=?",
+                        (str(resource_id),))
+                    return reduce(__organise_users_n_roles__, cursor.fetchall(), {})
+            raise AuthorisationError(
+                "You do not have sufficient privileges to view the resource "
+                "users.")
+        results = (
+            {
+                "user": dictify(row["user"]),
+                "user_group": dictify(row["user_group"]),
+                "roles": tuple(dictify(role) for role in row["roles"])
+            } for row in (
+                user_row for user_id, user_row
+                in with_db_connection(__the_users__).items()))
+        return jsonify(tuple(results))