diff --git a/templates/tutorialv2/messages/add_author_pm.md b/templates/tutorialv2/messages/add_author_pm.md index 58452e4e52..90c4ed431e 100644 --- a/templates/tutorialv2/messages/add_author_pm.md +++ b/templates/tutorialv2/messages/add_author_pm.md @@ -1,11 +1,10 @@ {% load i18n %} -{% blocktrans with title=content.title|safe type=type|safe user=user|safe %} +{% blocktrans with title=content.title|safe user=user|safe %} Bonjour {{ user }}, -Vous avez été intégré à la rédaction du contenu « [{{ title }}]({{ url }}) ». -Il a été ajouté à la liste de vos contenus en rédaction -[ici]({{ index }}). +Vous avez été intégré à la rédaction de « [{{ title }}]({{ url }}) ». +Vous pouvez retrouver ce lien dans votre [liste de publications]({{ index }}). Plus rien maintenant ne retient votre plume, alors bon courage ! {% endblocktrans %} diff --git a/zds/tutorialv2/models/events.py b/zds/tutorialv2/models/events.py index 8617d105c1..4815a5455b 100644 --- a/zds/tutorialv2/models/events.py +++ b/zds/tutorialv2/models/events.py @@ -4,7 +4,7 @@ from zds.tutorialv2.models.database import PublishableContent from zds.tutorialv2 import signals -from zds.tutorialv2.views.authors import AddAuthorToContent, RemoveAuthorFromContent +from zds.tutorialv2.views.authors import AddAuthorView, RemoveAuthorFromContent from zds.tutorialv2.views.beta import ManageBetaContent from zds.tutorialv2.views.canonical import EditCanonicalLinkView from zds.tutorialv2.views.contributors import AddContributorToContent, RemoveContributorFromContent @@ -97,7 +97,7 @@ def record_event_beta_management(sender, performer, signal, content, version, ac ).save() -@receiver(signals.authors_management, sender=AddAuthorToContent) +@receiver(signals.authors_management, sender=AddAuthorView) @receiver(signals.authors_management, sender=RemoveAuthorFromContent) def record_event_author_management(sender, performer, signal, content, author, action, **_): Event( diff --git a/zds/tutorialv2/urls/urls_contents.py b/zds/tutorialv2/urls/urls_contents.py index 89da39e1e1..37b01ceb45 100644 --- a/zds/tutorialv2/urls/urls_contents.py +++ b/zds/tutorialv2/urls/urls_contents.py @@ -38,7 +38,7 @@ ) from zds.tutorialv2.views.history import DisplayHistory, DisplayDiff from zds.tutorialv2.views.help import ContentsWithHelps, ChangeHelp -from zds.tutorialv2.views.authors import AddAuthorToContent, RemoveAuthorFromContent +from zds.tutorialv2.views.authors import AddAuthorView, RemoveAuthorFromContent from zds.tutorialv2.views.redirect import RedirectOldContentOfAuthor from zds.tutorialv2.views.archives import DownloadContent, UpdateContentWithArchive, CreateContentFromArchive from zds.tutorialv2.views.contributors import ( @@ -214,7 +214,7 @@ def get_version_pages(): path("comparaison///", DisplayDiff.as_view(), name="diff"), path("ajouter-contributeur//", AddContributorToContent.as_view(), name="add-contributor"), path("enlever-contributeur//", RemoveContributorFromContent.as_view(), name="remove-contributor"), - path("ajouter-auteur//", AddAuthorToContent.as_view(), name="add-author"), + path("ajouter-auteur//", AddAuthorView.as_view(), name="add-author"), path("enlever-auteur//", RemoveAuthorFromContent.as_view(), name="remove-author"), path("modifier-titre//", EditTitle.as_view(), name="edit-title"), path("modifier-sous-titre//", EditSubtitle.as_view(), name="edit-subtitle"), diff --git a/zds/tutorialv2/views/authors.py b/zds/tutorialv2/views/authors.py index e77d673884..04a6021e13 100644 --- a/zds/tutorialv2/views/authors.py +++ b/zds/tutorialv2/views/authors.py @@ -4,6 +4,7 @@ from django import forms from django.contrib import messages from django.contrib.auth.models import User +from django.db.models import Q from django.shortcuts import redirect from django.template.loader import render_to_string from django.urls import reverse @@ -36,23 +37,27 @@ def __init__(self, *args, **kwargs): ) def clean_username(self): - """Check every username and send it to the cleaned_data['user'] list - - :return: a dictionary of all treated data with the users key added + """ + Check each username in the comma-separated list and add the corresponding Users to cleaned_data["users"]. + Skip non-existing usernames and remove duplicates. """ cleaned_data = super().clean() - users = [] - if cleaned_data.get("username"): - for username in cleaned_data.get("username").split(","): - user = ( - Profile.objects.contactable_members() - .filter(user__username__iexact=username.strip().lower()) - .first() - ) - if user is not None: - users.append(user.user) - if len(users) > 0: - cleaned_data["users"] = users + + username_field = cleaned_data.get("username") + if username_field is None: + return cleaned_data + + usernames = username_field.split(",") + usernames_normalized = [username.strip().lower() for username in usernames] + + condition = Q() + for username in usernames_normalized: + condition |= Q(username__iexact=username) + users = User.objects.filter(condition, profile__in=Profile.objects.contactable_members()) + + if len(users) > 0: + cleaned_data["users"] = list(users) + return cleaned_data def is_valid(self): @@ -77,62 +82,55 @@ def clean_username(self): return cleaned_data -class AddAuthorToContent(LoggedWithReadWriteHability, SingleContentFormViewMixin): +class AddAuthorView(LoggedWithReadWriteHability, SingleContentFormViewMixin): must_be_author = True form_class = AuthorForm authorized_for_staff = True - - def get(self, request, *args, **kwargs): - content = self.get_object() - url = "content:find-{}".format("tutorial" if content.is_tutorial() else content.type.lower()) - return redirect(url, self.request.user) + http_method_names = ["post"] def form_valid(self, form): - _type = _("de l'article") + bot = get_bot_account() + authors = self.object.authors.all() + new_authors = [user for user in form.cleaned_data["users"] if user not in authors] + for user in new_authors: + self.object.authors.add(user) - if self.object.is_tutorial: - _type = _("du tutoriel") - elif self.object.is_opinion: - _type = _("du billet") + if self.object.validation_private_message: + self.object.validation_private_message.add_participant(user) + + if user != self.request.user: + self.notify_by_private_message(user, bot) + + UserGallery(gallery=self.object.gallery, user=user, mode=GALLERY_WRITE).save() + + signals.authors_management.send( + sender=self.__class__, content=self.object, performer=self.request.user, author=user, action="add" + ) - bot = get_bot_account() - all_authors_pk = [author.pk for author in self.object.authors.all()] - for user in form.cleaned_data["users"]: - if user.pk not in all_authors_pk: - self.object.authors.add(user) - if self.object.validation_private_message: - self.object.validation_private_message.add_participant(user) - all_authors_pk.append(user.pk) - if user != self.request.user: - url_index = reverse( - self.object.type.lower() + ":find-" + self.object.type.lower(), args=[user.username] - ) - send_mp( - bot, - [user], - format_lazy("{}{}", _("Ajout à la rédaction "), _type), - self.versioned_object.title, - render_to_string( - "tutorialv2/messages/add_author_pm.md", - { - "content": self.object, - "type": _type, - "url": self.object.get_absolute_url(), - "index": url_index, - "user": user.username, - }, - ), - hat=get_hat_from_settings("validation"), - ) - UserGallery(gallery=self.object.gallery, user=user, mode=GALLERY_WRITE).save() - signals.authors_management.send( - sender=self.__class__, content=self.object, performer=self.request.user, author=user, action="add" - ) self.object.save() self.success_url = self.object.get_absolute_url() return super().form_valid(form) + def notify_by_private_message(self, user, bot): + url_index = reverse(f"content:find-all", args=[user.username]) + send_mp( + bot, + [user], + _("Ajout à la rédaction d'une publication"), + self.versioned_object.title, + render_to_string( + "tutorialv2/messages/add_author_pm.md", + { + "content": self.object, + "url": self.object.get_absolute_url(), + "index": url_index, + "user": user.username, + }, + ), + hat=get_hat_from_settings("validation"), + ) + def form_invalid(self, form): messages.error(self.request, _("Les auteurs sélectionnés n'existent pas.")) self.success_url = self.object.get_absolute_url()