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
67 changes: 34 additions & 33 deletions lacommunaute/forum/tests/tests_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def test_context(self):
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(list(response.context_data["active_tag"]), [])

for filter, label in Filters.choices:
with self.subTest(filter=filter, label=label):
Expand All @@ -99,11 +99,8 @@ def test_context(self):
self.assertEqual(response.context_data["active_filter_name"], Filters.ALL.label)

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 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
Original file line number Diff line number Diff line change
Expand Up @@ -189,11 +189,38 @@
</div>
'''
# ---
# name: TestTopicListView.test_clickable_tags[10-?page=2-clickable_tags_page2][clickable_tags_page2]
'<a class="tag bg-info-lighter text-info" href="/topics/?tag=tag&amp;filter=">tag</a>'
# ---
# name: TestTopicListView.test_clickable_tags[None-None-clickable_tags_page1][clickable_tags_page1]
'<a class="tag bg-info-lighter text-info" href="/topics/?tag=tag&amp;filter=">tag</a>'
# ---
# 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>'
'<a class="tag bg-info-lighter text-info" href="/topics/?tag=tag&amp;filter=">tag</a>'
# ---
# 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>'
'<a class="tag bg-info-lighter text-info" href="/topics/?tag=tag&amp;filter=">tag</a>'
# ---
# 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="filtertopics-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="filtertopics-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="filtertopics-button">Réponse certifiée</button>
</li>

</ul>
</div>
'''
# ---
# name: test_breadcrumbs_on_topic_view[discussion_area_topic]
'''
Expand Down Expand Up @@ -259,6 +286,24 @@
</nav>
'''
# ---
# name: test_queryset_for_tagged_topic[1][1-tagged_topics]
'''
<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[2][2-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>
'''
# ---
# name: test_queryset_for_tagged_topic[tagged_topic]
'''
<div class="flex-grow-1" id="topic-list-filter-header">
Expand Down
84 changes: 47 additions & 37 deletions lacommunaute/forum_conversation/tests/tests_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from faker import Faker
from machina.core.db.models import get_model
from machina.core.loading import get_class

from pytest_django.asserts import assertContains, assertNotContains
from taggit.models import Tag

Expand Down Expand Up @@ -770,34 +769,36 @@ def test_numqueries(self):
self.assertEqual(response.status_code, 200)


@pytest.fixture(name="topics_url")
def fixture_topics_url():
return reverse("forum_conversation_extension:topics")


@pytest.mark.parametrize("tag", ["lower", "UPPER"])
def test_queryset_filtered_on_tag(client, db, tag):
def test_queryset_filtered_on_tag(client, db, tag, topics_url):
forum = ForumFactory(with_public_perms=True)
other_topic = TopicFactory(with_post=True, forum=forum)
tagged_topic = TopicFactory(with_post=True, forum=forum, with_tags=[tag])

response = client.get(reverse("forum_conversation_extension:topics"), data={"tags": tag})
response = client.get(topics_url, data={"tag": tag})
assert response.context_data["paginator"].count == 1
assertContains(response, tagged_topic.subject)
assertNotContains(response, other_topic.subject)


def test_queryset_for_tagged_topic(client, db, snapshot):
@pytest.mark.parametrize("num_of_tagged_topics", [1, 2])
def test_queryset_for_tagged_topic(client, db, num_of_tagged_topics, topics_url, snapshot):
tags = ["buckley", "jeff"]
tagged_topic = TopicFactory(with_post=True, with_tags=tags)
tagged_topics = TopicFactory.create_batch(num_of_tagged_topics, with_post=True, with_tags=tags)
untagged_topic = TopicFactory(with_post=True)

response = client.get(reverse("forum_conversation_extension:topics"), {"tags": tags[0]})
response = client.get(topics_url, {"tag": tags[0]})
content = parse_response_to_soup(response, selector="#topic-list-filter-header")
assert str(content) == snapshot(name="tagged_topic")
assertContains(response, tagged_topic.subject)
assert str(content) == snapshot(name=f"{num_of_tagged_topics}-tagged_topics")
for tagged_topic in tagged_topics:
assertContains(response, tagged_topic.subject)
assertNotContains(response, untagged_topic.subject)

TopicFactory(with_post=True, with_tags=tags)
response = client.get(reverse("forum_conversation_extension:topics"), {"tags": tags[0]})
content = parse_response_to_soup(response, selector="#topic-list-filter-header")
assert str(content) == snapshot(name="tagged_topics")


def test_breadcrumbs_on_topic_view(client, db, snapshot):
discussion_area_forum = ForumFactory(with_public_perms=True)
Expand Down Expand Up @@ -875,7 +876,7 @@ def test_context(self):
self.assertEqual(response.context_data["loadmoretopic_url"], reverse("forum_conversation_extension:topics"))
self.assertEqual(response.context_data["forum"], self.forum)
self.assertEqual(response.context_data["active_filter_name"], Filters.ALL.label)
self.assertEqual(response.context_data["active_tags"], "")
self.assertEqual(list(response.context_data["active_tag"]), [])

for filter, label in Filters.choices:
with self.subTest(filter=filter, label=label):
Expand All @@ -891,9 +892,9 @@ def test_context(self):

def test_context_with_tag(self):
tags = [Tag.objects.create(name=faker.sentence()) for i in range(2)]
response = self.client.get(self.url, {"tags": ",".join([tag.slug for tag in tags])})
self.assertEqual(response.context_data["active_tags"], ",".join([tag.slug for tag in tags]))
self.assertEqual(response.context_data["active_tags_label"], " ou ".join([tag.name for tag in tags]))
for tag in tags:
response = self.client.get(self.url, {"tag": tag.slug})
self.assertEqual(response.context_data["active_tag"], tag)

def test_queryset(self):
response = self.client.get(self.url)
Expand Down Expand Up @@ -976,13 +977,6 @@ def test_filter_dropdown_visibility(self):
self.assertNotContains(response, '<div class="dropdown-menu dropdown-menu-end" id="filterTopicsDropdown">')
self.assertEqual(response.context_data["filter_dropdown_endpoint"], None)

def test_filter_dropdown_with_tags(self):
tag = Tag.objects.create(name=faker.words(nb=3))
response = self.client.get(self.url + f"?tags={tag.slug}")
self.assertContains(response, f'hx-get="/topics/?filter=ALL&tags={tag.slug}"')
self.assertContains(response, f'hx-get="/topics/?filter=NEW&tags={tag.slug}"')
self.assertContains(response, f'hx-get="/topics/?filter=CERTIFIED&tags={tag.slug}"')

def test_template_name(self):
response = self.client.get(self.url)
self.assertTemplateUsed(response, "forum_conversation/topics_public.html")
Expand All @@ -991,33 +985,49 @@ def test_template_name(self):
self.assertTemplateUsed(response, "forum_conversation/topic_list.html")


@pytest.fixture(name="public_forum_with_topic")
def fixture_public_forum_with_topic(db):
forum = ForumFactory(with_public_perms=True)
TopicFactory(with_post=True, forum=forum, with_tags=["tag"])
return forum


class TestTopicListView:
def test_clickable_tags(self, client, db, snapshot):
@pytest.mark.parametrize(
"num_of_topics_before_tagged_topic,query_param,snapshot_name",
[(None, None, "clickable_tags_page1"), (10, "?page=2", "clickable_tags_page2")],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pour te faciliter la vie, tu pourrais définir les query params vide avec "". 🤷

)
def test_clickable_tags(
self, client, db, topics_url, num_of_topics_before_tagged_topic, query_param, snapshot_name, snapshot
):
forum = ForumFactory(with_public_perms=True)

TopicFactory(with_post=True, forum=forum, with_tags=["tag"])
if num_of_topics_before_tagged_topic:
# add 10 Topics before the tagged one to put it on the second page
TopicFactory.create_batch(num_of_topics_before_tagged_topic, with_post=True, forum=forum)

response = client.get(reverse("forum_conversation_extension:topics"))
url = topics_url + query_param if query_param else topics_url
response = client.get(url)
assert response.status_code == 200
assert str(parse_response_to_soup(response, selector="a.tag")) == snapshot(name="clickable_tags_page1")

# add 10 Topics before the tagged one to put it on the second page
TopicFactory.create_batch(10, with_post=True, forum=forum)
assert str(parse_response_to_soup(response, selector="a.tag")) == snapshot(name=snapshot_name)

response = client.get(reverse("forum_conversation_extension:topics") + "?page=2")
assert response.status_code == 200
assert str(parse_response_to_soup(response, selector="a.tag")) == snapshot(name="clickable_tags_page2")
def test_filter_dropdown_with_tags(self, client, db, public_forum_with_topic, topics_url, snapshot):
response = client.get(topics_url + "?tag=tag")
content = parse_response_to_soup(response, selector="#filterTopicsDropdown")
assert str(content) == snapshot(name="filter_dropdown_with_tags")


class TestPosterTemplate:
def test_topic_in_topics_view(self, client, db, snapshot):
def test_topic_in_topics_view(self, client, db, topics_url, snapshot):
topic = TopicFactory(with_post=True, poster=UserFactory(first_name="Jeff", last_name="Buckley"))
response = client.get(reverse("forum_conversation_extension:topics"))
response = client.get(topics_url)
soup = parse_response_to_soup(
response, replace_in_href=[(topic.poster.username, "poster_username")], selector=".poster-infos"
)
assert str(soup) == snapshot(name="topic_in_topics_view")

def test_topic_from_other_public_forum_in_topics_view(self, client, db, snapshot):
def test_topic_from_other_public_forum_in_topics_view(self, client, db, topics_url, snapshot):
# first_public_forum
ForumFactory(with_public_perms=True)

Expand All @@ -1026,7 +1036,7 @@ def test_topic_from_other_public_forum_in_topics_view(self, client, db, snapshot
forum=ForumFactory(with_public_perms=True, name="Abby's Forum"),
poster=UserFactory(first_name="Alan", last_name="Turing"),
)
response = client.get(reverse("forum_conversation_extension:topics"))
response = client.get(topics_url)
soup = parse_response_to_soup(
response,
replace_in_href=[
Expand Down
23 changes: 9 additions & 14 deletions lacommunaute/forum_conversation/view_mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,21 @@ def filter_queryset(self, qs):
elif filter == Filters.CERTIFIED:
qs = qs.filter(certified_post__isnull=False)

if self.get_tags():
qs = qs.filter(tags__in=self.get_tags())
if self.get_tag():
qs = qs.filter(tags=self.get_tag())

return qs

def get_tags(self, flat=None):
if not hasattr(self, "tags"):
def get_tag(self):
if not hasattr(self, "tag"):
try:
request_tags = self.request.GET["tags"]
request_tag = self.request.GET["tag"]
except KeyError:
self.tags = Tag.objects.none()
self.tag = Tag.objects.none()
else:
self.tags = Tag.objects.filter(slug__in=request_tags.lower().split(","))
self.tag = Tag.objects.filter(slug=request_tag.lower()).first()

if flat == "name":
return " ou ".join(tag.name for tag in self.tags)
if flat == "slug":
return ",".join(tag.slug for tag in self.tags)
return self.tags
return self.tag

def get_load_more_url(self, url):
"""
Expand All @@ -50,8 +46,7 @@ def get_topic_filter_context(self):
active_filter = self.request.GET.get("filter", Filters.ALL)

return {
"active_tags": self.get_tags(flat="slug"),
"active_tags_label": self.get_tags(flat="name"),
"active_tag": self.get_tag(),
"active_filter_name": getattr(Filters, active_filter, Filters.ALL).label,
"filters": Filters.choices,
}
Loading