This commit is contained in:
Ross
2025-12-14 17:13:19 +00:00
parent 2889825734
commit c43ff7fc73
3 changed files with 56 additions and 3 deletions
@@ -2,7 +2,14 @@
<div id="leave-list">
<ul>
{% for l in leaves %}
<li data-start="{{ l.start_date|date:'Y-m-d' }}" data-end="{{ l.end_date|date:'Y-m-d' }}">{{ l.start_date }} → {{ l.end_date }}{% if l.reason %} ({{ l.reason }}){% endif %}</li>
<li data-start="{{ l.start_date|date:'Y-m-d' }}" data-end="{{ l.end_date|date:'Y-m-d' }}">
<span class="leave-range">{{ l.start_date }} → {{ l.end_date }}</span>{% if l.reason %} <em>({{ l.reason }})</em>{% endif %}
<form method="post" hx-post="{% url 'rota:leave_delete' l.id %}" hx-target="#leave-list" hx-swap="outerHTML" style="display:inline;margin-left:0.5rem">
{% csrf_token %}
{% if token %}<input type="hidden" name="token" value="{{ token }}">{% endif %}
<button class="button is-small is-danger" type="submit" onclick="return confirm('Delete this leave request?');">Delete</button>
</form>
</li>
{% empty %}
<li>No leave recorded</li>
{% endfor %}
+1
View File
@@ -19,6 +19,7 @@ urlpatterns = [
path("worker/<int:worker_id>/leaves.json", views.leaves_json, name="worker_leaves_json"),
path("leave/request/", views.request_leave, name="request_leave"),
path("leave/request/token/<uuid:token>/", views.request_leave, name="request_leave_token"),
path("leave/<int:leave_id>/delete/", views.leave_delete, name="leave_delete"),
path("worker/<int:worker_id>/regenerate_token/", views.regenerate_worker_token, name="regenerate_worker_token"),
path("run/<int:run_id>/", views.rota_run_detail, name="rota_run_detail"),
path("run/<int:run_id>/export/html/", views.rota_run_export_html, name="rota_run_export_html"),
+47 -2
View File
@@ -512,7 +512,7 @@ def request_leave(request, token=None):
# Render updated leave list and return OOB swaps: update leave-list and clear modal.
leave_list_html = render_to_string(
"rota/partials/leave_list.html",
{"leaves": worker.leaves.all()},
{"leaves": worker.leaves.all(), "token": token},
request=request,
)
resp = (
@@ -563,7 +563,7 @@ def request_leave(request, token=None):
)
return HttpResponse(modal_html)
return render(request, "rota/leave_request.html", {"form": form, "worker": worker})
return render(request, "rota/leave_request.html", {"form": form, "worker": worker, "token": token})
def rota_options(request, rota_id):
@@ -952,6 +952,51 @@ def leaves_json(request, worker_id):
return JsonResponse({'leaves': data})
@require_POST
def leave_delete(request, leave_id):
"""Delete a Leave record. Allowed if the requester is staff, or if a valid token matches the worker, or the authenticated user's email matches the worker email."""
from .models import Leave
leave = get_object_or_404(Leave, pk=leave_id)
worker = leave.worker
# permission checks
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')
# perform delete
leave.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'<div id="leave-list" hx-swap-oob="true">{leave_list_html}</div>'
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.