Ajout d'un profil utilisateur et d'un mode expert

Fix #348
This commit is contained in:
Jean-Marie Favreau 2025-03-14 18:02:43 +01:00
parent 182d7b85ce
commit 5783b5caa0
8 changed files with 171 additions and 7 deletions

View File

@ -16,6 +16,7 @@ from .models import (
ReferenceLocation,
StaticContent,
Tag,
UserProfile,
)
admin.site.register(Category)
@ -28,6 +29,7 @@ admin.site.register(Place)
admin.site.register(Message)
admin.site.register(ReferenceLocation)
admin.site.register(Organisation)
admin.site.register(UserProfile)
class URLWidget(DynamicArrayWidget):

View File

@ -261,9 +261,24 @@ class CategorisationRuleImportForm(ModelForm):
fields = "__all__"
class MultipleChoiceFieldAcceptAll(MultipleChoiceField):
def validate(self, value):
pass
class EventForm(GroupFormMixin, ModelForm):
required_css_class = "required"
new_tags = MultipleChoiceFieldAcceptAll(
label=_("New tags"),
help_text=_(
"Create new labels (sparingly). Note: by starting your tag with the characters “TW:”, you"
"ll create a “trigger warning” tag, and the associated events will be announced as such."
),
widget=DynamicArrayWidget(),
required=False,
)
old_local_image = CharField(widget=HiddenInput(), required=False)
simple_cloning = CharField(widget=HiddenInput(), required=False)
cloning = CharField(widget=HiddenInput(), required=False)
@ -311,10 +326,13 @@ class EventForm(GroupFormMixin, ModelForm):
is_authenticated = kwargs.pop("is_authenticated", False)
self.cloning = kwargs.pop("is_cloning", False)
self.simple_cloning = kwargs.pop("is_simple_cloning", False)
self.is_moderation_expert = kwargs.pop("is_moderation_expert", False)
super().__init__(*args, **kwargs)
if not is_authenticated:
del self.fields["status"]
del self.fields["organisers"]
if not self.is_moderation_expert:
del self.fields["new_tags"]
self.fields["category"].queryset = self.fields["category"].queryset.order_by(
"name"
)
@ -370,10 +388,14 @@ class EventForm(GroupFormMixin, ModelForm):
self.fields["category"].group_id = "meta-admin"
self.fields["tags"].group_id = "meta-admin"
self.fields["status"].group_id = "meta-admin"
if self.is_moderation_expert:
self.fields["new_tags"].group_id = "meta-admin"
else:
self.add_group("meta", _("Meta information"))
self.fields["category"].group_id = "meta"
self.fields["tags"].group_id = "meta"
if self.is_moderation_expert:
self.fields["new_tags"].group_id = "meta"
def is_clone_from_url(self):
return self.cloning
@ -407,9 +429,15 @@ class EventForm(GroupFormMixin, ModelForm):
return end_time
def clean_new_tags(self):
return list(set(self.cleaned_data.get("new_tags")))
def clean(self):
super().clean()
if self.is_moderation_expert and self.cleaned_data.get("new_tags") is not None:
self.cleaned_data["tags"] += self.cleaned_data.get("new_tags")
# when cloning an existing event, we need to copy the local image
if (
(
@ -431,11 +459,6 @@ class EventFormWithContact(SimpleContactForm, EventForm):
pass
class MultipleChoiceFieldAcceptAll(MultipleChoiceField):
def validate(self, value):
pass
class EventModerateForm(ModelForm):
required_css_class = "required"
@ -468,10 +491,13 @@ class EventModerateForm(ModelForm):
widgets = {"status": RadioSelect}
def __init__(self, *args, **kwargs):
self.is_moderation_expert = kwargs.pop("is_moderation_expert", False)
super().__init__(*args, **kwargs)
self.fields["category"].queryset = self.fields["category"].queryset.order_by(
"name"
)
if not self.is_moderation_expert:
del self.fields["new_tags"]
self.fields["category"].empty_label = None
self.fields["category"].initial = Category.get_default_category()
self.fields["tags"].choices = Tag.get_tag_groups(all=True)
@ -485,7 +511,7 @@ class EventModerateForm(ModelForm):
if self.cleaned_data["tags"] is None:
self.cleaned_data["tags"] = []
if self.cleaned_data.get("new_tags") is not None:
if self.is_moderation_expert and self.cleaned_data.get("new_tags") is not None:
self.cleaned_data["tags"] += self.cleaned_data.get("new_tags")
self.cleaned_data["tags"] = list(set(self.cleaned_data["tags"]))

View File

@ -0,0 +1,38 @@
# Generated by Django 4.2.19 on 2025-03-14 16:35
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("auth", "0012_alter_user_first_name_max_length"),
("agenda_culturel", "0154_tag_message"),
]
operations = [
migrations.CreateModel(
name="UserProfile",
fields=[
(
"user",
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
primary_key=True,
serialize=False,
to=settings.AUTH_USER_MODEL,
),
),
(
"is_moderation_expert",
models.BooleanField(
default=False,
help_text="This user is an expert in moderation, and the interface features additional functionalities.",
verbose_name="Expert moderation user",
),
),
],
),
]

