diff --git a/notifications/admin.py b/notifications/admin.py index 3d9c172..95fb2b0 100644 --- a/notifications/admin.py +++ b/notifications/admin.py @@ -9,10 +9,11 @@ Notification = load_model('notifications', 'Notification') class NotificationAdmin(AbstractNotificationAdmin): raw_id_fields = ('recipient',) + readonly_fields = ('action_object_url', 'actor_object_url', 'target_object_url') list_display = ('recipient', 'actor', 'level', 'target', 'unread', 'public') list_filter = ('level', 'unread', 'public', 'timestamp',) - + def get_queryset(self, request): qs = super(NotificationAdmin, self).get_queryset(request) return qs.prefetch_related('actor') diff --git a/notifications/base/models.py b/notifications/base/models.py index 43f9ee3..bcc8bed 100644 --- a/notifications/base/models.py +++ b/notifications/base/models.py @@ -11,9 +11,10 @@ from django.core.exceptions import ImproperlyConfigured from django.db import models from django.db.models.query import QuerySet from django.utils import timezone +from django.utils.html import format_html + from jsonfield.fields import JSONField from model_utils import Choices - from notifications import settings as notifications_settings from notifications.signals import notify from notifications.utils import id2slug @@ -24,6 +25,12 @@ if StrictVersion(get_version()) >= StrictVersion('1.8.0'): else: from django.contrib.contenttypes.generic import GenericForeignKey # noqa +try: + # Django >= 1.7 + from django.urls import reverse, NoReverseMatch +except ImportError: + # Django <= 1.6 + from django.core.urlresolvers import reverse, NoReverseMatch # pylint: disable=no-name-in-module,import-error EXTRA_DATA = notifications_settings.get_config()['USE_JSONFIELD'] @@ -252,6 +259,33 @@ class AbstractNotification(models.Model): self.unread = True self.save() + def actor_object_url(self): + try: + url = reverse("admin:{0}_{1}_change".format(self.actor_content_type.app_label, + self.actor_content_type.model), + args=(self.actor_object_id,)) + return format_html("{id}", url=url, id=self.actor_object_id) + except NoReverseMatch: + return self.actor_object_id + + def action_object_url(self): + try: + url = reverse("admin:{0}_{1}_change".format(self.action_object_content_type.app_label, + self.action_content_type.model), + args=(self.action_object_id,)) + return format_html("{id}", url=url, id=self.action_object_object_id) + except NoReverseMatch: + return self.action_object_object_id + + def target_object_url(self): + try: + url = reverse("admin:{0}_{1}_change".format(self.target_content_type.app_label, + self.target_content_type.model), + args=(self.target_object_id,)) + return format_html("{id}", url=url, id=self.target_object_id) + except NoReverseMatch: + return self.target_object_id + def notify_handler(verb, **kwargs): """ @@ -270,6 +304,7 @@ def notify_handler(verb, **kwargs): timestamp = kwargs.pop('timestamp', timezone.now()) Notification = load_model('notifications', 'Notification') level = kwargs.pop('level', Notification.LEVELS.info) + actor_for_concrete_model = kwargs.pop('actor_for_concrete_model', True) # Check if User or Group if isinstance(recipient, Group): @@ -284,7 +319,7 @@ def notify_handler(verb, **kwargs): for recipient in recipients: newnotify = Notification( recipient=recipient, - actor_content_type=ContentType.objects.get_for_model(actor), + actor_content_type=ContentType.objects.get_for_model(actor, for_concrete_model=actor_for_concrete_model), actor_object_id=actor.pk, verb=str(verb), public=public, @@ -296,9 +331,10 @@ def notify_handler(verb, **kwargs): # Set optional objects for obj, opt in optional_objs: if obj is not None: + for_concrete_model = kwargs.pop(f'{opt}_for_concrete_model', True) setattr(newnotify, '%s_object_id' % opt, obj.pk) setattr(newnotify, '%s_content_type' % opt, - ContentType.objects.get_for_model(obj)) + ContentType.objects.get_for_model(obj, for_concrete_model=for_concrete_model)) if kwargs and EXTRA_DATA: newnotify.data = kwargs.copy() diff --git a/notifications/templatetags/notifications_tags.py b/notifications/templatetags/notifications_tags.py index 8e9d425..b589f71 100644 --- a/notifications/templatetags/notifications_tags.py +++ b/notifications/templatetags/notifications_tags.py @@ -41,7 +41,9 @@ def register_notify_callbacks(badge_class='live_notify_badge', # pylint: disabl refresh_period=15, callbacks='', api_name='list', - fetch=5): + fetch=5, + nonce=None + ): refresh_period = int(refresh_period) * 1000 if api_name == 'list': @@ -68,7 +70,10 @@ def register_notify_callbacks(badge_class='live_notify_badge', # pylint: disabl fetch_count=fetch ) - script = "" diff --git a/notifications/tests/templates/test_live.html b/notifications/tests/templates/test_live.html index c8c92c5..eb66c1c 100644 --- a/notifications/tests/templates/test_live.html +++ b/notifications/tests/templates/test_live.html @@ -2,7 +2,7 @@ -{% register_notify_callbacks callbacks='fill_notification_list,fill_notification_badge' fetch=20 refresh_period=5 %} +{% register_notify_callbacks callbacks='fill_notification_list,fill_notification_badge' fetch=20 refresh_period=5 nonce='{{nonce}}' %} There are this many notifications pending: {% live_notify_badge %} diff --git a/notifications/tests/tests.py b/notifications/tests/tests.py index d472adf..dafe35f 100644 --- a/notifications/tests/tests.py +++ b/notifications/tests/tests.py @@ -449,7 +449,7 @@ class NotificationTestPages(TestCase): request = factory.get('/notification/live_updater') request.user = self.to_user - render(request, 'notifications/test_tags.html', {'request': request}) + render(request, 'notifications/test_tags.html', {'request': request, 'nonce': 'nonce-T5esDNXMnDe5lKMQ6ZzTUw=='}) # TODO: Add more tests to check what is being output.