예제 #1
0
    def test_register_unregister_notification_type(self):
        test_type = {
            'verbose_name': 'Test Notification Type',
            'level': 'test',
            'verb': 'testing',
            'message': '{notification.verb} initiated by {notification.actor} since {notification}',
            'email_subject': '[{site.name}] {notification.verb} reported by {notification.actor}',
        }

        with self.subTest('Registering new notification type'):
            register_notification_type('test_type', test_type)
            self.notification_options.update({'type': 'test_type'})
            self._create_notification()
            n = notification_queryset.first()
            self.assertEqual(n.level, 'test')
            self.assertEqual(n.verb, 'testing')
            self.assertEqual(
                n.message, '<p>testing initiated by admin since 0\xa0minutes</p>',
            )
            self.assertEqual(n.email_subject, '[example.com] testing reported by admin')

        with self.subTest('Re-registering a notification type'):
            with self.assertRaises(ImproperlyConfigured):
                register_notification_type('test_type', test_type)

        with self.subTest('Check registration in NOTIFICATION_CHOICES'):
            notification_choice = NOTIFICATION_CHOICES[-1]
            self.assertTupleEqual(
                notification_choice, ('test_type', 'Test Notification Type')
            )

        with self.subTest('Unregistering a notification type which does not exists'):
            with self.assertRaises(ImproperlyConfigured):
                unregister_notification_type('wrong type')

        with self.subTest('Unregistering a notification choice which does not exists'):
            with self.assertRaises(ImproperlyConfigured):
                _unregister_notification_choice('wrong type')

        with self.subTest('Unregistering "test_type"'):
            unregister_notification_type('test_type')
            with self.assertRaises(ImproperlyConfigured):
                get_notification_configuration('test_type')

        with self.subTest('Using non existing notification type for new notification'):
            with self.assertRaises(ImproperlyConfigured):
                self._create_notification()
                n = notification_queryset.first()

        with self.subTest('Check unregistration in NOTIFICATION_CHOICES'):
            with self.assertRaises(ImproperlyConfigured):
                _unregister_notification_choice('test_type')
 def get_message(self, email_message=False):
     if self.type:
         # setting links in notification object for message rendering
         self.actor_link = self.actor_url
         self.action_link = self.action_url
         self.target_link = (
             self.target_url if not email_message else self.redirect_view_url
         )
         try:
             config = get_notification_configuration(self.type)
             data = self.data or {}
             if 'message' in config:
                 md_text = config['message'].format(notification=self, **data)
             else:
                 md_text = render_to_string(
                     config['message_template'], context=dict(notification=self)
                 ).strip()
         except (AttributeError, KeyError, NotificationRenderException) as exception:
             self._invalid_notification(
                 self.pk,
                 exception,
                 'Error encountered in rendering notification message',
             )
         # clean up
         self.actor_link = self.action_link = self.target_link = None
         return mark_safe(markdown(md_text))
     else:
         return self.description
    def test_post_migration_handler(self):
        # Simulates loading of app when Django server starts
        admin = self._get_admin()
        org_user = self._create_staff_org_admin()
        self.assertEqual(ns_queryset.count(), 3)

        default_type_config = get_notification_configuration('default')
        base_unregister_notification_type('default')
        base_register_notification_type('test', test_notification_type)
        notification_type_registered_unregistered_handler(sender=self)

        # Notification Setting for "default" type are deleted
        self.assertEqual(
            ns_queryset.filter(type='default', deleted=True).count(), 3)

        # Notification Settings for "test" type are created
        queryset = NotificationSetting.objects.filter(deleted=False)
        if NotificationSetting._meta.app_label == 'sample_notifications':
            self.assertEqual(queryset.count(), 6)
            self.assertEqual(queryset.filter(user=admin).count(), 4)
            self.assertEqual(queryset.filter(user=org_user.user).count(), 2)
        else:
            self.assertEqual(queryset.count(), 3)
            self.assertEqual(queryset.filter(user=admin).count(), 2)
            self.assertEqual(queryset.filter(user=org_user.user).count(), 1)

        base_register_notification_type('default', default_type_config)
예제 #4
0
    def get_message(self, email_message=False):
        if self.type:
            # setting links in notification object for message rendering
            self.actor_link = self.actor_url
            self.action_link = self.action_url
            self.target_link = (
                self.target_url if not email_message else self.redirect_view_url
            )

            config = get_notification_configuration(self.type)
            try:
                data = self.data or {}
                if 'message' in config:
                    md_text = config['message'].format(notification=self, **data)
                else:
                    md_text = render_to_string(
                        config['message_template'], context=dict(notification=self)
                    ).strip()
            except (AttributeError, KeyError) as e:
                from openwisp_notifications.tasks import delete_notification

                logger.error(e)
                delete_notification.delay(notification_id=self.pk)
                raise NotificationRenderException(
                    'Error in rendering notification message.'
                )
            # clean up
            self.actor_link = self.action_link = self.target_link = None
            return mark_safe(markdown(md_text))
        else:
            return self.description
