From f6f7fd575f45e6b95eae1180539c38bb8f2e017e Mon Sep 17 00:00:00 2001 From: Bachir Soussi Chiadmi Date: Tue, 25 Oct 2016 16:23:00 +0200 Subject: [PATCH] security updates of unpatched modules --- .../contrib/admin/google_analytics/README.txt | 59 +- .../googleanalytics.admin.inc | 46 +- .../google_analytics/googleanalytics.admin.js | 9 + .../google_analytics/googleanalytics.debug.js | 64 +- .../google_analytics/googleanalytics.info | 6 +- .../google_analytics/googleanalytics.install | 9 +- .../admin/google_analytics/googleanalytics.js | 58 +- .../google_analytics/googleanalytics.module | 36 +- .../google_analytics/googleanalytics.test | 62 +- .../googleanalytics.variable.inc | 4 + .../modules/contrib/dev/elysia_cron/API.txt | 15 +- .../contrib/dev/elysia_cron/INSTALL.txt | 17 +- .../contrib/dev/elysia_cron/README.txt | 121 +- .../modules/contrib/dev/elysia_cron/cron.php | 14 +- ...on-multilingual-image-path-2096571-1.patch | 13 - .../dev/elysia_cron/elysia_cron.admin.inc | 524 +++-- .../dev/elysia_cron/elysia_cron.api.php | 134 ++ .../dev/elysia_cron/elysia_cron.ctools.inc | 229 ++- .../dev/elysia_cron/elysia_cron.drush.inc | 170 +- .../contrib/dev/elysia_cron/elysia_cron.info | 10 +- .../dev/elysia_cron/elysia_cron.install | 117 +- .../dev/elysia_cron/elysia_cron.module | 1770 ++++++++++------- .../dev/elysia_cron/elysia_cron_scheduler.inc | 372 +++- .../elysia_cron/elysia_cron_scheduler_old.inc | 230 --- .../dev/elysia_cron/elysia_cron_update.php | 327 --- .../dev/elysia_cron/elysia_drupalconv.php | 86 - .../modules/contrib/flag/flag/flag.api.php | 58 +- .../modules/contrib/flag/flag/flag.flag.inc | 2 +- sites/all/modules/contrib/flag/flag/flag.info | 6 +- .../modules/contrib/flag/flag/flag.install | 46 +- .../all/modules/contrib/flag/flag/flag.module | 162 +- .../modules/contrib/flag/flag/flag.tokens.inc | 9 +- .../contrib/flag/flag/flag_actions.info | 8 +- .../contrib/flag/flag/flag_actions.module | 28 +- .../flag/flag_bookmark/flag_bookmark.info | 7 +- .../includes/flag_bookmark.views.inc | 21 + .../includes/flag_bookmark.views_default.inc | 7 +- .../flag_bookmark_plugin_validate_user.inc | 89 + .../flag/flag/includes/flag.actions.inc | 2 +- .../contrib/flag/flag/includes/flag.admin.inc | 17 +- .../flag/flag/includes/flag.export.inc | 6 +- .../flag/flag/includes/flag.features.inc | 2 +- .../contrib/flag/flag/includes/flag.pages.inc | 6 +- .../flag/flag/includes/flag/flag_comment.inc | 80 + .../flag/flag/includes/flag/flag_flag.inc | 104 +- .../flag/flag/includes/flag/flag_node.inc | 4 +- .../flag/flag/includes/views/flag.views.inc | 21 + .../views/flag_handler_argument_entity_id.inc | 2 +- .../modules/contrib/flag/flag/tests/flag.test | 130 +- .../flag_comment_flag_test.info | 13 + .../flag_comment_flag_test.module | 41 + .../flag_fields_test/flag_fields_test.info | 6 +- .../tests/flag_hook_test/flag_hook_test.info | 6 +- .../flag_hook_test/flag_hook_test.module | 4 +- .../tests/flagaccesstest/flagaccesstest.info | 6 +- .../webform/includes/webform.submissions.inc | 41 +- .../modules/contrib/form/webform/webform.info | 6 +- .../contrib/form/webform/webform.module | 16 +- .../modules/contrib/panels/panels/README.txt | 7 +- .../modules/contrib/panels/panels/UPGRADE.txt | 12 +- .../contrib/panels/panels/css/panels.css | 5 - .../contrib/panels/panels/css/panels_dnd.css | 16 +- .../panels/panels/help/plugins-layout.html | 2 +- .../panels/i18n_panels/i18n_panels.info | 6 +- .../panels/panels/includes/add-content.inc | 2 + .../contrib/panels/panels/includes/common.inc | 40 +- .../panels/panels/includes/display-edit.inc | 4 +- .../panels/panels/includes/display-layout.inc | 2 + .../panels/panels/includes/plugins.inc | 27 +- .../contrib/panels/panels/js/panels-base.js | 39 + .../modules/contrib/panels/panels/panels.info | 17 +- .../contrib/panels/panels/panels.install | 199 +- .../contrib/panels/panels/panels.module | 122 +- .../panels/panels/panels_ipe/js/panels_ipe.js | 24 +- .../panels/panels_ipe/panels_ipe.api.php | 31 + .../panels/panels/panels_ipe/panels_ipe.info | 7 +- .../panels/panels_ipe/panels_ipe.module | 7 +- .../panels_renderer_ipe.class.php | 73 +- .../panels/panels_mini/panels_mini.info | 7 +- .../panels/panels_mini/panels_mini.install | 60 +- .../panels/panels_mini/panels_mini.module | 91 +- .../plugins/content_types/panels_mini.inc | 11 +- .../plugins/panels_storage/panels_mini.inc | 22 + .../panels/panels_node/panels_node.info | 7 +- .../panels/panels_node/panels_node.install | 96 + .../panels/panels_node/panels_node.module | 76 +- .../plugins/panels_storage/panels_node.inc | 25 + .../panels_renderer_editor.class.php | 50 +- .../panels_renderer_standard.class.php | 46 +- .../plugins/page_wizards/landing_page.inc | 5 + .../plugins/panels_storage/page_manager.inc | 19 + .../panels/panels/plugins/styles/stylizer.inc | 8 +- .../plugins/task_handlers/panel_context.inc | 57 +- .../panels-add-content-modal.tpl.php | 6 + .../tests/PanelsEntityViewWebTestCase.test | 103 + .../tests/PanelsNodeViewWebTestCase.test | 31 + .../tests/PanelsTermViewWebTestCase.test | 31 + .../tests/PanelsUserViewWebTestCase.test | 31 + .../contrib/search/search_api/CHANGELOG.txt | 51 +- .../plugins/facetapi/adapter.inc | 13 +- .../plugins/facetapi/query_type_date.inc | 72 +- .../plugins/facetapi/query_type_term.inc | 27 +- .../search_api_facetapi.info | 6 +- .../search_api_facetapi.install | 32 +- .../search_api_facetapi.module | 79 +- .../includes/display_facet_block.inc | 25 + .../includes/handler_filter_entity.inc | 11 - .../includes/handler_filter_taxonomy_term.inc | 46 +- .../search_api_views/includes/query.inc | 12 +- .../search_api_views/search_api_views.info | 6 +- .../includes/callback_bundle_filter.inc | 7 +- .../search_api/includes/datasource_entity.inc | 11 +- .../search_api/includes/index_entity.inc | 4 +- .../includes/processor_highlight.inc | 16 +- .../includes/processor_html_filter.inc | 4 +- .../search/search_api/includes/query.inc | 11 +- .../search/search_api/search_api.admin.inc | 7 - .../contrib/search/search_api/search_api.info | 8 +- .../search/search_api/search_api.module | 118 +- .../contrib/search/search_api/search_api.test | 4 +- .../search_api/tests/search_api_test.info | 6 +- .../views/views_data_export/.gitignore | 1 - ...iews_data_export_plugin_display_export.inc | 73 +- .../views_data_export_plugin_style_export.inc | 15 +- ...ws_data_export_plugin_style_export_csv.inc | 16 + .../views/views_data_export/tests/access.test | 208 ++ .../views/views_data_export/tests/base.test | 6 +- .../views_data_export/tests/csv_export.test | 74 + .../tests/garbagecollection.test | 187 ++ .../theme/views_data_export.theme.inc | 42 +- .../views_data_export.drush.inc | 18 +- .../views_data_export/views_data_export.info | 8 +- .../views_data_export.module | 66 +- 133 files changed, 5598 insertions(+), 2574 deletions(-) delete mode 100644 sites/all/modules/contrib/dev/elysia_cron/elysia_cron-multilingual-image-path-2096571-1.patch create mode 100644 sites/all/modules/contrib/dev/elysia_cron/elysia_cron.api.php delete mode 100644 sites/all/modules/contrib/dev/elysia_cron/elysia_cron_scheduler_old.inc delete mode 100644 sites/all/modules/contrib/dev/elysia_cron/elysia_cron_update.php delete mode 100644 sites/all/modules/contrib/dev/elysia_cron/elysia_drupalconv.php create mode 100644 sites/all/modules/contrib/flag/flag/flag_bookmark/includes/flag_bookmark.views.inc create mode 100644 sites/all/modules/contrib/flag/flag/flag_bookmark/plugins/flag_bookmark_plugin_validate_user.inc create mode 100644 sites/all/modules/contrib/flag/flag/tests/flag_comment_flag_test/flag_comment_flag_test.info create mode 100644 sites/all/modules/contrib/flag/flag/tests/flag_comment_flag_test/flag_comment_flag_test.module create mode 100644 sites/all/modules/contrib/panels/panels/panels_ipe/panels_ipe.api.php create mode 100644 sites/all/modules/contrib/panels/panels/panels_mini/plugins/panels_storage/panels_mini.inc create mode 100644 sites/all/modules/contrib/panels/panels/panels_node/plugins/panels_storage/panels_node.inc create mode 100644 sites/all/modules/contrib/panels/panels/plugins/panels_storage/page_manager.inc create mode 100644 sites/all/modules/contrib/panels/panels/tests/PanelsEntityViewWebTestCase.test create mode 100644 sites/all/modules/contrib/panels/panels/tests/PanelsNodeViewWebTestCase.test create mode 100644 sites/all/modules/contrib/panels/panels/tests/PanelsTermViewWebTestCase.test create mode 100644 sites/all/modules/contrib/panels/panels/tests/PanelsUserViewWebTestCase.test delete mode 100644 sites/all/modules/contrib/views/views_data_export/.gitignore create mode 100644 sites/all/modules/contrib/views/views_data_export/tests/access.test create mode 100644 sites/all/modules/contrib/views/views_data_export/tests/garbagecollection.test diff --git a/sites/all/modules/contrib/admin/google_analytics/README.txt b/sites/all/modules/contrib/admin/google_analytics/README.txt index fab2f2ec..25fd22aa 100644 --- a/sites/all/modules/contrib/admin/google_analytics/README.txt +++ b/sites/all/modules/contrib/admin/google_analytics/README.txt @@ -12,12 +12,20 @@ Requirements * Google Analytics user account - Installation ============ Copy the 'googleanalytics' module directory in to your Drupal sites/all/modules directory as usual. +Upgrading from 6.x-3.x and 7.x-1.x +================================== +If you upgrade from 6.x-3.x and 7.x-1.x (ga.js) to 7.x-2.x (analytics.js) you +should verify if you used custom variables. Write down your settings or make a +screenshot. You need to re-configure the settings to use custom dimensions or +metrics. There is no automatic upgrade path for custom variables feature. All +other module settings are upgraded automatically. + +See https://support.google.com/analytics/answer/2795983?hl=en for more details. Usage ===== @@ -27,12 +35,8 @@ All pages will now have the required JavaScript added to the HTML footer can confirm this by viewing the page source from your browser. -New approach to page tracking in 5.x-1.5 and 6.x-1.1 -==================================================== -With 5.x-1.5 and 6.x-1.1 there are new settings on the settings page at -admin/config/system/googleanalytics. The "Page specific tracking" area now -comes with an interface that copies Drupal's block visibility settings. - +Page specific tracking +====================== The default is set to "Add to every page except the listed pages". By default the following pages are listed for exclusion: @@ -44,23 +48,24 @@ node/*/* user/*/* These defaults are changeable by the website administrator or any other -user with 'administer google analytics' permission. +user with 'Administer Google Analytics' permission. -Like the blocks visibility settings in Drupal core, there is now a -choice for "Add if the following PHP code returns TRUE." Sample PHP snippets -that can be used in this textarea can be found on the handbook page -"Overview-approach to block visibility" at http://drupal.org/node/64135. +Like the blocks visibility settings in Drupal core, there is a choice for +"Add if the following PHP code returns TRUE." Sample PHP snippets that can be +used in this textarea can be found on the handbook page "Overview-approach to +block visibility" at http://drupal.org/node/64135. Custom dimensions and metrics ============================= One example for custom dimensions tracking is the "User roles" tracking. -1. In the Google Analytics Management Interface you need to setup Dimension #1 - with name e.g. "User roles". This step is required. Do not miss it, please. +1. In the Google Analytics Management Interface (http://www.google.com/analytics/) + you need to setup Dimension #1 with name e.g. "User roles". This step is + required. Do not miss it, please. -2. Enter the below configuration data into the custom dimensions settings form - under admin/config/system/googleanalytics. You can also choose another index, - but keep it always in sync with the index used in step #1. +2. Enter the below configuration data into the Drupal custom dimensions settings + form under admin/config/system/googleanalytics. You can also choose another + index, but keep it always in sync with the index used in step #1. Index: 1 Value: [current-user:role-names] @@ -77,3 +82,23 @@ provided for any customisations you include. To speed up page loading you may also cache the Google Analytics "analytics.js" file locally. + +Manual JS debugging +=================== +For manual debugging of the JS code you are able to create a test node. This +is the example HTML code for this test node. You need to enable debugging mode +in your Drupal configuration of Google Analytics settings to see verbose +messages in your browsers JS console. + +Title: Google Analytics test page + +Body: + + +Text format: Full HTML diff --git a/sites/all/modules/contrib/admin/google_analytics/googleanalytics.admin.inc b/sites/all/modules/contrib/admin/google_analytics/googleanalytics.admin.inc index 4449077d..d32939a3 100644 --- a/sites/all/modules/contrib/admin/google_analytics/googleanalytics.admin.inc +++ b/sites/all/modules/contrib/admin/google_analytics/googleanalytics.admin.inc @@ -224,6 +224,18 @@ function googleanalytics_admin_settings_form($form_state) { ), ), ); + + $colorbox_dependencies = '
'; + $colorbox_dependencies .= t('Requires: !module-list', array('!module-list' => (module_exists('colorbox') ? t('@module (enabled)', array('@module' => 'Colorbox')) : t('@module (disabled)', array('@module' => 'Colorbox'))))); + $colorbox_dependencies .= '
'; + + $form['tracking']['linktracking']['googleanalytics_trackcolorbox'] = array( + '#type' => 'checkbox', + '#title' => t('Track content in colorbox modal dialogs'), + '#default_value' => variable_get('googleanalytics_trackcolorbox', 1), + '#description' => t('Enable to track the content shown in colorbox modal windows.') . $colorbox_dependencies, + '#disabled' => (module_exists('colorbox') ? FALSE : TRUE), + ); $form['tracking']['linktracking']['googleanalytics_tracklinkid'] = array( '#type' => 'checkbox', '#title' => t('Track enhanced link attribution'), @@ -246,7 +258,7 @@ function googleanalytics_admin_settings_form($form_state) { '#type' => 'checkboxes', '#title' => t('Track messages of type'), '#default_value' => variable_get('googleanalytics_trackmessages', array()), - '#description' => t('This will track the selected message types shown to users. Tracking of form validation errors may help you identifying usability issues in your site. For each visit (user session), a maximum of approximately 500 combined GATC requests (both events and page views) can be tracked. Every message is tracked as one individual event. Note that - as the number of events in a session approaches the limit - additional events might not be tracked. Messages from excluded pages cannot tracked.'), + '#description' => t('This will track the selected message types shown to users. Tracking of form validation errors may help you identifying usability issues in your site. For each visit (user session), a maximum of approximately 500 combined GATC requests (both events and page views) can be tracked. Every message is tracked as one individual event. Note that - as the number of events in a session approaches the limit - additional events might not be tracked. Messages from excluded pages cannot be tracked.'), '#options' => array( 'status' => t('Status message'), 'warning' => t('Warning message'), @@ -305,7 +317,7 @@ function googleanalytics_admin_settings_form($form_state) { $form['googleanalytics_custom_dimension'] = array( '#collapsed' => TRUE, '#collapsible' => TRUE, - '#description' => t('You can set values for Google Analytics Custom Dimensions here. You must have already configured your custom dimensions in the Google Analytics Management Interface. You may use tokens. Global and user tokens are always available; on node pages, node tokens are also available. A dimension value is allowed to have a maximum lenght of 150 bytes. Expect longer values to get trimmed.', array('@custom_var_documentation' => 'https://developers.google.com/analytics/devguides/collection/analyticsjs/custom-dims-mets', '@setup_documentation' => 'https://support.google.com/analytics/answer/2709829')), + '#description' => t('You can set values for Google Analytics Custom Dimensions here. You must have already configured your custom dimensions in the Google Analytics Management Interface. You may use tokens. Global and user tokens are always available; on node pages, node tokens are also available. A dimension value is allowed to have a maximum length of 150 bytes. Expect longer values to get trimmed.', array('@custom_var_documentation' => 'https://developers.google.com/analytics/devguides/collection/analyticsjs/custom-dims-mets', '@setup_documentation' => 'https://support.google.com/analytics/answer/2709829')), '#theme' => 'googleanalytics_admin_custom_var_table', '#title' => t('Custom dimensions'), '#tree' => TRUE, @@ -428,6 +440,8 @@ function googleanalytics_admin_settings_form($form_state) { ); } + $user_access_add_js_snippets = !user_access('add JS snippets for google analytics'); + $user_access_add_js_snippets_permission_warning = $user_access_add_js_snippets ? ' ' . t('This field has been disabled because you do not have sufficient permissions to edit it.') . '' : ''; $form['advanced']['codesnippet'] = array( '#type' => 'fieldset', '#title' => t('Custom JavaScript code'), @@ -447,15 +461,17 @@ function googleanalytics_admin_settings_form($form_state) { '#type' => 'textarea', '#title' => t('Code snippet (before)'), '#default_value' => variable_get('googleanalytics_codesnippet_before', ''), + '#disabled' => $user_access_add_js_snippets, '#rows' => 5, - '#description' => t('Code in this textarea will be added before ga("send", "pageview");.'), + '#description' => t('Code in this textarea will be added before ga("send", "pageview");.') . $user_access_add_js_snippets_permission_warning, ); $form['advanced']['codesnippet']['googleanalytics_codesnippet_after'] = array( '#type' => 'textarea', '#title' => t('Code snippet (after)'), '#default_value' => variable_get('googleanalytics_codesnippet_after', ''), + '#disabled' => $user_access_add_js_snippets, '#rows' => 5, - '#description' => t('Code in this textarea will be added after ga("send", "pageview");. This is useful if you\'d like to track a site in two accounts.'), + '#description' => t('Code in this textarea will be added after ga("send", "pageview");. This is useful if you\'d like to track a site in two accounts.') . $user_access_add_js_snippets_permission_warning, ); $form['advanced']['googleanalytics_debug'] = array( @@ -541,6 +557,12 @@ function googleanalytics_admin_settings_form_validate($form, &$form_state) { /** * Layout for the custom variables table in the admin settings form. + * + * @param array $variables + * An array contains the form elements. + * + * @return string + * The rendered output. */ function theme_googleanalytics_admin_custom_var_table($variables) { $form = $variables['form']; @@ -551,7 +573,7 @@ function theme_googleanalytics_admin_custom_var_table($variables) { ); $rows = array(); - foreach (element_children($form['indexes']) as $key => $id) { + foreach (element_children($form['indexes']) as $id) { $rows[] = array( 'data' => array( drupal_render($form['indexes'][$id]['index']), @@ -600,11 +622,18 @@ function googleanalytics_token_element_validate(&$element, &$form_state) { return $element; } +/** + * @param array $value + * An array of token values. + * + * @return array + * A unique array of invalid tokens. + */ function _googleanalytics_get_forbidden_tokens($value) { $invalid_tokens = array(); $value_tokens = is_string($value) ? token_scan($value) : $value; - foreach ($value_tokens as $type => $tokens) { + foreach ($value_tokens as $tokens) { if (array_filter($tokens, '_googleanalytics_contains_forbidden_token')) { $invalid_tokens = array_merge($invalid_tokens, array_values($tokens)); } @@ -617,8 +646,9 @@ function _googleanalytics_get_forbidden_tokens($value) { /** * Validate if a string contains forbidden tokens not allowed by privacy rules. * - * @param $token_string + * @param string $token_string * A string with one or more tokens to be validated. + * * @return boolean * TRUE if blacklisted token has been found, otherwise FALSE. */ @@ -724,7 +754,7 @@ function _googleanalytics_extract_create_field_values($string) { $list = array_map('trim', $list); $list = array_filter($list, 'strlen'); - foreach ($list as $position => $text) { + foreach ($list as $text) { // Check for an explicit key. $matches = array(); if (preg_match('/(.*)\|(.*)/', $text, $matches)) { diff --git a/sites/all/modules/contrib/admin/google_analytics/googleanalytics.admin.js b/sites/all/modules/contrib/admin/google_analytics/googleanalytics.admin.js index 083eeaa3..c81470d7 100644 --- a/sites/all/modules/contrib/admin/google_analytics/googleanalytics.admin.js +++ b/sites/all/modules/contrib/admin/google_analytics/googleanalytics.admin.js @@ -65,6 +65,15 @@ Drupal.behaviors.trackingSettingsSummary = { if ($('input#edit-googleanalytics-trackfiles', context).is(':checked')) { vals.push(Drupal.t('Downloads')); } + if ($('input#edit-googleanalytics-trackcolorbox', context).is(':checked')) { + vals.push(Drupal.t('Colorbox')); + } + if ($('input#edit-googleanalytics-tracklinkid', context).is(':checked')) { + vals.push(Drupal.t('Link attribution')); + } + if ($('input#edit-googleanalytics-trackurlfragments', context).is(':checked')) { + vals.push(Drupal.t('URL fragments')); + } if (!vals.length) { return Drupal.t('Not tracked'); } diff --git a/sites/all/modules/contrib/admin/google_analytics/googleanalytics.debug.js b/sites/all/modules/contrib/admin/google_analytics/googleanalytics.debug.js index 861f7fdb..a0be81ae 100644 --- a/sites/all/modules/contrib/admin/google_analytics/googleanalytics.debug.js +++ b/sites/all/modules/contrib/admin/google_analytics/googleanalytics.debug.js @@ -8,16 +8,16 @@ $(document).ready(function() { // clicks on all elements. $(document.body).bind("mousedown keyup touchstart", function(event) { console.group("Running Google Analytics for Drupal."); - console.info(event); + console.info("Event '%s' has been detected.", event.type); // Catch the closest surrounding link of a clicked element. $(event.target).closest("a,area").each(function() { - console.info("Element '%o' has been detected. Link '%s' found.", this, this.href); + console.info("Closest element '%o' has been found. URL '%s' extracted.", this, this.href); // Is the clicked URL internal? if (Drupal.googleanalytics.isInternal(this.href)) { // Skip 'click' tracking, if custom tracking events are bound. - if ($(this).is('.colorbox')) { + if ($(this).is('.colorbox') && (Drupal.settings.googleanalytics.trackColorbox)) { // Do nothing here. The custom event will handle all tracking. console.info("Click on .colorbox item has been detected."); } @@ -25,12 +25,22 @@ $(document).ready(function() { else if (Drupal.settings.googleanalytics.trackDownload && Drupal.googleanalytics.isDownload(this.href)) { // Download link clicked. console.info("Download url '%s' has been found. Tracked download as extension '%s'.", Drupal.googleanalytics.getPageUrl(this.href), Drupal.googleanalytics.getDownloadExtension(this.href).toUpperCase()); - ga("send", "event", "Downloads", Drupal.googleanalytics.getDownloadExtension(this.href).toUpperCase(), Drupal.googleanalytics.getPageUrl(this.href)); + ga("send", { + "hitType": "event", + "eventCategory": "Downloads", + "eventAction": Drupal.googleanalytics.getDownloadExtension(this.href).toUpperCase(), + "eventLabel": Drupal.googleanalytics.getPageUrl(this.href), + "transport": "beacon" + }); } else if (Drupal.googleanalytics.isInternalSpecial(this.href)) { // Keep the internal URL for Google Analytics website overlay intact. console.info("Click on internal special link '%s' has been tracked.", Drupal.googleanalytics.getPageUrl(this.href)); - ga("send", "pageview", { "page": Drupal.googleanalytics.getPageUrl(this.href) }); + ga("send", { + "hitType": "pageview", + "page": Drupal.googleanalytics.getPageUrl(this.href), + "transport": "beacon" + }); } else { // e.g. anchor in same page or other internal page link @@ -41,13 +51,25 @@ $(document).ready(function() { if (Drupal.settings.googleanalytics.trackMailto && $(this).is("a[href^='mailto:'],area[href^='mailto:']")) { // Mailto link clicked. console.info("Click on e-mail '%s' has been tracked.", this.href.substring(7)); - ga("send", "event", "Mails", "Click", this.href.substring(7)); + ga("send", { + "hitType": "event", + "eventCategory": "Mails", + "eventAction": "Click", + "eventLabel": this.href.substring(7), + "transport": "beacon" + }); } else if (Drupal.settings.googleanalytics.trackOutbound && this.href.match(/^\w+:\/\//i)) { - if (Drupal.settings.googleanalytics.trackDomainMode != 2 || (Drupal.settings.googleanalytics.trackDomainMode == 2 && !Drupal.googleanalytics.isCrossDomain(this.hostname, Drupal.settings.googleanalytics.trackCrossDomains))) { + if (Drupal.settings.googleanalytics.trackDomainMode !== 2 || (Drupal.settings.googleanalytics.trackDomainMode === 2 && !Drupal.googleanalytics.isCrossDomain(this.hostname, Drupal.settings.googleanalytics.trackCrossDomains))) { // External link clicked / No top-level cross domain clicked. console.info("Outbound link '%s' has been tracked.", this.href); - ga("send", "event", "Outbound links", "Click", this.href); + ga("send", { + "hitType": "event", + "eventCategory": "Outbound links", + "eventAction": "Click", + "eventLabel": this.href, + "transport": "beacon" + }); } else { console.info("Internal link '%s' clicked, not tracked.", this.href); @@ -63,19 +85,27 @@ $(document).ready(function() { if (Drupal.settings.googleanalytics.trackUrlFragments) { window.onhashchange = function() { console.info("Track URL '%s' as pageview. Hash '%s' has changed.", location.pathname + location.search + location.hash, location.hash); - ga('send', 'pageview', location.pathname + location.search + location.hash); - } + ga("send", { + "hitType": "pageview", + "page": location.pathname + location.search + location.hash + }); + }; } // Colorbox: This event triggers when the transition has completed and the // newly loaded content has been revealed. - $(document).bind("cbox_complete", function () { - var href = $.colorbox.element().attr("href"); - if (href) { - console.info("Colorbox transition to url '%s' has been tracked.", Drupal.googleanalytics.getPageUrl(href)); - ga("send", "pageview", { "page": Drupal.googleanalytics.getPageUrl(href) }); - } - }); + if (Drupal.settings.googleanalytics.trackColorbox) { + $(document).bind("cbox_complete", function () { + var href = $.colorbox.element().attr("href"); + if (href) { + console.info("Colorbox transition to url '%s' has been tracked.", Drupal.googleanalytics.getPageUrl(href)); + ga("send", { + "hitType": "pageview", + "page": Drupal.googleanalytics.getPageUrl(href) + }); + } + }); + } }); diff --git a/sites/all/modules/contrib/admin/google_analytics/googleanalytics.info b/sites/all/modules/contrib/admin/google_analytics/googleanalytics.info index adbf134a..2b814605 100644 --- a/sites/all/modules/contrib/admin/google_analytics/googleanalytics.info +++ b/sites/all/modules/contrib/admin/google_analytics/googleanalytics.info @@ -5,9 +5,9 @@ package = Statistics configure = admin/config/system/googleanalytics files[] = googleanalytics.test test_dependencies[] = token -; Information added by Drupal.org packaging script on 2014-11-29 -version = "7.x-2.1" +; Information added by Drupal.org packaging script on 2016-08-09 +version = "7.x-2.3" core = "7.x" project = "google_analytics" -datestamp = "1417276982" +datestamp = "1470779953" diff --git a/sites/all/modules/contrib/admin/google_analytics/googleanalytics.install b/sites/all/modules/contrib/admin/google_analytics/googleanalytics.install index d7b2edfb..a4f4e83a 100644 --- a/sites/all/modules/contrib/admin/google_analytics/googleanalytics.install +++ b/sites/all/modules/contrib/admin/google_analytics/googleanalytics.install @@ -25,6 +25,7 @@ function googleanalytics_uninstall() { variable_del('googleanalytics_roles'); variable_del('googleanalytics_site_search'); variable_del('googleanalytics_trackadsense'); + variable_del('googleanalytics_trackcolorbox'); variable_del('googleanalytics_trackdoubleclick'); variable_del('googleanalytics_tracker_anonymizeip'); variable_del('googleanalytics_trackfiles'); @@ -446,16 +447,16 @@ function googleanalytics_update_7200() { if (!empty($googleanalytics_codesnippet_before) && stristr($googleanalytics_codesnippet_before, '_gaq.push(')) { variable_set('googleanalytics_codesnippet_before_backup_7200', $googleanalytics_codesnippet_before); variable_del('googleanalytics_codesnippet_before'); - drupal_set_message(Database::getConnection()->prefixTables("A backup of your previous Google Analytics code snippet has been saved in database table '{variable}' as 'googleanalytics_codesnippet_before_backup_7200'. You need to manually upgrade the custom 'before' code snippet."), 'warning'); - $messages[] = t('Manual upgrade of custom "before" code snippet is required.'); + drupal_set_message(Database::getConnection()->prefixTables("A backup of your previous Google Analytics code snippet (ga.js) has been saved in database table '{variable}' as 'googleanalytics_codesnippet_before_backup_7200'. You need to manually upgrade the custom 'before' code snippet to analytics.js API."), 'warning'); + $messages[] = t('Manual upgrade of custom "before" code snippet from ja.js to analytics.js API is required.'); } $googleanalytics_codesnippet_after = variable_get('googleanalytics_codesnippet_after', ''); if (!empty($googleanalytics_codesnippet_after) && stristr($googleanalytics_codesnippet_after, '_gaq.push(')) { variable_set('googleanalytics_codesnippet_after_backup_7200', $googleanalytics_codesnippet_after); variable_del('googleanalytics_codesnippet_after'); - drupal_set_message(Database::getConnection()->prefixTables("A backup of your previous Google Analytics code snippet has been saved in database table '{variable}' as 'googleanalytics_codesnippet_before_backup_7200'. You need to manually upgrade the custom 'before' code snippet."), 'warning'); - $messages[] = t('Manual upgrade of custom "after" code snippet is required.'); + drupal_set_message(Database::getConnection()->prefixTables("A backup of your previous Google Analytics code snippet (ga.js) has been saved in database table '{variable}' as 'googleanalytics_codesnippet_after_backup_7200'. You need to manually upgrade the custom 'after' code snippet to analytics.js API."), 'warning'); + $messages[] = t('Manual upgrade of custom "after" code snippet from ja.js to analytics.js API is required.'); } return empty($messages) ? t('No custom code snipped found. Nothing to do.') : implode(' ', $messages); diff --git a/sites/all/modules/contrib/admin/google_analytics/googleanalytics.js b/sites/all/modules/contrib/admin/google_analytics/googleanalytics.js index 1eed3c32..8d5bde1b 100644 --- a/sites/all/modules/contrib/admin/google_analytics/googleanalytics.js +++ b/sites/all/modules/contrib/admin/google_analytics/googleanalytics.js @@ -14,29 +14,51 @@ $(document).ready(function() { // Is the clicked URL internal? if (Drupal.googleanalytics.isInternal(this.href)) { // Skip 'click' tracking, if custom tracking events are bound. - if ($(this).is('.colorbox')) { + if ($(this).is('.colorbox') && (Drupal.settings.googleanalytics.trackColorbox)) { // Do nothing here. The custom event will handle all tracking. //console.info("Click on .colorbox item has been detected."); } // Is download tracking activated and the file extension configured for download tracking? else if (Drupal.settings.googleanalytics.trackDownload && Drupal.googleanalytics.isDownload(this.href)) { // Download link clicked. - ga("send", "event", "Downloads", Drupal.googleanalytics.getDownloadExtension(this.href).toUpperCase(), Drupal.googleanalytics.getPageUrl(this.href)); + ga("send", { + "hitType": "event", + "eventCategory": "Downloads", + "eventAction": Drupal.googleanalytics.getDownloadExtension(this.href).toUpperCase(), + "eventLabel": Drupal.googleanalytics.getPageUrl(this.href), + "transport": "beacon" + }); } else if (Drupal.googleanalytics.isInternalSpecial(this.href)) { // Keep the internal URL for Google Analytics website overlay intact. - ga("send", "pageview", { "page": Drupal.googleanalytics.getPageUrl(this.href) }); + ga("send", { + "hitType": "pageview", + "page": Drupal.googleanalytics.getPageUrl(this.href), + "transport": "beacon" + }); } } else { if (Drupal.settings.googleanalytics.trackMailto && $(this).is("a[href^='mailto:'],area[href^='mailto:']")) { // Mailto link clicked. - ga("send", "event", "Mails", "Click", this.href.substring(7)); + ga("send", { + "hitType": "event", + "eventCategory": "Mails", + "eventAction": "Click", + "eventLabel": this.href.substring(7), + "transport": "beacon" + }); } else if (Drupal.settings.googleanalytics.trackOutbound && this.href.match(/^\w+:\/\//i)) { - if (Drupal.settings.googleanalytics.trackDomainMode != 2 || (Drupal.settings.googleanalytics.trackDomainMode == 2 && !Drupal.googleanalytics.isCrossDomain(this.hostname, Drupal.settings.googleanalytics.trackCrossDomains))) { + if (Drupal.settings.googleanalytics.trackDomainMode !== 2 || (Drupal.settings.googleanalytics.trackDomainMode === 2 && !Drupal.googleanalytics.isCrossDomain(this.hostname, Drupal.settings.googleanalytics.trackCrossDomains))) { // External link clicked / No top-level cross domain clicked. - ga("send", "event", "Outbound links", "Click", this.href); + ga("send", { + "hitType": "event", + "eventCategory": "Outbound links", + "eventAction": "Click", + "eventLabel": this.href, + "transport": "beacon" + }); } } } @@ -46,18 +68,26 @@ $(document).ready(function() { // Track hash changes as unique pageviews, if this option has been enabled. if (Drupal.settings.googleanalytics.trackUrlFragments) { window.onhashchange = function() { - ga('send', 'pageview', location.pathname + location.search + location.hash); - } + ga("send", { + "hitType": "pageview", + "page": location.pathname + location.search + location.hash + }); + }; } // Colorbox: This event triggers when the transition has completed and the // newly loaded content has been revealed. - $(document).bind("cbox_complete", function () { - var href = $.colorbox.element().attr("href"); - if (href) { - ga("send", "pageview", { "page": Drupal.googleanalytics.getPageUrl(href) }); - } - }); + if (Drupal.settings.googleanalytics.trackColorbox) { + $(document).bind("cbox_complete", function () { + var href = $.colorbox.element().attr("href"); + if (href) { + ga("send", { + "hitType": "pageview", + "page": Drupal.googleanalytics.getPageUrl(href) + }); + } + }); + } }); diff --git a/sites/all/modules/contrib/admin/google_analytics/googleanalytics.module b/sites/all/modules/contrib/admin/google_analytics/googleanalytics.module index 4051b1b9..b45ee103 100644 --- a/sites/all/modules/contrib/admin/google_analytics/googleanalytics.module +++ b/sites/all/modules/contrib/admin/google_analytics/googleanalytics.module @@ -69,6 +69,11 @@ function googleanalytics_permission() { 'description' => t('Enter PHP code in the field for tracking visibility settings.'), 'restrict access' => TRUE, ), + 'add JS snippets for google analytics' => array( + 'title' => t('Add JavaScript snippets'), + 'description' => 'Enter JavaScript code snippets for advanced Google Analytics functionality.', + 'restrict access' => TRUE, + ), ); } @@ -125,6 +130,9 @@ function googleanalytics_page_alter(&$page) { $link_settings['trackDownload'] = $track_download; $link_settings['trackDownloadExtensions'] = $trackfiles_extensions; } + if (module_exists('colorbox') && ($track_colorbox = variable_get('googleanalytics_trackcolorbox', 1))) { + $link_settings['trackColorbox'] = $track_colorbox; + } if ($track_domain_mode = variable_get('googleanalytics_domain_mode', 0)) { $link_settings['trackDomainMode'] = $track_domain_mode; } @@ -294,10 +302,7 @@ function googleanalytics_page_alter(&$page) { // Track logged in users across all devices. if (variable_get('googleanalytics_trackuserid', 0) && user_is_logged_in()) { - // The USER_ID value should be a unique, persistent, and non-personally - // identifiable string identifier that represents a user or signed-in - // account across devices. - $create_only_fields['userId'] = drupal_hmac_base64($user->uid, drupal_get_private_key() . drupal_get_hash_salt()); + $create_only_fields['userId'] = google_analytics_user_id_hash($user->uid); } // Create a tracker. @@ -352,13 +357,30 @@ function googleanalytics_page_alter(&$page) { // Custom tracking. Prepend before all other JavaScript. // @TODO: https://support.google.com/adsense/answer/98142 // sounds like it could be appended to $script. - drupal_add_js($googleanalytics_adsense_script, array('type' => 'inline', 'group' => JS_LIBRARY-1)); + drupal_add_js($googleanalytics_adsense_script, array('type' => 'inline', 'group' => JS_LIBRARY-1, 'requires_jquery' => FALSE)); } - drupal_add_js($script, array('scope' => 'header', 'type' => 'inline')); + drupal_add_js($script, array('scope' => 'header', 'type' => 'inline', 'requires_jquery' => FALSE)); } } +/** + * Generate user id hash to implement USER_ID. + * + * The USER_ID value should be a unique, persistent, and non-personally + * identifiable string identifier that represents a user or signed-in + * account across devices. + * + * @param int $uid + * User id. + * + * @return string + * User id hash. + */ +function google_analytics_user_id_hash($uid) { + return drupal_hmac_base64($uid, drupal_get_private_key() . drupal_get_hash_salt()); +} + /** * Implements hook_field_extra_fields(). */ @@ -456,7 +478,7 @@ function googleanalytics_preprocess_search_results(&$variables) { // found. But the pager item mumber can tell the number of search results. global $pager_total_items; - drupal_add_js('window.googleanalytics_search_results = ' . intval($pager_total_items[0]) . ';', array('type' => 'inline', 'group' => JS_LIBRARY-1)); + drupal_add_js('window.googleanalytics_search_results = ' . intval($pager_total_items[0]) . ';', array('type' => 'inline', 'group' => JS_LIBRARY-1, 'requires_jquery' => FALSE)); } } diff --git a/sites/all/modules/contrib/admin/google_analytics/googleanalytics.test b/sites/all/modules/contrib/admin/google_analytics/googleanalytics.test index 0b64bb82..745047a8 100644 --- a/sites/all/modules/contrib/admin/google_analytics/googleanalytics.test +++ b/sites/all/modules/contrib/admin/google_analytics/googleanalytics.test @@ -6,6 +6,13 @@ */ class GoogleAnalyticsBasicTest extends DrupalWebTestCase { + /** + * User without permissions to edit snippets. + * + * @var \StdClass + */ + protected $noSnippetUser; + public static function getInfo() { return array( 'name' => 'Google Analytics basic tests', @@ -25,6 +32,8 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase { ); // User to set up google_analytics. + $this->noSnippetUser = $this->drupalCreateUser($permissions); + $permissions[] = 'add JS snippets for google analytics'; $this->admin_user = $this->drupalCreateUser($permissions); $this->drupalLogin($this->admin_user); } @@ -48,6 +57,26 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase { $edit['googleanalytics_account'] = $this->randomName(2); $this->drupalPost('admin/config/system/googleanalytics', $edit, t('Save configuration')); $this->assertRaw(t('A valid Google Analytics Web Property ID is case sensitive and formatted like UA-xxxxxxx-yy.'), '[testGoogleAnalyticsConfiguration]: Invalid Web Property ID number validated.'); + + // User should have access to code snippets. + $this->assertFieldByName('googleanalytics_codesnippet_create'); + $this->assertFieldByName('googleanalytics_codesnippet_before'); + $this->assertFieldByName('googleanalytics_codesnippet_after'); + $this->assertNoFieldByXPath("//textarea[@name='googleanalytics_codesnippet_create' and @disabled='disabled']", NULL, '"Create only fields" is enabled.'); + $this->assertNoFieldByXPath("//textarea[@name='googleanalytics_codesnippet_before' and @disabled='disabled']", NULL, '"Code snippet (before)" is enabled.'); + $this->assertNoFieldByXPath("//textarea[@name='googleanalytics_codesnippet_after' and @disabled='disabled']", NULL, '"Code snippet (after)" is enabled.'); + + // Login as user without JS permissions. + $this->drupalLogin($this->noSnippetUser); + $this->drupalGet('admin/config/system/googleanalytics'); + + // User should *not* have access to snippets, but create fields. + $this->assertFieldByName('googleanalytics_codesnippet_create'); + $this->assertFieldByName('googleanalytics_codesnippet_before'); + $this->assertFieldByName('googleanalytics_codesnippet_after'); + $this->assertNoFieldByXPath("//textarea[@name='googleanalytics_codesnippet_create' and @disabled='disabled']", NULL, '"Create only fields" is enabled.'); + $this->assertFieldByXPath("//textarea[@name='googleanalytics_codesnippet_before' and @disabled='disabled']", NULL, '"Code snippet (before)" is disabled.'); + $this->assertFieldByXPath("//textarea[@name='googleanalytics_codesnippet_after' and @disabled='disabled']", NULL, '"Code snippet (after)" is disabled.'); } function testGoogleAnalyticsPageVisibility() { @@ -284,6 +313,7 @@ class GoogleAnalyticsCustomDimensionsAndMetricsTest extends DrupalWebTestCase { // User to set up google_analytics. $this->admin_user = $this->drupalCreateUser($permissions); + $this->drupalLogin($this->admin_user); } function testGoogleAnalyticsCustomDimensions() { @@ -362,34 +392,30 @@ class GoogleAnalyticsCustomDimensionsAndMetricsTest extends DrupalWebTestCase { 1 => array( 'index' => 1, 'value' => '6', - 'value_expected' => 6, ), 2 => array( 'index' => 2, 'value' => '8000', - 'value_expected' => 8000, ), 3 => array( 'index' => 3, 'value' => '7.8654', - 'value_expected' => 7.8654, ), 4 => array( 'index' => 4, 'value' => '1123.4', - 'value_expected' => 1123.4, ), 5 => array( 'index' => 5, 'value' => '5,67', - 'value_expected' => 5, ), ); + variable_set('googleanalytics_custom_metric', $googleanalytics_custom_metric); $this->drupalGet(''); foreach ($googleanalytics_custom_metric as $metric) { - $this->assertRaw('ga("set", ' . drupal_json_encode('metric' . $metric['index']) . ', ' . drupal_json_encode($metric['value_expected']) . ');', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: Metric #' . $metric['index'] . ' is shown.'); + $this->assertRaw('ga("set", ' . drupal_json_encode('metric' . $metric['index']) . ', ' . drupal_json_encode((float) $metric['value']) . ');', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: Metric #' . $metric['index'] . ' is shown.'); } // Test whether tokens are replaced in custom metric values. @@ -421,6 +447,30 @@ class GoogleAnalyticsCustomDimensionsAndMetricsTest extends DrupalWebTestCase { $this->assertNoRaw('ga("set", ' . drupal_json_encode('metric3') . ', ' . drupal_json_encode('') . ');', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: Empty value is not shown.'); $this->assertRaw('ga("set", ' . drupal_json_encode('metric4') . ', ' . drupal_json_encode(0) . ');', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: Value 0 is shown.'); } + + /** + * Tests if Custom Dimensions token form validation works. + */ + public function testGoogleAnalyticsCustomDimensionsTokenFormValidation() { + $ua_code = 'UA-123456-1'; + + // Check form validation. + $edit['googleanalytics_account'] = $ua_code; + $edit['googleanalytics_custom_dimension[indexes][1][value]'] = '[current-user:name]'; + $edit['googleanalytics_custom_dimension[indexes][2][value]'] = '[current-user:edit-url]'; + $edit['googleanalytics_custom_dimension[indexes][3][value]'] = '[user:name]'; + $edit['googleanalytics_custom_dimension[indexes][4][value]'] = '[term:name]'; + $edit['googleanalytics_custom_dimension[indexes][5][value]'] = '[term:tid]'; + + $this->drupalPost('admin/config/system/googleanalytics', $edit, t('Save configuration')); + + $this->assertRaw(t('The %element-title is using the following forbidden tokens with personal identifying information: @invalid-tokens.', array('%element-title' => t('Custom dimension value #@index', array('@index' => 1)), '@invalid-tokens' => implode(', ', array('[current-user:name]'))))); + $this->assertRaw(t('The %element-title is using the following forbidden tokens with personal identifying information: @invalid-tokens.', array('%element-title' => t('Custom dimension value #@index', array('@index' => 2)), '@invalid-tokens' => implode(', ', array('[current-user:edit-url]'))))); + $this->assertRaw(t('The %element-title is using the following forbidden tokens with personal identifying information: @invalid-tokens.', array('%element-title' => t('Custom dimension value #@index', array('@index' => 3)), '@invalid-tokens' => implode(', ', array('[user:name]'))))); + // BUG #2037595 + //$this->assertNoRaw(t('The %element-title is using the following forbidden tokens with personal identifying information: @invalid-tokens.', array('%element-title' => t('Custom dimension value #@index', array('@index' => 4)), '@invalid-tokens' => implode(', ', array('[term:name]'))))); + //$this->assertNoRaw(t('The %element-title is using the following forbidden tokens with personal identifying information: @invalid-tokens.', array('%element-title' => t('Custom dimension value #@index', array('@index' => 5)), '@invalid-tokens' => implode(', ', array('[term:tid]'))))); + } } class GoogleAnalyticsStatusMessagesTest extends DrupalWebTestCase { diff --git a/sites/all/modules/contrib/admin/google_analytics/googleanalytics.variable.inc b/sites/all/modules/contrib/admin/google_analytics/googleanalytics.variable.inc index 6a657350..9d142a27 100644 --- a/sites/all/modules/contrib/admin/google_analytics/googleanalytics.variable.inc +++ b/sites/all/modules/contrib/admin/google_analytics/googleanalytics.variable.inc @@ -40,6 +40,10 @@ function googleanalytics_variable_group_info() { /** * Validate Web Property ID variable. + * + * @param array $variable + * + * @return string */ function googleanalytics_validate_googleanalytics_account($variable) { // Replace all type of dashes (n-dash, m-dash, minus) with the normal dashes. diff --git a/sites/all/modules/contrib/dev/elysia_cron/API.txt b/sites/all/modules/contrib/dev/elysia_cron/API.txt index 8eebf380..727b970a 100644 --- a/sites/all/modules/contrib/dev/elysia_cron/API.txt +++ b/sites/all/modules/contrib/dev/elysia_cron/API.txt @@ -126,7 +126,7 @@ You can use the "hook_cron_alter" function to edit cronapi data of other modules. Example: -function module_cron_alter($data) { +function module_cron_alter(&$data) { $data['key']['rule'] = '0 */6 * * *'; } @@ -182,6 +182,19 @@ function phptemplate_elysia_cron_description($job) { Note: module default theme_elysia_cron_description($job) already contains some common tasks descriptions. +----------------------------------------------------------------------------- +DISABLE CRON JOBS VIA settings.php FILE +----------------------------------------------------------------------------- +If you have some instances for the project you can want to disable some cron +jobs on different instances. For example you don't want to execute PROD cron +jobs on DEV instance. There is no need to make it via interface or via SQL +query. You can define variable for each cron job to manage it state. For more +information please look at `_elysia_cron_is_job_disabled` and `_ec_get_name` +functions. + +For example, if you have cron job with name googleanalytics_cron, you can +add this string to your settings.php file: +$conf['ec_googleanalytics_cron_d'] = TRUE; ----------------------------------------------------------------------------- OLD 1.x MODULE API (OBSOLETE) diff --git a/sites/all/modules/contrib/dev/elysia_cron/INSTALL.txt b/sites/all/modules/contrib/dev/elysia_cron/INSTALL.txt index dac08617..dd92d9be 100644 --- a/sites/all/modules/contrib/dev/elysia_cron/INSTALL.txt +++ b/sites/all/modules/contrib/dev/elysia_cron/INSTALL.txt @@ -16,8 +16,7 @@ up and running. You can stop here if you don't need a great precision over task execution and you don't have to execute a task more often than once an hour. For example, if you need only the "Once a day", "Once a week" or "Once a month" -schedule rules the basic install is fine. (For D6 users that want to stop here: -you should have installed Drupal crontab as described in Drupal INSTALL guide). +schedule rules the basic install is fine. Instead, if you need: - to run some tasks more often than once an hour (eg: you have a function that @@ -41,8 +40,8 @@ The only difference is that you should use the "* * * * *" rule part instead of "0 * * * *" or "45 * * * *" as described in the guide. While you're editing the system crontab, it's also recommended to replace the -"/cron.php" part with "/sites/modules/elysia_cron/cron.php" (if you have -installed elysia_cron in "sites/modules" directory). +"/cron.php" part with "/sites/all/modules/elysia_cron/cron.php" (if you have +installed elysia_cron in "sites/all/modules" directory). This is an optional step (you can leave "/cron.php" if you want), doing it will result in a better performance in bigger sites (elysia_cron's cron.php handles cache in a better way). @@ -78,6 +77,10 @@ red; font-weight: bold; } PERMISSIONS ------------ -You can also give 'administer elysia_cron' permission to all user roles that -needs to administer cron jobs. You can do this with standard drupal users -administration. +There are three permission provided by module: + * Administer elysia cron - Perform changes to cron jobs timings, disable cron + or single jobs and access cron execution statistics; + * Execute elysia cron jobs - Allow users to view statistics, execution status + and do manually execute cron jobs; + * View elysia cron stats - Allows users to view statistics and execution status + of cron jobs; diff --git a/sites/all/modules/contrib/dev/elysia_cron/README.txt b/sites/all/modules/contrib/dev/elysia_cron/README.txt index 30e7878d..e5f5d56c 100644 --- a/sites/all/modules/contrib/dev/elysia_cron/README.txt +++ b/sites/all/modules/contrib/dev/elysia_cron/README.txt @@ -9,27 +9,27 @@ For module developers API documetation read API.TXT FEATURES ----------------------------------------------------------------------------- -Elysia Cron extends Drupal standard cron, allowing a fine grain control over +Elysia Cron extends Drupal standard cron, allowing a fine grain control over each task and several ways to add custom cron jobs to your site. - Set the timings and frequencies of each cron task (you can run some jobs every day at a specified hour, other only monthly and so on...). - For each task you can simply choose between some frequently used options - ("once a day", "once a month" ...), or use a powerful "linux crontab"-like - syntax to set the accurate timings. You can even define your frequently used + For each task you can simply choose between some frequently used options + ("once a day", "once a month" ...), or use a powerful "linux crontab"-like + syntax to set the accurate timings. You can even define your frequently used options to speed up site configuration. -- Parallel execution of cron task: you can group jobs in channels and execute +- Parallel execution of cron task: you can group jobs in channels and execute then simultaneously: so a task that takes a lot of time to execute won't block other tasks that need to be executed every 5 minutes... - You can disable all tasks, an entire channel or a single task. - Change the priority/order of task execution. - Manual force the execution of a cron tasks. -- Detailed overview of cron status with time statistics for single tasks and +- Detailed overview of cron status with time statistics for single tasks and channels. -- Powerful API for module developers: you can define extra cron tasks for your - modules, each one with own default timings (site administrators can override - them by configuration, other modules via hook_alter). Elysia Cron 2.0 gives a +- Powerful API for module developers: you can define extra cron tasks for your + modules, each one with own default timings (site administrators can override + them by configuration, other modules via hook_alter). Elysia Cron 2.0 gives a brand new API support (compatible with 1.0 version) with a lot of features. - Administrators can define custom jobs (call to functions with parameters), via the "script" option. @@ -43,7 +43,7 @@ It also can be used in a Drupal install profile. 3rd party integration: - Ping feature, for external tracking services like host-tracker to tell whether cron is functioning properly on your site. -- Drush support: you can call "drush elysia-cron" to manually run extended cron. +- Drush support: you can call "drush elysia-cron run" to manually run extended cron. - CTools support for exports/backup of task settings. - Features support. @@ -53,35 +53,35 @@ USAGE EXAMPLES Elysia cron is usually used in large sites that needs performance optimization. -- Avoid drupal peak loads by distributing heavy load tasks during quiet periods - of the day: for example you may want to rebuild the XML Sitemap of your site - at 2:00AM in the morning, where usually only a few people are visiting your - site. You can even move some tasks to be executed only once a month (log +- Avoid drupal peak loads by distributing heavy load tasks during quiet periods + of the day: for example you may want to rebuild the XML Sitemap of your site + at 2:00AM in the morning, where usually only a few people are visiting your + site. You can even move some tasks to be executed only once a month (log rotation, old records expiry...). -- If you have tasks that should be executed very often, but don't want to - execute ALL drupal cron tasks that often! For example, you may want to check - for emails that needs to be sent to your users every 2 minutes. Standard cron - is managed in a "monolithic" way, so even if you find out how to execute it +- If you have tasks that should be executed very often, but don't want to + execute ALL drupal cron tasks that often! For example, you may want to check + for emails that needs to be sent to your users every 2 minutes. Standard cron + is managed in a "monolithic" way, so even if you find out how to execute it every 2 minutes, you will end in having all cron tasks executed so often, with a lot of performance problems. -- Fine tune cron cache management : drupal cron will invalidate variable cache - every cron run, and this is a great performance problem if you have a - frequently called task. Elysia cron optimize cache management, and doesn't +- Fine tune cron cache management : drupal cron will invalidate variable cache + every cron run, and this is a great performance problem if you have a + frequently called task. Elysia cron optimize cache management, and doesn't need to invalidate cache. -- Setup tasks that should be run at a precise time: for example if you want to +- Setup tasks that should be run at a precise time: for example if you want to send a SimpleNews newsletter every monday at 9:00AM, you can do it. -- Parallel execution: if you have a task that takes a lot of time to execute, - you can setup a different channel for it so it won't block other tasks that +- Parallel execution: if you have a task that takes a lot of time to execute, + you can setup a different channel for it so it won't block other tasks that need to be executed every 5 minutes. - Turn off (disable) a cron task/feature you don't need. - Debug system cron problems. If your cron does not terminate correctly you can - use extended logging, see at each cron timings and disable task to track down + use extended logging, see at each cron timings and disable task to track down the problem. ----------------------------------------------------------------------------- @@ -93,11 +93,11 @@ Channels are groups of tasks. Each channel is a "parallel line" of execution Tasks inside a channel will be executed sequentially (if they should). WARNING: It's not recommended to create more than 2 or 3 channels. -Every channel will increase the delay between each cron check (of the same +Every channel will increase the delay between each cron check (of the same channel), because each cron call will cycle between all channels. So, for example: If you have 1 channel it will be checked once a minute. -If you have 2 channel each one will be checked every 2 minutes (almost usually, +If you have 2 channel each one will be checked every 2 minutes (almost usually, when the other one is running it will be checked once a minute). It you have 10 channels there will be a check every 10 minutes... if you have a job that should be executed every 5 minutes it won't do so! @@ -106,10 +106,10 @@ a job that should be executed every 5 minutes it won't do so! EXPORT VIA CTOOLS/FEATURES MODULE ----------------------------------------------------------------------------- -With 2.0 version of Elysia Cron you can use "Bulk Export" functionality of +With 2.0 version of Elysia Cron you can use "Bulk Export" functionality of "Chaos Tools Suite" to export cron settings. To use it simply enable all modules, go to Structure > Bulk Exporter and -select the tasks you want to export settings. You can also select all +select the tasks you want to export settings. You can also select all "elysia_cron" prefixed variables to export global options. Than generate the module. @@ -117,7 +117,7 @@ The generated code will set the new defaults of elysia cron settings. This way you can simply enable it to use them, but you are free to override them in the future using the normal settings page. Note that if you want to delete all overrides, and return to exported settings, -you should do a "reset to defaults" from elysia cron settings page. +you should do a "reset to defaults" from elysia cron settings page. You can also use "Features" module to create a Feature module will the settings you need. @@ -133,7 +133,32 @@ DRUSH SUPPORT Elysia Cron 2.0 adds a simple support for Drush module. -You can execute the "elysia-cron" command to run cron. +Run all cron tasks in all active modules for specified site using elysia cron +system. This replaces the standard "core-cron" drush handler. + +Examples: + elysia-cron run Run all cron tasks in all active + modules (as the standard "core-cron") + elysia-cron run --verbose Run all cron tasks in verbose mode + elysia-cron run @channel Run all cron tasks in specified + channel + elysia-cron run search_cron --ignore-time Run only search index + build task (force execution) + elysia-cron list --elysia-cron-verbose List all channels/tasks + in verbose mode + elysia-cron disable search_cron Disable search index build task + +Options: + --elysia-cron-verbose enable extended output (the same as + --verbose, but without enabling drush + verbose mode) + --ignore-disable run channels/tasks even if disabled + --ignore-running run channels/tasks even + if already running + --ignore-time run channels/tasks even if not ready + for execution + --quiet suppress all output + --verbose enable extended output ----------------------------------------------------------------------------- RULES AND SCRIPT SYNTAX @@ -150,17 +175,17 @@ RULES AND SCRIPT SYNTAX | | | | | * * * * * -Each of the patterns from the first five fields may be either * (an asterisk), -which matches all legal values, or a list of elements separated by commas +Each of the patterns from the first five fields may be either * (an asterisk), +which matches all legal values, or a list of elements separated by commas (see below). -For "day of the week" (field 5), 0 is considered Sunday, 6 is Saturday (7 is +For "day of the week" (field 5), 0 is considered Sunday, 6 is Saturday (7 is an illegal value) -A job is executed when the time/date specification fields all match the current -time and date. There is one exception: if both "day of month" and "day of week" -are restricted (not "*"), then either the "day of month" field (3) or the "day -of week" field (5) must match the current day (even though the other of the two +A job is executed when the time/date specification fields all match the current +time and date. There is one exception: if both "day of month" and "day of week" +are restricted (not "*"), then either the "day of month" field (3) or the "day +of week" field (5) must match the current day (even though the other of the two fields need not match the current day). 2. FIELDS OPERATOR @@ -169,13 +194,13 @@ fields need not match the current day). There are several ways of specifying multiple date/time values in a field: * The comma (',') operator specifies a list of values, for example: "1,3,4,7,8" -* The dash ('-') operator specifies a range of values, for example: "1-6", which +* The dash ('-') operator specifies a range of values, for example: "1-6", which is equivalent to "1,2,3,4,5,6" -* The asterisk ('*') operator specifies all possible values for a field. For - example, an asterisk in the hour time field would be equivalent to 'every hour' +* The asterisk ('*') operator specifies all possible values for a field. For + example, an asterisk in the hour time field would be equivalent to 'every hour' (subject to matching other specified fields). -* The slash ('/') operator (called "step") can be used to skip a given number of - values. For example, "*/3" in the hour time field is equivalent to +* The slash ('/') operator (called "step") can be used to skip a given number of + values. For example, "*/3" in the hour time field is equivalent to "0,3,6,9,12,15,18,21". 3. EXAMPLES @@ -190,10 +215,10 @@ There are several ways of specifying multiple date/time values in a field: 4. SCRIPTS --------------------------------- -You can use the script section to easily create new jobs (by calling a php +You can use the script section to easily create new jobs (by calling a php function) or to change the scheduling of an existing job. -Every line of the script can be a comment (if it starts with #) or a job +Every line of the script can be a comment (if it starts with #) or a job definition. The syntax of a job definition is: @@ -207,10 +232,10 @@ The syntax of a job definition is: * [job]: could be the name of a supported job (for example: 'search_cron') or a function call, ending with ; (for example: 'process_queue();'). -A comment on the line just preceding a job definition is considered the job +A comment on the line just preceding a job definition is considered the job description. -Remember that script OVERRIDES all settings on single jobs sections or channel +Remember that script OVERRIDES all settings on single jobs sections or channel sections of the configuration 5. EXAMPLE OF SCRIPT @@ -219,7 +244,7 @@ sections of the configuration # Search indexing every 2 hours (i'm setting this as the job description) 0 */2 * * * search_cron -# I'll check for module status only on sunday nights +# I'll check for module status only on sunday nights # (and this is will not be the job description, see the empty line below) 0 2 * * 0 update_status_cron diff --git a/sites/all/modules/contrib/dev/elysia_cron/cron.php b/sites/all/modules/contrib/dev/elysia_cron/cron.php index 3ba20503..294a1c4d 100644 --- a/sites/all/modules/contrib/dev/elysia_cron/cron.php +++ b/sites/all/modules/contrib/dev/elysia_cron/cron.php @@ -8,9 +8,11 @@ if (!file_exists('includes/bootstrap.inc')) { if (!empty($_SERVER['DOCUMENT_ROOT']) && file_exists($_SERVER['DOCUMENT_ROOT'] . '/includes/bootstrap.inc')) { chdir($_SERVER['DOCUMENT_ROOT']); - } elseif (preg_match('@^(.*)[\\\\/]sites[\\\\/][^\\\\/]+[\\\\/]modules[\\\\/]([^\\\\/]+[\\\\/])?elysia(_cron)?$@', getcwd(), $r) && file_exists($r[1] . '/includes/bootstrap.inc')) { + } + elseif (preg_match('@^(.*)[\\\\/]sites[\\\\/][^\\\\/]+[\\\\/]modules[\\\\/]([^\\\\/]+[\\\\/])?elysia(_cron)?$@', getcwd(), $r) && file_exists($r[1] . '/includes/bootstrap.inc')) { chdir($r[1]); - } else { + } + else { die("Cron Fatal Error: Can't locate bootstrap.inc. Check cron.php position."); } } @@ -21,16 +23,14 @@ if (!file_exists('includes/bootstrap.inc')) { define('DRUPAL_ROOT', getcwd()); include_once DRUPAL_ROOT . '/includes/bootstrap.inc'; -drupal_override_server_variables(array( - 'SCRIPT_NAME' => '/cron.php', -)); +drupal_override_server_variables(array('SCRIPT_NAME' => '/cron.php')); drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); -if (!isset($_GET['cron_key']) || variable_get('cron_key', 'drupal') != $_GET['cron_key']) { +if ((variable_get('cron_key') && empty($_GET['cron_key'])) || !empty($_GET['cron_key']) && variable_get('cron_key') != $_GET['cron_key']) { watchdog('cron', 'Cron could not run because an invalid key was used.', array(), WATCHDOG_NOTICE); drupal_access_denied(); } -elseif (variable_get('maintenance_mode', 0)) { +elseif (variable_get('maintenance_mode', 0) && !variable_get('elysia_cron_run_maintenance', FALSE)) { watchdog('cron', 'Cron could not run because the site is in maintenance mode.', array(), WATCHDOG_NOTICE); drupal_access_denied(); } diff --git a/sites/all/modules/contrib/dev/elysia_cron/elysia_cron-multilingual-image-path-2096571-1.patch b/sites/all/modules/contrib/dev/elysia_cron/elysia_cron-multilingual-image-path-2096571-1.patch deleted file mode 100644 index ddd57ea1..00000000 --- a/sites/all/modules/contrib/dev/elysia_cron/elysia_cron-multilingual-image-path-2096571-1.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/elysia_cron.admin.inc b/elysia_cron.admin.inc -index fa5c6de..4011d91 100644 ---- a/elysia_cron.admin.inc -+++ b/elysia_cron.admin.inc -@@ -42,7 +42,7 @@ function elysia_cron_admin_page() { - - $rows = array(); - -- $ipath = url(drupal_get_path('module', 'elysia_cron') . '/images/icon_'); -+ $ipath = file_create_url(drupal_get_path('module', 'elysia_cron') . '/images/icon_'); - - foreach ($elysia_cron_settings_by_channel as $channel => $data) { - $running = elysia_cron_is_channel_running($channel); diff --git a/sites/all/modules/contrib/dev/elysia_cron/elysia_cron.admin.inc b/sites/all/modules/contrib/dev/elysia_cron/elysia_cron.admin.inc index 4011d913..ba6251d8 100644 --- a/sites/all/modules/contrib/dev/elysia_cron/elysia_cron.admin.inc +++ b/sites/all/modules/contrib/dev/elysia_cron/elysia_cron.admin.inc @@ -1,35 +1,34 @@ ' . t('Global disable') . ': ' . ($v ? '' . t('YES') . '' : 'no') . '

