From c1c0e064bf63ebcfd5c8107775fa32ca9352454e Mon Sep 17 00:00:00 2001 From: vincent porte Date: Thu, 20 Jul 2023 11:17:44 +0200 Subject: [PATCH] feat(forum_factories): add certifiedpost view, urls, tests and factories after having migrated model --- lacommunaute/forum/tests/tests_views.py | 14 +-- lacommunaute/forum_conversation/factories.py | 8 +- .../forum_conversation/tests/tests_views.py | 41 ++++----- .../tests/tests_views_htmx.py | 92 ++++++++++++++++--- lacommunaute/forum_conversation/urls.py | 2 + lacommunaute/forum_conversation/views_htmx.py | 51 +++++++++- .../partials/post_certified_actions.html | 2 +- 7 files changed, 166 insertions(+), 44 deletions(-) diff --git a/lacommunaute/forum/tests/tests_views.py b/lacommunaute/forum/tests/tests_views.py index 75e5a1015..72a411b2d 100644 --- a/lacommunaute/forum/tests/tests_views.py +++ b/lacommunaute/forum/tests/tests_views.py @@ -7,7 +7,7 @@ from lacommunaute.forum.factories import CategoryForumFactory, ForumFactory from lacommunaute.forum.views import ForumView -from lacommunaute.forum_conversation.factories import PostFactory, TopicFactory +from lacommunaute.forum_conversation.factories import CertifiedPostFactory, PostFactory, TopicFactory from lacommunaute.forum_conversation.forms import PostForm from lacommunaute.forum_conversation.models import Topic from lacommunaute.users.factories import UserFactory @@ -260,14 +260,14 @@ def test_certified_post_display(self): self.assertNotContains(response, "Certifié par la Plateforme de l'Inclusion") # certify post - # CertifiedPostFactory(topic=self.topic, post=post, user=self.user) + CertifiedPostFactory(topic=self.topic, post=post, user=self.user) - # response = self.client.get(self.url) + response = self.client.get(self.url) - # self.assertEqual(response.status_code, 200) - # self.assertContains(response, truncatechars_html(post.content.rendered, 200)) - # self.assertContains(response, topic_certified_post_url) - # self.assertContains(response, "Certifié par la Plateforme de l'Inclusion") + self.assertEqual(response.status_code, 200) + self.assertContains(response, truncatechars_html(post.content.rendered, 200)) + self.assertContains(response, topic_certified_post_url) + self.assertContains(response, "Certifié par la Plateforme de l'Inclusion") def test_loadmoretopic_url(self): loadmoretopic_url = reverse( diff --git a/lacommunaute/forum_conversation/factories.py b/lacommunaute/forum_conversation/factories.py index 72f8c1519..8e33a8b47 100644 --- a/lacommunaute/forum_conversation/factories.py +++ b/lacommunaute/forum_conversation/factories.py @@ -3,8 +3,7 @@ from lacommunaute.forum.factories import ForumFactory from lacommunaute.forum_conversation.forum_polls.factories import TopicPollVoteFactory -from lacommunaute.forum_conversation.models import Topic -from lacommunaute.forum_upvote.factories import CertifiedPostFactory +from lacommunaute.forum_conversation.models import CertifiedPost, Topic from lacommunaute.users.factories import UserFactory @@ -14,6 +13,11 @@ class PostFactory(BasePostFactory): poster = factory.SubFactory(UserFactory) +class CertifiedPostFactory(factory.django.DjangoModelFactory): + class Meta: + model = CertifiedPost + + class TopicFactory(BaseTopicFactory): forum = factory.SubFactory(ForumFactory) poster = factory.SubFactory(UserFactory) diff --git a/lacommunaute/forum_conversation/tests/tests_views.py b/lacommunaute/forum_conversation/tests/tests_views.py index 2a19a73ce..eb5915c26 100644 --- a/lacommunaute/forum_conversation/tests/tests_views.py +++ b/lacommunaute/forum_conversation/tests/tests_views.py @@ -15,7 +15,7 @@ from lacommunaute.forum.enums import Kind as ForumKind from lacommunaute.forum.factories import ForumFactory from lacommunaute.forum_conversation.enums import Filters -from lacommunaute.forum_conversation.factories import PostFactory, TopicFactory +from lacommunaute.forum_conversation.factories import CertifiedPostFactory, PostFactory, TopicFactory from lacommunaute.forum_conversation.forms import PostForm from lacommunaute.forum_conversation.models import Topic from lacommunaute.forum_conversation.views import PostDeleteView, TopicCreateView @@ -439,18 +439,18 @@ def test_post_has_upvote_by_user(self): self.assertEqual(response.status_code, 200) self.assertContains(response, '1') - # def test_certified_post_is_highlighted(self): - # post = PostFactory(topic=self.topic, poster=self.poster) - # self.client.force_login(self.poster) + def test_certified_post_is_highlighted(self): + post = PostFactory(topic=self.topic, poster=self.poster) + self.client.force_login(self.poster) - # response = self.client.get(self.url) - # self.assertEqual(response.status_code, 200) - # self.assertNotContains(response, "Certifié par la Plateforme de l'Inclusion") + response = self.client.get(self.url) + self.assertEqual(response.status_code, 200) + self.assertNotContains(response, "Certifié par la Plateforme de l'Inclusion") - # CertifiedPostFactory(topic=self.topic, post=post, user=self.poster) - # response = self.client.get(self.url) - # self.assertEqual(response.status_code, 200) - # self.assertContains(response, "Certifié par la Plateforme de l'Inclusion") + CertifiedPostFactory(topic=self.topic, post=post, user=self.poster) + response = self.client.get(self.url) + self.assertEqual(response.status_code, 200) + self.assertContains(response, "Certifié par la Plateforme de l'Inclusion") def test_has_tags(self): tag = f"tag_{faker.word()}" @@ -474,17 +474,16 @@ def test_edit_link_is_visible(self): self.assertEqual(response.status_code, 200) self.assertContains(response, reverse("forum_conversation:topic_update", kwargs=self.kwargs)) + def test_numqueries(self): + PostFactory.create_batch(10, topic=self.topic, poster=self.poster) + UpVoteFactory(post=self.topic.last_post, voter=UserFactory()) + CertifiedPostFactory(topic=self.topic, post=self.topic.last_post, user=UserFactory()) + self.client.force_login(self.poster) -# def test_numqueries(self): -# PostFactory.create_batch(10, topic=self.topic, poster=self.poster) -# UpVoteFactory(post=self.topic.last_post, voter=UserFactory()) -# CertifiedPostFactory(topic=self.topic, post=self.topic.last_post, user=UserFactory()) -# self.client.force_login(self.poster) - -# note vincentporte : to be optimized -# with self.assertNumQueries(44): -# response = self.client.get(self.url) -# self.assertEqual(response.status_code, 200) + # note vincentporte : to be optimized + with self.assertNumQueries(44): + response = self.client.get(self.url) + self.assertEqual(response.status_code, 200) class TopicListViewTest(TestCase): diff --git a/lacommunaute/forum_conversation/tests/tests_views_htmx.py b/lacommunaute/forum_conversation/tests/tests_views_htmx.py index a81e8b539..da5380502 100644 --- a/lacommunaute/forum_conversation/tests/tests_views_htmx.py +++ b/lacommunaute/forum_conversation/tests/tests_views_htmx.py @@ -7,9 +7,9 @@ from machina.core.loading import get_class from taggit.models import Tag -from lacommunaute.forum_conversation.factories import PostFactory, TopicFactory +from lacommunaute.forum_conversation.factories import CertifiedPostFactory, PostFactory, TopicFactory from lacommunaute.forum_conversation.forms import PostForm -from lacommunaute.forum_conversation.models import Topic +from lacommunaute.forum_conversation.models import CertifiedPost, Topic from lacommunaute.forum_conversation.views_htmx import PostListView from lacommunaute.forum_upvote.factories import UpVoteFactory from lacommunaute.notification.factories import BouncedEmailFactory @@ -350,18 +350,18 @@ def test_upvote_annotations(self): self.assertEqual(response.status_code, 200) self.assertContains(response, '2') - # def test_certified_post_highlight(self): - # post = PostFactory(topic=self.topic, poster=self.user) - # self.client.force_login(self.user) + def test_certified_post_highlight(self): + post = PostFactory(topic=self.topic, poster=self.user) + self.client.force_login(self.user) - # response = self.client.get(self.url) - # self.assertEqual(response.status_code, 200) - # self.assertNotContains(response, "Certifié par la Plateforme de l'Inclusion") + response = self.client.get(self.url) + self.assertEqual(response.status_code, 200) + self.assertNotContains(response, "Certifié par la Plateforme de l'Inclusion") - # CertifiedPostFactory(topic=self.topic, post=post, user=self.user) - # response = self.client.get(self.url) - # self.assertEqual(response.status_code, 200) - # self.assertContains(response, "Certifié par la Plateforme de l'Inclusion") + CertifiedPostFactory(topic=self.topic, post=post, user=self.user) + response = self.client.get(self.url) + self.assertEqual(response.status_code, 200) + self.assertContains(response, "Certifié par la Plateforme de l'Inclusion") class PostFeedCreateViewTest(TestCase): @@ -468,3 +468,71 @@ def test_create_post_as_bounced_not_bounced_anonymous(self, *args): self.topic.posts.values("content", "username", "approved").last(), {"content": self.content, "username": username, "approved": False}, ) + + +class CertifiedPostViewTest(TestCase): + @classmethod + def setUpTestData(cls): + cls.topic = TopicFactory(with_post=True) + cls.user = cls.topic.poster + assign_perm("can_read_forum", cls.user, cls.topic.forum) + cls.url = reverse( + "forum_conversation_extension:certify", + kwargs={ + "forum_pk": cls.topic.forum.pk, + "forum_slug": cls.topic.forum.slug, + "pk": cls.topic.pk, + "slug": cls.topic.slug, + }, + ) + cls.form_data = {"post_pk": cls.topic.last_post.pk} + + def test_get(self): + self.client.force_login(self.user) + response = self.client.get(self.url) + self.assertEqual(response.status_code, 405) + + def test_post_instance_doesnt_exist(self): + self.client.force_login(self.user) + response = self.client.post(self.url, data={"post_pk": 9999}) + self.assertEqual(response.status_code, 404) + + def test_certify_without_permission(self): + self.client.force_login(self.user) + response = self.client.post(self.url, data=self.form_data) + self.assertEqual(response.status_code, 403) + + def test_certify_with_permission(self): + self.topic.forum.members_group.user_set.add(self.user) + self.topic.forum.members_group.save() + self.client.force_login(self.user) + response = self.client.post(self.url, data=self.form_data) + + self.assertEqual(response.status_code, 200) + self.assertEqual(CertifiedPost.objects.count(), 1) + certified_post = CertifiedPost.objects.first() + self.assertEqual(certified_post.post, self.topic.last_post) + self.assertEqual(certified_post.user, self.user) + self.assertEqual(certified_post.topic, self.topic) + self.assertEqual(ForumReadTrack.objects.count(), 1) + + def test_uncertify_with_permission(self): + self.topic.forum.members_group.user_set.add(self.user) + self.topic.forum.members_group.save() + CertifiedPost(topic=self.topic, post=self.topic.last_post, user=self.user).save() + self.client.force_login(self.user) + response = self.client.post(self.url, data=self.form_data) + + self.assertEqual(response.status_code, 200) + self.assertEqual(CertifiedPost.objects.count(), 0) + self.assertEqual(ForumReadTrack.objects.count(), 1) + + def test_rendered_content(self): + self.topic.forum.members_group.user_set.add(self.user) + self.topic.forum.members_group.save() + self.client.force_login(self.user) + response = self.client.post(self.url, data=self.form_data) + + self.assertEqual(response.status_code, 200) + self.assertContains(response, f'
') + self.assertTemplateUsed(response, "forum_conversation/partials/posts_list.html") diff --git a/lacommunaute/forum_conversation/urls.py b/lacommunaute/forum_conversation/urls.py index 2bb0ddf6c..4689b1023 100644 --- a/lacommunaute/forum_conversation/urls.py +++ b/lacommunaute/forum_conversation/urls.py @@ -2,6 +2,7 @@ from lacommunaute.forum_conversation.views import NewsFeedTopicListView, TopicListView from lacommunaute.forum_conversation.views_htmx import ( + CertifiedPostView, ForumTopicListView, PostFeedCreateView, PostListView, @@ -19,6 +20,7 @@ path("topic/-/showmore/posts", PostListView.as_view(), name="showmore_posts"), path("topic/-/showmore/certified", TopicCertifiedPostView.as_view(), name="showmore_certified"), path("topic/-/comment", PostFeedCreateView.as_view(), name="post_create"), + path("topic/-/certify", CertifiedPostView.as_view(), name="certify"), path("topic/", ForumTopicListView.as_view(), name="topic_list"), ] diff --git a/lacommunaute/forum_conversation/views_htmx.py b/lacommunaute/forum_conversation/views_htmx.py index 0d648fccc..9393e1cb9 100644 --- a/lacommunaute/forum_conversation/views_htmx.py +++ b/lacommunaute/forum_conversation/views_htmx.py @@ -9,7 +9,7 @@ from lacommunaute.forum.models import Forum from lacommunaute.forum_conversation.forms import PostForm -from lacommunaute.forum_conversation.models import Topic +from lacommunaute.forum_conversation.models import CertifiedPost, Post, Topic from lacommunaute.forum_conversation.shortcuts import can_certify_post, get_posts_of_a_topic_except_first_one @@ -195,3 +195,52 @@ def get_controlled_object(self): def perform_permissions_check(self, user, obj, perms): return self.request.forum_permission_handler.can_add_post(obj, user) + + +class CertifiedPostView(PermissionRequiredMixin, View): + def _can_certify_post(self, forum, user): + if not hasattr(self, "can_certify_post"): + self.can_certify_post = can_certify_post(forum, user) + return self.can_certify_post + + def dispatch(self, request, *args, **kwargs): + if request.method != "POST": + return self.http_method_not_allowed(request) + return super().dispatch(request, *args, **kwargs) + + def get_object(self): + if not hasattr(self, "object"): + self.object = get_object_or_404( + Post, + pk=self.request.POST["post_pk"], + ) + return self.object + + def post(self, request, **kwargs): + post = self.get_object() + certified_post = CertifiedPost.objects.filter(post=post) + + if certified_post.exists(): + certified_post.delete() + else: + CertifiedPost(post=post, topic=post.topic, user=request.user).save() + + track_handler.mark_topic_read(post.topic, request.user) + + return render( + request, + "forum_conversation/partials/posts_list.html", + context={ + "topic": post.topic, + "posts": get_posts_of_a_topic_except_first_one(post.topic, request.user), + "form": PostForm(forum=post.topic.forum, user=request.user), + "next_url": post.topic.get_absolute_url(), + "can_certify_post": self._can_certify_post(post.topic.forum, request.user), + }, + ) + + def get_controlled_object(self): + return self.get_object().topic.forum + + def perform_permissions_check(self, user, obj, perms): + return self.request.forum_permission_handler.can_read_forum(obj, user) and self._can_certify_post(obj, user) diff --git a/lacommunaute/templates/forum_conversation/partials/post_certified_actions.html b/lacommunaute/templates/forum_conversation/partials/post_certified_actions.html index f693112cb..eae5989ff 100644 --- a/lacommunaute/templates/forum_conversation/partials/post_certified_actions.html +++ b/lacommunaute/templates/forum_conversation/partials/post_certified_actions.html @@ -1,7 +1,7 @@ {%if can_certify_post %} {% if not topic.is_certified or post.is_certified %} - -