From 241ac9a5b3a40cf937b2bd42f2534d4b9e8207cd Mon Sep 17 00:00:00 2001
From: Laurent Laffont <llaffont@afi-sa.fr>
Date: Mon, 30 Nov 2020 11:36:25 +0100
Subject: [PATCH] hotline #122811 adds google tag manager id support

---
 VERSIONS_HOTLINE/122811                       |   1 +
 .../modules/opac/views/scripts/head.phtml     |   1 +
 .../telephone/views/scripts/head.phtml        |   1 +
 .../telephone/views/scripts/main.phtml        |   1 +
 library/Class/AdminVar.php                    |   3 +-
 library/Class/AdminVar/GoogleTagManager.php   |  55 +++++++++
 library/templates/Historic/Template.php       |   1 +
 library/templates/Intonation/View/Opac.php    |  21 +++-
 .../GoogleTagManager/GoogleTagManagerTest.php | 112 ++++++++++++++++++
 ...TemplatesDispatchIntonationScriptsTest.php |   1 -
 10 files changed, 190 insertions(+), 7 deletions(-)
 create mode 100644 VERSIONS_HOTLINE/122811
 create mode 100644 library/Class/AdminVar/GoogleTagManager.php
 create mode 100644 tests/scenarios/GoogleTagManager/GoogleTagManagerTest.php

diff --git a/VERSIONS_HOTLINE/122811 b/VERSIONS_HOTLINE/122811
new file mode 100644
index 00000000000..b6b066f1359
--- /dev/null
+++ b/VERSIONS_HOTLINE/122811
@@ -0,0 +1 @@
+ - ticket #122811 : Intégration de Google Tag Manager : ajout de la variable d'administration GOOGLE_TAG_MANAGER_ID
\ No newline at end of file
diff --git a/application/modules/opac/views/scripts/head.phtml b/application/modules/opac/views/scripts/head.phtml
index 21073ca50e4..370b3a01f8f 100644
--- a/application/modules/opac/views/scripts/head.phtml
+++ b/application/modules/opac/views/scripts/head.phtml
@@ -1,5 +1,6 @@
 <html lang="<?php echo $this->_translate()->getLocale() ?>">
   <head>
+    <?php echo (new Class_AdminVar_GoogleTagManager())->headScript(); ?>
     <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
     <title><?php echo $this->titre ?></title>
     <?php $current_profil = Class_Profil::getCurrentProfil(); ?>
diff --git a/application/modules/telephone/views/scripts/head.phtml b/application/modules/telephone/views/scripts/head.phtml
index 3460411f31d..debfc0b0f4d 100644
--- a/application/modules/telephone/views/scripts/head.phtml
+++ b/application/modules/telephone/views/scripts/head.phtml
@@ -1,6 +1,7 @@
 <!DOCTYPE html >
 <html lang="<?php echo $this->_translate()->getLocale() ?>">
 <head>
+  <?php echo (new Class_AdminVar_GoogleTagManager())->headScript(); ?>
   <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
   <title><?php echo $this->getTitre() ?></title>
   <link rel="apple-touch-icon" href="<?php echo BASE_URL.'/public/opac/mobile/images/'; ?>apple-touch-icon.png" />
diff --git a/application/modules/telephone/views/scripts/main.phtml b/application/modules/telephone/views/scripts/main.phtml
index f1a2796285a..7b52112b5c2 100644
--- a/application/modules/telephone/views/scripts/main.phtml
+++ b/application/modules/telephone/views/scripts/main.phtml
@@ -4,6 +4,7 @@ ob_start();
 ?>
 
 <body <?php echo $this->bodyParam; ?>>
+  <?php  echo (new Class_AdminVar_GoogleTagManager())->bodyHTML(); ?>
   <div class="main" data-role="page">
   <?php
    echo $this->partial("banniere.phtml", array("profil" => $this->profil));
diff --git a/library/Class/AdminVar.php b/library/Class/AdminVar.php
index f7c7e831a67..587246fb51a 100644
--- a/library/Class/AdminVar.php
+++ b/library/Class/AdminVar.php
@@ -466,7 +466,8 @@ class Class_AdminVarLoader extends Storm_Model_Loader {
 
   protected function _getStatVars() {
     return ['JS_STAT' => Class_AdminVar_Meta::newRawText($this->_('Javascript code for statistics')),
-            'MATOMO_AUTH_TOKEN' => Class_AdminVar_Meta::newDefault($this->_('MATOMO authentication token for widgets'))];
+            'MATOMO_AUTH_TOKEN' => Class_AdminVar_Meta::newDefault($this->_('MATOMO authentication token for widgets')),
+            'GOOGLE_TAG_MANAGER_ID' => Class_AdminVar_Meta::newDefault($this->_('Identifiant Google Tag Manager (sous la forme GTM-XXXXXX'))];
   }
 
 
