From c5850eb1b2ee50c4f27b7ca035e1fef2d2c60bd6 Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 15 Dec 2025 21:25:21 +0000 Subject: [PATCH] Add functionality to delete all leave requests for a worker with permission checks --- .../templates/rota/leave_request.html | 9 +++- .../templates/rota/partials/leave_list.html | 5 +- .../templates/rota/worker_detail.html | 14 ++++++ djangorota/rota/urls.py | 1 + djangorota/rota/views.py | 46 +++++++++++++++++++ 5 files changed, 73 insertions(+), 2 deletions(-) diff --git a/djangorota/djangorota/templates/rota/leave_request.html b/djangorota/djangorota/templates/rota/leave_request.html index dbbfd3f..769ae86 100644 --- a/djangorota/djangorota/templates/rota/leave_request.html +++ b/djangorota/djangorota/templates/rota/leave_request.html @@ -14,7 +14,14 @@

Update your settings

{% endif %} - + {# Navigation back to the first rota this worker belongs to (if available) #} + {% if worker %} + {% with back_rota=worker.rotas.all.0 %} + {% if back_rota %} +

← Back to rota: {{ back_rota.name }}

+ {% endif %} + {% endwith %} + {% endif %}
{% csrf_token %} {% if token %} diff --git a/djangorota/djangorota/templates/rota/partials/leave_list.html b/djangorota/djangorota/templates/rota/partials/leave_list.html index fcf88c0..f6b9076 100644 --- a/djangorota/djangorota/templates/rota/partials/leave_list.html +++ b/djangorota/djangorota/templates/rota/partials/leave_list.html @@ -7,11 +7,14 @@ - + {% comment %}Only show delete control when the current request is allowed to delete:{% endcomment %} + {% if request.user.is_staff or request.user.is_authenticated and request.user.email and request.user.email == l.worker.email or token %} + {% csrf_token %} {% if token %}{% endif %}
+ {% endif %} {% empty %}
  • No leave recorded
  • diff --git a/djangorota/djangorota/templates/rota/worker_detail.html b/djangorota/djangorota/templates/rota/worker_detail.html index dbc98dd..1123ff1 100644 --- a/djangorota/djangorota/templates/rota/worker_detail.html +++ b/djangorota/djangorota/templates/rota/worker_detail.html @@ -18,6 +18,13 @@

    {{ worker.name }}

    {{ worker.email }} - {{ worker.site }}

    + {# Navigation: back to an assigned rota (show first assigned rota if any) #} + {% with back_rota=worker.rotas.all.0 %} + {% if back_rota %} +

    ← Back to rota: {{ back_rota.name }}

    + {% endif %} + {% endwith %} +

    Request leave

    @@ -33,6 +40,13 @@

    Existing leave

    + {# Delete-all control: only show to staff or the worker themselves #} + {% if request.user.is_staff or request.user.is_authenticated and request.user.email and request.user.email == worker.email %} + + {% csrf_token %} + + + {% endif %} {% include 'rota/partials/leave_list.html' with leaves=worker.leaves.all %}
    diff --git a/djangorota/rota/urls.py b/djangorota/rota/urls.py index 5284e10..e6fec72 100644 --- a/djangorota/rota/urls.py +++ b/djangorota/rota/urls.py @@ -21,6 +21,7 @@ urlpatterns = [ path("leave/request/token//", views.request_leave, name="request_leave_token"), path("worker/settings/token//", views.worker_settings_token, name="worker_settings_token"), path("leave//delete/", views.leave_delete, name="leave_delete"), + path("worker//leaves/delete_all/", views.leave_delete_all, name="leave_delete_all"), path("worker//regenerate_token/", views.regenerate_worker_token, name="regenerate_worker_token"), path("run//", views.rota_run_detail, name="rota_run_detail"), path("run//export/html/", views.rota_run_export_html, name="rota_run_export_html"), diff --git a/djangorota/rota/views.py b/djangorota/rota/views.py index 3e42319..cb22d91 100644 --- a/djangorota/rota/views.py +++ b/djangorota/rota/views.py @@ -1062,6 +1062,52 @@ def leave_delete(request, leave_id): return response +@require_POST +def leave_delete_all(request, worker_id): + """Delete all Leave records for a worker. Permissions same as `leave_delete`. + + Returns an OOB swap updating `#leave-list` and triggers `leaveUpdated`. + """ + worker = get_object_or_404(Worker, pk=worker_id) + + # permission checks (same as leave_delete) + allowed = False + token = request.POST.get('token') or request.GET.get('token') + try: + if request.user and request.user.is_authenticated and request.user.is_staff: + allowed = True + elif request.user and request.user.is_authenticated and getattr(request.user, 'email', None) and request.user.email == (worker.email or ''): + allowed = True + elif token: + try: + import uuid + + token_uuid = uuid.UUID(token) + if worker.request_token == token_uuid: + allowed = True + except Exception: + allowed = False + except Exception: + allowed = False + + if not allowed: + return HttpResponseBadRequest('Permission denied') + + # delete all leaves for this worker + worker.leaves.all().delete() + + # render updated leave list for the worker + leave_list_html = render_to_string( + "rota/partials/leave_list.html", + {"leaves": worker.leaves.all(), "token": token}, + request=request, + ) + resp = f'
    {leave_list_html}
    ' + response = HttpResponse(resp) + response["HX-Trigger"] = "leaveUpdated" + return response + + @require_POST def rota_run_export_regenerate(request, run_id): """Regenerate the HTML export for a completed run and persist it on the RotaRun.