about summary refs log tree commit diff
path: root/gn_auth/auth/authorisation
diff options
context:
space:
mode:
Diffstat (limited to 'gn_auth/auth/authorisation')
-rw-r--r--gn_auth/auth/authorisation/data/phenotypes.py89
-rw-r--r--gn_auth/auth/authorisation/data/views.py3
2 files changed, 90 insertions, 2 deletions
diff --git a/gn_auth/auth/authorisation/data/phenotypes.py b/gn_auth/auth/authorisation/data/phenotypes.py
index 3e45af3..b1fefec 100644
--- a/gn_auth/auth/authorisation/data/phenotypes.py
+++ b/gn_auth/auth/authorisation/data/phenotypes.py
@@ -4,17 +4,22 @@ from dataclasses import asdict
 from typing import Any, Iterable
 
 from gn_libs import mysqldb as gn3db
+from gn_libs import sqlite3 as authdb
 from MySQLdb.cursors import DictCursor
+from flask import request, jsonify, Response, Blueprint, current_app as app
 
-from gn_auth.auth.db import sqlite3 as authdb
+from gn_auth.auth.authentication.oauth2.resource_server import require_oauth
 
 from gn_auth.auth.errors import AuthorisationError
 from gn_auth.auth.authorisation.checks import authorised_p
 from gn_auth.auth.authorisation.resources.system.models import system_resource
 from gn_auth.auth.authorisation.resources.groups.models import Group, group_resource
 
+from gn_auth.auth.authorisation.checks import require_json
 from gn_auth.auth.authorisation.resources.checks import authorised_for2
 
+phenosbp = Blueprint("phenotypes", __name__)
+
 def linked_phenotype_data(
         authconn: authdb.DbConnection, gn3conn: gn3db.Connection,
         species: str = "") -> Iterable[dict[str, Any]]:
@@ -155,3 +160,85 @@ def link_phenotype_data(
             "group": asdict(group),
             "traits": params
         }
+
+
+def unlink_from_resources(
+        cursor: authdb.DbCursor,
+        data_link_ids: tuple[uuid.UUID, ...]
+) -> tuple[uuid.UUID, ...]:
+    """Unlink phenotypes from resources."""
+    cursor.executemany("DELETE FROM phenotype_resources "
+                       "WHERE data_link_id=? RETURNING resource_id",
+                       tuple((str(_id),) for _id in data_link_ids))
+    return tuple(uuid.UUID(row["resource_id"]) for row in cursor.fetchall())
+
+
+def delete_resources(
+        cursor: authdb.DbCursor,
+        resource_ids: tuple[uuid.UUID, ...]
+) -> tuple[uuid.UUID, ...]:
+    """Delete the specified phenotype resources."""
+    cursor.executemany("DELETE FROM resources "
+                       "WHERE resource_id=? RETURNING resource_id",
+                       tuple((str(_id),) for _id in resource_ids))
+    return tuple(uuid.UUID(row["resource_id"]) for row in cursor.fetchall())
+
+
+def fetch_data_link_ids(
+        cursor: authdb.DbCursor,
+        species_id: int,
+        population_id: int,
+        dataset_id: int,
+        xref_ids: tuple[int, ...]
+) -> tuple[uuid.UUID, ...]:
+    """Fetch `data_link_id` values for phenotypes."""
+    paramstr = ", ".join(["(?, ?, ?, ?)"] * len(xref_ids))
+    cursor.execute(
+        "SELECT data_link_id FROM linked_phenotype_data "
+        "WHERE (SpeciesId, InbredSetId, PublishFreezeId, PublishXRefId) IN "
+        f"({paramstr})",
+        tuple(str(field) for arow in
+              ((species_id, population_id, dataset_id, xref_id)
+             for xref_id in xref_ids)
+            for field in arow))
+    return tuple(uuid.UUID(row["data_link_id"]) for row in cursor.fetchall())
+
+
+def delete_linked_data(
+        cursor: authdb.DbCursor,
+        data_link_ids: tuple[uuid.UUID, ...]
+) -> int:
+    """Delete the actual linked data."""
+    cursor.executemany("DELETE FROM linked_phenotype_data "
+                       "WHERE data_link_id=?",
+                       tuple((str(_id),) for _id in data_link_ids))
+    return cursor.rowcount
+
+
+@phenosbp.route("/<int:species_id>/<int:population_id>/<int:dataset_id>/delete",
+                methods=["POST"])
+@require_json
+def delete_linked_phenotypes_data(
+        species_id: int,
+        population_id: int,
+        dataset_id: int
+) -> Response:
+    """Delete the linked phenotypes data from the database."""
+    db_uri = app.config["AUTH_DB"]
+    with (require_oauth.acquire("profile group resource") as _token,
+          authdb.connection(db_uri) as auth_conn,
+          authdb.cursor(auth_conn) as cursor):
+        _deleted = 0
+        xref_ids = tuple(request.json.get("xref_ids", []))#type: ignore[union-attr]
+        if len(xref_ids) > 0:
+            # TOD0: Introduce background jobs for this.
+            data_link_ids = fetch_data_link_ids(
+                cursor, species_id, population_id, dataset_id, xref_ids)
+            _resources_ids = unlink_from_resources(cursor, data_link_ids)
+            delete_resources(cursor, _resources_ids)
+            _deleted = delete_linked_data(cursor, data_link_ids)
+
+        return jsonify({
+            "requested": len(xref_ids),
+            "deleted": _deleted
+        })
diff --git a/gn_auth/auth/authorisation/data/views.py b/gn_auth/auth/authorisation/data/views.py
index 5172157..4bf6746 100644
--- a/gn_auth/auth/authorisation/data/views.py
+++ b/gn_auth/auth/authorisation/data/views.py
@@ -36,10 +36,11 @@ from ...authentication.users import User
 from ...authentication.oauth2.resource_server import require_oauth
 
 from .mrna import link_mrna_data, ungrouped_mrna_data
-from .phenotypes import link_phenotype_data, pheno_traits_from_db
 from .genotypes import link_genotype_data, ungrouped_genotype_data
+from .phenotypes import phenosbp, link_phenotype_data, pheno_traits_from_db
 
 data = Blueprint("data", __name__)
+data.register_blueprint(phenosbp, url_prefix="/phenotypes")
 
 def build_trait_name(trait_fullname):
     """