diff options
author | Frederick Muriuki Muriithi | 2023-07-10 10:59:50 +0300 |
---|---|---|
committer | Frederick Muriuki Muriithi | 2023-07-11 11:46:12 +0300 |
commit | d35d28bab08a7ae21ba771f044a59fbbf3eafe74 (patch) | |
tree | 2ab2e15bc7a6a3633ea178b924fb466c01df38be | |
parent | 90ebb0f18ef3f0b1bc397543bfe69335ad18c8dc (diff) | |
download | genenetwork2-d35d28bab08a7ae21ba771f044a59fbbf3eafe74.tar.gz |
Use new auth to determine access to diffs
* wqflask/wqflask/metadata_edits.py: Filter out diffs that the user
has access to before sending them to the template.
* wqflask/wqflask/templates/display_files.html: Remove access control
code in the UI template.
-rw-r--r-- | wqflask/wqflask/metadata_edits.py | 138 | ||||
-rw-r--r-- | wqflask/wqflask/templates/display_files.html | 36 |
2 files changed, 99 insertions, 75 deletions
diff --git a/wqflask/wqflask/metadata_edits.py b/wqflask/wqflask/metadata_edits.py index 5b03f3ed..7b921a6d 100644 --- a/wqflask/wqflask/metadata_edits.py +++ b/wqflask/wqflask/metadata_edits.py @@ -2,6 +2,9 @@ import datetime import json import os +from pathlib import Path +from functools import reduce + from collections import namedtuple from itertools import groupby from typing import Dict @@ -24,6 +27,9 @@ from wqflask.decorators import login_required from wqflask.decorators import required_access from wqflask.decorators import edit_admins_access_required +from wqflask.oauth2 import client +from wqflask.oauth2.request_utils import flash_error, process_error + from gn3.authentication import AdminRole from gn3.authentication import get_highest_user_access_role from gn3.csvcmp import create_dirs_if_not_exists @@ -50,10 +56,8 @@ from gn3.db.sample_data import update_sample_data metadata_edit = Blueprint("metadata_edit", __name__) - -def _get_diffs( - diff_dir: str, user_id: str, redis_conn: redis.Redis, gn_proxy_url: str -): +def _get_diffs(diff_dir: str, redis_conn: redis.Redis): + """Get all the diff details.""" def __get_file_metadata(file_name: str) -> Dict: author, resource_id, time_stamp, *_ = file_name.split(".") try: @@ -66,31 +70,19 @@ def _get_diffs( "resource_id": resource_id, "file_name": file_name, "author": author, - "time_stamp": time_stamp, - "roles": get_highest_user_access_role( - resource_id=resource_id, - user_id=user_id, - gn_proxy_url=gn_proxy_url, - ), + "time_stamp": time_stamp } - approved, rejected, waiting = [], [], [] - if os.path.exists(diff_dir): - for name in os.listdir(diff_dir): - file_metadata = __get_file_metadata(file_name=name) - admin_status = file_metadata["roles"].get("admin") - append_p = user_id in name or admin_status > AdminRole.EDIT_ACCESS - if name.endswith(".rejected") and append_p: - rejected.append(__get_file_metadata(file_name=name)) - elif name.endswith(".approved") and append_p: - approved.append(__get_file_metadata(file_name=name)) - elif append_p: # Normal file - waiting.append(__get_file_metadata(file_name=name)) - return { - "approved": approved, - "rejected": rejected, - "waiting": waiting, - } + def __get_diff__(diff_dir: str, diff_file_name: str) -> dict: + """Get the contents of the diff at `filepath`.""" + with open(Path(diff_dir, diff_file_name), encoding="utf8") as dfile: + return json.loads(dfile.read().strip()) + + return tuple({ + "filepath": Path(diff_dir, dname).absolute(), + "meta": __get_file_metadata(file_name=dname), + "diff": __get_diff__(diff_dir, dname) + } for dname in os.listdir(diff_dir)) def edit_phenotype(conn, name, dataset_id): @@ -270,6 +262,7 @@ def update_phenotype(dataset_id: str, name: str): "trait_name": str(name), "phenotype_id": str(phenotype_id), "dataset_id": name, + "dataset_name": request.args["dataset_name"], "resource_id": request.args.get("resource-id"), "author": author, "timestamp": ( @@ -512,38 +505,71 @@ filename=sample-data-{dataset_id}.csv" @metadata_edit.route("/diffs") -@login_required +# @login_required def list_diffs(): files = _get_diffs( diff_dir=f"{current_app.config.get('TMPDIR')}/sample-data/diffs", - user_id=( - (g.user_session.record.get(b"user_id") or b"").decode("utf-8") - or g.user_session.record.get("user_id") - or "" - ), - redis_conn=redis.from_url( - current_app.config["REDIS_URL"], decode_responses=True - ), - gn_proxy_url=current_app.config.get("GN2_PROXY"), - ) - return render_template( - "display_files.html", - approved=sorted( - files.get("approved"), - reverse=True, - key=lambda d: d.get("time_stamp"), - ), - rejected=sorted( - files.get("rejected"), - reverse=True, - key=lambda d: d.get("time_stamp"), - ), - waiting=sorted( - files.get("waiting"), - reverse=True, - key=lambda d: d.get("time_stamp"), - ), - ) + redis_conn=redis.from_url(current_app.config["REDIS_URL"], + decode_responses=True)) + + def __filter_authorised__(diffs, auth_details): + """Retain only those diffs that the current user has edit access to.""" + return [ + diff for diff in diffs + for auth in auth_details + if (diff["diff"]["dataset_name"] == auth["dataset_name"] + and + diff["diff"]["trait_name"] == auth["trait_name"]) ] + + def __organise_diffs__(acc, item): + if item["filepath"].name.endswith(".rejected"): + return {**acc, "rejected": acc["rejected"] + [item]} + if item["filepath"].name.endswith(".approved"): + return {**acc, "approved": acc["approved"] + [item]} + return {**acc, "waiting": acc["waiting"] + [item]} + + accessible_diffs = client.post( + "oauth2/data/authorisation", + json={ + "traits": [ + f"{meta['diff']['dataset_name']}::{meta['diff']['trait_name']}" + for meta in files + ] + } + ).map( + lambda lst: [ + auth_item for auth_item in lst + if (("group:resource:edit-resource" in auth_item["privileges"]) + or + ("system:resources:edit-all" in auth_item["privileges"]))] + ).map( + lambda alst: __filter_authorised__(files, alst) + ).map(lambda diffs: reduce(__organise_diffs__, + diffs, + {"approved": [], "rejected": [], "waiting": []})) + + def __handle_error__(error): + flash_error(process_error(error)) + return render_template( + "display_files.html", approved=[], rejected=[], waiting=[]) + + def __success__(org_diffs): + return render_template( + "display_files.html", + approved=sorted( + org_diffs.get("approved"), + reverse=True, + key=lambda d: d.get("time_stamp")), + rejected=sorted( + org_diffs.get("rejected"), + reverse=True, + key=lambda d: d.get("time_stamp")), + waiting=sorted( + org_diffs.get("waiting"), + reverse=True, + key=lambda d: d.get("time_stamp"))) + + return accessible_diffs.either(__handle_error__, __success__) @metadata_edit.route("/diffs/<name>") diff --git a/wqflask/wqflask/templates/display_files.html b/wqflask/wqflask/templates/display_files.html index 5fad5d14..08933ee0 100644 --- a/wqflask/wqflask/templates/display_files.html +++ b/wqflask/wqflask/templates/display_files.html @@ -9,11 +9,11 @@ <!-- Start of body --> {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} -{% for category, message in messages %} <div class="container-fluid bg-{{ category }}"> - <p>{{ message }}</p> + {% for category, message in messages %} + <div class="alert {{category}}" role="alert">{{ message }}</div> + {% endfor %} </div> -{% endfor %} {% endif %} {% endwith %} @@ -33,13 +33,12 @@ <tbody> {% for data in waiting %} <tr> - {% set file_url = url_for('metadata_edit.show_diff', name=data.get('file_name')) %} - <td><a href="{{ file_url }}" target="_blank">{{ data.get("resource_id") }}</a></td> - <td>{{ data.get("author")}}</td> - <td>{{ data.get("time_stamp")}}</td> - {% if data.get("roles").get("admin") > AdminRole.EDIT_ACCESS %} - {% set reject_url = url_for('metadata_edit.reject_data', resource_id=data.get('resource_id'), file_name=data.get('file_name')) %} - {% set approve_url = url_for('metadata_edit.approve_data', resource_id=data.get('resource_id'), file_name=data.get('file_name')) %} + {% set file_url = url_for('metadata_edit.show_diff', name=data.filepath.name) %} + <td><a href="{{ file_url }}" target="_blank">{{ data.meta.get("resource_id") }}</a></td> + <td>{{ data.meta.get("author")}}</td> + <td>{{ data.meta.get("time_stamp")}}</td> + {% set reject_url = url_for('metadata_edit.reject_data', resource_id=data.meta.get('resource_id'), file_name=data.filepath.name) %} + {% set approve_url = url_for('metadata_edit.approve_data', resource_id=data.meta.get('resource_id'), file_name=data.filepath.name) %} <td> <button type="button" class="btn btn-secondary btn-sm"> @@ -52,7 +51,6 @@ <a href="{{ approve_url }}">Approve</a> </button> </td> - {% endif %} </tr> {% endfor %} </tbody> @@ -74,10 +72,10 @@ <tbody> {% for data in approved %} <tr> - {% set file_url = url_for('metadata_edit.show_diff', name=data.get('file_name')) %} - <td><a href="{{ file_url }}" target="_blank">{{ data.get("resource_id") }}</a></td> - <td>{{ data.get("author")}}</td> - <td>{{ data.get("time_stamp")}}</td> + {% set file_url = url_for('metadata_edit.show_diff', name=data.filepath.name) %} + <td><a href="{{ file_url }}" target="_blank">{{ data.meta.get("resource_id") }}</a></td> + <td>{{ data.meta.get("author")}}</td> + <td>{{ data.meta.get("time_stamp")}}</td> </tr> {% endfor %} </tbody> @@ -99,10 +97,10 @@ <tbody> {% for data in rejected %} <tr> - {% set file_url = url_for('metadata_edit.show_diff', name=data.get('file_name')) %} - <td><a href="{{ file_url }}" target="_blank">{{ data.get("resource_id") }}</a></td> - <td>{{ data.get("author")}}</td> - <td>{{ data.get("time_stamp")}}</td> + {% set file_url = url_for('metadata_edit.show_diff', name=data.filepath.name) %} + <td><a href="{{ file_url }}" target="_blank">{{ data.meta.get("resource_id") }}</a></td> + <td>{{ data.meta.get("author")}}</td> + <td>{{ data.meta.get("time_stamp")}}</td> </tr> {% endfor %} </tbody> |