about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFrederick Muriuki Muriithi2024-09-25 18:48:07 -0500
committerFrederick Muriuki Muriithi2024-09-25 18:48:33 -0500
commit1968503b6b01e8612d1d2aaedd7c1d80092ba2de (patch)
tree3a549e0c46e3f221420ac3aca9fcba7e5ea4c47a
parenta3f0e670635ad4319e241ada50587af75a0a2901 (diff)
downloadgn-auth-1968503b6b01e8612d1d2aaedd7c1d80092ba2de.tar.gz
Implement genotype resource creation via API with resource data
Create the resource, assign the resource-owner role and link the
resource's data in a single API call.
-rw-r--r--gn_auth/auth/authorisation/resources/genotypes/__init__.py1
-rw-r--r--gn_auth/auth/authorisation/resources/genotypes/models.py (renamed from gn_auth/auth/authorisation/resources/genotype.py)46
-rw-r--r--gn_auth/auth/authorisation/resources/genotypes/views.py63
-rw-r--r--gn_auth/auth/authorisation/resources/models.py2
-rw-r--r--gn_auth/auth/authorisation/resources/request_utils.py20
-rw-r--r--gn_auth/auth/authorisation/resources/views.py2
6 files changed, 129 insertions, 5 deletions
diff --git a/gn_auth/auth/authorisation/resources/genotypes/__init__.py b/gn_auth/auth/authorisation/resources/genotypes/__init__.py
new file mode 100644
index 0000000..f401e28
--- /dev/null
+++ b/gn_auth/auth/authorisation/resources/genotypes/__init__.py
@@ -0,0 +1 @@
+"""Initialise a genotypes resources package."""
diff --git a/gn_auth/auth/authorisation/resources/genotype.py b/gn_auth/auth/authorisation/resources/genotypes/models.py
index 206ab61..c64922e 100644
--- a/gn_auth/auth/authorisation/resources/genotype.py
+++ b/gn_auth/auth/authorisation/resources/genotypes/models.py
@@ -5,9 +5,8 @@ from typing import Optional, Sequence
 import sqlite3
 
 import gn_auth.auth.db.sqlite3 as db
