From 38198e1ecda01b9ee2c41e45f778771c996a38c8 Mon Sep 17 00:00:00 2001 From: Situphen Date: Sun, 16 Jun 2024 19:00:37 +0200 Subject: [PATCH] =?UTF-8?q?Corrige=20la=20perte=20de=20forums=20et=20sujet?= =?UTF-8?q?s=20suivis=20lors=20de=20l'=C3=A9viction=20d'un=20groupe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zds/member/tests/factories.py | 24 ++++++++++++++++ zds/notification/receivers.py | 6 +++- zds/notification/tests/tests_tricky.py | 39 +++++++++++++++++++++++++- 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/zds/member/tests/factories.py b/zds/member/tests/factories.py index e75e4d2e85..80f3ee376c 100644 --- a/zds/member/tests/factories.py +++ b/zds/member/tests/factories.py @@ -103,6 +103,22 @@ class NonAsciiUserFactory(UserFactory): username = factory.Sequence("ïéàçÊÀ{}".format) +class MultipleGroupsUserFactory(UserFactory): + """ + Factory that creates a User with multiple groups + + WARNING: Don't try to directly use `MultipleGroupsUserFactory` because it won't create the associated Profile. + Use `MultipleGroupsProfileFactory` instead. + """ + + @factory.post_generation + def groups(self, create, extracted, **kwargs): + for group_name in ("first_group", "second_group"): + group = Group(name=group_name) + group.save() + self.groups.add(group) + + class ProfileFactory(factory.django.DjangoModelFactory): """ Use this factory when you need a complete Profile for a standard User. @@ -153,3 +169,11 @@ class NonAsciiProfileFactory(ProfileFactory): """ user = factory.SubFactory(NonAsciiUserFactory) + + +class MultipleGroupsProfileFactory(ProfileFactory): + """ + Use this factory when you need a complete Profile for a User with multiple groups. + """ + + user = factory.SubFactory(MultipleGroupsUserFactory) diff --git a/zds/notification/receivers.py b/zds/notification/receivers.py index 1581c4bec8..7f4e7d30da 100644 --- a/zds/notification/receivers.py +++ b/zds/notification/receivers.py @@ -48,7 +48,11 @@ def remove_group_subscription_on_quitting_groups(*, sender, instance, action, pk ) return - for forum in Forum.objects.filter(groups__pk__in=list(pk_set)): + all_groups_pk = instance.groups.values_list("pk", flat=True) + removed_groups_pk = pk_set + kept_groups_pk = set(all_groups_pk) - set(removed_groups_pk) + + for forum in Forum.objects.filter(groups__pk__in=removed_groups_pk).exclude(groups__pk__in=kept_groups_pk): subscriptions = [] forum_subscription = NewTopicSubscription.objects.get_existing(instance, forum, True) diff --git a/zds/notification/tests/tests_tricky.py b/zds/notification/tests/tests_tricky.py index c3b1f66e6d..1c6f1d11ba 100644 --- a/zds/notification/tests/tests_tricky.py +++ b/zds/notification/tests/tests_tricky.py @@ -9,7 +9,7 @@ from zds.forum.tests.factories import ForumCategoryFactory, ForumFactory from zds.forum.models import Topic from zds.gallery.tests.factories import UserGalleryFactory -from zds.member.tests.factories import StaffProfileFactory, ProfileFactory +from zds.member.tests.factories import StaffProfileFactory, ProfileFactory, MultipleGroupsProfileFactory from zds.notification.models import ( NewTopicSubscription, TopicAnswerSubscription, @@ -40,13 +40,19 @@ def setUp(self): self.user2 = ProfileFactory().user self.to_be_changed_staff = StaffProfileFactory().user self.staff = StaffProfileFactory().user + self.multi_groups_user = MultipleGroupsProfileFactory().user self.assertTrue(self.staff.has_perm("forum.change_topic")) self.category1 = ForumCategoryFactory(position=1) self.forum11 = ForumFactory(category=self.category1, position_in_category=1) self.forum12 = ForumFactory(category=self.category1, position_in_category=2) + self.forum13 = ForumFactory(category=self.category1, position_in_category=3) for group in self.staff.groups.all(): self.forum12.groups.add(group) + self.forum13.groups.add(group) self.forum12.save() + for group in self.multi_groups_user.groups.all(): + self.forum13.groups.add(group) + self.forum13.save() def test_ping_unknown(self): self.client.force_login(self.user2) @@ -340,6 +346,37 @@ def test_no_more_new_topic_notif_on_losing_one_group(self): self.assertFalse(subscription.is_active) self.assertTrue(subscription.last_notification.is_read, "As forum is not reachable, notification is read") + def test_keep_new_topic_notif_if_losing_only_one_group(self): + """ + Context: self.multi_groups_user is in two groups that both give access to self.forum13 + If this user leaves one of the two groups, they should keep receiving new topic notifications. + """ + + NewTopicSubscription.objects.get_or_create_active(self.multi_groups_user, self.forum13) + self.client.force_login(self.staff) + self.client.post( + reverse("forum:topic-new") + f"?forum={self.forum13.pk}", + { + "title": "Super sujet", + "subtitle": "Pour tester les notifs", + "text": "En tout cas l'un abonnement", + "tags": "", + }, + follow=False, + ) + subscription = NewTopicSubscription.objects.get_existing(self.multi_groups_user, self.forum13, True) + self.assertIsNotNone(subscription, "There must be an active subscription for now") + self.assertIsNotNone(subscription.last_notification, "There must be a notification.") + self.assertFalse(subscription.last_notification.is_read, "The notification has not been read yet") + + self.multi_groups_user.groups.remove(list(self.multi_groups_user.groups.all())[0]) + self.multi_groups_user.save() + + subscription = NewTopicSubscription.objects.get_existing(self.multi_groups_user, self.forum13, True) + self.assertIsNotNone(subscription, "There must still be an active subscription") + self.assertTrue(subscription.is_active) + self.assertFalse(subscription.last_notification.is_read, "The notification has not been read yet") + def test_no_more_topic_answer_notif_on_losing_all_groups(self): self.client.force_login(self.to_be_changed_staff) self.client.post(