about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFrederick Muriuki Muriithi2023-04-24 11:45:45 +0300
committerFrederick Muriuki Muriithi2023-04-24 11:45:45 +0300
commit3e2198e39bc229553d118f367fbd2f9932a9a76b (patch)
tree8c388b14df38240a159358475ecf35f85b6d4d9c
parent993420e616e143684deb1c11565b6a8286cde37f (diff)
downloadgenenetwork3-3e2198e39bc229553d118f367fbd2f9932a9a76b.tar.gz
auth: Return the actual privileges for the user
Previously, the `oauth2/data/authorisation` endpoint was returning hard-coded
values for the privileges assigned to the user for each resource. In this
change, we rework to return the actual privileges for the user.
-rw-r--r--gn3/auth/authorisation/data/views.py38
-rw-r--r--gn3/auth/authorisation/resources/models.py21
-rw-r--r--gn3/auth/authorisation/users/models.py47
3 files changed, 84 insertions, 22 deletions
diff --git a/gn3/auth/authorisation/data/views.py b/gn3/auth/authorisation/data/views.py
index 81b3e2f..d2bdbf3 100644
--- a/gn3/auth/authorisation/data/views.py
+++ b/gn3/auth/authorisation/data/views.py
@@ -22,6 +22,8 @@ from gn3.auth.authorisation.errors import InvalidData, NotFoundError
 
 from gn3.auth.authorisation.groups.models import group_by_id
 
+from gn3.auth.authorisation.users.models import user_resource_roles
+
 from gn3.auth.authorisation.resources.checks import authorised_for
 from gn3.auth.authorisation.resources.models import (
     user_resources, public_resources, attach_resources_data)
@@ -53,14 +55,17 @@ def authorisation() -> Response:
             with require_oauth.acquire("profile group resource") as the_token:
                 resources = attach_resources_data(
                     auth_conn, user_resources(auth_conn, the_token.user))
+                resources_roles = user_resource_roles(auth_conn, the_token.user)
                 privileges = {
-                    resource_id: ("group:resource:view-resource",)
+                    resource_id: tuple(
+                        privilege.privilege_id
+                        for roles in resources_roles[resource_id]
+                        for privilege in roles.privileges)#("group:resource:view-resource",)
                     for resource_id, is_authorised
                     in authorised_for(
                         auth_conn, the_token.user,
                         ("group:resource:view-resource",), tuple(
-                            resource.resource_id for resource in resources
-                            if not resource.public)).items()
+                            resource.resource_id for resource in resources)).items()
                     if is_authorised
                 }
         except _HTTPException as exc:
@@ -76,18 +81,26 @@ def authorisation() -> Response:
         #    -H "Content-Type: application/json" \
         #    -d '{"traits": ["HC_M2_0606_P::1442370_at", "BXDGeno::01.001.695",
         #        "BXDPublish::10001"]}'
+        def __gen_key__(resource, data_item):
+            if resource.resource_category.resource_category_key.lower() == "phenotype":
+                return (
+                    f"{resource.resource_category.resource_category_key.lower()}::"
+                    f"{data_item['dataset_name']}::{data_item['PublishXRefId']}")
+            return (
+                f"{resource.resource_category.resource_category_key.lower()}::"
+                f"{data_item['dataset_name']}")
+
         data_to_resource_map = {
-            (f"{data_item['dataset_type'].lower()}::"
-             f"{data_item['dataset_name']}"): resource.resource_id
+            __gen_key__(resource, data_item): resource.resource_id
             for resource in resources
             for data_item in resource.resource_data
         }
         privileges = {
-            **privileges,
             **{
                 resource.resource_id: ("system:resource:public-read",)
                 for resource in resources if resource.public
-            }}
+            },
+            **privileges}
 
         args = request.get_json()
         traits_names = args["traits"] # type: ignore[index]
@@ -97,6 +110,14 @@ def authorisation() -> Response:
                 "Geno": "Genotype",
                 "Publish": "Phenotype"
             }[val]
