moved post-save hook for notifs
This commit is contained in:
		| @ -1,2 +1,2 @@ | ||||
| __version__ = '0.0.0' | ||||
| __version__ = '2.4.1' | ||||
| name = "djangoldp_notification" | ||||
|  | ||||
| @ -17,7 +17,6 @@ from djangoldp.activities.services import ActivityQueueService, ActivityPubServi | ||||
| from djangoldp_notification.middlewares import MODEL_MODIFICATION_USER_FIELD | ||||
| from djangoldp_notification.permissions import InboxPermissions, SubscriptionsPermissions | ||||
| from djangoldp_notification.views import LDPNotificationsViewSet | ||||
| from djangoldp_webpushnotification.views import _send_push | ||||
| import logging | ||||
|  | ||||
|  | ||||
| @ -277,30 +276,6 @@ def send_email_on_notification(sender, instance, created, **kwargs): | ||||
|                 html_message=html_message | ||||
|             ) | ||||
|  | ||||
| @receiver(post_save, sender=Notification) | ||||
| def send_webpush_on_notification(sender, instance, created, **kwargs): | ||||
|     if instance.summary : | ||||
|         if instance.user:   # if the person exists and accepts notifications | ||||
|  | ||||
|             try: | ||||
|                 # local author | ||||
|                 if instance.author.startswith(settings.SITE_URL): | ||||
|                     who = str(Model.resolve_id(instance.author.replace(settings.SITE_URL, '')).get_full_name()) | ||||
|                 # external author | ||||
|                 else: | ||||
|                     who = requests.get(instance.author).json()['name'] | ||||
|             except: | ||||
|                 who = "Quelqu'un" | ||||
|              | ||||
|             payload = { | ||||
|                 "head": "Notification from " + who, | ||||
|                 "body": instance.summary, | ||||
|                 "id": instance.user.id | ||||
|             }   # make the payload that we wanna send? | ||||
|  | ||||
|             _send_push(payload) | ||||
|  | ||||
|  | ||||
| @receiver(post_save, sender=settings.AUTH_USER_MODEL) | ||||
| def create_user_settings(sender, instance, created, **kwargs): | ||||
|     try: | ||||
|  | ||||
							
								
								
									
										310
									
								
								djangoldp_notification/models.py~
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										310
									
								
								djangoldp_notification/models.py~
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,310 @@ | ||||
| import requests | ||||
| import json | ||||
| from django.conf import settings | ||||
| from django.contrib.auth import get_user_model | ||||
| from django.core.mail import send_mail | ||||
| from django.core.exceptions import ObjectDoesNotExist | ||||
| from django.db import models | ||||
| from django.db.models.signals import post_save, post_delete | ||||
| from django.dispatch import receiver | ||||
| from django.template import loader | ||||
| from django.urls import NoReverseMatch, get_resolver, reverse | ||||
| from django.utils.translation import ugettext_lazy as _ | ||||
| from djangoldp.fields import LDPUrlField | ||||
| from djangoldp.models import Model | ||||
| from djangoldp.views import LDPViewSet | ||||
| from djangoldp.activities.services import ActivityQueueService, ActivityPubService, activity_sending_finished | ||||
| from djangoldp_notification.middlewares import MODEL_MODIFICATION_USER_FIELD | ||||
| from djangoldp_notification.permissions import InboxPermissions, SubscriptionsPermissions | ||||
| from djangoldp_notification.views import LDPNotificationsViewSet | ||||
| from djangoldp_webpushnotification.views import _send_push | ||||
| import logging | ||||
|  | ||||
|  | ||||
| logger = logging.getLogger('djangoldp') | ||||
|  | ||||
|  | ||||
| class Notification(Model): | ||||
|     user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='inbox', on_delete=models.deletion.CASCADE) | ||||
|     author = LDPUrlField() | ||||
|     object = LDPUrlField() | ||||
|     type = models.CharField(max_length=255) | ||||
|     summary = models.TextField() | ||||
|     date = models.DateTimeField(auto_now_add=True) | ||||
|     unread = models.BooleanField(default=True) | ||||
|  | ||||
|     class Meta(Model.Meta): | ||||
|         owner_field = 'user' | ||||
|         ordering = ['-date'] | ||||
|         permission_classes = [InboxPermissions] | ||||
|         anonymous_perms = ['add'] | ||||
|         authenticated_perms = ['inherit'] | ||||
|         owner_perms = ['view', 'change', 'control'] | ||||
|         view_set = LDPNotificationsViewSet | ||||
|  | ||||
|     # NOTE: this would be our ideal cache behaviour | ||||
|     # the functionality for optimising it was removed because of an issue with extensibility | ||||
|     #  https://git.startinblox.com/djangoldp-packages/djangoldp-notification/merge_requests/42#note_58559 | ||||
|     '''def clear_djangoldp_cache(self, cache, cache_entry): | ||||
|         # should only clear the users/x/inbox | ||||
|  | ||||
|         lookup_arg = LDPViewSet.get_lookup_arg(model=get_user_model()) | ||||
|  | ||||
|         url = reverse('{}-{}-list'.format(self.user.__class__.__name__.lower(), self.__class__.__name__.lower()), | ||||
|                       args=[getattr(self.user, lookup_arg)]) | ||||
|         url = '{}{}'.format(settings.SITE_URL, url) | ||||
|  | ||||
|         cache.invalidate(cache_entry, url) | ||||
|  | ||||
|         # invalidate the global /notifications/ container also | ||||
|         url = '{}{}'.format(settings.SITE_URL, reverse('{}-list'.format(self.__class__.__name__.lower()))) | ||||
|         cache.invalidate(cache_entry, url)''' | ||||
|  | ||||
|     def __str__(self): | ||||
|         return '{}'.format(self.type) | ||||
|  | ||||
|     def save(self, *args, **kwargs): | ||||
|         # I cannot send a notification to myself | ||||
|         if self.author.startswith(settings.SITE_URL): | ||||
|             try: | ||||
|                 # author is a WebID.. convert to local representation | ||||
|                 author = Model.resolve(self.author.replace(settings.SITE_URL, ''))[1] | ||||
|             except NoReverseMatch: | ||||
|                 author = None | ||||
|             if author == self.user: | ||||
|                 return | ||||
|  | ||||
|         super(Notification, self).save(*args, **kwargs) | ||||
|  | ||||
| class NotificationSetting(Model): | ||||
|     user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="settings") | ||||
|     receiveMail = models.BooleanField(default=True) | ||||
|  | ||||
|     class Meta: | ||||
|         auto_author = 'user' | ||||
|         owner_field = 'user' | ||||
|         anonymous_perms = [] | ||||
|         authenticated_perms = [] | ||||
|         owner_perms = ['view', 'change'] | ||||
|         container_path = 'settings/' | ||||
|         serializer_fields = ['@id', 'receiveMail'] | ||||
|         rdf_type = 'sib:usersettings' | ||||
|  | ||||
|     def __str__(self): | ||||
|         return '{} ({})'.format(self.user.get_full_name(), self.user.urlid) | ||||
|  | ||||
| class Subscription(Model): | ||||
|     object = models.URLField() | ||||
|     inbox = models.URLField() | ||||
|     field = models.CharField(max_length=255, blank=True, null=True, | ||||
|                              help_text='if set to a field name on the object model, the field will be passed instead of the object instance') | ||||
|  | ||||
|     def __str__(self): | ||||
|         return '{}'.format(self.object) | ||||
|  | ||||
|     class Meta(Model.Meta): | ||||
|         anonymous_perms = [] | ||||
|         authenticated_perms = ["add", "view", "delete"] | ||||
|         permission_classes = [SubscriptionsPermissions] | ||||
|  | ||||
|  | ||||
| @receiver(post_save, sender=Subscription, dispatch_uid="nested_subscriber_check") | ||||
| def create_nested_subscribers(sender, instance, created, **kwargs): | ||||
|     # save subscriptions for one-to-many nested fields | ||||
|     if created and not instance.is_backlink and instance.object.startswith(settings.SITE_URL): | ||||
|         try: | ||||
|             # object is a WebID.. convert to local representation | ||||
|             local = Model.resolve(instance.object.replace(settings.SITE_URL, ''))[0] | ||||
|             nested_fields = Model.get_meta(local, 'nested_fields', []) | ||||
|  | ||||
|             # Don't create nested subscriptions for user model (Notification loop issue) | ||||
|             if local._meta.model_name == get_user_model()._meta.model_name: | ||||
|                 return | ||||
|  | ||||
|             for nested_field in nested_fields: | ||||
|                 try: | ||||
|                     field = local._meta.get_field(nested_field) | ||||
|                     nested_container = field.related_model | ||||
|                     nested_container_url = Model.absolute_url(nested_container) | ||||
|  | ||||
|                     if field.one_to_many: | ||||
|                         # get the nested view set | ||||
|                         nested_url = str(instance.object) + '1/' + nested_field + '/' | ||||
|                         view, args, kwargs = get_resolver().resolve(nested_url.replace(settings.SITE_URL, '')) | ||||
|                         # get the reverse name for the field | ||||
|                         field_name = view.initkwargs['nested_related_name'] | ||||
|  | ||||
|                         if field_name is not None and field_name != '': | ||||
|                             # check that this nested-field subscription doesn't already exist | ||||
|                             existing_subscriptions = Subscription.objects.filter(object=nested_container_url, inbox=instance.inbox, | ||||
|                                                                                  field=field_name) | ||||
|                             # save a Subscription on this container | ||||
|                             if not existing_subscriptions.exists(): | ||||
|                                 Subscription.objects.create(object=nested_container_url, inbox=instance.inbox, is_backlink=True, | ||||
|                                                             field=field_name) | ||||
|                 except: | ||||
|                     pass | ||||
|         except: | ||||
|             pass | ||||
|  | ||||
|  | ||||
|  | ||||
| # --- SUBSCRIPTION SYSTEM --- | ||||
| @receiver(post_save, dispatch_uid="callback_notif") | ||||
| @receiver(post_delete, dispatch_uid="delete_callback_notif") | ||||
| def send_notification(sender, instance, **kwargs): | ||||
|     if(type(instance).__name__ != "ScheduledActivity" and type(instance).__name__ != "LogEntry" and type(instance).__name__ != "Activity"): | ||||
|         if sender != Notification: | ||||
|             # don't send notifications for foreign resources | ||||
|             if hasattr(instance, 'urlid') and Model.is_external(instance.urlid): | ||||
|                 return | ||||
|  | ||||
|             recipients = [] | ||||
|             try: | ||||
|                 url_container = settings.BASE_URL + Model.container_id(instance) | ||||
|                 url_resource = settings.BASE_URL + Model.resource_id(instance) | ||||
|             except NoReverseMatch: | ||||
|                 return | ||||
|  | ||||
|             # dispatch a notification for every Subscription on this resource | ||||
|             for subscription in Subscription.objects.filter(models.Q(object=url_resource) | models.Q(object=url_container)): | ||||
|                 if subscription.inbox not in recipients and (not subscription.is_backlink or not kwargs.get("created")): | ||||
|                     # I may have configured to send the subscription to a foreign key | ||||
|                     if subscription.field is not None and len(subscription.field) > 1: | ||||
|                         try: | ||||
|                             if kwargs.get("created"): | ||||
|                                 continue | ||||
|  | ||||
|                             instance = getattr(instance, subscription.field, instance) | ||||
|  | ||||
|                             # don't send notifications for foreign resources | ||||
|                             if hasattr(instance, 'urlid') and Model.is_external(instance.urlid): | ||||
|                                 continue | ||||
|  | ||||
|                             url_resource = settings.BASE_URL + Model.resource_id(instance) | ||||
|                         except NoReverseMatch: | ||||
|                             continue | ||||
|                         except ObjectDoesNotExist: | ||||
|                             continue | ||||
|  | ||||
|                     send_request(subscription.inbox, url_resource, instance, kwargs.get("created")) | ||||
|                     recipients.append(subscription.inbox) | ||||
|  | ||||
|  | ||||
| @receiver(activity_sending_finished, sender=ActivityQueueService) | ||||
| def _handle_prosody_response(sender, response, saved_activity, **kwargs): | ||||
|     '''callback function for handling a response from Prosody on a notification''' | ||||
|     # if text is defined in the response body then it's an error | ||||
|     if saved_activity is not None: | ||||
|         response_body = saved_activity.response_to_json() | ||||
|         if 'condition' in response_body: | ||||
|             logger.error("[DjangoLDP-Notification.models._handle_prosody_response] error in Prosody response " + | ||||
|                          str(response_body)) | ||||
|  | ||||
|  | ||||
| def send_request(target, object_iri, instance, created): | ||||
|     author = getattr(getattr(instance, MODEL_MODIFICATION_USER_FIELD, None), "urlid", str(_("Auteur inconnu"))) | ||||
|     if(created is not None): | ||||
|         request_type = "creation" if created else "update" | ||||
|     else: | ||||
|         request_type = "deletion" | ||||
|  | ||||
|     # local inbox | ||||
|     if target.startswith(settings.SITE_URL): | ||||
|         user = Model.resolve_parent(target.replace(settings.SITE_URL, '')) | ||||
|         Notification.objects.create(user=user, object=object_iri, type=request_type, author=author) | ||||
|     # external inbox | ||||
|     else: | ||||
|         json = { | ||||
|             "@context": settings.LDP_RDF_CONTEXT, | ||||
|             "object": object_iri, | ||||
|             "author": author, | ||||
|             "type": request_type | ||||
|         } | ||||
|         ActivityQueueService.send_activity(target, json) | ||||
|  | ||||
|  | ||||
| @receiver(post_save, sender=Notification) | ||||
| def send_email_on_notification(sender, instance, created, **kwargs): | ||||
|     if created and instance.summary and getattr(settings,'JABBER_DEFAULT_HOST',False) and instance.user.email: | ||||
|         # get author name, and store in who | ||||
|         try: | ||||
|             # local author | ||||
|             if instance.author.startswith(settings.SITE_URL): | ||||
|                 who = str(Model.resolve_id(instance.author.replace(settings.SITE_URL, '')).get_full_name()) | ||||
|             # external author | ||||
|             else: | ||||
|                 who = requests.get(instance.author).json()['name'] | ||||
|         except: | ||||
|             who = "Quelqu'un" | ||||
|  | ||||
|         # get identifier for resource triggering notification, and store in where | ||||
|         try: | ||||
|             if instance.object.startswith(settings.SITE_URL): | ||||
|                 if hasattr(Model.resolve_id(instance.object.replace(settings.SITE_URL, '')), 'get_full_name'): | ||||
|                     where = Model.resolve_id(instance.object.replace(settings.SITE_URL, '')).get_full_name() | ||||
|                 else: | ||||
|                     where = str(Model.resolve_id(instance.object.replace(settings.SITE_URL, '')).name) | ||||
|             else: | ||||
|                 where = requests.get(instance.object).json()['name'] | ||||
|         except: | ||||
|             where = "le chat" | ||||
|  | ||||
|         if who == where: | ||||
|             where = "t'a envoyé un message privé" | ||||
|         else: | ||||
|             where = "t'a mentionné sur " + where | ||||
|  | ||||
|         on = (getattr(settings, 'INSTANCE_DEFAULT_CLIENT', False) or settings.JABBER_DEFAULT_HOST) | ||||
|  | ||||
|         html_message = loader.render_to_string( | ||||
|             'email.html', | ||||
|             { | ||||
|                 'on': on, | ||||
|                 'instance': instance, | ||||
|                 'author': who, | ||||
|                 'object': where | ||||
|             } | ||||
|         ) | ||||
|  | ||||
|         if instance.user.settings.receiveMail: | ||||
|             send_mail( | ||||
|                 'Notification sur ' + on, | ||||
|                 instance.summary, | ||||
|                 (getattr(settings, 'EMAIL_HOST_USER', False) or "noreply@" + settings.JABBER_DEFAULT_HOST), | ||||
|                 [instance.user.email], | ||||
|                 fail_silently=True, | ||||
|                 html_message=html_message | ||||
|             ) | ||||
|  | ||||
| @receiver(post_save, sender=Notification) | ||||
| def send_webpush_on_notification(sender, instance, created, **kwargs): | ||||
|     if instance.summary : | ||||
|         if instance.user:   # if the person exists and accepts notifications | ||||
|  | ||||
|             try: | ||||
|                 # local author | ||||
|                 if instance.author.startswith(settings.SITE_URL): | ||||
|                     who = str(Model.resolve_id(instance.author.replace(settings.SITE_URL, '')).get_full_name()) | ||||
|                 # external author | ||||
|                 else: | ||||
|                     who = requests.get(instance.author).json()['name'] | ||||
|             except: | ||||
|                 who = "Quelqu'un" | ||||
|              | ||||
|             payload = { | ||||
|                 "head": "Notification from " + who, | ||||
|                 "body": instance.summary, | ||||
|                 "id": instance.user.id | ||||
|             }   # make the payload that we wanna send? | ||||
|  | ||||
|             _send_push(payload) | ||||
|  | ||||
|  | ||||
| @receiver(post_save, sender=settings.AUTH_USER_MODEL) | ||||
| def create_user_settings(sender, instance, created, **kwargs): | ||||
|     try: | ||||
|         if created and instance.urlid.startswith(settings.SITE_URL): | ||||
|             NotificationSetting.objects.create(user=instance) | ||||
|     except: | ||||
|         pass | ||||
		Reference in New Issue
	
	Block a user