diff options
| author | Frederick Muriuki Muriithi | 2024-09-25 18:48:07 -0500 |
|---|---|---|
| committer | Frederick Muriuki Muriithi | 2024-09-25 18:48:33 -0500 |
| commit | 1968503b6b01e8612d1d2aaedd7c1d80092ba2de (patch) | |
| tree | 3a549e0c46e3f221420ac3aca9fcba7e5ea4c47a /gn_auth/auth/authorisation/resources/genotypes | |
| parent | a3f0e670635ad4319e241ada50587af75a0a2901 (diff) | |
| download | gn-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.
Diffstat (limited to 'gn_auth/auth/authorisation/resources/genotypes')
3 files changed, 171 insertions, 0 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/genotypes/models.py b/gn_auth/auth/authorisation/resources/genotypes/models.py new file mode 100644 index 0000000..c64922e --- /dev/null +++ b/gn_auth/auth/authorisation/resources/genotypes/models.py @@ -0,0 +1,107 @@ +"""Genotype data resources functions and utilities.""" +import uuid +from typing import Optional, Sequence + +import sqlite3 + +import gn_auth.auth.db.sqlite3 as db +from gn_auth.auth.authorisation.resources.base import Resource +from gn_auth.auth.authorisation.resources.data import __attach_data__ + + +def resource_data( + cursor: db.DbCursor, + resource_id: uuid.UUID, + offset: int = 0, + limit: Optional[int] = None) -> Sequence[sqlite3.Row]: + """Fetch data linked to a Genotype resource""" + cursor.execute( + (("SELECT * FROM genotype_resources AS gr " + "INNER JOIN linked_genotype_data AS lgd " + "ON gr.data_link_id=lgd.data_link_id " + "WHERE gr.resource_id=?") + ( + f" LIMIT {limit} OFFSET {offset}" if bool(limit) else "")), + (str(resource_id),)) + return cursor.fetchall() + +def link_data_to_resource( + conn: db.DbConnection, + resource: Resource, + data_link_id: uuid.UUID) -> dict: + """Link Genotype data with a resource using the GUI.""" + with db.cursor(conn) as cursor: + params = { + "resource_id": str(resource.resource_id), + "data_link_id": str(data_link_id) + } + cursor.execute( + "INSERT INTO genotype_resources VALUES" + "(:resource_id, :data_link_id)", + params) + return params + +def unlink_data_from_resource( + conn: db.DbConnection, + resource: Resource, + data_link_id: uuid.UUID) -> dict: + """Unlink data from Genotype resources""" + with db.cursor(conn) as cursor: + cursor.execute("DELETE FROM genotype_resources " + "WHERE resource_id=? AND data_link_id=?", + (str(resource.resource_id), str(data_link_id))) + return { + "resource_id": str(resource.resource_id), + "dataset_type": resource.resource_category.resource_category_key, + "data_link_id": data_link_id + } + +def attach_resources_data( + cursor, resources: Sequence[Resource]) -> Sequence[Resource]: + """Attach linked data to Genotype resources""" + placeholders = ", ".join(["?"] * len(resources)) + cursor.execute( + "SELECT * FROM genotype_resources AS gr " + "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) + + +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) |
