From e66e0d24f76458aade54056e18de7d4e0762d06c Mon Sep 17 00:00:00 2001 From: Frederick Muriuki Muriithi Date: Tue, 28 Feb 2023 12:45:57 +0300 Subject: auth: Unlink data from resources Enable the data editor to unlink data from a particular resource. --- gn3/auth/authorisation/data/views.py | 62 +++++++++++++++++++----------- gn3/auth/authorisation/resources/models.py | 4 +- 2 files changed, 42 insertions(+), 24 deletions(-) (limited to 'gn3') diff --git a/gn3/auth/authorisation/data/views.py b/gn3/auth/authorisation/data/views.py index 76f4158..08032db 100644 --- a/gn3/auth/authorisation/data/views.py +++ b/gn3/auth/authorisation/data/views.py @@ -1,16 +1,15 @@ """Handle data endpoints.""" +import uuid import json -from functools import reduce -from flask import request, Response, Blueprint, current_app as app from authlib.integrations.flask_oauth2.errors import _HTTPException - -from gn3 import db_utils as gn3db +from flask import request, jsonify, Response, Blueprint, current_app as app from gn3.db.traits import build_trait_name from gn3.auth import db from gn3.auth.authentication.oauth2.resource_server import require_oauth +from gn3.auth.authorisation.resources.checks import authorised_for from gn3.auth.authorisation.resources.models import ( user_resources, public_resources, attach_resources_data) @@ -20,12 +19,22 @@ data = Blueprint("data", __name__) def authorisation() -> Response: """Retrive the authorisation level for datasets/traits for the user.""" db_uri = app.config["AUTH_DB"] - the_user = "ANONYMOUS" - with db.connection(db_uri) as auth_conn, gn3db.database_connection() as gn3conn: + privileges = {} + with db.connection(db_uri) as auth_conn: try: with require_oauth.acquire("profile group resource") as the_token: resources = attach_resources_data( auth_conn, user_resources(auth_conn, the_token.user)) + privileges = { + resource_id: ("group:resource:view-resource",) + for resource_id, is_authorised + in authorised_for( + auth_conn, the_token.user, + ("group:resource:view-resource",), tuple( + resource.resource_id for resource in resources + if not resource.public)).items() + if is_authorised + } except _HTTPException as exc: err_msg = json.loads(exc.body) if err_msg["error"] == "missing_authorization": @@ -37,31 +46,40 @@ def authorisation() -> Response: # Access endpoint with somethin like: # curl -X GET http://127.0.0.1:8080/api/oauth2/data/authorisation \ # -H "Content-Type: application/json" \ - # -d '{"traits": ["HC_M2_0606_P::1442370_at", "BXDGeno::01.001.695", "BXDPublish::10001"]}' + # -d '{"traits": ["HC_M2_0606_P::1442370_at", "BXDGeno::01.001.695", + # "BXDPublish::10001"]}' + data_to_resource_map = { + (f"{data_item['dataset_type'].lower()}::" + f"{data_item['dataset_name']}"): resource.resource_id + for resource in resources + for data_item in resource.resource_data + } + privileges = { + **privileges, + **{ + resource.resource_id: ("system:resource:public-read",) + for resource in resources if resource.public + }} + args = request.get_json() - traits_names = args["traits"] + traits_names = args["traits"] # type: ignore[index] def __translate__(val): return { "ProbeSet": "mRNA", "Geno": "Genotype", "Publish": "Phenotype" }[val] - traits = ( + return jsonify(tuple( { **{key:trait[key] for key in ("trait_fullname", "trait_name")}, "dataset_name": trait["db"]["dataset_name"], - "dataset_type": __translate__(trait["db"]["dataset_type"]) + "dataset_type": __translate__(trait["db"]["dataset_type"]), + "privileges": privileges.get( + data_to_resource_map.get( + f"{__translate__(trait['db']['dataset_type']).lower()}" + f"::{trait['db']['dataset_name']}", + uuid.UUID("4afa415e-94cb-4189-b2c6-f9ce2b6a878d")), + tuple()) } for trait in (build_trait_name(trait_fullname) - for trait_fullname in traits_names)) - # Retrieve the dataset/trait IDs from traits above - - # Compare the traits/dataset names/ids from request with resources' data - # - Any trait not in resources' data is marked inaccessible - # - Any trait in resources' data: - # - IF public is marked readable - # - IF private and user has read privilege: mark readable - # - ELSE mark inaccessible - - - return "NOT COMPLETED! ..." + for trait_fullname in traits_names))) diff --git a/gn3/auth/authorisation/resources/models.py b/gn3/auth/authorisation/resources/models.py index 13f234f..be1bc17 100644 --- a/gn3/auth/authorisation/resources/models.py +++ b/gn3/auth/authorisation/resources/models.py @@ -414,12 +414,12 @@ def __attach_data__( **acc, resource_id: acc.get(resource_id, tuple()) + (dict(row),) } - organised = reduce(__organise__, data_rows, {}) + organised: dict[UUID, tuple[dict, ...]] = reduce(__organise__, data_rows, {}) return tuple( Resource( resource.group, resource.resource_id, resource.resource_name, resource.resource_category, resource.public, - organised[resource.resource_id]) + organised.get(resource.resource_id, tuple())) for resource in resources) def attach_mrna_resources_data( -- cgit v1.2.3