+
+        def __trait_key__(trait):
+            dataset_type = __translate__(trait['db']['dataset_type']).lower()
+            dataset_name = trait["db"]["dataset_name"]
+            if dataset_type == "phenotype":
+                return f"{dataset_type}::{dataset_name}::{trait['trait_name']}"
+            return f"{dataset_type}::{dataset_name}"
+
         return jsonify(tuple(
             {
                 **{key:trait[key] for key in ("trait_fullname", "trait_name")},
@@ -104,8 +125,7 @@ def authorisation() -> Response:
                 "dataset_type": __translate__(trait["db"]["dataset_type"]),
                 "privileges": privileges.get(
                     data_to_resource_map.get(
-                        f"{__translate__(trait['db']['dataset_type']).lower()}"
-                        f"::{trait['db']['dataset_name']}",
+                        __trait_key__(trait),
                         uuid.UUID("4afa415e-94cb-4189-b2c6-f9ce2b6a878d")),
                     tuple())
             } for trait in
diff --git a/gn3/auth/authorisation/resources/models.py b/gn3/auth/authorisation/resources/models.py
index bc88691..e54ec48 100644
--- a/gn3/auth/authorisation/resources/models.py
+++ b/gn3/auth/authorisation/resources/models.py
@@ -423,9 +423,8 @@ def attach_mrna_resources_data(
     """Attach linked data to mRNA Assay resources"""
     placeholders = ", ".join(["?"] * len(resources))
     cursor.execute(
-        "SELECT * FROM mrna_resources AS mr INNER JOIN linked_group_data AS lgd"
-        " ON (mr.dataset_id=lgd.dataset_or_trait_id "
-        "AND mr.dataset_type=lgd.dataset_type) "
+        "SELECT * FROM mrna_resources AS mr INNER JOIN linked_mrna_data AS lmd"
+        " ON mr.data_link_id=lmd.data_link_id "
         f"WHERE mr.resource_id IN ({placeholders})",
         tuple(str(resource.resource_id) for resource in resources))
     return __attach_data__(cursor.fetchall(), resources)
@@ -436,10 +435,9 @@ def attach_genotype_resources_data(
     placeholders = ", ".join(["?"] * len(resources))
     cursor.execute(
         "SELECT * FROM genotype_resources AS gr "
-        "INNER JOIN linked_group_data AS lgd "
-        "ON (gr.trait_id=lgd.dataset_or_trait_id "
-        "AND gr.dataset_type=lgd.dataset_type) "
-        f"WHERE gr.resource_id IN {placeholders}",
+        "INNER JOIN linked_genotype_data AS lgd "
+        "ON gr.data_link_id=lgd.data_link_id "
+        f"WHERE gr.resource_id IN ({placeholders})",
         tuple(str(resource.resource_id) for resource in resources))
     return __attach_data__(cursor.fetchall(), resources)
 
@@ -449,10 +447,9 @@ def attach_phenotype_resources_data(
     placeholders = ", ".join(["?"] * len(resources))
     cursor.execute(
         "SELECT * FROM phenotype_resources AS pr "
-        "INNER JOIN linked_group_data AS lgd "
-        "ON (pr.trait_id=lgd.dataset_or_trait_id "
-        "AND pr.dataset_type=lgd.dataset_type) "
-        f"WHERE pr.resource_id IN {placeholders}",
+        "INNER JOIN linked_phenotype_data AS lpd "
+        "ON pr.data_link_id=lpd.data_link_id "
+        f"WHERE pr.resource_id IN ({placeholders})",
         tuple(str(resource.resource_id) for resource in resources))
     return __attach_data__(cursor.fetchall(), resources)
 
@@ -532,8 +529,6 @@ def save_resource(
         conn, user, ("group:resource:edit-resource",), (resource_id,))
     if authorised[resource_id]:
         with db.cursor(conn) as cursor:
-            params = {**dictify(resource), "public": 1 if resource.public else 0}
-            print(f"THE PARAMS: {params}")
             cursor.execute(
                 "UPDATE resources SET "
                 "resource_name=:resource_name, "
diff --git a/gn3/auth/authorisation/users/models.py b/gn3/auth/authorisation/users/models.py
index 844a8a9..8cfc1af 100644
--- a/gn3/auth/authorisation/users/models.py
+++ b/gn3/auth/authorisation/users/models.py
@@ -1,8 +1,11 @@
 """Functions for acting on users."""
 import uuid
+from functools import reduce
 
 from gn3.auth import db
+from gn3.auth.authorisation.roles.models import Role
 from gn3.auth.authorisation.checks import authorised_p
+from gn3.auth.authorisation.privileges import Privilege
 
 from gn3.auth.authentication.users import User
 
@@ -17,3 +20,47 @@ def list_users(conn: db.DbConnection) -> tuple[User, ...]:
         return tuple(
             User(uuid.UUID(row["user_id"]), row["email"], row["name"])
             for row in cursor.fetchall())
+
+def __build_resource_roles__(rows):
+    def __build_roles__(roles, row):
+        role_id = uuid.UUID(row["role_id"])
+        priv = Privilege(row["privilege_id"], row["privilege_description"])
+        role = roles.get(role_id, Role(
+            role_id, row["role_name"], tuple()))
+        return {
+            **roles,
+            role_id: Role(role_id, role.role_name, role.privileges + (priv,))
+        }
+    def __build__(acc, row):
+        resource_id = uuid.UUID(row["resource_id"])
+        return {
+            **acc,
+            resource_id: __build_roles__(acc.get(resource_id, {}), row)
+        }
+    return {
+        resource_id: tuple(roles.values())
+        for resource_id, roles in reduce(__build__, rows, {}).items()
+    }
+
+# @authorised_p(
+#     ("",),
+#     ("You do not have the appropriate privileges to view a user's roles on "
+#      "resources."))
+def user_resource_roles(conn: db.DbConnection, user: User) -> dict[uuid.UUID, tuple[Role, ...]]:
+    """Fetch all the user's roles on resources."""
+    with db.cursor(conn) as cursor:
+        cursor.execute(
+            "SELECT res.*, rls.*, p.*"
+            "FROM resources AS res INNER JOIN "
+            "group_user_roles_on_resources AS guror "
+            "ON res.resource_id=guror.resource_id "
+            "LEFT JOIN roles AS rls "
+            "ON guror.role_id=rls.role_id "
+            "LEFT JOIN role_privileges AS rp "
+            "ON rls.role_id=rp.role_id "
+            "LEFT JOIN privileges AS p "
+            "ON rp.privilege_id=p.privilege_id "
+            "WHERE guror.user_id = ?",
+            (str(user.user_id),))
+        return __build_resource_roles__(
+            (dict(row) for row in cursor.fetchall()))