diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index 70084adfde..c52911feed 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -265,6 +265,12 @@ class BaseInvenTreeSetting(models.Model): filters['plugin'] = plugin kwargs['plugin'] = plugin + # Filter by method + method = kwargs.get('method', None) + + if method is not None: + filters['method'] = method + try: setting = settings.filter(**filters).first() except (ValueError, cls.DoesNotExist): diff --git a/InvenTree/common/notifications.py b/InvenTree/common/notifications.py index 749af6e63d..a7177c9da5 100644 --- a/InvenTree/common/notifications.py +++ b/InvenTree/common/notifications.py @@ -5,6 +5,7 @@ from InvenTree.helpers import inheritors from InvenTree.ready import isImportingData from common.models import NotificationEntry, NotificationMessage from plugin import registry +from plugin.models import NotificationUserSetting logger = logging.getLogger('inventree') @@ -20,6 +21,7 @@ class NotificationMethod: CONTEXT_BUILTIN = ['name', 'message', ] CONTEXT_EXTRA = [] GLOBAL_SETTING = None + USER_SETTING = None def __init__(self, obj, category, targets, context) -> None: # Check if a sending fnc is defined @@ -127,10 +129,33 @@ class BulkNotificationMethod(NotificationMethod): class MethodStorageClass: liste = None + user_settings = {} def collect(self): storage.liste = inheritors(NotificationMethod) - IGNORED_NOTIFICATION_CLS + def get_usersettings(self, user): + methods = [] + for item in storage.liste: + if item.USER_SETTING: + new_key = f'NOTIFICATION_METHOD_{item.METHOD_NAME.upper()}' + + # make sure the setting exists + self.user_settings[new_key] = item.USER_SETTING + NotificationUserSetting.get_setting( + key=new_key, + user=user, + method=item.METHOD_NAME, + ) + + # save definition + methods.append({ + 'key': new_key, + 'icon': 'envelope', + 'method': item.METHOD_NAME, + }) + return methods + IGNORED_NOTIFICATION_CLS = set([ SingleNotificationMethod, diff --git a/InvenTree/part/templatetags/inventree_extras.py b/InvenTree/part/templatetags/inventree_extras.py index dc93e00efa..455c66a922 100644 --- a/InvenTree/part/templatetags/inventree_extras.py +++ b/InvenTree/part/templatetags/inventree_extras.py @@ -27,7 +27,7 @@ import InvenTree.helpers from common.models import InvenTreeSetting, ColorTheme, InvenTreeUserSetting from common.settings import currency_code_default -from plugin.models import PluginSetting +from plugin.models import PluginSetting, NotificationUserSetting register = template.Library() @@ -306,6 +306,9 @@ def setting_object(key, *args, **kwargs): return PluginSetting.get_setting_object(key, plugin=plugin) + if 'method' in kwargs: + return NotificationUserSetting.get_setting_object(key, user=kwargs['user'], method=kwargs['method']) + if 'user' in kwargs: return InvenTreeUserSetting.get_setting_object(key, user=kwargs['user']) diff --git a/InvenTree/plugin/builtin/integration/core_notifications.py b/InvenTree/plugin/builtin/integration/core_notifications.py index dc8b36114f..8fef0be44c 100644 --- a/InvenTree/plugin/builtin/integration/core_notifications.py +++ b/InvenTree/plugin/builtin/integration/core_notifications.py @@ -42,6 +42,11 @@ class CoreNotificationsPlugin(SettingsMixin, IntegrationPluginBase): ('template', 'subject', ), ] GLOBAL_SETTING = 'ENABLE_NOTIFICATION_EMAILS' + USER_SETTING = { + 'name': _('Enable email notifications'), + 'description': _('Allow sending of emails for event notifications'), + 'default': True, + 'validator': bool, } def get_targets(self): diff --git a/InvenTree/plugin/migrations/0005_notificationusersetting.py b/InvenTree/plugin/migrations/0005_notificationusersetting.py new file mode 100644 index 0000000000..4ea1959f90 --- /dev/null +++ b/InvenTree/plugin/migrations/0005_notificationusersetting.py @@ -0,0 +1,29 @@ +# Generated by Django 3.2.12 on 2022-04-03 23:38 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('plugin', '0004_alter_pluginsetting_key'), + ] + + operations = [ + migrations.CreateModel( + name='NotificationUserSetting', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('key', models.CharField(help_text='Settings key (must be unique - case insensitive)', max_length=50)), + ('value', models.CharField(blank=True, help_text='Settings value', max_length=200)), + ('method', models.CharField(max_length=255, verbose_name='Method')), + ('user', models.ForeignKey(blank=True, help_text='User', null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='User')), + ], + options={ + 'unique_together': {('method', 'user', 'key')}, + }, + ), + ] diff --git a/InvenTree/plugin/models.py b/InvenTree/plugin/models.py index 44eeafd012..0109e3f890 100644 --- a/InvenTree/plugin/models.py +++ b/InvenTree/plugin/models.py @@ -7,6 +7,7 @@ from __future__ import unicode_literals from django.utils.translation import gettext_lazy as _ from django.db import models +from django.contrib.auth.models import User import common.models @@ -182,3 +183,71 @@ class PluginSetting(common.models.BaseInvenTreeSetting): verbose_name=_('Plugin'), on_delete=models.CASCADE, ) + + +class NotificationUserSetting(common.models.BaseInvenTreeSetting): + """ + This model represents notification settings for a user + """ + + class Meta: + unique_together = [ + ('method', 'user', 'key'), + ] + + def clean(self, **kwargs): + + kwargs['method'] = self.method + + super().clean(**kwargs) + + """ + We override the following class methods, + so that we can pass the method instance + """ + + def is_bool(self, **kwargs): + + kwargs['method'] = self.method + + return super().is_bool(**kwargs) + + @property + def name(self): + return self.__class__.get_setting_name(self.key, method=self.method) + + @property + def default_value(self): + return self.__class__.get_setting_default(self.key, method=self.method) + + @property + def description(self): + return self.__class__.get_setting_description(self.key, method=self.method) + + @property + def units(self): + return self.__class__.get_setting_units(self.key, method=self.method) + + def choices(self): + return self.__class__.get_setting_choices(self.key, method=self.method) + + @classmethod + def get_setting_definition(cls, key, method, **kwargs): + from common.notifications import storage + + kwargs['settings'] = storage.user_settings + + return super().get_setting_definition(key, **kwargs) + + method = models.CharField( + max_length=255, + verbose_name=_('Method'), + ) + + user = models.ForeignKey( + User, + on_delete=models.CASCADE, + blank=True, null=True, + verbose_name=_('User'), + help_text=_('User'), + ) diff --git a/InvenTree/plugin/templatetags/plugin_extras.py b/InvenTree/plugin/templatetags/plugin_extras.py index 9e83cf96aa..d51e990cc4 100644 --- a/InvenTree/plugin/templatetags/plugin_extras.py +++ b/InvenTree/plugin/templatetags/plugin_extras.py @@ -8,7 +8,7 @@ from django.urls import reverse from common.models import InvenTreeSetting from plugin import registry - +from common.notifications import storage register = template.Library() @@ -73,3 +73,10 @@ def plugin_errors(*args, **kwargs): All plugin errors in the current session """ return registry.errors + +@register.simple_tag(takes_context=True) +def notification_settings_list(context, *args, **kwargs): + """ + List of all user notification settings + """ + return storage.get_usersettings(user=context.get('user', None)) diff --git a/InvenTree/templates/InvenTree/settings/setting.html b/InvenTree/templates/InvenTree/settings/setting.html index 9ef6008292..db1cdec15f 100644 --- a/InvenTree/templates/InvenTree/settings/setting.html +++ b/InvenTree/templates/InvenTree/settings/setting.html @@ -5,6 +5,8 @@ {% setting_object key plugin=plugin as setting %} {% elif user_setting %} {% setting_object key user=request.user as setting %} +{% elif notification_setting %} +{% setting_object key method=method user=request.user as setting %} {% else %} {% setting_object key as setting %} {% endif %} diff --git a/InvenTree/templates/InvenTree/settings/user_notifications.html b/InvenTree/templates/InvenTree/settings/user_notifications.html index 4e9889ca69..6d67d34851 100644 --- a/InvenTree/templates/InvenTree/settings/user_notifications.html +++ b/InvenTree/templates/InvenTree/settings/user_notifications.html @@ -2,6 +2,7 @@ {% load i18n %} {% load inventree_extras %} +{% load plugin_extras %} {% block label %}user-notifications{% endblock label %} @@ -12,7 +13,10 @@