From 2500dc92348ae1a61bc400c48091467893e0c87f Mon Sep 17 00:00:00 2001 From: Nitesh Sinha Date: Sat, 26 Dec 2020 15:04:12 +0530 Subject: [PATCH] [feature] Added general setting to disable all notifications #148 closes #148 --- openwisp_notifications/admin.py | 14 +++- openwisp_notifications/base/admin.py | 9 ++- openwisp_notifications/base/forms.py | 8 +++ openwisp_notifications/base/models.py | 36 +++++++++++ openwisp_notifications/handlers.py | 16 ++++- .../migrations/0007_generalsetting.py | 64 +++++++++++++++++++ openwisp_notifications/models.py | 7 ++ .../tests/test_general_setting.py | 48 ++++++++++++++ .../openwisp2/sample_notifications/models.py | 6 ++ 9 files changed, 204 insertions(+), 4 deletions(-) create mode 100644 openwisp_notifications/migrations/0007_generalsetting.py create mode 100644 openwisp_notifications/tests/test_general_setting.py diff --git a/openwisp_notifications/admin.py b/openwisp_notifications/admin.py index 0e320be6..3baa2fe7 100644 --- a/openwisp_notifications/admin.py +++ b/openwisp_notifications/admin.py @@ -1,6 +1,9 @@ from django.contrib import admin -from openwisp_notifications.base.admin import NotificationSettingAdminMixin +from openwisp_notifications.base.admin import ( + GeneralSettingAdminMixin, + NotificationSettingAdminMixin, +) from openwisp_notifications.swapper import load_model from openwisp_notifications.widgets import _add_object_notification_widget from openwisp_users.admin import UserAdmin @@ -8,6 +11,7 @@ Notification = load_model('Notification') NotificationSetting = load_model('NotificationSetting') +GeneralSetting = load_model('GeneralSetting') class NotificationSettingInline( @@ -20,6 +24,12 @@ def has_change_permission(self, request, obj=None): return request.user.is_superuser or request.user == obj -UserAdmin.inlines = [NotificationSettingInline] + UserAdmin.inlines +class GeneralSettingAdmin( + GeneralSettingAdminMixin, AlwaysHasChangedMixin, admin.TabularInline +): + model = GeneralSetting + + +UserAdmin.inlines = [NotificationSettingInline, GeneralSettingAdmin] + UserAdmin.inlines _add_object_notification_widget() diff --git a/openwisp_notifications/base/admin.py b/openwisp_notifications/base/admin.py index bb299571..335a6a1b 100644 --- a/openwisp_notifications/base/admin.py +++ b/openwisp_notifications/base/admin.py @@ -1,4 +1,7 @@ -from openwisp_notifications.base.forms import NotificationSettingForm +from openwisp_notifications.base.forms import ( + GeneralSettingForm, + NotificationSettingForm, +) class NotificationSettingAdminMixin: @@ -30,3 +33,7 @@ class Media: 'admin/js/jquery.init.js', 'openwisp-notifications/js/notification-settings.js', ] + + +class GeneralSettingAdminMixin: + form = GeneralSettingForm diff --git a/openwisp_notifications/base/forms.py b/openwisp_notifications/base/forms.py index 4b1b91f5..49bdc3cc 100644 --- a/openwisp_notifications/base/forms.py +++ b/openwisp_notifications/base/forms.py @@ -33,3 +33,11 @@ class Meta: 'web': widgets.CheckboxInput, 'email': widgets.CheckboxInput, } + + +class GeneralSettingForm(ModelForm): + class Meta: + widgets = { + 'web': widgets.CheckboxInput, + 'email': widgets.CheckboxInput, + } diff --git a/openwisp_notifications/base/models.py b/openwisp_notifications/base/models.py index 700e1c92..0ab5935e 100644 --- a/openwisp_notifications/base/models.py +++ b/openwisp_notifications/base/models.py @@ -269,3 +269,39 @@ class AbstractIgnoreObjectNotification(UUIDModel): class Meta: abstract = True ordering = ['valid_till'] + + +class AbstractGeneralSetting(UUIDModel): + _DISABLE_HELP = ( + 'Note: If Yes is selected, ' 'User will not recieve any notifications. ' + ) + user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) + web = models.BooleanField( + _('disable web notifications'), + null=True, + blank=True, + help_text=_(_DISABLE_HELP), + ) + email = models.BooleanField( + _('disable email notifications'), + null=True, + blank=True, + help_text=_(_DISABLE_HELP), + ) + + class Meta: + abstract = True + verbose_name = _('general settings') + verbose_name_plural = verbose_name + ordering = ['user'] + + def __str__(self): + return '{user} - general setting'.format(user=self.user.username) + + @property + def email_notification(self): + return self.email + + @property + def web_notification(self): + return self.web diff --git a/openwisp_notifications/handlers.py b/openwisp_notifications/handlers.py index 0c5ef3da..8632c0f9 100644 --- a/openwisp_notifications/handlers.py +++ b/openwisp_notifications/handlers.py @@ -36,6 +36,7 @@ Notification = load_model('Notification') NotificationSetting = load_model('NotificationSetting') IgnoreObjectNotification = load_model('IgnoreObjectNotification') +GeneralSetting = load_model('GeneralSetting') NotificationsAppConfig = apps.get_app_config(NotificationSetting._meta.app_label) Group = swapper_load_model('openwisp_users', 'Group') @@ -178,7 +179,12 @@ def send_email_notification(sender, instance, created, **kwargs): if not (email_preference and instance.recipient.email): return - + try: + general_setting = instance.recipient.generalsetting + if general_setting.email_notification: + return + except GeneralSetting.DoesNotExist: + pass try: subject = instance.email_subject except NotificationRenderException: @@ -227,6 +233,14 @@ def clear_notification_cache(sender, instance, **kwargs): return # Reload notification only if notification is created or deleted # Display when a new notification is created + try: + general_setting = instance.recipient.generalsetting + if general_setting.web_notification: + if kwargs.get('created'): + instance.delete() + return + except GeneralSetting.DoesNotExist: + pass ws_handlers.notification_update_handler( recipient=instance.recipient, reload_widget=kwargs.get('created', True), diff --git a/openwisp_notifications/migrations/0007_generalsetting.py b/openwisp_notifications/migrations/0007_generalsetting.py new file mode 100644 index 00000000..2fb4435a --- /dev/null +++ b/openwisp_notifications/migrations/0007_generalsetting.py @@ -0,0 +1,64 @@ +# Generated by Django 3.1.4 on 2020-12-24 08:43 + +import uuid + +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), + ('openwisp_notifications', '0006_objectnotification'), + ] + + operations = [ + migrations.CreateModel( + name='GeneralSetting', + fields=[ + ( + 'id', + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ( + 'web', + models.BooleanField( + blank=True, + help_text='Note: If Yes is selected, User will not recieve any notifications. ', + null=True, + verbose_name='disable web notifications', + ), + ), + ( + 'email', + models.BooleanField( + blank=True, + help_text='Note: If Yes is selected, User will not recieve any notifications. ', + null=True, + verbose_name='disable email notifications', + ), + ), + ( + 'user', + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={ + 'verbose_name': 'general settings', + 'verbose_name_plural': 'general settings', + 'ordering': ['user'], + 'abstract': False, + 'swappable': 'OPENWISP_NOTIFICATIONS_GENERALSETTING_MODEL', + }, + ), + ] diff --git a/openwisp_notifications/models.py b/openwisp_notifications/models.py index ae7bd9fe..7059c4f6 100644 --- a/openwisp_notifications/models.py +++ b/openwisp_notifications/models.py @@ -1,6 +1,7 @@ from swapper import swappable_setting from openwisp_notifications.base.models import ( + AbstractGeneralSetting, AbstractIgnoreObjectNotification, AbstractNotification, AbstractNotificationSetting, @@ -26,3 +27,9 @@ class Meta(AbstractIgnoreObjectNotification.Meta): swappable = swappable_setting( 'openwisp_notifications', 'IgnoreObjectNotification' ) + + +class GeneralSetting(AbstractGeneralSetting): + class Meta(AbstractGeneralSetting.Meta): + abstract = False + swappable = swappable_setting('openwisp_notifications', 'GeneralSetting') diff --git a/openwisp_notifications/tests/test_general_setting.py b/openwisp_notifications/tests/test_general_setting.py new file mode 100644 index 00000000..e4710e47 --- /dev/null +++ b/openwisp_notifications/tests/test_general_setting.py @@ -0,0 +1,48 @@ +from django.test import TestCase + +from openwisp_notifications.signals import notify +from openwisp_notifications.swapper import load_model +from openwisp_users.tests.utils import TestOrganizationMixin + +GeneralSetting = load_model('GeneralSetting') +Notification = load_model('Notification') +on_queryset = Notification.objects + + +class TestDisableNotifications(TestOrganizationMixin, TestCase): + def setUp(self): + self.admin = self._get_admin() + self.org1 = self._get_org() + + def test_disable_only_email_notifications(self): + ''' + notification is created and it have emailed = False + ''' + GeneralSetting.objects.create(user=self.admin, email=True, web=False) + notify.send(sender=self.admin, type='default', target=self.org1) + self.assertEqual(on_queryset.count(), 1) + notification = on_queryset.all()[0] + self.assertEqual(notification.emailed, False) + + def test_disable_only_web_notifications(self): + ''' + notification is not created when web notifications + are disabled + ''' + GeneralSetting.objects.create(user=self.admin, email=False, web=True) + notify.send(sender=self.admin, type='default', target=self.org1) + self.assertEqual(on_queryset.count(), 0) + + def test_disable_all_notifications(self): + ''' + notification is not created when all notifications + are disabled + ''' + GeneralSetting.objects.create(user=self.admin, email=True, web=True) + notify.send(sender=self.admin, type='default', target=self.org1) + self.assertEqual(on_queryset.count(), 0) + + # test when other organizations are created + org2 = self._create_org(name='test org 2', slug='test-org-2') + notify.send(sender=self.admin, type='default', target=org2) + self.assertEqual(on_queryset.count(), 0) diff --git a/tests/openwisp2/sample_notifications/models.py b/tests/openwisp2/sample_notifications/models.py index 1c85fbef..be3b0e3a 100644 --- a/tests/openwisp2/sample_notifications/models.py +++ b/tests/openwisp2/sample_notifications/models.py @@ -4,6 +4,7 @@ AbstractNotification, AbstractNotificationSetting, AbstractIgnoreObjectNotification, + AbstractGeneralSetting, ) # Only for testing openwisp_notifications @@ -41,6 +42,11 @@ class Meta(AbstractIgnoreObjectNotification.Meta): abstract = False +class GeneralSetting(DetailsModel, AbstractGeneralSetting): + class Meta(AbstractGeneralSetting.Meta): + abstract = False + + class TestApp(UUIDModel): name = models.CharField(max_length=50) organization = models.ForeignKey(