Ajout d'un outil de modération pour ajouter modifier quelques éléments simples d'un événement sans le modifiier

This commit is contained in:
Jean-Marie Favreau 2024-11-16 20:11:10 +01:00
parent e3c14437ac
commit 11d5cf9aa4
9 changed files with 178 additions and 3 deletions

View File

@ -182,6 +182,57 @@ class EventForm(ModelForm):
self.cleaned_data['local_image'] = File(name=basename, file=open(old, "rb")) self.cleaned_data['local_image'] = File(name=basename, file=open(old, "rb"))
class MultipleChoiceFieldAcceptAll(MultipleChoiceField):
def validate(self, value):
pass
class EventModerateForm(ModelForm):
tags = MultipleChoiceField(
label=_("Tags"),
help_text=_('Select tags from existing ones.'),
required=False
)
new_tags = MultipleChoiceFieldAcceptAll(
label=_("New tags"),
help_text=_('Create new labels (sparingly).'),
widget=DynamicArrayWidget(),
required=False
)
class Meta:
model = Event
fields = [
"status",
"category",
"exact_location",
"tags"
]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['category'].queryset = self.fields['category'].queryset.order_by('name')
self.fields['category'].empty_label = None
self.fields['category'].initial = Category.get_default_category()
self.fields['tags'].choices = Tag.get_tag_groups(all=True)
def clean_new_tags(self):
return list(set(self.cleaned_data.get("new_tags")))
def clean(self):
super().clean()
if self.cleaned_data['tags'] is None:
self.cleaned_data['tags'] = []
if not self.cleaned_data.get('new_tags') is None:
self.cleaned_data['tags'] += self.cleaned_data.get('new_tags')
self.cleaned_data['tags'] = list(set(self.cleaned_data['tags']))
class BatchImportationForm(Form): class BatchImportationForm(Form):
json = CharField( json = CharField(
@ -270,7 +321,6 @@ class FixDuplicates(Form):
def get_selected_event(self, edup): def get_selected_event(self, edup):
selected = self.get_selected_event_code() selected = self.get_selected_event_code()
logger.warning("selected " + str(selected))
for e in edup.get_duplicated(): for e in edup.get_duplicated():
if e.pk == selected: if e.pk == selected:
return e return e

View File

@ -790,6 +790,12 @@ class Event(models.Model):
def set_no_modification_date_changed(self): def set_no_modification_date_changed(self):
self.no_modification_date_changed = True self.no_modification_date_changed = True
def set_in_moderation_process(self):
self.in_moderation_process = True
def is_in_moderation_process(self):
return hasattr(self, "in_moderation_process")
def update_modification_dates(self): def update_modification_dates(self):
now = timezone.now() now = timezone.now()
if not self.id: if not self.id:
@ -798,6 +804,8 @@ class Event(models.Model):
self.imported_date = now self.imported_date = now
if self.modified_date is None or not self.is_no_modification_date_changed(): if self.modified_date is None or not self.is_no_modification_date_changed():
self.modified_date = now self.modified_date = now
if self.is_in_moderation_process():
self.moderated_date = now
def get_recurrence_at_date(self, year, month, day): def get_recurrence_at_date(self, year, month, day):
dtstart = timezone.make_aware( dtstart = timezone.make_aware(

View File

@ -1399,4 +1399,9 @@ form.messages div, form.moderation-events {
clear: both; clear: both;
float: left; float: left;
} }
}
.moderate-preview .event-body {
max-height: 300px;
overflow-y: auto;
} }

View File

@ -1,6 +1,12 @@
{% load utils_extra %} {% load utils_extra %}
{% if event.moderated_date %}
<a href="{% url 'moderate_event' event.id %}" role="button">Modérer de nouveau {% picto_from_name "check-square" %}</a>
{% else %}
<a href="{% url 'moderate_event' event.id %}" role="button">Modérer {% picto_from_name "check-square" %}</a>
{% endif %}
{% if event.pure_import %} {% if event.pure_import %}
{% with event.get_local_version as local %} {% with event.get_local_version as local %}
{% if local %} {% if local %}

View File

@ -60,7 +60,7 @@ Création d'une copie de {% else %}
{% endif %} {% endif %}
</header> </header>
<div id="container"></div>
{% if form.is_clone_from_url %} {% if form.is_clone_from_url %}
{% url "add_event_details" as urlparam %} {% url "add_event_details" as urlparam %}
{% endif %} {% endif %}

View File

@ -0,0 +1,85 @@
{% extends "agenda_culturel/page.html" %}
{% load static %}
{% block title %}{% block og_title %}Modération de l'événement {{ object.title }} ({{ object.start_day }}){% endblock %}{% endblock %}
{% block ajouter-bouton %}{% block ajouter-menu %}{% endblock %}{% endblock %}
{% block entete_header %}
<script src="{% static 'choicejs/choices.min.js' %}"></script>
<script src="{% url 'jsi18n' %}"></script>
<script src="/static/admin/js/vendor/jquery/jquery.js"></script>
<script src="/static/admin/js/jquery.init.js"></script>
<script src="/static/admin/js/admin/DateTimeShortcuts.js"></script>
<script src="{% static 'recurrence/js/recurrence.js' %}"></script>
<script src="{% static 'recurrence/js/recurrence.js' %}"></script>
<script src="/static/admin/js/admin/RelatedObjectLookups.js"></script>
<script>window.CKEDITOR_BASEPATH = '/static/ckeditor/ckeditor/';</script>
<script src="/static/admin/js/vendor/jquery/jquery.js"></script>
<script src="/static/admin/js/jquery.init.js"></script>
<link href="{% static 'css/django_better_admin_arrayfield.min.css' %}" type="text/css" media="all" rel="stylesheet">
<script src="{% static 'js/django_better_admin_arrayfield.min.js' %}"></script>
<script src="{% static 'js/adjust_datetimes.js' %}"></script>
{% endblock %}
{% block fluid %}{% endblock %}
{% block content %}
{% load static_content_extra %}
<article class="moderate-preview">
<header>
<h1>Modération de l'événement {{ object.title }} ({{ object.start_day }})</h1>
</header>
{% include "agenda_culturel/single-event/event-single-inc.html" with event=event filter=filter %}
<form method="post" enctype="multipart/form-data">{% csrf_token %}
{{ form.media }}
{{ form.as_p }}
<div class="grid buttons">
<a href="{% if request.META.HTTP_REFERER %}{{ request.META.HTTP_REFERER }}{% else %}{{ object.get_absolute_url }}{% endif %}" role="button" class="secondary">Annuler</a>
<input type="submit" value="Enregistrer">
</div>
</form>
{% if object %}
{% include "agenda_culturel/event-info-inc.html" %}
{% endif %}
</article>
<script>
const element = document.querySelector('#id_exact_location');
const choices = new Choices(element);
show_firstgroup = {
choice(classes, choice) {
const i = Choices.defaults.templates.choice.call(this, classes, choice);
i.classList.add("visible");
return i;
},
choiceGroup(classes, group) {
const g = Choices.defaults.templates.choiceGroup.call(this, classes, group);
g.classList.add("visible");
return g;
}
};
const tags = document.querySelector('#id_tags');
const choices_tags = new Choices(tags,
{
placeholderValue: 'Sélectionner les étiquettes à ajouter',
allowHTML: true,
delimiter: ',',
removeItemButton: true,
shouldSort: false,
callbackOnCreateTemplates: () => (show_firstgroup)
}
);
</script>
{% endblock %}

View File

@ -49,6 +49,7 @@
{% endif %} {% endif %}
</header> </header>
<div class="event-body">
{% if event.has_image_url %} {% if event.has_image_url %}
@ -58,6 +59,7 @@
{% endif %} {% endif %}
<p>{{ event.description |linebreaks | robust_urlize }}</p> <p>{{ event.description |linebreaks | robust_urlize }}</p>
</div>
<footer class="infos-and-buttons"> <footer class="infos-and-buttons">
<div class="infos"> <div class="infos">

View File

@ -32,6 +32,7 @@ urlpatterns = [
name="view_event", name="view_event",
), ),
path("event/<int:pk>/edit", EventUpdateView.as_view(), name="edit_event"), path("event/<int:pk>/edit", EventUpdateView.as_view(), name="edit_event"),
path("event/<int:pk>/moderate", EventModerateView.as_view(), name="moderate_event"),
path("event/<int:pk>/clone/edit", EventUpdateView.as_view(), name="clone_edit"), path("event/<int:pk>/clone/edit", EventUpdateView.as_view(), name="clone_edit"),
path("event/<int:pk>/update-from-source", update_from_source, name="update_from_source"), path("event/<int:pk>/update-from-source", update_from_source, name="update_from_source"),
path( path(

View File

@ -31,7 +31,8 @@ from .forms import (
CategorisationForm, CategorisationForm,
EventAddPlaceForm, EventAddPlaceForm,
PlaceForm, PlaceForm,
MultipleHiddenInput MultipleHiddenInput,
EventModerateForm
) )
from .filters import ( from .filters import (
@ -333,6 +334,23 @@ class EventUpdateView(
return super().form_valid(form) return super().form_valid(form)
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
success_message = _("The event has been successfully moderated.")
def form_valid(self, form):
form.instance.set_no_modification_date_changed()
form.instance.set_in_moderation_process()
return super().form_valid(form)
class EventDeleteView( class EventDeleteView(
SuccessMessageMixin, PermissionRequiredMixin, LoginRequiredMixin, DeleteView SuccessMessageMixin, PermissionRequiredMixin, LoginRequiredMixin, DeleteView
): ):