First Issues / Improvements detected in Beta (#36)

Co-authored-by: Tim Lorsbach <tim@lorsba.ch>
Reviewed-on: enviPath/enviPy#36
This commit is contained in:
2025-07-24 09:57:50 +12:00
parent 2c9f9038f3
commit 026189ccd9
8 changed files with 360 additions and 128 deletions

View File

@ -21,6 +21,7 @@ class UserManager(object):
return bool(re.findall(UserManager.user_pattern, url))
@staticmethod
@transaction.atomic
def create_user(username, email, password, set_setting=True, add_to_group=True, *args, **kwargs):
# avoid circular import :S
from .tasks import send_registration_mail
@ -59,19 +60,24 @@ class UserManager(object):
def get_user(user_url):
pass
@staticmethod
def get_user_by_id(user, user_uuid: str):
if user.uuid != user_uuid and not user.is_superuser:
raise ValueError("Getting user failed!")
return get_user_model().objects.get(uuid=user_uuid)
@staticmethod
def get_user_lp(user_url: str):
uuid = user_url.strip().split('/')[-1]
return get_user_model().objects.get(uuid=uuid)
@staticmethod
def get_users_lp():
return get_user_model().objects.all()
@staticmethod
def get_users():
return []
@staticmethod
def get_user_lp(user_url: str):
uuid = user_url.strip().split('/')[-1]
return get_user_model().objects.get(uuid=uuid)
raise ValueError("")
@staticmethod
def writable(current_user, user):
@ -102,6 +108,10 @@ class GroupManager(object):
uuid = group_url.strip().split('/')[-1]
return Group.objects.get(uuid=uuid)
@staticmethod
def get_groups_lp():
return Group.objects.all()
@staticmethod
def get_group_by_url(user, group_url):
return GroupManager.get_group_by_id(user, group_url.split('/')[-1])
@ -173,6 +183,30 @@ class PackageManager(object):
return True
return False
@staticmethod
def has_package_permission(user: 'User', package: Union[str, 'Package'], permission: str):
if isinstance(package, str):
package = Package.objects.get(uuid=package)
groups = GroupManager.get_groups(user)
perms = {
'all': ['all'],
'write': ['all', 'write'],
'read': ['all', 'write', 'read']
}
valid_perms = perms.get(permission)
if UserPackagePermission.objects.filter(package=package, user=user, permission__in=valid_perms).exists() or \
GroupPackagePermission.objects.filter(package=package, group__in=groups,
permission__in=valid_perms).exists() or \
user.is_superuser:
return True
return False
@staticmethod
def get_package_lp(package_url):
match = re.findall(PackageManager.package_pattern, package_url)
@ -701,8 +735,9 @@ class SettingManager(object):
@staticmethod
def get_all_settings(user):
sp = UserSettingPermission.objects.filter(user=user).values('setting').distinct()
return Setting.objects.filter(id__in=sp)
sp = UserSettingPermission.objects.filter(user=user).values('setting')
return (Setting.objects.filter(id__in=sp) | Setting.objects.filter(public=True) | Setting.objects.filter(
global_default=True)).distinct()
@staticmethod
@transaction.atomic

View File

@ -1,6 +1,5 @@
import json
import logging
from functools import wraps
from typing import List, Dict, Any
from django.conf import settings as s
@ -10,6 +9,7 @@ from django.shortcuts import render, redirect
from django.views.decorators.csrf import csrf_exempt
from utilities.chem import FormatConverter, IndigoUtils
from utilities.decorators import package_permission_required
from .logic import GroupManager, PackageManager, UserManager, SettingManager, SearchManager
from .models import Package, GroupPackagePermission, Group, CompoundStructure, Compound, Reaction, Rule, Pathway, Node, \
EPModel, EnviFormer, MLRelativeReasoning, RuleBaseRelativeReasoning, Scenario, SimpleAmbitRule, APIToken, \
@ -24,6 +24,20 @@ def log_post_params(request):
logger.debug(f"{k}\t{v}")
def error(request, message: str, detail: str, code: int = 400):
context = get_base_context(request)
error_context = {
'error_message': message,
'error_detail': detail,
}
if request.headers.get('Accept') == 'application/json':
return JsonResponse(error_context, status=500)
context.update(**error_context)
return render(request, "errors/error.html", context, status=code)
def login(request):
current_user = _anonymous_or_real(request)
context = get_base_context(request)
@ -55,8 +69,11 @@ def login(request):
except get_user_model().DoesNotExist:
context['message'] = "Login failed!"
return render(request, 'login.html', context)
try:
user = authenticate(username=email, password=password)
except Exception as e:
context['message'] = "Login failed!"
return render(request, 'login.html', context)
if user is not None:
login(request, user)
@ -68,15 +85,23 @@ def login(request):
elif is_register:
username = request.POST.get('username')
email = request.POST.get('email')
password = request.POST.get('password')
rpassword = request.POST.get('rpassword')
password = request.POST.get('password', '').strip()
rpassword = request.POST.get('rpassword', '').strip()
if password != rpassword:
pass
if password != rpassword or password == '':
context['message'] = "Registration failed, provided passwords differ!"
return render(request, 'login.html', context)
try:
u = UserManager.create_user(username, email, password)
except Exception:
context['message'] = "Registration failed! Couldn't create User Account."
return render(request, 'login.html', context)
if s.ADMIN_APPROVAL_REQUIRED:
context['message'] = "Your account has been created! An admin will activate it soon!"
else:
context['message'] = "Account has been created! You'll receive a mail to activate your account shortly."
return render(request, 'login.html', context)
@ -92,25 +117,11 @@ def logout(request):
return HttpResponseBadRequest()
def catch_exceptions(view_func):
@wraps(view_func)
def _wrapped_view(request, *args, **kwargs):
try:
return view_func(request, *args, **kwargs)
except Exception as e:
# Optionally return JSON or plain HttpResponse
if request.headers.get('Accept') == 'application/json':
return JsonResponse(
{'error': 'Internal server error. Please try again later.'},
status=500
)
else:
return render(request, 'errors/error.html', get_base_context(request))
return _wrapped_view
def editable(request, user):
if user.is_superuser:
return True
url = request.build_absolute_uri(request.path)
if PackageManager.is_package_url(url):
_package = PackageManager.get_package_lp(request.build_absolute_uri())
@ -129,11 +140,13 @@ def editable(request, user):
return False
def get_base_context(request) -> Dict[str, Any]:
def get_base_context(request, for_user=None) -> Dict[str, Any]:
current_user = _anonymous_or_real(request)
can_edit = editable(request, current_user)
if for_user:
current_user = for_user
ctx = {
'title': 'enviPath',
'meta': {
@ -183,8 +196,6 @@ def breadcrumbs(first_level_object=None, second_level_namespace=None, second_lev
return bread
# @catch_exceptions
def index(request):
context = get_base_context(request)
context['title'] = 'enviPath - Home'
@ -269,6 +280,9 @@ def compounds(request):
default_package = current_user.default_package
return package_compounds(request, default_package.uuid)
else:
return HttpResponseNotAllowed(['GET', 'POST'])
def rules(request):
if request.method == 'GET':
@ -305,6 +319,9 @@ def rules(request):
default_package = current_user.default_package
return package_rules(request, default_package.uuid)
else:
return HttpResponseNotAllowed(['GET', 'POST'])
def reactions(request):
if request.method == 'GET':
@ -341,6 +358,9 @@ def reactions(request):
default_package = current_user.default_package
return package_reactions(request, default_package.uuid)
else:
return HttpResponseNotAllowed(['GET', 'POST'])
def pathways(request):
if request.method == 'GET':
@ -378,6 +398,9 @@ def pathways(request):
default_package = current_user.default_package
return package_pathways(request, default_package.uuid)
else:
return HttpResponseNotAllowed(['GET', 'POST'])
def scenarios(request):
if request.method == 'GET':
@ -408,11 +431,14 @@ def scenarios(request):
context['reviewed_objects'] = reviewed_scenario_qs
return render(request, 'collections/objects_list.html', context)
# TODO
# elif request.method == 'POST':
# # delegate to default package
# default_package = request.user.default_package
# return package_scenarios(request, default_package.uuid)
elif request.method == 'POST':
# delegate to default package
default_package = request.user.default_package
return package_scenarios(request, default_package.uuid)
else:
return HttpResponseNotAllowed(['GET', 'POST'])
def models(request):
@ -459,6 +485,9 @@ def models(request):
default_package = current_user.default_package
return package_models(request, default_package.uuid)
else:
return HttpResponseNotAllowed(['GET', 'POST'])
def search(request):
current_user = _anonymous_or_real(request)
@ -504,7 +533,11 @@ def search(request):
return render(request, 'search.html', context)
else:
return HttpResponseNotAllowed(['GET'])
@package_permission_required()
def package_models(request, package_uuid):
current_user = _anonymous_or_real(request)
current_package = PackageManager.get_package_by_id(current_user, package_uuid)
@ -587,10 +620,15 @@ def package_models(request, package_uuid):
mod = RuleBaseRelativeReasoning()
mod.save()
else:
return error(request, 'Invalid model type.', f'Model type "{model_type}" is not supported."')
return redirect(mod.url)
else:
return HttpResponseNotAllowed(['GET', 'POST'])
@package_permission_required()
def package_model(request, package_uuid, model_uuid):
current_user = _anonymous_or_real(request)
current_package = PackageManager.get_package_by_id(current_user, package_uuid)
@ -641,9 +679,10 @@ def package_model(request, package_uuid, model_uuid):
return HttpResponseBadRequest()
else:
return HttpResponseBadRequest()
return HttpResponseNotAllowed(['GET', 'POST'])
@package_permission_required()
def package(request, package_uuid):
current_user = _anonymous_or_real(request)
current_package = PackageManager.get_package_by_id(current_user, package_uuid)
@ -751,10 +790,10 @@ def package(request, package_uuid):
return HttpResponseBadRequest()
else:
return HttpResponseBadRequest()
return HttpResponseNotAllowed(['GET', 'POST'])
# https://envipath.org/package/<id>/compound
@package_permission_required()
def package_compounds(request, package_uuid):
current_user = _anonymous_or_real(request)
current_package = PackageManager.get_package_by_id(current_user, package_uuid)
@ -797,8 +836,11 @@ def package_compounds(request, package_uuid):
return redirect(c.url)
else:
return HttpResponseNotAllowed(['GET', 'POST'])
# https://envipath.org/package/<id>/compound/<id>
@package_permission_required()
def package_compound(request, package_uuid, compound_uuid):
current_user = _anonymous_or_real(request)
current_package = PackageManager.get_package_by_id(current_user, package_uuid)
@ -838,11 +880,12 @@ def package_compound(request, package_uuid, compound_uuid):
return redirect(current_compound.url)
else:
return HttpResponseBadRequest()
else:
return HttpResponseBadRequest()
return HttpResponseNotAllowed(['GET', 'POST'])
# https://envipath.org/package/<uuid>/compound/<uuid>/structure
@package_permission_required()
def package_compound_structures(request, package_uuid, compound_uuid):
current_user = _anonymous_or_real(request)
current_package = PackageManager.get_package_by_id(current_user, package_uuid)
@ -878,10 +921,10 @@ def package_compound_structures(request, package_uuid, compound_uuid):
return redirect(cs.url)
else:
return HttpResponseBadRequest()
return HttpResponseNotAllowed(['GET', 'POST'])
# https://envipath.org/package/<id>/compound/<id>/structure/<id>
@package_permission_required()
def package_compound_structure(request, package_uuid, compound_uuid, structure_uuid):
current_user = _anonymous_or_real(request)
current_package = PackageManager.get_package_by_id(current_user, package_uuid)
@ -899,8 +942,11 @@ def package_compound_structure(request, package_uuid, compound_uuid, structure_u
return render(request, 'objects/compound_structure.html', context)
else:
return HttpResponseNotAllowed(['GET', ])
# https://envipath.org/package/<id>/rule
@package_permission_required()
def package_rules(request, package_uuid):
current_user = _anonymous_or_real(request)
current_package = PackageManager.get_package_by_id(current_user, package_uuid)
@ -965,10 +1011,10 @@ def package_rules(request, package_uuid):
return redirect(r.url)
else:
return HttpResponseBadRequest()
return HttpResponseNotAllowed(['GET', 'POST'])
# https://envipath.org/package/<id>/rule/<id>
@package_permission_required()
def package_rule(request, package_uuid, rule_uuid):
current_user = _anonymous_or_real(request)
current_package = PackageManager.get_package_by_id(current_user, package_uuid)
@ -1012,10 +1058,10 @@ def package_rule(request, package_uuid, rule_uuid):
return HttpResponseBadRequest()
else:
return HttpResponseBadRequest()
return HttpResponseNotAllowed(['GET', 'POST'])
# https://envipath.org/package/<id>/reaction
@package_permission_required()
def package_reactions(request, package_uuid):
current_user = _anonymous_or_real(request)
current_package = PackageManager.get_package_by_id(current_user, package_uuid)
@ -1063,10 +1109,10 @@ def package_reactions(request, package_uuid):
return redirect(r.url)
else:
return HttpResponseBadRequest()
return HttpResponseNotAllowed(['GET', 'POST'])
# https://envipath.org/package/<id>/reaction/<id>
@package_permission_required()
def package_reaction(request, package_uuid, reaction_uuid):
current_user = _anonymous_or_real(request)
current_package = PackageManager.get_package_by_id(current_user, package_uuid)
@ -1108,10 +1154,10 @@ def package_reaction(request, package_uuid, reaction_uuid):
return HttpResponseBadRequest()
else:
return HttpResponseBadRequest()
return HttpResponseNotAllowed(['GET', 'POST'])
# https://envipath.org/package/<id>/pathway
@package_permission_required()
def package_pathways(request, package_uuid):
current_user = _anonymous_or_real(request)
current_package = PackageManager.get_package_by_id(current_user, package_uuid)
@ -1154,13 +1200,22 @@ def package_pathways(request, package_uuid):
pw_mode = request.POST.get('predict', 'predict')
smiles = request.POST.get('smiles')
if smiles is None or smiles == '':
return HttpResponseBadRequest()
if smiles is None or smiles.strip() == '':
return error(request, "Pathway prediction failed!",
"Pathway prediction failed due to missing or empty SMILES")
smiles = smiles.strip()
try:
stand_smiles = FormatConverter.standardize(smiles)
except ValueError:
return error(request, "Pathway prediction failed!",
f'Pathway prediction failed as standardization of SMILES "{smiles}" failed!')
if pw_mode not in ['predict', 'build', 'incremental']:
return HttpResponseBadRequest()
modes = ['predict', 'build', 'incremental']
if pw_mode not in modes:
return error(request, "Pathway prediction failed!",
f'Pathway prediction failed as received mode "{pw_mode}" is none of {modes}')
pw = Pathway.create(current_package, stand_smiles, name=name, description=description)
# set mode
@ -1185,10 +1240,10 @@ def package_pathways(request, package_uuid):
return redirect(pw.url)
else:
return HttpResponseBadRequest()
return HttpResponseNotAllowed(['GET', 'POST'])
# https://envipath.org/package/<id>/pathway/<id>
@package_permission_required()
def package_pathway(request, package_uuid, pathway_uuid):
current_user: User = _anonymous_or_real(request)
current_package: Package = PackageManager.get_package_by_id(current_user, package_uuid)
@ -1257,10 +1312,10 @@ def package_pathway(request, package_uuid, pathway_uuid):
return HttpResponseBadRequest()
else:
return HttpResponseBadRequest()
return HttpResponseNotAllowed(['GET', 'POST'])
# https://envipath.org/package/<id>/pathway/<id>/node
@package_permission_required()
def package_pathway_nodes(request, package_uuid, pathway_uuid):
current_user = _anonymous_or_real(request)
current_package = PackageManager.get_package_by_id(current_user, package_uuid)
@ -1313,10 +1368,10 @@ def package_pathway_nodes(request, package_uuid, pathway_uuid):
return redirect(current_pathway.url)
else:
return HttpResponseBadRequest()
return HttpResponseNotAllowed(['GET', 'POST'])
# https://envipath.org/package/<id>/pathway/<id>/node/<id>
@package_permission_required()
def package_pathway_node(request, package_uuid, pathway_uuid, node_uuid):
current_user = _anonymous_or_real(request)
current_package = PackageManager.get_package_by_id(current_user, package_uuid)
@ -1361,10 +1416,10 @@ def package_pathway_node(request, package_uuid, pathway_uuid, node_uuid):
return redirect(current_pathway.url)
else:
return HttpResponseBadRequest()
return HttpResponseNotAllowed(['GET', 'POST'])
# https://envipath.org/package/<id>/pathway/<id>/edge
@package_permission_required()
def package_pathway_edges(request, package_uuid, pathway_uuid):
current_user = _anonymous_or_real(request)
current_package = PackageManager.get_package_by_id(current_user, package_uuid)
@ -1422,10 +1477,10 @@ def package_pathway_edges(request, package_uuid, pathway_uuid):
return redirect(current_pathway.url)
else:
return HttpResponseBadRequest()
return HttpResponseNotAllowed(['GET', 'POST'])
# https://envipath.org/package/<id>/pathway/<id>/edge/<id>
@package_permission_required()
def package_pathway_edge(request, package_uuid, pathway_uuid, edge_uuid):
current_user = _anonymous_or_real(request)
current_package = PackageManager.get_package_by_id(current_user, package_uuid)
@ -1440,7 +1495,8 @@ def package_pathway_edge(request, package_uuid, pathway_uuid, edge_uuid):
return HttpResponse(svg_data, content_type="image/svg+xml")
context = get_base_context(request)
context['title'] = f'enviPath - {current_package.name} - {current_pathway.name} - {current_edge.edge_label.name}'
context[
'title'] = f'enviPath - {current_package.name} - {current_pathway.name} - {current_edge.edge_label.name}'
context['meta']['current_package'] = current_package
context['object_type'] = 'reaction'
@ -1460,10 +1516,10 @@ def package_pathway_edge(request, package_uuid, pathway_uuid, edge_uuid):
return redirect(current_pathway.url)
else:
return HttpResponseBadRequest()
return HttpResponseNotAllowed(['GET', 'POST'])
# https://envipath.org/package/<id>/scenario
@package_permission_required()
def package_scenarios(request, package_uuid):
current_user = _anonymous_or_real(request)
current_package = PackageManager.get_package_by_id(current_user, package_uuid)
@ -1497,8 +1553,11 @@ def package_scenarios(request, package_uuid):
return render(request, 'collections/objects_list.html', context)
else:
return HttpResponseNotAllowed(['GET', ])
# https://envipath.org/package/<id>/scenario/<id>
@package_permission_required()
def package_scenario(request, package_uuid, scenario_uuid):
current_user = _anonymous_or_real(request)
current_package = PackageManager.get_package_by_id(current_user, package_uuid)
@ -1516,6 +1575,9 @@ def package_scenario(request, package_uuid, scenario_uuid):
return render(request, 'objects/scenario.html', context)
else:
return HttpResponseNotAllowed(['GET', ])
##############
# User/Group #
@ -1536,6 +1598,9 @@ def users(request):
return render(request, 'collections/objects_list.html', context)
else:
return HttpResponseNotAllowed(['GET'])
def user(request, user_uuid):
current_user = _anonymous_or_real(request)
@ -1546,6 +1611,8 @@ def user(request, user_uuid):
if str(current_user.uuid) != user_uuid and not current_user.is_superuser:
return HttpResponseBadRequest()
user = UserManager.get_user_by_id(current_user, user_uuid)
context = get_base_context(request)
context['title'] = f'enviPath - User'
@ -1556,7 +1623,7 @@ def user(request, user_uuid):
{current_user.username: current_user.url}
]
context['user'] = current_user
context['user'] = user
model_qs = EPModel.objects.none()
for p in PackageManager.get_all_readable_packages(current_user, include_reviewed=True):
@ -1637,6 +1704,9 @@ def user(request, user_uuid):
return HttpResponseBadRequest()
else:
return HttpResponseNotAllowed(['GET', 'POST'])
def groups(request):
current_user = _anonymous_or_real(request)
@ -1663,6 +1733,9 @@ def groups(request):
return redirect(g.url)
else:
return HttpResponseNotAllowed(['GET', 'POST'])
def group(request, group_uuid):
current_user = _anonymous_or_real(request)
@ -1681,9 +1754,8 @@ def group(request, group_uuid):
context['group'] = current_group
# TODO use managers
context['users'] = get_user_model().objects.exclude(id__in=current_group.user_member.all())
context['groups'] = Group.objects.exclude(id__in=current_group.group_member.all()).exclude(id=current_group.pk)
context['users'] = UserManager.get_users_lp().exclude(id__in=current_group.user_member.all())
context['groups'] = GroupManager.get_groups_lp().exclude(id__in=current_group.group_member.all()).exclude(id=current_group.pk)
context['packages'] = Package.objects.filter(
id__in=GroupPackagePermission.objects.filter(group=current_group).values('package').distinct())
@ -1716,6 +1788,9 @@ def group(request, group_uuid):
return redirect(current_group.url)
else:
return HttpResponseNotAllowed(['GET', 'POST'])
def settings(request):
current_user = _anonymous_or_real(request)
@ -1775,6 +1850,9 @@ def settings(request):
return HttpResponse("Success!")
else:
return HttpResponseNotAllowed(['GET', 'POST'])
def setting(request, setting_uuid):
pass

View File

@ -3,10 +3,10 @@
{% block content %}
<div class="alert alert-danger" role="alert">
<h4 class="alert-heading">Something went wrong!</h4>
<p>An unexpected Error occurred...</p>
<h4 class="alert-heading">{{ error_message }}</h4>
<hr>
<p class="mb-0">
{{ error_detail }}<br>
The error was logged and will be investigated.
</p>
</div>

View File

@ -1,6 +1,5 @@
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
@ -29,17 +28,6 @@
z-index: -1;
}
/* Optional: dim layer */
.bg-dim {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.4);
z-index: 0;
}
.center-button {
position: absolute;
top: 50%;
@ -47,6 +35,15 @@
transform: translate(-50%, -50%);
z-index: 1;
}
.center-message {
position: absolute;
top: 40%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 1;
}
</style>
</head>
<body>
@ -55,17 +52,28 @@
<div class="bg-blur"></div>
<div class="bg-dim"></div>
{% if message %}
<div class="alert alert-danger" role="alert">
{{ message }}
</div>
{% endif %}
<!-- Trigger Button -->
<div class="center-button">
<button class="btn btn-primary btn-lg" data-toggle="modal" data-target="#signupmodal">Login / Sign Up</button>
</div>
<br>
<div class="center-message">
{% if message %}
<div class="alert alert-danger" role="alert">
{{ message }}
</div>
{% else %}
<div class="alert alert-success" role="alert">
Kia ora! We are running our closed beta tests at the moment. It would be great to get your help as tester,
you
can apply to become tester by registering for this page, just hit the button below. More information on the
beta
test is available in our <a href="https://community.envipath.org/t/apply-to-join-our-closed-beta/95">
community
form</a>
</div>
{% endif %}
</div>
<!-- Bootstrap Modal -->
<div class="modal fade bs-modal-sm" id="signupmodal" tabindex="-1" role="dialog"
aria-labelledby="mySmallModalLabel"

View File

@ -1,14 +0,0 @@
{% extends "base.html" %}
{% block content %}
{% if request.user.is_authenticated %}
<p>You are already logged in as {{ request.user.email }}.</p>
{% endif %}
<form action="{{ request.path }}" method="POST">
{% csrf_token %}
<p>
{{ form }}
<input type="submit" value="Send log in link">
</p>
</form>
{% endblock content %}

View File

@ -1,5 +0,0 @@
{% extends "base.html" %}
{% block content %}
<p>We sent a log in link. Check your email.</p>
{% endblock content %}

View File

@ -1,7 +1,7 @@
{% extends "framework.html" %}
{% load static %}
{% block content %}
{% load static %}
<script src="https://d3js.org/d3.v7.min.js"></script>
<style>
svg {
@ -141,7 +141,7 @@
<div id="tooltip" class="tooltip"></div>
</div>
</div>
<!-- Description -->
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
<h4 class="panel-title">
<a id="DescriptionLink" data-toggle="collapse" data-parent="#pathwayAccordion"
@ -152,6 +152,96 @@
{{ pathway.description | safe }}
</div>
</div>
{% if pathway.setting %}
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
<h4 class="panel-title">
<a id="pathwaySettingLink" data-toggle="collapse" data-parent="#pathwayAccordion"
href="#pathwaySetting">Setting</a></h4>
</div>
<div id="pathwaySetting" class="panel-collapse collapse in">
<div class="panel-body list-group-item" id="pathwaySettingContent">
<table class="table table-bordered table-hover">
<tr style="background-color: rgba(0, 0, 0, 0.08);">
<th scope="col" width="20%">Parameter</th>
<th scope="col" width="80%">Value</th>
</tr>
<tbody>
{% if pathway.setting.model %}
<tr>
<td width="20%">Model</td>
<td width="80%">
<table width="100%" class="table table-bordered table-hover">
<tbody>
<tr>
<td colspan="2">
<li class="list-group-item">
<a href="{{ pathway.setting.model.url }}">
{{ pathway.setting.model.name }}
</a>
</li>
</td>
</tr>
<tr>
<th width="20%">Model Parameter</th>
<th width="80%">Parameter Value</th>
</tr>
<tr>
<td width="20%">
Threshold
</td>
<td width="80%">
{{ pathway.setting.model_threshold }}
</td>
</tr>
</tbody>
</table>
</td>
</tr>
{% endif %}
{% if pathway.setting.rule_packages.all %}
<tr>
<td width="20%">Rule Packages</td>
<td width="80%">
<table width="100%" class="table table-bordered table-hover">
<tbody>
<tr>
<td colspan="2">
{% for p in pathway.setting.rule_packages.all %}
<li class="list-group-item">
<a href="{{ p.url }}">
{{ p.name }}
</a>
</li>
{% endfor %}
</td>
</tr>
</tbody>
</table>
</td>
</tr>
{% endif %}
<tr>
<td>
<p>Max Nodes</p>
</td>
<td>
<p>{{ pathway.setting.max_nodes }}</p>
</td>
</tr>
<tr>
<td>
<p>Max Depth</p>
</td>
<td>
<p>{{ pathway.setting.max_depth }}</p>
</td>
</tr>
</tbody>
</table>
</div>
</div>
{% endif %}
</div>
</div>
<script>

40
utilities/decorators.py Normal file
View File

@ -0,0 +1,40 @@
# decorators.py
from functools import wraps
from django.shortcuts import render
from epdb.logic import PackageManager
# Map HTTP methods to required permissions
DEFAULT_METHOD_PERMISSIONS = {
'GET': 'read',
'POST': 'write',
'DELETE': 'write',
}
def package_permission_required(method_permissions=None):
if method_permissions is None:
method_permissions = DEFAULT_METHOD_PERMISSIONS
def decorator(view_func):
@wraps(view_func)
def _wrapped_view(request, package_uuid, *args, **kwargs):
from epdb.views import _anonymous_or_real
user = _anonymous_or_real(request)
permission_required = method_permissions[request.method]
if not PackageManager.has_package_permission(user, package_uuid, permission_required):
from epdb.views import error
return error(
request,
"Operation failed!",
f"Couldn't perform the desired operation as {user.username} does not have the required permissions!",
code=403
)
return view_func(request, package_uuid, *args, **kwargs)
return _wrapped_view
return decorator