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)
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
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)
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
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
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
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
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
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)