예제 #5
0
    def test_unregistered_notification_type_related_notification(self):
        # Notifications related to notification type should
        # get deleted on unregistration of notification type
        default_type_config = get_notification_configuration('default')
        self.notification_options.update({'type': 'default'})
        unregister_notification_type('default')
        self.assertEqual(notification_queryset.count(), 0)

        register_notification_type('default', default_type_config)
예제 #6
0
 def email_subject(self):
     if self.type:
         try:
             config = get_notification_configuration(self.type)
             return config['email_subject'].format(
                 site=Site.objects.get_current(), notification=self
             )
         except AttributeError as e:
             logger.error(e)
             raise NotificationException('Error while generating notification')
     elif self.data.get('email_subject', None):
         return self.data.get('email_subject')
     else:
         return self.message
예제 #7
0
    def test_notification_type_email_web_notification_defaults(self):
        test_type = {
            'verbose_name': 'Test Notification Type',
            'level': 'info',
            'verb': 'testing',
            'message': 'Test message',
            'email_subject': 'Test Email Subject',
        }
        register_notification_type('test_type', test_type)

        notification_type_config = get_notification_configuration('test_type')
        self.assertTrue(notification_type_config['web_notification'])
        self.assertTrue(notification_type_config['email_notification'])

        unregister_notification_type('test_type')
 def email_subject(self):
     if self.type:
         try:
             config = get_notification_configuration(self.type)
             data = self.data or {}
             return config['email_subject'].format(
                 site=Site.objects.get_current(), notification=self, **data
             )
         except (AttributeError, KeyError, NotificationRenderException) as exception:
             self._invalid_notification(
                 self.pk,
                 exception,
                 'Error encountered in generating notification email',
             )
     elif self.data.get('email_subject', None):
         return self.data.get('email_subject')
     else:
         return self.message
예제 #9
0
    def email_subject(self):
        if self.type:
            try:
                config = get_notification_configuration(self.type)
                data = self.data or {}
                return config['email_subject'].format(
                    site=Site.objects.get_current(), notification=self, **data
                )
            except (AttributeError, KeyError) as e:
                from openwisp_notifications.tasks import delete_notification

                logger.error(e)
                delete_notification.delay(notification_id=self.pk)
                raise NotificationRenderException(
                    'Error while generating notification email'
                )
        elif self.data.get('email_subject', None):
            return self.data.get('email_subject')
        else:
            return self.message
예제 #10
0
    def message(self):
        if self.type:
            # setting links in notification object for message rendering
            self.actor_link = _get_object_link(
                self, field='actor', html=False, url_only=True, absolute_url=True
            )
            self.action_link = _get_object_link(
                self,
                field='action_object',
                html=False,
                url_only=True,
                absolute_url=True,
            )
            self.target_link = _get_object_link(
                self, field='target', html=False, url_only=True, absolute_url=True
            )

            config = get_notification_configuration(self.type)
            try:
                if 'message' in config:
                    md_text = config['message'].format(notification=self)
                else:
                    md_text = render_to_string(
                        config['message_template'], context=dict(notification=self)
                    ).strip()
            except AttributeError as e:
                logger.error(e)
                md_text = (
                    'Error while generating notification message,'
                    ' notification data may have been deleted.'
                )
            # clean up
            self.actor_link = self.action_link = self.target_link = None
            return mark_safe(markdown(md_text))
        else:
            return self.description
예제 #11
0
def notify_handler(**kwargs):
    """
    Handler function to create Notification instance upon action signal call.
    """
    # Pull the options out of kwargs
    kwargs.pop('signal', None)
    actor = kwargs.pop('sender')
    public = bool(kwargs.pop('public', True))
    description = kwargs.pop('description', None)
    timestamp = kwargs.pop('timestamp', timezone.now())
    recipient = kwargs.pop('recipient', None)
    notification_type = kwargs.pop('type', None)
    notification_template = get_notification_configuration(notification_type)
    level = notification_template.get(
        'level', kwargs.pop('level', Notification.LEVELS.info)
    )
    verb = notification_template.get('verb', kwargs.pop('verb', None))
    target_org = getattr(kwargs.get('target', None), 'organization_id', None)

    where = Q(is_superuser=True)
    where_group = Q()
    if target_org:
        where = where | (Q(is_staff=True) & Q(openwisp_users_organization=target_org))
        where_group = Q(openwisp_users_organization=target_org)
    where_group = where_group & Q(notificationuser__receive=True)
    where = where & Q(notificationuser__receive=True)

    if recipient:
        # Check if recipient is User, Group or QuerySet
        if isinstance(recipient, Group):
            recipients = recipient.user_set.filter(where_group)
        elif isinstance(recipient, (QuerySet, list)):
            recipients = recipient
        else:
            recipients = [recipient]
    else:
        recipients = (
            User.objects.select_related('notificationuser')
            .order_by('date_joined')
            .filter(where)
        )

    optional_objs = [
        (kwargs.pop(opt, None), opt) for opt in ('target', 'action_object')
    ]

    new_notifications = []
    for recipient in recipients:
        newnotify = Notification(
            recipient=recipient,
            actor_content_type=ContentType.objects.get_for_model(actor),
            actor_object_id=actor.pk,
            verb=str(verb),
            public=public,
            description=description,
            timestamp=timestamp,
            level=level,
            type=notification_type,
        )

        # Set optional objects
        for obj, opt in optional_objs:
            if obj is not None:
                setattr(newnotify, '%s_object_id' % opt, obj.pk)
                setattr(
                    newnotify,
                    '%s_content_type' % opt,
                    ContentType.objects.get_for_model(obj),
                )
        if kwargs and EXTRA_DATA:
            newnotify.data = kwargs
        newnotify.save()
        new_notifications.append(newnotify)

    return new_notifications
