forked from enviPath/enviPy
[Feature] Server pagination implementation (#243)
## Major Changes - Implement a REST style API app in epapi - Currently implements a GET method for all entity types in the browse menu (both package level and global) - Provides paginated results per default with query style filtering for reviewed vs unreviewed. - Provides new paginated templates with thin wrappers per entity types for easier maintainability - Implements e2e tests for the API ## Minor changes - Added more comprehensive gitignore to cover coverage reports and other test/node.js etc. data. - Add additional CI file for API tests that only gets triggered on API relevant changes. ## ⚠️ Currently only works with session-based authentication. Token based will be added in new PR. Co-authored-by: Tim Lorsbach <tim@lorsba.ch> Co-authored-by: jebus <lorsbach@envipath.com> Reviewed-on: enviPath/enviPy#243 Co-authored-by: Tobias O <tobias.olenyi@envipath.com> Co-committed-by: Tobias O <tobias.olenyi@envipath.com>
This commit is contained in:
251
epdb/views.py
251
epdb/views.py
@ -474,20 +474,15 @@ def packages(request):
|
||||
if request.method == "GET":
|
||||
context = get_base_context(request)
|
||||
context["title"] = "enviPath - Packages"
|
||||
|
||||
context["object_type"] = "package"
|
||||
context["meta"]["current_package"] = context["meta"]["user"].default_package
|
||||
context["meta"]["can_edit"] = True
|
||||
|
||||
reviewed_package_qs = Package.objects.filter(reviewed=True).order_by("created")
|
||||
unreviewed_package_qs = PackageManager.get_all_readable_packages(current_user).order_by(
|
||||
"name"
|
||||
)
|
||||
# Context for paginated template
|
||||
context["entity_type"] = "package"
|
||||
context["api_endpoint"] = "/api/v1/packages/"
|
||||
context["per_page"] = s.API_PAGINATION_DEFAULT_PAGE_SIZE
|
||||
context["list_title"] = "packages"
|
||||
|
||||
context["reviewed_objects"] = reviewed_package_qs
|
||||
context["unreviewed_objects"] = unreviewed_package_qs
|
||||
|
||||
return render(request, "collections/objects_list.html", context)
|
||||
return render(request, "collections/packages_paginated.html", context)
|
||||
|
||||
elif request.method == "POST":
|
||||
if hidden := request.POST.get("hidden", None):
|
||||
@ -533,29 +528,16 @@ def compounds(request):
|
||||
if request.method == "GET":
|
||||
context = get_base_context(request)
|
||||
context["title"] = "enviPath - Compounds"
|
||||
|
||||
context["object_type"] = "compound"
|
||||
context["meta"]["current_package"] = context["meta"]["user"].default_package
|
||||
|
||||
reviewed_compound_qs = Compound.objects.none()
|
||||
# Context for paginated template
|
||||
context["entity_type"] = "compound"
|
||||
context["api_endpoint"] = "/api/v1/compounds/"
|
||||
context["per_page"] = s.API_PAGINATION_DEFAULT_PAGE_SIZE
|
||||
context["list_mode"] = "tabbed"
|
||||
context["list_title"] = "compounds"
|
||||
|
||||
for p in PackageManager.get_reviewed_packages():
|
||||
reviewed_compound_qs |= Compound.objects.filter(package=p)
|
||||
|
||||
reviewed_compound_qs = reviewed_compound_qs.order_by("name")
|
||||
|
||||
if request.GET.get("all"):
|
||||
return JsonResponse(
|
||||
{
|
||||
"objects": [
|
||||
{"name": pw.name, "url": pw.url, "reviewed": True}
|
||||
for pw in reviewed_compound_qs
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
context["reviewed_objects"] = reviewed_compound_qs
|
||||
return render(request, "collections/objects_list.html", context)
|
||||
return render(request, "collections/compounds_paginated.html", context)
|
||||
|
||||
elif request.method == "POST":
|
||||
# delegate to default package
|
||||
@ -571,32 +553,19 @@ def rules(request):
|
||||
if request.method == "GET":
|
||||
context = get_base_context(request)
|
||||
context["title"] = "enviPath - Rules"
|
||||
|
||||
context["object_type"] = "rule"
|
||||
context["meta"]["current_package"] = context["meta"]["user"].default_package
|
||||
context["breadcrumbs"] = [
|
||||
{"Home": s.SERVER_URL},
|
||||
{"Rule": s.SERVER_URL + "/rule"},
|
||||
]
|
||||
reviewed_rule_qs = Rule.objects.none()
|
||||
|
||||
for p in PackageManager.get_reviewed_packages():
|
||||
reviewed_rule_qs |= Rule.objects.filter(package=p)
|
||||
# Context for paginated template
|
||||
context["entity_type"] = "rule"
|
||||
context["api_endpoint"] = "/api/v1/rules/"
|
||||
context["per_page"] = s.API_PAGINATION_DEFAULT_PAGE_SIZE
|
||||
context["list_title"] = "rules"
|
||||
|
||||
reviewed_rule_qs = reviewed_rule_qs.order_by("name")
|
||||
|
||||
if request.GET.get("all"):
|
||||
return JsonResponse(
|
||||
{
|
||||
"objects": [
|
||||
{"name": pw.name, "url": pw.url, "reviewed": True}
|
||||
for pw in reviewed_rule_qs
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
context["reviewed_objects"] = reviewed_rule_qs
|
||||
return render(request, "collections/objects_list.html", context)
|
||||
return render(request, "collections/rules_paginated.html", context)
|
||||
|
||||
elif request.method == "POST":
|
||||
# delegate to default package
|
||||
@ -612,32 +581,19 @@ def reactions(request):
|
||||
if request.method == "GET":
|
||||
context = get_base_context(request)
|
||||
context["title"] = "enviPath - Reactions"
|
||||
|
||||
context["object_type"] = "reaction"
|
||||
context["meta"]["current_package"] = context["meta"]["user"].default_package
|
||||
context["breadcrumbs"] = [
|
||||
{"Home": s.SERVER_URL},
|
||||
{"Reaction": s.SERVER_URL + "/reaction"},
|
||||
]
|
||||
reviewed_reaction_qs = Reaction.objects.none()
|
||||
|
||||
for p in PackageManager.get_reviewed_packages():
|
||||
reviewed_reaction_qs |= Reaction.objects.filter(package=p).order_by("name")
|
||||
# Context for paginated template
|
||||
context["entity_type"] = "reaction"
|
||||
context["api_endpoint"] = "/api/v1/reactions/"
|
||||
context["per_page"] = s.API_PAGINATION_DEFAULT_PAGE_SIZE
|
||||
context["list_title"] = "reactions"
|
||||
|
||||
reviewed_reaction_qs = reviewed_reaction_qs.order_by("name")
|
||||
|
||||
if request.GET.get("all"):
|
||||
return JsonResponse(
|
||||
{
|
||||
"objects": [
|
||||
{"name": pw.name, "url": pw.url, "reviewed": True}
|
||||
for pw in reviewed_reaction_qs
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
context["reviewed_objects"] = reviewed_reaction_qs
|
||||
return render(request, "collections/objects_list.html", context)
|
||||
return render(request, "collections/reactions_paginated.html", context)
|
||||
|
||||
elif request.method == "POST":
|
||||
# delegate to default package
|
||||
@ -653,33 +609,19 @@ def pathways(request):
|
||||
if request.method == "GET":
|
||||
context = get_base_context(request)
|
||||
context["title"] = "enviPath - Pathways"
|
||||
|
||||
context["object_type"] = "pathway"
|
||||
context["meta"]["current_package"] = context["meta"]["user"].default_package
|
||||
context["breadcrumbs"] = [
|
||||
{"Home": s.SERVER_URL},
|
||||
{"Pathway": s.SERVER_URL + "/pathway"},
|
||||
]
|
||||
|
||||
reviewed_pathway_qs = Pathway.objects.none()
|
||||
# Context for paginated template
|
||||
context["entity_type"] = "pathway"
|
||||
context["api_endpoint"] = "/api/v1/pathways/"
|
||||
context["per_page"] = s.API_PAGINATION_DEFAULT_PAGE_SIZE
|
||||
context["list_title"] = "pathways"
|
||||
|
||||
for p in PackageManager.get_reviewed_packages():
|
||||
reviewed_pathway_qs |= Pathway.objects.filter(package=p).order_by("name")
|
||||
|
||||
reviewed_pathway_qs = reviewed_pathway_qs.order_by("name")
|
||||
|
||||
if request.GET.get("all"):
|
||||
return JsonResponse(
|
||||
{
|
||||
"objects": [
|
||||
{"name": pw.name, "url": pw.url, "reviewed": True}
|
||||
for pw in reviewed_pathway_qs
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
context["reviewed_objects"] = reviewed_pathway_qs
|
||||
return render(request, "collections/objects_list.html", context)
|
||||
return render(request, "collections/pathways_paginated.html", context)
|
||||
|
||||
elif request.method == "POST":
|
||||
# delegate to default package
|
||||
@ -703,25 +645,13 @@ def scenarios(request):
|
||||
{"Scenario": s.SERVER_URL + "/scenario"},
|
||||
]
|
||||
|
||||
reviewed_scenario_qs = Scenario.objects.none()
|
||||
# Context for paginated template
|
||||
context["entity_type"] = "scenario"
|
||||
context["api_endpoint"] = "/api/v1/scenarios/"
|
||||
context["per_page"] = s.API_PAGINATION_DEFAULT_PAGE_SIZE
|
||||
context["list_title"] = "scenarios"
|
||||
|
||||
for p in PackageManager.get_reviewed_packages():
|
||||
reviewed_scenario_qs |= Scenario.objects.filter(package=p).order_by("name")
|
||||
|
||||
reviewed_scenario_qs = reviewed_scenario_qs.order_by("name")
|
||||
|
||||
if request.GET.get("all"):
|
||||
return JsonResponse(
|
||||
{
|
||||
"objects": [
|
||||
{"name": s.name, "url": s.url, "reviewed": True}
|
||||
for s in reviewed_scenario_qs
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
context["reviewed_objects"] = reviewed_scenario_qs
|
||||
return render(request, "collections/objects_list.html", context)
|
||||
return render(request, "collections/scenarios_paginated.html", context)
|
||||
|
||||
elif request.method == "POST":
|
||||
# delegate to default package
|
||||
@ -736,42 +666,28 @@ def models(request):
|
||||
if request.method == "GET":
|
||||
context = get_base_context(request)
|
||||
context["title"] = "enviPath - Models"
|
||||
|
||||
context["object_type"] = "model"
|
||||
context["meta"]["current_package"] = context["meta"]["user"].default_package
|
||||
context["breadcrumbs"] = [
|
||||
{"Home": s.SERVER_URL},
|
||||
{"Model": s.SERVER_URL + "/model"},
|
||||
]
|
||||
|
||||
# Keep model_types for potential modal/action use
|
||||
context["model_types"] = {
|
||||
"ML Relative Reasoning": "ml-relative-reasoning",
|
||||
"Rule Based Relative Reasoning": "rule-based-relative-reasoning",
|
||||
"EnviFormer": "enviformer",
|
||||
}
|
||||
|
||||
for k, v in s.CLASSIFIER_PLUGINS.items():
|
||||
context["model_types"][v.display()] = k
|
||||
|
||||
reviewed_model_qs = EPModel.objects.none()
|
||||
# Context for paginated template
|
||||
context["entity_type"] = "model"
|
||||
context["api_endpoint"] = "/api/v1/models/"
|
||||
context["per_page"] = s.API_PAGINATION_DEFAULT_PAGE_SIZE
|
||||
context["list_title"] = "models"
|
||||
|
||||
for p in PackageManager.get_reviewed_packages():
|
||||
reviewed_model_qs |= EPModel.objects.filter(package=p).order_by("name")
|
||||
|
||||
reviewed_model_qs = reviewed_model_qs.order_by("name")
|
||||
|
||||
if request.GET.get("all"):
|
||||
return JsonResponse(
|
||||
{
|
||||
"objects": [
|
||||
{"name": pw.name, "url": pw.url, "reviewed": True}
|
||||
for pw in reviewed_model_qs
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
context["reviewed_objects"] = reviewed_model_qs
|
||||
return render(request, "collections/objects_list.html", context)
|
||||
return render(request, "collections/models_paginated.html", context)
|
||||
|
||||
elif request.method == "POST":
|
||||
current_user = _anonymous_or_real(request)
|
||||
@ -848,6 +764,10 @@ def package_models(request, package_uuid):
|
||||
context["meta"]["current_package"] = current_package
|
||||
context["object_type"] = "model"
|
||||
context["breadcrumbs"] = breadcrumbs(current_package, "model")
|
||||
context["entity_type"] = "model"
|
||||
context["api_endpoint"] = f"/api/v1/package/{current_package.uuid}/model/"
|
||||
context["per_page"] = s.API_PAGINATION_DEFAULT_PAGE_SIZE
|
||||
context["list_title"] = "models"
|
||||
|
||||
reviewed_model_qs = EPModel.objects.none()
|
||||
unreviewed_model_qs = EPModel.objects.none()
|
||||
@ -869,9 +789,6 @@ def package_models(request, package_uuid):
|
||||
}
|
||||
)
|
||||
|
||||
context["reviewed_objects"] = reviewed_model_qs
|
||||
context["unreviewed_objects"] = unreviewed_model_qs
|
||||
|
||||
context["model_types"] = {
|
||||
"ML Relative Reasoning": "mlrr",
|
||||
"Rule Based Relative Reasoning": "rbrr",
|
||||
@ -884,7 +801,7 @@ def package_models(request, package_uuid):
|
||||
for k, v in s.CLASSIFIER_PLUGINS.items():
|
||||
context["model_types"][v.display()] = k
|
||||
|
||||
return render(request, "collections/objects_list.html", context)
|
||||
return render(request, "collections/models_paginated.html", context)
|
||||
|
||||
elif request.method == "POST":
|
||||
log_post_params(request)
|
||||
@ -1242,6 +1159,11 @@ def package_compounds(request, package_uuid):
|
||||
context["meta"]["current_package"] = current_package
|
||||
context["object_type"] = "compound"
|
||||
context["breadcrumbs"] = breadcrumbs(current_package, "compound")
|
||||
context["entity_type"] = "compound"
|
||||
context["api_endpoint"] = f"/api/v1/package/{current_package.uuid}/compound/"
|
||||
context["per_page"] = s.API_PAGINATION_DEFAULT_PAGE_SIZE
|
||||
context["list_mode"] = "tabbed"
|
||||
context["list_title"] = "compounds"
|
||||
|
||||
reviewed_compound_qs = Compound.objects.none()
|
||||
unreviewed_compound_qs = Compound.objects.none()
|
||||
@ -1267,10 +1189,7 @@ def package_compounds(request, package_uuid):
|
||||
}
|
||||
)
|
||||
|
||||
context["reviewed_objects"] = reviewed_compound_qs
|
||||
context["unreviewed_objects"] = unreviewed_compound_qs
|
||||
|
||||
return render(request, "collections/objects_list.html", context)
|
||||
return render(request, "collections/compounds_paginated.html", context)
|
||||
|
||||
elif request.method == "POST":
|
||||
compound_name = request.POST.get("compound-name")
|
||||
@ -1389,19 +1308,17 @@ def package_compound_structures(request, package_uuid, compound_uuid):
|
||||
context["breadcrumbs"] = breadcrumbs(
|
||||
current_package, "compound", current_compound, "structure"
|
||||
)
|
||||
context["entity_type"] = "structure"
|
||||
context["page_title"] = f"{current_compound.name} - Structures"
|
||||
context["api_endpoint"] = (
|
||||
f"/api/v1/package/{current_package.uuid}/compound/{current_compound.uuid}/structure/"
|
||||
)
|
||||
context["per_page"] = s.API_PAGINATION_DEFAULT_PAGE_SIZE
|
||||
context["compound"] = current_compound
|
||||
context["list_mode"] = "combined"
|
||||
context["list_title"] = "structures"
|
||||
|
||||
reviewed_compound_structure_qs = CompoundStructure.objects.none()
|
||||
unreviewed_compound_structure_qs = CompoundStructure.objects.none()
|
||||
|
||||
if current_package.reviewed:
|
||||
reviewed_compound_structure_qs = current_compound.structures.order_by("name")
|
||||
else:
|
||||
unreviewed_compound_structure_qs = current_compound.structures.order_by("name")
|
||||
|
||||
context["reviewed_objects"] = reviewed_compound_structure_qs
|
||||
context["unreviewed_objects"] = unreviewed_compound_structure_qs
|
||||
|
||||
return render(request, "collections/objects_list.html", context)
|
||||
return render(request, "collections/structures_paginated.html", context)
|
||||
|
||||
elif request.method == "POST":
|
||||
structure_name = request.POST.get("structure-name")
|
||||
@ -1548,6 +1465,10 @@ def package_rules(request, package_uuid):
|
||||
context["meta"]["current_package"] = current_package
|
||||
context["object_type"] = "rule"
|
||||
context["breadcrumbs"] = breadcrumbs(current_package, "rule")
|
||||
context["entity_type"] = "rule"
|
||||
context["api_endpoint"] = f"/api/v1/package/{current_package.uuid}/rule/"
|
||||
context["per_page"] = s.API_PAGINATION_DEFAULT_PAGE_SIZE
|
||||
context["list_title"] = "rules"
|
||||
|
||||
reviewed_rule_qs = Rule.objects.none()
|
||||
unreviewed_rule_qs = Rule.objects.none()
|
||||
@ -1569,10 +1490,7 @@ def package_rules(request, package_uuid):
|
||||
}
|
||||
)
|
||||
|
||||
context["reviewed_objects"] = reviewed_rule_qs
|
||||
context["unreviewed_objects"] = unreviewed_rule_qs
|
||||
|
||||
return render(request, "collections/objects_list.html", context)
|
||||
return render(request, "collections/rules_paginated.html", context)
|
||||
|
||||
elif request.method == "POST":
|
||||
log_post_params(request)
|
||||
@ -1750,11 +1668,15 @@ def package_reactions(request, package_uuid):
|
||||
|
||||
if request.method == "GET":
|
||||
context = get_base_context(request)
|
||||
context["title"] = f"enviPath - {current_package.name} - {current_package.name} - Reactions"
|
||||
context["title"] = f"enviPath - {current_package.name} - Reactions"
|
||||
|
||||
context["meta"]["current_package"] = current_package
|
||||
context["object_type"] = "reaction"
|
||||
context["breadcrumbs"] = breadcrumbs(current_package, "reaction")
|
||||
context["entity_type"] = "reaction"
|
||||
context["api_endpoint"] = f"/api/v1/package/{current_package.uuid}/reaction/"
|
||||
context["per_page"] = s.API_PAGINATION_DEFAULT_PAGE_SIZE
|
||||
context["list_title"] = "reactions"
|
||||
|
||||
reviewed_reaction_qs = Reaction.objects.none()
|
||||
unreviewed_reaction_qs = Reaction.objects.none()
|
||||
@ -1780,10 +1702,7 @@ def package_reactions(request, package_uuid):
|
||||
}
|
||||
)
|
||||
|
||||
context["reviewed_objects"] = reviewed_reaction_qs
|
||||
context["unreviewed_objects"] = unreviewed_reaction_qs
|
||||
|
||||
return render(request, "collections/objects_list.html", context)
|
||||
return render(request, "collections/reactions_paginated.html", context)
|
||||
|
||||
elif request.method == "POST":
|
||||
reaction_name = request.POST.get("reaction-name")
|
||||
@ -1902,6 +1821,10 @@ def package_pathways(request, package_uuid):
|
||||
context["meta"]["current_package"] = current_package
|
||||
context["object_type"] = "pathway"
|
||||
context["breadcrumbs"] = breadcrumbs(current_package, "pathway")
|
||||
context["entity_type"] = "pathway"
|
||||
context["api_endpoint"] = f"/api/v1/package/{current_package.uuid}/pathway/"
|
||||
context["per_page"] = s.API_PAGINATION_DEFAULT_PAGE_SIZE
|
||||
context["list_title"] = "pathways"
|
||||
|
||||
reviewed_pathway_qs = Pathway.objects.none()
|
||||
unreviewed_pathway_qs = Pathway.objects.none()
|
||||
@ -1925,10 +1848,7 @@ def package_pathways(request, package_uuid):
|
||||
}
|
||||
)
|
||||
|
||||
context["reviewed_objects"] = reviewed_pathway_qs
|
||||
context["unreviewed_objects"] = unreviewed_pathway_qs
|
||||
|
||||
return render(request, "collections/objects_list.html", context)
|
||||
return render(request, "collections/pathways_paginated.html", context)
|
||||
|
||||
elif request.method == "POST":
|
||||
log_post_params(request)
|
||||
@ -2465,6 +2385,10 @@ def package_scenarios(request, package_uuid):
|
||||
context["meta"]["current_package"] = current_package
|
||||
context["object_type"] = "scenario"
|
||||
context["breadcrumbs"] = breadcrumbs(current_package, "scenario")
|
||||
context["entity_type"] = "scenario"
|
||||
context["api_endpoint"] = f"/api/v1/package/{current_package.uuid}/scenario/"
|
||||
context["per_page"] = s.API_PAGINATION_DEFAULT_PAGE_SIZE
|
||||
context["list_title"] = "scenarios"
|
||||
|
||||
reviewed_scenario_qs = Scenario.objects.none()
|
||||
unreviewed_scenario_qs = Scenario.objects.none()
|
||||
@ -2490,9 +2414,6 @@ def package_scenarios(request, package_uuid):
|
||||
}
|
||||
)
|
||||
|
||||
context["reviewed_objects"] = reviewed_scenario_qs
|
||||
context["unreviewed_objects"] = unreviewed_scenario_qs
|
||||
|
||||
from envipy_additional_information import (
|
||||
SEDIMENT_ADDITIONAL_INFORMATION,
|
||||
SLUDGE_ADDITIONAL_INFORMATION,
|
||||
@ -2527,7 +2448,7 @@ def package_scenarios(request, package_uuid):
|
||||
context["soil_additional_information"] = SOIL_ADDITIONAL_INFORMATION
|
||||
context["sediment_additional_information"] = SEDIMENT_ADDITIONAL_INFORMATION
|
||||
|
||||
return render(request, "collections/objects_list.html", context)
|
||||
return render(request, "collections/scenarios_paginated.html", context)
|
||||
elif request.method == "POST":
|
||||
log_post_params(request)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user