add tracking of close + first version of tracking server side
authorymh <ymh.work@gmail.com>
Sun, 03 Jul 2016 14:16:07 +0200
changeset 74 fa4fd5e8b54e
parent 73 f64fb2da5a54
child 75 ada126bb171a
add tracking of close + first version of tracking server side
server/src/metaeducation/static/metaeducation/js/mtdc-tracking-worker.js
server/src/metaeducation/templates/renkan_edit.html
server/src/metaeducation/tracking/__init__.py
server/src/metaeducation/tracking/messages.py
server/src/metaeducation/tracking/tasks.py
server/src/metaeducation/urls.py
server/src/metaeducation/views.py
server/src/metaeducation/views/__init__.py
server/src/metaeducation/views/tracking.py
--- a/server/src/metaeducation/static/metaeducation/js/mtdc-tracking-worker.js	Fri Jul 01 12:44:07 2016 +0200
+++ b/server/src/metaeducation/static/metaeducation/js/mtdc-tracking-worker.js	Sun Jul 03 14:16:07 2016 +0200
@@ -12,7 +12,7 @@
     var Mtdc = root.Mtdc;
 
 
-    Mtdc.TrackingWorker = function(currentUser, trackingUrl, registration, debounceDelay = 1000) {
+    Mtdc.TrackingWorker = function(renkan, trackingUrl, trackingCloseUrl, registration, debounceDelay = 1000) {
 
         function _sendTrackingInfo() {
             var trackingMessages = this.trackingMessages;
@@ -37,8 +37,10 @@
 
         var trackingWorker = {
             trackingMessages: [],
-            currentUser: currentUser,
+            currentUser: renkan.currentUser,
+            renkan: renkan,
             trackingUrl: trackingUrl,
+            trackingCloseUrl: trackingCloseUrl,
             getUUID4 : function() {
                 return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
                     var r = Math.random() * 16 | 0,
@@ -57,7 +59,7 @@
                 this.sendTrackingInfo();
             },
             flushTrackingInfo() {
-                this.sendTrackingInfo.flush();
+                //this.sendTrackingInfo.flush();
             },
             _getBaseMsg: function(verb) {
                 var timestamp = new Date(),
@@ -182,7 +184,24 @@
             updateView: function(viewData, changedData, previousData) {
                 this._sendViewMsg('update', viewData, changedData, previousData);
             },
-            closeProject: function(projData) {
+            closeProject: function() {
+                this.flushTrackingInfo();
+                $.ajax({
+                    method: 'POST',
+                    url: this.trackingCloseUrl,
+                    headers: {
+                        'X-CSRFToken': this.csrftoken
+                    },
+                    data: {
+                        'renkan_guid': this.renkan.project.get('id'),
+                        'registration': this.registration
+                    }
+
+                }).done(function() {
+                    console.log('Send close tracking info success');
+                }).fail(function(){
+                    console.log('send tracking data failed');
+                });
             }
 
         };
--- a/server/src/metaeducation/templates/renkan_edit.html	Fri Jul 01 12:44:07 2016 +0200
+++ b/server/src/metaeducation/templates/renkan_edit.html	Sun Jul 03 14:16:07 2016 +0200
@@ -50,7 +50,7 @@
           });
           _renkan.setCurrentUser('{{ user.external_id }}', '{{ user.username }}');
 
-          var trackingWorker = Mtdc.TrackingWorker(_renkan.current_user, "{% url 'tracking_view' %}");
+          var trackingWorker = Mtdc.TrackingWorker(_renkan, "{% url 'tracking_view' %}", "{% url 'tracking_view_close' %}");
 
           Rkns.mtdcTracking(_renkan, trackingWorker);
           Rkns.mtdcJsonIO(_renkan, {
@@ -58,6 +58,9 @@
               user_id: '{{ user.external_id }}',
               user_name: '{{ user.username }}'
           });
+          $(window).on('beforeunload', function(e) {
+              trackingWorker.closeProject();
+          });
       };
   </script>
 {% endblock js_import %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/src/metaeducation/tracking/__init__.py	Sun Jul 03 14:16:07 2016 +0200
@@ -0,0 +1,4 @@
+from .tasks import send_tracking_data
+from .messages import send_close_renkan
+
+__all__ = ['send_tracking_data', 'send_close_renkan']
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/src/metaeducation/tracking/messages.py	Sun Jul 03 14:16:07 2016 +0200
@@ -0,0 +1,95 @@
+import datetime
+import json
+import logging
+import pytz
+
+from .tasks import send_tracking_data
+
+logger = logging.getLogger(__name__)
+
+
+def get_base_message(verb, renkan_id, current_user, registration = None):
+    #create
+    #open-read
+    #open-edit
+    #close
+    #delete
+    #update
+    timestamp = datetime.datetime.utcnow().replace(tzinfo=pytz.utc)
+
+    verbNode = {
+        "create" : {
+            "id": 'http://activitystrea.ms/schema/1.0/create',
+            "display": { 'fr-FR': 'a créé' }
+        },
+        "update": {
+            "id": 'http://activitystrea.ms/schema/1.0/update',
+            "display": { 'fr-FR': 'a modifié' }
+        },
+        "delete": {
+            "id": 'http://activitystrea.ms/schema/1.0/delete',
+            "display": { 'fr-FR': 'a supprimé' }
+        },
+        "close": {
+            "id": 'http://activitystrea.ms/schema/1.0/close',
+            "display": { 'fr-FR': 'a fermé'}
+        },
+        "open_read": {
+            "id": 'http://id.tincanapi.com/verb/viewed',
+            "display": { 'fr-FR': 'a vu'}
+        },
+        "open_edit": {
+            "id" : 'http://activitystrea.ms/schema/1.0/access',
+            "display": { 'fr-FR': "a édité" }
+        }
+    }[verb];
+    msg = {
+        'actor': {
+            'objectType': 'Agent',
+            'name': current_user,
+            'account': {
+                'homePage': 'https://www.metaeducation.fr/Utilisateurs/',
+                'name': current_user
+            }
+        },
+        'verb': verbNode,
+        'object': {
+            'objectType': 'Activity',
+            'id': get_renkan_urn(renkan_id)
+        },
+        'context': {
+            'extensions': {
+                'http://liris.renkantracking.org/application': 'Outil carte mentale'
+            }
+        },
+        'timestamp': timestamp.isoformat()
+    };
+    if registration:
+        msg['context']['registration'] = registration
+
+    return msg
+
+def get_renkan_urn(renkan_id):
+    return 'urn:mtdc:renkan:renkan:%s' % renkan_id;
+
+
+
+def send_close_renkan(renkan, current_user, registration):
+    msg = get_base_message('close', renkan.renkan_guid, current_user, registration)
+
+    msg['object'] = {
+        **(msg['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),
+                }
+            }
+        }
+    }
+
+    send_tracking_data(msg)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/src/metaeducation/tracking/tasks.py	Sun Jul 03 14:16:07 2016 +0200
@@ -0,0 +1,30 @@
+import logging, json
+import requests
+from django.conf import settings
+
+logger = logging.getLogger(__name__)
+
+def send_tracking_data(json_data):
+
+    tracking_data = (json_data if isinstance(json_data, str) else json.dumps(json_data)).encode('utf-8')
+
+    logger.debug("SENDING %r", tracking_data)
+
+    try:
+        resp = requests.post(
+            settings.LRS_TRACKING_SERVICE_URL + "statements",
+            data=tracking_data,
+            auth=requests.auth.HTTPBasicAuth(
+                settings.LRS_MTDC_RENKAN_USERNAME,
+                settings.LRS_MTDC_RENKAN_PASSWORD
+            ),
+            headers = {"X-Experience-API-Version": "1.0.1", "Content-Type": "application/json"}
+        )
+        logger.debug("tracking info sent %r: %r", resp.status_code, resp.text)
+        resp.raise_for_status()
+    except requests.exceptions.ConnectionError as e:
+        logger.exception("Tracking send error Connecting %r", e)
+        # do nothing this should be a fire and forget interface
+    except requests.exceptions.HTTPError as e:
+        logger.debug("Tracking send error posting data %r", e)
+        # do nothing this should be a fire and forget interface
--- a/server/src/metaeducation/urls.py	Fri Jul 01 12:44:07 2016 +0200
+++ b/server/src/metaeducation/urls.py	Sun Jul 03 14:16:07 2016 +0200
@@ -20,7 +20,7 @@
 from django.core.urlresolvers import reverse_lazy
 from django.views.generic import RedirectView
 
-from .views import ListRenkansView, NewRenkanView, EditRenkanView, ViewRenkanView, DeleteRenkanView, UITrackingView
+from .views import ListRenkansView, NewRenkanView, EditRenkanView, ViewRenkanView, DeleteRenkanView, UITrackingView, UITrackingViewClose
 
 
 urlpatterns = [
@@ -33,7 +33,8 @@
     url(r'^front/edit/(?P<renkan_guid>[\w-]+)/$', EditRenkanView.as_view(), name='front_edit_renkan'),
     url(r'^front/view/(?P<renkan_guid>[\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<renkan_guid>[\w-]+)/$', staff_member_required(DeleteRenkanView.as_view()), name='front_delete_renkan')
 ]
 
-urlpatterns += staticfiles_urlpatterns()
\ No newline at end of file
+urlpatterns += staticfiles_urlpatterns()
--- a/server/src/metaeducation/views.py	Fri Jul 01 12:44:07 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-import logging, json
-from django.conf import settings
-from django.core.urlresolvers import reverse
-from django.http import HttpResponse, HttpResponseRedirect
-from django.shortcuts import render, get_object_or_404
-from django.views.decorators.csrf import csrf_exempt
-from django.views.generic import TemplateView, View
-from renkanmanager.api.views import RenkanDetail
-from renkanmanager.models import Renkan
-from renkanmanager.serializers import RenkanSerializer
-from metaeducation import __version__
-from metaeducation.utils import send_tracking_data
-
-logger = logging.getLogger(__name__)
-
-class ListRenkansView(View):
-    template_name = "renkan_list.html"
-    
-    def get(self, request):
-        renkans = Renkan.objects.filter(creator=request.user)
-        return render(request, self.template_name, {'renkans': renkans, 'version': __version__})  
-      
-    def post(self, request):
-        create_data = {
-            "title" : request.POST.get("title", "Untitled Renkan")
-        }
-        
-        serializer = RenkanSerializer(data=create_data)
-        if serializer.is_valid():
-            serializer.save(creator=request.user)
-        return HttpResponseRedirect(request.META.get('HTTP_REFERER', settings.BASE_URL))
-
-class NewRenkanView(View):
-    
-    def get(self, request):
-        create_data = {
-            "title" : "Untitled Renkan"
-        }
-        serializer = RenkanSerializer(data=create_data)
-        if serializer.is_valid():
-            new_renkan = serializer.save(creator=request.user)
-            return HttpResponseRedirect(reverse("front_edit_renkan", kwargs={"renkan_guid": new_renkan.renkan_guid}))
-        
-
-class ViewRenkanView(TemplateView):
-    template_name = "renkan_view.html"
-
-
-class EditRenkanView(TemplateView):
-    template_name = "renkan_edit.html"
-    
-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))
-    
-class UITrackingView(View):
-    def post(self, request):
-        try:
-            logger.debug("POSTING DATA %r", str(request.body, 'utf-8'))
-            # Testing if JSON is properly formatted
-            json.loads(str(request.body, 'utf-8'))
-            send_tracking_data(str(request.body, 'utf-8'))
-            return HttpResponse("Tracking data was sent")
-        except ValueError:
-            logger.debug("ERROR POSTING DATA")
-            return HttpResponse("Error sending data")
\ No newline at end of file
--- a/server/src/metaeducation/views/__init__.py	Fri Jul 01 12:44:07 2016 +0200
+++ b/server/src/metaeducation/views/__init__.py	Sun Jul 03 14:16:07 2016 +0200
@@ -1,5 +1,5 @@
 
 from .renkan import ListRenkansView, NewRenkanView, EditRenkanView, ViewRenkanView, DeleteRenkanView
