diff --git a/epapi/v1/endpoints/joblogs.py b/epapi/v1/endpoints/joblogs.py new file mode 100644 index 00000000..0ed190c9 --- /dev/null +++ b/epapi/v1/endpoints/joblogs.py @@ -0,0 +1,26 @@ +from django.conf import settings as s +from ninja import Router +from ninja_extra.pagination import paginate + +from epdb.models import JobLog +from ..pagination import EnhancedPageNumberPagination +from ..schemas import JobLogOutSchema + +router = Router() + + +@router.get("/joblog/", response=EnhancedPageNumberPagination.Output[JobLogOutSchema]) +@paginate( + EnhancedPageNumberPagination, + page_size=s.API_PAGINATION_DEFAULT_PAGE_SIZE, +) +def list_all_joblogs(request): + """ + List all JobLogs from reviewed packages. + """ + current_user = request.user + + if current_user.is_superuser: + return JobLog.objects.all().order_by("-created") + else: + return JobLog.objects.filter(user=current_user).order_by("-created") diff --git a/epapi/v1/router.py b/epapi/v1/router.py index 472c6f3c..7da967dd 100644 --- a/epapi/v1/router.py +++ b/epapi/v1/router.py @@ -15,6 +15,7 @@ from .endpoints import ( additional_information, settings, groups, + joblogs, ) # Main router with authentication @@ -37,6 +38,7 @@ router.add_router("", structure.router) router.add_router("", additional_information.router) router.add_router("", settings.router) router.add_router("", groups.router) +router.add_router("", joblogs.router) if s.IUCLID_EXPORT_ENABLED: from epiuclid.api import router as iuclid_router diff --git a/epapi/v1/schemas.py b/epapi/v1/schemas.py index 7d1d9036..52794f40 100644 --- a/epapi/v1/schemas.py +++ b/epapi/v1/schemas.py @@ -1,7 +1,10 @@ -from ninja import FilterSchema, FilterLookup, Schema +from datetime import datetime from typing import Annotated, Optional, List, Dict, Any from uuid import UUID +from django.urls import reverse +from ninja import Field, FilterSchema, FilterLookup, Schema + # Filter schema for query parameters class ReviewStatusFilter(FilterSchema): @@ -133,3 +136,23 @@ class GroupOutSchema(Schema): url: str = "" name: str description: str + + +class SimpleUserOutSchema(Schema): + uuid: UUID + url: str + name: str = Field(alias="username") + + +class JobLogOutSchema(Schema): + user: SimpleUserOutSchema + id: UUID = Field(alias="task_id") + url: str + name: str = Field(alias="job_name") + created: datetime = Field(alias="created") + status: str = Field(alias="status") + done: Optional[datetime] = Field(None, alias="done_at") + + @staticmethod + def resolve_url(obj): + return reverse("job detail", kwargs={"job_uuid": obj.task_id}) diff --git a/epdb/views.py b/epdb/views.py index 50385576..169fd86d 100644 --- a/epdb/views.py +++ b/epdb/views.py @@ -3080,12 +3080,21 @@ def jobs(request): {"Home": s.SERVER_URL}, {"Jobs": s.SERVER_URL + "/jobs"}, ] - if current_user.is_superuser: - context["jobs"] = JobLog.objects.all().order_by("-created") - else: - context["jobs"] = JobLog.objects.filter(user=current_user).order_by("-created") + # if current_user.is_superuser: + # context["jobs"] = JobLog.objects.all().order_by("-created") + # else: + # context["jobs"] = JobLog.objects.filter(user=current_user).order_by("-created") - return render(request, "collections/joblog.html", context) + # Context for paginated template + context["entity_type"] = "joblog" + context["api_endpoint"] = f"{s.SERVER_PATH}/api/v1/joblog/" + context["per_page"] = s.API_PAGINATION_DEFAULT_PAGE_SIZE + context["list_title"] = "joblog" + context["list_mode"] = "combined" + + return render(request, "collections/joblog_paginated.html", context) + + # return render(request, "collections/joblog.html", context) elif request.method == "POST": job_name = request.POST.get("job-name") diff --git a/templates/collections/_joblog_paginated_list_partial.html b/templates/collections/_joblog_paginated_list_partial.html new file mode 100644 index 00000000..de2f582f --- /dev/null +++ b/templates/collections/_joblog_paginated_list_partial.html @@ -0,0 +1,102 @@ +{# Partial for paginated list content - expects to be inside a remotePaginatedList Alpine.js context #} +{# Variables: empty_text (string), show_review_badge (bool), always_show_badge (bool) #} +{% load envipytags %} +{# Loading state #} +
No {{ empty_text|default:"items" }} found.
+List of Jobs submitted.
+{% endblock description %} diff --git a/templates/collections/paginated_base.html b/templates/collections/paginated_base.html index 9e328374..7626f1db 100644 --- a/templates/collections/paginated_base.html +++ b/templates/collections/paginated_base.html @@ -37,7 +37,11 @@ perPage: {{ per_page|default:50 }} })" > - {% include "collections/_paginated_list_partial.html" with empty_text=list_title|default:"items" show_review_badge=True %} + {% if entity_type == 'joblog' %} + {% include "collections/_joblog_paginated_list_partial.html" with empty_text=list_title|default:"items" show_review_badge=True %} + {% else %} + {% include "collections/_paginated_list_partial.html" with empty_text=list_title|default:"items" show_review_badge=True %} + {% endif %} {% else %} {# ===== TABBED MODE: Reviewed/Unreviewed tabs (default) ===== #} diff --git a/uv.lock b/uv.lock index ba790259..634ae6af 100644 --- a/uv.lock +++ b/uv.lock @@ -894,7 +894,7 @@ provides-extras = ["ms-login", "dev", "pepper-plugin"] [[package]] name = "envipy-additional-information" version = "0.4.2" -source = { git = "ssh://git@git.envipath.com/enviPath/enviPy-additional-information.git?branch=develop#676dae1c5678539beac637b87e49b9dadfdfd85a" } +source = { git = "ssh://git@git.envipath.com/enviPath/enviPy-additional-information.git?branch=develop#79285f522e0a6ed3f2e805dfeeb6b9fa5cea4323" } dependencies = [ { name = "pydantic" }, ]