aboutsummaryrefslogtreecommitdiff
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")