# HG changeset patch # User ymh # Date 1467717578 -7200 # Node ID 06f627e804b6f2b80e89e5584dd9d5511264c43c # Parent d3804d2eaf2dc0215a24b25414474540e20b06aa add tracking of renkan create, delete and update diff -r d3804d2eaf2d -r 06f627e804b6 server/src/metaeducation/settings/__init__.py --- a/server/src/metaeducation/settings/__init__.py Mon Jul 04 00:31:19 2016 +0200 +++ b/server/src/metaeducation/settings/__init__.py Tue Jul 05 13:19:38 2016 +0200 @@ -59,7 +59,7 @@ ), 'DEFAULT_PARSER_CLASSES': ( 'rest_framework.parsers.JSONParser', - ), + ), 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination' } @@ -72,7 +72,9 @@ 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.security.SecurityMiddleware','guardian.backends.ObjectPermissionBackend', - 'metaeducation.middleware.MtdcLoginRequiredWithContextMiddleware' + 'metaeducation.middleware.MtdcLoginRequiredWithContextMiddleware', + 'metaeducation.tracking.middleware.TrackingMiddleware' + ) ROOT_URLCONF = 'metaeducation.urls' diff -r d3804d2eaf2d -r 06f627e804b6 server/src/metaeducation/static/metaeducation/css/style.css --- a/server/src/metaeducation/static/metaeducation/css/style.css Mon Jul 04 00:31:19 2016 +0200 +++ b/server/src/metaeducation/static/metaeducation/css/style.css Tue Jul 05 13:19:38 2016 +0200 @@ -4,17 +4,17 @@ .errorModal { font-family: Arial, Helvetica, sans-serif; - display: none; - position: fixed; - z-index: 1000; - padding-top: 100px; + display: none; + position: fixed; + z-index: 1000; + padding-top: 100px; left: 0; top: 0; - width: 100%; - height: 100%; - overflow: auto; - background-color: rgb(0,0,0); - background-color: rgba(35,0,0,0.4); + width: 100%; + height: 100%; + overflow: auto; + background-color: rgb(0,0,0); + background-color: rgba(35,0,0,0.4); } /* Modal Content */ @@ -34,7 +34,7 @@ /* Add Animation */ @-webkit-keyframes animatetop { - from {top:-300px; opacity:0} + from {top:-300px; opacity:0} to {top:0; opacity:1} } @@ -65,4 +65,23 @@ .errorMsg{ display: none; +} + +.renkanlist-action { + padding: 0 0.3em; +} +.renkan-del-form { + display: inline-block; +} + +.renkan-del-button { + color: #337ab7; + text-decoration: none; + border: none; + background: none; +} + +.renkan-del-button:hover, .renkan-del-button:focus { + color: #23527c; + text-decoration: underline; } \ No newline at end of file diff -r d3804d2eaf2d -r 06f627e804b6 server/src/metaeducation/templates/renkan_list.html --- a/server/src/metaeducation/templates/renkan_list.html Mon Jul 04 00:31:19 2016 +0200 +++ b/server/src/metaeducation/templates/renkan_list.html Tue Jul 05 13:19:38 2016 +0200 @@ -29,9 +29,13 @@ {{renkan.title}} {{renkan.creation_date}} - View - Edit - Delete + View + Edit +
+ {% csrf_token %} + + +
{% endfor %} @@ -43,4 +47,4 @@

