aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrederick Muriuki Muriithi2023-07-10 10:59:50 +0300
committerFrederick Muriuki Muriithi2023-07-11 11:46:12 +0300
commitd35d28bab08a7ae21ba771f044a59fbbf3eafe74 (patch)
tree2ab2e15bc7a6a3633ea178b924fb466c01df38be
parent90ebb0f18ef3f0b1bc397543bfe69335ad18c8dc (diff)
downloadgenenetwork2-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.py138
-rw-r--r--wqflask/wqflask/templates/display_files.html36
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>