--- 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)