Small refactoring for tracking handler to correct a but in unregister and also allow to switch user when the api is called with the act_as parameter
--- a/server/src/metaeducation/auth.py Tue Jul 12 17:40:27 2016 +0200
+++ b/server/src/metaeducation/auth.py Fri Jul 22 23:56:47 2016 +0200
@@ -8,6 +8,8 @@
from rest_framework.authentication import BaseAuthentication
from rest_framework import exceptions
+from metaeducation.tracking import change_handlers_user
+
logger = logging.getLogger(__name__)
@@ -87,4 +89,11 @@
logger.debug("CLIENT CREDENTIAL AUTH: user %r is authenticated by token %r, auth success", external_id, token)
+
+
+ if hasattr(request, 'renkan_request_id') and user != getattr(request,'user', None):
+ # Re-register the tracking handlers with the new user
+ logger.debug("CLIENT CREDENTIAL AUTH: Change the registered tracking handlers to user %r", user.external_id)
+ change_handlers_user(user, request.renkan_request_id)
+
return (user, None)
--- a/server/src/metaeducation/tracking/__init__.py Tue Jul 12 17:40:27 2016 +0200
+++ b/server/src/metaeducation/tracking/__init__.py Fri Jul 22 23:56:47 2016 +0200
@@ -1,8 +1,10 @@
from .tasks import send_tracking_data
from .messages import send_close_renkan, send_open_edit_renkan, send_open_read_renkan, \
send_delete_renkan, send_create_renkan, send_update_renkan
+from .signals_handler import register_handlers, register_pre_save_handlers, unregister_handlers, change_handlers_user
__all__ = [
'send_tracking_data', 'send_close_renkan', 'send_open_read_renkan', 'send_open_edit_renkan',
- 'send_delete_renkan', 'send_update_renkan', 'send_create_renkan'
+ 'send_delete_renkan', 'send_update_renkan', 'send_create_renkan', 'register_handlers',
+ 'unregister_handlers', 'register_pre_save_handlers', 'change_handlers_user'
]
--- a/server/src/metaeducation/tracking/messages.py Tue Jul 12 17:40:27 2016 +0200
+++ b/server/src/metaeducation/tracking/messages.py Fri Jul 22 23:56:47 2016 +0200
@@ -2,7 +2,6 @@
import json
import logging
import pytz
-import functools
from .tasks import send_tracking_data
@@ -47,10 +46,10 @@
msg = {
'actor': {
'objectType': 'Agent',
- 'name': current_user,
+ 'name': current_user or 'n/a',
'account': {
'homePage': 'https://www.metaeducation.fr/Utilisateurs/',
- 'name': current_user
+ 'name': current_user or 'n/a'
}
},
'verb': verbNode,
@@ -135,16 +134,12 @@
send_tracking_data.delay(msg)
-def _send_operation_renkan(action, renkan, current_user, content=None):
- if not content:
- content = json.loads(renkan.content)
- title = renkan.title
- renkan_guid = renkan.renkan_guid
- else:
- content = json.loads(content)
- title = content.get('title', '')
- renkan_guid = content.get('id', content.get('_id', ''))
- msg = get_base_message(action, renkan_guid, current_user)
+def send_delete_renkan(renkan, current_user):
+ content = json.loads(renkan.content)
+ title = renkan.title
+ renkan_guid = renkan.renkan_guid
+
+ msg = get_base_message('delete', renkan_guid, current_user)
msg['object'] = {
**(msg.get('object',{})),
**{
@@ -161,9 +156,31 @@
}
send_tracking_data.delay(msg)
+# This must be called with a revision object containing the new content BEFORE the object save
+def send_update_renkan(revision, current_user):
+ renkan = revision.parent_renkan
+ previousContent = json.loads(renkan.content)
+ content = json.loads(revision.content)
+ title = renkan.title
+ renkan_guid = renkan.renkan_guid
+ msg = get_base_message('update', renkan_guid, current_user)
+ msg['object'] = {
+ **(msg.get('object',{})),
+ **{
+ "definition": {
+ "name": {
+ 'fr-FR': title
+ },
+ "type": "http://www.w3.org/ns/activitystreams#Renkan",
+ "extensions": {
+ 'http://www.w3.org/ns/activitystreams#Data': content,
+ 'http://www.w3.org/ns/activitystreams#previousData': previousContent,
+ }
+ }
+ }
+ }
+ send_tracking_data.delay(msg)
-send_delete_renkan = functools.partial(_send_operation_renkan, 'delete')
-send_update_renkan = functools.partial(_send_operation_renkan, 'update')
def send_create_renkan(renkan, current_user):
msg = get_base_message('create', renkan.renkan_guid, current_user)
--- a/server/src/metaeducation/tracking/middleware.py Tue Jul 12 17:40:27 2016 +0200
+++ b/server/src/metaeducation/tracking/middleware.py Fri Jul 22 23:56:47 2016 +0200
@@ -6,11 +6,10 @@
from renkanmanager.models import Renkan, Revision
-from . import send_delete_renkan, send_create_renkan, send_update_renkan
+from . import send_update_renkan, register_handlers, unregister_handlers, register_pre_save_handlers
logger = logging.getLogger(__name__)
-# Inspired by https://github.com/Atomidata/django-audit-log/blob/master/audit_log/middleware.py
class TrackingMiddleware(object):
def process_request(self, request):
@@ -20,42 +19,23 @@
else:
user = None
- request.renkan_request_id = uuid.uuid4()
+ request.renkan_request_id = str(uuid.uuid4())
+ register_handlers(user, request.renkan_request_id)
- pre_delete.connect(curry(self.renkan_delete, user), sender=Renkan, dispatch_uid = (self.__class__, request.renkan_request_id,), weak=False)
- post_save.connect(curry(self.revision_save, user), sender=Revision, dispatch_uid = (self.__class__, request.renkan_request_id,), weak=False)
def process_response(self, request, response):
if hasattr(request, 'renkan_request_id'):
- pre_delete.disconnect(dispatch_uid = (self.__class__, request.renkan_request_id,))
- post_save.disconnect(dispatch_uid = (self.__class__, request.renkan_request_id,))
+ unregister_handlers(request.renkan_request_id)
return response
- def process_exception(self, request, exception):
- if hasattr(request, 'renkan_request_id'):
- pre_delete.disconnect(dispatch_uid = (self.__class__, request.renkan_request_id,))
- post_save.disconnect(dispatch_uid = (self.__class__, request.renkan_request_id,))
- return None
-
def process_view(self, request, view_func, view_args, view_kwargs):
if view_func.__name__ == 'RenkanDetail' and view_func.__module__ == 'renkanmanager.api.views' and request.method == 'PUT' and 'renkan_guid' in view_kwargs:
if hasattr(request, 'user') and request.user.is_authenticated():
user = request.user.external_id
else:
user = None
- send_update_renkan(None, user, request.body.decode('utf-8'))
+ # this test should never fail
+ if not hasattr(request, 'renkan_request_id'):
+ request.renkan_request_id = str(uuid.uuid4())
+ register_pre_save_handlers(user, request.renkan_request_id)
return None
-
-
- def renkan_delete(self, user, sender, **kwargs):
- renkan = kwargs.get('instance', None)
- if not renkan:
- return
- send_delete_renkan(renkan, user)
-
- def revision_save(self, user, sender, **kwargs):
- revision = kwargs.get('instance', None)
- if not revision:
- return
- if kwargs.get('created', False) and revision.parent_renkan.revision_count <= 1:
- send_create_renkan(revision.parent_renkan, user)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/server/src/metaeducation/tracking/signals_handler.py Fri Jul 22 23:56:47 2016 +0200
@@ -0,0 +1,58 @@
+from functools import partial
+
+import logging
+
+from django.db.models.signals import pre_delete, post_save, pre_save
+
+from renkanmanager.models import Renkan, Revision
+from . import send_delete_renkan, send_create_renkan, send_update_renkan
+
+logger = logging.getLogger(__name__)
+
+# Inspired by https://github.com/Atomidata/django-audit-log/blob/master/audit_log/middleware.py
+
+def register_handlers(user, uid):
+ pre_delete.connect(partial(renkan_delete, user), sender = Renkan, dispatch_uid = uid, weak = False)
+ post_save.connect(partial(revision_post_save, user), sender = Revision, dispatch_uid = uid, weak = False)
+
+def register_pre_save_handlers(user, uid):
+ pre_save.connect(partial(revision_pre_save, user), sender = Revision, dispatch_uid = uid, weak = False)
+
+
+def unregister_handlers(uid):
+ pre_delete.disconnect(dispatch_uid = uid, sender = Renkan)
+ post_save.disconnect(dispatch_uid = uid, sender = Revision)
+ pre_save.disconnect(dispatch_uid = uid, sender = Revision)
+
+def change_handlers_user(user, uid):
+ if pre_delete.disconnect(dispatch_uid = uid, sender = Renkan):
+ pre_delete.connect(partial(renkan_delete, user), sender = Renkan, dispatch_uid = uid, weak = False)
+ if post_save.disconnect(dispatch_uid = uid, sender = Revision):
+ post_save.connect(partial(revision_post_save, user), sender = Revision, dispatch_uid = uid, weak = False)
+ if pre_save.disconnect(dispatch_uid = uid, sender = Revision):
+ pre_save.connect(partial(revision_pre_save, user), sender = Revision, dispatch_uid = uid, weak = False)
+
+
+def renkan_delete(user, sender, **kwargs):
+ renkan = kwargs.get('instance', None)
+ if not renkan:
+ return
+ send_delete_renkan(renkan, user)
+
+def revision_post_save(user, sender, **kwargs):
+ revision = kwargs.get('instance', None)
+
+ if not revision:
+ return
+ if kwargs.get('created', False) and revision.parent_renkan.revision_count <= 1:
+ send_create_renkan(revision.parent_renkan, user)
+
+#This handler is used and registered in a single case, i.e. PUT on renkanmanager.api.views.RenkanDetail
+def revision_pre_save(user, sender, **kwargs):
+ revision = kwargs.get('instance', None)
+
+ if not revision:
+ return
+
+ # we look for renkan update : i.e. creation of a revision with a revision count > 0 or simple revision update
+ send_update_renkan(revision, user)