-from .tracking import UITrackingView
+from .tracking import UITrackingView, UITrackingViewClose
 
-__all__ = [ "ListRenkansView", "NewRenkanView", "EditRenkanView", "ViewRenkanView", "DeleteRenkanView", "UITrackingView" ]
+__all__ = [ "ListRenkansView", "NewRenkanView", "EditRenkanView", "ViewRenkanView", "DeleteRenkanView", "UITrackingView", "UITrackingViewClose" ]
--- a/server/src/metaeducation/views/tracking.py	Fri Jul 01 12:44:07 2016 +0200
+++ b/server/src/metaeducation/views/tracking.py	Sun Jul 03 14:16:07 2016 +0200
@@ -1,42 +1,38 @@
-import logging, json
-import requests
+import logging
 from django.conf import settings
-from django.http import HttpResponse, HttpResponseServerError
+from django.http import HttpResponse
 from django.views.generic import View
+from django import forms
+from django.shortcuts import get_object_or_404
+
+from metaeducation.tracking import send_tracking_data, send_close_renkan
+from renkanmanager.models import Renkan
 
 logger = logging.getLogger(__name__)
 
 class UITrackingView(View):
 
-    def send_tracking_data(self, json_data):
-        tracking_data = json.loads(json_data)
-        logger.debug("SENDING %r", tracking_data)
-        resp = requests.post(
-            settings.LRS_TRACKING_SERVICE_URL + "statements",
-            json=tracking_data,
-            auth=requests.auth.HTTPBasicAuth(
-                settings.LRS_MTDC_RENKAN_USERNAME,
-                settings.LRS_MTDC_RENKAN_PASSWORD
-            ),
-            headers = {"X-Experience-API-Version": "1.0.1"}
-        )
-        logger.debug("%r: %r", resp.status_code, resp.text)
-        return resp
-
     def post(self, request):
         logger.debug("POSTING DATA %r", str(request.body, 'utf-8'))
 
