Skip to content

Commit

Permalink
Rend générique en fonction du type la vue "RemoveAuthorFromContent"
Browse files Browse the repository at this point in the history
* supprime la distinction de type de publication
* préfère le terme "publication" à "contenu"
* renomme les vues pour adopter la convention de Django
* refactorise pour améliorer la lisibilité
* interdit les méthodes HTTP autres que POST
  • Loading branch information
Arnaud-D committed Dec 25, 2024
1 parent 4d9a460 commit ba288b5
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 73 deletions.
4 changes: 2 additions & 2 deletions templates/tutorialv2/messages/remove_author_pm.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{% 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é retiré de la rédaction du contenu « {{ title }} ».
Vous avez été retiré de la rédaction de « {{ title }} ».

{% endblocktrans %}
15 changes: 15 additions & 0 deletions zds/tutorialv2/models/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,21 @@ def is_author(self, user: User) -> bool:
# This is fast because there are few authors and the QuerySet is usually prefetched and cached.
return user in self.authors.all()

def remove_author(self, user: User) -> bool:
"""
Remove a user from the authors and remove his access to the gallery.
If the user is not an author, do nothing.
If the user is the last author, do nothing. This method will not delete the content.
Return ``True`` if the user was effectively removed from the authors and ``False`` otherwise.
"""
if self.is_author(user) and self.authors.count() > 1:
gallery = UserGallery.objects.filter(user__pk=user.pk, gallery__pk=self.gallery.pk).first()
if gallery:
gallery.delete()
self.authors.remove(user)
return True
return False

def is_permanently_unpublished(self):
"""Is this content permanently unpublished by a moderator ?"""

Expand Down
4 changes: 2 additions & 2 deletions zds/tutorialv2/models/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 AddAuthorToContent, RemoveAuthorView
from zds.tutorialv2.views.beta import ManageBetaContent
from zds.tutorialv2.views.canonical import EditCanonicalLinkView
from zds.tutorialv2.views.contributors import AddContributorToContent, RemoveContributorFromContent
Expand Down Expand Up @@ -98,7 +98,7 @@ def record_event_beta_management(sender, performer, signal, content, version, ac


@receiver(signals.authors_management, sender=AddAuthorToContent)
@receiver(signals.authors_management, sender=RemoveAuthorFromContent)
@receiver(signals.authors_management, sender=RemoveAuthorView)
def record_event_author_management(sender, performer, signal, content, author, action, **_):
Event(
performer=performer,
Expand Down
4 changes: 2 additions & 2 deletions zds/tutorialv2/urls/urls_contents.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 AddAuthorToContent, RemoveAuthorView
from zds.tutorialv2.views.redirect import RedirectOldContentOfAuthor
from zds.tutorialv2.views.archives import DownloadContent, UpdateContentWithArchive, CreateContentFromArchive
from zds.tutorialv2.views.contributors import (
Expand Down Expand Up @@ -215,7 +215,7 @@ def get_version_pages():
path("ajouter-contributeur/<int:pk>/", AddContributorToContent.as_view(), name="add-contributor"),
path("enlever-contributeur/<int:pk>/", RemoveContributorFromContent.as_view(), name="remove-contributor"),
path("ajouter-auteur/<int:pk>/", AddAuthorToContent.as_view(), name="add-author"),
path("enlever-auteur/<int:pk>/", RemoveAuthorFromContent.as_view(), name="remove-author"),
path("enlever-auteur/<int:pk>/", RemoveAuthorView.as_view(), name="remove-author"),
path("modifier-titre/<int:pk>/", EditTitle.as_view(), name="edit-title"),
path("modifier-sous-titre/<int:pk>/", EditSubtitle.as_view(), name="edit-subtitle"),
path("modifier-miniature/<int:pk>/", EditThumbnailView.as_view(), name="edit-thumbnail"),
Expand Down
104 changes: 41 additions & 63 deletions zds/tutorialv2/views/authors.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from crispy_forms.layout import Layout, Field
from django import forms
from django.contrib import messages
from django.contrib.auth.models import User
from django.shortcuts import redirect
from django.template.loader import render_to_string
from django.urls import reverse
Expand Down Expand Up @@ -139,63 +138,24 @@ def form_invalid(self, form):
return super().form_valid(form)


class RemoveAuthorFromContent(LoggedWithReadWriteHability, SingleContentFormViewMixin):
class RemoveAuthorView(LoggedWithReadWriteHability, SingleContentFormViewMixin):
form_class = RemoveAuthorForm
must_be_author = True
authorized_for_staff = True

@staticmethod
def remove_author(content, user):
"""Remove a user from the authors and ensure that he is access to the content's gallery is also removed.
The last author is not removed.
:param content: the content
:type content: zds.tutorialv2.models.database.PublishableContent
:param user: the author
:type user: User
:return: ``True`` if the author was removed, ``False`` otherwise
"""
if user in content.authors.all() and content.authors.count() > 1:
gallery = UserGallery.objects.filter(user__pk=user.pk, gallery__pk=content.gallery.pk).first()

if gallery:
gallery.delete()

content.authors.remove(user)
return True

return False
http_method_names = ["post"]

def form_valid(self, form):
content = self.object
current_user = False
users = form.cleaned_data["users"]

_type = (_("cet article"), _("de l'article"))
if self.object.is_tutorial:
_type = (_("ce tutoriel"), _("du tutoriel"))
elif self.object.is_opinion:
_type = (_("ce billet"), _("du billet"))

bot = get_bot_account()
for user in users:
if RemoveAuthorFromContent.remove_author(self.object, user):
if content.remove_author(user):
if user.pk == self.request.user.pk:
current_user = True
elif is_reachable(user):
send_mp(
bot,
[user],
format_lazy("{}{}", _("Retrait de la rédaction "), _type[1]),
self.versioned_object.title,
render_to_string(
"tutorialv2/messages/remove_author_pm.md",
{
"content": self.object,
"user": user.username,
},
),
hat=get_hat_from_settings("validation"),
)
self.notify_by_private_message(user, bot)
signals.authors_management.send(
sender=self.__class__,
content=self.object,
Expand All @@ -206,36 +166,54 @@ def form_valid(self, form):
else: # if user is incorrect or alone
messages.error(
self.request,
_("Vous êtes le seul auteur de {} ou le membre sélectionné en a déjà quitté la rédaction.").format(
_type[0]
_(
"Vous êtes le seul auteur de la publication ou le membre sélectionné en a déjà quitté la rédaction."
),
)
return redirect(self.object.get_absolute_url())

self.object.save()
content.save()

authors_list = ""
if current_user: # Redirect self-removing authors to their publications list
messages.success(self.request, _("Vous avez bien quitté la rédaction de la publication."))
self.success_url = reverse("content:find-all", args=[self.request.user.username])
else: # The user removed another user from the authors
authors_list = self.users_list(users)
messages.success(
self.request,
_("Vous avez enlevé {} de la liste des auteurs et autrices de la publication.").format(authors_list),
)
self.success_url = self.object.get_absolute_url()

for index, user in enumerate(form.cleaned_data["users"]):
return super().form_valid(form)

@staticmethod
def users_list(users):
authors_list = ""
for index, user in enumerate(users):
if index > 0:
if index == len(users) - 1:
authors_list += _(" et ")
else:
authors_list += _(", ")
authors_list += user.username

if not current_user: # if the removed author is not current user
messages.success(
self.request,
_("Vous avez enlevé {} de la liste des auteurs et autrices de {}.").format(authors_list, _type[0]),
)
self.success_url = self.object.get_absolute_url()
else: # if current user is leaving the content's redaction, redirect him to a more suitable page
messages.success(self.request, _("Vous avez bien quitté la rédaction de {}.").format(_type[0]))
self.success_url = reverse(
self.object.type.lower() + ":find-" + self.object.type.lower(), args=[self.request.user.username]
)
return super().form_valid(form)
return authors_list

def notify_by_private_message(self, user, bot):
send_mp(
bot,
[user],
_("Retrait de la rédaction de la publication"),
self.versioned_object.title,
render_to_string(
"tutorialv2/messages/remove_author_pm.md",
{
"content": self.object,
"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."))
Expand Down
7 changes: 3 additions & 4 deletions zds/tutorialv2/views/contents.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
)
from zds.tutorialv2.models.database import PublishableContent, Validation
from zds.tutorialv2.utils import init_new_repo
from zds.tutorialv2.views.authors import RemoveAuthorFromContent
from zds.tutorialv2.views.authors import RemoveAuthorView
from zds.utils.forms import IncludeEasyMDE
from zds.utils.models import get_hat_from_settings
from zds.mp.utils import send_mp, send_message_mp
Expand Down Expand Up @@ -450,11 +450,10 @@ def form_valid(self, form):
elif self.object.is_opinion:
_type = _("ce billet")

if self.object.authors.count() > 1: # if more than one author, just remove author from list
RemoveAuthorFromContent.remove_author(self.object, self.request.user)
if self.object.remove_author(self.request.user):
messages.success(self.request, _("Vous avez quitté la rédaction de {}.").format(_type))

else:
# If removing the author failed, it is the last author, and we must delete the content.
validation = Validation.objects.filter(content=self.object).order_by("-date_proposition").first()

if validation and validation.status == "PENDING_V": # if the validation have a validator, warn him by PM
Expand Down

0 comments on commit ba288b5

Please sign in to comment.