-{% endblock main_content %} \ No newline at end of file +{% endblock main_content %} diff -r d3804d2eaf2d -r 06f627e804b6 server/src/metaeducation/tracking/__init__.py --- a/server/src/metaeducation/tracking/__init__.py Mon Jul 04 00:31:19 2016 +0200 +++ b/server/src/metaeducation/tracking/__init__.py Tue Jul 05 13:19:38 2016 +0200 @@ -1,4 +1,8 @@ from .tasks import send_tracking_data -from .messages import send_close_renkan, send_open_edit_renkan, send_open_read_renkan +from .messages import send_close_renkan, send_open_edit_renkan, send_open_read_renkan, \ + send_delete_renkan, send_create_renkan, send_update_renkan -__all__ = ['send_tracking_data', 'send_close_renkan', 'send_open_read_renkan', 'send_open_edit_renkan'] +__all__ = [ + 'send_tracking_data', 'send_close_renkan', 'send_open_read_renkan', 'send_open_edit_renkan', + 'send_delete_renkan', 'send_update_renkan', 'send_create_renkan' +] diff -r d3804d2eaf2d -r 06f627e804b6 server/src/metaeducation/tracking/messages.py --- a/server/src/metaeducation/tracking/messages.py Mon Jul 04 00:31:19 2016 +0200 +++ b/server/src/metaeducation/tracking/messages.py Tue Jul 05 13:19:38 2016 +0200 @@ -2,6 +2,7 @@ import json import logging import pytz +import functools from .tasks import send_tracking_data @@ -118,7 +119,7 @@ msg = get_base_message('open_edit', renkan.renkan_guid, current_user, registration) msg['object'] = { - **(msg['object']), + **(msg.get('object', {})), **{ "definition": { "name": { @@ -133,3 +134,58 @@ } send_tracking_data(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) + 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, + } + } + } + } + send_tracking_data(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) + msg['object'] = { + **(msg.get('object', {})), + **{ + "definition": { + "name": { + 'fr-FR': renkan.title + }, + "type": "http://www.w3.org/ns/activitystreams#Renkan", + "extensions": { + 'http://www.w3.org/ns/activitystreams#Data': json.loads(renkan.content), + } + } + } + } + if renkan.source_revision: + msg['context']['extensions'] = { + **msg.get('context', {}).get('extensions', {}), + **{ + 'http://liris.renkantracking.org/fromCreate': {'renkan': renkan.source_revision.parent_renkan.renkan_guid, 'revision': renkan.source_revision.revision_guid} + } + } + send_tracking_data(msg) diff -r d3804d2eaf2d -r 06f627e804b6 server/src/metaeducation/tracking/middleware.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/src/metaeducation/tracking/middleware.py Tue Jul 05 13:19:38 2016 +0200 @@ -0,0 +1,59 @@ +import logging +import uuid + +from django.db.models.signals import pre_delete, post_save +from django.utils.functional import curry + +from renkanmanager.models import Renkan, Revision + +from . import send_delete_renkan, send_create_renkan, send_update_renkan + +logger = logging.getLogger(__name__) + +class TrackingMiddleware(object): + def process_request(self, request): + if not request.method in ('GET', 'HEAD', 'OPTIONS', 'TRACE'): + if hasattr(request, 'user') and request.user.is_authenticated(): + user = request.user.external_id + else: + user = None + + request.renkan_request_id = uuid.uuid4() + + 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,)) + 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')) + 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) diff -r d3804d2eaf2d -r 06f627e804b6 server/src/metaeducation/urls.py --- a/server/src/metaeducation/urls.py Mon Jul 04 00:31:19 2016 +0200 +++ b/server/src/metaeducation/urls.py Tue Jul 05 13:19:38 2016 +0200 @@ -34,7 +34,7 @@ url(r'^front/view/(?P[\w-]+)/$', ViewRenkanView.as_view(), name='front_view_renkan'), url(r'^tracking/$', UITrackingView.as_view(), name='tracking_view'), url(r'^tracking/close/$', UITrackingViewClose.as_view(), name='tracking_view_close'), - url(r'^front/delete/(?P[\w-]+)/$', staff_member_required(DeleteRenkanView.as_view()), name='front_delete_renkan') + url(r'^front/delete/$', staff_member_required(DeleteRenkanView.as_view()), name='front_delete_renkan') ] urlpatterns += staticfiles_urlpatterns() diff -r d3804d2eaf2d -r 06f627e804b6 server/src/metaeducation/views/renkan.py --- a/server/src/metaeducation/views/renkan.py Mon Jul 04 00:31:19 2016 +0200 +++ b/server/src/metaeducation/views/renkan.py Tue Jul 05 13:19:38 2016 +0200 @@ -1,5 +1,6 @@ import logging, json, uuid +from django import forms from django.conf import settings from django.core.urlresolvers import reverse from django.http import HttpResponse, HttpResponseRedirect @@ -72,10 +73,17 @@ send_open_edit_renkan(renkan, str(request.user.external_id), str(context['registration'])) return self.render_to_response(context) +class DeleteForm(forms.Form): + renkan_guid = forms.UUIDField() class DeleteRenkanView(View): - def get(self, request, renkan_guid): - request.method = "DELETE" - delete_response = RenkanDetail.as_view()(request, renkan_guid) - return HttpResponseRedirect(request.META.get('HTTP_REFERER', settings.BASE_URL)) + def post(self, request): + form = DeleteForm(request.POST) + if form.is_valid(): + renkan_guid = form.cleaned_data['renkan_guid'] + logger.debug("DELETE FORM VALID %r", form.cleaned_data) + request.method = "DELETE" + delete_response = RenkanDetail.as_view()(request, str(renkan_guid)) + return HttpResponseRedirect(request.META.get('HTTP_REFERER', settings.BASE_URL)) + return HttpResponse('field renkan_guid unknown or bad format', status=400)