From 8946dbf78fc5ba0363e4aa057a16db35da6e659e Mon Sep 17 00:00:00 2001 From: Christophe Date: Fri, 13 Dec 2019 15:51:36 +0100 Subject: [PATCH] bugfix: Do not send HTTP request when creating a local notification --- README.md | 13 ++++++-- djangoldp_notification/middlewares.py | 31 +++++++++++++++++++ djangoldp_notification/models.py | 44 +++++++++++++++++---------- 3 files changed, 70 insertions(+), 18 deletions(-) create mode 100644 djangoldp_notification/middlewares.py diff --git a/README.md b/README.md index d78b0ac..4d249b2 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,18 @@ An object allowing a User to be notified of any change on a resource or a contai | `object` | `URLField` | | ID of the resource or the container to watch | | `inbox` | `URLField` | | ID of the inbox to notify when the resource or the container change | +# Middlewares +There is a `CurrentUserMiddleware` that catches the connected user of the last performed HTTP request and adds +to every model before it is saved. This is useful if you need to get the connected user that performed +the last HTTP request in a `pre_saved` signal. You can get it by using the following line : + +```python +getattr(instance, MODEL_MODIFICATION_USER_FIELD, "Unknown user") +``` + +`MODEL_MODIFICATION_USER_FIELD` is a constant that lies in `djangoldp_notification.middlewares` and +`instance` is the instance of your model before save in DB. # Signals @@ -40,8 +51,6 @@ An object allowing a User to be notified of any change on a resource or a contai When an object is saved, a notification is created for all the subscriptions related to this object. - - ## Send email when new notification When a notification is created, an email is sent to the user. diff --git a/djangoldp_notification/middlewares.py b/djangoldp_notification/middlewares.py new file mode 100644 index 0000000..d67000a --- /dev/null +++ b/djangoldp_notification/middlewares.py @@ -0,0 +1,31 @@ +from django.db.models import signals + + +MODEL_MODIFICATION_USER_FIELD = 'modification_user' + + +class CurrentUserMiddleware: + def __init__(self, get_response=None): + self.get_response = get_response + + def __call__(self, request): + self.process_request(request) + response = self.get_response(request) + signals.pre_save.disconnect(dispatch_uid=request) + return response + + def process_request(self, request): + if request.method in ('GET', 'HEAD', 'OPTION'): + # this request shouldn't update anything + # so no signal handler should be attached + return + + if hasattr(request, 'user') and request.user.is_authenticated(): + user = request.user + else: + user = None + + def _update_users(sender, instance, **kwargs): + setattr(instance, MODEL_MODIFICATION_USER_FIELD, user) + + signals.pre_save.connect(_update_users, dispatch_uid=request, weak=False) diff --git a/djangoldp_notification/models.py b/djangoldp_notification/models.py index 980dbfb..4e9b28c 100644 --- a/djangoldp_notification/models.py +++ b/djangoldp_notification/models.py @@ -16,6 +16,8 @@ from djangoldp.fields import LDPUrlField from djangoldp.models import Model from django.template import loader + +from djangoldp_notification.middlewares import MODEL_MODIFICATION_USER_FIELD from .permissions import InboxPermissions @@ -47,32 +49,42 @@ class Subscription(Model): def __str__(self): return '{}'.format(self.object) - # --- SUBSCRIPTION SYSTEM --- @receiver(post_save, dispatch_uid="callback_notif") -def send_notification(sender, instance, **kwargs): +def send_notification(sender, instance, created, **kwargs): if sender != Notification: threads = [] try: - urlContainer = settings.BASE_URL + Model.container_id(instance) - urlResource = settings.BASE_URL + Model.resource_id(instance) + url_container = settings.BASE_URL + Model.container_id(instance) + url_resource = settings.BASE_URL + Model.resource_id(instance) except NoReverseMatch: return - for subscription in Subscription.objects.filter(models.Q(object=urlResource)|models.Q(object=urlContainer)): - process = Thread(target=send_request, args=[subscription.inbox, urlResource]) + for subscription in Subscription.objects.filter(models.Q(object=url_resource) | models.Q(object=url_container)): + process = Thread(target=send_request, args=[subscription.inbox, url_resource, instance, created]) process.start() threads.append(process) -def send_request(target, object_iri): +def send_request(target, object_iri, instance, created): + unknown = _("Unknown author") + author = getattr(getattr(instance, MODEL_MODIFICATION_USER_FIELD, unknown), "urlid", unknown) + request_type = "creation" if created else "update" + try: - req = requests.post(target, - json={"@context": "https://cdn.happy-dev.fr/owl/hdcontext.jsonld", - "object": object_iri, "type": "update"}, - headers={"Content-Type": "application/ld+json"}) - except: - logging.error('Djangoldp_notifications: Error with request') + 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) + else: + json = { + "@context": settings.LDP_RDF_CONTEXT, + "object": object_iri, + "author": author, + "type": request_type + } + requests.post(target, json=json, headers={"Content-Type": "application/ld+json"}) + except Exception as e: + logging.error('Djangoldp_notifications: Error with request: {}'.format(e)) return True @@ -81,7 +93,7 @@ def send_email_on_notification(sender, instance, created, **kwargs): if created and instance.summary and settings.JABBER_DEFAULT_HOST and instance.user.email: try: if instance.author.startswith(settings.SITE_URL): - who = str(Model.resolve_id(instance.author.replace(settings.SITE_URL,''))) + who = str(Model.resolve_id(instance.author.replace(settings.SITE_URL, ''))) else: who = requests.get(instance.author).json()['name'] except: @@ -89,13 +101,13 @@ def send_email_on_notification(sender, instance, created, **kwargs): try: if instance.object.startswith(settings.SITE_URL): - where = str(Model.resolve_id(instance.object.replace(settings.SITE_URL,''))) + where = str(Model.resolve_id(instance.object.replace(settings.SITE_URL, ''))) else: where = requests.get(instance.object).json()['name'] except: where = "Unknown place" - if(who == where): + if who == where: where = "has sent you a private message" else: where = "mention you on " + where