From 424f91e91917e2aabcecf02cb04a8e63b48a8e7b Mon Sep 17 00:00:00 2001 From: moanos Date: Tue, 14 Jan 2025 07:30:36 +0100 Subject: [PATCH] feat: Add a timestamp for when a notification is read --- .../0036_basenotification_read_at.py | 18 +++++++++++++++++ .../0037_alter_basenotification_title.py | 18 +++++++++++++++++ src/fellchensammlung/models.py | 8 +++++++- src/fellchensammlung/views.py | 6 ++---- src/tests/test_models.py | 20 ++++++++++++++++++- 5 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 src/fellchensammlung/migrations/0036_basenotification_read_at.py create mode 100644 src/fellchensammlung/migrations/0037_alter_basenotification_title.py diff --git a/src/fellchensammlung/migrations/0036_basenotification_read_at.py b/src/fellchensammlung/migrations/0036_basenotification_read_at.py new file mode 100644 index 0000000..090a554 --- /dev/null +++ b/src/fellchensammlung/migrations/0036_basenotification_read_at.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.4 on 2025-01-14 06:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fellchensammlung', '0035_alter_image_alt_text_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='basenotification', + name='read_at', + field=models.DateTimeField(blank=True, null=True, verbose_name='Gelesen am'), + ), + ] diff --git a/src/fellchensammlung/migrations/0037_alter_basenotification_title.py b/src/fellchensammlung/migrations/0037_alter_basenotification_title.py new file mode 100644 index 0000000..74310df --- /dev/null +++ b/src/fellchensammlung/migrations/0037_alter_basenotification_title.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.4 on 2025-01-14 06:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fellchensammlung', '0036_basenotification_read_at'), + ] + + operations = [ + migrations.AlterField( + model_name='basenotification', + name='title', + field=models.CharField(max_length=100, verbose_name='Titel'), + ), + ] diff --git a/src/fellchensammlung/models.py b/src/fellchensammlung/models.py index d530b98..6c83d46 100644 --- a/src/fellchensammlung/models.py +++ b/src/fellchensammlung/models.py @@ -818,7 +818,8 @@ class Comment(models.Model): class BaseNotification(models.Model): created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) - title = models.CharField(max_length=100) + read_at = models.DateTimeField(blank=True, null=True, verbose_name=_("Gelesen am")) + title = models.CharField(max_length=100, verbose_name=_("Titel")) text = models.TextField(verbose_name="Inhalt") user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name=_('Nutzer*in')) read = models.BooleanField(default=False) @@ -829,6 +830,11 @@ class BaseNotification(models.Model): def get_absolute_url(self): self.user.get_notifications_url() + def mark_read(self): + self.read = True + self.read_at = timezone.now() + self.save() + class CommentNotification(BaseNotification): comment = models.ForeignKey(Comment, on_delete=models.CASCADE, verbose_name=_('Antwort')) diff --git a/src/fellchensammlung/views.py b/src/fellchensammlung/views.py index 2f24821..11747bf 100644 --- a/src/fellchensammlung/views.py +++ b/src/fellchensammlung/views.py @@ -481,13 +481,11 @@ def my_profile(request): notification = CommentNotification.objects.get(pk=notification_id) except CommentNotification.DoesNotExist: notification = BaseNotification.objects.get(pk=notification_id) - notification.read = True - notification.save() + notification.mark_read() elif action == "notification_mark_all_read": notifications = CommentNotification.objects.filter(user=request.user, mark_read=False) for notification in notifications: - notification.read = True - notification.save() + notification.mark_read() elif action == "search_subscription_delete": search_subscription_id = request.POST.get("search_subscription_id") SearchSubscription.objects.get(pk=search_subscription_id).delete() diff --git a/src/tests/test_models.py b/src/tests/test_models.py index 38b0a55..9aff0fe 100644 --- a/src/tests/test_models.py +++ b/src/tests/test_models.py @@ -4,7 +4,7 @@ from django.utils import timezone from django.test import TestCase from model_bakery import baker -from fellchensammlung.models import Announcement, Language, User, TrustLevel +from fellchensammlung.models import Announcement, Language, User, TrustLevel, BaseNotification class UserTest(TestCase): @@ -77,3 +77,21 @@ class AnnouncementTest(TestCase): self.assertTrue(self.announcement2 not in active_announcements) self.assertTrue(self.announcement4 not in active_announcements) self.assertTrue(self.announcement5 in active_announcements) + + +class TestNotifications(TestCase): + @classmethod + def setUpTestData(cls): + cls.test_user_1 = User.objects.create(username="Testuser1", password="SUPERSECRET", email="test@example.org") + + def test_mark_read(self): + not1 = BaseNotification.objects.create(user=self.test_user_1, text="New rats to adopt", title="🔔 New Rat alert") + not2 = BaseNotification.objects.create(user=self.test_user_1, + text="New wombat to adopt", title="🔔 New Wombat alert") + not1.mark_read() + + self.assertTrue(not1.read) + self.assertFalse(not2.read) + self.assertTrue((timezone.now() - timedelta(hours=1)) < not1.read_at < timezone.now()) + self.assertIsNone(not2.read_at) +