Skip to content

Commit

Permalink
feat(tags): ajouter des étiquettes à un forum (#746)
Browse files Browse the repository at this point in the history
## Description

Lors de la création ou de la mise à jour d'un `Forum` :
🎸 Permettre de selectionner une ou plusieurs étiquettes 
🎸 Permettre d'ajouter une ou plusieurs étiquettes inexistantes

## Type de changement

🎢 Nouvelle fonctionnalité (changement non cassant qui ajoute une
fonctionnalité).

### Points d'attention

🦺 suite PR #744 

### Captures d'écran (optionnel)

Création d'un forum


![image](https://github.com/user-attachments/assets/a2b1da0b-5c99-4476-8808-c5cb81c04e1a)


Mise à jour d'un forum, avec plusieurs nouveaux tags séparés par des
virgules


![image](https://github.com/user-attachments/assets/8f447d1d-fdaf-4234-bb1b-bc9e46a6f3f7)


Résultat de la mise à jour


![image](https://github.com/user-attachments/assets/119e48fd-6962-4301-b774-64ec283bfc7a)
  • Loading branch information
vincentporte authored Aug 26, 2024
1 parent b82ea73 commit 7f435bb
Show file tree
Hide file tree
Showing 9 changed files with 180 additions and 1 deletion.
2 changes: 1 addition & 1 deletion lacommunaute/forum/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

class ForumAdmin(BaseForumAdmin):
fieldsets = BaseForumAdmin.fieldsets
fieldsets[0][1]["fields"] += ("short_description", "certified")
fieldsets[0][1]["fields"] += ("short_description", "certified", "tags")
fieldsets[1][1]["fields"] += (
"members_group",
"invitation_token",
Expand Down
9 changes: 9 additions & 0 deletions lacommunaute/forum/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ def upvoted_by(self, create, extracted, **kwargs):
for user in extracted:
UpVote.objects.create(voter=user, content_object=self)

@factory.post_generation
def with_tags(self, create, extracted, **kwargs):
if not create or not extracted:
return

if isinstance(extracted, list):
for tag in extracted:
self.tags.add(tag)


class CategoryForumFactory(ForumFactory):
type = Forum.FORUM_CAT
Expand Down
21 changes: 21 additions & 0 deletions lacommunaute/forum/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from django import forms
from django.conf import settings
from django.forms import CharField, CheckboxSelectMultiple, ModelMultipleChoiceField
from taggit.models import Tag

from lacommunaute.forum.models import Forum

Expand Down Expand Up @@ -36,12 +38,31 @@ class ForumForm(forms.ModelForm):
widget=forms.FileInput(attrs={"accept": settings.SUPPORTED_IMAGE_FILE_TYPES.keys()}),
)
certified = forms.BooleanField(required=False, label="Certifiée par la communauté de l'inclusion")
tags = ModelMultipleChoiceField(
label="Sélectionner un ou plusieurs tags",
queryset=Tag.objects.all(),
widget=CheckboxSelectMultiple,
required=False,
)
new_tags = CharField(required=False, label="Ajouter un tag ou plusieurs tags (séparés par des virgules)")

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.instance.pk:
self.fields["tags"].initial = self.instance.tags.all()

def save(self, commit=True):
forum = super().save(commit=False)
forum.description = wrap_iframe_in_div_tag(self.cleaned_data.get("description"))

if commit:
forum.save()
forum.tags.set(self.cleaned_data["tags"])
(
forum.tags.add(*[tag.strip() for tag in self.cleaned_data["new_tags"].split(",")])
if self.cleaned_data.get("new_tags")
else None
)
return forum

class Meta:
Expand Down
24 changes: 24 additions & 0 deletions lacommunaute/forum/migrations/0017_forum_tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 5.0.7 on 2024-08-07 14:21

import taggit.managers
from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("forum", "0016_forum_certified"),
("taggit", "0006_rename_taggeditem_content_type_object_id_taggit_tagg_content_8fc721_idx"),
]

operations = [
migrations.AddField(
model_name="forum",
name="tags",
field=taggit.managers.TaggableManager(
help_text="A comma-separated list of tags.",
through="taggit.TaggedItem",
to="taggit.Tag",
verbose_name="Tags",
),
),
]
3 changes: 3 additions & 0 deletions lacommunaute/forum/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from machina.apps.forum.abstract_models import AbstractForum
from machina.models import DatedModel
from storages.backends.s3boto3 import S3Boto3Storage
from taggit.managers import TaggableManager

from lacommunaute.forum.enums import Kind as Forum_Kind
from lacommunaute.forum_conversation.models import Topic
Expand Down Expand Up @@ -40,6 +41,8 @@ class Forum(AbstractForum):

upvotes = GenericRelation(UpVote, related_query_name="forum")

tags = TaggableManager()

objects = ForumQuerySet().as_manager()

def get_absolute_url(self):
Expand Down
51 changes: 51 additions & 0 deletions lacommunaute/forum/tests/__snapshots__/test_forum_updateview.ambr
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# serializer version: 1
# name: test_selected_tags_are_preloaded[selected_tags_preloaded]
'''
<div class="form-group" id="div_id_tags">


<label class="control-label" for="id_tags">
Sélectionner un ou plusieurs tags

<span class="text-muted">(optional)</span>

</label>



<div class="form-check form-check-inline">
<input checked="" class="form-check-input" id="id_tags_0" name="tags" type="checkbox" value="9999"/>
<label class="form-check-label tag bg-info-lighter text-info" for="id_tags_0">
iae
</label>
</div>

<div class="form-check form-check-inline">
<input checked="" class="form-check-input" id="id_tags_1" name="tags" type="checkbox" value="10000"/>
<label class="form-check-label tag bg-info-lighter text-info" for="id_tags_1">
siae
</label>
</div>

<div class="form-check form-check-inline">
<input checked="" class="form-check-input" id="id_tags_2" name="tags" type="checkbox" value="10001"/>
<label class="form-check-label tag bg-info-lighter text-info" for="id_tags_2">
prescripteur
</label>
</div>

<div class="form-check form-check-inline">
<input class="form-check-input" id="id_tags_3" name="tags" type="checkbox" value="10002"/>
<label class="form-check-label tag bg-info-lighter text-info" for="id_tags_3">
undesired_tag
</label>
</div>






</div>
'''
# ---
66 changes: 66 additions & 0 deletions lacommunaute/forum/tests/test_forum_updateview.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
from io import BytesIO

import pytest # noqa
from django.conf import settings
from django.core.files.uploadedfile import SimpleUploadedFile
from django.urls import reverse
from faker import Faker
from PIL import Image
from pytest_django.asserts import assertContains
from taggit.models import Tag

from lacommunaute.forum.factories import CategoryForumFactory, ForumFactory
from lacommunaute.users.factories import UserFactory
from lacommunaute.utils.testing import parse_response_to_soup, reset_model_sequence_fixture


faker = Faker(settings.LANGUAGE_CODE)

reset_tag_sequence = pytest.fixture(reset_model_sequence_fixture(Tag))


@pytest.fixture
Expand Down Expand Up @@ -97,3 +105,61 @@ def test_certified_forum(client, db):

forum.refresh_from_db()
assert forum.certified is True


def test_selected_tags_are_preloaded(client, db, reset_tag_sequence, snapshot):
client.force_login(UserFactory(is_superuser=True))
forum = ForumFactory(with_tags=["iae", "siae", "prescripteur"])
Tag.objects.create(name="undesired_tag")
url = reverse("forum_extension:edit_forum", kwargs={"pk": forum.pk, "slug": forum.slug})

response = client.get(url)
assert response.status_code == 200

content_tags = parse_response_to_soup(
response, selector="#div_id_tags", replace_in_href=[tag for tag in Tag.objects.all()]
)
assert str(content_tags) == snapshot(name="selected_tags_preloaded")


def test_added_tags_are_saved(client, db):
client.force_login(UserFactory(is_superuser=True))
forum = ForumFactory()

Tag.objects.bulk_create([Tag(name=tag, slug=tag) for tag in [faker.word() for _ in range(3)]])
tags_list = [faker.word() for i in range(2)]

url = reverse("forum_extension:edit_forum", kwargs={"pk": forum.pk, "slug": forum.slug})
response = client.post(
url,
data={
"name": forum.name,
"short_description": forum.short_description,
"description": forum.description.raw,
"tags": [Tag.objects.first().pk],
"new_tags": ", ".join(tags_list),
},
)

assert response.status_code == 302

forum.refresh_from_db()
assert all(tag in [tag.name for tag in forum.tags.all()] for tag in [Tag.objects.first().name] + tags_list)


def test_update_forum_without_tag(client, db):
client.force_login(UserFactory(is_superuser=True))
forum = ForumFactory()
url = reverse("forum_extension:edit_forum", kwargs={"pk": forum.pk, "slug": forum.slug})
response = client.post(
url,
data={
"name": forum.name,
"short_description": forum.short_description,
"description": forum.description.raw,
},
)
assert response.status_code == 302

forum.refresh_from_db()
assert forum.tags.count() == 0
2 changes: 2 additions & 0 deletions lacommunaute/forum/tests/tests_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,5 @@ def test_form_field():
assert not form.fields["description"].required
assert not form.fields["image"].required
assert not form.fields["certified"].required
assert not form.fields["tags"].required
assert not form.fields["new_tags"].required
3 changes: 3 additions & 0 deletions lacommunaute/templates/forum/partials/forum_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
{% include "partials/form_field.html" with field=form.description %}
{% include "partials/form_field.html" with field=form.image %}
{% include "partials/form_field.html" with field=form.certified %}
<hr>
{% include "partials/form_field.html" with field=form.tags %}
{% include "partials/form_field.html" with field=form.new_tags %}
<hr class="mb-5">
<div class="form-actions form-row">
<div class="form-group col-auto">
Expand Down

0 comments on commit 7f435bb

Please sign in to comment.