diff --git a/library/Class/AdminVar/GoogleTagManager.php b/library/Class/AdminVar/GoogleTagManager.php
new file mode 100644
index 00000000000..ff46f160460
--- /dev/null
+++ b/library/Class/AdminVar/GoogleTagManager.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Copyright (c) 2012-2014, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+class Class_AdminVar_GoogleTagManager {
+  public function isEnabled() {
+    return '' !== $this->getGoogleTagId();
+  }
+
+
+  public function getGoogleTagId() {
+    return trim(Class_AdminVar::get('GOOGLE_TAG_MANAGER_ID'));
+  }
+
+
+  public function headScript() {
+    if (!$this->isEnabled())
+      return '';
+
+    return sprintf('<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({\'gtm.start\':
+new Date().getTime(),event:\'gtm.js\'});var f=d.getElementsByTagName(s)[0],
+j=d.createElement(s),dl=l!=\'dataLayer\'?\'&l=\'+l:\'\';j.async=true;j.src=
+\'https://www.googletagmanager.com/gtm.js?id=\'+i+dl;f.parentNode.insertBefore(j,f);
+})(window,document,\'script\',\'dataLayer\',\'%s\');</script>',
+                   $this->getGoogleTagId());
+  }
+
+
+  public function bodyHTML() {
+    if (!$this->isEnabled())
+      return '';
+
+    return sprintf('<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=%s"
+height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>',
+                   $this->getGoogleTagId());
+  }
+}
\ No newline at end of file
diff --git a/library/templates/Historic/Template.php b/library/templates/Historic/Template.php
index 6f991788acf..70b86a700fa 100644
--- a/library/templates/Historic/Template.php
+++ b/library/templates/Historic/Template.php
@@ -31,6 +31,7 @@ class Historic_Template extends Class_Template {
   public function renderOpac($view) {
     ob_start();
     echo '<body '.$view->bodyParam.'>';
+    echo (new Class_AdminVar_GoogleTagManager())->bodyHTML();
     echo $view->Admin_FrontNav();
 
     $content_html = (isset($view->getModuleContent))
diff --git a/library/templates/Intonation/View/Opac.php b/library/templates/Intonation/View/Opac.php
index 966874d9ee2..2b2b871a725 100644
--- a/library/templates/Intonation/View/Opac.php
+++ b/library/templates/Intonation/View/Opac.php
@@ -25,7 +25,8 @@ class Intonation_View_Opac extends ZendAfi_View_Helper_BaseHelper {
   protected
     $_profile,
     $_template,
-    $_styles;
+    $_styles,
+    $_google_tag_manager;
 
 
   public function __construct($template, $view) {
@@ -37,16 +38,25 @@ class Intonation_View_Opac extends ZendAfi_View_Helper_BaseHelper {
 
 
   public function render() {
-    $content = $this->view->grid($this->_tag('div',
-                                             $this->_bodyContent(),
-                                             $this->_template->getHtmlAttribs()))
+    $google_tag_manager = new Class_AdminVar_GoogleTagManager();
+
+    $content =
+      $google_tag_manager->bodyHTML()
+
+      . $this->view->grid($this->_tag('div',
+                                      $this->_bodyContent(),
+                                      $this->_template->getHtmlAttribs()))
       . $this->_renderJSstat();
 
+
+
     $body = $this->_tag('body',
                         $content,
                         $this->view->body_attribs);
 
     $head = $this->_tag('head',
+                        $google_tag_manager->headScript()
+                        .
                         $this->_headContent());
 
     return $this->_tag('html',
@@ -191,7 +201,8 @@ class Intonation_View_Opac extends ZendAfi_View_Helper_BaseHelper {
                 $this->_tag('meta', null, ['name' => 'revisit-after',
                                            'content' => '10 days']),
 
-                $this->_tag('title', $this->view->getTitre())];
+                $this->_tag('title', $this->view->getTitre())
+    ];
 
     if ($this->_profile->hasFavicon())
       $content [] = $this->_tag('link',
diff --git a/tests/scenarios/GoogleTagManager/GoogleTagManagerTest.php b/tests/scenarios/GoogleTagManager/GoogleTagManagerTest.php
new file mode 100644
index 00000000000..ba93c429424
--- /dev/null
+++ b/tests/scenarios/GoogleTagManager/GoogleTagManagerTest.php
@@ -0,0 +1,112 @@
+<?php
+/**
+ * Copyright (c) 2012-2020, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+class GoogleTagManagerNotSetTest extends Admin_AbstractControllerTestCase {
+  protected $_storm_default_to_volatile = true;
+
+  public function setUp() {
+    parent::setUp();
+    $this->_buildTemplateProfil(['id' => 1, 'libelle' => 'No tracking']);
+    Class_AdminVar::set('GOOGLE_TAG_MANAGER_ID', '');
+    $this->dispatch('/');
+  }
+
+
+  /** @test */
+  public function headShouldNotContainsScriptWithDataLayer() {
+    $this->assertNotXPathContentContains('//head/script', 'dataLayer');
+  }
+
+
+  /** @test */
+  public function bodyShouldNotContainsNoScript() {
+    $this->assertNotXPath('//body/noscript');
+  }
+}
+
+
+
+
+abstract class GoogleTagManagerEnabledTestCase extends Admin_AbstractControllerTestCase {
+  protected $_storm_default_to_volatile = true;
+
+  public function setUp() {
+    parent::setUp();
+    $this->_buildProfile();
+    Class_AdminVar::set('GOOGLE_TAG_MANAGER_ID', 'GTM-1234');
+    $this->dispatchIndex();
+  }
+
+
+  public function dispatchIndex() {
+    $this->dispatch('/');
+  }
+
+
+  /** @test */
+  public function headScriptShouldContainsGoogleTagManagerScriptOnFirstPosition() {
+    $this->assertXPathContentContains('//head/script[1]', 'window,document,\'script\',\'dataLayer\',\'GTM-1234\');');
+  }
+
+
+  /** @test */
+  public function bodyShouldContainsNoScriptWithGoogleTagManagerIFrameOnFirstPosition() {
+    $this->assertXPath('//body/noscript[1]/iframe[@src="https://www.googletagmanager.com/ns.html?id=GTM-1234"]');
+  }
+}
+
+
+
+
+class GoogleTagManagerTemplatesTest extends GoogleTagManagerEnabledTestCase {
+  protected function _buildProfile() {
+    $this->_buildTemplateProfil(['id' => 1, 'libelle' => 'Big Brother']);
+  }
+}
+
+
+
+
+class GoogleTagManagerHistoricTest extends GoogleTagManagerEnabledTestCase {
+  protected function _buildProfile() {
+    Class_Profil::newInstanceWithIdAssertSave(1,
+                                              ['libelle' => 'no tracking']);
+  }
+}
+
+
+
+
+class GoogleTagManagerPhoneTest extends GoogleTagManagerEnabledTestCase {
+  protected function _buildProfile() {
+    $_SERVER['HTTP_USER_AGENT'] = 'iPhone';
+    Class_Profil::newInstanceWithIdAssertSave(1,
+                                              ['libelle' => 'no tracking'])
+      ->beTelephone()
+      ->assertSave();
+  }
+
+
+  public function dispatchIndex() {
+    $this->dispatch('/telephone');
+  }
+}
\ No newline at end of file
diff --git a/tests/scenarios/Templates/TemplatesDispatchIntonationScriptsTest.php b/tests/scenarios/Templates/TemplatesDispatchIntonationScriptsTest.php
index 7f6702d0f56..4c73bb9fb0d 100644
--- a/tests/scenarios/Templates/TemplatesDispatchIntonationScriptsTest.php
+++ b/tests/scenarios/Templates/TemplatesDispatchIntonationScriptsTest.php
@@ -22,7 +22,6 @@
 require_once('TemplatesTest.php');
 
 class TemplatesDispatchIntonationScriptsTest extends TemplatesIntonationTestCase {
-
   public function setUp() {
     parent::setUp();
     Class_AdminVar::newInstanceWithId('JS_STAT', ['valeur' => "<script> var _gaq = _gaq ||
-- 
GitLab