예제 #12
0
def notify_handler(**kwargs):
    """
    Handler function to create Notification instance upon action signal call.
    """
    # Pull the options out of kwargs
    kwargs.pop('signal', None)
    actor = kwargs.pop('sender')
    public = bool(kwargs.pop('public', True))
    description = kwargs.pop('description', None)
    timestamp = kwargs.pop('timestamp', timezone.now())
    recipient = kwargs.pop('recipient', None)
    notification_type = kwargs.pop('type', None)
    notification_template = get_notification_configuration(notification_type)
    target = kwargs.get('target', None)
    level = notification_template.get(
        'level', kwargs.pop('level', Notification.LEVELS.info)
    )
    verb = notification_template.get('verb', kwargs.pop('verb', None))
    target_org = getattr(target, 'organization_id', None)
    user_app_name = User._meta.app_label

    where = Q(is_superuser=True)
    not_where = Q()
    where_group = Q()
    if target_org:
        org_admin_query = Q(
            **{
                f'{user_app_name}_organizationuser__organization': target_org,
                f'{user_app_name}_organizationuser__is_admin': True,
            }
        )
        where = where | (Q(is_staff=True) & org_admin_query)
        where_group = org_admin_query

        # We can only find notification setting if notification type and
        # target organization is present.
        if notification_type:
            # Create notification for users who have opted for receiving notifications.
            # For users who have not configured web_notifications,
            # use default from notification type
            web_notification = Q(notificationsetting__web=True)
            if notification_template['web_notification']:
                web_notification |= Q(notificationsetting__web=None)

            notification_setting = web_notification & Q(
                notificationsetting__type=notification_type,
                notificationsetting__organization_id=target_org,
            )
            where = where & notification_setting
            where_group = where_group & notification_setting

    # Ensure notifications are only sent to active user
    where = where & Q(is_active=True)
    where_group = where_group & Q(is_active=True)

    # We can only find ignore notification setting if target object is present
    if target:
        not_where = Q(
            ignoreobjectnotification__object_id=target.pk,
            ignoreobjectnotification__object_content_type=ContentType.objects.get_for_model(
                target._meta.model
            ),
        ) & (
            Q(ignoreobjectnotification__valid_till=None)
            | Q(ignoreobjectnotification__valid_till__gt=timezone.now())
        )

    if recipient:
        # Check if recipient is User, Group or QuerySet
        if isinstance(recipient, Group):
            recipients = recipient.user_set.filter(where_group)
        elif isinstance(recipient, (QuerySet, list)):
            recipients = recipient
        else:
            recipients = [recipient]
    else:
        recipients = (
            User.objects.prefetch_related(
                'notificationsetting_set', 'ignoreobjectnotification_set'
            )
            .order_by('date_joined')
            .filter(where)
            .exclude(not_where)
        )
    optional_objs = [
        (kwargs.pop(opt, None), opt) for opt in ('target', 'action_object')
    ]

    notification_list = []
    for recipient in recipients:
        notification = Notification(
            recipient=recipient,
            actor=actor,
            verb=str(verb),
            public=public,
            description=description,
            timestamp=timestamp,
            level=level,
            type=notification_type,
        )

        # Set optional objects
        for obj, opt in optional_objs:
            if obj is not None:
                setattr(notification, '%s_object_id' % opt, obj.pk)
                setattr(
                    notification,
                    '%s_content_type' % opt,
                    ContentType.objects.get_for_model(obj),
                )
        if kwargs and EXTRA_DATA:
            notification.data = kwargs
        notification.save()
        notification_list.append(notification)

    return notification_list
 def type_config(self):
     return get_notification_configuration(self.type)