'; - $output .= '

' . t('Last channel executed') . ': ' . (($c = elysia_cron_last_channel()) ? $c : t('n/a')) . '

'; - - if (EC_DRUPAL_VERSION < 7) { - if (_ec_variable_get('elysia_cron_semaphore', 0)) { - $output .= '

' . t('Global semaphore active since !date', array('!date' => elysia_cron_date(_ec_variable_get('elysia_cron_semaphore', 0)))) . '

'; - } + if (elysia_cron_access('execute elysia_cron')) { + $aoutput[] = drupal_get_form('elysia_cron_run_form'); } + $output = ''; + elysia_cron_initialize(); + global $_elysia_cron_settings_by_channel; + + $global_disabled = variable_get('elysia_cron_disabled', FALSE); + $last_channel = elysia_cron_last_channel(); + $output .= '

' . t('Global disable') . ': ' . ($global_disabled ? '' . t('YES') . '' : t('no')) . '

'; + $output .= '

' . t('Last channel executed') . ': ' . ($last_channel ? $last_channel : t('n/a')) . '

'; + $running = ''; - foreach ($elysia_cron_settings_by_channel as $channel => $data) { + foreach ($_elysia_cron_settings_by_channel as $channel => $data) { if (elysia_cron_is_channel_running($channel)) { $running .= $channel . ' '; } @@ -39,19 +38,33 @@ function elysia_cron_admin_page() { } $output .= '