-        try:
-            resp = self.send_tracking_data(str(request.body, 'utf-8'))
-            resp.raise_for_status()
-        except requests.exceptions.ConnectionError as e:
-            logger.debug("ERROR Connecting %r", e)
-            return HttpResponseServerError(str(e))
-        except requests.exceptions.HTTPError as e:
-            logger.debug("ERROR POSTING DATA %r", e)
-            return HttpResponse(resp.text, status=resp.status_code, content_type='text/plain')
+        send_tracking_data(str(request.body, 'utf-8'))
+
+        # This is a fire and forget !!!
+        # please track the log to see if everything is ok
+        return HttpResponse(status=204)
+
+class RenkanCloseForm(forms.Form):
+    renkan_guid = forms.UUIDField()
+    registration = forms.UUIDField()
+
+
+class UITrackingViewClose(View):
+    def post(self, request):
+        renkan_close_form = RenkanCloseForm(request.POST)
+        if renkan_close_form.is_valid():
+            form_data = renkan_close_form.cleaned_data
+            renkan = get_object_or_404(Renkan.objects.select_related('current_revision'), renkan_guid=form_data['renkan_guid'])
+            send_close_renkan(renkan, str(request.user.external_id), str(form_data['registration']))
+            return HttpResponse(status=204)
         else:
-            httpresp = HttpResponse(resp.text, status=resp.status_code, content_type=resp.headers.get('content-type'))
-            for h in {'X-Experience-API-Consistent-Through', 'X-Experience-API-Version', 'Date'}.intersection(resp.headers.keys()):
-                httpresp[h] = resp.headers[h]
-            return httpresp
+            return HttpResponse(status=400)