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

fix: filtrage des questions en utilisant les étiquettes #794

Merged
merged 10 commits into from
Oct 9, 2024
89 changes: 45 additions & 44 deletions lacommunaute/forum/tests/tests_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,27 +83,24 @@ def test_context(self):
self.assertEqual(response.context_data["loadmoretopic_url"], loadmoretopic_url)
self.assertEqual(response.context_data["forum"], self.forum)
self.assertIsNone(response.context_data["rating"])
self.assertEqual(response.context_data["active_filter_name"], Filters.ALL.label)
self.assertEqual(response.context_data["active_tags"], "")
self.assertEqual(response.context_data["active_filter"], Filters.ALL)
self.assertEqual(list(response.context_data["active_tag"]), [])

for filter, label in Filters.choices:
with self.subTest(filter=filter, label=label):
response = self.client.get(self.url + f"?filter={filter}")
for filter in Filters:
with self.subTest(filter=filter):
response = self.client.get(self.url + f"?filter={filter.value}")
self.assertEqual(
response.context_data["loadmoretopic_url"],
loadmoretopic_url + f"?filter={filter}",
loadmoretopic_url + f"?filter={filter.value}",
)
self.assertEqual(response.context_data["active_filter_name"], label)
self.assertEqual(response.context_data["active_filter"], filter)

response = self.client.get(self.url + "?filter=FAKE")
self.assertEqual(response.context_data["active_filter_name"], Filters.ALL.label)
self.assertEqual(response.context_data["active_filter"], Filters.ALL)

tag = Tag.objects.create(name="tag_1", slug="tag_1")
response = self.client.get(self.url + f"?tags=nonexistant,{tag.name}")
self.assertIn(tag.slug, response.context_data["active_tags"])
self.assertNotIn("nonexistant", response.context_data["active_tags"])
self.assertIn(tag.name, response.context_data["active_tags_label"])
self.assertNotIn("nonexistant", response.context_data["active_tags_label"])
response = self.client.get(self.url + f"?tag={tag.name}")
self.assertEqual(tag, response.context_data["active_tag"])

def test_template_name(self):
response = self.client.get(self.url)
Expand Down Expand Up @@ -358,7 +355,7 @@ def test_filtered_queryset_on_tag(self):

with self.assertNumQueries(20):
response = self.client.get(
reverse("forum_extension:forum", kwargs={"pk": self.forum.pk, "slug": self.forum.slug}), {"tags": tag}
reverse("forum_extension:forum", kwargs={"pk": self.forum.pk, "slug": self.forum.slug}), {"tag": tag}
)
self.assertContains(response, topic.subject)
self.assertNotContains(response, self.topic.subject)
Expand All @@ -368,14 +365,14 @@ def test_queryset_for_unanswered_topics(self):
response = self.client.get(self.url + f"?filter={Filters.NEW.value}")
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context_data["paginator"].count, 0)
self.assertEqual(response.context_data["active_filter_name"], Filters.NEW.label)
self.assertEqual(response.context_data["active_filter"], Filters.NEW)

new_topic = TopicFactory(with_post=True, forum=self.forum)

response = self.client.get(self.url + f"?filter={Filters.NEW.value}")
self.assertEqual(response.context_data["paginator"].count, 1)
self.assertContains(response, new_topic.subject, status_code=200)
self.assertEqual(response.context_data["active_filter_name"], Filters.NEW.label)
self.assertEqual(response.context_data["active_filter"], Filters.NEW)

for topic in Topic.objects.exclude(id=new_topic.id):
with self.subTest(topic):
Expand All @@ -385,15 +382,15 @@ def test_queryset_for_certified_topics(self):
response = self.client.get(self.url + f"?filter={Filters.CERTIFIED.value}")
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context_data["paginator"].count, 0)
self.assertEqual(response.context_data["active_filter_name"], Filters.CERTIFIED.label)
self.assertEqual(response.context_data["active_filter"], Filters.CERTIFIED)

