Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(tags): afficher les étiquettes dans les fiches pratiques #747

Closed
wants to merge 10 commits into from
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
17 changes: 17 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,27 @@ 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_tag = CharField(required=False, label="Ajouter un tag")

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(self.cleaned_data["new_tag"]) if self.cleaned_data.get("new_tag") 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 badge badge-sm rounded-pill 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 badge badge-sm rounded-pill 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 badge badge-sm rounded-pill 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 badge badge-sm rounded-pill bg-info-lighter text-info" for="id_tags_3">
undesired_tag
</label>
</div>






</div>
'''
# ---
49 changes: 49 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,44 @@ 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)]])
# new_tag is not in the database
new_tag = faker.word()

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_tag": new_tag,
},
)

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, new_tag])
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_tag"].required
16 changes: 6 additions & 10 deletions lacommunaute/forum_conversation/forms.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import F
from django.forms import CharField, CheckboxSelectMultiple, HiddenInput, ModelMultipleChoiceField
from machina.apps.forum_conversation.forms import PostForm as AbstractPostForm, TopicForm as AbstractTopicForm
Expand Down Expand Up @@ -55,22 +54,19 @@ class TopicForm(CreateUpdatePostMixin, AbstractTopicForm):
tags = ModelMultipleChoiceField(
label="", queryset=Tag.objects.all(), widget=CheckboxSelectMultiple, required=False
)
new_tag = CharField(required=False, label="Ajouter un tag")

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
try:
if hasattr(self.instance, "topic"):
self.fields["tags"].initial = self.instance.topic.tags.all()
except ObjectDoesNotExist:
pass
if self.instance.pk:
self.fields["tags"].initial = self.instance.topic.tags.all()

def save(self):
post = super().save()
post.topic.tags.set(self.cleaned_data["tags"])

if self.user.is_anonymous:
post.username = self.cleaned_data["username"]
post.topic.tags.set(self.cleaned_data["tags"])
post.topic.tags.add(self.cleaned_data["new_tag"]) if self.cleaned_data.get("new_tag") else None
post.username = self.cleaned_data["username"] if self.user.is_anonymous else None

post.save()

return post
18 changes: 17 additions & 1 deletion lacommunaute/forum_conversation/tests/tests_views.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import pytest
import pytest # noqa
from django.conf import settings
from django.contrib.messages.api import get_messages
from django.contrib.messages.middleware import MessageMiddleware
Expand Down Expand Up @@ -255,6 +255,22 @@ def test_redirections_on_documentation_forum(self, db, client, snapshot):
content = parse_response_to_soup(response, selector="#div_id_content")
assert str(content) == snapshot(name="topic_create")

def test_add_a_new_tag(self, db, client):
forum = ForumFactory(with_public_perms=True)
client.force_login(UserFactory())
tag = faker.word()
response = client.post(
reverse("forum_conversation:topic_create", kwargs={"forum_pk": forum.pk, "forum_slug": forum.slug}),
{
"subject": faker.sentence(),
"content": faker.paragraph(nb_sentences=5),
"new_tag": tag,
},
follow=True,
)
assert response.status_code == 200
assert forum.topics.first().tags.filter(name=tag).exists()


class TopicUpdateViewTest(TestCase):
@classmethod
Expand Down
6 changes: 2 additions & 4 deletions lacommunaute/templates/forum/forum_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,9 @@
<div class="s-title-01__container container">
<div class="s-title-01__row row">
<div class="s-title-01__col col-12">
{% include "forum/partials/tags.html" with tags=forum.tags.all only %}
<h1>{{ forum.name }}</h1>
{% if user.is_superuser %}
<a href="{% url 'forum_extension:edit_forum' forum.slug forum.id %}"><small>Mettre à jour</small></a>
{% endif %}
{% if forum.short_description %}<h2 class="mt-3">{{ forum.short_description }}</h2>{% endif %}
{% if forum.short_description %}<h2 class="mt-3 fs-base">{{ forum.short_description }}</h2>{% endif %}
</div>
</div>
</div>
Expand Down
9 changes: 1 addition & 8 deletions lacommunaute/templates/forum/forum_documentation.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,7 @@
<div class="col-12 col-lg-9">
<div class="row align-items-sm-center mb-3">
<div class="col-12 col-sm" id="updated_area">
{% if forum.certified %}
<span class="badge badge-xs rounded-pill bg-communaute text-white text-decoration-none">
<i class="ri-checkbox-circle-fill"></i>
Certifiée par la communauté de l'inclusion le {{ forum.updated|date:"d/m/Y" }}
</span>
{% else %}
<span class="fs-sm">Fiche mise à jour le {{ forum.updated|date:"d/m/Y" }}</span>
{% endif %}
{% include "forum/partials/updated_certified.html" with forum=forum user=user only %}
</div>
<div class="col-12 col-sm-auto">
{% include "partials/upvotes.html" with obj=forum kind="forum" %}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
{% extends "forum/forum_detail.html" %}
{% block forum_head_content %}
{{ block.super }}
{% if user.is_superuser %}
<a href="{% url 'forum_extension:edit_forum' forum.slug forum.id %}"><small>Mettre à jour</small></a>
{% endif %}
{% endblock %}
{% block subforum_list %}
<div class="row mt-4" id="documentation-category-subforums">
{% for node in sub_forums.top_nodes %}
Expand Down
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_tag %}
<hr class="mb-5">
<div class="form-actions form-row">
<div class="form-group col-auto">
Expand Down
5 changes: 5 additions & 0 deletions lacommunaute/templates/forum/partials/tags.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div class="mb-3">
{% for tag in tags %}
<span class="badge badge-md rounded-pill bg-info-lighter text-info">{{ tag.name }}</span>
{% endfor %}
</div>
11 changes: 11 additions & 0 deletions lacommunaute/templates/forum/partials/updated_certified.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{% if forum.certified %}
<span class="badge badge-md rounded-pill bg-communaute-light text-communaute text-decoration-none">
<i class="ri-checkbox-circle-fill"></i>
Certifiée par la communauté de l'inclusion le {{ forum.updated|date:"d/m/Y" }}
</span>
{% else %}
<span class="fs-sm">Fiche mise à jour le {{ forum.updated|date:"d/m/Y" }}</span>
{% endif %}
{% if user.is_superuser %}
<a href="{% url 'forum_extension:edit_forum' forum.slug forum.id %}"><small>Mettre à jour</small></a>
{% endif %}
Loading
Loading