about summary refs log tree commit diff
path: root/gn3
diff options
context:
space:
mode:
authorFrederick Muriuki Muriithi2023-04-08 08:26:50 +0300
committerFrederick Muriuki Muriithi2023-04-08 08:26:50 +0300
commite636acc412fef6b1d5aa08ac701bbadc3be52b80 (patch)
treee46f3281df1080e29f588ad146ed4260ff4dfb7b /gn3
parentdb6457bfbcccce35162d9d2ece988c7c8c8f9308 (diff)
downloadgenenetwork3-e636acc412fef6b1d5aa08ac701bbadc3be52b80.tar.gz
auth: Link genotype datasets to groups.
Diffstat (limited to 'gn3')
-rw-r--r--gn3/auth/authorisation/data/genotypes.py45
-rw-r--r--gn3/auth/authorisation/data/views.py34
2 files changed, 71 insertions, 8 deletions
diff --git a/gn3/auth/authorisation/data/genotypes.py b/gn3/auth/authorisation/data/genotypes.py
index 690293c..fe06726 100644
--- a/gn3/auth/authorisation/data/genotypes.py
+++ b/gn3/auth/authorisation/data/genotypes.py
@@ -1,11 +1,14 @@
 """Handle linking of Genotype data to the Auth(entic|oris)ation system."""
+import uuid
 from typing import Iterable
 
 from MySQLdb.cursors import DictCursor
 
 import gn3.auth.db as authdb
 import gn3.db_utils as gn3db
+from gn3.auth.dictify import dictify
 from gn3.auth.authorisation.checks import authorised_p
+from gn3.auth.authorisation.groups.models import Group
 
 def linked_genotype_data(conn: authdb.DbConnection) -> Iterable[dict]:
     """Retrive genotype data that is linked to user groups."""
@@ -39,11 +42,11 @@ def ungrouped_genotype_data(
         query = query + "WHERE "
 
     if len(params) > 0:
-        paramstr = ", ".join(["(?, ?, ?)"] * len(params))
+        paramstr = ", ".join(["(%s, %s, %s)"] * len(params))
         query = query + (
-            "(s.SpeciesId, iset.InbredSetId, GenoFreezeId) "
+            "(s.SpeciesId, iset.InbredSetId, gf.Id) "
             f"NOT IN ({paramstr}) "
-            "AND ")
+            ) + ("AND " if bool(search_query) else "")
 
     if bool(search_query):
         query = query + (
@@ -51,7 +54,41 @@ def ungrouped_genotype_data(
         params = params + ((search_query,),)# type: ignore[operator]
 
     query = query + f"LIMIT {int(limit)} OFFSET {int(offset)}"
+    final_params = tuple(item for sublist in params for item in sublist)
     with gn3conn.cursor(DictCursor) as cursor:
         cursor.execute(
-            query, tuple(item for sublist in params for item in sublist))
+            query, final_params)
         return tuple(row for row in cursor.fetchall())
+
+@authorised_p(
+    ("system:data:link-to-group",),
+    error_description=(
+        "You do not have sufficient privileges to link data to (a) "
+        "group(s)."),
+    oauth2_scope="profile group resource")
+def link_genotype_data(
+        conn: authdb.DbConnection, group: Group, datasets: dict) -> dict:
+    """Link genotye `datasets` to `group`."""
+    with authdb.cursor(conn) as cursor:
+        cursor.executemany(
+            "INSERT INTO linked_genotype_data VALUES "
+            "(:data_link_id, :group_id, :SpeciesId, :InbredSetId, "
+            ":GenoFreezeId, :dataset_name, :dataset_fullname, "
+            ":dataset_shortname) "
+            "ON CONFLICT (SpeciesId, InbredSetId, GenoFreezeId) DO NOTHING",
+            tuple({
+                "data_link_id": str(uuid.uuid4()),
+                "group_id": str(group.group_id),
+                **{
+                    key: value for key,value in dataset.items() if key in (
+                        "GenoFreezeId", "InbredSetId", "SpeciesId",
+                        "dataset_fullname", "dataset_name", "dataset_shortname")
+                }
+            } for dataset in datasets))
+        return {
+            "description": (
+                f"Successfully linked {len(datasets)} to group "
+                f"'{group.group_name}'."),
+            "group": dictify(group),
+            "datasets": datasets
+        }
diff --git a/gn3/auth/authorisation/data/views.py b/gn3/auth/authorisation/data/views.py
index 70b14d7..55a7373 100644
--- a/gn3/auth/authorisation/data/views.py
+++ b/gn3/auth/authorisation/data/views.py
@@ -6,7 +6,7 @@ import random
 import string
 import datetime
 from functools import reduce, partial
-from typing import Sequence, Iterable
+from typing import Any, Sequence, Iterable
 
 import redis
 from MySQLdb.cursors import DictCursor
@@ -21,14 +21,14 @@ from gn3.auth import db
 from gn3.auth.dictify import dictify
 from gn3.auth.db_utils import with_db_connection
 
-from gn3.auth.authorisation.errors import NotFoundError
+from gn3.auth.authorisation.errors import InvalidData, NotFoundError
 
 from gn3.auth.authorisation.roles.models import(
     revoke_user_role_by_name, assign_user_role_by_name)
 
 from gn3.auth.authorisation.groups.data import retrieve_ungrouped_data
 from gn3.auth.authorisation.groups.models import (
-    Group, user_group, add_user_to_group)
+    Group, user_group, group_by_id, add_user_to_group)
 
 from gn3.auth.authorisation.resources.checks import authorised_for
 from gn3.auth.authorisation.resources.models import (
@@ -40,7 +40,8 @@ from gn3.auth.authorisation.errors import ForbiddenAccess
 from gn3.auth.authentication.oauth2.resource_server import require_oauth
 from gn3.auth.authentication.users import User, user_by_email, set_user_password
 
-from gn3.auth.authorisation.data.genotypes import ungrouped_genotype_data
+from gn3.auth.authorisation.data.genotypes import (
+    link_genotype_data, ungrouped_genotype_data)
 
 data = Blueprint("data", __name__)
 
@@ -336,3 +337,28 @@ def search_unlinked_data():
         "phenotype": __search_phenotypes__
     }
     return search_fns[dataset_type]()
+
+@data.route("/link/genotype", methods=["POST"])
+def link_genotypes() -> Response:
+    """Link genotype data to group."""
+    def __values__(form) -> dict[str, Any]:
+        if not bool(form.get("species_name", "").strip()):
+            raise InvalidData("Expected 'species_name' not provided.")
+        if not bool(form.get("group_id")):
+            raise InvalidData("Expected 'group_id' not provided.",)
+        try:
+            _group_id = uuid.UUID(form.get("group_id"))
+        except TypeError as terr:
+            raise InvalidData("Expected a UUID for 'group_id' value.") from terr
+        if not bool(form.get("selected_datasets")):
+            raise InvalidData("Expected at least one dataset to be provided.")
+        return {
+            "group_id": uuid.UUID(form.get("group_id")),
+            "datasets": form.get("selected_datasets")
+        }
+
+    def __link__(conn: db.DbConnection, group_id: uuid.UUID, datasets: dict):
+        return link_genotype_data(conn, group_by_id(conn, group_id), datasets)
+
+    return jsonify(with_db_connection(
+        partial(__link__, **__values__(request.json))))