certified_topic = TopicFactory(with_post=True, with_certified_post=True, forum=self.forum)

response = self.client.get(self.url + f"?filter={Filters.CERTIFIED.value}")
self.assertEqual(response.context_data["paginator"].count, 1)
self.assertContains(response, certified_topic.subject, status_code=200)
self.assertContains(response, certified_topic.certified_post.post.content.raw[:100])
self.assertEqual(response.context_data["active_filter_name"], Filters.CERTIFIED.label)
self.assertEqual(response.context_data["active_filter"], Filters.CERTIFIED)

for topic in Topic.objects.exclude(id=certified_topic.id):
with self.subTest(topic):
Expand Down Expand Up @@ -608,6 +605,22 @@ def test_documentation_forum_with_partner(self, client, db, snapshot, documentat
assert str(content.select("#partner_area")) == snapshot(name="documentation_forum_with_partner")


@pytest.fixture(name="documentation_category_forum_with_descendants")
def documentation_category_forum_with_descendants_fixture():
tags = [faker.word() for _ in range(3)]
category_forum = CategoryForumFactory(with_public_perms=True)
first_child = ForumFactory(parent=category_forum, with_public_perms=True, with_tags=[tags[0]])
second_child = ForumFactory(parent=category_forum, with_public_perms=True, with_tags=[tags[0], tags[1]])
third_child = ForumFactory(parent=category_forum, with_public_perms=True, with_tags=[tags[2]])
# forum without tags
ForumFactory(parent=category_forum, with_public_perms=True)

# edge case: grand_child is filtered out. No actual use case to display them in the subforum list
ForumFactory(parent=third_child, with_public_perms=True, with_tags=[tags[2]])

return category_forum, tags[0], [first_child, second_child]


class TestDocumentationCategoryForumContent:
def test_documentation_category_subforum_list(
self, client, db, snapshot, reset_forum_sequence, documentation_forum
Expand Down Expand Up @@ -636,36 +649,24 @@ def test_documentation_category_foot_content(
assert len(add_documentation_control) == 1
assert str(add_documentation_control[0]) == snapshot(name="documentation_category_add_file_control")

def test_filter_subforums_on_tags(self, client, db):
tags = [faker.word() for _ in range(3)]
category_forum = CategoryForumFactory(with_public_perms=True)
first_child = ForumFactory(parent=category_forum, with_public_perms=True, with_tags=[tags[0]])
second_child = ForumFactory(parent=category_forum, with_public_perms=True, with_tags=[tags[0], tags[1]])
third_child = ForumFactory(parent=category_forum, with_public_perms=True, with_tags=[tags[2]])
# forum without tags
ForumFactory(parent=category_forum, with_public_perms=True)

# edge case: grand_child is filtered out. No actual use case to display them in the subforum list
ForumFactory(parent=third_child, with_public_perms=True, with_tags=[tags[2]])

# no filter
response = client.get(category_forum.get_absolute_url())
assert response.status_code == 200
assert [node.obj for node in response.context_data["sub_forums"].top_nodes] == list(
category_forum.get_children()
)
@pytest.mark.parametrize("filtered, sub_forums_count", [(False, 4), (True, 2)])
def test_filter_subforums_on_tags(
self, client, db, documentation_category_forum_with_descendants, filtered, sub_forums_count
):
category_forum, first_tag, subforums_with_first_tag = documentation_category_forum_with_descendants

# filter on one tag
response = client.get(category_forum.get_absolute_url() + f"?forum_tag={tags[0]}")
assert response.status_code == 200
assert set([node.obj for node in response.context_data["sub_forums"].top_nodes]) == set(
[first_child, second_child]
expected = subforums_with_first_tag if filtered else list(category_forum.get_children())
url = (
category_forum.get_absolute_url() + f"?forum_tag={first_tag}"
if filtered
else category_forum.get_absolute_url()
)

# filtering on multiple tags is not supported yet
response = client.get(category_forum.get_absolute_url() + f"?forum_tag={tags[1]},{tags[2]}")
response = client.get(url)
assert response.status_code == 200
assert set([node.obj for node in response.context_data["sub_forums"].top_nodes]) == set([])
sub_forums = [node.obj for node in response.context_data["sub_forums"].top_nodes]
assert sub_forums == expected
assert len(sub_forums) == sub_forums_count

def test_show_subforum_tag(self, client, db, snapshot, reset_forum_sequence):
category_forum = CategoryForumFactory(with_public_perms=True, for_snapshot=True)
Expand Down
6 changes: 3 additions & 3 deletions lacommunaute/forum_conversation/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@


class Filters(models.TextChoices):
ALL = "ALL", "Les plus récentes"
NEW = "NEW", "En attente de réponse"
CERTIFIED = "CERTIFIED", "Réponse certifiée"
ALL = "ALL", "les plus récentes"
NEW = "NEW", "en attente de réponse"
CERTIFIED = "CERTIFIED", "avec une réponse certifiée"
7 changes: 7 additions & 0 deletions lacommunaute/forum_conversation/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ def with_tags(self, create, extracted, **kwargs):
for tag in extracted:
self.tags.add(tag)

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

PostFactory(topic=self)


class AnonymousTopicFactory(TopicFactory):
poster = None
Expand Down
115 changes: 93 additions & 22 deletions lacommunaute/forum_conversation/tests/__snapshots__/tests_views.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -189,11 +189,100 @@
</div>
'''
# ---
# name: TestTopicListView.test_clickable_tags[clickable_tags_page1]
'<a class="tag bg-info-lighter text-info" href="/topics/?tags=tag&amp;page=1">tag</a>'
# name: TestTopicListView.test_clickable_tags[10-query_param1-clickable_tags_page2][clickable_tags_page2]
'<button class="tag bg-info-lighter text-info matomo-event" data-matomo-action="filter" data-matomo-category="engagement" data-matomo-option="topics" hx-get="/topics/?tag=tag&amp;filter=ALL" hx-push-url="true" hx-swap="outerHTML" hx-target="#topicsarea" id="filtertopics-button">tag</button>'
# ---
# name: TestTopicListView.test_clickable_tags[clickable_tags_page2]
'<a class="tag bg-info-lighter text-info" href="/topics/?tags=tag&amp;page=1">tag</a>'
# name: TestTopicListView.test_clickable_tags[None-query_param0-clickable_tags_page1][clickable_tags_page1]
'<button class="tag bg-info-lighter text-info matomo-event" data-matomo-action="filter" data-matomo-category="engagement" data-matomo-option="topics" hx-get="/topics/?tag=tag&amp;filter=ALL" hx-push-url="true" hx-swap="outerHTML" hx-target="#topicsarea" id="filtertopics-button">tag</button>'
# ---
# name: TestTopicListView.test_filter_dropdown_with_tags[filter_dropdown_with_tags]
'''
<div class="dropdown-menu dropdown-menu-end" id="filterTopicsDropdown">
<ul class="list-unstyled">

<li>
<button class="dropdown-item matomo-event" data-matomo-action="filter" data-matomo-category="engagement" data-matomo-option="topics" hx-get="/topics/?filter=ALL&amp;tag=tag" hx-push-url="true" hx-swap="outerHTML" hx-target="#topicsarea" id="filter-ontag-button">les plus récentes</button>
</li>

<li>
<button class="dropdown-item matomo-event" data-matomo-action="filter" data-matomo-category="engagement" data-matomo-option="topics" hx-get="/topics/?filter=NEW&amp;tag=tag" hx-push-url="true" hx-swap="outerHTML" hx-target="#topicsarea" id="filter-ontag-button">en attente de réponse</button>
</li>

<li>
<button class="dropdown-item matomo-event" data-matomo-action="filter" data-matomo-category="engagement" data-matomo-option="topics" hx-get="/topics/?filter=CERTIFIED&amp;tag=tag" hx-push-url="true" hx-swap="outerHTML" hx-target="#topicsarea" id="filter-ontag-button">avec une réponse certifiée</button>
</li>

</ul>
</div>
'''
# ---
# name: TestTopicListView.test_queryset_on_filter[ALL-<lambda>-None][ALL-tagged_topics]
'''
<div class="flex-grow-1" id="topic-list-filter-header">
<span class="h5 m-0">2 questions</span>
les plus récentes

</div>
'''
# ---
# name: TestTopicListView.test_queryset_on_filter[CERTIFIED-<lambda>-<lambda>][CERTIFIED-tagged_topics]
'''
<div class="flex-grow-1" id="topic-list-filter-header">
<span class="h5 m-0">1 question</span>
avec une réponse certifiée

</div>
'''
# ---
# name: TestTopicListView.test_queryset_on_filter[NEW-<lambda>-<lambda>][NEW-tagged_topics]
'''
<div class="flex-grow-1" id="topic-list-filter-header">
<span class="h5 m-0">2 questions</span>
en attente de réponse

</div>
'''
# ---
# name: TestTopicListView.test_queryset_on_tag[-<lambda>-None][-tagged_topics]
'''
<div class="flex-grow-1" id="topic-list-filter-header">
<span class="h5 m-0">2 questions</span>
les plus récentes

</div>
'''
# ---
# name: TestTopicListView.test_queryset_on_tag[buckley-<lambda>-<lambda>][buckley-tagged_topics]
'''
<div class="flex-grow-1" id="topic-list-filter-header">
<span class="h5 m-0">1 question</span>
les plus récentes

<span class="fs-sm">
sous l'étiquette
<button aria-label="Supprimer ce filtre" class="tag bg-info text-white matomo-event" data-bs-placement="top" data-bs-title="Supprimer ce filtre" data-bs-toggle="tooltip" data-matomo-action="unfilter" data-matomo-category="engagement" data-matomo-option="topics" hx-get="/topics/?filter=ALL" hx-push-url="true" hx-swap="outerHTML" hx-target="#topicsarea" id="unfilter-ontag-button">
<i class="ri-close-fill ri-xs"></i>buckley
</button>
</span>

</div>
'''
# ---
# name: TestTopicListView.test_queryset_on_tag[tag-<lambda>-<lambda>][tag-tagged_topics]
'''
<div class="flex-grow-1" id="topic-list-filter-header">
<span class="h5 m-0">2 questions</span>
les plus récentes

<span class="fs-sm">
sous l'étiquette
<button aria-label="Supprimer ce filtre" class="tag bg-info text-white matomo-event" data-bs-placement="top" data-bs-title="Supprimer ce filtre" data-bs-toggle="tooltip" data-matomo-action="unfilter" data-matomo-category="engagement" data-matomo-option="topics" hx-get="/topics/?filter=ALL" hx-push-url="true" hx-swap="outerHTML" hx-target="#topicsarea" id="unfilter-ontag-button">
<i class="ri-close-fill ri-xs"></i>tag
</button>
</span>

</div>
'''
# ---
# name: test_breadcrumbs_on_topic_view[discussion_area_topic]
'''
Expand Down Expand Up @@ -259,21 +348,3 @@
</nav>
'''
# ---
# name: test_queryset_for_tagged_topic[tagged_topic]
'''
<div class="flex-grow-1" id="topic-list-filter-header">
<span class="h5 m-0">1 question
avec l'étiquette buckley
</span>
</div>
'''
# ---
# name: test_queryset_for_tagged_topic[tagged_topics]
'''
<div class="flex-grow-1" id="topic-list-filter-header">
<span class="h5 m-0">2 questions
avec l'étiquette buckley
</span>
</div>
'''
# ---
Loading
Loading