aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrederick Muriuki Muriithi2023-04-19 17:49:58 +0300
committerFrederick Muriuki Muriithi2023-04-19 18:07:19 +0300
commit735adc012cc5d974eb8eabb26eda6c483af0da1a (patch)
treefad7b75fd7df167fa859674653f2b93274d3ba35
parent2a7e8b7ffdf260a643c7fcd615c8982d3268347f (diff)
downloadgenenetwork3-735adc012cc5d974eb8eabb26eda6c483af0da1a.tar.gz
oauth2: Link the phenotype traits to user groups.
-rw-r--r--gn3/auth/authorisation/data/phenotypes.py69
-rw-r--r--gn3/auth/authorisation/data/views.py29
-rw-r--r--scripts/search_phenotypes.py2
3 files changed, 95 insertions, 5 deletions
diff --git a/gn3/auth/authorisation/data/phenotypes.py b/gn3/auth/authorisation/data/phenotypes.py
index a330d4a..ff98295 100644
--- a/gn3/auth/authorisation/data/phenotypes.py
+++ b/gn3/auth/authorisation/data/phenotypes.py
@@ -1,11 +1,14 @@
"""Handle linking of Phenotype data to the Auth(entic|oris)ation system."""
+import uuid
from typing import Any, 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_phenotype_data(
authconn: authdb.DbConnection, gn3conn: gn3db.Connection,
@@ -19,9 +22,9 @@ def linked_phenotype_data(
for row in authcursor.fetchall())
if len(linked) <= 0:
return iter(())
- paramstr = "".join(["(%s, %s, %s, %s)"] * len(linked))
+ paramstr = ", ".join(["(%s, %s, %s, %s)"] * len(linked))
query = (
- "SELECT spc.SpeciesId, spc.SpeciesName, iset.InbredSetId, "
+ "SELECT spc.SpeciesId, spc.Name AS SpeciesName, iset.InbredSetId, "
"iset.InbredSetName, pf.Id AS PublishFreezeId, "
"pf.Name AS dataset_name, pf.FullName AS dataset_fullname, "
"pf.ShortName AS dataset_shortname, pxr.Id AS PublishXRefId "
@@ -35,10 +38,11 @@ def linked_phenotype_data(
"ON pf.InbredSetId=pxr.InbredSetId") + (
" WHERE" if (len(linked) > 0 or bool(species)) else "") + (
(" (spc.SpeciesId, iset.InbredSetId, pf.Id, pxr.Id) "
- f"NOT IN ({paramstr})") if len(linked) > 0 else "") + (
+ f"IN ({paramstr})") if len(linked) > 0 else "") + (
" AND"if len(linked) > 0 else "") + (
" spc.SpeciesName=%s" if bool(species) else "")
- params = linked + ((species,) if bool(species) else tuple())
+ params = tuple(item for sublist in linked for item in sublist) + (
+ (species,) if bool(species) else tuple())
gn3cursor.execute(query, params)
return (item for item in gn3cursor.fetchall())
@@ -77,3 +81,60 @@ def ungrouped_phenotype_data(
return tuple(dict(row) for row in cursor.fetchall())
return tuple()
+
+def __traits__(gn3conn: gn3db.Connection, params: tuple[dict, ...]) -> tuple[dict, ...]:
+ """An internal utility function. Don't use outside of this module."""
+ if len(params) < 1:
+ return tuple()
+ paramstr = ", ".join(["(%s, %s, %s, %s)"] * len(params))
+ with gn3conn.cursor(DictCursor) as cursor:
+ cursor.execute(
+ "SELECT spc.SpeciesId, iset.InbredSetId, pf.Id AS PublishFreezeId, "
+ "pf.Name AS dataset_name, pf.FullName AS dataset_fullname, "
+ "pf.ShortName AS dataset_shortname, pxr.Id AS PublishXRefId "
+ "FROM "
+ "Species AS spc "
+ "INNER JOIN InbredSet AS iset "
+ "ON spc.SpeciesId=iset.SpeciesId "
+ "INNER JOIN PublishFreeze AS pf "
+ "ON iset.InbredSetId=pf.InbredSetId "
+ "INNER JOIN PublishXRef AS pxr "
+ "ON pf.InbredSetId=pxr.InbredSetId "
+ "WHERE (spc.SpeciesName, iset.InbredSetName, pf.Name, pxr.Id) "
+ f"IN ({paramstr})",
+ tuple(
+ itm for sublist in (
+ (item["species"], item["group"], item["dataset"], item["name"])
+ for item in params)
+ for itm in sublist))
+ return 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_phenotype_data(
+ authconn:authdb.DbConnection, gn3conn: gn3db.Connection, group: Group,
+ traits: tuple[dict, ...]) -> dict:
+ """Link phenotype traits to a user group."""
+ with authdb.cursor(authconn) as cursor:
+ params = tuple({
+ "data_link_id": str(uuid.uuid4()),
+ "group_id": str(group.group_id),
+ **item
+ } for item in __traits__(gn3conn, traits))
+ cursor.executemany(
+ "INSERT INTO linked_phenotype_data "
+ "VALUES ("
+ ":data_link_id, :group_id, :SpeciesId, :InbredSetId, "
+ ":PublishFreezeId, :dataset_name, :dataset_fullname, "
+ ":dataset_shortname, :PublishXRefId"
+ ")",
+ params)
+ return {
+ "description": (
+ f"Successfully linked {len(traits)} traits to group."),
+ "group": dictify(group),
+ "traits": params
+ }
diff --git a/gn3/auth/authorisation/data/views.py b/gn3/auth/authorisation/data/views.py
index a9861d2..81b3e2f 100644
--- a/gn3/auth/authorisation/data/views.py
+++ b/gn3/auth/authorisation/data/views.py
@@ -28,6 +28,7 @@ from gn3.auth.authorisation.resources.models import (
from gn3.auth.authentication.oauth2.resource_server import require_oauth
+from gn3.auth.authorisation.data.phenotypes import link_phenotype_data
from gn3.auth.authorisation.data.mrna import link_mrna_data, ungrouped_mrna_data
from gn3.auth.authorisation.data.genotypes import (
link_genotype_data, ungrouped_genotype_data)
@@ -246,3 +247,31 @@ def link_mrna() -> Response:
return jsonify(with_db_connection(
partial(__link__, **__values__(request.json))))
+
+@data.route("/link/phenotype", methods=["POST"])
+def link_phenotype() -> Response:
+ """Link phenotype data to group."""
+ def __values__(form):
+ 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")):
+ raise InvalidData("Expected at least one dataset to be provided.")
+ return {
+ "group_id": uuid.UUID(form["group_id"]),
+ "traits": form["selected"]
+ }
+
+ with gn3db.database_connection(app.config["SQL_URI"]) as gn3conn:
+ def __link__(conn: db.DbConnection, group_id: uuid.UUID,
+ traits: tuple[dict, ...]) -> dict:
+ return link_phenotype_data(
+ conn, gn3conn, group_by_id(conn, group_id), traits)
+
+ return jsonify(with_db_connection(
+ partial(__link__, **__values__(request.json))))
diff --git a/scripts/search_phenotypes.py b/scripts/search_phenotypes.py
index 1bab41c..38b992b 100644
--- a/scripts/search_phenotypes.py
+++ b/scripts/search_phenotypes.py
@@ -97,7 +97,7 @@ def search(# pylint: disable=[too-many-arguments, too-many-locals]
for item in json.loads(selected))
linked = tuple(
(row["SpeciesName"], row["InbredSetName"], row["dataset_name"],
- row["PublishXRefId"])
+ str(row["PublishXRefId"]))
for row in linked_phenotype_data(authconn, gn3conn, species))
page = 1
count = 0