Séparation des vues modération

This commit is contained in:
SebF 2025-03-25 17:08:41 +01:00
parent 76610993ba
commit 69ced85e1e
4 changed files with 221 additions and 194 deletions

View File

@ -26,7 +26,11 @@ from .views import (
mentions_legales,
moderation_rules,
thank_you,
# tags
# Moderation
EventModerateView,
moderate_event_next,
moderate_from_date,
# Tags
view_tag,
view_tag_past,
TagUpdateView,
@ -72,8 +76,6 @@ from .views import (
run_all_rimports,
EventDetailView,
EventUpdateView,
EventModerateView,
moderate_event_next,
RecurrentImportCreateView,
RecurrentImportDeleteView,
RecurrentImportUpdateView,
@ -92,7 +94,6 @@ from .views import (
delete_cm_spam,
PlaceCreateView,
PlaceFromEventCreateView,
moderate_from_date,
update_from_source,
change_status_event,
EventDeleteView,
@ -149,6 +150,38 @@ urlpatterns = [
path("mentions-legales", mentions_legales, name="mentions_legales"),
path("regles-de-moderation", moderation_rules, name="moderation_rules"),
path("merci", thank_you, name="thank_you"),
# Moderation
path("moderate", EventModerateView.as_view(), name="moderate"),
path(
"event/<int:pk>/moderate",
EventModerateView.as_view(),
name="moderate_event",
),
path(
"event/<int:pk>/moderate-force",
EventModerateView.as_view(),
name="moderate_event_force",
),
path(
"event/<int:pk>/moderate/after/<int:pred>",
EventModerateView.as_view(),
name="moderate_event_step",
),
path(
"event/<int:pk>/moderate/back/<int:pred>",
EventModerateView.as_view(),
name="moderate_event_backstep",
),
path(
"event/<int:pk>/moderate-next",
moderate_event_next,
name="moderate_event_next",
),
path(
"moderate/<int:y>/<int:m>/<int:d>",
moderate_from_date,
name="moderate_from_date",
),
# TODO pas encore trié
path("", home, name="home"),
path("cat:<cat>/", home, name="home_category"),
@ -218,37 +251,6 @@ urlpatterns = [
path(
"event/<int:pk>/edit-force", EventUpdateView.as_view(), name="edit_event_force"
),
path(
"event/<int:pk>/moderate",
EventModerateView.as_view(),
name="moderate_event",
),
path(
"event/<int:pk>/moderate-force",
EventModerateView.as_view(),
name="moderate_event_force",
),
path(
"event/<int:pk>/moderate/after/<int:pred>",
EventModerateView.as_view(),
name="moderate_event_step",
),
path(
"event/<int:pk>/moderate/back/<int:pred>",
EventModerateView.as_view(),
name="moderate_event_backstep",
),
path(
"event/<int:pk>/moderate-next",
moderate_event_next,
name="moderate_event_next",
),
path("moderate", EventModerateView.as_view(), name="moderate"),
path(
"moderate/<int:y>/<int:m>/<int:d>",
moderate_from_date,
name="moderate_from_date",
),
path(
"event/<int:pk>/simple-clone/edit",
EventUpdateView.as_view(),

View File

@ -1,4 +1,5 @@
from .oldviews import *
from .errors import *
from .general_pages_views import *
from .moderation_views import *
from .tag_views import *

View File

@ -0,0 +1,168 @@
from datetime import date
from django.contrib.auth.decorators import login_required, permission_required
from django.contrib.auth.mixins import PermissionRequiredMixin, LoginRequiredMixin
from django.contrib.messages.views import SuccessMessageMixin
from django.http import Http404, HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse_lazy
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
from django.views.generic import UpdateView
from django.db.models import Q, F
from django.utils.timezone import datetime
from ..forms import EventModerateForm
from ..models import Event
class EventModerateView(
SuccessMessageMixin,
PermissionRequiredMixin,
LoginRequiredMixin,
UpdateView,
):
model = Event
permission_required = "agenda_culturel.change_event"
template_name = "agenda_culturel/event_form_moderate.html"
form_class = EventModerateForm
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs["is_moderation_expert"] = (
self.request.user.userprofile.is_moderation_expert
)
return kwargs
def get_success_message(self, cleaned_data):
txt = (
_(" A message has been sent to the person who proposed the event.")
if hasattr(self, "with_msg") and self.with_msg
else ""
)
return mark_safe(
_('The event <a href="{}">{}</a> has been moderated with success.').format(
self.object.get_absolute_url(), self.object.title
)
+ txt
)
def is_moderate_next(self):
return "after" in self.request.path.split("/")
def is_moderate_back(self):
return "back" in self.request.path.split("/")
def is_moderate_force(self):
return "moderate-force" in self.request.path.split("/")
def is_starting_moderation(self):
return "pk" not in self.kwargs
def is_moderation_from_date(self):
return "m" in self.kwargs and "y" in self.kwargs and "d" in self.kwargs
def get_next_event(start_day, start_time, opk):
# select non moderated events
qs = Event.objects.filter(moderated_date__isnull=True)
# select events after the current one
if start_time:
qs = qs.filter(
Q(start_day__gt=start_day)
| (
Q(start_day=start_day)
& (Q(start_time__isnull=True) | Q(start_time__gt=start_time))
)
)
else:
qs = qs.filter(Q(start_day__gte=start_day) & ~Q(pk=opk))
# get only possibly representative events
qs = qs.filter(
Q(other_versions__isnull=True)
| Q(other_versions__representative=F("pk"))
| Q(other_versions__representative__isnull=True)
)
# remove trash events
qs = qs.filter(~Q(status=Event.STATUS.TRASH))
# sort by datetime
qs = qs.order_by("start_day", "start_time")
return qs.first()
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if self.is_moderate_next():
context["pred"] = self.kwargs["pred"]
return context
def get_object(self, queryset=None):
if self.is_starting_moderation():
now = datetime.now()
event = EventModerateView.get_next_event(now.date(), now.time(), None)
else:
event = super().get_object(queryset)
if event.status == Event.STATUS.DRAFT:
event.status = Event.STATUS.PUBLISHED
if self.is_moderate_back():
pred = Event.objects.filter(pk=self.kwargs["pred"]).first()
pred.free_modification_lock(self.request.user)
if self.is_moderate_force():
event.free_modification_lock(self.request.user, False)
return event
def post(self, request, *args, **kwargs):
try:
return super().post(request, args, kwargs)
except Http404:
return HttpResponseRedirect(
reverse_lazy("error_next_event", args=[self.object.pk])
)
def form_valid(self, form):
form.instance.set_no_modification_date_changed()
form.instance.set_in_moderation_process()
form.instance.set_processing_user(self.request.user)
self.with_msg = form.instance.notify_if_required(self.request)
return super().form_valid(form)
def get_success_url(self):
if "save_and_next" in self.request.POST:
return reverse_lazy("moderate_event_next", args=[self.object.pk])
elif "save_and_edit_local" in self.request.POST:
return reverse_lazy("edit_event", args=[self.object.get_local_version().pk])
else:
return self.object.get_absolute_url()
@login_required(login_url="/accounts/login/")
@permission_required("agenda_culturel.change_event")
def moderate_event_next(request, pk):
# current event
obj = Event.objects.filter(pk=pk).first()
# free lock
obj.free_modification_lock(request.user)
start_day = obj.start_day
start_time = obj.start_time
next_obj = EventModerateView.get_next_event(start_day, start_time, pk)
if next_obj is None:
return render(
request,
"agenda_culturel/event_next_error_message.html",
{"pk": pk, "object": obj},
)
else:
return HttpResponseRedirect(
reverse_lazy("moderate_event_step", args=[next_obj.pk, obj.pk])
)
@login_required(login_url="/accounts/login/")
@permission_required("agenda_culturel.change_event")
def moderate_from_date(request, y, m, d):
d = date(y, m, d)
obj = EventModerateView.get_next_event(d, None, None)
return HttpResponseRedirect(reverse_lazy("moderate_event", args=[obj.pk]))

View File

@ -14,10 +14,13 @@ from django.contrib.auth.mixins import (
from django.contrib.messages.views import SuccessMessageMixin
from django.core.cache import cache
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
from django.db.models import Aggregate, FloatField
from django.db.models import Avg, Max, Min
from django.db.models import Count, F, Func, OuterRef, Q, Subquery
from django.db.models.aggregates import StdDev
from django.db.models.functions import ExtractDay
from django.db.models.functions import TruncMonth
from django.http import (
Http404,
HttpResponse,
HttpResponseForbidden,
HttpResponseRedirect,
@ -37,10 +40,6 @@ from django.views.generic.edit import (
UpdateView,
)
from honeypot.decorators import check_honeypot
from django.db.models.aggregates import StdDev
from django.db.models import Avg, Max, Min
from django.db.models import Aggregate, FloatField
from django.db.models.functions import ExtractDay
from ..calendar import CalendarDay, CalendarList, CalendarMonth, CalendarWeek
from ..celery import app as celery_app
@ -70,7 +69,6 @@ from ..forms import (
EventAddPlaceForm,
EventForm,
EventFormWithContact,
EventModerateForm,
FixDuplicates,
MergeDuplicates,
MessageEventForm,
@ -159,6 +157,17 @@ class PaginatorFilter(Paginator):
return page
#
#
# Useful for translation
to_be_translated = [
_("Recurrent import name"),
_("Add another"),
_("Browse..."),
_("No file selected."),
]
def home(request, cat=None):
return week_view(request, home=True, cat=cat)
@ -475,159 +484,6 @@ class EventUpdateView(
return self.object.get_absolute_url()
class EventModerateView(
SuccessMessageMixin,
PermissionRequiredMixin,
LoginRequiredMixin,
UpdateView,
):
model = Event
permission_required = "agenda_culturel.change_event"
template_name = "agenda_culturel/event_form_moderate.html"
form_class = EventModerateForm
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs["is_moderation_expert"] = (
self.request.user.userprofile.is_moderation_expert
)
return kwargs
def get_success_message(self, cleaned_data):
txt = (
_(" A message has been sent to the person who proposed the event.")
if hasattr(self, "with_msg") and self.with_msg
else ""
)
return mark_safe(
_('The event <a href="{}">{}</a> has been moderated with success.').format(
self.object.get_absolute_url(), self.object.title
)
+ txt
)
def is_moderate_next(self):
return "after" in self.request.path.split("/")
def is_moderate_back(self):
return "back" in self.request.path.split("/")
def is_moderate_force(self):
return "moderate-force" in self.request.path.split("/")
def is_starting_moderation(self):
return "pk" not in self.kwargs
def is_moderation_from_date(self):
return "m" in self.kwargs and "y" in self.kwargs and "d" in self.kwargs
def get_next_event(start_day, start_time, opk):
# select non moderated events
qs = Event.objects.filter(moderated_date__isnull=True)
# select events after the current one
if start_time:
qs = qs.filter(
Q(start_day__gt=start_day)
| (
Q(start_day=start_day)
& (Q(start_time__isnull=True) | Q(start_time__gt=start_time))
)
)
else:
qs = qs.filter(Q(start_day__gte=start_day) & ~Q(pk=opk))
# get only possibly representative events
qs = qs.filter(
Q(other_versions__isnull=True)
| Q(other_versions__representative=F("pk"))
| Q(other_versions__representative__isnull=True)
)
# remove trash events
qs = qs.filter(~Q(status=Event.STATUS.TRASH))
# sort by datetime
qs = qs.order_by("start_day", "start_time")
return qs.first()
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if self.is_moderate_next():
context["pred"] = self.kwargs["pred"]
return context
def get_object(self, queryset=None):
if self.is_starting_moderation():
now = datetime.now()
event = EventModerateView.get_next_event(now.date(), now.time(), None)
else:
event = super().get_object(queryset)
if event.status == Event.STATUS.DRAFT:
event.status = Event.STATUS.PUBLISHED
if self.is_moderate_back():
pred = Event.objects.filter(pk=self.kwargs["pred"]).first()
pred.free_modification_lock(self.request.user)
if self.is_moderate_force():
event.free_modification_lock(self.request.user, False)
return event
def post(self, request, *args, **kwargs):
try:
return super().post(request, args, kwargs)
except Http404:
return HttpResponseRedirect(
reverse_lazy("error_next_event", args=[self.object.pk])
)
def form_valid(self, form):
form.instance.set_no_modification_date_changed()
form.instance.set_in_moderation_process()
form.instance.set_processing_user(self.request.user)
self.with_msg = form.instance.notify_if_required(self.request)
return super().form_valid(form)
def get_success_url(self):
if "save_and_next" in self.request.POST:
return reverse_lazy("moderate_event_next", args=[self.object.pk])
elif "save_and_edit_local" in self.request.POST:
return reverse_lazy("edit_event", args=[self.object.get_local_version().pk])
else:
return self.object.get_absolute_url()
@login_required(login_url="/accounts/login/")
@permission_required("agenda_culturel.change_event")
def moderate_event_next(request, pk):
# current event
obj = Event.objects.filter(pk=pk).first()
# free lock
obj.free_modification_lock(request.user)
start_day = obj.start_day
start_time = obj.start_time
next_obj = EventModerateView.get_next_event(start_day, start_time, pk)
if next_obj is None:
return render(
request,
"agenda_culturel/event_next_error_message.html",
{"pk": pk, "object": obj},
)
else:
return HttpResponseRedirect(
reverse_lazy("moderate_event_step", args=[next_obj.pk, obj.pk])
)
@login_required(login_url="/accounts/login/")
@permission_required("agenda_culturel.change_event")
def moderate_from_date(request, y, m, d):
d = date(y, m, d)
obj = EventModerateView.get_next_event(d, None, None)
return HttpResponseRedirect(reverse_lazy("moderate_event", args=[obj.pk]))
class EventDeleteView(
SuccessMessageMixin,
PermissionRequiredMixin,