' . t('Last run') . ': ' . elysia_cron_date(_ec_variable_get('elysia_cron_last_run', 0)) . '

'; - $rows = array(); - - $ipath = file_create_url(drupal_get_path('module', 'elysia_cron') . '/images/icon_'); - - foreach ($elysia_cron_settings_by_channel as $channel => $data) { + $ipath = drupal_get_path('module', 'elysia_cron') . '/images/icon_'; + + foreach ($_elysia_cron_settings_by_channel as $channel => $data) { $running = elysia_cron_is_channel_running($channel); $rows[] = array( - array('data' => '

' . t('Channel') . ': ' . $channel . ($data['#data']['disabled'] ? ' (' . t('DISABLED') . ')' : '') . '

', 'colspan' => 2, 'header' => 'true'), - array('data' => elysia_cron_date($data['#data']['last_run']), 'header' => 'true'), - array('data' => $data['#data']['last_execution_time'] . 's ' . t('(Shutdown: !shutdown)', array('!shutdown' => $data['#data']['last_shutdown_time'] . 's')), 'header' => 'true'), - array('data' => $data['#data']['execution_count'], 'header' => 'true'), - array('data' => $data['#data']['avg_execution_time'] . 's / ' . $data['#data']['max_execution_time'] . 's', 'header' => 'true'), + array( + 'data' => '

