From 0cf11c63486142d846fe013cae526a60a9167002 Mon Sep 17 00:00:00 2001 From: Ehouarn Date: Thu, 8 May 2025 18:34:23 +0200 Subject: [PATCH 1/5] ok --- apps/activity/models.py | 2 +- .../templates/activity/activity_detail.html | 18 ++++++++++++++++++ .../activity/includes/activity_info.html | 5 ++++- apps/activity/urls.py | 1 + apps/activity/views.py | 15 +++++++++++++++ 5 files changed, 39 insertions(+), 2 deletions(-) diff --git a/apps/activity/models.py b/apps/activity/models.py index c7c92e8d..4e313a57 100644 --- a/apps/activity/models.py +++ b/apps/activity/models.py @@ -234,7 +234,7 @@ class Guest(models.Model): """ activity = models.ForeignKey( Activity, - on_delete=models.PROTECT, + on_delete=models.CASCADE, related_name='+', ) diff --git a/apps/activity/templates/activity/activity_detail.html b/apps/activity/templates/activity/activity_detail.html index a94d1e37..077acb29 100644 --- a/apps/activity/templates/activity/activity_detail.html +++ b/apps/activity/templates/activity/activity_detail.html @@ -95,5 +95,23 @@ SPDX-License-Identifier: GPL-3.0-or-later errMsg(xhr.responseJSON); }); }); + $("#delete_activity").click(function () { + if (!confirm("{% trans 'Are you sure you want to delete this activity?' %}")) { + return; + } + + $.ajax({ + url: "/api/activity/activity/{{ activity.pk }}/", + type: "DELETE", + headers: { + "X-CSRFTOKEN": CSRF_TOKEN + } + }).done(function () { + addMsg("{% trans 'Activity deleted' %}", "success"); + window.location.href = "/activity/"; // Redirige vers la liste des activités (à adapter) + }).fail(function (xhr) { + errMsg(xhr.responseJSON); + }); + }); {% endblock %} diff --git a/apps/activity/templates/activity/includes/activity_info.html b/apps/activity/templates/activity/includes/activity_info.html index a16ad33b..f9ea634b 100644 --- a/apps/activity/templates/activity/includes/activity_info.html +++ b/apps/activity/templates/activity/includes/activity_info.html @@ -70,7 +70,10 @@ SPDX-License-Identifier: GPL-3.0-or-later {% if ".change_"|has_perm:activity %} {% trans "edit"|capfirst %} {% endif %} - {% if activity.activity_type.can_invite and not activity_started %} + {% if not activity.valid and ".delete_"|has_perm:activity %} + {% trans "delete"|capfirst %} + {% endif %} + {% if activity.activity_type.can_invite and not activity_started and activity.valid %} {% trans "Invite" %} {% endif %} {% endif %} diff --git a/apps/activity/urls.py b/apps/activity/urls.py index 962be72a..63a3a169 100644 --- a/apps/activity/urls.py +++ b/apps/activity/urls.py @@ -15,4 +15,5 @@ urlpatterns = [ path('/update/', views.ActivityUpdateView.as_view(), name='activity_update'), path('new/', views.ActivityCreateView.as_view(), name='activity_create'), path('calendar.ics', views.CalendarView.as_view(), name='calendar_ics'), + path('/delete', views.ActivityDeleteView.as_view(), name='delete_activity'), ] diff --git a/apps/activity/views.py b/apps/activity/views.py index 80bc1506..02a98254 100644 --- a/apps/activity/views.py +++ b/apps/activity/views.py @@ -152,6 +152,21 @@ class ActivityUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): def get_success_url(self, **kwargs): return reverse_lazy('activity:activity_detail', kwargs={"pk": self.kwargs["pk"]}) +class ActivityDeleteView(View): + def delete(self, request, pk): + try: + activity = Activity.objects.get(pk=pk) + activity.delete() + return JsonResponse({"message": "Activity deleted"}) + except ProtectedError as e: + return JsonResponse({"error": "Cannot delete this activity because it is still referenced by guests."}, status=400) + except Activity.DoesNotExist: + return JsonResponse({"error": "Activity not found"}, status=404) + + def dispatch(self, *args, **kwargs): + # Optionnel : restreindre à utilisateur connecté ou permissions + return super().dispatch(*args, **kwargs) + class ActivityInviteView(ProtectQuerysetMixin, ProtectedCreateView): """ From 71ef3aedd8f1c46e5ec3a4b42c5bcd6d7ccfe53e Mon Sep 17 00:00:00 2001 From: ehouarn Date: Thu, 8 May 2025 19:09:22 +0200 Subject: [PATCH 2/5] Update views.py --- apps/activity/views.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/activity/views.py b/apps/activity/views.py index 02a98254..bebc7899 100644 --- a/apps/activity/views.py +++ b/apps/activity/views.py @@ -158,8 +158,6 @@ class ActivityDeleteView(View): activity = Activity.objects.get(pk=pk) activity.delete() return JsonResponse({"message": "Activity deleted"}) - except ProtectedError as e: - return JsonResponse({"error": "Cannot delete this activity because it is still referenced by guests."}, status=400) except Activity.DoesNotExist: return JsonResponse({"error": "Activity not found"}, status=404) From 3065eacc96431eadc01098cf9253bae98bfbf736 Mon Sep 17 00:00:00 2001 From: ehouarn Date: Thu, 8 May 2025 19:38:40 +0200 Subject: [PATCH 3/5] Update views.py --- apps/activity/views.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/apps/activity/views.py b/apps/activity/views.py index bebc7899..08e53077 100644 --- a/apps/activity/views.py +++ b/apps/activity/views.py @@ -9,7 +9,7 @@ from django.contrib.contenttypes.models import ContentType from django.core.exceptions import PermissionDenied from django.db import transaction from django.db.models import F, Q -from django.http import HttpResponse +from django.http import HttpResponse,JsonResponse from django.urls import reverse_lazy from django.utils import timezone from django.utils.decorators import method_decorator @@ -153,6 +153,9 @@ class ActivityUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): return reverse_lazy('activity:activity_detail', kwargs={"pk": self.kwargs["pk"]}) class ActivityDeleteView(View): + """ + Deletes an Activity + """ def delete(self, request, pk): try: activity = Activity.objects.get(pk=pk) @@ -162,7 +165,18 @@ class ActivityDeleteView(View): return JsonResponse({"error": "Activity not found"}, status=404) def dispatch(self, *args, **kwargs): - # Optionnel : restreindre à utilisateur connecté ou permissions + """ + Don't display the delete button if the user has no right to delete. + """ + if not self.request.user.is_authenticated: + return self.handle_no_permission() + + activity = Activity.objects.get(pk=self.kwargs["pk"]) + if not PermissionBackend.check_perm(self.request, "activity.delete_activity", activity): + raise PermissionDenied(_("You are not allowed to delete this activity.")) + + if activity.valid: + raise PermissionDenied(_("This activity is valid.")) return super().dispatch(*args, **kwargs) From 4afafceba1ecd616b1dc61c0ef515ec2a2ee86a3 Mon Sep 17 00:00:00 2001 From: ehouarn Date: Thu, 8 May 2025 19:39:59 +0200 Subject: [PATCH 4/5] Update activity_detail.html --- apps/activity/templates/activity/activity_detail.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/activity/templates/activity/activity_detail.html b/apps/activity/templates/activity/activity_detail.html index 077acb29..1a8d01ee 100644 --- a/apps/activity/templates/activity/activity_detail.html +++ b/apps/activity/templates/activity/activity_detail.html @@ -108,7 +108,7 @@ SPDX-License-Identifier: GPL-3.0-or-later } }).done(function () { addMsg("{% trans 'Activity deleted' %}", "success"); - window.location.href = "/activity/"; // Redirige vers la liste des activités (à adapter) + window.location.href = "/activity/"; // Redirige vers la liste des activités }).fail(function (xhr) { errMsg(xhr.responseJSON); }); From cdd81c144438967d4939435d67336932ee01f19a Mon Sep 17 00:00:00 2001 From: ehouarn Date: Thu, 8 May 2025 20:14:24 +0200 Subject: [PATCH 5/5] Update views.py --- apps/activity/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/activity/views.py b/apps/activity/views.py index 08e53077..3081c45b 100644 --- a/apps/activity/views.py +++ b/apps/activity/views.py @@ -9,7 +9,7 @@ from django.contrib.contenttypes.models import ContentType from django.core.exceptions import PermissionDenied from django.db import transaction from django.db.models import F, Q -from django.http import HttpResponse,JsonResponse +from django.http import HttpResponse, JsonResponse from django.urls import reverse_lazy from django.utils import timezone from django.utils.decorators import method_decorator @@ -152,6 +152,7 @@ class ActivityUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): def get_success_url(self, **kwargs): return reverse_lazy('activity:activity_detail', kwargs={"pk": self.kwargs["pk"]}) + class ActivityDeleteView(View): """ Deletes an Activity