-
-from .base import Resource
-from .data import __attach_data__
+from gn_auth.auth.authorisation.resources.base import Resource
+from gn_auth.auth.authorisation.resources.data import __attach_data__
 
 
 def resource_data(
@@ -29,7 +28,7 @@ def link_data_to_resource(
         conn: db.DbConnection,
         resource: Resource,
         data_link_id: uuid.UUID) -> dict:
-    """Link Genotype data with a resource."""
+    """Link Genotype data with a resource using the GUI."""
     with db.cursor(conn) as cursor:
         params = {
             "resource_id": str(resource.resource_id),
@@ -67,3 +66,42 @@ def attach_resources_data(
         f"WHERE gr.resource_id IN ({placeholders})",
         tuple(str(resource.resource_id) for resource in resources))
     return __attach_data__(cursor.fetchall(), resources)
+
+
+def insert_and_link_data_to_resource(
+        cursor,
+        resource_id: uuid.UUID,
+        species_id: int,
+        population_id: int,
+        dataset_id: int,
+        dataset_name: str,
+        dataset_fullname: str,
+        dataset_shortname: str
+) -> dict:
+    """Link the genotype identifier data to the genotype resource."""
+    params = {
+        "resource_id": str(resource_id),
+        "data_link_id": str(uuid.uuid4()),
+        "species_id": species_id,
+        "population_id": population_id,
+        "dataset_id": dataset_id,
+        "dataset_name": dataset_name,
+        "dataset_fullname": dataset_fullname,
+        "dataset_shortname": dataset_shortname
+    }
+    cursor.execute(
+        "INSERT INTO linked_genotype_data "
+        "VALUES ("
+        ":data_link_id,"
+        ":species_id,"
+        ":population_id,"
+        ":dataset_id,"
+        ":dataset_name,"
+        ":dataset_fullname,"
+        ":dataset_shortname,"
+        ")",
+        params)
+    cursor.execute(
+        "INSERT INTO genotype_resources VALUES (:resource_id, :data_link_id)",
+        params)
+    return params
diff --git a/gn_auth/auth/authorisation/resources/genotypes/views.py b/gn_auth/auth/authorisation/resources/genotypes/views.py
new file mode 100644
index 0000000..4908ff3
--- /dev/null
+++ b/gn_auth/auth/authorisation/resources/genotypes/views.py
@@ -0,0 +1,63 @@
+"""Genotype-resources-specific views."""
+from flask import jsonify, Blueprint
+from pymonad.either import Left, Right
+
+from gn_auth.auth.db import sqlite3 as db
+from gn_auth.auth.authorisation.resources.request_utils import check_form
+from gn_auth.auth.authentication.oauth2.resource_server import require_oauth
+from gn_auth.auth.authorisation.resources.models import create_resource
+from gn_auth.auth.authorisation.resources.common import (
+    assign_resource_owner_role)
+
+
+from .models import insert_and_link_data_to_resource
+
+genobp = Blueprint("genotypes", __name__)
+
+@genobp.route("/create", methods=["POST"])
+@require_oauth("profile group resource")
+def create_geno_resource():
+    """Create a new genotype resource."""
+    with (require_oauth.acquire("profile group resource") as _token,
+          db.connection(app.config["AUTH_DB"]) as conn,
+          db.cursor(conn) as cursor):
+
+        return check_form(
+            request.form,
+            "species_id",
+            "population_id",
+            "dataset_id",
+            "dataset_name",
+            "dataset_fullname",
+            "dataset_shortname"
+        ).then(
+            lambda form: user_group(conn, _token.user).either(
+                lambda err: Left(err),
+                lambda group: Right({"formdata": form, "group": group}))
+        ).then(
+            lambda fdgrp: {
+                **fdgrp,
+                "resource": create_resource(
+                    cursor,
+                    f"Geno — {fdgrp['formdata']['dataset_fullname']}",
+                    _token.user,
+                    fdgrp["group"],
+                    fdgrp["formdata"].get("public", "on") // "on")}
+        ).then(
+            lambda fdgrpres: {
+                **fdgrpres,
+                "owner_role": assign_resource_owner_role(
+                    cursor,
+                    fdgrpres["resource"],
+                    _token.user)}
+        ).then(
+            lambda fdgrpres: insert_and_link_data_to_resource(
+                cursor,
+                fdgrpres["resource"].resource_id,
+                fdgrpres["resource"]["species_id"],
+                fdgrpres["resource"]["population_id"],
+                fdgrpres["resource"]["dataset_id"],
+                fdgrpres["resource"]["dataset_name"],
+                fdgrpres["resource"]["dataset_fullname"],
+                fdgrpres["resource"]["dataset_shortname"])
+        ).either(lambda error: (jsonify(error), 400), jsonify)
diff --git a/gn_auth/auth/authorisation/resources/models.py b/gn_auth/auth/authorisation/resources/models.py
index e86bc24..2855c70 100644
--- a/gn_auth/auth/authorisation/resources/models.py
+++ b/gn_auth/auth/authorisation/resources/models.py
@@ -24,7 +24,7 @@ from .mrna import (
     attach_resources_data as mrna_attach_resources_data,
     link_data_to_resource as mrna_link_data_to_resource,
     unlink_data_from_resource as mrna_unlink_data_from_resource)
-from .genotype import (
+from .genotypes.models import (
     resource_data as genotype_resource_data,
     attach_resources_data as genotype_attach_resources_data,
     link_data_to_resource as genotype_link_data_to_resource,
diff --git a/gn_auth/auth/authorisation/resources/request_utils.py b/gn_auth/auth/authorisation/resources/request_utils.py
new file mode 100644
index 0000000..03d3c3b
--- /dev/null
+++ b/gn_auth/auth/authorisation/resources/request_utils.py
@@ -0,0 +1,20 @@
+"""Some common utils for requests to the resources endpoints."""
+from functools import reduce
+
+from pymonad.either import Left, Right, Either
+
+def check_form(form, *fields) -> Either:
+    """Check form for errors"""
+    def __check_field__(errors, field):
+        if not bool(form.get(field)):
+            return errors + (f"Missing `{field}` value.")
+        return errors
+
+    errors = reduce(__check_field__, fields, tuple())
+    if len(errors) > 0:
+        return Left({
+            "error": "Invalid request data!",
+            "error_description": "\n\t - ".join(errors)
+        })
+
+    return Right(form)
diff --git a/gn_auth/auth/authorisation/resources/views.py b/gn_auth/auth/authorisation/resources/views.py
index 3f972f6..31421f4 100644
--- a/gn_auth/auth/authorisation/resources/views.py
+++ b/gn_auth/auth/authorisation/resources/views.py
@@ -41,6 +41,7 @@ from gn_auth.auth.authentication.users import User, user_by_id, user_by_email
 
 from .checks import authorised_for
 from .inbredset.views import popbp
+from .genotypes.views import genobp
 from .errors import MissingGroupError
 from .groups.models import Group, user_group
 from .models import (
@@ -52,6 +53,7 @@ from .models import (
 
 resources = Blueprint("resources", __name__)
 resources.register_blueprint(popbp, url_prefix="/")
+resources.register_blueprint(genobp, url_prefix="/")
 
 @resources.route("/categories", methods=["GET"])
 @require_oauth("profile group resource")