diff --git a/lacommunaute/forum_conversation/models.py b/lacommunaute/forum_conversation/models.py index 2078798b..368e825a 100644 --- a/lacommunaute/forum_conversation/models.py +++ b/lacommunaute/forum_conversation/models.py @@ -146,7 +146,7 @@ def is_first_reply(self): def save(self, *args, **kwargs): created = not self.pk super().save(*args, **kwargs) - if created and (self.is_topic_tail and not self.is_topic_head): + if created: post_create.send(sender=self.__class__, instance=self) diff --git a/lacommunaute/notification/enums.py b/lacommunaute/notification/enums.py index 177bcc99..71e0a87b 100644 --- a/lacommunaute/notification/enums.py +++ b/lacommunaute/notification/enums.py @@ -13,3 +13,10 @@ class EmailSentTrackKind(models.TextChoices): class NotificationDelay(models.TextChoices): ASAP = "asap", _("As soon as possible") DAY = "day", _("The following day") + + +delay_of_notifications = { + EmailSentTrackKind.PENDING_TOPIC: NotificationDelay.DAY, + EmailSentTrackKind.FIRST_REPLY: NotificationDelay.ASAP, + EmailSentTrackKind.FOLLOWING_REPLIES: NotificationDelay.DAY, +} diff --git a/lacommunaute/notification/signals.py b/lacommunaute/notification/signals.py index a2e1f065..d5a18df4 100644 --- a/lacommunaute/notification/signals.py +++ b/lacommunaute/notification/signals.py @@ -1,4 +1,4 @@ -from lacommunaute.notification.enums import EmailSentTrackKind, NotificationDelay +from lacommunaute.notification.enums import EmailSentTrackKind, delay_of_notifications from lacommunaute.notification.models import Notification @@ -11,8 +11,14 @@ def create_post_notifications(sender, instance, **kwargs): if not instance.approved: return - delay = NotificationDelay.ASAP if instance.is_first_reply else NotificationDelay.DAY - kind = EmailSentTrackKind.FIRST_REPLY if instance.is_first_reply else EmailSentTrackKind.FOLLOWING_REPLIES + if instance.is_topic_head: + kind = EmailSentTrackKind.PENDING_TOPIC + elif instance.is_first_reply: + kind = EmailSentTrackKind.FIRST_REPLY + else: + kind = EmailSentTrackKind.FOLLOWING_REPLIES + + delay = delay_of_notifications[kind] notifications = [ Notification(recipient=email_address, post=instance, kind=kind, delay=delay) diff --git a/lacommunaute/notification/tests/tests_signals.py b/lacommunaute/notification/tests/tests_signals.py index 30188794..c99dcca7 100644 --- a/lacommunaute/notification/tests/tests_signals.py +++ b/lacommunaute/notification/tests/tests_signals.py @@ -1,59 +1,109 @@ -from django.test import TestCase +import pytest +from lacommunaute.forum.factories import ForumFactory from lacommunaute.forum_conversation.factories import ( + AnonymousPostFactory, AnonymousTopicFactory, PostFactory, TopicFactory, ) -from lacommunaute.forum_upvote.models import UpVote -from lacommunaute.notification.enums import EmailSentTrackKind, NotificationDelay +from lacommunaute.notification.enums import EmailSentTrackKind, NotificationDelay, delay_of_notifications from lacommunaute.notification.models import Notification from lacommunaute.users.factories import UserFactory -class PostCreatedTest(TestCase): - def test_notifications_on_post_creation(self): - topic = TopicFactory(with_post=True) - assert Notification.objects.count() == 0 +@pytest.fixture(name="upvoter") +def fixture_upvoter(): + return UserFactory() - first_post = PostFactory(topic=topic) + +@pytest.fixture(name="topic_in_forum_with_upvoter") +def fixture_topic_in_forum_with_upvoter(upvoter): + return TopicFactory(forum=ForumFactory(upvoted_by=[upvoter]), with_post=True) + + +class TestCreatePostNotifications: + def test_pending_topic(self, db, topic_in_forum_with_upvoter, upvoter): + notification = Notification.objects.get() + + for key, expected in [ + ("recipient", upvoter.email), + ("post", topic_in_forum_with_upvoter.first_post), + ("kind", EmailSentTrackKind.PENDING_TOPIC), + ("delay", NotificationDelay.DAY), + ]: + assert getattr(notification, key) == expected + + def test_first_reply(self, db, topic_in_forum_with_upvoter): + Notification.objects.all().delete() + + PostFactory(topic=topic_in_forum_with_upvoter) notification = Notification.objects.get() - assert notification.recipient == topic.poster.email - assert notification.post == first_post - assert notification.kind == EmailSentTrackKind.FIRST_REPLY - assert notification.delay == NotificationDelay.ASAP + + for key, expected in [ + ("recipient", topic_in_forum_with_upvoter.first_post.poster.email), + ("post", topic_in_forum_with_upvoter.last_post), + ("kind", EmailSentTrackKind.FIRST_REPLY), + ("delay", NotificationDelay.ASAP), + ]: + assert getattr(notification, key) == expected + + def test_first_reply_on_anonymous_topic(self, db): + topic = AnonymousTopicFactory(with_post=True) + Notification.objects.all().delete() PostFactory(topic=topic) - notifs = Notification.objects.exclude(id=notification.id) - assert notifs.count() == 2 - assert notifs.exclude(post=first_post).count() == 2 - assert notifs.exclude(kind=EmailSentTrackKind.FOLLOWING_REPLIES).count() == 0 - assert notifs.exclude(delay=NotificationDelay.DAY).count() == 0 - anticipated_recipients = set({topic.poster.email, first_post.poster.email}) - assert set(notifs.values_list("recipient", flat=True)) == anticipated_recipients - - def test_notifications_on_post_creation_upvote_follower(self): - topic = TopicFactory(with_post=True) - - upvoter = UserFactory() - UpVote.objects.create(content_object=topic.first_post, voter=upvoter) - - post = PostFactory(topic=topic) - notification = Notification.objects.get(recipient=upvoter.email) - assert notification.post == post - assert notification.kind == EmailSentTrackKind.FIRST_REPLY - assert notification.delay == NotificationDelay.ASAP - - def test_notifications_on_post_creation_anonymous_poster(self): + notification = Notification.objects.get() + + for key, expected in [ + ("recipient", topic.first_post.username), + ("post", topic.last_post), + ("kind", EmailSentTrackKind.FIRST_REPLY), + ("delay", NotificationDelay.ASAP), + ]: + assert getattr(notification, key) == expected + + def test_following_replies(self, db, topic_in_forum_with_upvoter): + first_reply_poster = UserFactory() + PostFactory(topic=topic_in_forum_with_upvoter, poster=first_reply_poster) + Notification.objects.all().delete() + + PostFactory(topic=topic_in_forum_with_upvoter) + + assert Notification.objects.count() == 2 + + for notification in Notification.objects.all(): + assert notification.recipient in [ + topic_in_forum_with_upvoter.first_post.poster.email, + first_reply_poster.email, + ] + for key, expected in [ + ("post", topic_in_forum_with_upvoter.last_post), + ("kind", EmailSentTrackKind.FOLLOWING_REPLIES), + ("delay", NotificationDelay.DAY), + ]: + assert getattr(notification, key) == expected + + def test_following_replies_on_anonymous_topic(self, db): topic = AnonymousTopicFactory(with_post=True) + post = AnonymousPostFactory(topic=topic) + Notification.objects.all().delete() + + PostFactory(topic=topic) + assert Notification.objects.count() == 2 + + for notification in Notification.objects.all(): + assert notification.recipient in [topic.first_post.username, post.username] + for key, expected in [ + ("post", topic.last_post), + ("kind", EmailSentTrackKind.FOLLOWING_REPLIES), + ("delay", NotificationDelay.DAY), + ]: + assert getattr(notification, key) == expected - post = PostFactory(topic=topic) - notification = Notification.objects.get(recipient=topic.first_post.username) - assert notification.post == post - assert notification.kind == EmailSentTrackKind.FIRST_REPLY - assert notification.delay == NotificationDelay.ASAP + def test_no_notifications_on_unapproved_post(self, db, upvoter): + topic = TopicFactory(forum=ForumFactory(upvoted_by=[upvoter])) - def test_notifications_no_approved_post(self): - topic = TopicFactory(with_post=True) - PostFactory(topic=topic, approved=False) - assert Notification.objects.count() == 0 + for _ in delay_of_notifications: + PostFactory(topic=topic, approved=False) + assert Notification.objects.count() == 0