From 55b06f3f441e8689b7af95a78662ea37e7b85e71 Mon Sep 17 00:00:00 2001 From: vincent porte Date: Thu, 20 Jul 2023 10:33:57 +0200 Subject: [PATCH 1/4] feat(forum_conversation): move can_certify_post method to forum_conversation app --- lacommunaute/forum_conversation/shortcuts.py | 9 +++++ .../tests/tests_shortcuts.py | 32 ++++++++++++++++- lacommunaute/forum_conversation/views.py | 3 +- lacommunaute/forum_conversation/views_htmx.py | 3 +- lacommunaute/forum_upvote/shortcuts.py | 9 ----- .../forum_upvote/tests/tests_shortcuts.py | 34 ------------------- 6 files changed, 42 insertions(+), 48 deletions(-) delete mode 100644 lacommunaute/forum_upvote/shortcuts.py delete mode 100644 lacommunaute/forum_upvote/tests/tests_shortcuts.py diff --git a/lacommunaute/forum_conversation/shortcuts.py b/lacommunaute/forum_conversation/shortcuts.py index fba68900f..02699f602 100644 --- a/lacommunaute/forum_conversation/shortcuts.py +++ b/lacommunaute/forum_conversation/shortcuts.py @@ -1,5 +1,6 @@ from django.db.models import Count, Exists, OuterRef, Prefetch, Q, QuerySet +from lacommunaute.forum.enums import Kind as Forum_Kind from lacommunaute.forum_conversation.models import Post, Topic from lacommunaute.forum_upvote.models import UpVote from lacommunaute.users.models import User @@ -28,3 +29,11 @@ def get_posts_of_a_topic_except_first_one(topic: Topic, user: User) -> QuerySet[ upvotes_count=Count("upvotes"), ) return qs.order_by("created") + + +def can_certify_post(forum, user): + return ( + user.is_authenticated + and forum.kind == Forum_Kind.PUBLIC_FORUM + and (user.groups.filter(forum=forum).exists() or user.is_staff) + ) diff --git a/lacommunaute/forum_conversation/tests/tests_shortcuts.py b/lacommunaute/forum_conversation/tests/tests_shortcuts.py index d425ec1ea..d27c6ef1d 100644 --- a/lacommunaute/forum_conversation/tests/tests_shortcuts.py +++ b/lacommunaute/forum_conversation/tests/tests_shortcuts.py @@ -1,9 +1,12 @@ from django.contrib.auth.models import AnonymousUser from django.test import TestCase +from lacommunaute.forum.enums import Kind as ForumKind +from lacommunaute.forum.factories import ForumFactory from lacommunaute.forum_conversation.factories import PostFactory, TopicFactory -from lacommunaute.forum_conversation.shortcuts import get_posts_of_a_topic_except_first_one +from lacommunaute.forum_conversation.shortcuts import can_certify_post, get_posts_of_a_topic_except_first_one from lacommunaute.forum_upvote.factories import UpVoteFactory +from lacommunaute.users.factories import UserFactory class GetPostsofaTopicExceptFirstOneTest(TestCase): @@ -66,3 +69,30 @@ def test_topic_has_been_upvoted_by_the_user(self): self.assertEqual(len(posts), 1) self.assertEqual(post.upvotes_count, 1) self.assertTrue(post.has_upvoted) + + +class CanCertifyPostShortcutTest(TestCase): + @classmethod + def setUpTestData(cls): + cls.user = UserFactory.create() + cls.forum = ForumFactory.create() + + def test_user_is_not_authenticated(self): + self.assertFalse(can_certify_post(self.forum, AnonymousUser())) + + def test_forum_is_private(self): + self.assertFalse(can_certify_post(ForumFactory.create(kind=ForumKind.PRIVATE_FORUM), self.user)) + + def test_forum_is_newsfeed(self): + self.assertFalse(can_certify_post(ForumFactory.create(kind=ForumKind.NEWS), self.user)) + + def test_user_is_not_in_the_forum_members_group(self): + self.assertFalse(can_certify_post(self.forum, self.user)) + + def test_user_is_in_the_forum_members_group(self): + self.forum.members_group.user_set.add(self.user) + self.assertTrue(can_certify_post(self.forum, self.user)) + + def test_user_is_staff(self): + self.user.is_staff = True + self.assertTrue(can_certify_post(self.forum, self.user)) diff --git a/lacommunaute/forum_conversation/views.py b/lacommunaute/forum_conversation/views.py index 6a23d5a51..8100e2164 100644 --- a/lacommunaute/forum_conversation/views.py +++ b/lacommunaute/forum_conversation/views.py @@ -12,8 +12,7 @@ from lacommunaute.forum_conversation.enums import Filters from lacommunaute.forum_conversation.forms import PostForm, TopicForm from lacommunaute.forum_conversation.models import Topic -from lacommunaute.forum_conversation.shortcuts import get_posts_of_a_topic_except_first_one -from lacommunaute.forum_upvote.shortcuts import can_certify_post +from lacommunaute.forum_conversation.shortcuts import can_certify_post, get_posts_of_a_topic_except_first_one logger = logging.getLogger(__name__) diff --git a/lacommunaute/forum_conversation/views_htmx.py b/lacommunaute/forum_conversation/views_htmx.py index 3ff200ab5..0d648fccc 100644 --- a/lacommunaute/forum_conversation/views_htmx.py +++ b/lacommunaute/forum_conversation/views_htmx.py @@ -10,8 +10,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.shortcuts import get_posts_of_a_topic_except_first_one -from lacommunaute.forum_upvote.shortcuts import can_certify_post +from lacommunaute.forum_conversation.shortcuts import can_certify_post, get_posts_of_a_topic_except_first_one logger = logging.getLogger(__name__) diff --git a/lacommunaute/forum_upvote/shortcuts.py b/lacommunaute/forum_upvote/shortcuts.py deleted file mode 100644 index daefa9935..000000000 --- a/lacommunaute/forum_upvote/shortcuts.py +++ /dev/null @@ -1,9 +0,0 @@ -from lacommunaute.forum.enums import Kind as Forum_Kind - - -def can_certify_post(forum, user): - return ( - user.is_authenticated - and forum.kind == Forum_Kind.PUBLIC_FORUM - and (user.groups.filter(forum=forum).exists() or user.is_staff) - ) diff --git a/lacommunaute/forum_upvote/tests/tests_shortcuts.py b/lacommunaute/forum_upvote/tests/tests_shortcuts.py deleted file mode 100644 index 704c196f3..000000000 --- a/lacommunaute/forum_upvote/tests/tests_shortcuts.py +++ /dev/null @@ -1,34 +0,0 @@ -from django.contrib.auth.models import AnonymousUser -from django.test import TestCase - -from lacommunaute.forum.enums import Kind as ForumKind -from lacommunaute.forum.factories import ForumFactory -from lacommunaute.forum_upvote.shortcuts import can_certify_post -from lacommunaute.users.factories import UserFactory - - -class CanCertifyPostShortcutTest(TestCase): - @classmethod - def setUpTestData(cls): - cls.user = UserFactory.create() - cls.forum = ForumFactory.create() - - def test_user_is_not_authenticated(self): - self.assertFalse(can_certify_post(self.forum, AnonymousUser())) - - def test_forum_is_private(self): - self.assertFalse(can_certify_post(ForumFactory.create(kind=ForumKind.PRIVATE_FORUM), self.user)) - - def test_forum_is_newsfeed(self): - self.assertFalse(can_certify_post(ForumFactory.create(kind=ForumKind.NEWS), self.user)) - - def test_user_is_not_in_the_forum_members_group(self): - self.assertFalse(can_certify_post(self.forum, self.user)) - - def test_user_is_in_the_forum_members_group(self): - self.forum.members_group.user_set.add(self.user) - self.assertTrue(can_certify_post(self.forum, self.user)) - - def test_user_is_staff(self): - self.user.is_staff = True - self.assertTrue(can_certify_post(self.forum, self.user)) From d6f50c4cf42f8596514d476dd2d8dea53c970aa6 Mon Sep 17 00:00:00 2001 From: vincent porte Date: Thu, 20 Jul 2023 11:07:39 +0200 Subject: [PATCH 2/4] feat(upvotes): remove certifiedpost view, urls, tests and factories before migrate model --- lacommunaute/forum/tests/tests_views.py | 13 ++-- .../forum_conversation/tests/tests_views.py | 41 ++++++------ .../tests/tests_views_htmx.py | 22 +++---- lacommunaute/forum_upvote/admin.py | 12 +--- lacommunaute/forum_upvote/factories.py | 7 +-- .../forum_upvote/tests/tests_models.py | 18 ------ .../forum_upvote/tests/tests_views.py | 62 +------------------ lacommunaute/forum_upvote/urls.py | 3 +- lacommunaute/forum_upvote/views.py | 54 +--------------- .../partials/post_certified_actions.html | 2 +- 10 files changed, 44 insertions(+), 190 deletions(-) diff --git a/lacommunaute/forum/tests/tests_views.py b/lacommunaute/forum/tests/tests_views.py index ab16c1d6e..75e5a1015 100644 --- a/lacommunaute/forum/tests/tests_views.py +++ b/lacommunaute/forum/tests/tests_views.py @@ -10,7 +10,6 @@ from lacommunaute.forum_conversation.factories import PostFactory, TopicFactory from lacommunaute.forum_conversation.forms import PostForm from lacommunaute.forum_conversation.models import Topic -from lacommunaute.forum_upvote.factories import CertifiedPostFactory from lacommunaute.users.factories import UserFactory @@ -261,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/tests/tests_views.py b/lacommunaute/forum_conversation/tests/tests_views.py index 21f47a454..2a19a73ce 100644 --- a/lacommunaute/forum_conversation/tests/tests_views.py +++ b/lacommunaute/forum_conversation/tests/tests_views.py @@ -19,7 +19,7 @@ from lacommunaute.forum_conversation.forms import PostForm from lacommunaute.forum_conversation.models import Topic from lacommunaute.forum_conversation.views import PostDeleteView, TopicCreateView -from lacommunaute.forum_upvote.factories import CertifiedPostFactory, UpVoteFactory +from lacommunaute.forum_upvote.factories import UpVoteFactory from lacommunaute.notification.factories import BouncedEmailFactory from lacommunaute.users.factories import UserFactory @@ -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,16 +474,17 @@ 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) - # note vincentporte : to be optimized - with self.assertNumQueries(44): - response = self.client.get(self.url) - self.assertEqual(response.status_code, 200) +# 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) class TopicListViewTest(TestCase): diff --git a/lacommunaute/forum_conversation/tests/tests_views_htmx.py b/lacommunaute/forum_conversation/tests/tests_views_htmx.py index 12872e870..a81e8b539 100644 --- a/lacommunaute/forum_conversation/tests/tests_views_htmx.py +++ b/lacommunaute/forum_conversation/tests/tests_views_htmx.py @@ -11,7 +11,7 @@ from lacommunaute.forum_conversation.forms import PostForm from lacommunaute.forum_conversation.models import Topic from lacommunaute.forum_conversation.views_htmx import PostListView -from lacommunaute.forum_upvote.factories import CertifiedPostFactory, UpVoteFactory +from lacommunaute.forum_upvote.factories import UpVoteFactory from lacommunaute.notification.factories import BouncedEmailFactory from lacommunaute.users.factories import UserFactory @@ -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): diff --git a/lacommunaute/forum_upvote/admin.py b/lacommunaute/forum_upvote/admin.py index 3307f0533..cd732201a 100644 --- a/lacommunaute/forum_upvote/admin.py +++ b/lacommunaute/forum_upvote/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -from lacommunaute.forum_upvote.models import CertifiedPost, UpVote +from lacommunaute.forum_upvote.models import UpVote class UpVoteAdmin(admin.ModelAdmin): @@ -11,14 +11,4 @@ class UpVoteAdmin(admin.ModelAdmin): ) -class CertifiedPostAdmin(admin.ModelAdmin): - list_display = ("topic", "post", "user") - raw_id_fields = ( - "topic", - "post", - "user", - ) - - -admin.site.register(CertifiedPost, CertifiedPostAdmin) admin.site.register(UpVote, UpVoteAdmin) diff --git a/lacommunaute/forum_upvote/factories.py b/lacommunaute/forum_upvote/factories.py index a013112fe..38c49326c 100644 --- a/lacommunaute/forum_upvote/factories.py +++ b/lacommunaute/forum_upvote/factories.py @@ -1,14 +1,9 @@ import factory import factory.django -from lacommunaute.forum_upvote.models import CertifiedPost, UpVote +from lacommunaute.forum_upvote.models import UpVote class UpVoteFactory(factory.django.DjangoModelFactory): class Meta: model = UpVote - - -class CertifiedPostFactory(factory.django.DjangoModelFactory): - class Meta: - model = CertifiedPost diff --git a/lacommunaute/forum_upvote/tests/tests_models.py b/lacommunaute/forum_upvote/tests/tests_models.py index df314319c..4a9a6885e 100644 --- a/lacommunaute/forum_upvote/tests/tests_models.py +++ b/lacommunaute/forum_upvote/tests/tests_models.py @@ -2,7 +2,6 @@ from django.test import TestCase from lacommunaute.forum_conversation.factories import TopicFactory -from lacommunaute.forum_upvote.factories import CertifiedPostFactory from lacommunaute.forum_upvote.models import UpVote @@ -13,20 +12,3 @@ def test_post_and_voter_are_uniques_together(self): with self.assertRaises(IntegrityError): UpVote.objects.create(post=topic.first_post, voter=topic.first_post.poster) - - -class CertifiedPostModelTest(TestCase): - def test_topic_is_unique(self): - topic = TopicFactory(with_certified_post=True) - - with self.assertRaises(IntegrityError): - CertifiedPostFactory(topic=topic, post=topic.first_post, user=topic.poster) - - def test_post_is_link_to_topic(self): - topic_to_be_certified = TopicFactory() - other_topic = TopicFactory(with_post=True) - - with self.assertRaises(ValueError): - CertifiedPostFactory( - topic=topic_to_be_certified, post=other_topic.first_post, user=topic_to_be_certified.poster - ) diff --git a/lacommunaute/forum_upvote/tests/tests_views.py b/lacommunaute/forum_upvote/tests/tests_views.py index 97df5b923..270c43721 100644 --- a/lacommunaute/forum_upvote/tests/tests_views.py +++ b/lacommunaute/forum_upvote/tests/tests_views.py @@ -5,7 +5,7 @@ from machina.core.loading import get_class from lacommunaute.forum_conversation.factories import PostFactory, TopicFactory -from lacommunaute.forum_upvote.models import CertifiedPost, UpVote +from lacommunaute.forum_upvote.models import UpVote from lacommunaute.users.factories import UserFactory @@ -74,63 +74,3 @@ def test_topic_is_marked_as_read_when_upvoting(self): self.assertEqual(response.status_code, 200) self.assertEqual(1, ForumReadTrack.objects.count()) - - -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_upvote:certify") - 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_upvote/urls.py b/lacommunaute/forum_upvote/urls.py index 8c191a302..212d6c78b 100644 --- a/lacommunaute/forum_upvote/urls.py +++ b/lacommunaute/forum_upvote/urls.py @@ -1,6 +1,6 @@ from django.urls import path -from lacommunaute.forum_upvote.views import CertifiedPostView, PostUpvoteView +from lacommunaute.forum_upvote.views import PostUpvoteView app_name = "forum_upvote" @@ -8,5 +8,4 @@ urlpatterns = [ path("upvote/", PostUpvoteView.as_view(), name="upvote"), - path("certify/", CertifiedPostView.as_view(), name="certify"), ] diff --git a/lacommunaute/forum_upvote/views.py b/lacommunaute/forum_upvote/views.py index 2d7f23150..61fb70c37 100644 --- a/lacommunaute/forum_upvote/views.py +++ b/lacommunaute/forum_upvote/views.py @@ -4,11 +4,8 @@ from django.views import View from machina.core.loading import get_class -from lacommunaute.forum_conversation.forms import PostForm from lacommunaute.forum_conversation.models import Post -from lacommunaute.forum_conversation.shortcuts import get_posts_of_a_topic_except_first_one -from lacommunaute.forum_upvote.models import CertifiedPost, UpVote -from lacommunaute.forum_upvote.shortcuts import can_certify_post +from lacommunaute.forum_upvote.models import UpVote logger = logging.getLogger(__name__) @@ -56,52 +53,3 @@ def get_controlled_object(self): def perform_permissions_check(self, user, obj, perms): return self.request.forum_permission_handler.can_read_forum(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 d03298aaf..f693112cb 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 %} - -
Date: Thu, 20 Jul 2023 11:12:39 +0200 Subject: [PATCH 3/4] =?UTF-8?q?feat(forum=5Fconversation):=C2=A0migrate=20?= =?UTF-8?q?CertifiedPost=20model=20from=20forum=5Fupvote=20to=20forum=5Fco?= =?UTF-8?q?nversation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lacommunaute/forum_conversation/admin.py | 15 ++++ .../migrations/0007_certifiedpost.py | 79 +++++++++++++++++++ lacommunaute/forum_conversation/models.py | 38 +++++++++ .../forum_conversation/tests/tests_models.py | 20 ++++- .../migrations/0003_delete_certifiedpost.py | 13 +++ lacommunaute/forum_upvote/models.py | 40 +--------- 6 files changed, 165 insertions(+), 40 deletions(-) create mode 100644 lacommunaute/forum_conversation/migrations/0007_certifiedpost.py create mode 100644 lacommunaute/forum_upvote/migrations/0003_delete_certifiedpost.py diff --git a/lacommunaute/forum_conversation/admin.py b/lacommunaute/forum_conversation/admin.py index 1853a9608..4fe728e49 100644 --- a/lacommunaute/forum_conversation/admin.py +++ b/lacommunaute/forum_conversation/admin.py @@ -1,5 +1,8 @@ +from django.contrib import admin from machina.apps.forum_conversation.admin import TopicAdmin as BaseTopicAdmin +from lacommunaute.forum_conversation.models import CertifiedPost + # TODO vincentporte, need to be fixed, likers field does not appear like a raw id fields class TopicAdmin(BaseTopicAdmin): @@ -8,3 +11,15 @@ class TopicAdmin(BaseTopicAdmin): "subscribers", "likers", ) + + +class CertifiedPostAdmin(admin.ModelAdmin): + list_display = ("topic", "post", "user") + raw_id_fields = ( + "topic", + "post", + "user", + ) + + +admin.site.register(CertifiedPost, CertifiedPostAdmin) diff --git a/lacommunaute/forum_conversation/migrations/0007_certifiedpost.py b/lacommunaute/forum_conversation/migrations/0007_certifiedpost.py new file mode 100644 index 000000000..7949640f0 --- /dev/null +++ b/lacommunaute/forum_conversation/migrations/0007_certifiedpost.py @@ -0,0 +1,79 @@ +# Generated by Django 4.2.3 on 2023-07-19 08:59 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("forum_conversation", "0006_topic_tags"), + ("forum_upvote", "0002_certifiedpost"), + ] + + operations = [ + migrations.CreateModel( + name="CertifiedPost", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("created", models.DateTimeField(auto_now_add=True, verbose_name="Creation date")), + ("updated", models.DateTimeField(auto_now=True, verbose_name="Update date")), + ( + "post", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name="certified_post", + to="forum_conversation.post", + verbose_name="Post", + ), + ), + ( + "topic", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name="certified_post", + to="forum_conversation.topic", + verbose_name="Topic", + ), + ), + ( + "user", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="certified_posts", + to=settings.AUTH_USER_MODEL, + verbose_name="User", + ), + ), + ], + options={ + "ordering": ["-created"], + }, + ), + migrations.RunSQL( + """ + INSERT INTO forum_conversation_certifiedpost ( + id, created, updated, post_id, topic_id, user_id + ) + SELECT + id, created, updated, post_id, topic_id, user_id + FROM + forum_upvote_certifiedpost; + SELECT + setval( + pg_get_serial_sequence('"forum_conversation_certifiedpost"','id'), + coalesce(max("id"), 1), + max("id") IS NOT null + ) + FROM + "forum_conversation_certifiedpost"; + """, + reverse_sql=""" + INSERT INTO forum_upvote_certifiedpost (id, created, updated, post_id, topic_id, user_id) + SELECT id, created, updated, post_id, topic_id, user_id FROM forum_conversation_certifiedpost; + """, + ), + ] diff --git a/lacommunaute/forum_conversation/models.py b/lacommunaute/forum_conversation/models.py index e8d936403..3c8ffb713 100644 --- a/lacommunaute/forum_conversation/models.py +++ b/lacommunaute/forum_conversation/models.py @@ -3,6 +3,7 @@ from django.db.models import Count, Exists, OuterRef from django.urls import reverse from machina.apps.forum_conversation.abstract_models import AbstractPost, AbstractTopic +from machina.models.abstract_models import DatedModel from taggit.managers import TaggableManager from lacommunaute.forum_member.shortcuts import get_forum_member_display_name @@ -90,3 +91,40 @@ def poster_display_name(self): @property def is_certified(self): return hasattr(self, "certified_post") + + +class CertifiedPost(DatedModel): + topic = models.OneToOneField( + Topic, + related_name="certified_post", + on_delete=models.CASCADE, + verbose_name="Topic", + ) + + post = models.OneToOneField( + Post, + related_name="certified_post", + on_delete=models.CASCADE, + verbose_name="Post", + ) + user = models.ForeignKey( + settings.AUTH_USER_MODEL, + related_name="certified_posts", + blank=True, + null=True, + on_delete=models.SET_NULL, + verbose_name="User", + ) + + class Meta: + ordering = [ + "-created", + ] + + def __str__(self): + return f"{self.post} - {self.topic} - {self.user}" + + def save(self, *args, **kwargs): + if self.topic != self.post.topic: + raise ValueError("The post is not link to the topic") + super().save(*args, **kwargs) diff --git a/lacommunaute/forum_conversation/tests/tests_models.py b/lacommunaute/forum_conversation/tests/tests_models.py index 87459d9a9..a1422c682 100644 --- a/lacommunaute/forum_conversation/tests/tests_models.py +++ b/lacommunaute/forum_conversation/tests/tests_models.py @@ -1,9 +1,10 @@ from django.core.exceptions import ValidationError +from django.db import IntegrityError from django.test import TestCase from django.urls import reverse from lacommunaute.forum.factories import ForumFactory -from lacommunaute.forum_conversation.factories import PostFactory, TopicFactory +from lacommunaute.forum_conversation.factories import CertifiedPostFactory, PostFactory, TopicFactory from lacommunaute.forum_conversation.models import Post, Topic from lacommunaute.forum_member.shortcuts import get_forum_member_display_name @@ -124,3 +125,20 @@ def test_topic_types(self): self.assertEqual(0, Topic.TOPIC_POST) self.assertEqual(1, Topic.TOPIC_STICKY) self.assertEqual(2, Topic.TOPIC_ANNOUNCE) + + +class CertifiedPostModelTest(TestCase): + def test_topic_is_unique(self): + topic = TopicFactory(with_certified_post=True) + + with self.assertRaises(IntegrityError): + CertifiedPostFactory(topic=topic, post=topic.first_post, user=topic.poster) + + def test_post_is_link_to_topic(self): + topic_to_be_certified = TopicFactory() + other_topic = TopicFactory(with_post=True) + + with self.assertRaises(ValueError): + CertifiedPostFactory( + topic=topic_to_be_certified, post=other_topic.first_post, user=topic_to_be_certified.poster + ) diff --git a/lacommunaute/forum_upvote/migrations/0003_delete_certifiedpost.py b/lacommunaute/forum_upvote/migrations/0003_delete_certifiedpost.py new file mode 100644 index 000000000..ca40f5bdd --- /dev/null +++ b/lacommunaute/forum_upvote/migrations/0003_delete_certifiedpost.py @@ -0,0 +1,13 @@ +# Generated by Django 4.2.3 on 2023-07-19 09:28 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [("forum_upvote", "0002_certifiedpost"), ("forum_conversation", "0007_certifiedpost")] + + operations = [ + migrations.DeleteModel( + name="CertifiedPost", + ), + ] diff --git a/lacommunaute/forum_upvote/models.py b/lacommunaute/forum_upvote/models.py index 5823664b9..f13590ca1 100644 --- a/lacommunaute/forum_upvote/models.py +++ b/lacommunaute/forum_upvote/models.py @@ -1,8 +1,7 @@ from django.conf import settings from django.db import models -from machina.models.abstract_models import DatedModel -from lacommunaute.forum_conversation.models import Post, Topic +from lacommunaute.forum_conversation.models import Post class UpVote(models.Model): @@ -32,40 +31,3 @@ class Meta: ordering = [ "-created_at", ] - - -class CertifiedPost(DatedModel): - topic = models.OneToOneField( - Topic, - related_name="certified_post", - on_delete=models.CASCADE, - verbose_name="Topic", - ) - - post = models.OneToOneField( - Post, - related_name="certified_post", - on_delete=models.CASCADE, - verbose_name="Post", - ) - user = models.ForeignKey( - settings.AUTH_USER_MODEL, - related_name="certified_posts", - blank=True, - null=True, - on_delete=models.SET_NULL, - verbose_name="User", - ) - - class Meta: - ordering = [ - "-created", - ] - - def __str__(self): - return f"{self.post} - {self.topic} - {self.user}" - - def save(self, *args, **kwargs): - if self.topic != self.post.topic: - raise ValueError("The post is not link to the topic") - super().save(*args, **kwargs) From 64385cf360e3f539f57962f714dd0edf3af1d7c8 Mon Sep 17 00:00:00 2001 From: vincent porte Date: Thu, 20 Jul 2023 11:17:44 +0200 Subject: [PATCH 4/4] 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 %} - -