' . t('Channel') . ': ' . $channel . ($data['#data']['disabled'] ? ' (' . t('DISABLED') . ')' : '') . '

', + 'colspan' => 2, + 'header' => TRUE, + ), + array( + 'data' => elysia_cron_date($data['#data']['last_run']), + 'header' => TRUE, + ), + array( + 'data' => $data['#data']['last_execution_time'] . 's ' . t('(Shutdown: !shutdown)', array('!shutdown' => $data['#data']['last_shutdown_time'] . 's')), + 'header' => TRUE, + ), + array( + 'data' => $data['#data']['execution_count'], + 'header' => TRUE, + ), + array( + 'data' => $data['#data']['avg_execution_time'] . 's / ' . $data['#data']['max_execution_time'] . 's', + 'header' => TRUE, + ), ); $messages = ''; if ($running) { @@ -68,10 +81,14 @@ function elysia_cron_admin_page() { $messages .= implode(', ', $msg) . '
'; } if ($messages) { - $rows[] = array( '', '', array('data' => $messages, 'colspan' => 4, 'header' => true) ); - $rows[] = array( array('data' => '', 'colspan' => 6) ); + $rows[] = array( + '', + '', + array('data' => $messages, 'colspan' => 4, 'header' => TRUE), + ); + $rows[] = array(array('data' => '', 'colspan' => 6)); } - + foreach ($data as $job => $conf) { $icon = 'idle'; $caption = '' . $job . ''; @@ -90,16 +107,25 @@ function elysia_cron_admin_page() { $icon = 'waiting'; $tip = t('Waiting for execution'); } - + if ($job != '#data') { + $force_run = elysia_cron_access('execute elysia_cron') + ? l(t('Force run'), 'admin/config/system/cron/execute/' . $job, array('attributes' => array('onclick' => 'return confirm("' . t('Force execution of !job?', array('!job' => $job)) . '");'))) + : ''; + + $icon_image = theme('image', array( + 'path' => $ipath . $icon . '.png', + 'alt' => $tip, + 'title' => $tip, + )); $rows[] = array( - array( 'data' => '' . $tip . '', 'align' => 'right' ), - array( 'data' => $caption . ': ' . elysia_cron_description($job) . ' ', 'colspan' => 4 ), - array( 'data' => _dco_l(t('Force run'), _dcf_internal_path('admin/config/system/cron/execute/') . $job, array('attributes' => array('onclick' => 'return confirm("' . t('Force execution of !job?', array('!job' => $job)) . '");'))), 'align' => 'right'), + array('data' => $icon_image, 'align' => 'right'), + array('data' => $caption . ': ' . elysia_cron_description($job) . ' ', 'colspan' => 4), + array('data' => $force_run, 'align' => 'right'), ); $rows[] = array( '', - $conf['rule'] . (!empty($conf['weight']) ? ' (' . t('Weight') . ': ' . $conf['weight'] . ')' : ''), + check_plain($conf['rule']) . (!empty($conf['weight']) ? ' (' . t('Weight') . ': ' . $conf['weight'] . ')' : ''), elysia_cron_date($conf['last_run']), $conf['last_execution_time'] . 's', $conf['execution_count'], @@ -107,21 +133,38 @@ function elysia_cron_admin_page() { ); } } - $rows[] = array(' ','','','','',''); + + $rows[] = array(' ', '', '', '', '', ''); } - - $output .= _dco_theme('table', array('header' => array('', t('Job / Rule'), t('Last run'), t('Last exec time'), t('Exec count'), t('Avg/Max Exec time')), 'rows' => $rows)); + + $output .= theme('table', array( + 'header' => array( + '', + t('Job / Rule'), + t('Last run'), + t('Last exec time'), + t('Exec count'), + t('Avg/Max Exec time'), + ), + 'rows' => $rows, + )); $output .= '
'; - - $output .= _dco_theme('table', array( + + $legend_icons = array( + 'idle' => theme('image', array('path' => $ipath . 'idle.png')), + 'waiting' => theme('image', array('path' => $ipath . 'waiting.png')), + 'running' => theme('image', array('path' => $ipath . 'running.png')), + 'disabled' => theme('image', array('path' => $ipath . 'disabled.png')), + ); + $output .= theme('table', array( 'header' => array(t('Legend')), 'rows' => array( - array('' . $tip . ' ' . t('Job shouldn\'t do anything right now')), - array('' . $tip . ' ' . t('Job is ready to be executed, and is waiting for system cron call')), - array('' . $tip . ' ' . t('Job is running right now')), - array('' . $tip . ' ' . t('Job is disabled by settings, and won\'t run until enabled again')), - array(t('Notes: job times don\'t include shutdown times (only shown on channel times).')), - array(t('If an abort occours usually the job is not properly terminated, and so job timings can be inaccurate or wrong.')), + array($legend_icons['idle'] . ' - ' . t("Job shouldn't do anything right now")), + array($legend_icons['waiting'] . ' - ' . t('Job is ready to be executed, and is waiting for system cron call')), + array($legend_icons['running'] . ' - ' . t('Job is running right now')), + array($legend_icons['disabled'] . ' - ' . t("Job is disabled by settings, and won't run until enabled again")), + array(t("Notes: job times don't include shutdown times (only shown on channel times).")), + array(t('If an abort occurs usually the job is not properly terminated, and so job timings can be inaccurate or wrong.')), ), )); @@ -130,11 +173,17 @@ function elysia_cron_admin_page() { '#markup' => $output, ); - return _dcr_render_array($aoutput); + return $aoutput; } +/** + * Form builder for general settings form. + * + * @return array + * From API array. + */ function elysia_cron_settings_form() { - global $elysia_cron_settings, $elysia_cron_settings_by_channel; + global $_elysia_cron_settings_by_channel; elysia_cron_initialize(); $form = array(); @@ -142,8 +191,8 @@ function elysia_cron_settings_form() { $form['prefix_1'] = array( '#type' => 'fieldset', '#title' => t('Click for help and cron rules and script syntax'), - '#collapsible' => true, - '#collapsed' => true, + '#collapsible' => TRUE, + '#collapsed' => TRUE, '#description' => t(<<Fields order
@@ -190,7 +239,7 @@ or to change the scheduling of an existing job.

<-> [rule] <ch:CHANNEL> [job] -

(Tokens betweens [] are mandatory)

+

(Tokens between [] are mandatory)

  • <->: a line starting with "-" means that the job is DISABLED.
  • [rule]: a crontab schedule rule. See above.
  • @@ -216,13 +265,13 @@ or to change the scheduling of an existing job.

    # Disable node_cron (i must set the cron rule even if disabled) - */15 * * * * node_cron -# Launch function send_summary_mail('test@test.com', false); every night +# Launch function send_summary_mail('test@test.com', FALSE); every night # And set its description to "Send daily summary" # Send daily summary -0 1 * * * send_summary_mail('test@test.com', false); +0 1 * * * send_summary_mail('test@test.com', FALSE);
EOT -), + ), ); $form['prefix_2'] = array( @@ -232,54 +281,71 @@ EOT $form['main'] = array( '#title' => t('Main'), '#type' => 'fieldset', - '#collapsible' => false, - '#collapsed' => false, + '#collapsible' => FALSE, + '#collapsed' => FALSE, ); $form['main']['elysia_cron_disabled'] = array( '#title' => t('Global disable'), '#type' => 'checkbox', - '#default_value' => variable_get('elysia_cron_disabled', false), + '#default_value' => variable_get('elysia_cron_disabled', FALSE), + ); + $form['main']['elysia_cron_run_maintenance'] = array( + '#title' => t('Run in maintenance'), + '#description' => t('Allow to run cron in maintenance mode.'), + '#type' => 'checkbox', + '#default_value' => variable_get('elysia_cron_run_maintenance', FALSE), ); $form['installation'] = array( '#title' => t('Installation settings'), '#type' => 'fieldset', - '#collapsible' => true, - '#collapsed' => true, + '#collapsible' => TRUE, + '#collapsed' => TRUE, ); - if (EC_DRUPAL_VERSION >= 7) { - $form['installation']['cron_safe_threshold'] = array( - '#type' => 'select', - '#title' => t('Run cron on visitor\'s requests, every'), - '#default_value' => variable_get('cron_safe_threshold', DRUPAL_CRON_DEFAULT_THRESHOLD), - '#description' => t('Setting a time here will enable the "poormanscron" method, which runs the Drupal cron operation using normal browser/page requests instead of having to set up a crontab to request the cron.php script. This approach requires that your site gets regular traffic/visitors in order to trigger the cron request.') . '
' . - t('This way is fine if you don\'t need a great control over job starting times and execution frequency.') . '
' . - t('If you need a fine grained control over cron timings use the crontab metod, as described in Drupal installation guide.', array('!cron_url' => url('http://drupal.org/cron'))) . '
' . - t('If you have a very large site, or you need to execute some jobs very often (more than once an hour) refer to Elysia cron\'s INSTALL.TXT to improve main cron setup.'), - '#options' => array(0 => t('Never / Use external crontab')) + drupal_map_assoc(array(3600, 10800, 21600, 43200, 86400, 604800), 'format_interval'), - ); - } + $options[0] = t('Never / Use external crontab'); + $options += drupal_map_assoc(array(3600, 10800, 21600, 43200, 86400, 604800), 'format_interval'); + $form['installation']['cron_safe_threshold'] = array( + '#type' => 'select', + '#title' => t("Run cron on visitor's requests, every"), + '#default_value' => variable_get('cron_safe_threshold', DRUPAL_CRON_DEFAULT_THRESHOLD), + '#description' => t('Setting a time here will enable the "poormanscron" method, which runs the Drupal cron operation using normal browser/page requests instead of having to set up a crontab to request the cron.php script. This approach requires that your site gets regular traffic/visitors in order to trigger the cron request.') + . '
' + . t("This way is fine if you don't need a great control over job starting times and execution frequency.") + . '
' + . t('If you need fine-grained control over cron timings use the crontab method, as described in Drupal installation guide.', array('!cron_url' => url('http://drupal.org/cron'))) + . '
' + . t("If you have a very large site, or you need to execute some jobs very often (more than once an hour) refer to Elysia cron's INSTALL.TXT to improve main cron setup."), + '#options' => $options, + ); + + $form['installation']['elysia_cron_queue_show_count'] = array( + '#title' => t('Show the number of items in queues'), + '#description' => t('Some queue backends may have performance issue related with counting items in queue. If you faced with it, just disable this option.'), + '#type' => 'checkbox', + '#default_value' => variable_get('elysia_cron_queue_show_count', TRUE), + ); $form['installation']['cron_key'] = array( '#title' => t('Cron key'), '#type' => 'textfield', - '#default_value' => variable_get('cron_key', ''), - '#description' => t('This is used to avoid external cron calling. If you set this cron will by accessible only by calling http://site/cron.php?cron_key=XXX, so you\'ll need to modify system crontab to support this (Logged user with [administer elysia_cron] permission avoid this check).'), + '#default_value' => variable_get('cron_key'), + '#description' => t("This is used to avoid external cron calling. If you set this cron will by accessible only by calling http://site/cron.php?cron_key=XXX, so you'll need to modify system crontab to support this (Logged users with execute elysia_cron permission avoid this check). +
If you left this field empty, you can run cron without cron_key parameter, like this http://site/cron.php, but it HIGHLY NOT RECOMMENDED."), ); $form['installation']['elysia_cron_allowed_hosts'] = array( '#title' => t('Allowed hosts'), '#type' => 'textfield', '#default_value' => variable_get('elysia_cron_allowed_hosts', ''), - '#description' => t('Insert a list of ip addresses separated by , that can run cron.php (Logged user with [administer elysia_cron] permission avoid this check).'), + '#description' => t('Insert a list of ip addresses separated by , that can run cron.php (Logged user with [execute elysia_cron] permission avoid this check).'), ); $form['installation']['elysia_cron_default_rule'] = array( '#title' => t('Default schedule rule'), '#type' => 'textfield', - '#default_value' => variable_get('elysia_cron_default_rule', false), - '#description' => t('If you don\'t specify a rule for a process, and if it has not a module specified one, this rule will apply'), + '#default_value' => variable_get('elysia_cron_default_rule', FALSE), + '#description' => t("If you don't specify a rule for a process, and if it has not a module specified one, this rule will apply"), ); if (!ini_get('safe_mode')) { @@ -309,25 +375,25 @@ EOT '#description' => t('Enable extended logging (in watchdog)'), ); - $default_ruless = ''; - $default_rules = variable_get('elysia_cron_default_rules', $GLOBALS['elysia_cron_default_rules']); + $default_rules_human = ''; + $default_rules = variable_get('elysia_cron_default_rules', _elysia_cron_default_rules()); foreach ($default_rules as $dk => $dr) { - $default_ruless .= $dr . ' = ' . $dk . "\n"; + $default_rules_human .= $dr . ' = ' . $dk . PHP_EOL; } $form['installation']['elysia_cron_default_rules'] = array( '#title' => t('Predefined rules'), '#type' => 'textarea', '#rows' => 5, - '#default_value' => $default_ruless, + '#default_value' => $default_rules_human, '#description' => t('You can put here standard rules used in your system, each one with its own caption. Put each rule in a separate line, in the form "caption = rule". For example: "every 15 minutes = */15 * * * *".'), ); $form['installation']['elysia_cron_alert_fieldset'] = array( '#title' => t('External cron tracking'), '#type' => 'fieldset', - '#collapsible' => true, - '#collapsed' => true, + '#collapsible' => TRUE, + '#collapsed' => TRUE, '#description' => t('This lets you use an external tracking system like Host Tracker to be used to monitor the health of cron on your site. Point the tracking service to !cron-ping-url. If Elysia cron has been called within the time interval specified below, the ping page will return HTTP 200. If not, the ping page will throw a 404 (page not found).', array('!cron-ping-url' => url('admin/build/cron/ping'))), ); $form['installation']['elysia_cron_alert_fieldset']['elysia_cron_alert_interval'] = array( @@ -341,49 +407,46 @@ EOT $form['elysia_cron_script_fieldset'] = array( '#title' => t('Script'), '#type' => 'fieldset', - '#collapsible' => true, + '#collapsible' => TRUE, '#collapsed' => !variable_get('elysia_cron_script', ''), ); $form['elysia_cron_script_fieldset']['elysia_cron_script'] = array( '#type' => 'textarea', '#rows' => 20, '#default_value' => variable_get('elysia_cron_script', ''), - '#description' => t('You can specify new cron jobs or modify existing schedules by adding lines to the script.
' . - 'Warning All rules specified in the script will OVERRIDE single job settings and channel settings (sections below).'), + '#description' => t('You can specify new cron jobs or modify existing schedules by adding lines to the script.') + . '
' + . t('Warning All rules specified in the script will OVERRIDE single job settings and channel settings (sections below).'), ); - + $form['single_job'] = array( '#title' => t('Single job settings'), - '#description' => - ''.t('Disabled').': '.t('Flag this to disable job execution').'
'. - ''.t('Schedule rule').': '.t('Timing rule for the job. Leave empty to use default rule (shown after the field in parenthesis)').'
'. - ''.t('Weight').': '.t('Use this to specify execution order: low weights are executed before high weights. Default value shown in parenthesis').'
'. - ''.t('Channel').': '.t('Specify a channel for the job (create the channel if not exists)').'

', + '#description' => '' . t('Disabled') . ': ' . t('Flag this to disable job execution') . '
' + . '' . t('Schedule rule') . ': ' . t('Timing rule for the job. Leave empty to use default rule (shown after the field in parenthesis)') . '
' + . '' . t('Weight') . ': ' . t('Use this to specify execution order: low weights are executed before high weights. Default value shown in parenthesis') . '
' + . '' . t('Channel') . ': ' . t('Specify a channel for the job (create the channel if not exists)') . '

', '#type' => 'fieldset', - '#collapsible' => true, - //'#collapsed' => true, + '#collapsible' => TRUE, ); - + $jobchannels = array( '#title' => t('Job channel associations'), '#description' => t('Leave empty for default channel'), '#type' => 'fieldset', - '#collapsible' => true, - '#collapsed' => true, + '#collapsible' => TRUE, + '#collapsed' => TRUE, ); - foreach ($elysia_cron_settings_by_channel as $channel => $cconf) { + foreach ($_elysia_cron_settings_by_channel as $channel => $cconf) { foreach ($cconf as $job => $conf) { if ($job != '#data' && empty($conf['expression'])) { $form['single_job']['elysia_cron_' . $job] = array( - '#title' => $job, // t('Job !job', array('!job' => $job)), + '#title' => $job, '#description' => elysia_cron_description($job), '#type' => 'fieldset', - '#collapsible' => true, + '#collapsible' => TRUE, '#collapsed' => !elysia_cron_get_job_rule($job) && !elysia_cron_get_job_weight($job) && !elysia_cron_is_job_disabled($job) && !elysia_cron_get_job_channel($job), ); - //if (!$form['single_job']['elysia_cron_'.$job]['#collapsed']) - // $form['single_job']['#collapsed'] = false; $rule = elysia_cron_get_job_rule($job); $options = array_merge(array('default' => t('Default') . ' (' . (!empty($default_rules[$conf['default_rule']]) ? $default_rules[$conf['default_rule']] : $conf['default_rule']) . ')'), $default_rules); @@ -414,23 +477,18 @@ EOT '#description' => '(' . $conf['default_weight'] . ')', ); - //$form['single_job']['elysia_cron_'.$job]['elysia_cron_'.$job.'_disabled'] = array( $form['single_job']['elysia_cron_' . $job]['_elysia_cron_job_disabled_' . $job] = array( '#title' => t('Disabled'), '#type' => 'checkbox', - '#default_value' => elysia_cron_is_job_disabled($job, false), + '#default_value' => elysia_cron_is_job_disabled($job, FALSE), ); - //$jobchannels['elysia_cron_'.$job.'_channel'] = array( $form['single_job']['elysia_cron_' . $job]['_elysia_cron_job_channel_' . $job] = array( - '#title' => t('Channel'), // t('Channel for !job', array('!job' => $job)), + '#title' => t('Channel'), '#type' => 'textfield', '#size' => 20, '#default_value' => elysia_cron_get_job_channel($job), ); - - //if (elysia_cron_get_job_channel($job)) - // $jobchannels['#collapsed'] = false; } } } @@ -438,13 +496,12 @@ EOT $form['channels'] = array( '#title' => t('Channels settings'), '#type' => 'fieldset', - '#collapsible' => true, - //'#collapsed' => $jobchannels['#collapsed'], + '#collapsible' => TRUE, ); - foreach ($elysia_cron_settings_by_channel as $channel => $conf) { + foreach ($_elysia_cron_settings_by_channel as $channel => $conf) { $form['channels']['elysia_cron_ch_' . $channel] = array( - '#title' => $channel, // t('Channel !channel', array('!channel' => $channel)), + '#title' => $channel, '#type' => 'fieldset', ); $form['channels']['elysia_cron_ch_' . $channel]['_elysia_cron_ch_disabled_' . $channel] = array( @@ -458,12 +515,8 @@ EOT '#size' => 20, '#default_value' => elysia_cron_get_channel_rule($channel), ); - //if (elysia_cron_is_channel_disabled($channel)) - // $form['channels']['#collapsed'] = false; } - //$form['channels']['jobchannels'] = $jobchannels; - $form['buttons'] = array('#type' => 'actions'); $form['buttons']['submit'] = array( '#type' => 'submit', @@ -478,17 +531,22 @@ EOT elysia_cron_error('The settings have not been saved because of the errors.'); } - return _dcr_form($form); + return $form; } -function theme_elysia_cron_settings_form($_dco_variables) { - extract(_dcf_theme_form($_dco_variables)); +/** + * Theme function for general settings form. + * + * @param array $variables + * Theme vars. + * + * @return string + * Ready for print HTML. + */ +function theme_elysia_cron_settings_form(array &$variables) { $form = &$variables['form']; $output = '