From 155af563f96d625fb253bc21ab21d6225ebd9bb3 Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE <nroche@entrouvert.com>
Date: Wed, 27 Mar 2019 17:12:30 +0100
Subject: [PATCH 4/4] matomo: manage automatic configuration (#19743)

---
 hobo/matomo/templates/hobo/matomo_home.html |  74 ++++++++----
 hobo/matomo/views.py                        |  19 ++-
 tests/test_matomo_views.py                  | 125 ++++++++++++++++++++
 3 files changed, 195 insertions(+), 23 deletions(-)
 create mode 100644 tests/test_matomo_views.py

diff --git a/hobo/matomo/templates/hobo/matomo_home.html b/hobo/matomo/templates/hobo/matomo_home.html
index e1c87e7..02bfb95 100644
--- a/hobo/matomo/templates/hobo/matomo_home.html
+++ b/hobo/matomo/templates/hobo/matomo_home.html
@@ -36,6 +36,11 @@
 
 {% if not enabled %}
 <p>
+  {% if error != '' %}
+  <div class="errornotice">
+    {{ error }}
+  </div>
+  {% endif %}
  {% trans "Support is currently disabled." %}
 </p>
 <p>
@@ -43,42 +48,71 @@
   <a class="button" rel="popup" href="{% url 'matomo-enable-auto' %}">{% trans 'Automatic' %}</a>
 </p>
 {% else %}
-
-{% if cnil_ack_level == 'success' %}
+  {% if tracking_js != '' %}
+    {% if cnil_ack_level == 'success' %}
 <div class="successnotice">
   suivi des recommandations CNIL
 </div>
-{% elif cnil_ack_level == 'warning' %}
+    {% elif cnil_ack_level == 'warning' %}
 <div class="warningnotice">
   suivi des recommandations CNIL
 </div>
-{% elif cnil_ack_level == 'error' %}
+    {% elif cnil_ack_level == 'error' %}
 <div class="errornotice">
   suivi des recommandations CNIL
 </div>
-{% endif %}
+    {% endif %}
+  {% endif %}
 
-{% if mode == 'manual' %}
-<p>
- {% trans "Manual mode." %}
-</p>
-{% endif %}
-
-{% if mode == 'auto' %}
-<p>
- {% trans "Automatic mode." %}
-</p>
-{% endif %}
+  {% if mode == 'manual' %}
+<h4>
+    {% trans "Manual mode" %}
+</h4>
 
 <form method="post">
-{% csrf_token %}
-{{ form.as_p }}
+  {% csrf_token %}
+  {{ form.as_p }}
 
 <div class="buttons">
-<button class="submit-button">{% trans "Save" %}</button>
+  <button class="submit-button">{% trans "Save" %}</button>
 </div>
 </form>
+  {% endif %}
 
-{% endif %}
+  {% if mode == 'auto' %}
+<p>
+  <h4>
+    {% trans "Automatic mode" %}
+  </h4>
+</p>
 
+<ul>
+  <li>
+    {% trans "Matomo login url" %} :
+    <a href={{matomo_url}}/index.php?module=Login&action=logme&login={{matomo_user_login}}&password={{matomo_password}}>
+      {{matomo_url}}/index.php?module=Login&action=logme&login={{matomo_user_login}}&password={{matomo_password}}
+    </a>
+  </li>
+  <li>
+    {% trans "Untrack me code" %} :
+    <br/>
+    <textarea readonly rows='10' cols='40' size='1024'>
+      <iframe
+	style="border: 0; height: 200px; width: 600px;"
+	src="{{matomo_url}}/index.php?module=CoreAdminHome&action=optOut&language=fr&backgroundColor=&fontColor=&fontSize=&fontFamily="
+	>
+      </iframe>
+    </textarea>
+    <br/>
+    exemple:
+    <br/>
+    <iframe
+      style="border: 0; height: 200px; width: 600px;"
+      src="{{matomo_url}}/index.php?module=CoreAdminHome&action=optOut&language=fr&backgroundColor=&fontColor=&fontSize=&fontFamily="
+      >
+    </iframe>
+  </li>
+</ul>
+  {% endif %}
+{% endif %}
 {% endblock %}
diff --git a/hobo/matomo/views.py b/hobo/matomo/views.py
index f9552b9..236c7ba 100644
--- a/hobo/matomo/views.py
+++ b/hobo/matomo/views.py
@@ -14,6 +14,8 @@
 # You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+import hashlib
+
 from django.core.urlresolvers import reverse_lazy
 from django.views.generic import RedirectView, FormView
 
@@ -44,8 +46,18 @@ class HomeView(FormView):
         context = super(HomeView, self).get_context_data(**kwargs)
         context['enabled'] = bool(get_variable('matomo_enable').json)
         context['mode'] = get_variable('matomo_mode').json
+        context['error'] = get_variable('matomo_error').value
         tracking_js = get_variable('cnil_compliant_visits_tracking_js').value
         context['cnil_ack_level'] = compute_cnil_acknowledgment_level(tracking_js)
+        context['tracking_js'] = tracking_js
+
+        if context['mode'] == 'auto':
+            matomo_setings = get_matomo_settings()
+            tenant_name, unused = get_tenant_name_and_public_urls()
+            password = get_variable('matomo_password').value
+            context['matomo_url'] = matomo_setings[0]
+            context['matomo_user_login'] = tenant_name
+            context['matomo_password'] = hashlib.md5(password).hexdigest()
         return context
 
 home = HomeView.as_view()
@@ -74,12 +86,13 @@ class EnableAutoView(FormView):
     success_url = reverse_lazy('matomo-home')
 
     def form_valid(self, form):
-        variable = get_variable('matomo_enable')
-        variable.value = 'true'
-        variable.save()
         variable = get_variable('matomo_mode')
         variable.value = 'auto'
         variable.save()
+        if auto_configure_matomo():
+            variable = get_variable('matomo_enable')
+            variable.value = 'true'
+            variable.save()
         return super(EnableAutoView, self).form_valid(form)
 
 enable_auto = EnableAutoView.as_view()
diff --git a/tests/test_matomo_views.py b/tests/test_matomo_views.py
new file mode 100644
index 0000000..e8e9695
--- /dev/null
+++ b/tests/test_matomo_views.py
@@ -0,0 +1,125 @@
+# -*- coding: utf-8 -*-
+
+import mock
+import pytest
+from requests import Response
+from webtest import TestApp
+
+from django.conf import settings
+from django.contrib.auth.models import User
+from django.test import override_settings
+
+from hobo.environment.models import Variable, Wcs, Combo, Fargo
+from hobo.wsgi import application
+
+pytestmark = pytest.mark.django_db
+
+CONFIG = {'URL': 'https://matomo.test', 'TOKEN_AUTH': '1234'}
+
+GET_SITE_NOT_ALREADY_THERE = """<?xml version="1.0" encoding="utf-8" ?>
+<result>
+    <error message="An unexpected website was found in the request: website id was set to '42' ." />
+</result>
+"""
+
+ADD_SITE_SUCCESS = """<?xml version="1.0" encoding="utf-8" ?>
+<result>42</result>
+"""
+
+ADD_USER_SUCCESS = """<?xml version="1.0" encoding="utf-8" ?>
+<result>
+    <success message="ok" />
+</result>
+"""
+
+JAVASCRIPT_TAG = """<?xml version="1.0" encoding="utf-8" ?>
+<result>&lt;!-- Matomo --&gt;
+&lt;script type=&quot;text/javascript&quot;&gt;
+  var _paq = window._paq || [];
+  /* tracker methods like &quot;setCustomDimension&quot; should be called before &quot;trackPageView&quot; */
+  _paq.push(['trackPageView']);
+  _paq.push(['enableLinkTracking']);
+  (function() {
+    var u=&quot;//matomo-test.entrouvert.org/&quot;;
+    _paq.push(['setTrackerUrl', u+'piwik.php']);
+    _paq.push(['setSiteId', '7']);
+    var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
+    g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
+  })();
+&lt;/script&gt;
+&lt;!-- End Matomo Code --&gt;
+</result>
+"""
+
+@pytest.fixture
+def admin_user():
+    try:
+        user = User.objects.get(username='admin')
+    except User.DoesNotExist:
+        user = User.objects.create_superuser('admin', email=None, password='admin')
+    return user
+
+def login(app, username='admin', password='admin'):
+    login_page = app.get('/login/')
+    login_form = login_page.forms[0]
+    login_form['username'] = username
+    login_form['password'] = password
+    resp = login_form.submit()
+    assert resp.status_int == 302
+    return app
+
+def test_unlogged_access():
+    # connect while not being logged in
+    app = TestApp(application)
+    resp = app.get('/matomo/', status=302)
+    assert resp.location.endswith('/login/?next=/matomo/')
+
+def test_access(admin_user):
+    app = login(TestApp(application))
+    assert app.get('/matomo/', status=200)
+
+def test_disable(admin_user):
+    app = login(TestApp(application))
+    resp1 = app.get('/matomo/disable', status=200)
+    resp2 = resp1.form.submit()
+    assert resp2.location.endswith('/matomo/')
+
+def test_enable_manual(admin_user):
+    """scenario where user manually paste a javascript code"""
+    app = login(TestApp(application))
+    resp1 = app.get('/matomo/enable-manual', status=200)
+    resp2 = resp1.form.submit().follow()
+    resp2.form['tracking_js'] = '...js_code...'
+    resp3 = resp2.form.submit().follow()
+    assert resp3.body.find('"warningnotice">\n  suivi des recommandations CNIL') != -1
+
+def auto_conf_mocked_post(url, **kwargs):
+    contents = [GET_SITE_NOT_ALREADY_THERE,
+                ADD_SITE_SUCCESS,
+                ADD_USER_SUCCESS,
+                JAVASCRIPT_TAG]
+    response = Response()
+    response._content = contents[auto_conf_mocked_post.cpt]
+    response.status_code = 200
+
+    auto_conf_mocked_post.cpt += 1
+    return response
+
+@mock.patch('requests.post', side_effect=auto_conf_mocked_post)
+def test_enable_auto(mocked_post, admin_user):
+    """automatic scenario"""
+    Combo.objects.create(base_url='https://combo.dev.publik.love',
+                         template_name='portal-user')
+    Wcs.objects.create(base_url='https://wcs.dev.publik.love')
+    Fargo.objects.create(base_url='https://fargo.dev.publik.love')
+
+    auto_conf_mocked_post.cpt = 0
+    with override_settings(MATOMO_FEED=CONFIG):
+        app = login(TestApp(application))
+        resp1 = app.get('/matomo/enable-auto', status=200)
+        resp2 = resp1.form.submit()
+
+        # call utils.py::auto_configure_matomo()
+        resp3 = resp2.follow()
+        print resp3.body
+        assert resp3.body.find('"successnotice">\n  suivi des recommandations CNIL') != -1
-- 
2.20.1

