forked from enviPath/enviPy
[Feature] Leftovers after Release (#303)
Co-authored-by: Tim Lorsbach <tim@lorsba.ch> Reviewed-on: enviPath/enviPy#303
This commit is contained in:
@ -28,7 +28,7 @@ Package = s.GET_PACKAGE_MODEL()
|
||||
|
||||
|
||||
class UserAdmin(admin.ModelAdmin):
|
||||
list_display = ["username", "email", "is_active"]
|
||||
list_display = ["username", "email", "is_active", "is_staff", "is_superuser"]
|
||||
|
||||
|
||||
class UserPackagePermissionAdmin(admin.ModelAdmin):
|
||||
@ -48,7 +48,7 @@ class JobLogAdmin(admin.ModelAdmin):
|
||||
|
||||
|
||||
class EPAdmin(admin.ModelAdmin):
|
||||
search_fields = ["name", "description"]
|
||||
search_fields = ["name", "description", "url", "uuid"]
|
||||
list_display = ["name", "url", "created"]
|
||||
ordering = ["-created"]
|
||||
|
||||
|
||||
@ -18,6 +18,8 @@ from .models import (
|
||||
Edge,
|
||||
EnviFormer,
|
||||
EPModel,
|
||||
Group,
|
||||
GroupPackagePermission,
|
||||
MLRelativeReasoning,
|
||||
Node,
|
||||
PackageBasedModel,
|
||||
@ -204,6 +206,82 @@ def get_user(request, user_uuid):
|
||||
}
|
||||
|
||||
|
||||
########
|
||||
# Group #
|
||||
########
|
||||
|
||||
|
||||
class GroupMember(Schema):
|
||||
id: str = Field(None, alias="url")
|
||||
identifier: str
|
||||
name: str
|
||||
|
||||
|
||||
class GroupWrapper(Schema):
|
||||
group: List[SimpleGroup]
|
||||
|
||||
|
||||
class GroupSchema(Schema):
|
||||
description: str
|
||||
id: str = Field(None, alias="url")
|
||||
identifier: str = "group"
|
||||
members: List[GroupMember] = Field([], alias="members")
|
||||
name: str = Field(None, alias="name")
|
||||
ownerid: str = Field(None, alias="owner.url")
|
||||
ownername: str = Field(None, alias="owner.name")
|
||||
packages: List["SimplePackage"] = Field([], alias="packages")
|
||||
readers: List[GroupMember] = Field([], alias="readers")
|
||||
writers: List[GroupMember] = Field([], alias="writers")
|
||||
|
||||
@staticmethod
|
||||
def resolve_members(obj: Group):
|
||||
res = []
|
||||
for member in obj.user_member.all():
|
||||
res.append(GroupMember(id=member.url, identifier="usermember", name=member.username))
|
||||
|
||||
for member in obj.group_member.all():
|
||||
res.append(GroupMember(id=member.url, identifier="groupmember", name=member.name))
|
||||
|
||||
return res
|
||||
|
||||
@staticmethod
|
||||
def resolve_packages(obj: Group):
|
||||
return Package.objects.filter(
|
||||
id__in=[
|
||||
GroupPackagePermission.objects.filter(group=obj).values_list(
|
||||
"package_id", flat=True
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def resolve_readers(obj: Group):
|
||||
return GroupSchema.resolve_members(obj)
|
||||
|
||||
@staticmethod
|
||||
def resolve_writers(obj: Group):
|
||||
return [GroupMember(id=obj.owner.url, identifier="usermember", name=obj.owner.username)]
|
||||
|
||||
|
||||
@router.get("/group", response={200: GroupWrapper, 403: Error})
|
||||
def get_groups(request):
|
||||
return {"group": GroupManager.get_groups(request.user)}
|
||||
|
||||
|
||||
@router.get("/group/{uuid:group_uuid}", response={200: GroupSchema, 403: Error})
|
||||
def get_group(request, group_uuid):
|
||||
try:
|
||||
g = GroupManager.get_group_by_id(request.user, group_uuid)
|
||||
return g
|
||||
except ValueError:
|
||||
return 403, {
|
||||
"message": f"Getting Group with id {group_uuid} failed due to insufficient rights!"
|
||||
}
|
||||
|
||||
|
||||
##########
|
||||
# Search #
|
||||
##########
|
||||
class Search(Schema):
|
||||
packages: List[str] = Field(alias="packages[]")
|
||||
search: str
|
||||
|
||||
17
epdb/migrations/0015_user_is_reviewer.py
Normal file
17
epdb/migrations/0015_user_is_reviewer.py
Normal file
@ -0,0 +1,17 @@
|
||||
# Generated by Django 5.2.7 on 2026-01-19 19:26
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("epdb", "0014_rename_expansion_schema_setting_expansion_scheme"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="user",
|
||||
name="is_reviewer",
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
||||
@ -72,6 +72,7 @@ class User(AbstractUser):
|
||||
null=True,
|
||||
blank=False,
|
||||
)
|
||||
is_reviewer = models.BooleanField(default=False)
|
||||
|
||||
USERNAME_FIELD = "email"
|
||||
REQUIRED_FIELDS = ["username"]
|
||||
@ -1828,8 +1829,8 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin):
|
||||
queue.append(prod)
|
||||
|
||||
# We shouldn't lose or make up nodes...
|
||||
assert len(nodes) == len(self.nodes)
|
||||
logger.debug(f"{self.name}: Num Nodes {len(nodes)} vs. DB Nodes {len(self.nodes)}")
|
||||
if len(nodes) != len(self.nodes):
|
||||
logger.debug(f"{self.name}: Num Nodes {len(nodes)} vs. DB Nodes {len(self.nodes)}")
|
||||
|
||||
links = [e.d3_json() for e in self.edges]
|
||||
|
||||
@ -1880,6 +1881,7 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin):
|
||||
"source": pseudo_idx,
|
||||
"target": node_url_to_idx[target],
|
||||
"app_domain": link.get("app_domain", None),
|
||||
"multi_step": link["multi_step"],
|
||||
}
|
||||
adjusted_links.append(new_link)
|
||||
|
||||
@ -2146,6 +2148,7 @@ class Node(EnviPathModel, AliasMixin, ScenarioMixin):
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
@transaction.atomic
|
||||
def create(
|
||||
pathway: "Pathway",
|
||||
smiles: str,
|
||||
@ -2185,8 +2188,11 @@ class Node(EnviPathModel, AliasMixin, ScenarioMixin):
|
||||
if data:
|
||||
rule_ids = defaultdict(list)
|
||||
for e in Edge.objects.filter(start_nodes__in=[self]):
|
||||
for r in e.edge_label.rules.all():
|
||||
rule_ids[str(r.uuid)].append(e.simple_json())
|
||||
# TODO While the Pathway is being predicted we sometimes
|
||||
# TODO receive 'NoneType' object has no attribute 'rules'
|
||||
if e.edge_label:
|
||||
for r in e.edge_label.rules.all():
|
||||
rule_ids[str(r.uuid)].append(e.simple_json())
|
||||
|
||||
for t in data["assessment"]["transformations"]:
|
||||
if t["rule"]["uuid"] in rule_ids:
|
||||
@ -2230,6 +2236,7 @@ class Edge(EnviPathModel, AliasMixin, ScenarioMixin):
|
||||
"reaction": {"name": self.edge_label.name, "url": self.edge_label.url}
|
||||
if self.edge_label
|
||||
else None,
|
||||
"multi_step": self.edge_label.multi_step if self.edge_label else False,
|
||||
"reaction_probability": self.kv.get("probability"),
|
||||
"start_node_urls": [x.url for x in self.start_nodes.all()],
|
||||
"end_node_urls": [x.url for x in self.end_nodes.all()],
|
||||
@ -2270,6 +2277,7 @@ class Edge(EnviPathModel, AliasMixin, ScenarioMixin):
|
||||
return edge_json
|
||||
|
||||
@staticmethod
|
||||
@transaction.atomic
|
||||
def create(
|
||||
pathway,
|
||||
start_nodes: List[Node],
|
||||
@ -3819,6 +3827,11 @@ class Scenario(EnviPathModel):
|
||||
|
||||
yield inst
|
||||
|
||||
def related_pathways(self):
|
||||
return Pathway.objects.filter(
|
||||
scenarios__in=[self], package__reviewed=True, package=self.package
|
||||
).distinct()
|
||||
|
||||
|
||||
class UserSettingPermission(Permission):
|
||||
uuid = models.UUIDField(
|
||||
|
||||
@ -1352,6 +1352,14 @@ def package_compound_structure(request, package_uuid, compound_uuid, structure_u
|
||||
)
|
||||
|
||||
if request.method == "GET":
|
||||
is_image_request = request.GET.get("image")
|
||||
|
||||
if is_image_request:
|
||||
if is_image_request == "svg":
|
||||
return HttpResponse(current_structure.as_svg, content_type="image/svg+xml")
|
||||
else:
|
||||
return HttpResponseBadRequest("Currently only SVG as image formate supported!")
|
||||
|
||||
context = get_base_context(request)
|
||||
context["title"] = (
|
||||
f"enviPath - {current_package.name} - {current_compound.name} - {current_structure.name}"
|
||||
@ -2569,6 +2577,28 @@ def package_scenario(request, package_uuid, scenario_uuid):
|
||||
return redirect(current_scenario.url)
|
||||
else:
|
||||
return HttpResponseBadRequest()
|
||||
|
||||
new_scenario_name = request.POST.get("scenario-name")
|
||||
|
||||
if new_scenario_name is not None:
|
||||
new_scenario_name = nh3.clean(new_scenario_name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||
|
||||
if new_scenario_name:
|
||||
current_scenario.name = new_scenario_name
|
||||
|
||||
new_scenario_description = request.POST.get("scenario-description")
|
||||
|
||||
if new_scenario_description is not None:
|
||||
new_scenario_description = nh3.clean(
|
||||
new_scenario_description, tags=s.ALLOWED_HTML_TAGS
|
||||
).strip()
|
||||
|
||||
if new_scenario_description:
|
||||
current_scenario.description = new_scenario_description
|
||||
|
||||
if any([new_scenario_name, new_scenario_description]):
|
||||
current_scenario.save()
|
||||
return redirect(current_scenario.url)
|
||||
else:
|
||||
return HttpResponseBadRequest()
|
||||
else:
|
||||
@ -2784,10 +2814,17 @@ def settings(request):
|
||||
context["object_type"] = "setting"
|
||||
context["breadcrumbs"] = [
|
||||
{"Home": s.SERVER_URL},
|
||||
{"Group": s.SERVER_URL + "/setting"},
|
||||
{"Setting": s.SERVER_URL + "/setting"},
|
||||
]
|
||||
|
||||
context["objects"] = SettingManager.get_all_settings(current_user)
|
||||
# Context for paginated template
|
||||
context["entity_type"] = "setting"
|
||||
context["api_endpoint"] = "/api/v1/settings/"
|
||||
context["per_page"] = s.API_PAGINATION_DEFAULT_PAGE_SIZE
|
||||
context["list_title"] = "settings"
|
||||
context["list_mode"] = "combined"
|
||||
|
||||
return render(request, "collections/settings_paginated.html", context)
|
||||
|
||||
return render(request, "collections/objects_list.html", context)
|
||||
elif request.method == "POST":
|
||||
@ -2867,7 +2904,26 @@ def settings(request):
|
||||
|
||||
|
||||
def setting(request, setting_uuid):
|
||||
pass
|
||||
current_user = _anonymous_or_real(request)
|
||||
current_setting = SettingManager.get_setting_by_id(current_user, setting_uuid)
|
||||
|
||||
if request.method == "GET":
|
||||
context = get_base_context(request)
|
||||
context["title"] = f"enviPath - {current_setting.name}"
|
||||
|
||||
context["object_type"] = "setting"
|
||||
context["breadcrumbs"] = [
|
||||
{"Home": s.SERVER_URL},
|
||||
{"Setting": s.SERVER_URL + "/setting"},
|
||||
{f"{current_setting.name}": current_setting.url},
|
||||
]
|
||||
|
||||
context["setting"] = current_setting
|
||||
context["current_object"] = current_setting
|
||||
|
||||
return render(request, "objects/setting.html", context)
|
||||
else:
|
||||
return HttpResponseNotAllowed(["GET"])
|
||||
|
||||
|
||||
def jobs(request):
|
||||
|
||||
Reference in New Issue
Block a user