Skip to content

Commit

Permalink
Réorganise le module tutorialv2 (#6591)
Browse files Browse the repository at this point in the history
* Déplace le code relatif aux tags dans un fichier dédié
* Déplace le code relatif à la licence dans un fichier dédié
* Déplace le code relatif aux suggestions dans un fichier dédié
* Déplace les formulaires relatifs aux contributeurs avec leurs vues
* Déplace le formulaire relatif à l'aide avec sa vue
* Déplace les formulaires relatifs aux auteurs avec leurs vues
  • Loading branch information
Arnaud-D authored Mar 29, 2024
1 parent 2da324a commit 6e0d801
Show file tree
Hide file tree
Showing 15 changed files with 420 additions and 379 deletions.
287 changes: 3 additions & 284 deletions zds/tutorialv2/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@

from zds.tutorialv2.utils import get_content_version_url
from zds.utils.forms import CommonLayoutEditor, CommonLayoutVersionEditor
from zds.utils.models import SubCategory, Licence
from zds.utils.models import SubCategory
from zds.tutorialv2.models import TYPE_CHOICES
from zds.tutorialv2.models.help_requests import HelpWriting
from zds.tutorialv2.models.database import PublishableContent, ContentContributionRole, ContentSuggestion
from zds.tutorialv2.models.database import PublishableContent
from django.utils.translation import gettext_lazy as _
from zds.member.models import Profile
from zds.utils.forms import TagValidator, IncludeEasyMDE
from zds.utils.forms import IncludeEasyMDE
from zds.utils.validators import with_svg_validator, slugify_raise_on_invalid, InvalidSlugError


Expand Down Expand Up @@ -48,123 +46,6 @@ def label_from_instance(self, obj):
return obj.title


class ContributionForm(forms.Form):
contribution_role = ReviewerTypeModelChoiceField(
label=_("Role"),
required=True,
queryset=ContentContributionRole.objects.order_by("title").all(),
)

username = forms.CharField(
label=_("Contributeur"),
required=True,
widget=forms.TextInput(
attrs={"placeholder": _("Pseudo du membre à ajouter."), "data-autocomplete": "{ 'type': 'single' }"}
),
)

comment = forms.CharField(
label=_("Commentaire"),
required=False,
widget=forms.Textarea(attrs={"placeholder": _("Commentaire sur ce contributeur."), "rows": "3"}),
)

def __init__(self, content, *args, **kwargs):
self.helper = FormHelper()
self.helper.form_class = "modal modal-flex"
self.helper.form_id = "add-contributor"
self.helper.form_method = "post"
self.helper.form_action = reverse("content:add-contributor", kwargs={"pk": content.pk})
self.helper.layout = Layout(
Field("username"),
Field("contribution_role"),
Field("comment"),
ButtonHolder(
StrictButton(_("Ajouter"), type="submit", css_class="btn-submit"),
),
)
super().__init__(*args, **kwargs)

def clean_username(self):
cleaned_data = super().clean()
if cleaned_data.get("username"):
username = cleaned_data.get("username")
user = Profile.objects.contactable_members().filter(user__username__iexact=username.strip().lower()).first()
if user is not None:
cleaned_data["user"] = user.user
else:
self._errors["user"] = self.error_class([_("L'utilisateur sélectionné n'existe pas")])

if "user" not in cleaned_data:
self._errors["user"] = self.error_class([_("Veuillez renseigner l'utilisateur")])

return cleaned_data


class RemoveContributionForm(forms.Form):
pk_contribution = forms.CharField(
label=_("Contributeur"),
required=True,
)


class AuthorForm(forms.Form):
username = forms.CharField(label=_("Auteurs à ajouter séparés d'une virgule."), required=True)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_class = "content-wrapper"
self.helper.form_method = "post"
self.helper.layout = Layout(
Field("username"),
ButtonHolder(
StrictButton(_("Ajouter"), type="submit"),
),
)

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
"""
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
return cleaned_data

def is_valid(self):
return super().is_valid() and "users" in self.clean()


class RemoveAuthorForm(AuthorForm):
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
"""
cleaned_data = super(AuthorForm, self).clean()
users = []
for username in cleaned_data.get("username").split(","):
# we can remove all users (bots inclued)
user = Profile.objects.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
return cleaned_data


class ContainerForm(FormWithTitle):
introduction = forms.CharField(
label=_("Introduction"),
Expand Down Expand Up @@ -316,109 +197,6 @@ def clean(self):
return cleaned_data


class EditContentTagsForm(forms.Form):
tags = forms.CharField(
label=_("Tags séparés par des virgules (exemple : python,api,web) :"),
max_length=64,
required=False,
widget=forms.TextInput(),
error_messages={"max_length": _("La liste de tags saisie dépasse la longueur maximale autorisée.")},
)

def __init__(self, content, db_content, *args, **kwargs):
self.db_content = db_content
kwargs["initial"] = {"tags": ", ".join(db_content.tags.values_list("title", flat=True))}
super(forms.Form, self).__init__(*args, **kwargs)

self.fields["tags"].widget.attrs.update(
{
"data-autocomplete": '{ "type": "multiple", "fieldname": "title", "url": "'
+ reverse("api:utils:tags-list")
+ '?search=%s" }',
}
)

self.helper = FormHelper()
self.helper.form_class = "content-wrapper"
self.helper.form_method = "post"
self.helper.form_id = "edit-tags"
self.helper.form_class = "modal modal-flex"
self.helper.form_action = reverse("content:edit-tags", kwargs={"pk": content.pk})
self.helper.layout = Layout(
HTML(
"""<p>Les tags permettent de grouper les publications plus finement que les catégories.
Par exemple, vous pouvez indiquer une technologie ou une sous-discipline.
Consultez <a href="{}">la page des tags</a> pour voir des exemples.""".format(
reverse("content:tags")
)
),
Field("tags"),
ButtonHolder(StrictButton("Valider", type="submit")),
)
self.previous_page_url = reverse("content:view", kwargs={"pk": content.pk, "slug": content.slug})

def clean_tags(self):
validator = TagValidator()
cleaned_tags = self.cleaned_data.get("tags")
if not validator.validate_raw_string(cleaned_tags):
self.add_error("tags", self.error_class(validator.errors))
return cleaned_tags


class EditContentLicenseForm(forms.Form):
license = forms.ModelChoiceField(
label=_("Licence de votre publication : "),
queryset=Licence.objects.order_by("title").all(),
required=True,
empty_label=_("Choisir une licence"),
error_messages={
"required": _("Merci de choisir une licence."),
"invalid_choice": _("Merci de choisir une licence valide dans la liste."),
},
)

update_preferred_license = forms.BooleanField(
label=_("Je souhaite utiliser cette licence comme choix par défaut pour mes futures publications."),
required=False,
)

def __init__(self, versioned_content, *args, **kwargs):
kwargs["initial"] = {"license": versioned_content.licence}
super(forms.Form, self).__init__(*args, **kwargs)

self.helper = FormHelper()
self.helper.form_class = "content-wrapper"
self.helper.form_method = "post"
self.helper.form_id = "edit-license"
self.helper.form_class = "modal modal-flex"
self.helper.form_action = reverse("content:edit-license", kwargs={"pk": versioned_content.pk})
self.previous_page_url = reverse(
"content:view", kwargs={"pk": versioned_content.pk, "slug": versioned_content.slug}
)
self._create_layout()

if "type" in self.initial:
self.helper["type"].wrap(Field, disabled=True)

def _create_layout(self):
self.helper.layout = Layout(
HTML(
"""<p>{} encourage l'utilisation de licences facilitant le partage,
telles que les licences <a href="https://creativecommons.org/">Creative Commons</a>.</p>
<p>Pour choisir la licence de votre publication, aidez-vous de la
<a href="{}" alt="{}">présentation
des différentes licences proposées sur le site</a>.</p>""".format(
settings.ZDS_APP["site"]["literal_name"],
settings.ZDS_APP["site"]["licenses"]["licence_info_title"],
settings.ZDS_APP["site"]["licenses"]["licence_info_link"],
)
),
Field("license"),
Field("update_preferred_license"),
ButtonHolder(StrictButton("Valider", type="submit")),
)


class ExtractForm(FormWithTitle):
text = forms.CharField(
label=_("Texte"),
Expand Down Expand Up @@ -1289,62 +1067,3 @@ def clean(self):
raise forms.ValidationError(_("Vous devez choisir des URL a comparer"))
if len(urls) < 2:
raise forms.ValidationError(_("Il faut au minimum 2 urls à comparer"))


class SearchSuggestionForm(forms.Form):
suggestion_pk = forms.CharField(
label="Contenu à suggérer",
required=False,
widget=forms.TextInput(),
)
excluded_pk = forms.CharField(required=False, widget=forms.HiddenInput(attrs={"class": "excluded_field"}))

def __init__(self, content, *args, **kwargs):
super().__init__(*args, **kwargs)

self.fields["suggestion_pk"].widget.attrs.update(
{
"data-autocomplete": '{"type": "multiple_checkbox",'
'"limit": 10,'
'"fieldname": "title",'
'"url": "' + reverse("search:suggestion") + '?q=%s&excluded=%e"}',
"placeholder": "Rechercher un contenu",
}
)

self.helper = FormHelper()
self.helper.form_action = reverse("content:add-suggestion", kwargs={"pk": content.pk})
self.helper.form_class = "modal modal-large"
self.helper.form_id = "add-suggestion"
self.helper.form_method = "post"

self.helper.layout = Layout(
Field("suggestion_pk"), Field("excluded_pk"), StrictButton(_("Ajouter"), type="submit")
)


class RemoveSuggestionForm(forms.Form):
pk_suggestion = forms.IntegerField(
label=_("Suggestion"),
required=True,
error_messages={"does_not_exist": _("La suggestion sélectionnée n'existe pas.")},
)

def clean_pk_suggestion(self):
pk_suggestion = self.cleaned_data.get("pk_suggestion")
suggestion = ContentSuggestion.objects.filter(id=pk_suggestion).first()
if suggestion is None:
self.add_error("pk_suggestion", self.fields["pk_suggestion"].error_messages["does_not_exist"])
return pk_suggestion


class ToggleHelpForm(forms.Form):
help_wanted = forms.CharField()
activated = forms.BooleanField(required=False)

def clean(self):
clean_data = super().clean()
clean_data["help_wanted"] = HelpWriting.objects.filter(title=(self.data["help_wanted"] or "").strip()).first()
if not clean_data["help_wanted"]:
self.add_error("help_wanted", _("Inconnu"))
return clean_data
5 changes: 3 additions & 2 deletions zds/tutorialv2/models/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
from zds.tutorialv2.views.authors import AddAuthorToContent, RemoveAuthorFromContent
from zds.tutorialv2.views.beta import ManageBetaContent
from zds.tutorialv2.views.contributors import AddContributorToContent, RemoveContributorFromContent
from zds.tutorialv2.views.editorialization import EditContentTags, AddSuggestion, RemoveSuggestion
from zds.tutorialv2.views.suggestions import AddSuggestion, RemoveSuggestion
from zds.tutorialv2.views.tags import EditTags
from zds.tutorialv2.views.goals import EditGoals
from zds.tutorialv2.views.labels import EditLabels
from zds.tutorialv2.views.help import ChangeHelp
Expand Down Expand Up @@ -132,7 +133,7 @@ def record_event_validation_management(sender, performer, signal, content, versi
).save()


@receiver(signals.tags_management, sender=EditContentTags)
@receiver(signals.tags_management, sender=EditTags)
def record_event_tags_management(sender, performer, signal, content, **_):
Event(
performer=performer,
Expand Down
2 changes: 1 addition & 1 deletion zds/tutorialv2/tests/tests_views/tests_addcontributor.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from zds.member.tests.factories import ProfileFactory, StaffProfileFactory
from zds.tutorialv2.tests.factories import ContentContributionRoleFactory, PublishableContentFactory
from zds.tutorialv2.forms import ContributionForm
from zds.tutorialv2.views.contributors import ContributionForm
from zds.tutorialv2.models.database import ContentContribution
from zds.tutorialv2.tests import TutorialTestMixin, override_for_contents

Expand Down
3 changes: 1 addition & 2 deletions zds/tutorialv2/tests/tests_views/tests_editcontentlicense.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@

from zds.tutorialv2.models.database import PublishableContent
from zds.member.models import Profile
from zds.tutorialv2.views.contents import EditContentLicense
from zds.tutorialv2.forms import EditContentLicenseForm
from zds.tutorialv2.views.licence import EditContentLicenseForm, EditContentLicense
from zds.tutorialv2.tests import TutorialTestMixin, override_for_contents
from zds.member.tests.factories import ProfileFactory, StaffProfileFactory
from zds.tutorialv2.tests.factories import PublishableContentFactory
Expand Down
9 changes: 4 additions & 5 deletions zds/tutorialv2/tests/tests_views/tests_editcontenttags.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
from django.utils.html import escape

from zds.tutorialv2.models.database import PublishableContent
from zds.tutorialv2.views.editorialization import EditContentTags
from zds.tutorialv2.forms import EditContentTagsForm
from zds.tutorialv2.views.tags import EditTagsForm, EditTags
from zds.tutorialv2.tests import TutorialTestMixin, override_for_contents
from zds.tutorialv2.tests.factories import PublishableContentFactory
from zds.member.tests.factories import ProfileFactory, StaffProfileFactory
Expand Down Expand Up @@ -73,8 +72,8 @@ def setUp(self):

# Get information to be reused in tests
self.form_url = reverse("content:edit-tags", kwargs={"pk": self.content.pk})
self.error_messages = EditContentTagsForm.declared_fields["tags"].error_messages
self.success_message = EditContentTags.success_message
self.error_messages = EditTagsForm.declared_fields["tags"].error_messages
self.success_message = EditTags.success_message

# Log in with an authorized user (e.g the author of the content) to perform the tests
self.client.force_login(self.author.user)
Expand All @@ -90,7 +89,7 @@ def get_test_cases(self):
"success_tags": {"inputs": {"tags": "test, test1"}, "expected_outputs": [self.success_message]},
"stripped_to_empty": {"inputs": {"tags": " "}, "expected_outputs": [self.success_message]},
"tags_string_too_long": {
"inputs": {"tags": "a" * (EditContentTagsForm.declared_fields["tags"].max_length + 1)},
"inputs": {"tags": "a" * (EditTagsForm.declared_fields["tags"].max_length + 1)},
"expected_outputs": [self.error_messages["max_length"]],
},
"invalid_slug_tag": {
Expand Down
2 changes: 1 addition & 1 deletion zds/tutorialv2/tests/tests_views/tests_removesuggestion.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from zds.member.tests.factories import ProfileFactory, StaffProfileFactory
from zds.tutorialv2.tests.factories import PublishableContentFactory
from zds.tutorialv2.forms import RemoveSuggestionForm
from zds.tutorialv2.views.suggestions import RemoveSuggestionForm
from zds.tutorialv2.models.database import ContentSuggestion
from zds.tutorialv2.tests import TutorialTestMixin, override_for_contents

Expand Down
Loading

0 comments on commit 6e0d801

Please sign in to comment.