View File

@ -0,0 +1,20 @@
# Generated by Django 4.2.19 on 2025-03-14 16:42
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("agenda_culturel", "0155_userprofile"),
]
operations = [
migrations.AlterModelOptions(
name="userprofile",
options={
"verbose_name": "User profile",
"verbose_name_plural": "User profiles",
},
),
]

View File

@ -0,0 +1,33 @@
# Generated by Django 4.2.19 on 2025-03-14 16:45
from django.db import migrations
def create_profiles(apps, schema_editor):
User = apps.get_model("auth", "User")
UserProfile = apps.get_model("agenda_culturel", "UserProfile")
for instance in User.objects.all():
if not hasattr(instance, "userprofile"):
UserProfile.objects.create(user=instance)
instance.userprofile.is_moderation_expert = True
instance.userprofile.save()
def create_profiles_backward(apps, schema_editor):
pass
class Migration(migrations.Migration):
dependencies = [
("agenda_culturel", "0156_alter_userprofile_options"),
]
operations = [
migrations.RunPython(
code=create_profiles,
reverse_code=create_profiles_backward,
),
]

View File

@ -40,6 +40,8 @@ from django_resized import ResizedImageField
from icalendar import Calendar as icalCal
from icalendar import Event as icalEvent
from location_field.models.spatial import LocationField
from django.dispatch import receiver
from django.db.models.signals import post_save
from .calendar import CalendarDay
from .import_tasks.extractor import Extractor
@ -50,6 +52,37 @@ from .import_tasks.generic_extractors.fbevent import (
logger = logging.getLogger(__name__)
class UserProfile(models.Model):
user = models.OneToOneField(
User,
on_delete=models.CASCADE,
primary_key=True,
)
is_moderation_expert = models.BooleanField(
verbose_name=_("Expert moderation user"),
help_text=_(
"This user is an expert in moderation, and the interface features additional functionalities."
),
default=False,
)
class Meta:
verbose_name = _("User profile")
verbose_name_plural = _("User profiles")
def __str__(self):
return _("User profile") + " (" + self.user.username + ")"
@receiver(post_save, sender=User)
def update_profile_signal(sender, instance, created, **kwargs):
if not hasattr(instance, "userprofile"):
UserProfile.objects.create(user=instance)
instance.userprofile.save()
def remove_accents(input_str):
if input_str is None:
return None

View File

@ -9,7 +9,9 @@
{% if local %}
<a href="{{ local.get_absolute_url }}" role="button">Voir la version locale {% picto_from_name "eye" %}</a>
{% else %}
<a href="{% url 'clone_edit' event.id %}" role="button">modifier & modérer {% picto_from_name "edit-3" %}</a>
{% if user.userprofile.is_moderation_expert %}
<a href="{% url 'clone_edit' event.id %}" role="button">modifier & modérer {% picto_from_name "edit-3" %}</a>
{% endif %}
{% endif %}
{% endwith %}
{% else %}

View File

@ -472,6 +472,9 @@ class EventUpdateView(
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs["is_authenticated"] = self.request.user.is_authenticated
kwargs["is_moderation_expert"] = (
self.request.user.userprofile.is_moderation_expert
)
kwargs["is_cloning"] = self.is_cloning
kwargs["is_simple_cloning"] = self.is_simple_cloning
return kwargs
@ -548,6 +551,13 @@ class EventModerateView(
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.")