.
This commit is contained in:
@@ -2,7 +2,14 @@
|
|||||||
<div id="leave-list">
|
<div id="leave-list">
|
||||||
<ul>
|
<ul>
|
||||||
{% for l in leaves %}
|
{% 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 %}
|
{% empty %}
|
||||||
<li>No leave recorded</li>
|
<li>No leave recorded</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ urlpatterns = [
|
|||||||
path("worker/<int:worker_id>/leaves.json", views.leaves_json, name="worker_leaves_json"),
|
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/", views.request_leave, name="request_leave"),
|
||||||
path("leave/request/token/<uuid:token>/", views.request_leave, name="request_leave_token"),
|
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("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>/", 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"),
|
path("run/<int:run_id>/export/html/", views.rota_run_export_html, name="rota_run_export_html"),
|
||||||
|
|||||||
@@ -512,7 +512,7 @@ def request_leave(request, token=None):
|
|||||||
# Render updated leave list and return OOB swaps: update leave-list and clear modal.
|
# Render updated leave list and return OOB swaps: update leave-list and clear modal.
|
||||||
leave_list_html = render_to_string(
|
leave_list_html = render_to_string(
|
||||||
"rota/partials/leave_list.html",
|
"rota/partials/leave_list.html",
|
||||||
{"leaves": worker.leaves.all()},
|
{"leaves": worker.leaves.all(), "token": token},
|
||||||
request=request,
|
request=request,
|
||||||
)
|
)
|
||||||
resp = (
|
resp = (
|
||||||
@@ -563,7 +563,7 @@ def request_leave(request, token=None):
|
|||||||
)
|
)
|
||||||
return HttpResponse(modal_html)
|
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):
|
def rota_options(request, rota_id):
|
||||||
@@ -952,6 +952,51 @@ def leaves_json(request, worker_id):
|
|||||||
return JsonResponse({'leaves': data})
|
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
|
@require_POST
|
||||||
def rota_run_export_regenerate(request, run_id):
|
def rota_run_export_regenerate(request, run_id):
|
||||||
"""Regenerate the HTML export for a completed run and persist it on the RotaRun.
|
"""Regenerate the HTML export for a completed run and persist it on the RotaRun.
|
||||||
|
|||||||
Reference in New Issue
Block a user