From 993b01a6622f6c4e6234d43db43b58c80ab6c223 Mon Sep 17 00:00:00 2001 From: Chris Gross <gross.364@osu.edu> Date: Wed, 29 Aug 2018 15:23:09 -0400 Subject: [PATCH] 7.x-1.9 Release Candidate 3 --- profiles/wcm_base/CHANGELOG.txt | 16 +- .../modules/contrib/antibot/antibot.admin.inc | 9 +- .../modules/contrib/antibot/antibot.info | 9 +- .../modules/contrib/antibot/antibot.install | 5 + .../modules/contrib/antibot/antibot.module | 138 ++++++++++++++---- .../modules/contrib/antibot/antibot.pages.inc | 18 ++- .../modules/contrib/antibot/js/antibot.js | 51 ++++--- .../antibot/templates/antibot-no-js.tpl.php | 16 ++ profiles/wcm_base/modules/contrib/ds/ds.info | 6 +- .../wcm_base/modules/contrib/ds/ds.module | 8 +- .../contrib/ds/modules/ds_devel/ds_devel.info | 6 +- .../ds/modules/ds_extras/ds_extras.info | 6 +- .../ds/modules/ds_format/ds_format.info | 6 +- .../contrib/ds/modules/ds_forms/ds_forms.info | 6 +- .../ds/modules/ds_search/ds_search.info | 6 +- .../contrib/ds/modules/ds_ui/ds_ui.info | 6 +- .../ds_exportables_test.info | 6 +- .../modules/contrib/ds/tests/ds_test.info | 6 +- .../googleanalytics.admin.inc | 35 +++-- .../google_analytics/googleanalytics.info | 7 +- .../google_analytics/googleanalytics.install | 58 +++++--- .../google_analytics/googleanalytics.module | 35 ++++- .../google_analytics/googleanalytics.test | 72 +++++++-- .../google_analytics/googleanalytics.test.js | 10 +- .../modules/contrib/honeypot/README.md | 58 ++++++++ .../modules/contrib/honeypot/README.txt | 43 ------ .../contrib/honeypot/docker-compose.yml | 32 ++++ .../contrib/honeypot/honeypot.admin.inc | 22 ++- .../modules/contrib/honeypot/honeypot.info | 7 +- .../modules/contrib/honeypot/honeypot.install | 4 +- .../modules/contrib/honeypot/honeypot.module | 133 ++++++++++++++++- .../modules/contrib/honeypot/honeypot.test | 55 +++++++ .../modules/contrib/honeypot/js/honeypot.js | 37 +++++ .../contrib/honeypot/tests/honeypot_test.info | 7 +- .../wcm_base/modules/contrib/redis/README.txt | 2 +- .../wcm_base/modules/contrib/redis/redis.info | 6 +- .../modules/contrib/redis/redis.install | 2 +- .../modules/contrib/redis/redis.path.inc | 16 +- .../taxonomy_access_fix.info | 6 +- .../taxonomy_access_fix.module | 13 +- .../actions/book.action.inc | 13 +- .../actions/modify.action.inc | 18 +-- .../actions_permissions.info | 7 +- .../js/views_bulk_operations.js | 35 +++-- .../plugins/operation_types/action.class.php | 7 +- ...lk_operations_handler_field_operations.inc | 1 + .../views_bulk_operations.info | 7 +- .../views_bulk_operations.module | 30 +++- .../views_bulk_operations.rules.inc | 6 +- .../custom/news_client/news_client.module | 3 +- .../custom/news_client/news_client.tokens.inc | 14 +- ...s_handler_field_news_client_image_json.inc | 2 +- .../modules/custom/ocio_news/ocio_news.module | 4 +- .../custom/ocio_taxonomy/ocio_taxonomy.make | 2 +- .../wcm_panels_settings.install | 12 ++ .../custom/wcm_security/wcm_security.make | 4 +- profiles/wcm_base/wcm_base.make | 8 +- 57 files changed, 855 insertions(+), 302 deletions(-) create mode 100644 profiles/wcm_base/modules/contrib/antibot/templates/antibot-no-js.tpl.php create mode 100644 profiles/wcm_base/modules/contrib/honeypot/README.md delete mode 100644 profiles/wcm_base/modules/contrib/honeypot/README.txt create mode 100644 profiles/wcm_base/modules/contrib/honeypot/docker-compose.yml create mode 100644 profiles/wcm_base/modules/contrib/honeypot/js/honeypot.js diff --git a/profiles/wcm_base/CHANGELOG.txt b/profiles/wcm_base/CHANGELOG.txt index 15044bb9..6a48cd15 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 62aba615..45ccc4a6 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 022d7742..80107917 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 9f73a9bc..40a52f9a 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 b09da089..81baf985 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 ad2163fa..85b08648 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 6cfb0fde..bb1eed44 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 00000000..3d1e0b85 --- /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 97e4edb0..6ce9b321 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 e3c20572..d5af8a4a 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 35066a0b..2a28e104 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 c5fc287b..663c4269 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 3d1de7fe..92db5bb6 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 7f26da2a..d6808778 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 bc85846c..5cfb2e92 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 0a52303a..c8dad2c8 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 fcbfa514..dbd678f9 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 d7db78e4..021d44a1 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 d32939a3..20abb5c3 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 2b814605..9232102f 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 a4f4e83a..12f1c55e 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 b45ee103..275262be 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 745047a8..3db117fe 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 05c720fb..b3893501 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 00000000..91f9a4e8 --- /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 bc5fb1bb..00000000 --- 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 00000000..1c8b6bb8 --- /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 64e3ae42..84bb7e2c 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 857d242e..6ce86d53 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 5a560525..c17b4cb4 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 46f83ae6..e8137966 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 dd136b93..aab7f6e0 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 00000000..63acffd7 --- /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 7b0226ad..89aa78bc 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 3314cc37..37357eb3 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 a3ca4afe..931f282b 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 79188871..b3e60670 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 a53017df..73ffa091 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 587e84be..eaf1389c 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 36d27f11..763de11c 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 ad8fa9c4..4621dcd1 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 06fa46dc..e46268d1 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 11ff5235..1f97bd51 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 a4e8237a..62218bed 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 f3e60a30..0be5785a 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 dcfd5342..9b1f88ec 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 b16bf0e0..058bef7a 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 9b17c444..081e5407 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 1273552e..78fae206 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 5cd7c926..b6749760 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 e65700e1..0288fa7e 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 9cadaf63..479c7169 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 65dd177c..cd64ec2b 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 92b16922..e2a59c98 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 40c57149..92b6ad2a 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 ec50037c..62b95db9 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 a6d6a674..bdb15e38 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 -- GitLab