diff --git a/profiles/wcm_base/CHANGELOG.txt b/profiles/wcm_base/CHANGELOG.txt index 15044bb9f233ed8dd5083cbdedbb637d0803f406..6a48cd157550ac9b3f0129898bc1f914af44d74c 100644 --- a/profiles/wcm_base/CHANGELOG.txt +++ b/profiles/wcm_base/CHANGELOG.txt @@ -1,3 +1,18 @@ +WCM Base 7.x-1.9-rc3, 2018-08-29 +-------------------------------- +- WCM Base: + - Updated Display Suite to 2.16. + - Updated Google Analytics to 2.5. + - Updated Redis to 3.17. + - Updated Views Bulk Operations to 3.5. +- WCM News Client: Corrected warnings and notices to improve logging. +- WCM Panels Settings: Converted File pane fields from generic file to media browser. +- WCM Security: + - Updated Antibot to 1.2. + - Updated Honeypot to 1.25. +- OCIO News: Updated change that put "See All News" link at the bottom of news panes. +- OCIO Taxonomy: Updated Taxonomy Access Fix to 2.4. + WCM Base 7.x-1.9-rc2, 2018-08-24 -------------------------------- - WCM Omega: @@ -12,7 +27,6 @@ WCM Base 7.x-1.9-rc2, 2018-08-24 - OCIO Media: Added additional checks to reduce notices in logs. - OCIO Seven: Replaced non-rendering Capita font with Georgia within WYSIWYG editor. - WCM Base 7.x-1.9-rc1, 2018-08-09 -------------------------------- - WCM Base: Upgraded PHP to version 5.6. diff --git a/profiles/wcm_base/modules/contrib/antibot/antibot.admin.inc b/profiles/wcm_base/modules/contrib/antibot/antibot.admin.inc index 62aba615ffed2591a17bedf4d340ca19db3e37bb..45ccc4a6b9a4c0d0f2bab42fb689234dbffd6e74 100644 --- a/profiles/wcm_base/modules/contrib/antibot/antibot.admin.inc +++ b/profiles/wcm_base/modules/contrib/antibot/antibot.admin.inc @@ -1,5 +1,10 @@ <?php +/** + * @file + * Admin callbacks and functions. + */ + /** * Admin settings form. */ @@ -7,7 +12,7 @@ function antibot_admin_settings($form, &$form_state) { $form['message'] = array( '#type' => 'html_tag', '#tag' => 'h3', - '#value' => t('Antibot requires that a user has Javascript enabled in order to use and submit a given form.'), + '#value' => t('Antibot requires that a user has JavaScript enabled in order to use and submit a given form.'), ); $form['antibot_form_ids'] = array( '#type' => 'textarea', @@ -21,6 +26,6 @@ function antibot_admin_settings($form, &$form_state) { '#default_value' => variable_get('antibot_show_form_ids', 0), '#description' => t('When enabled, the form IDs of all forms on every page will be displayed to any user with permission to access these settings. Also displayed will be whether or not Antibot is enabled for each form. This should only be turned on temporarily in order to easily determine the form IDs to use.'), ); - + return system_settings_form($form); } diff --git a/profiles/wcm_base/modules/contrib/antibot/antibot.info b/profiles/wcm_base/modules/contrib/antibot/antibot.info index 022d7742f3d741201f45f45d9a2e9a0fb1a22593..80107917fc60ec82f81fc977abdd4425a83ff550 100644 --- a/profiles/wcm_base/modules/contrib/antibot/antibot.info +++ b/profiles/wcm_base/modules/contrib/antibot/antibot.info @@ -1,11 +1,10 @@ name = Antibot -description = Prevent forms from being submitted without Javascript enabled +description = Prevent forms from being submitted without JavaScript enabled core = 7.x configure = admin/config/system/antibot -; Information added by Drupal.org packaging script on 2016-06-28 -version = "7.x-1.0" +; Information added by Drupal.org packaging script on 2018-06-11 +version = "7.x-1.2" core = "7.x" project = "antibot" -datestamp = "1467123647" - +datestamp = "1528676285" diff --git a/profiles/wcm_base/modules/contrib/antibot/antibot.install b/profiles/wcm_base/modules/contrib/antibot/antibot.install index 9f73a9bc83af27dc9f2ef351d62b6302b41741d2..40a52f9a14e4591ada704314e33385ddde514d7b 100644 --- a/profiles/wcm_base/modules/contrib/antibot/antibot.install +++ b/profiles/wcm_base/modules/contrib/antibot/antibot.install @@ -1,5 +1,10 @@ <?php +/** + * @file + * Install/uninstall/update hooks and functions. + */ + /** * Implements hook_uninstall(). */ diff --git a/profiles/wcm_base/modules/contrib/antibot/antibot.module b/profiles/wcm_base/modules/contrib/antibot/antibot.module index b09da08962dda736d4741a8a37e9f471710b9c34..81baf9858bb86f2d5dde0bf47067fcce149d5560 100644 --- a/profiles/wcm_base/modules/contrib/antibot/antibot.module +++ b/profiles/wcm_base/modules/contrib/antibot/antibot.module @@ -1,5 +1,10 @@ <?php +/** + * @file + * Attempt to prevent robotic form submissions and spam. + */ + /** * Implements hook_menu(). */ @@ -20,7 +25,21 @@ function antibot_menu() { 'access arguments' => array('administer site configuration'), 'file' => 'antibot.admin.inc', ); - return $items; + return $items; +} + +/** + * Implements hook_theme(). + */ +function antibot_theme() { + $theme = array(); + $theme['antibot_no_js'] = array( + 'variables' => array( + 'message' => NULL, + ), + 'template' => 'templates/antibot-no-js', + ); + return $theme; } /** @@ -30,10 +49,11 @@ function antibot_form_alter(&$form, &$form_state, $form_id) { // Track if this form is antibot-enabled. $enabled = FALSE; - // See if this form should have antibot protection + // See if this form should have antibot protection. if (drupal_match_path($form_id, antibot_active_form_ids())) { - // Add a pre-render to activate antibot. - $form['#pre_render'][] = 'antibot_form_pre_render'; + // Add antibot protection. + antibot_protect_form($form); + // Mark as enabled. $enabled = TRUE; } @@ -48,17 +68,49 @@ function antibot_form_alter(&$form, &$form_state, $form_id) { } } +/** + * Helper function to enable Antibot protection for a given form. + * + * @param array &$form + * The form to enable Antibot protection on. + */ +function antibot_protect_form(array &$form) { + // Ensure the form has an ID set. + if (!empty($form['#form_id'])) { + // Generate a key for this form. + $key = md5($form['#form_id']); + + // Store the key in the form. + $form['#antibot_key'] = $key; + + // Add a hidden value which will receive the key via JS. + // The point of this is to add an additonal layer of protection for remotely + // POSTed forms. Since the key will not be present in that scenario, the + // remote post will fail. + $form['antibot_key'] = array( + '#type' => 'hidden', + '#value' => '', + ); + + // Add validation for the key. + $form['#validate'][] = 'antibot_form_validation'; + } + + // Add a pre-render to activate antibot. + $form['#pre_render'][] = 'antibot_form_pre_render'; +} + /** * Determine the form IDs that should contain Antibot protection. - * - * @return - * A list of form IDs that can contain wildcard (*) characters. The + * + * @return string + * A list of form IDs that can contain wildcard (*) characters. The * form IDs are separated by newline characters. */ function antibot_active_form_ids() { - // See if we have IDs set + // See if we have IDs set. if (!($ids = variable_get('antibot_form_ids', NULL))) { - // Provide default IDs + // Provide default IDs. $ids = implode("\n", array( 'comment_node_*', 'user_login', @@ -68,17 +120,17 @@ function antibot_active_form_ids() { 'contact_site_form', )); } - + return $ids; } /** - * Pre-render callback on forms that should have Antibot protection. - * - * @see antibot_form_alter(). + * Pre-render callback on forms that have Antibot protection. + * + * @see antibot_protect_form() */ function antibot_form_pre_render($form) { - // Attach the needed Javascript to re-enable this form + // Attach the needed JavaScript to re-enable this form. $form['antibot'] = array( '#attached' => array( 'js' => array( @@ -86,8 +138,11 @@ function antibot_form_pre_render($form) { 'type' => 'setting', 'data' => array( 'antibot' => array( - 'actions' => array( - $form['#id'] => $form['#action'], + 'forms' => array( + $form['#id'] => array( + 'action' => $form['#action'], + 'key' => !empty($form['#antibot_key']) ? $form['#antibot_key'] : NULL, + ), ), ), ), @@ -96,17 +151,48 @@ function antibot_form_pre_render($form) { ), ), ); - - // Change the action so the submission does not go through + + // Change the action so the submission does not go through. $form['#action'] = base_path() . 'antibot'; - - // Hide the form in the event that the user does not have Javascript. - // If they do, it will be restored. - $form['#attributes']['style'] = 'display: none;'; - $form['#attributes']['class'][] = 'antibot-hidden'; - - // Provide a message in the event that the user does not have Javascript. - $form['#prefix'] = '<div class="antibot-no-js messages warning">' . t('You must have Javascript enabled to use this form.') . '</div>'; + + // Add a class to the form. + $form['#attributes']['class'][] = 'antibot'; + + // Provide a message in the event that the user does not have JavaScript. + $no_js = array( + '#theme' => 'antibot_no_js', + '#weight' => -500, + '#message' => t('You must have JavaScript enabled to use this form.'), + ); + $no_js = drupal_render($no_js); + + // Inject the message in to the form. + if (!isset($form['#prefix'])) { + $form['#prefix'] = ''; + } + $form['#prefix'] = $no_js . $form['#prefix']; return $form; } + +/** + * Validation to Antibot-protected forms. + * + * @see antibot_protect_form() + */ +function antibot_form_validation($form, &$form_state) { + // Check if a key was provided in the form. + if (!empty($form['#antibot_key'])) { + // Views exposed forms will initially load and submit without the key. + if (($form['#form_id'] == 'views_exposed_form') && empty($form_state['input']['antibot_key'])) { + // We must allow this. + return; + } + + // Validate the key. + if (empty($form_state['input']['antibot_key']) || ($form['#antibot_key'] != $form_state['input']['antibot_key'])) { + // Prevent the form from submitting. + form_set_error('', t('Submission failed. Please reload the page and try again.')); + } + } +} diff --git a/profiles/wcm_base/modules/contrib/antibot/antibot.pages.inc b/profiles/wcm_base/modules/contrib/antibot/antibot.pages.inc index ad2163fafc0a279ac309e2977dc8b1cbdcfc67b1..85b0864822f30879b50dcdecc1508aed37dff4fc 100644 --- a/profiles/wcm_base/modules/contrib/antibot/antibot.pages.inc +++ b/profiles/wcm_base/modules/contrib/antibot/antibot.pages.inc @@ -1,8 +1,15 @@ <?php /** - * The landing page you are brought to if you submit a protected form - * without Javascript enabled. + * @file + * Page callbacks and functions. + */ + +/** + * The landing page callback. + * + * You are brought here if you submit a protected form without JavaScript + * enabled. */ function antibot_landing_page() { $page = array(); @@ -12,12 +19,7 @@ function antibot_landing_page() { '#attributes' => array( 'class' => array('messages', 'error'), ), - '#value' => t('You have reached this page because you submitted a form that required Javascript to be enabled on your browser. This protection is in place to attempt to prevent automated submissions made on forms. Please return to the page that you came from and enable Javascript on your browser before attempting to submit the form again.'), - ); - $page['return'] = array( - '#type' => 'item', - '#markup' => l(t('Click here to go back'), $_SERVER['HTTP_REFERER']), - '#access' => (bool) strlen($_SERVER['HTTP_REFERER']), + '#value' => t('You have reached this page because you submitted a form that required JavaScript to be enabled on your browser. This protection is in place to attempt to prevent automated submissions made on forms. Please return to the page that you came from and enable JavaScript on your browser before attempting to submit the form again.'), ); return $page; } diff --git a/profiles/wcm_base/modules/contrib/antibot/js/antibot.js b/profiles/wcm_base/modules/contrib/antibot/js/antibot.js index 6cfb0fdec279d777c44881837eabd185904fb95b..bb1eed443a48d4eef0b66345fbe593676542b9bf 100644 --- a/profiles/wcm_base/modules/contrib/antibot/js/antibot.js +++ b/profiles/wcm_base/modules/contrib/antibot/js/antibot.js @@ -5,46 +5,55 @@ */ (function ($) { Drupal.antibot = {}; - + Drupal.behaviors.antibot = { attach: function (context) { - // Assume the user is not human, despite JS being enabled + // Assume the user is not human, despite JS being enabled. Drupal.settings.antibot.human = false; - - // Display the hidden forms - $('.antibot-hidden', context).show(); - // Remove the "no javascript" messages - $('.antibot-no-js', context).remove(); - - // Wait for a mouse to move, indicating they are human + + // Wait for a mouse to move, indicating they are human. $('body').mousemove(function() { - // Unlock the forms + // Unlock the forms. Drupal.antibot.unlockForms(); }); - - // A tab or enter key pressed can also indicate they are human + + // Wait for a touch move event, indicating that they are human. + $('body').bind('touchmove', function() { + // Unlock the forms. + Drupal.antibot.unlockForms(); + }); + + // A tab or enter key pressed can also indicate they are human. $('body').keydown(function(e) { if ((e.keyCode == 9) || (e.keyCode == 13)) { - // Unlock the forms + // Unlock the forms. Drupal.antibot.unlockForms(); } }); } - } - + }; + /** * Revert the action on the protected forms to what it was originally * set to. */ Drupal.antibot.unlockForms = function() { - // Act only if we haven't yet verified this user as being human + // Act only if we haven't yet verified this user as being human. if (!Drupal.settings.antibot.human) { - // Iterate all antibot form actions that we need to revert - for (n in Drupal.settings.antibot.actions) { - $('form#' + n).attr('action', Drupal.settings.antibot.actions[n]); + // Iterate all antibot forms that we need to unlock. + for (var id in Drupal.settings.antibot.forms) { + // Switch the action to the original value. + $('form#' + id).attr('action', Drupal.settings.antibot.forms[id].action); + + // Check if a key is required. + if (Drupal.settings.antibot.forms[id].key) { + // Inject the key value. + $('form#' + id).find('input[name="antibot_key"]').val(Drupal.settings.antibot.forms[id].key); + } } - // Mark this user as being human + // Mark this user as being human. Drupal.settings.antibot.human = true; } - } + }; + })(jQuery); diff --git a/profiles/wcm_base/modules/contrib/antibot/templates/antibot-no-js.tpl.php b/profiles/wcm_base/modules/contrib/antibot/templates/antibot-no-js.tpl.php new file mode 100644 index 0000000000000000000000000000000000000000..3d1e0b855dcc19301a6cab997d530066940ba694 --- /dev/null +++ b/profiles/wcm_base/modules/contrib/antibot/templates/antibot-no-js.tpl.php @@ -0,0 +1,16 @@ +<?php + +/** + * @file + * Template for printing a message to users without JavaScript enabled. + * + * Available variables: + * - $message: The message to display. + */ +?> +<noscript> + <style>form.antibot { display: none !important; }</style> + <div class="antibot-no-js antibot-message antibot-message-warning messages warning"> + <?php print $message; ?> + </div> +</noscript> diff --git a/profiles/wcm_base/modules/contrib/ds/ds.info b/profiles/wcm_base/modules/contrib/ds/ds.info index 97e4edb0ce5286dd0ec4452bec7fc02af9c9e55e..6ce9b32139ae8e829b69786f8f857852611ba878 100644 --- a/profiles/wcm_base/modules/contrib/ds/ds.info +++ b/profiles/wcm_base/modules/contrib/ds/ds.info @@ -13,8 +13,8 @@ files[] = tests/ds.views.test files[] = tests/ds.forms.test configure = admin/structure/ds -; Information added by Drupal.org packaging script on 2018-04-18 -version = "7.x-2.15" +; Information added by Drupal.org packaging script on 2018-07-03 +version = "7.x-2.16" core = "7.x" project = "ds" -datestamp = "1524068596" +datestamp = "1530614326" diff --git a/profiles/wcm_base/modules/contrib/ds/ds.module b/profiles/wcm_base/modules/contrib/ds/ds.module index e3c20572adcaf6b301b0b9e3d12e9b2ecbc5128b..d5af8a4ac95c7a058bf093fcc3486cb14beea133 100644 --- a/profiles/wcm_base/modules/contrib/ds/ds.module +++ b/profiles/wcm_base/modules/contrib/ds/ds.module @@ -957,13 +957,13 @@ function ds_render_block_field($field) { return drupal_render($renderable_block); break; case DS_BLOCK_TITLE_CONTENT: - if (isset($block->subject) && isset($block->content['#markup'])) { - return '<h2 class="block-title">' . $block->subject . '</h2>' . $block->content['#markup']; + if (isset($block->subject) && isset($block->content) && $block->content) { + return '<h2 class="block-title">' . $block->subject . '</h2>' . drupal_render($block->content); } break; case DS_BLOCK_CONTENT: - if (isset($block->content['#markup'])) { - return $block->content['#markup']; + if (isset($block->content) && $block->content) { + return drupal_render($block->content); } break; } diff --git a/profiles/wcm_base/modules/contrib/ds/modules/ds_devel/ds_devel.info b/profiles/wcm_base/modules/contrib/ds/modules/ds_devel/ds_devel.info index 35066a0bbbf111f7816a5092eaaa2837b91de311..2a28e104a3252e5bf20b8906f4a474c92b6a0fd6 100644 --- a/profiles/wcm_base/modules/contrib/ds/modules/ds_devel/ds_devel.info +++ b/profiles/wcm_base/modules/contrib/ds/modules/ds_devel/ds_devel.info @@ -5,8 +5,8 @@ package = "Display Suite" dependencies[] = ds dependencies[] = devel -; Information added by Drupal.org packaging script on 2018-04-18 -version = "7.x-2.15" +; Information added by Drupal.org packaging script on 2018-07-03 +version = "7.x-2.16" core = "7.x" project = "ds" -datestamp = "1524068596" +datestamp = "1530614326" diff --git a/profiles/wcm_base/modules/contrib/ds/modules/ds_extras/ds_extras.info b/profiles/wcm_base/modules/contrib/ds/modules/ds_extras/ds_extras.info index c5fc287bb0d8d9ccb2dae103e51ce5385db0a617..663c426961f0a565ecc998d894aa2367fb7d5fb4 100644 --- a/profiles/wcm_base/modules/contrib/ds/modules/ds_extras/ds_extras.info +++ b/profiles/wcm_base/modules/contrib/ds/modules/ds_extras/ds_extras.info @@ -5,8 +5,8 @@ package = "Display Suite" dependencies[] = ds configure = admin/structure/ds/list/extras -; Information added by Drupal.org packaging script on 2018-04-18 -version = "7.x-2.15" +; Information added by Drupal.org packaging script on 2018-07-03 +version = "7.x-2.16" core = "7.x" project = "ds" -datestamp = "1524068596" +datestamp = "1530614326" diff --git a/profiles/wcm_base/modules/contrib/ds/modules/ds_format/ds_format.info b/profiles/wcm_base/modules/contrib/ds/modules/ds_format/ds_format.info index 3d1de7fef73993f231eb9e8674ce3cebc41e0f31..92db5bb656482110d04a53ec57ae460b90785739 100644 --- a/profiles/wcm_base/modules/contrib/ds/modules/ds_format/ds_format.info +++ b/profiles/wcm_base/modules/contrib/ds/modules/ds_format/ds_format.info @@ -5,8 +5,8 @@ package = "Display Suite" dependencies[] = ds configure = admin/structure/ds/list/extras -; Information added by Drupal.org packaging script on 2018-04-18 -version = "7.x-2.15" +; Information added by Drupal.org packaging script on 2018-07-03 +version = "7.x-2.16" core = "7.x" project = "ds" -datestamp = "1524068596" +datestamp = "1530614326" diff --git a/profiles/wcm_base/modules/contrib/ds/modules/ds_forms/ds_forms.info b/profiles/wcm_base/modules/contrib/ds/modules/ds_forms/ds_forms.info index 7f26da2a84715e18198c2f399ad3d717a9ad638d..d680877883e97f4b632f945ebdea278f799088c4 100644 --- a/profiles/wcm_base/modules/contrib/ds/modules/ds_forms/ds_forms.info +++ b/profiles/wcm_base/modules/contrib/ds/modules/ds_forms/ds_forms.info @@ -4,8 +4,8 @@ core = "7.x" package = "Display Suite" dependencies[] = ds -; Information added by Drupal.org packaging script on 2018-04-18 -version = "7.x-2.15" +; Information added by Drupal.org packaging script on 2018-07-03 +version = "7.x-2.16" core = "7.x" project = "ds" -datestamp = "1524068596" +datestamp = "1530614326" diff --git a/profiles/wcm_base/modules/contrib/ds/modules/ds_search/ds_search.info b/profiles/wcm_base/modules/contrib/ds/modules/ds_search/ds_search.info index bc85846cc380de581042c39c1d725837e6e2583a..5cfb2e920b363d5713663fc4a03a7e2ecab510fc 100644 --- a/profiles/wcm_base/modules/contrib/ds/modules/ds_search/ds_search.info +++ b/profiles/wcm_base/modules/contrib/ds/modules/ds_search/ds_search.info @@ -5,8 +5,8 @@ package = "Display Suite" dependencies[] = ds configure = admin/structure/ds/list/search -; Information added by Drupal.org packaging script on 2018-04-18 -version = "7.x-2.15" +; Information added by Drupal.org packaging script on 2018-07-03 +version = "7.x-2.16" core = "7.x" project = "ds" -datestamp = "1524068596" +datestamp = "1530614326" diff --git a/profiles/wcm_base/modules/contrib/ds/modules/ds_ui/ds_ui.info b/profiles/wcm_base/modules/contrib/ds/modules/ds_ui/ds_ui.info index 0a52303a1d7adf07d96965a0e0da0c3ac9e32d42..c8dad2c8ff6292600a313281bcba2621bbe982ef 100644 --- a/profiles/wcm_base/modules/contrib/ds/modules/ds_ui/ds_ui.info +++ b/profiles/wcm_base/modules/contrib/ds/modules/ds_ui/ds_ui.info @@ -4,8 +4,8 @@ core = "7.x" package = "Display Suite" dependencies[] = ds -; Information added by Drupal.org packaging script on 2018-04-18 -version = "7.x-2.15" +; Information added by Drupal.org packaging script on 2018-07-03 +version = "7.x-2.16" core = "7.x" project = "ds" -datestamp = "1524068596" +datestamp = "1530614326" diff --git a/profiles/wcm_base/modules/contrib/ds/tests/ds_exportables_test/ds_exportables_test.info b/profiles/wcm_base/modules/contrib/ds/tests/ds_exportables_test/ds_exportables_test.info index fcbfa51402c9f2ece29bb28b3a3b3920bff4d24a..dbd678f94b77dfdddfbb205af89c4cc988827d11 100644 --- a/profiles/wcm_base/modules/contrib/ds/tests/ds_exportables_test/ds_exportables_test.info +++ b/profiles/wcm_base/modules/contrib/ds/tests/ds_exportables_test/ds_exportables_test.info @@ -4,8 +4,8 @@ package = "Display Suite" core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2018-04-18 -version = "7.x-2.15" +; Information added by Drupal.org packaging script on 2018-07-03 +version = "7.x-2.16" core = "7.x" project = "ds" -datestamp = "1524068596" +datestamp = "1530614326" diff --git a/profiles/wcm_base/modules/contrib/ds/tests/ds_test.info b/profiles/wcm_base/modules/contrib/ds/tests/ds_test.info index d7db78e40b7c9a0adc532680fa3bb505e84c0545..021d44a1d04ea86a1b2984814d50919bfbe9acb2 100644 --- a/profiles/wcm_base/modules/contrib/ds/tests/ds_test.info +++ b/profiles/wcm_base/modules/contrib/ds/tests/ds_test.info @@ -5,8 +5,8 @@ package = "Display Suite" dependencies[] = ds_extras hidden = TRUE -; Information added by Drupal.org packaging script on 2018-04-18 -version = "7.x-2.15" +; Information added by Drupal.org packaging script on 2018-07-03 +version = "7.x-2.16" core = "7.x" project = "ds" -datestamp = "1524068596" +datestamp = "1530614326" diff --git a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.admin.inc b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.admin.inc index d32939a369ed32e45f1d06abec612430e330a188..20abb5c36fa60d9d6bd8766056fb17f07ee922d5 100644 --- a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.admin.inc +++ b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.admin.inc @@ -18,12 +18,19 @@ function googleanalytics_admin_settings_form($form_state) { '#title' => t('Web Property ID'), '#type' => 'textfield', '#default_value' => variable_get('googleanalytics_account', 'UA-'), - '#size' => 15, + '#size' => 20, '#maxlength' => 20, '#required' => TRUE, '#description' => t('This ID is unique to each site you want to track separately, and is in the form of UA-xxxxxxx-yy. To get a Web Property ID, <a href="@analytics">register your site with Google Analytics</a>, or if you already have registered your site, go to your Google Analytics Settings page to see the ID next to every site profile. <a href="@webpropertyid">Find more information in the documentation</a>.', array('@analytics' => 'http://www.google.com/analytics/', '@webpropertyid' => url('https://developers.google.com/analytics/resources/concepts/gaConceptsAccounts', array('fragment' => 'webProperty')))), ); + $form['account']['googleanalytics_premium'] = array( + '#type' => 'checkbox', + '#title' => t('Premium account'), + '#description' => t('If you are a Google Analytics Premium customer, you can use up to 200 instead of 20 custom dimensions and metrics.'), + '#default_value' => variable_get('googleanalytics_premium', FALSE), + ); + // Visibility settings. $form['tracking_title'] = array( '#type' => 'item', @@ -169,7 +176,7 @@ function googleanalytics_admin_settings_form($form_state) { '#type' => 'fieldset', '#title' => t('Users'), ); - $t_permission = array('%permission' => t('opt-in or out of tracking')); + $t_permission = array('%permission' => t('Opt-in or out of tracking')); $form['tracking']['user_vis_settings']['googleanalytics_custom'] = array( '#type' => 'radios', '#title' => t('Allow users to customize tracking on their account page'), @@ -326,8 +333,10 @@ function googleanalytics_admin_settings_form($form_state) { $googleanalytics_custom_dimension = variable_get('googleanalytics_custom_dimension', array()); - // Google Analytics supports up to 20 custom dimensions. - for ($i = 1; $i <= 20; $i++) { + // Standard Google Analytics accounts support up to 20 custom dimensions, + // premium accounts support up to 200 custom dimensions. + $limit = (variable_get('googleanalytics_premium', FALSE)) ? 200 : 20; + for ($i = 1; $i <= $limit; $i++) { $form['googleanalytics_custom_dimension']['indexes'][$i]['index'] = array( '#default_value' => $i, '#description' => t('Index number'), @@ -377,8 +386,9 @@ function googleanalytics_admin_settings_form($form_state) { $googleanalytics_custom_metric = variable_get('googleanalytics_custom_metric', array()); - // Google Analytics supports up to 20 custom metrics. - for ($i = 1; $i <= 20; $i++) { + // Standard Google Analytics accounts support up to 20 custom metrics, + // premium accounts support up to 200 custom metrics. + for ($i = 1; $i <= $limit; $i++) { $form['googleanalytics_custom_metric']['indexes'][$i]['index'] = array( '#default_value' => $i, '#description' => t('Index number'), @@ -785,16 +795,19 @@ function _googleanalytics_validate_create_field_name($name) { // List of supported field names: // https://developers.google.com/analytics/devguides/collection/analyticsjs/field-reference#create $create_only_fields = array( - 'clientId', - 'userId', - 'sampleRate', - 'siteSpeedSampleRate', - 'alwaysSendReferrer', 'allowAnchor', + 'alwaysSendReferrer', + 'clientId', 'cookieName', 'cookieDomain', 'cookieExpires', 'legacyCookieDomain', + 'legacyHistoryImport', + 'sampleRate', + 'siteSpeedSampleRate', + 'storage', + 'useAmpClientId', + 'userId', ); if ($name == 'name') { diff --git a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.info b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.info index 2b814605447367abc33a1f485ffbc16c55a574a0..9232102f03d355978395b60d5816dd6b24d7a9c8 100644 --- a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.info +++ b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.info @@ -5,9 +5,8 @@ package = Statistics configure = admin/config/system/googleanalytics files[] = googleanalytics.test test_dependencies[] = token -; Information added by Drupal.org packaging script on 2016-08-09 -version = "7.x-2.3" +; Information added by Drupal.org packaging script on 2018-07-13 +version = "7.x-2.5" core = "7.x" project = "google_analytics" -datestamp = "1470779953" - +datestamp = "1531469026" diff --git a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.install b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.install index a4f4e83ab11a6b25f4b3044f7033fc553edd91cd..12f1c55e6eade1ed02d417675d146974191173a1 100644 --- a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.install +++ b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.install @@ -10,6 +10,7 @@ */ function googleanalytics_uninstall() { variable_del('googleanalytics_account'); + variable_del('googleanalytics_premium'); variable_del('googleanalytics_cache'); variable_del('googleanalytics_codesnippet_create'); variable_del('googleanalytics_codesnippet_before'); @@ -41,7 +42,7 @@ function googleanalytics_uninstall() { variable_del('googleanalytics_visibility_roles'); variable_del('googleanalytics_privacy_donottrack'); - // Remove backup variables if exist. Remove this code in D8. + // Remove backup variables if they exist. Remove this code in D8. variable_del('googleanalytics_codesnippet_after_backup_7200'); variable_del('googleanalytics_codesnippet_before_backup_7200'); } @@ -88,7 +89,8 @@ function googleanalytics_requirements($phase) { } /** - * Upgrade old extension variable to new and use old name as enabled/disabled flag. + * Upgrade old extension variable to new and use old name as enabled/disabled + * flag. */ function googleanalytics_update_6000() { variable_set('googleanalytics_trackfiles_extensions', variable_get('googleanalytics_trackfiles', '7z|aac|avi|csv|doc|exe|flv|gif|gz|jpe?g|js|mp(3|4|e?g)|mov|pdf|phps|png|ppt|rar|sit|tar|torrent|txt|wma|wmv|xls|xml|zip')); @@ -101,7 +103,8 @@ function googleanalytics_update_6000() { function googleanalytics_update_6001() { variable_set('googleanalytics_visibility', 0); - // Remove tracking from all administrative pages, see http://drupal.org/node/34970. + // Remove tracking from all administrative pages, see: + // http://drupal.org/node/34970. $pages = array( 'admin*', 'user*', @@ -114,11 +117,12 @@ function googleanalytics_update_6001() { } /** - * Upgrade role settings and per user tracking settings - * of "User 1" and remove outdated tracking variables. + * Upgrade role settings and per user tracking settings of "User 1" and remove + * outdated tracking variables. */ function googleanalytics_update_6002() { - // Upgrade enabled/disabled roles to new logic (correct for upgrades from 5.x-1.4 and 6.x-1.0). + // Upgrade enabled/disabled roles to new logic (correct for upgrades from + // 5.x-1.4 and 6.x-1.0). $roles = array(); $messages = array(); foreach (user_roles() as $rid => $name) { @@ -137,7 +141,7 @@ function googleanalytics_update_6002() { if (!$track_user1 = variable_get('googleanalytics_track__user1', 1)) { variable_set('googleanalytics_custom', 1); - // Load user 1 object, set appropriate value and save new user settings back. + // Load user 1 object, set appropriate value and save new user settings. $account = user_load(1); $account = user_save($account, array('data' => array('googleanalytics' => array('custom' => 0))), 'account'); $messages[] = t('Disabled user specific page tracking for site administrator.'); @@ -152,11 +156,11 @@ function googleanalytics_update_6002() { } /** - * #262468: Clear menu cache to solve stale menu data in 5.x-1.5 and 6.x-1.1 + * #262468: Clear menu cache to solve stale menu data in 5.x-1.5 and 6.x-1.1. */ function googleanalytics_update_6003() { menu_rebuild(); - return t('Menu has been rebuild.'); + return t('Menu has been rebuilt.'); } /** @@ -231,8 +235,9 @@ function googleanalytics_update_6006() { /** * Remove "User identifier" and "User name" from segmentation fields. * - * This is a data protection and privacy law change. For more information see Google Analytics - * terms of use section 8.1 (http://www.google.com/analytics/en-GB/tos.html). + * This is a data protection and privacy law change. For more information see + * Google Analytics terms of use section 8.1: + * http://www.google.com/analytics/en-GB/tos.html */ function googleanalytics_update_6007() { $profile_fields = variable_get('googleanalytics_segmentation', array()); @@ -293,15 +298,15 @@ function googleanalytics_update_6300() { $messages[] = t('Upgraded custom "before" code snippet.'); } - // Upgrade of AFTER code snippet. - // We cannot update this code snippet automatically. Show message that the upgrade has been skipped. + // Upgrade of AFTER code snippet. We cannot update this code snippet + // automatically. Show message that the upgrade has been skipped. $code_after = variable_get('googleanalytics_codesnippet_after', ''); if (!empty($code_after)) { drupal_set_message(Database::getConnection()->prefixTables("Automatic upgrade of Google Analytics custom 'after' code snippet has been skipped. Backup of previous code snippet has been saved in database table '{variable}' as 'googleanalytics_codesnippet_after_backup_6300'. You need to manually upgrade the custom 'after' code snippet."), 'error'); $messages[] = t('Skipped custom "after" code snippet.'); } - return empty($messages) ? t('No custom code snipped found. Nothing to do.') : implode(' ', $messages); + return empty($messages) ? t('No custom code snippet found. Nothing to do.') : implode(' ', $messages); } /** @@ -356,18 +361,20 @@ function googleanalytics_update_7002() { $googleanalytics_custom_vars['slots'][1]['slot'] = 1; $googleanalytics_custom_vars['slots'][1]['name'] = 'User roles'; $googleanalytics_custom_vars['slots'][1]['value'] = '[current-user:role-names]'; - $googleanalytics_custom_vars['slots'][1]['scope'] = 1; // Sets the scope to visitor-level. + // Sets the scope to visitor-level. + $googleanalytics_custom_vars['slots'][1]['scope'] = 1; variable_set('googleanalytics_custom_var', $googleanalytics_custom_vars); - return t('The deprecated profile segmentation setting for "User roles" has been added to custom variables. You need to deselect all selected profile fields in <a href="@admin">Google Analytics settings</a> and upgrade other profile fields manually or you may loose tracking data in future! See Google Analytics <a href="@customvar">Custom Variables</a> for more information.', array('@customvar' => 'https://developers.google.com/analytics/devguides/collection/gajs/gaTrackingCustomVariables', '@admin' => url('admin/config/system/googleanalytics'))); + return t('The deprecated profile segmentation setting for "User roles" has been added to custom variables. You need to deselect all selected profile fields in <a href="@admin">Google Analytics settings</a> and upgrade other profile fields manually or you may lose tracking data in future! See Google Analytics <a href="@customvar">Custom Variables</a> for more information.', array('@customvar' => 'https://developers.google.com/analytics/devguides/collection/gajs/gaTrackingCustomVariables', '@admin' => url('admin/config/system/googleanalytics'))); } else { - return t('You need to deselect all selected profile fields in <a href="@admin">Google Analytics settings</a> and upgrade other profile fields manually or you may loose tracking data in future! See Google Analytics <a href="@customvar">Custom Variables</a> for more information.', array('@customvar' => 'https://developers.google.com/analytics/devguides/collection/gajs/gaTrackingCustomVariables', '@admin' => url('admin/config/system/googleanalytics'))); + return t('You need to deselect all selected profile fields in <a href="@admin">Google Analytics settings</a> and upgrade other profile fields manually or you may lose tracking data in future! See Google Analytics <a href="@customvar">Custom Variables</a> for more information.', array('@customvar' => 'https://developers.google.com/analytics/devguides/collection/gajs/gaTrackingCustomVariables', '@admin' => url('admin/config/system/googleanalytics'))); } } /** - * Rename googleanalytics_trackoutgoing variable to googleanalytics_trackoutbound. + * Rename googleanalytics_trackoutgoing variable to + * googleanalytics_trackoutbound. */ function googleanalytics_update_7003() { variable_set('googleanalytics_trackoutbound', variable_get('googleanalytics_trackoutgoing', 1)); @@ -377,7 +384,8 @@ function googleanalytics_update_7003() { } /** - * Rename googleanalytics_visibility variable to googleanalytics_visibility_pages for consistency. + * Rename googleanalytics_visibility variable to + * googleanalytics_visibility_pages for consistency. */ function googleanalytics_update_7004() { variable_set('googleanalytics_visibility_pages', variable_get('googleanalytics_visibility', 1)); @@ -401,7 +409,7 @@ function googleanalytics_update_7005() { $diff = array_diff($pages, preg_split('/(\r\n?|\n)/', variable_get('googleanalytics_pages', implode("\n", $pages)))); if (empty($diff)) { - // No diff to previous settings found. Update with new settings. + // No difference to previous settings found. Update with new settings. $pages = array( 'admin', 'admin/*', @@ -437,7 +445,8 @@ function googleanalytics_update_7007() { } /** - * Delete custom ga.js code snipptes to prevent malfunctions in new Universal Analytics tracker. A backup of your snippets will be created. + * Delete custom ga.js code snippets to prevent malfunctions in new Universal + * Analytics tracker. A backup of your snippets will be created. */ function googleanalytics_update_7200() { $messages = array(); @@ -459,11 +468,12 @@ function googleanalytics_update_7200() { $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); + return empty($messages) ? t('No custom code snippet found. Nothing to do.') : implode(' ', $messages); } /** - * Delete obsolete custom variables. Custom variables are now custom dimensions and metrics. + * Delete obsolete custom variables. Custom variables are now custom dimensions + * and metrics. */ function googleanalytics_update_7201() { variable_del('googleanalytics_custom_var'); @@ -475,7 +485,7 @@ function googleanalytics_update_7201() { * Delete obsolete JavaScript scope variable. */ function googleanalytics_update_7202() { - // Remove obsolete scope variable + // Remove obsolete scope variable. variable_del('googleanalytics_js_scope'); return t('Removed obsolete JavaScript scope variable.'); diff --git a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.module b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.module index b45ee103610482572c32e1f7013b558bdcc3fd15..275262be7d074a141186b11bbe2be7ba398eb3b7 100644 --- a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.module +++ b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.module @@ -98,7 +98,7 @@ function googleanalytics_menu() { * Implements hook_page_alter() to insert JavaScript to the appropriate scope/region of the page. */ function googleanalytics_page_alter(&$page) { - global $user; + global $base_path, $user; $id = variable_get('googleanalytics_account', ''); @@ -134,7 +134,7 @@ function googleanalytics_page_alter(&$page) { $link_settings['trackColorbox'] = $track_colorbox; } if ($track_domain_mode = variable_get('googleanalytics_domain_mode', 0)) { - $link_settings['trackDomainMode'] = $track_domain_mode; + $link_settings['trackDomainMode'] = (int) $track_domain_mode; } if ($track_cross_domains = variable_get('googleanalytics_cross_domains', '')) { $link_settings['trackCrossDomains'] = preg_split('/(\r\n?|\n)/', $track_cross_domains); @@ -202,10 +202,22 @@ function googleanalytics_page_alter(&$page) { // Track access denied (403) and file not found (404) pages. if ($status == '403 Forbidden') { // See http://www.google.com/support/analytics/bin/answer.py?answer=86927 - $url_custom = '"/403.html?page=" + document.location.pathname + document.location.search + "&from=" + document.referrer'; + $url_custom = '"' . $base_path . '403.html?page=" + document.location.pathname + document.location.search + "&from=" + document.referrer'; } elseif ($status == '404 Not Found') { - $url_custom = '"/404.html?page=" + document.location.pathname + document.location.search + "&from=" + document.referrer'; + $url_custom = '"' . $base_path . '404.html?page=" + document.location.pathname + document.location.search + "&from=" + document.referrer'; + } + + // #2693595: User has entered an invalid login and clicked on forgot + // password link. This link contains the username or email address and may + // get send to Google if we do not override it. Override only if 'name' + // query param exists. Last custom url condition, this need to win. + // + // URLs to protect are: + // - user/password?name=username + // - user/password?name=foo@example.com + if (arg(0) == 'user' && arg(1) == 'password' && array_key_exists('name', drupal_get_query_parameters())) { + $url_custom = '"' . $base_path . 'user/password"'; } // Add custom dimensions and metrics. @@ -256,11 +268,10 @@ function googleanalytics_page_alter(&$page) { $script .= '})(window,document,"script",'; // Which version of the tracking library should be used? - $library_tracker_url = '//www.google-analytics.com/' . ($debug ? 'analytics_debug.js' : 'analytics.js'); - $library_cache_url = 'http:' . $library_tracker_url; + $library_tracker_url = 'https://www.google-analytics.com/' . ($debug ? 'analytics_debug.js' : 'analytics.js'); // Should a local cached copy of analytics.js be used? - if (variable_get('googleanalytics_cache', 0) && $url = _googleanalytics_cache($library_cache_url)) { + if (variable_get('googleanalytics_cache', 0) && $url = _googleanalytics_cache($library_tracker_url)) { // A dummy query-string is added to filenames, to gain control over // browser-caching. The string changes on every update or full cache // flush, forcing browsers to load a new copy of the files, as the @@ -462,7 +473,7 @@ function googleanalytics_user_presave(&$edit, $account, $category) { function googleanalytics_cron() { // Regenerate the tracking code file every day. if (REQUEST_TIME - variable_get('googleanalytics_last_cache', 0) >= 86400 && variable_get('googleanalytics_cache', 0)) { - _googleanalytics_cache('http://www.google-analytics.com/analytics.js', TRUE); + _googleanalytics_cache('https://www.google-analytics.com/analytics.js', TRUE); variable_set('googleanalytics_last_cache', REQUEST_TIME); } } @@ -526,6 +537,10 @@ function _googleanalytics_cache($location, $synchronize = FALSE) { if ($data_hash_local != $data_hash_remote && file_prepare_directory($path)) { // Save updated tracking code file to disk. file_unmanaged_save_data($result->data, $file_destination, FILE_EXISTS_REPLACE); + // Based on Drupal Core drupal_build_css_cache(). + if (variable_get('css_gzip_compression', TRUE) && variable_get('clean_url', 0) && extension_loaded('zlib')) { + file_unmanaged_save_data(gzencode($result->data, 9, FORCE_GZIP), $file_destination . '.gz', FILE_EXISTS_REPLACE); + } watchdog('googleanalytics', 'Locally cached tracking code file has been updated.', array(), WATCHDOG_INFO); // Change query-strings on css/js files to enforce reload for all users. @@ -538,6 +553,10 @@ function _googleanalytics_cache($location, $synchronize = FALSE) { // There is no need to flush JS here as core refreshes JS caches // automatically, if new files are added. file_unmanaged_save_data($result->data, $file_destination, FILE_EXISTS_REPLACE); + // Based on Drupal Core drupal_build_css_cache(). + if (variable_get('css_gzip_compression', TRUE) && variable_get('clean_url', 0) && extension_loaded('zlib')) { + file_unmanaged_save_data(gzencode($result->data, 9, FORCE_GZIP), $file_destination . '.gz', FILE_EXISTS_REPLACE); + } watchdog('googleanalytics', 'Locally cached tracking code file has been saved.', array(), WATCHDOG_INFO); // Return the local JS file path. diff --git a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.test b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.test index 745047a841f268bdcc49f34020603cd79a44724a..3db117fe16d35a22957d6b47c2b876550a08b575 100644 --- a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.test +++ b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.test @@ -83,7 +83,7 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase { // Verify that no tracking code is embedded into the webpage; if there is // only the module installed, but UA code not configured. See #2246991. $this->drupalGet(''); - $this->assertNoRaw('//www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPageVisibility]: Tracking code is not displayed without UA code configured.'); + $this->assertNoRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPageVisibility]: Tracking code is not displayed without UA code configured.'); $ua_code = 'UA-123456-1'; variable_set('googleanalytics_account', $ua_code); @@ -104,7 +104,7 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase { $this->assertNoRaw($ua_code, '[testGoogleAnalyticsPageVisibility]: Tracking code is not displayed on admin page.'); $this->drupalGet('admin/config/system/googleanalytics'); // Checking for tracking code URI here, as $ua_code is displayed in the form. - $this->assertNoRaw('//www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPageVisibility]: Tracking code is not displayed on admin subpage.'); + $this->assertNoRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPageVisibility]: Tracking code is not displayed on admin subpage.'); // Test whether tracking code display is properly flipped. variable_set('googleanalytics_visibility_pages', 1); @@ -112,7 +112,7 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase { $this->assertRaw($ua_code, '[testGoogleAnalyticsPageVisibility]: Tracking code is displayed on admin page.'); $this->drupalGet('admin/config/system/googleanalytics'); // Checking for tracking code URI here, as $ua_code is displayed in the form. - $this->assertRaw('//www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPageVisibility]: Tracking code is displayed on admin subpage.'); + $this->assertRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPageVisibility]: Tracking code is displayed on admin subpage.'); $this->drupalGet(''); $this->assertNoRaw($ua_code, '[testGoogleAnalyticsPageVisibility]: Tracking code is NOT displayed on front page.'); @@ -126,13 +126,15 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase { // Enable tracking code for all user roles. variable_set('googleanalytics_roles', array()); + $base_path = base_path(); + // Test whether 403 forbidden tracking code is shown if user has no access. $this->drupalGet('admin'); - $this->assertRaw('/403.html', '[testGoogleAnalyticsPageVisibility]: 403 Forbidden tracking code shown if user has no access.'); + $this->assertRaw($base_path . '403.html', '[testGoogleAnalyticsPageVisibility]: 403 Forbidden tracking code shown if user has no access.'); // Test whether 404 not found tracking code is shown on non-existent pages. $this->drupalGet($this->randomName(64)); - $this->assertRaw('/404.html', '[testGoogleAnalyticsPageVisibility]: 404 Not Found tracking code shown on non-existent page.'); + $this->assertRaw($base_path . '404.html', '[testGoogleAnalyticsPageVisibility]: 404 Not Found tracking code shown on non-existent page.'); // DNT Tests: // Enable system internal page cache for anonymous users. @@ -168,7 +170,7 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase { (function(q,u,i,c,k){window['GoogleAnalyticsObject']=q; window[q]=window[q]||function(){(window[q].q=window[q].q||[]).push(arguments)}, window[q].l=1*new Date();c=i.createElement(u),k=i.getElementsByTagName(u)[0]; - c.async=true;c.src='//www.google-analytics.com/analytics.js'; + c.async=true;c.src='https://www.google-analytics.com/analytics.js'; k.parentNode.insertBefore(c,k)})('ga','script',document); ga('create', 'UA-123456-7'); ga('send', 'pageview'); @@ -179,7 +181,7 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase { // Test whether tracking code uses latest JS. variable_set('googleanalytics_cache', 0); $this->drupalGet(''); - $this->assertRaw('//www.google-analytics.com/analytics.js', '[testGoogleAnalyticsTrackingCode]: Latest tracking code used.'); + $this->assertRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsTrackingCode]: Latest tracking code used.'); // Test whether anonymize visitors IP address feature has been enabled. variable_set('googleanalytics_tracker_anonymizeip', 0); @@ -256,13 +258,14 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase { $this->assertRaw('ga("create", "' . $ua_code . '", {"cookieDomain":"auto","allowLinker":true', '[testGoogleAnalyticsTrackingCode]: "allowLinker" has been found. Cross domain tracking is active.'); $this->assertRaw('ga("require", "linker");', '[testGoogleAnalyticsTrackingCode]: Require linker has been found. Cross domain tracking is active.'); $this->assertRaw('ga("linker:autoLink", ["www.example.com","www.example.net"]);', '[testGoogleAnalyticsTrackingCode]: "linker:autoLink" has been found. Cross domain tracking is active.'); + $this->assertRaw('"trackDomainMode":2,', '[testGoogleAnalyticsTrackingCode]: Domain mode value is of type integer.'); $this->assertRaw('"trackCrossDomains":["www.example.com","www.example.net"]', '[testGoogleAnalyticsTrackingCode]: Cross domain tracking with www.example.com and www.example.net is active.'); variable_set('googleanalytics_domain_mode', 0); // Test whether debugging script has been enabled. variable_set('googleanalytics_debug', 1); $this->drupalGet(''); - $this->assertRaw('//www.google-analytics.com/analytics_debug.js', '[testGoogleAnalyticsTrackingCode]: Google debugging script has been enabled.'); + $this->assertRaw('https://www.google-analytics.com/analytics_debug.js', '[testGoogleAnalyticsTrackingCode]: Google debugging script has been enabled.'); // Check if text and link is shown on 'Status Reports' page. // Requires 'administer site configuration' permission. @@ -272,7 +275,7 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase { // Test whether debugging script has been disabled. variable_set('googleanalytics_debug', 0); $this->drupalGet(''); - $this->assertRaw('//www.google-analytics.com/analytics.js', '[testGoogleAnalyticsTrackingCode]: Google debugging script has been disabled.'); + $this->assertRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsTrackingCode]: Google debugging script has been disabled.'); // Test whether the CREATE and BEFORE and AFTER code is added to the tracker. $codesnippet_create = array( @@ -473,6 +476,51 @@ class GoogleAnalyticsCustomDimensionsAndMetricsTest extends DrupalWebTestCase { } } +/** + * Test custom url functionality of Google Analytics module. + */ +class GoogleAnalyticsCustomUrls extends DrupalWebTestCase { + + public static function getInfo() { + return array( + 'name' => 'Google Analytics custom url tests', + 'description' => 'Test custom url functionality of Google Analytics module.', + 'group' => 'Google Analytics', + ); + } + + function setUp() { + parent::setUp('googleanalytics'); + + $permissions = array( + 'access administration pages', + 'administer google analytics', + ); + + // User to set up google_analytics. + $this->admin_user = $this->drupalCreateUser($permissions); + } + + /** + * Tests if user password page urls are overridden. + */ + public function testGoogleAnalyticsUserPasswordPage() { + $base_path = base_path(); + $ua_code = 'UA-123456-4'; + variable_set('googleanalytics_account', $ua_code); + + $this->drupalGet('user/password', array('query' => array('name' => 'foo'))); + $this->assertRaw('ga("set", "page", "' . $base_path . 'user/password"'); + + $this->drupalGet('user/password', array('query' => array('name' => 'foo@example.com'))); + $this->assertRaw('ga("set", "page", "' . $base_path . 'user/password"'); + + $this->drupalGet('user/password'); + $this->assertNoRaw('ga("set", "page",', '[testGoogleAnalyticsCustomUrls]: Custom url not set.'); + } + +} + class GoogleAnalyticsStatusMessagesTest extends DrupalWebTestCase { public static function getInfo() { @@ -734,13 +782,13 @@ class GoogleAnalyticsPhpFilterTest extends DrupalWebTestCase { // Check tracking code visibility. variable_set('googleanalytics_pages', '<?php return TRUE; ?>'); $this->drupalGet(''); - $this->assertRaw('//www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPhpFilter]: Tracking is displayed on frontpage page.'); + $this->assertRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPhpFilter]: Tracking is displayed on frontpage page.'); $this->drupalGet('admin'); - $this->assertRaw('//www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPhpFilter]: Tracking is displayed on admin page.'); + $this->assertRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPhpFilter]: Tracking is displayed on admin page.'); variable_set('googleanalytics_pages', '<?php return FALSE; ?>'); $this->drupalGet(''); - $this->assertNoRaw('//www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPhpFilter]: Tracking is not displayed on frontpage page.'); + $this->assertNoRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPhpFilter]: Tracking is not displayed on frontpage page.'); // Test administration form. variable_set('googleanalytics_pages', '<?php return TRUE; ?>'); diff --git a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.test.js b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.test.js index 05c720fb3261e96ea425660c411cd228afb17257..b3893501d669cf28d0641c631adcb01632b4d462 100644 --- a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.test.js +++ b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.test.js @@ -86,8 +86,10 @@ $(document).ready(function() { console.groupEnd(); console.group("Test 'getPageUrl':"); - Drupal.googleanalytics.test.assertSame(base_path, Drupal.googleanalytics.getPageUrl(base_url + Drupal.settings.basePath + 'node/1'), "Absolute internal URL '" + Drupal.settings.basePath + "node/1' has been extracted from full qualified url '" + base_url + base_path + "'."); - Drupal.googleanalytics.test.assertSame(base_path, Drupal.googleanalytics.getPageUrl(Drupal.settings.basePath + 'node/1'), "Absolute internal URL '" + Drupal.settings.basePath + "node/1' has been extracted from absolute url '" + base_path + "'."); + Drupal.google_analytics.test.assertSame(base_path, Drupal.google_analytics.getPageUrl(window.location.href), "Absolute internal URL '" + base_path + "' has been extracted from full qualified url '" + window.location.href + "'."); + Drupal.google_analytics.test.assertSame(base_path, Drupal.google_analytics.getPageUrl(base_path), "Absolute internal URL '" + base_path + "' has been extracted from absolute url '" + base_path + "'."); + //Drupal.googleanalytics.test.assertSame(base_path, Drupal.googleanalytics.getPageUrl(base_url + Drupal.settings.basePath + 'node/1'), "Absolute internal URL '" + Drupal.settings.basePath + "node/1' has been extracted from full qualified url '" + base_url + base_path + "'."); + //Drupal.googleanalytics.test.assertSame(base_path, Drupal.googleanalytics.getPageUrl(Drupal.settings.basePath + 'node/1'), "Absolute internal URL '" + Drupal.settings.basePath + "node/1' has been extracted from absolute url '" + base_path + "'."); Drupal.googleanalytics.test.assertSame('http://example.com/node/2', Drupal.googleanalytics.getPageUrl('http://example.com/node/2'), "Full qualified external url 'http://example.com/node/2' has been extracted."); Drupal.googleanalytics.test.assertSame('//example.com/node/2', Drupal.googleanalytics.getPageUrl('//example.com/node/2'), "Full qualified external url '//example.com/node/2' has been extracted."); console.groupEnd(); @@ -105,9 +107,9 @@ $(document).ready(function() { if (Drupal.settings.googleanalytics.trackCrossDomains) { console.dir(Drupal.settings.googleanalytics.trackCrossDomains); Drupal.googleanalytics.test.assertTrue(Drupal.googleanalytics.isCrossDomain('example.com', Drupal.settings.googleanalytics.trackCrossDomains), "URL 'example.com' has been found in cross domain list."); - Drupal.googleanalytics.test.assertTrue(Drupal.googleanalytics.isCrossDomain('example.net', Drupal.settings.googleanalytics.trackCrossDomains), "URL 'example.com' has been found in cross domain list."); + Drupal.googleanalytics.test.assertTrue(Drupal.googleanalytics.isCrossDomain('example.net', Drupal.settings.googleanalytics.trackCrossDomains), "URL 'example.net' has been found in cross domain list."); Drupal.googleanalytics.test.assertFalse(Drupal.googleanalytics.isCrossDomain('www.example.com', Drupal.settings.googleanalytics.trackCrossDomains), "URL 'www.example.com' not found in cross domain list."); - Drupal.googleanalytics.test.assertFalse(Drupal.googleanalytics.isCrossDomain('www.example.net', Drupal.settings.googleanalytics.trackCrossDomains), "URL 'www.example.com' not found in cross domain list."); + Drupal.googleanalytics.test.assertFalse(Drupal.googleanalytics.isCrossDomain('www.example.net', Drupal.settings.googleanalytics.trackCrossDomains), "URL 'www.example.net' not found in cross domain list."); } else { console.warn('Cross domain tracking is not enabled. Tests skipped.'); diff --git a/profiles/wcm_base/modules/contrib/honeypot/README.md b/profiles/wcm_base/modules/contrib/honeypot/README.md new file mode 100644 index 0000000000000000000000000000000000000000..91f9a4e882bd5c614d84b93f22c4529372485ef1 --- /dev/null +++ b/profiles/wcm_base/modules/contrib/honeypot/README.md @@ -0,0 +1,58 @@ + +# Honeypot + +[](https://travis-ci.org/geerlingguy/drupal-honeypot) + + +## Installation + +To install this module, place it in your sites/all/modules folder and enable it +on the modules page. + + +## Configuration + +All settings for this module are on the Honeypot configuration page, under the +Configuration section, in the Content authoring settings. You can visit the +configuration page directly at admin/config/content/honeypot. + +Note that, when testing Honeypot on your website, make sure you're not logged in +as an administrative user or user 1; Honeypot allows administrative users to +bypass Honeypot protection, so by default, Honeypot will not be added to forms +accessed by site administrators. + + +## Use in Your Own Forms + +If you want to add honeypot to your own forms, or to any form through your own +module's hook_form_alter's, you can simply place the following function call +inside your form builder function (or inside a hook_form_alter): + + honeypot_add_form_protection( + $form, + $form_state, + array('honeypot', 'time_restriction') + ); + +Note that you can enable or disable either the honeypot field, or the time +restriction on the form by including or not including the option in the array. + + +## Testing + +Honeypot includes a `docker-compose.yml` file that can be used for testing purposes. To build a Drupal 8 environment for local testing, do the following: + + 1. Make sure you have Docker for Mac (or for whatever OS you're using) installed. + 2. Add the following entry to your `/etc/hosts` file: `192.168.22.33 local.drupalhoneypot.com` + 3. Run `docker-compose up -d` in this directory. + 4. Install Drupal: `docker exec honeypot install-drupal 7.x` (optionally provide a version after `install-drupal`). + 5. Link the honeypot module directory into the Drupal modules directory: `docker exec honeypot ln -s /opt/honeypot/ /var/www/drupalvm/drupal/web/sites/all/modules/honeypot` + 6. Visit `http://local.drupalhoneypot.com/user` and log in using the admin credentials Drush displayed. + +> Note: If you're using a Mac, you may also need to perform additional steps to get the hostname working; see [Managing your hosts file](http://docs.drupalvm.com/en/latest/other/docker/#managing-your-hosts-file) in the Drupal VM documentation. + + +## Credit + +The Honeypot module was originally developed by Jeff Geerling of Midwestern Mac, +LLC (midwesternmac.com), and sponsored by Flocknote (flocknote.com). diff --git a/profiles/wcm_base/modules/contrib/honeypot/README.txt b/profiles/wcm_base/modules/contrib/honeypot/README.txt deleted file mode 100644 index bc5fb1bbb1000874f6871b383f2e6ac40462a82e..0000000000000000000000000000000000000000 --- a/profiles/wcm_base/modules/contrib/honeypot/README.txt +++ /dev/null @@ -1,43 +0,0 @@ - -Honeypot Module Readme ----------------------- - - -Installation ------------- - -To install this module, place it in your sites/all/modules folder and enable it -on the modules page. - - -Configuration -------------- - -All settings for this module are on the Honeypot configuration page, under the -Configuration section, in the Content authoring settings. You can visit the -configuration page directly at admin/config/content/honeypot. - -Note that, when testing Honeypot on your website, make sure you're not logged in -as an administrative user or user 1; Honeypot allows administrative users to -bypass Honeypot protection, so by default, Honeypot will not be added to forms -accessed by site administrators. - - -Use in Your Own Forms ---------------------- - -If you want to add honeypot to your own forms, or to any form through your own -module's hook_form_alter's, you can simply place the following function call -inside your form builder function (or inside a hook_form_alter): - -honeypot_add_form_protection($form, $form_state, array('honeypot', 'time_restriction')); - -Note that you can enable or disable either the honeypot field, or the time -restriction on the form by including or not including the option in the array. - - -Credit ------- - -The Honeypot module was originally developed by Jeff Geerling of Midwestern Mac, -LLC (midwesternmac.com), and sponsored by flockNote (flocknote.com). \ No newline at end of file diff --git a/profiles/wcm_base/modules/contrib/honeypot/docker-compose.yml b/profiles/wcm_base/modules/contrib/honeypot/docker-compose.yml new file mode 100644 index 0000000000000000000000000000000000000000..1c8b6bb8ff92c6c6f6dac92ada0e43d21cb7c558 --- /dev/null +++ b/profiles/wcm_base/modules/contrib/honeypot/docker-compose.yml @@ -0,0 +1,32 @@ +version: "3" + +services: + + honeypot: + image: geerlingguy/drupal-vm + container_name: honeypot + ports: + - 80:80 + - 443:443 + privileged: true + extra_hosts: + local.drupalhoneypot.com: 127.0.0.1 + dns: + - 8.8.8.8 + - 8.8.4.4 + volumes: + - ./:/opt/honeypot/:rw,delegated + command: /lib/systemd/systemd + networks: + honeypot: + ipv4_address: 192.168.22.33 + +networks: + + honeypot: + driver: bridge + driver_opts: + ip: 192.168.22.1 + ipam: + config: + - subnet: "192.168.22.0/16" diff --git a/profiles/wcm_base/modules/contrib/honeypot/honeypot.admin.inc b/profiles/wcm_base/modules/contrib/honeypot/honeypot.admin.inc index 64e3ae42269c59acfcfc0d5d3effcd424d86be95..84bb7e2cd7d25abb2e0feee257deb0548019b85b 100644 --- a/profiles/wcm_base/modules/contrib/honeypot/honeypot.admin.inc +++ b/profiles/wcm_base/modules/contrib/honeypot/honeypot.admin.inc @@ -22,7 +22,9 @@ function honeypot_admin_form($form, &$form_state) { '#description' => t('Enable Honeypot protection for ALL forms on this site (it is best to only enable Honeypot for the forms you need below).'), '#default_value' => variable_get('honeypot_protect_all_forms', 0), ); - $form['configuration']['honeypot_protect_all_forms']['#description'] .= '<br />' . t('<strong>Page caching will be disabled on any page where a form is present if the Honeypot time limit is not set to 0.</strong>'); + if (!variable_get('honeypot_use_js_for_cached_pages', FALSE)) { + $form['configuration']['honeypot_protect_all_forms']['#description'] .= '<br />' . t('<strong>Page caching will be disabled on any page where a form is present if the Honeypot time limit is not set to 0.</strong>'); + } $form['configuration']['honeypot_log'] = array( '#type' => 'checkbox', '#title' => t('Log blocked form submissions'), @@ -46,7 +48,23 @@ function honeypot_admin_form($form, &$form_state) { '#size' => 5, '#field_suffix' => t('seconds'), ); - $form['configuration']['honeypot_time_limit']['#description'] .= '<br />' . t('<strong>Page caching will be disabled if there is a form protected by time limit on the page.</strong>'); + if (!variable_get('honeypot_use_js_for_cached_pages', FALSE)) { + $form['configuration']['honeypot_time_limit']['#description'] .= '<br />' . t('<strong>Page caching will be disabled if there is a form protected by time limit on the page.</strong>'); + } + + $form['configuration']['honeypot_use_js_for_cached_pages'] = array( + '#type' => 'checkbox', + '#title' => t('Use Javascript protection for cacheable pages. (experimental)'), + '#description' => t('Uses Javascript to preserve Page caching.'), + '#default_value' => variable_get('honeypot_use_js_for_cached_pages', FALSE), + '#states' => array( + // Hide this when time limit is disabled. + 'invisible' => array( + 'input[name="honeypot_time_limit"]' => array('value' => 0), + ), + ), + ); + $form['configuration']['honeypot_use_js_for_cached_pages']['#description'] .= '<br />' . t('<strong>Warning: Users who have javascript disabled will need to confirm their form submission on the next page (if the Honeypot-enabled form is on a cacheable page).</strong>'); // Honeypot Enabled forms. $form['enabled_forms'] = array( diff --git a/profiles/wcm_base/modules/contrib/honeypot/honeypot.info b/profiles/wcm_base/modules/contrib/honeypot/honeypot.info index 857d242ef72b2beeb3098f9cd4efcf3f4359519e..6ce86d53c36fe1b775220d2638435d2f8049c56d 100644 --- a/profiles/wcm_base/modules/contrib/honeypot/honeypot.info +++ b/profiles/wcm_base/modules/contrib/honeypot/honeypot.info @@ -6,9 +6,8 @@ package = "Spam control" files[] = honeypot.test -; Information added by Drupal.org packaging script on 2016-03-11 -version = "7.x-1.22" +; Information added by Drupal.org packaging script on 2018-08-09 +version = "7.x-1.25" core = "7.x" project = "honeypot" -datestamp = "1457672041" - +datestamp = "1533849190" diff --git a/profiles/wcm_base/modules/contrib/honeypot/honeypot.install b/profiles/wcm_base/modules/contrib/honeypot/honeypot.install index 5a56052509a7e71d9c840c8c98b223ff6e96ad96..c17b4cb45c0be0d96b7320c4e770b78b92d6d6d4 100644 --- a/profiles/wcm_base/modules/contrib/honeypot/honeypot.install +++ b/profiles/wcm_base/modules/contrib/honeypot/honeypot.install @@ -68,8 +68,8 @@ function honeypot_uninstall() { } } - // Delete 'honeypot' directory from public file directory. - file_unmanaged_delete_recursive('public://honeypot'); + // Delete 'honeypot' directory from files directory. + file_unmanaged_delete_recursive(honeypot_file_default_scheme() . '://honeypot'); } /** diff --git a/profiles/wcm_base/modules/contrib/honeypot/honeypot.module b/profiles/wcm_base/modules/contrib/honeypot/honeypot.module index 46f83ae61e5d92cc415d64dbe5e189b631030507..e8137966c038ef54b955155fe9ad49d7117262f7 100644 --- a/profiles/wcm_base/modules/contrib/honeypot/honeypot.module +++ b/profiles/wcm_base/modules/contrib/honeypot/honeypot.module @@ -78,7 +78,7 @@ function honeypot_form_alter(&$form, &$form_state, $form_id) { if (variable_get('honeypot_protect_all_forms', 0) && !in_array($form_id, $unprotected_forms)) { // Don't protect system forms - only admins should have access, and system // forms may be programmatically submitted by drush and other modules. - if (strpos($form_id, 'system_') === FALSE && strpos($form_id, 'search_') === FALSE && strpos($form_id, 'views_exposed_form_') === FALSE) { + if (preg_match('/[^a-zA-Z]system_/', $form_id) === 0 && preg_match('/[^a-zA-Z]search_/', $form_id) === 0 && preg_match('/[^a-zA-Z]views_exposed_form_/', $form_id) === 0) { honeypot_add_form_protection($form, $form_state, array('honeypot', 'time_restriction')); } } @@ -135,6 +135,36 @@ function honeypot_rules_event_info() { ); } +/** + * Implements hook_library(). + */ +function honeypot_library() { + $info = system_get_info('module', 'honeypot'); + $version = $info['version']; + + // Library for Honeypot JS. + $libraries['timestamp.js'] = array( + 'title' => 'Javascript to support timelimit on cached pages.', + 'version' => $version, + 'js' => array( + array( + 'type' => 'setting', + 'data' => array( + 'honeypot' => array( + 'jsToken' => honeypot_get_signed_timestamp('js_token:' . mt_rand(0, 2147483647)), + ), + ), + ), + drupal_get_path('module', 'honeypot') . '/js/honeypot.js' => array( + 'group' => JS_LIBRARY, + 'weight' => 3, + ), + ), + ); + + return $libraries; +} + /** * Build an array of all the protected forms on the site, by form_id. * @@ -233,8 +263,16 @@ function honeypot_add_form_protection(&$form, &$form_state, $options = array()) ); // Disable page caching to make sure timestamp isn't cached. - if (user_is_anonymous()) { - drupal_page_is_cacheable(FALSE); + if (user_is_anonymous() && drupal_page_is_cacheable()) { + // Use javascript implementation if this page should be cached. + if (variable_get('honeypot_use_js_for_cached_pages', FALSE)) { + $form['honeypot_time']['#default_value'] = 'no_js_available'; + $form['honeypot_time']['#attached']['library'][] = array('honeypot', 'timestamp.js'); + $form['#attributes']['class'][] = 'honeypot-timestamp-js'; + } + else { + drupal_page_is_cacheable(FALSE); + } } } @@ -261,7 +299,7 @@ function _honeypot_honeypot_validate($element, &$form_state) { /** * Validate honeypot's time restriction field. */ -function _honeypot_time_restriction_validate($element, &$form_state) { +function _honeypot_time_restriction_validate(&$element, &$form_state) { if (!empty($form_state['programmed'])) { // Don't do anything if the form was submitted programmatically. return; @@ -272,8 +310,43 @@ function _honeypot_time_restriction_validate($element, &$form_state) { return; } - // Get the time value. - $honeypot_time = honeypot_get_time_from_signed_timestamp($form_state['values']['honeypot_time']); + if ($form_state['values']['honeypot_time'] == 'no_js_available') { + // Set an error, but do not penalize the user as it might be a legitimate + // attempt. + form_set_error('', t('You seem to have javascript disabled. Please confirm your form submission.')); + + if (variable_get('honeypot_log', 0)) { + $variables = array( + '%form' => $form_state['values']['form_id'], + ); + watchdog('honeypot', 'User tried to submit form %form without javascript enabled.', $variables); + } + + // Update the value in $form_state and $element. + $form_state['values']['honeypot_time'] = honeypot_get_signed_timestamp(REQUEST_TIME); + $element['#value'] = $form_state['values']['honeypot_time']; + return; + } + + $honeypot_time = FALSE; + + // Update the honeypot_time for JS requests and get the $honeypot_time value. + if (strpos($form_state['values']['honeypot_time'], 'js_token:') === 0) { + $interval = _honeypot_get_interval_from_signed_js_value($form_state['values']['honeypot_time']); + if ($interval) { + // Set correct value for timestamp validation. + $honeypot_time = REQUEST_TIME - $interval; + + // Update form_state and element values so they're correct. + $form_state['values']['honeypot_time'] = honeypot_get_signed_timestamp($honeypot_time); + $element['#value'] = $form_state['values']['honeypot_time']; + } + } + // Otherwise just get the $honeypot_time value. + else { + // Get the time value. + $honeypot_time = honeypot_get_time_from_signed_timestamp($form_state['values']['honeypot_time']); + } // Get the honeypot_time_limit. $time_limit = honeypot_get_time_limit($form_state['values']); @@ -284,11 +357,43 @@ function _honeypot_time_restriction_validate($element, &$form_state) { _honeypot_log($form_state['values']['form_id'], 'honeypot_time'); // Get the time limit again, since it increases after first failure. $time_limit = honeypot_get_time_limit($form_state['values']); + // Update the honeypot_time value in the form state and element. $form_state['values']['honeypot_time'] = honeypot_get_signed_timestamp(REQUEST_TIME); + $element['#value'] = $form_state['values']['honeypot_time']; form_set_error('', t('There was a problem with your form submission. Please wait @limit seconds and try again.', array('@limit' => $time_limit))); } } +/** + * Returns an interval if the given javascript submitted value is valid. + * + * @param string $honeypot_time + * The signed interval as submitted via javascript. + * + * @return int|FALSE + * The interval in seconds if the token is valid, FALSE otherwise. + */ +function _honeypot_get_interval_from_signed_js_value($honeypot_time) { + $t = explode('|', $honeypot_time); + + if (count($t) != 3) { + return FALSE; + } + + $js_token = $t[0] . '|' . $t[1]; + $token_check = honeypot_get_time_from_signed_timestamp($js_token); + if (!$token_check) { + return FALSE; + } + + $interval = (int) $t[2]; + if ($interval == 0) { + return FALSE; + } + + return $interval; +} + /** * Log blocked form submissions. * @@ -398,7 +503,7 @@ function honeypot_log_failure($form_id, $type) { * The path to the honeypot.css file. */ function honeypot_get_css_file_path() { - return variable_get('file_public_path', conf_path() . '/files') . '/honeypot/honeypot.css'; + return honeypot_file_default_scheme() . '://honeypot/honeypot.css'; } /** @@ -408,7 +513,7 @@ function honeypot_get_css_file_path() { * The honeypot element class name (e.g. 'url'). */ function honeypot_create_css($element_name) { - $path = 'public://honeypot'; + $path = honeypot_file_default_scheme() . '://honeypot'; if (!file_prepare_directory($path, FILE_CREATE_DIRECTORY)) { drupal_set_message(t('Unable to create Honeypot CSS directory, %path. Check the permissions on your files directory.', array('%path' => file_uri_target($path))), 'error'); @@ -487,3 +592,15 @@ function honeypot_get_time_from_signed_timestamp($signed_timestamp) { return $honeypot_time; } + +/** + * Gets the default file stream for honeypot. + * + * @return + * 'public', 'private' or any other file scheme defined as the default. + * + * @see file_default_scheme() + */ +function honeypot_file_default_scheme() { + return variable_get('honeypot_file_default_scheme', file_default_scheme()); +} diff --git a/profiles/wcm_base/modules/contrib/honeypot/honeypot.test b/profiles/wcm_base/modules/contrib/honeypot/honeypot.test index dd136b93684c999dcd7843501b4d83cc8d283025..aab7f6e03cb077783085346780e57d6011168c41 100644 --- a/profiles/wcm_base/modules/contrib/honeypot/honeypot.test +++ b/profiles/wcm_base/modules/contrib/honeypot/honeypot.test @@ -366,6 +366,60 @@ class HoneypotCssTestCase extends DrupalWebTestCase { // Revert the honeypot element name back to the original. variable_set('honeypot_element_name', $original_element_name); } + + /** + * Test CSS works when default file scheme is not public:// + */ + public function testHoneypotCssNonpublicFileSystem() { + variable_set('file_default_scheme', 'private'); + + $honeypot_css = honeypot_get_css_file_path(); + + // Delete the Honeypot CSS file (if it exists). + file_unmanaged_delete($honeypot_css); + + // Make sure the Honeypot CSS file doesn't exist. + $this->assertFalse(file_exists($honeypot_css)); + + // Run cron. + honeypot_cron(); + + // Make sure the Honeypot CSS file exists. + $this->assertTrue(file_exists($honeypot_css)); + } + + /** + * Test CSS file availability. + */ + public function testHoneypotCssAvailability() { + // Public CSS file can be consumed. + variable_set('file_default_scheme', 'public'); + if ($wrapper = file_stream_wrapper_get_instance_by_uri(honeypot_get_css_file_path())) { + $url = $wrapper->getExternalUrl(); + } + $this->drupalGet($url); + $this->assertResponse(200); + + + // Private CSS file can not be consumed. + variable_set('file_default_scheme', 'private'); + honeypot_cron(); + if ($wrapper = file_stream_wrapper_get_instance_by_uri(honeypot_get_css_file_path())) { + $url = $wrapper->getExternalUrl(); + } + $this->drupalGet($url); + $this->assertNoResponse(200); + + // Site default is private, but override honeypot's to public to consume. + variable_set('honeypot_file_default_scheme', 'public'); + honeypot_cron(); + if ($wrapper = file_stream_wrapper_get_instance_by_uri(honeypot_get_css_file_path())) { + $url = $wrapper->getExternalUrl(); + } + $this->drupalGet($url); + $this->assertResponse(200); + } + } /** @@ -423,4 +477,5 @@ class HoneypotTriggerTestCase extends DrupalWebTestCase { $this->drupalGet('node'); $this->assertText(t('has been banned'), 'User banned successfully.'); } + } diff --git a/profiles/wcm_base/modules/contrib/honeypot/js/honeypot.js b/profiles/wcm_base/modules/contrib/honeypot/js/honeypot.js new file mode 100644 index 0000000000000000000000000000000000000000..63acffd7e14d88febcd11426fc9407f9cea9958a --- /dev/null +++ b/profiles/wcm_base/modules/contrib/honeypot/js/honeypot.js @@ -0,0 +1,37 @@ +(function ($) { + + Drupal.honeypot = {}; + Drupal.honeypot.timestampJS = new Date(); + + Drupal.behaviors.honeypotJS = { + attach: function (context, settings) { + $('form.honeypot-timestamp-js').once('honeypot-timestamp').bind('submit', function() { + var $honeypotTime = $(this).find('input[name="honeypot_time"]'); + $honeypotTime.attr('value', Drupal.behaviors.honeypotJS.getIntervalTimestamp()); + }); + }, + getIntervalTimestamp: function() { + var now = new Date(); + var interval = Math.floor((now - Drupal.honeypot.timestampJS) / 1000); + return Drupal.settings.honeypot.jsToken + '|' + interval; + } + }; + + if (Drupal.ajax && Drupal.ajax.prototype && Drupal.ajax.prototype.beforeSubmit) { + Drupal.ajax.prototype.honeypotOriginalBeforeSubmit = Drupal.ajax.prototype.beforeSubmit; + Drupal.ajax.prototype.beforeSubmit = function (form_values, element, options) { + if (this.form && $(this.form).hasClass('honeypot-timestamp-js')) { + for (key in form_values) { + // Inject the right interval timestamp. + if (form_values[key].name == 'honeypot_time' && form_values[key].value == 'no_js_available') { + form_values[key].value = Drupal.behaviors.honeypotJS.getIntervalTimestamp(); + } + } + } + + // Call the original function in case someone else has overridden it. + return Drupal.ajax.prototype.honeypotOriginalBeforeSubmit(form_values, element, options); + } + } + +}(jQuery)); diff --git a/profiles/wcm_base/modules/contrib/honeypot/tests/honeypot_test.info b/profiles/wcm_base/modules/contrib/honeypot/tests/honeypot_test.info index 7b0226ad7e78dac6a4156741306428b334ed946e..89aa78bce446d270d27b537635312411fbd8980b 100644 --- a/profiles/wcm_base/modules/contrib/honeypot/tests/honeypot_test.info +++ b/profiles/wcm_base/modules/contrib/honeypot/tests/honeypot_test.info @@ -4,9 +4,8 @@ core = 7.x package = Testing hidden = true -; Information added by Drupal.org packaging script on 2016-03-11 -version = "7.x-1.22" +; Information added by Drupal.org packaging script on 2018-08-09 +version = "7.x-1.25" core = "7.x" project = "honeypot" -datestamp = "1457672041" - +datestamp = "1533849190" diff --git a/profiles/wcm_base/modules/contrib/redis/README.txt b/profiles/wcm_base/modules/contrib/redis/README.txt index 3314cc377ebd32ac80b8d57c2276bddcbac30671..37357eb30054af84ab7fa102e0c44bac752b3560 100644 --- a/profiles/wcm_base/modules/contrib/redis/README.txt +++ b/profiles/wcm_base/modules/contrib/redis/README.txt @@ -26,7 +26,7 @@ enabled due to the EVAL command usage. If you can't upgrade you Redis server: - - 3.x release will only officially support Redis server <= 2.6 + - 3.x release will only officially support Redis server <= 2.8 and 3.x nevertheless you may use it with Redis 2.4 if you configure your cache backend to operate in sharding mode. diff --git a/profiles/wcm_base/modules/contrib/redis/redis.info b/profiles/wcm_base/modules/contrib/redis/redis.info index a3ca4afefe92e308bd0494d38bed2dbff66e002b..931f282bdb9c7e5080d7ae086eb352996d21234a 100644 --- a/profiles/wcm_base/modules/contrib/redis/redis.info +++ b/profiles/wcm_base/modules/contrib/redis/redis.info @@ -36,9 +36,9 @@ files[] = lib/Redis/Tests/Queue/QueueUnitTestCase.php files[] = lib/Redis/Tests/Queue/PhpRedisQueueUnitTestCase.test files[] = lib/Redis/Tests/Queue/PredisQueueUnitTestCase.test -; Information added by Drupal.org packaging script on 2016-12-21 -version = "7.x-3.15" +; Information added by Drupal.org packaging script on 2017-12-22 +version = "7.x-3.17" core = "7.x" project = "redis" -datestamp = "1482355391" +datestamp = "1513939095" diff --git a/profiles/wcm_base/modules/contrib/redis/redis.install b/profiles/wcm_base/modules/contrib/redis/redis.install index 7918887186d4b2b82b826c40d1430266bee2bb35..b3e6067065ec77ac81ce10e7a200e6c13bbdf50c 100644 --- a/profiles/wcm_base/modules/contrib/redis/redis.install +++ b/profiles/wcm_base/modules/contrib/redis/redis.install @@ -30,7 +30,7 @@ function redis_requirements($phase) { 'title' => "Redis", 'value' => t("Not connected."), 'severity' => REQUIREMENT_WARNING, - 'description' => t("No Redis client connected, this module is useless thereof. Ensure that you enabled module using it or disable it."), + 'description' => t("No Redis client connected. Please ensure that your Redis connection is working properly. If you are not using a Redis server connection you should disable this module."), ); } diff --git a/profiles/wcm_base/modules/contrib/redis/redis.path.inc b/profiles/wcm_base/modules/contrib/redis/redis.path.inc index a53017df72885496144e6ebd3369be28aa834789..73ffa091001ec30543a8a85707a4299476c71103 100644 --- a/profiles/wcm_base/modules/contrib/redis/redis.path.inc +++ b/profiles/wcm_base/modules/contrib/redis/redis.path.inc @@ -121,17 +121,17 @@ function drupal_lookup_path($action, $path = '', $path_language = NULL) { // the right language (keeps track of LANGUAGE_NONE or specific language // so that default fallback behavior is the same that core). if ($path_language == LANGUAGE_NONE) { - list ($ret, $path_language) = db_query("SELECT alias, language FROM {url_alias} WHERE source = :source AND language = :language ORDER BY pid DESC LIMIT 1", array( + list ($ret, $path_language) = db_query_range("SELECT alias, language FROM {url_alias} WHERE source = :source AND language = :language ORDER BY pid DESC", 0, 1, array( ':source' => $path, ':language' => $path_language, ))->fetch(PDO::FETCH_NUM); } else if ($path_language > LANGUAGE_NONE) { - list ($ret, $path_language) = db_query("SELECT alias, language FROM {url_alias} WHERE source = :source AND language IN (:language) ORDER BY language DESC, pid DESC LIMIT 1", array( + list ($ret, $path_language) = db_query_range("SELECT alias, language FROM {url_alias} WHERE source = :source AND language IN (:language) ORDER BY language DESC, pid DESC", 0, 1, array( ':source' => $path, ':language' => array($path_language, LANGUAGE_NONE), ))->fetch(PDO::FETCH_NUM); } else { - list ($ret, $path_language) = db_query("SELECT alias, language FROM {url_alias} WHERE source = :source AND language IN (:language) ORDER BY language ASC, pid DESC LIMIT 1", array( + list ($ret, $path_language) = db_query_range("SELECT alias, language FROM {url_alias} WHERE source = :source AND language IN (:language) ORDER BY language ASC, pid DESC", 0, 1, array( ':source' => $path, ':language' => array($path_language, LANGUAGE_NONE), ))->fetch(PDO::FETCH_NUM); @@ -163,17 +163,17 @@ function drupal_lookup_path($action, $path = '', $path_language = NULL) { // the right language (keeps track of LANGUAGE_NONE or specific language // so that default fallback behavior is the same that core). if ($path_language == LANGUAGE_NONE) { - list ($ret, $path_language) = db_query("SELECT source, language FROM {url_alias} WHERE alias = :alias AND language = :language ORDER BY pid DESC LIMIT 1", array( + list ($ret, $path_language) = db_query_range("SELECT source, language FROM {url_alias} WHERE alias = :alias AND language = :language ORDER BY pid DESC", 0, 1, array( ':alias' => $path, ':language' => LANGUAGE_NONE, ))->fetch(PDO::FETCH_NUM); } else if ($path_language > LANGUAGE_NONE) { - list ($ret, $path_language) = db_query("SELECT source, language FROM {url_alias} WHERE alias = :alias AND language IN (:language) ORDER BY language DESC, pid DESC LIMIT 1", array( + list ($ret, $path_language) = db_query_range("SELECT source, language FROM {url_alias} WHERE alias = :alias AND language IN (:language) ORDER BY language DESC, pid DESC", 0, 1, array( ':alias' => $path, ':language' => array($path_language, LANGUAGE_NONE), ))->fetch(PDO::FETCH_NUM); } else { - list ($ret, $path_language) = db_query("SELECT source, language FROM {url_alias} WHERE alias = :alias AND language IN (:language) ORDER BY language ASC, pid DESC LIMIT 1", array( + list ($ret, $path_language) = db_query_range("SELECT source, language FROM {url_alias} WHERE alias = :alias AND language IN (:language) ORDER BY language ASC, pid DESC", 0, 1, array( ':alias' => $path, ':language' => array($path_language, LANGUAGE_NONE), ))->fetch(PDO::FETCH_NUM); @@ -567,8 +567,8 @@ function drupal_valid_path($path, $dynamic_allowed = FALSE) { elseif ($dynamic_allowed && preg_match('/\/\%/', $path)) { // Path is dynamic (ie 'user/%'), so check directly against menu_router table. if ($item = db_query("SELECT * FROM {menu_router} where path = :path", array(':path' => $path))->fetchAssoc()) { - $item['link_path'] = $item['link_path']; - $item['link_title'] = $item['link_title']; + $item['link_path'] = $item['path']; + $item['link_title'] = $item['title']; $item['external'] = FALSE; $item['options'] = ''; _menu_link_translate($item); diff --git a/profiles/wcm_base/modules/contrib/taxonomy_access_fix/taxonomy_access_fix.info b/profiles/wcm_base/modules/contrib/taxonomy_access_fix/taxonomy_access_fix.info index 587e84be942aaa85642b6b97de05908c6f4a9419..eaf1389ce06fd46d278c5a82c37f5e2185932ca3 100644 --- a/profiles/wcm_base/modules/contrib/taxonomy_access_fix/taxonomy_access_fix.info +++ b/profiles/wcm_base/modules/contrib/taxonomy_access_fix/taxonomy_access_fix.info @@ -6,9 +6,9 @@ package = Taxonomy dependencies[] = taxonomy -; Information added by Drupal.org packaging script on 2015-11-11 -version = "7.x-2.3" +; Information added by Drupal.org packaging script on 2018-02-09 +version = "7.x-2.4" core = "7.x" project = "taxonomy_access_fix" -datestamp = "1447247349" +datestamp = "1518211686" diff --git a/profiles/wcm_base/modules/contrib/taxonomy_access_fix/taxonomy_access_fix.module b/profiles/wcm_base/modules/contrib/taxonomy_access_fix/taxonomy_access_fix.module index 36d27f117edb78126800eab84bfb9adb3470cc80..763de11cdc658daefd8937f1d50fed326f3c7ab6 100644 --- a/profiles/wcm_base/modules/contrib/taxonomy_access_fix/taxonomy_access_fix.module +++ b/profiles/wcm_base/modules/contrib/taxonomy_access_fix/taxonomy_access_fix.module @@ -149,6 +149,8 @@ function taxonomy_access_fix_access($op, $vocabulary = NULL) { return TRUE; } + $access = FALSE; + if ($vocabulary && is_string($vocabulary)) { $vocabulary = taxonomy_vocabulary_machine_name_load($vocabulary); } @@ -159,7 +161,8 @@ function taxonomy_access_fix_access($op, $vocabulary = NULL) { // Allow access when the user has access to at least one vocabulary. foreach (taxonomy_get_vocabularies() as $vid => $vocabulary) { if (user_access('edit terms in ' . $vid) || user_access('delete terms in ' . $vid) || user_access('add terms in ' . $vocabulary->machine_name)) { - return TRUE; + $access = TRUE; + break; } } break; @@ -169,7 +172,7 @@ function taxonomy_access_fix_access($op, $vocabulary = NULL) { if ($vocabulary) { $vid = $vocabulary->vid; if (user_access('edit terms in ' . $vid) || user_access('delete terms in ' . $vid) || user_access('add terms in ' . $vocabulary->machine_name)) { - return TRUE; + $access = TRUE; } } break; @@ -177,11 +180,15 @@ function taxonomy_access_fix_access($op, $vocabulary = NULL) { case 'add terms': if ($vocabulary) { if (user_access('add terms in ' . $vocabulary->machine_name)) { - return TRUE; + $access = TRUE; } } break; } + + drupal_alter('taxonomy_access_fix', $op, $vocabulary, $access); + + return $access; } /** diff --git a/profiles/wcm_base/modules/contrib/views_bulk_operations/actions/book.action.inc b/profiles/wcm_base/modules/contrib/views_bulk_operations/actions/book.action.inc index ad8fa9c41e9de4e0aec47d824d24e6ee3fb9cfc8..4621dcd16cb03e650c33bc8ddf0da5ebcda1eea3 100644 --- a/profiles/wcm_base/modules/contrib/views_bulk_operations/actions/book.action.inc +++ b/profiles/wcm_base/modules/contrib/views_bulk_operations/actions/book.action.inc @@ -58,9 +58,9 @@ function views_bulk_operations_move_to_book_action_submit($form, $form_state) { function views_bulk_operations_move_to_book_action($node, $context = array()) { if (isset($context['book'])) { $book_node = node_load($context['book']); - $mlid = db_select('menu_links' , 'ml') - ->condition('ml.link_path' , 'node/' . $node->nid) - ->fields('ml' , array('mlid')) + $mlid = db_select('menu_links', 'ml') + ->condition('ml.link_path', 'node/' . $node->nid) + ->fields('ml', array('mlid')) ->execute() ->fetchField(); $node->book['mlid'] = $mlid; @@ -71,9 +71,10 @@ function views_bulk_operations_move_to_book_action($node, $context = array()) { } /** - * Adds the action 'Remove node from a parent book' + * Adds the action 'Remove node from a parent book'. */ -function views_bulk_operations_remove_from_book_action($node, $context) { - $book = $node->book['mlid']; +function views_bulk_operations_remove_from_book_action($node) { book_node_delete($node); + // Remove book to avoid book_node_update() from building the links again. + unset($node->book); } diff --git a/profiles/wcm_base/modules/contrib/views_bulk_operations/actions/modify.action.inc b/profiles/wcm_base/modules/contrib/views_bulk_operations/actions/modify.action.inc index 06fa46dc7e092742c206f9b3799166380bed7850..e46268d1fd121887ac72b0593e4c9395d5f9f1f4 100644 --- a/profiles/wcm_base/modules/contrib/views_bulk_operations/actions/modify.action.inc +++ b/profiles/wcm_base/modules/contrib/views_bulk_operations/actions/modify.action.inc @@ -55,7 +55,7 @@ function views_bulk_operations_modify_action($entity, $context) { } } - if (in_array($key, $context['append']['bundle_' . $bundle_name]) && !empty($entity->$key)) { + if (in_array($key, $context['append']['bundle_' . $bundle_name]) && !empty($entity->{$key})) { $entity->{$key}[$language] = array_merge($entity->{$key}[$language], $pseudo_entity->{$key}[$language]); // Check if we breached cardinality, and notify the user. @@ -96,24 +96,24 @@ function views_bulk_operations_modify_action($entity, $context) { if (!empty($context['selected']['properties'])) { foreach ($context['selected']['properties'] as $key) { - if (!$wrapper->$key->access('update')) { + if (!$wrapper->{$key}->access('update')) { // No access. continue; } if (in_array($key, $context['append']['properties'])) { - $old_values = $wrapper->$key->value(); - $wrapper->$key->set($context['properties'][$key]); + $old_values = $wrapper->{$key}->value(); + $wrapper->{$key}->set($context['properties'][$key]); $new_values = $wrapper->{$key}->value(); $all_values = array_merge($old_values, $new_values); - $wrapper->$key->set($all_values); + $wrapper->{$key}->set($all_values); } else { $value = $context['properties'][$key]; if (is_string($value)) { $value = token_replace($value, array($context['entity_type'] => $entity), array('sanitize' => FALSE)); } - $wrapper->$key->set($value); + $wrapper->{$key}->set($value); } } } @@ -193,9 +193,9 @@ function views_bulk_operations_modify_action_form($context, &$form_state) { $form['properties'][$key]['#maxlength'] = 255; } - if (!empty($property['options list'])) { + if (!empty($property['options list']) && is_callable($property['options list'])) { $form['properties'][$key]['#type'] = 'select'; - $form['properties'][$key]['#options'] = $property['options list']($key, array()); + $form['properties'][$key]['#options'] = call_user_func_array($property['options list'], array($key, array())); if ($property['type'] == 'list') { $form['properties'][$key]['#type'] = 'checkboxes'; @@ -405,7 +405,7 @@ function views_bulk_operations_modify_action_validate($form, &$form_state) { $properties = _views_bulk_operations_modify_action_get_properties($form_state['entity_type']); foreach ($form_state['selected']['properties'] as $key) { $value = $form_state['values']['properties'][$key]; - if (!$wrapper->$key->validate($value)) { + if (!$wrapper->{$key}->validate($value)) { $label = $properties[$key]['label']; form_set_error('properties][' . $key, t('%label contains an invalid value.', array('%label' => $label))); } diff --git a/profiles/wcm_base/modules/contrib/views_bulk_operations/actions_permissions.info b/profiles/wcm_base/modules/contrib/views_bulk_operations/actions_permissions.info index 11ff52358330cd69722280aea097f79f55d04522..1f97bd510a3799884e4464f3a9f73573c410c032 100644 --- a/profiles/wcm_base/modules/contrib/views_bulk_operations/actions_permissions.info +++ b/profiles/wcm_base/modules/contrib/views_bulk_operations/actions_permissions.info @@ -3,9 +3,8 @@ description = Provides permission-based access control for actions. Used by View package = Administration core = 7.x -; Information added by Drupal.org packaging script on 2017-02-21 -version = "7.x-3.4" +; Information added by Drupal.org packaging script on 2018-05-08 +version = "7.x-3.5" core = "7.x" project = "views_bulk_operations" -datestamp = "1487698687" - +datestamp = "1525821486" diff --git a/profiles/wcm_base/modules/contrib/views_bulk_operations/js/views_bulk_operations.js b/profiles/wcm_base/modules/contrib/views_bulk_operations/js/views_bulk_operations.js index a4e8237ad001ce39609984cb7422cc4279f3da60..62218bed99b6d55665cf34b5f39800a87810528a 100644 --- a/profiles/wcm_base/modules/contrib/views_bulk_operations/js/views_bulk_operations.js +++ b/profiles/wcm_base/modules/contrib/views_bulk_operations/js/views_bulk_operations.js @@ -38,9 +38,9 @@ $('.vbo-table-select-all', form).show(); // This is the "select all" checkbox in (each) table header. - $('.vbo-table-select-all', form).click(function() { - var table = $(this).closest('table')[0]; - $('input[id^="edit-views-bulk-operations"]:not(:disabled)', table).prop('checked', this.checked); + $('input.vbo-table-select-all', form).click(function() { + var table = $(this).closest('table:not(.sticky-header)')[0]; + $('.vbo-select:not(:disabled)', table).prop('checked', this.checked); Drupal.vbo.toggleButtonsState(form); // Toggle the visibility of the "select all" row (if any). @@ -57,17 +57,13 @@ // Set up the ability to click anywhere on the row to select it. if (Drupal.settings.vbo.row_clickable) { $('.views-table tbody tr', form).click(function(event) { - if (event.target.tagName.toLowerCase() != 'input' && event.target.tagName.toLowerCase() != 'a') { - $('input[id^="edit-views-bulk-operations"]:not(:disabled)', this).each(function() { - var checked = this.checked; - // trigger() toggles the checkmark *after* the event is set, - // whereas manually clicking the checkbox toggles it *beforehand*. - // that's why we manually set the checkmark first, then trigger the - // event (so that listeners get notified), then re-set the checkmark - // which the trigger will have toggled. yuck! - this.checked = !checked; - $(this).trigger('click'); - this.checked = !checked; + var tagName = event.target.tagName.toLowerCase(); + if (tagName != 'input' && tagName != 'a' && tagName != 'label') { + $('.vbo-select:not(:disabled)', this).each(function() { + // Always return true for radios, you cannot de-select a radio by clicking on it, + // it should be the same when clicking on a row. + this.checked = $(this).is(':radio') ? true : !this.checked; + $(this).trigger('change'); }); } }); @@ -92,7 +88,7 @@ $('.vbo-select-all-markup', form).show(); $('.vbo-select-this-page', form).click(function() { - $('input[id^="edit-views-bulk-operations"]', form).prop('checked', this.checked); + $('.vbo-select', form).prop('checked', this.checked); Drupal.vbo.toggleButtonsState(form); $('.vbo-select-all-pages', form).prop('checked', false); @@ -100,7 +96,7 @@ $('.vbo-table-select-all', form).prop('checked', this.checked); }); $('.vbo-select-all-pages', form).click(function() { - $('input[id^="edit-views-bulk-operations"]', form).prop('checked', this.checked); + $('.vbo-select', form).prop('checked', this.checked); Drupal.vbo.toggleButtonsState(form); $('.vbo-select-this-page', form).prop('checked', false); @@ -117,7 +113,8 @@ Drupal.vbo.toggleButtonsState(form); }); - $('.vbo-select', form).click(function() { + // Handle a "change" event originating either from a row click or an actual checkbox click. + $('.vbo-select', form).change(function() { // If a checkbox was deselected, uncheck any "select all" checkboxes. if (!this.checked) { $('.vbo-select-this-page', form).prop('checked', false); @@ -147,7 +144,9 @@ // If no rows are checked, disable any form submit actions. var selectbox = $('select[name="operation"]', form); var checkedCheckboxes = $('.vbo-select:checked', form); - var buttons = $('[id^="edit-select"] input[type="submit"]', form); + // The .vbo-prevent-toggle CSS class is added to buttons to prevent toggling + // between disabled and enabled. For example the case of an 'add' button. + var buttons = $('[id^="edit-select"] [type="submit"]:not(.vbo-prevent-toggle)', form); if (selectbox.length) { var has_selection = checkedCheckboxes.length && selectbox.val() !== '0'; diff --git a/profiles/wcm_base/modules/contrib/views_bulk_operations/plugins/operation_types/action.class.php b/profiles/wcm_base/modules/contrib/views_bulk_operations/plugins/operation_types/action.class.php index f3e60a30507e1e4fec44c811e7129a1ec4674e72..0be5785a9e519a0faa6d757fdc05a76e7ea4b677 100644 --- a/profiles/wcm_base/modules/contrib/views_bulk_operations/plugins/operation_types/action.class.php +++ b/profiles/wcm_base/modules/contrib/views_bulk_operations/plugins/operation_types/action.class.php @@ -128,7 +128,12 @@ class ViewsBulkOperationsAction extends ViewsBulkOperationsBaseOperation { actions_list(); $submit_callback = $this->operationInfo['callback'] . '_submit'; - $this->formOptions = $submit_callback($form, $form_state); + // If the return value from the callback is an options array, store it for + // later union onto the context. + $options = $submit_callback($form, $form_state); + if ($options && is_array($options)) { + $this->formOptions = $options; + } } /** diff --git a/profiles/wcm_base/modules/contrib/views_bulk_operations/views/views_bulk_operations_handler_field_operations.inc b/profiles/wcm_base/modules/contrib/views_bulk_operations/views/views_bulk_operations_handler_field_operations.inc index dcfd534264bbea40b3183e6f561e888e91997841..9b1f88ec39c28f884cf678f84503f3887e22ab9a 100644 --- a/profiles/wcm_base/modules/contrib/views_bulk_operations/views/views_bulk_operations_handler_field_operations.inc +++ b/profiles/wcm_base/modules/contrib/views_bulk_operations/views/views_bulk_operations_handler_field_operations.inc @@ -285,6 +285,7 @@ class views_bulk_operations_handler_field_operations extends views_handler_field '#type' => 'radio', '#parents' => array($this->options['id']), '#return_value' => $id, + '#attributes' => array('class' => array('vbo-select')), ); } else { diff --git a/profiles/wcm_base/modules/contrib/views_bulk_operations/views_bulk_operations.info b/profiles/wcm_base/modules/contrib/views_bulk_operations/views_bulk_operations.info index b16bf0e022f6c29cbe2fc28a09a16df2261a3f9f..058bef7adee64b1eaef308e16ed5cc7762360510 100644 --- a/profiles/wcm_base/modules/contrib/views_bulk_operations/views_bulk_operations.info +++ b/profiles/wcm_base/modules/contrib/views_bulk_operations/views_bulk_operations.info @@ -9,9 +9,8 @@ php = 5.2.9 files[] = plugins/operation_types/base.class.php files[] = views/views_bulk_operations_handler_field_operations.inc -; Information added by Drupal.org packaging script on 2017-02-21 -version = "7.x-3.4" +; Information added by Drupal.org packaging script on 2018-05-08 +version = "7.x-3.5" core = "7.x" project = "views_bulk_operations" -datestamp = "1487698687" - +datestamp = "1525821486" diff --git a/profiles/wcm_base/modules/contrib/views_bulk_operations/views_bulk_operations.module b/profiles/wcm_base/modules/contrib/views_bulk_operations/views_bulk_operations.module index 9b17c4448d6a4cf9f1f54e56846864925bc6d5cc..081e5407225c72cfe6f077ec58bc3fc2c5499fc8 100644 --- a/profiles/wcm_base/modules/contrib/views_bulk_operations/views_bulk_operations.module +++ b/profiles/wcm_base/modules/contrib/views_bulk_operations/views_bulk_operations.module @@ -13,6 +13,7 @@ define('VBO_ACCESS_OP_DELETE', 0x08); /** * Implements hook_action_info(). + * * Registers custom VBO actions as Drupal actions. */ function views_bulk_operations_action_info() { @@ -20,9 +21,14 @@ function views_bulk_operations_action_info() { $files = views_bulk_operations_load_action_includes(); foreach ($files as $filename) { $action_info_fn = 'views_bulk_operations_'. str_replace('.', '_', basename($filename, '.inc')).'_info'; - $action_info = call_user_func($action_info_fn); - if (is_array($action_info)) { - $actions += $action_info; + if (is_callable($action_info_fn)) { + $action_info = call_user_func($action_info_fn); + if (is_array($action_info)) { + $actions += $action_info; + } + } + else { + watchdog('views bulk operations', 'views_bulk_operations_action_info() expects action filenames to have a matching valid callback function named: %function', array('%function' => $action_info_fn), WATCHDOG_WARNING); } } @@ -190,7 +196,7 @@ function views_bulk_operations_get_operation_info($operation_id = NULL) { $operations += $plugin['list callback'](); } - uasort($operations, create_function('$a, $b', 'return strcasecmp($a["label"], $b["label"]);')); + uasort($operations, '_views_bulk_operations_sort_operations_by_label'); } if (!empty($operation_id)) { @@ -201,6 +207,16 @@ function views_bulk_operations_get_operation_info($operation_id = NULL) { } } +/** + * Sort function used by uasort in views_bulk_operations_get_operation_info(). + * + * A closure would be better suited for this, but closure support was added in + * PHP 5.3 and D7 supports 5.2. + */ +function _views_bulk_operations_sort_operations_by_label($a, $b) { + return strcasecmp($a['label'], $b['label']); +} + /** * Returns an operation instance. * @@ -523,7 +539,7 @@ function views_bulk_operations_form($form, &$form_state, $vbo) { $enable_select_all_pages = FALSE; // If the view is paginated, and "select all items on all pages" is // enabled, tell that to the theme function. - if (count($vbo->view->result) != $vbo->view->total_rows && $vbo->get_vbo_option('enable_select_all_pages')) { + if (isset($vbo->view->total_rows) && count($vbo->view->result) != $vbo->view->total_rows && $vbo->get_vbo_option('enable_select_all_pages')) { $enable_select_all_pages = TRUE; } $form['select_all_markup'] = array( @@ -842,7 +858,7 @@ function views_bulk_operations_execute($vbo, $operation, $selection, $select_all // All items on all pages should be selected, add a batch job to gather // and enqueue them. - if ($select_all_pages && $vbo->view->query->pager->has_more_records()) { + if ($select_all_pages && ($vbo->view->query->pager->has_more_records() || $vbo->view->query->pager->get_current_page() > 0)) { $total_rows = $vbo->view->total_rows; $batch['operations'][] = array( @@ -1186,7 +1202,7 @@ function views_bulk_operations_direct_process($operation, $rows, $options) { $skip_permission_check = $operation->getAdminOption('skip_permission_check'); // Filter out entities that can't be accessed. foreach ($entities as $id => $entity) { - if (!$skip_permission_check && !_views_bulk_operations_entity_access($operation, $entity_type, $entity, $account)) { + if (!$skip_permission_check && !_views_bulk_operations_entity_access($operation, $entity_type, $entity, $user)) { $context['results']['log'][] = t('Skipped %operation on @type %title due to insufficient permissions.', array( '%operation' => $operation->label(), '@type' => $entity_type, diff --git a/profiles/wcm_base/modules/contrib/views_bulk_operations/views_bulk_operations.rules.inc b/profiles/wcm_base/modules/contrib/views_bulk_operations/views_bulk_operations.rules.inc index 1273552eaf8117b52c1a907a76efeaf195398e1e..78fae2063eda9889111f46a448a225d97b08ad75 100644 --- a/profiles/wcm_base/modules/contrib/views_bulk_operations/views_bulk_operations.rules.inc +++ b/profiles/wcm_base/modules/contrib/views_bulk_operations/views_bulk_operations.rules.inc @@ -173,7 +173,11 @@ function views_bulk_operations_action_load_list($view, $args) { $entity_type = $vbo->get_entity_type(); $entities = entity_metadata_wrapper("list<$entity_type>", array()); foreach ($vbo->view->result as $row_index => $result) { - $entities[] = entity_metadata_wrapper($entity_type, $vbo->get_value($result)); + // Grab the entire entity if it's already loaded or fall back to the + // entity identifier. + $entity = $vbo->get_value($result); + $data = $entity ? $entity : $result->{$vbo->real_field}; + $entities[] = entity_metadata_wrapper($entity_type, $data); } return array('entity_list' => $entities); diff --git a/profiles/wcm_base/modules/custom/news_client/news_client.module b/profiles/wcm_base/modules/custom/news_client/news_client.module index 5cd7c926da30ce1840f8b0fd7591c67ce49f3ae8..b6749760d46bc2d6aa610cd9cf96d781930cd869 100644 --- a/profiles/wcm_base/modules/custom/news_client/news_client.module +++ b/profiles/wcm_base/modules/custom/news_client/news_client.module @@ -281,7 +281,8 @@ function news_client_field_formatter_view($entity_type, $entity, $field, $instan $url = $image_data->url; $alt = $image_data->alt; $title = $image_data->title; - $caption_text = $image_data->caption; + // Caption is a new addtion. It may not exist for legacy articles. + $caption_text = (property_exists($image_data, 'caption')) ? $image_data->caption : ''; $display_caption = (empty($caption_text)) ? FALSE : $settings['display_caption']; $image_vars = array( diff --git a/profiles/wcm_base/modules/custom/news_client/news_client.tokens.inc b/profiles/wcm_base/modules/custom/news_client/news_client.tokens.inc index e65700e160e956812132670810cb560e032df279..0288fa7ebce683c5d26ddf1c6d883028ea86089d 100644 --- a/profiles/wcm_base/modules/custom/news_client/news_client.tokens.inc +++ b/profiles/wcm_base/modules/custom/news_client/news_client.tokens.inc @@ -61,7 +61,12 @@ function news_client_tokens($type, $tokens, array $data = array(), array $option case 'news_client_featured_image_url' : $image_json = $wrapper->news_client_image_json->value(); $image_array = json_decode($image_json, TRUE); - $image_data = array_shift($image_array); + $image_data = array(); + + // news_client_image_json may be empty, and $image_array would be NULL. Test first. + if (is_array($image_array)) { + $image_data = array_shift($image_array); + } $replacements[$original] = isset($image_data['url']) ? $image_data['url'] : ''; break; @@ -69,7 +74,12 @@ function news_client_tokens($type, $tokens, array $data = array(), array $option case 'news_client_featured_image_alt' : $image_json = $wrapper->news_client_image_json->value(); $image_array = json_decode($image_json, TRUE); - $image_data = array_shift($image_array); + $image_data = array(); + + // news_client_image_json may be empty, and $image_array would be NULL. Test first. + if (is_array($image_array)) { + $image_data = array_shift($image_array); + } $replacements[$original] = isset($image_data['alt']) ? $image_data['alt'] : ''; break; diff --git a/profiles/wcm_base/modules/custom/news_client/views/handlers/news_client_views_handler_field_news_client_image_json.inc b/profiles/wcm_base/modules/custom/news_client/views/handlers/news_client_views_handler_field_news_client_image_json.inc index 9cadaf6396648e3c291cea14104c817568f8eeac..479c71696abe927891ccb22fb250bf1f8bc83981 100644 --- a/profiles/wcm_base/modules/custom/news_client/views/handlers/news_client_views_handler_field_news_client_image_json.inc +++ b/profiles/wcm_base/modules/custom/news_client/views/handlers/news_client_views_handler_field_news_client_image_json.inc @@ -90,7 +90,7 @@ class news_client_views_handler_field_news_client_image_json extends views_handl ), ); $image_markup .= theme_image($data); - $caption_text = $image->caption; + $caption_text = isset($image->caption) ? $image->caption : ''; } $display_caption = (empty($caption_text)) ? FALSE : $this->options['display_caption']; diff --git a/profiles/wcm_base/modules/custom/ocio_news/ocio_news.module b/profiles/wcm_base/modules/custom/ocio_news/ocio_news.module index 65dd177c84d3391f063e249c6b0472d6a26970b4..cd64ec2b8fd2689d59fd0ac77bc49f1e1f8b9153 100644 --- a/profiles/wcm_base/modules/custom/ocio_news/ocio_news.module +++ b/profiles/wcm_base/modules/custom/ocio_news/ocio_news.module @@ -58,10 +58,10 @@ function ocio_news_tokens_alter(&$replacements, $context) { function ocio_news_preprocess_views_view(&$vars) { $view = $vars['view']; - if ($view->name == 'ocio_news_archive' && $view->current_display == 'page') { + if ($view->name == 'ocio_news_archive') { // Modify page title for tag-filtered news page. $tids = isset($view->exposed_raw_input['tag']) ? $view->exposed_raw_input['tag']: 'All'; - if (!empty($tids) && $tids != 'All') { + if ($view->current_display == 'page' && !empty($tids) && $tids != 'All') { $title = $view->display_handler->options['title'] .= ': '; foreach ($tids as $key => $value) { $tids[$key] = taxonomy_term_load($key)->name; diff --git a/profiles/wcm_base/modules/custom/ocio_taxonomy/ocio_taxonomy.make b/profiles/wcm_base/modules/custom/ocio_taxonomy/ocio_taxonomy.make index 92b1692243210b5f17ee4a55bf49fe17343d0d64..e2a59c98c56f619ffe2b9982fb736b10d21a2b5e 100644 --- a/profiles/wcm_base/modules/custom/ocio_taxonomy/ocio_taxonomy.make +++ b/profiles/wcm_base/modules/custom/ocio_taxonomy/ocio_taxonomy.make @@ -6,5 +6,5 @@ core = 7.x ;modules -projects[taxonomy_access_fix][version] = 2.3 +projects[taxonomy_access_fix][version] = 2.4 projects[taxonomy_access_fix][subdir] = contrib diff --git a/profiles/wcm_base/modules/custom/wcm_panels_settings/wcm_panels_settings.install b/profiles/wcm_base/modules/custom/wcm_panels_settings/wcm_panels_settings.install index 40c57149232123f2df8cc9e8dab6cadc3511e0d5..92b6ad2a60ff2df74d99f0b9870bd7c830fbe142 100644 --- a/profiles/wcm_base/modules/custom/wcm_panels_settings/wcm_panels_settings.install +++ b/profiles/wcm_base/modules/custom/wcm_panels_settings/wcm_panels_settings.install @@ -14,3 +14,15 @@ function wcm_panels_settings_update_7001() { } } +/** + * Convert File pane fields from generic file to media. + */ +function wcm_panels_settings_update_7002() { + if ($instance = field_info_instance('fieldable_panels_pane', 'field_basic_file_file', 'basic_file')) { + if ($instance['widget']['type'] == 'file_generic') { + $instance['widget']['module'] = 'media'; + $instance['widget']['type'] = 'media_generic'; + field_update_instance($instance); + } + } +} diff --git a/profiles/wcm_base/modules/custom/wcm_security/wcm_security.make b/profiles/wcm_base/modules/custom/wcm_security/wcm_security.make index ec50037c02a2ed304b92d7b7db9e2979bff49082..62b95db974389218e43771036f57805e60076576 100644 --- a/profiles/wcm_base/modules/custom/wcm_security/wcm_security.make +++ b/profiles/wcm_base/modules/custom/wcm_security/wcm_security.make @@ -5,8 +5,8 @@ core = 7.x ;modules -projects[antibot][version] = 1.0 +projects[antibot][version] = 1.2 projects[antibot][subdir] = contrib -projects[honeypot][version] = 1.22 +projects[honeypot][version] = 1.25 projects[honeypot][subdir] = contrib diff --git a/profiles/wcm_base/wcm_base.make b/profiles/wcm_base/wcm_base.make index a6d6a6740953eb99c25faf2a007c0a4e9b034f3e..bdb15e38d6421bcb14854b14fc852813ee4d3c63 100644 --- a/profiles/wcm_base/wcm_base.make +++ b/profiles/wcm_base/wcm_base.make @@ -39,7 +39,7 @@ projects[entity][version] = 1.9 projects[entity][subdir] = contrib projects[entity][patch][1312374] = http://drupal.org/files/issues/entity-1312374-42-fatal-error-if-missing-property-callback.patch -projects[ds][version] = 2.15 +projects[ds][version] = 2.16 projects[ds][subdir] = contrib projects[features][version] = 2.10 @@ -63,7 +63,7 @@ projects[file_entity][patch][1997208] = http://drupal.org/files/issues/use-file_ projects[file_entity_swf][version] = 1.0-rc2 projects[file_entity_swf][subdir] = contrib -projects[google_analytics][version] = 2.3 +projects[google_analytics][version] = 2.5 projects[google_analytics][subdir] = contrib projects[google_tag][version] = 1.2 @@ -144,7 +144,7 @@ projects[realname][subdir] = contrib projects[r4032login][version] = 1.8 projects[r4032login][subdir] = contrib -projects[redis][version] = 3.15 +projects[redis][version] = 3.17 projects[redis][subdir] = contrib projects[search_api_solr][version] = 1.12 @@ -183,7 +183,7 @@ projects[views_accordion][subdir] = contrib projects[views_conditional][version] = 1.3 projects[views_conditional][subdir] = contrib -projects[views_bulk_operations][version] = 3.4 +projects[views_bulk_operations][version] = 3.5 projects[views_bulk_operations][subdir] = contrib projects[views_nested_accordion][version] = 1.0