security updates of unpatched modules

This commit is contained in:
Bachir Soussi Chiadmi
2016-10-25 16:23:00 +02:00
parent 610760bedf
commit f6f7fd575f
133 changed files with 5598 additions and 2574 deletions

View File

@@ -12,12 +12,20 @@ Requirements
* Google Analytics user account
Installation
============
Copy the 'googleanalytics' module directory in to your Drupal
sites/all/modules directory as usual.
Upgrading from 6.x-3.x and 7.x-1.x
==================================
If you upgrade from 6.x-3.x and 7.x-1.x (ga.js) to 7.x-2.x (analytics.js) you
should verify if you used custom variables. Write down your settings or make a
screenshot. You need to re-configure the settings to use custom dimensions or
metrics. There is no automatic upgrade path for custom variables feature. All
other module settings are upgraded automatically.
See https://support.google.com/analytics/answer/2795983?hl=en for more details.
Usage
=====
@@ -27,12 +35,8 @@ All pages will now have the required JavaScript added to the
HTML footer can confirm this by viewing the page source from
your browser.
New approach to page tracking in 5.x-1.5 and 6.x-1.1
====================================================
With 5.x-1.5 and 6.x-1.1 there are new settings on the settings page at
admin/config/system/googleanalytics. The "Page specific tracking" area now
comes with an interface that copies Drupal's block visibility settings.
Page specific tracking
======================
The default is set to "Add to every page except the listed pages". By
default the following pages are listed for exclusion:
@@ -44,23 +48,24 @@ node/*/*
user/*/*
These defaults are changeable by the website administrator or any other
user with 'administer google analytics' permission.
user with 'Administer Google Analytics' permission.
Like the blocks visibility settings in Drupal core, there is now a
choice for "Add if the following PHP code returns TRUE." Sample PHP snippets
that can be used in this textarea can be found on the handbook page
"Overview-approach to block visibility" at http://drupal.org/node/64135.
Like the blocks visibility settings in Drupal core, there is a choice for
"Add if the following PHP code returns TRUE." Sample PHP snippets that can be
used in this textarea can be found on the handbook page "Overview-approach to
block visibility" at http://drupal.org/node/64135.
Custom dimensions and metrics
=============================
One example for custom dimensions tracking is the "User roles" tracking.
1. In the Google Analytics Management Interface you need to setup Dimension #1
with name e.g. "User roles". This step is required. Do not miss it, please.
1. In the Google Analytics Management Interface (http://www.google.com/analytics/)
you need to setup Dimension #1 with name e.g. "User roles". This step is
required. Do not miss it, please.
2. Enter the below configuration data into the custom dimensions settings form
under admin/config/system/googleanalytics. You can also choose another index,
but keep it always in sync with the index used in step #1.
2. Enter the below configuration data into the Drupal custom dimensions settings
form under admin/config/system/googleanalytics. You can also choose another
index, but keep it always in sync with the index used in step #1.
Index: 1
Value: [current-user:role-names]
@@ -77,3 +82,23 @@ provided for any customisations you include.
To speed up page loading you may also cache the Google Analytics "analytics.js"
file locally.
Manual JS debugging
===================
For manual debugging of the JS code you are able to create a test node. This
is the example HTML code for this test node. You need to enable debugging mode
in your Drupal configuration of Google Analytics settings to see verbose
messages in your browsers JS console.
Title: Google Analytics test page
Body:
<ul>
<li><a href="mailto:foo@example.com">Mailto</a></li>
<li><a href="/files/test.txt">Download file</a></li>
<li><a class="colorbox" href="#">Open colorbox</a></li>
<li><a href="http://example.com/">External link</a></li>
<li><a href="/go/test">Go link</a></li>
</ul>
Text format: Full HTML

View File

@@ -224,6 +224,18 @@ function googleanalytics_admin_settings_form($form_state) {
),
),
);
$colorbox_dependencies = '<div class="admin-requirements">';
$colorbox_dependencies .= t('Requires: !module-list', array('!module-list' => (module_exists('colorbox') ? t('@module (<span class="admin-enabled">enabled</span>)', array('@module' => 'Colorbox')) : t('@module (<span class="admin-disabled">disabled</span>)', array('@module' => 'Colorbox')))));
$colorbox_dependencies .= '</div>';
$form['tracking']['linktracking']['googleanalytics_trackcolorbox'] = array(
'#type' => 'checkbox',
'#title' => t('Track content in colorbox modal dialogs'),
'#default_value' => variable_get('googleanalytics_trackcolorbox', 1),
'#description' => t('Enable to track the content shown in colorbox modal windows.') . $colorbox_dependencies,
'#disabled' => (module_exists('colorbox') ? FALSE : TRUE),
);
$form['tracking']['linktracking']['googleanalytics_tracklinkid'] = array(
'#type' => 'checkbox',
'#title' => t('Track enhanced link attribution'),
@@ -246,7 +258,7 @@ function googleanalytics_admin_settings_form($form_state) {
'#type' => 'checkboxes',
'#title' => t('Track messages of type'),
'#default_value' => variable_get('googleanalytics_trackmessages', array()),
'#description' => t('This will track the selected message types shown to users. Tracking of form validation errors may help you identifying usability issues in your site. For each visit (user session), a maximum of approximately 500 combined GATC requests (both events and page views) can be tracked. Every message is tracked as one individual event. Note that - as the number of events in a session approaches the limit - additional events might not be tracked. Messages from excluded pages cannot tracked.'),
'#description' => t('This will track the selected message types shown to users. Tracking of form validation errors may help you identifying usability issues in your site. For each visit (user session), a maximum of approximately 500 combined GATC requests (both events and page views) can be tracked. Every message is tracked as one individual event. Note that - as the number of events in a session approaches the limit - additional events might not be tracked. Messages from excluded pages cannot be tracked.'),
'#options' => array(
'status' => t('Status message'),
'warning' => t('Warning message'),
@@ -305,7 +317,7 @@ function googleanalytics_admin_settings_form($form_state) {
$form['googleanalytics_custom_dimension'] = array(
'#collapsed' => TRUE,
'#collapsible' => TRUE,
'#description' => t('You can set values for Google Analytics <a href="@custom_var_documentation">Custom Dimensions</a> here. You must have already configured your custom dimensions in the <a href="@setup_documentation">Google Analytics Management Interface</a>. You may use tokens. Global and user tokens are always available; on node pages, node tokens are also available. A dimension <em>value</em> is allowed to have a maximum lenght of 150 bytes. Expect longer values to get trimmed.', array('@custom_var_documentation' => 'https://developers.google.com/analytics/devguides/collection/analyticsjs/custom-dims-mets', '@setup_documentation' => 'https://support.google.com/analytics/answer/2709829')),
'#description' => t('You can set values for Google Analytics <a href="@custom_var_documentation">Custom Dimensions</a> here. You must have already configured your custom dimensions in the <a href="@setup_documentation">Google Analytics Management Interface</a>. You may use tokens. Global and user tokens are always available; on node pages, node tokens are also available. A dimension <em>value</em> is allowed to have a maximum length of 150 bytes. Expect longer values to get trimmed.', array('@custom_var_documentation' => 'https://developers.google.com/analytics/devguides/collection/analyticsjs/custom-dims-mets', '@setup_documentation' => 'https://support.google.com/analytics/answer/2709829')),
'#theme' => 'googleanalytics_admin_custom_var_table',
'#title' => t('Custom dimensions'),
'#tree' => TRUE,
@@ -428,6 +440,8 @@ function googleanalytics_admin_settings_form($form_state) {
);
}
$user_access_add_js_snippets = !user_access('add JS snippets for google analytics');
$user_access_add_js_snippets_permission_warning = $user_access_add_js_snippets ? ' <em>' . t('This field has been disabled because you do not have sufficient permissions to edit it.') . '</em>' : '';
$form['advanced']['codesnippet'] = array(
'#type' => 'fieldset',
'#title' => t('Custom JavaScript code'),
@@ -447,15 +461,17 @@ function googleanalytics_admin_settings_form($form_state) {
'#type' => 'textarea',
'#title' => t('Code snippet (before)'),
'#default_value' => variable_get('googleanalytics_codesnippet_before', ''),
'#disabled' => $user_access_add_js_snippets,
'#rows' => 5,
'#description' => t('Code in this textarea will be added <strong>before</strong> <code>ga("send", "pageview");</code>.'),
'#description' => t('Code in this textarea will be added <strong>before</strong> <code>ga("send", "pageview");</code>.') . $user_access_add_js_snippets_permission_warning,
);
$form['advanced']['codesnippet']['googleanalytics_codesnippet_after'] = array(
'#type' => 'textarea',
'#title' => t('Code snippet (after)'),
'#default_value' => variable_get('googleanalytics_codesnippet_after', ''),
'#disabled' => $user_access_add_js_snippets,
'#rows' => 5,
'#description' => t('Code in this textarea will be added <strong>after</strong> <code>ga("send", "pageview");</code>. This is useful if you\'d like to track a site in two accounts.'),
'#description' => t('Code in this textarea will be added <strong>after</strong> <code>ga("send", "pageview");</code>. This is useful if you\'d like to track a site in two accounts.') . $user_access_add_js_snippets_permission_warning,
);
$form['advanced']['googleanalytics_debug'] = array(
@@ -541,6 +557,12 @@ function googleanalytics_admin_settings_form_validate($form, &$form_state) {
/**
* Layout for the custom variables table in the admin settings form.
*
* @param array $variables
* An array contains the form elements.
*
* @return string
* The rendered output.
*/
function theme_googleanalytics_admin_custom_var_table($variables) {
$form = $variables['form'];
@@ -551,7 +573,7 @@ function theme_googleanalytics_admin_custom_var_table($variables) {
);
$rows = array();
foreach (element_children($form['indexes']) as $key => $id) {
foreach (element_children($form['indexes']) as $id) {
$rows[] = array(
'data' => array(
drupal_render($form['indexes'][$id]['index']),
@@ -600,11 +622,18 @@ function googleanalytics_token_element_validate(&$element, &$form_state) {
return $element;
}
/**
* @param array $value
* An array of token values.
*
* @return array
* A unique array of invalid tokens.
*/
function _googleanalytics_get_forbidden_tokens($value) {
$invalid_tokens = array();
$value_tokens = is_string($value) ? token_scan($value) : $value;
foreach ($value_tokens as $type => $tokens) {
foreach ($value_tokens as $tokens) {
if (array_filter($tokens, '_googleanalytics_contains_forbidden_token')) {
$invalid_tokens = array_merge($invalid_tokens, array_values($tokens));
}
@@ -617,8 +646,9 @@ function _googleanalytics_get_forbidden_tokens($value) {
/**
* Validate if a string contains forbidden tokens not allowed by privacy rules.
*
* @param $token_string
* @param string $token_string
* A string with one or more tokens to be validated.
*
* @return boolean
* TRUE if blacklisted token has been found, otherwise FALSE.
*/
@@ -724,7 +754,7 @@ function _googleanalytics_extract_create_field_values($string) {
$list = array_map('trim', $list);
$list = array_filter($list, 'strlen');
foreach ($list as $position => $text) {
foreach ($list as $text) {
// Check for an explicit key.
$matches = array();
if (preg_match('/(.*)\|(.*)/', $text, $matches)) {

View File

@@ -65,6 +65,15 @@ Drupal.behaviors.trackingSettingsSummary = {
if ($('input#edit-googleanalytics-trackfiles', context).is(':checked')) {
vals.push(Drupal.t('Downloads'));
}
if ($('input#edit-googleanalytics-trackcolorbox', context).is(':checked')) {
vals.push(Drupal.t('Colorbox'));
}
if ($('input#edit-googleanalytics-tracklinkid', context).is(':checked')) {
vals.push(Drupal.t('Link attribution'));
}
if ($('input#edit-googleanalytics-trackurlfragments', context).is(':checked')) {
vals.push(Drupal.t('URL fragments'));
}
if (!vals.length) {
return Drupal.t('Not tracked');
}

View File

@@ -8,16 +8,16 @@ $(document).ready(function() {
// clicks on all elements.
$(document.body).bind("mousedown keyup touchstart", function(event) {
console.group("Running Google Analytics for Drupal.");
console.info(event);
console.info("Event '%s' has been detected.", event.type);
// Catch the closest surrounding link of a clicked element.
$(event.target).closest("a,area").each(function() {
console.info("Element '%o' has been detected. Link '%s' found.", this, this.href);
console.info("Closest element '%o' has been found. URL '%s' extracted.", this, this.href);
// Is the clicked URL internal?
if (Drupal.googleanalytics.isInternal(this.href)) {
// Skip 'click' tracking, if custom tracking events are bound.
if ($(this).is('.colorbox')) {
if ($(this).is('.colorbox') && (Drupal.settings.googleanalytics.trackColorbox)) {
// Do nothing here. The custom event will handle all tracking.
console.info("Click on .colorbox item has been detected.");
}
@@ -25,12 +25,22 @@ $(document).ready(function() {
else if (Drupal.settings.googleanalytics.trackDownload && Drupal.googleanalytics.isDownload(this.href)) {
// Download link clicked.
console.info("Download url '%s' has been found. Tracked download as extension '%s'.", Drupal.googleanalytics.getPageUrl(this.href), Drupal.googleanalytics.getDownloadExtension(this.href).toUpperCase());
ga("send", "event", "Downloads", Drupal.googleanalytics.getDownloadExtension(this.href).toUpperCase(), Drupal.googleanalytics.getPageUrl(this.href));
ga("send", {
"hitType": "event",
"eventCategory": "Downloads",
"eventAction": Drupal.googleanalytics.getDownloadExtension(this.href).toUpperCase(),
"eventLabel": Drupal.googleanalytics.getPageUrl(this.href),
"transport": "beacon"
});
}
else if (Drupal.googleanalytics.isInternalSpecial(this.href)) {
// Keep the internal URL for Google Analytics website overlay intact.
console.info("Click on internal special link '%s' has been tracked.", Drupal.googleanalytics.getPageUrl(this.href));
ga("send", "pageview", { "page": Drupal.googleanalytics.getPageUrl(this.href) });
ga("send", {
"hitType": "pageview",
"page": Drupal.googleanalytics.getPageUrl(this.href),
"transport": "beacon"
});
}
else {
// e.g. anchor in same page or other internal page link
@@ -41,13 +51,25 @@ $(document).ready(function() {
if (Drupal.settings.googleanalytics.trackMailto && $(this).is("a[href^='mailto:'],area[href^='mailto:']")) {
// Mailto link clicked.
console.info("Click on e-mail '%s' has been tracked.", this.href.substring(7));
ga("send", "event", "Mails", "Click", this.href.substring(7));
ga("send", {
"hitType": "event",
"eventCategory": "Mails",
"eventAction": "Click",
"eventLabel": this.href.substring(7),
"transport": "beacon"
});
}
else if (Drupal.settings.googleanalytics.trackOutbound && this.href.match(/^\w+:\/\//i)) {
if (Drupal.settings.googleanalytics.trackDomainMode != 2 || (Drupal.settings.googleanalytics.trackDomainMode == 2 && !Drupal.googleanalytics.isCrossDomain(this.hostname, Drupal.settings.googleanalytics.trackCrossDomains))) {
if (Drupal.settings.googleanalytics.trackDomainMode !== 2 || (Drupal.settings.googleanalytics.trackDomainMode === 2 && !Drupal.googleanalytics.isCrossDomain(this.hostname, Drupal.settings.googleanalytics.trackCrossDomains))) {
// External link clicked / No top-level cross domain clicked.
console.info("Outbound link '%s' has been tracked.", this.href);
ga("send", "event", "Outbound links", "Click", this.href);
ga("send", {
"hitType": "event",
"eventCategory": "Outbound links",
"eventAction": "Click",
"eventLabel": this.href,
"transport": "beacon"
});
}
else {
console.info("Internal link '%s' clicked, not tracked.", this.href);
@@ -63,19 +85,27 @@ $(document).ready(function() {
if (Drupal.settings.googleanalytics.trackUrlFragments) {
window.onhashchange = function() {
console.info("Track URL '%s' as pageview. Hash '%s' has changed.", location.pathname + location.search + location.hash, location.hash);
ga('send', 'pageview', location.pathname + location.search + location.hash);
}
ga("send", {
"hitType": "pageview",
"page": location.pathname + location.search + location.hash
});
};
}
// Colorbox: This event triggers when the transition has completed and the
// newly loaded content has been revealed.
$(document).bind("cbox_complete", function () {
var href = $.colorbox.element().attr("href");
if (href) {
console.info("Colorbox transition to url '%s' has been tracked.", Drupal.googleanalytics.getPageUrl(href));
ga("send", "pageview", { "page": Drupal.googleanalytics.getPageUrl(href) });
}
});
if (Drupal.settings.googleanalytics.trackColorbox) {
$(document).bind("cbox_complete", function () {
var href = $.colorbox.element().attr("href");
if (href) {
console.info("Colorbox transition to url '%s' has been tracked.", Drupal.googleanalytics.getPageUrl(href));
ga("send", {
"hitType": "pageview",
"page": Drupal.googleanalytics.getPageUrl(href)
});
}
});
}
});

View File

@@ -5,9 +5,9 @@ package = Statistics
configure = admin/config/system/googleanalytics
files[] = googleanalytics.test
test_dependencies[] = token
; Information added by Drupal.org packaging script on 2014-11-29
version = "7.x-2.1"
; Information added by Drupal.org packaging script on 2016-08-09
version = "7.x-2.3"
core = "7.x"
project = "google_analytics"
datestamp = "1417276982"
datestamp = "1470779953"

View File

@@ -25,6 +25,7 @@ function googleanalytics_uninstall() {
variable_del('googleanalytics_roles');
variable_del('googleanalytics_site_search');
variable_del('googleanalytics_trackadsense');
variable_del('googleanalytics_trackcolorbox');
variable_del('googleanalytics_trackdoubleclick');
variable_del('googleanalytics_tracker_anonymizeip');
variable_del('googleanalytics_trackfiles');
@@ -446,16 +447,16 @@ function googleanalytics_update_7200() {
if (!empty($googleanalytics_codesnippet_before) && stristr($googleanalytics_codesnippet_before, '_gaq.push(')) {
variable_set('googleanalytics_codesnippet_before_backup_7200', $googleanalytics_codesnippet_before);
variable_del('googleanalytics_codesnippet_before');
drupal_set_message(Database::getConnection()->prefixTables("A backup of your previous Google Analytics code snippet has been saved in database table '{variable}' as 'googleanalytics_codesnippet_before_backup_7200'. You need to manually upgrade the custom 'before' code snippet."), 'warning');
$messages[] = t('Manual upgrade of custom "before" code snippet is required.');
drupal_set_message(Database::getConnection()->prefixTables("A backup of your previous Google Analytics code snippet (ga.js) has been saved in database table '{variable}' as 'googleanalytics_codesnippet_before_backup_7200'. You need to manually upgrade the custom 'before' code snippet to analytics.js API."), 'warning');
$messages[] = t('Manual upgrade of custom "before" code snippet from ja.js to analytics.js API is required.');
}
$googleanalytics_codesnippet_after = variable_get('googleanalytics_codesnippet_after', '');
if (!empty($googleanalytics_codesnippet_after) && stristr($googleanalytics_codesnippet_after, '_gaq.push(')) {
variable_set('googleanalytics_codesnippet_after_backup_7200', $googleanalytics_codesnippet_after);
variable_del('googleanalytics_codesnippet_after');
drupal_set_message(Database::getConnection()->prefixTables("A backup of your previous Google Analytics code snippet has been saved in database table '{variable}' as 'googleanalytics_codesnippet_before_backup_7200'. You need to manually upgrade the custom 'before' code snippet."), 'warning');
$messages[] = t('Manual upgrade of custom "after" code snippet is required.');
drupal_set_message(Database::getConnection()->prefixTables("A backup of your previous Google Analytics code snippet (ga.js) has been saved in database table '{variable}' as 'googleanalytics_codesnippet_after_backup_7200'. You need to manually upgrade the custom 'after' code snippet to analytics.js API."), 'warning');
$messages[] = t('Manual upgrade of custom "after" code snippet from ja.js to analytics.js API is required.');
}
return empty($messages) ? t('No custom code snipped found. Nothing to do.') : implode(' ', $messages);

View File

@@ -14,29 +14,51 @@ $(document).ready(function() {
// Is the clicked URL internal?
if (Drupal.googleanalytics.isInternal(this.href)) {
// Skip 'click' tracking, if custom tracking events are bound.
if ($(this).is('.colorbox')) {
if ($(this).is('.colorbox') && (Drupal.settings.googleanalytics.trackColorbox)) {
// Do nothing here. The custom event will handle all tracking.
//console.info("Click on .colorbox item has been detected.");
}
// Is download tracking activated and the file extension configured for download tracking?
else if (Drupal.settings.googleanalytics.trackDownload && Drupal.googleanalytics.isDownload(this.href)) {
// Download link clicked.
ga("send", "event", "Downloads", Drupal.googleanalytics.getDownloadExtension(this.href).toUpperCase(), Drupal.googleanalytics.getPageUrl(this.href));
ga("send", {
"hitType": "event",
"eventCategory": "Downloads",
"eventAction": Drupal.googleanalytics.getDownloadExtension(this.href).toUpperCase(),
"eventLabel": Drupal.googleanalytics.getPageUrl(this.href),
"transport": "beacon"
});
}
else if (Drupal.googleanalytics.isInternalSpecial(this.href)) {
// Keep the internal URL for Google Analytics website overlay intact.
ga("send", "pageview", { "page": Drupal.googleanalytics.getPageUrl(this.href) });
ga("send", {
"hitType": "pageview",
"page": Drupal.googleanalytics.getPageUrl(this.href),
"transport": "beacon"
});
}
}
else {
if (Drupal.settings.googleanalytics.trackMailto && $(this).is("a[href^='mailto:'],area[href^='mailto:']")) {
// Mailto link clicked.
ga("send", "event", "Mails", "Click", this.href.substring(7));
ga("send", {
"hitType": "event",
"eventCategory": "Mails",
"eventAction": "Click",
"eventLabel": this.href.substring(7),
"transport": "beacon"
});
}
else if (Drupal.settings.googleanalytics.trackOutbound && this.href.match(/^\w+:\/\//i)) {
if (Drupal.settings.googleanalytics.trackDomainMode != 2 || (Drupal.settings.googleanalytics.trackDomainMode == 2 && !Drupal.googleanalytics.isCrossDomain(this.hostname, Drupal.settings.googleanalytics.trackCrossDomains))) {
if (Drupal.settings.googleanalytics.trackDomainMode !== 2 || (Drupal.settings.googleanalytics.trackDomainMode === 2 && !Drupal.googleanalytics.isCrossDomain(this.hostname, Drupal.settings.googleanalytics.trackCrossDomains))) {
// External link clicked / No top-level cross domain clicked.
ga("send", "event", "Outbound links", "Click", this.href);
ga("send", {
"hitType": "event",
"eventCategory": "Outbound links",
"eventAction": "Click",
"eventLabel": this.href,
"transport": "beacon"
});
}
}
}
@@ -46,18 +68,26 @@ $(document).ready(function() {
// Track hash changes as unique pageviews, if this option has been enabled.
if (Drupal.settings.googleanalytics.trackUrlFragments) {
window.onhashchange = function() {
ga('send', 'pageview', location.pathname + location.search + location.hash);
}
ga("send", {
"hitType": "pageview",
"page": location.pathname + location.search + location.hash
});
};
}
// Colorbox: This event triggers when the transition has completed and the
// newly loaded content has been revealed.
$(document).bind("cbox_complete", function () {
var href = $.colorbox.element().attr("href");
if (href) {
ga("send", "pageview", { "page": Drupal.googleanalytics.getPageUrl(href) });
}
});
if (Drupal.settings.googleanalytics.trackColorbox) {
$(document).bind("cbox_complete", function () {
var href = $.colorbox.element().attr("href");
if (href) {
ga("send", {
"hitType": "pageview",
"page": Drupal.googleanalytics.getPageUrl(href)
});
}
});
}
});

View File

@@ -69,6 +69,11 @@ function googleanalytics_permission() {
'description' => t('Enter PHP code in the field for tracking visibility settings.'),
'restrict access' => TRUE,
),
'add JS snippets for google analytics' => array(
'title' => t('Add JavaScript snippets'),
'description' => 'Enter JavaScript code snippets for advanced Google Analytics functionality.',
'restrict access' => TRUE,
),
);
}
@@ -125,6 +130,9 @@ function googleanalytics_page_alter(&$page) {
$link_settings['trackDownload'] = $track_download;
$link_settings['trackDownloadExtensions'] = $trackfiles_extensions;
}
if (module_exists('colorbox') && ($track_colorbox = variable_get('googleanalytics_trackcolorbox', 1))) {
$link_settings['trackColorbox'] = $track_colorbox;
}
if ($track_domain_mode = variable_get('googleanalytics_domain_mode', 0)) {
$link_settings['trackDomainMode'] = $track_domain_mode;
}
@@ -294,10 +302,7 @@ function googleanalytics_page_alter(&$page) {
// Track logged in users across all devices.
if (variable_get('googleanalytics_trackuserid', 0) && user_is_logged_in()) {
// The USER_ID value should be a unique, persistent, and non-personally
// identifiable string identifier that represents a user or signed-in
// account across devices.
$create_only_fields['userId'] = drupal_hmac_base64($user->uid, drupal_get_private_key() . drupal_get_hash_salt());
$create_only_fields['userId'] = google_analytics_user_id_hash($user->uid);
}
// Create a tracker.
@@ -352,13 +357,30 @@ function googleanalytics_page_alter(&$page) {
// Custom tracking. Prepend before all other JavaScript.
// @TODO: https://support.google.com/adsense/answer/98142
// sounds like it could be appended to $script.
drupal_add_js($googleanalytics_adsense_script, array('type' => 'inline', 'group' => JS_LIBRARY-1));
drupal_add_js($googleanalytics_adsense_script, array('type' => 'inline', 'group' => JS_LIBRARY-1, 'requires_jquery' => FALSE));
}
drupal_add_js($script, array('scope' => 'header', 'type' => 'inline'));
drupal_add_js($script, array('scope' => 'header', 'type' => 'inline', 'requires_jquery' => FALSE));
}
}
/**
* Generate user id hash to implement USER_ID.
*
* The USER_ID value should be a unique, persistent, and non-personally
* identifiable string identifier that represents a user or signed-in
* account across devices.
*
* @param int $uid
* User id.
*
* @return string
* User id hash.
*/
function google_analytics_user_id_hash($uid) {
return drupal_hmac_base64($uid, drupal_get_private_key() . drupal_get_hash_salt());
}
/**
* Implements hook_field_extra_fields().
*/
@@ -456,7 +478,7 @@ function googleanalytics_preprocess_search_results(&$variables) {
// found. But the pager item mumber can tell the number of search results.
global $pager_total_items;
drupal_add_js('window.googleanalytics_search_results = ' . intval($pager_total_items[0]) . ';', array('type' => 'inline', 'group' => JS_LIBRARY-1));
drupal_add_js('window.googleanalytics_search_results = ' . intval($pager_total_items[0]) . ';', array('type' => 'inline', 'group' => JS_LIBRARY-1, 'requires_jquery' => FALSE));
}
}

View File

@@ -6,6 +6,13 @@
*/
class GoogleAnalyticsBasicTest extends DrupalWebTestCase {
/**
* User without permissions to edit snippets.
*
* @var \StdClass
*/
protected $noSnippetUser;
public static function getInfo() {
return array(
'name' => 'Google Analytics basic tests',
@@ -25,6 +32,8 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase {
);
// User to set up google_analytics.
$this->noSnippetUser = $this->drupalCreateUser($permissions);
$permissions[] = 'add JS snippets for google analytics';
$this->admin_user = $this->drupalCreateUser($permissions);
$this->drupalLogin($this->admin_user);
}
@@ -48,6 +57,26 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase {
$edit['googleanalytics_account'] = $this->randomName(2);
$this->drupalPost('admin/config/system/googleanalytics', $edit, t('Save configuration'));
$this->assertRaw(t('A valid Google Analytics Web Property ID is case sensitive and formatted like UA-xxxxxxx-yy.'), '[testGoogleAnalyticsConfiguration]: Invalid Web Property ID number validated.');
// User should have access to code snippets.
$this->assertFieldByName('googleanalytics_codesnippet_create');
$this->assertFieldByName('googleanalytics_codesnippet_before');
$this->assertFieldByName('googleanalytics_codesnippet_after');
$this->assertNoFieldByXPath("//textarea[@name='googleanalytics_codesnippet_create' and @disabled='disabled']", NULL, '"Create only fields" is enabled.');
$this->assertNoFieldByXPath("//textarea[@name='googleanalytics_codesnippet_before' and @disabled='disabled']", NULL, '"Code snippet (before)" is enabled.');
$this->assertNoFieldByXPath("//textarea[@name='googleanalytics_codesnippet_after' and @disabled='disabled']", NULL, '"Code snippet (after)" is enabled.');
// Login as user without JS permissions.
$this->drupalLogin($this->noSnippetUser);
$this->drupalGet('admin/config/system/googleanalytics');
// User should *not* have access to snippets, but create fields.
$this->assertFieldByName('googleanalytics_codesnippet_create');
$this->assertFieldByName('googleanalytics_codesnippet_before');
$this->assertFieldByName('googleanalytics_codesnippet_after');
$this->assertNoFieldByXPath("//textarea[@name='googleanalytics_codesnippet_create' and @disabled='disabled']", NULL, '"Create only fields" is enabled.');
$this->assertFieldByXPath("//textarea[@name='googleanalytics_codesnippet_before' and @disabled='disabled']", NULL, '"Code snippet (before)" is disabled.');
$this->assertFieldByXPath("//textarea[@name='googleanalytics_codesnippet_after' and @disabled='disabled']", NULL, '"Code snippet (after)" is disabled.');
}
function testGoogleAnalyticsPageVisibility() {
@@ -284,6 +313,7 @@ class GoogleAnalyticsCustomDimensionsAndMetricsTest extends DrupalWebTestCase {
// User to set up google_analytics.
$this->admin_user = $this->drupalCreateUser($permissions);
$this->drupalLogin($this->admin_user);
}
function testGoogleAnalyticsCustomDimensions() {
@@ -362,34 +392,30 @@ class GoogleAnalyticsCustomDimensionsAndMetricsTest extends DrupalWebTestCase {
1 => array(
'index' => 1,
'value' => '6',
'value_expected' => 6,
),
2 => array(
'index' => 2,
'value' => '8000',
'value_expected' => 8000,
),
3 => array(
'index' => 3,
'value' => '7.8654',
'value_expected' => 7.8654,
),
4 => array(
'index' => 4,
'value' => '1123.4',
'value_expected' => 1123.4,
),
5 => array(
'index' => 5,
'value' => '5,67',
'value_expected' => 5,
),
);
variable_set('googleanalytics_custom_metric', $googleanalytics_custom_metric);
$this->drupalGet('');
foreach ($googleanalytics_custom_metric as $metric) {
$this->assertRaw('ga("set", ' . drupal_json_encode('metric' . $metric['index']) . ', ' . drupal_json_encode($metric['value_expected']) . ');', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: Metric #' . $metric['index'] . ' is shown.');
$this->assertRaw('ga("set", ' . drupal_json_encode('metric' . $metric['index']) . ', ' . drupal_json_encode((float) $metric['value']) . ');', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: Metric #' . $metric['index'] . ' is shown.');
}
// Test whether tokens are replaced in custom metric values.
@@ -421,6 +447,30 @@ class GoogleAnalyticsCustomDimensionsAndMetricsTest extends DrupalWebTestCase {
$this->assertNoRaw('ga("set", ' . drupal_json_encode('metric3') . ', ' . drupal_json_encode('') . ');', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: Empty value is not shown.');
$this->assertRaw('ga("set", ' . drupal_json_encode('metric4') . ', ' . drupal_json_encode(0) . ');', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: Value 0 is shown.');
}
/**
* Tests if Custom Dimensions token form validation works.
*/
public function testGoogleAnalyticsCustomDimensionsTokenFormValidation() {
$ua_code = 'UA-123456-1';
// Check form validation.
$edit['googleanalytics_account'] = $ua_code;
$edit['googleanalytics_custom_dimension[indexes][1][value]'] = '[current-user:name]';
$edit['googleanalytics_custom_dimension[indexes][2][value]'] = '[current-user:edit-url]';
$edit['googleanalytics_custom_dimension[indexes][3][value]'] = '[user:name]';
$edit['googleanalytics_custom_dimension[indexes][4][value]'] = '[term:name]';
$edit['googleanalytics_custom_dimension[indexes][5][value]'] = '[term:tid]';
$this->drupalPost('admin/config/system/googleanalytics', $edit, t('Save configuration'));
$this->assertRaw(t('The %element-title is using the following forbidden tokens with personal identifying information: @invalid-tokens.', array('%element-title' => t('Custom dimension value #@index', array('@index' => 1)), '@invalid-tokens' => implode(', ', array('[current-user:name]')))));
$this->assertRaw(t('The %element-title is using the following forbidden tokens with personal identifying information: @invalid-tokens.', array('%element-title' => t('Custom dimension value #@index', array('@index' => 2)), '@invalid-tokens' => implode(', ', array('[current-user:edit-url]')))));
$this->assertRaw(t('The %element-title is using the following forbidden tokens with personal identifying information: @invalid-tokens.', array('%element-title' => t('Custom dimension value #@index', array('@index' => 3)), '@invalid-tokens' => implode(', ', array('[user:name]')))));
// BUG #2037595
//$this->assertNoRaw(t('The %element-title is using the following forbidden tokens with personal identifying information: @invalid-tokens.', array('%element-title' => t('Custom dimension value #@index', array('@index' => 4)), '@invalid-tokens' => implode(', ', array('[term:name]')))));
//$this->assertNoRaw(t('The %element-title is using the following forbidden tokens with personal identifying information: @invalid-tokens.', array('%element-title' => t('Custom dimension value #@index', array('@index' => 5)), '@invalid-tokens' => implode(', ', array('[term:tid]')))));
}
}
class GoogleAnalyticsStatusMessagesTest extends DrupalWebTestCase {

View File

@@ -40,6 +40,10 @@ function googleanalytics_variable_group_info() {
/**
* Validate Web Property ID variable.
*
* @param array $variable
*
* @return string
*/
function googleanalytics_validate_googleanalytics_account($variable) {
// Replace all type of dashes (n-dash, m-dash, minus) with the normal dashes.