From 3e8861682a4ae6b2bd1129473104be37b63695ac Mon Sep 17 00:00:00 2001 From: catch Date: Tue, 8 May 2012 11:53:23 +0900 Subject: [PATCH 01/11] Issue #1540174 by Niklas Fiekas, attiks: Fixed Some attributes not allowed for the new HTML5 input elements. --- core/includes/form.inc | 40 +++++++-- .../field/modules/number/number.module | 5 -- core/modules/field/modules/text/text.module | 1 - core/modules/field_ui/field_ui.api.php | 1 - core/modules/filter/filter.module | 2 - core/modules/image/image.admin.inc | 4 - core/modules/image/image.field.inc | 8 -- core/modules/poll/poll.module | 2 - core/modules/search/search.admin.inc | 3 +- core/modules/system/image.gd.inc | 2 - core/modules/system/system.module | 4 - core/modules/system/tests/form.test | 14 +++ .../tests/modules/form_test/form_test.module | 86 +++++++++++++++++++ core/modules/user/user.admin.inc | 2 - 14 files changed, 136 insertions(+), 38 deletions(-) diff --git a/core/includes/form.inc b/core/includes/form.inc index c387384b2a3..6d577806d19 100644 --- a/core/includes/form.inc +++ b/core/includes/form.inc @@ -3951,8 +3951,8 @@ function theme_tel($variables) { * @param $variables * An associative array containing: * - element: An associative array containing the properties of the element. - * Properties used: #title, #value, #description, #size, #min, #max, - * #placeholder, #required, #attributes, #step. + * Properties used: #title, #value, #description, #min, #max, #placeholder, + * #required, #attributes, #step. * * @ingroup themeable */ @@ -3960,7 +3960,7 @@ function theme_number($variables) { $element = $variables['element']; $element['#attributes']['type'] = 'number'; - element_set_attributes($element, array('id', 'name', 'value', 'size', 'step', 'min', 'max', 'maxlength', 'placeholder')); + element_set_attributes($element, array('id', 'name', 'value', 'step', 'min', 'max', 'placeholder')); _form_set_class($element, array('form-number')); $output = ''; @@ -3974,8 +3974,8 @@ function theme_number($variables) { * @param $variables * An associative array containing: * - element: An associative array containing the properties of the element. - * Properties used: #title, #value, #description, #size, #min, #max, - * #required, #attributes, #step. + * Properties used: #title, #value, #description, #min, #max, #attributes, + * #step. * * @ingroup themeable */ @@ -4031,6 +4031,36 @@ function form_validate_number(&$element, &$form_state) { } } +/** + * Determines the value for a range element. + * + * Make sure range elements always have a value. The 'required' attribute is not + * allowed for range elements. + * + * @param $element + * The form element whose value is being populated. + * @param $input + * The incoming input to populate the form element. If this is FALSE, the + * element's default value should be returned. + * + * @return + * The data that will appear in the $form_state['values'] collection for + * this element. Return nothing to use the default. + */ +function form_type_range_value($element, $input = FALSE) { + if ($input === '') { + $offset = ($element['#max'] - $element['#min']) / 2; + + // Round to the step. + if (strtolower($element['#step']) != 'any') { + $steps = round($offset / $element['#step']); + $offset = $element['#step'] * $steps; + } + + return $element['#min'] + $offset; + } +} + /** * Returns HTML for a url form element. * diff --git a/core/modules/field/modules/number/number.module b/core/modules/field/modules/number/number.module index 1b9a300d86d..b3f56151d68 100644 --- a/core/modules/field/modules/number/number.module +++ b/core/modules/field/modules/number/number.module @@ -324,11 +324,6 @@ function number_field_widget_form(&$form, &$form_state, $field, $instance, $lang $element += array( '#type' => 'number', '#default_value' => $value, - // Allow a slightly larger size that the field length to allow for some - // configurations where all characters won't fit in input field. - '#size' => $field['type'] == 'number_decimal' ? $field['settings']['precision'] + 4 : 12, - // Allow two extra characters for signed values and decimal separator. - '#maxlength' => $field['type'] == 'number_decimal' ? $field['settings']['precision'] + 2 : 10, ); // Set the step for floating point and decimal numbers. diff --git a/core/modules/field/modules/text/text.module b/core/modules/field/modules/text/text.module index 985fa9b696a..dcf4d1e7f6d 100644 --- a/core/modules/field/modules/text/text.module +++ b/core/modules/field/modules/text/text.module @@ -225,7 +225,6 @@ function text_field_formatter_settings_form($field, $instance, $view_mode, $form $element['trim_length'] = array( '#title' => t('Trim length'), '#type' => 'number', - '#size' => 10, '#default_value' => $settings['trim_length'], '#min' => 1, '#required' => TRUE, diff --git a/core/modules/field_ui/field_ui.api.php b/core/modules/field_ui/field_ui.api.php index b6c8aeede9a..ff85b5d957a 100644 --- a/core/modules/field_ui/field_ui.api.php +++ b/core/modules/field_ui/field_ui.api.php @@ -158,7 +158,6 @@ function hook_field_formatter_settings_form($field, $instance, $view_mode, $form $element['trim_length'] = array( '#title' => t('Length'), '#type' => 'number', - '#size' => 20, '#default_value' => $settings['trim_length'], '#min' => 1, '#required' => TRUE, diff --git a/core/modules/filter/filter.module b/core/modules/filter/filter.module index 9f492fe3f16..1e6c28c0936 100644 --- a/core/modules/filter/filter.module +++ b/core/modules/filter/filter.module @@ -1363,8 +1363,6 @@ function _filter_url_settings($form, &$form_state, $filter, $format, $defaults) '#type' => 'number', '#title' => t('Maximum link text length'), '#default_value' => $filter->settings['filter_url_length'], - '#size' => 5, - '#maxlength' => 4, '#min' => 1, '#field_suffix' => t('characters'), '#description' => t('URLs longer than this number of characters will be truncated to prevent long strings that break formatting. The link itself will be retained; just the text portion of the link will be truncated.'), diff --git a/core/modules/image/image.admin.inc b/core/modules/image/image.admin.inc index c6b1356c070..f31d98ff617 100644 --- a/core/modules/image/image.admin.inc +++ b/core/modules/image/image.admin.inc @@ -450,7 +450,6 @@ function image_resize_form($data) { '#default_value' => isset($data['width']) ? $data['width'] : '', '#field_suffix' => ' ' . t('pixels'), '#required' => TRUE, - '#size' => 10, '#min' => 1, ); $form['height'] = array( @@ -459,7 +458,6 @@ function image_resize_form($data) { '#default_value' => isset($data['height']) ? $data['height'] : '', '#field_suffix' => ' ' . t('pixels'), '#required' => TRUE, - '#size' => 10, '#min' => 1, ); return $form; @@ -547,8 +545,6 @@ function image_rotate_form($data) { '#description' => t('The number of degrees the image should be rotated. Positive numbers are clockwise, negative are counter-clockwise.'), '#field_suffix' => '°', '#required' => TRUE, - '#size' => 6, - '#maxlength' => 4, ); $form['bgcolor'] = array( '#type' => 'textfield', diff --git a/core/modules/image/image.field.inc b/core/modules/image/image.field.inc index 07dc9e390c6..0fb657c59c2 100644 --- a/core/modules/image/image.field.inc +++ b/core/modules/image/image.field.inc @@ -91,8 +91,6 @@ function image_field_instance_settings_form($field, $instance) { '#title' => t('Maximum width'), '#title_display' => 'invisible', '#default_value' => $max_resolution[0], - '#size' => 5, - '#maxlength' => 5, '#min' => 1, '#field_suffix' => ' x ', ); @@ -101,8 +99,6 @@ function image_field_instance_settings_form($field, $instance) { '#title' => t('Maximum height'), '#title_display' => 'invisible', '#default_value' => $max_resolution[1], - '#size' => 5, - '#maxlength' => 5, '#min' => 1, '#field_suffix' => ' ' . t('pixels'), ); @@ -122,8 +118,6 @@ function image_field_instance_settings_form($field, $instance) { '#title' => t('Minimum width'), '#title_display' => 'invisible', '#default_value' => $min_resolution[0], - '#size' => 5, - '#maxlength' => 5, '#min' => 1, '#field_suffix' => ' x ', ); @@ -132,8 +126,6 @@ function image_field_instance_settings_form($field, $instance) { '#title' => t('Minimum height'), '#title_display' => 'invisible', '#default_value' => $min_resolution[1], - '#size' => 5, - '#maxlength' => 5, '#min' => 1, '#field_suffix' => ' ' . t('pixels'), ); diff --git a/core/modules/poll/poll.module b/core/modules/poll/poll.module index b62568c1a5a..7c3a27e24f4 100644 --- a/core/modules/poll/poll.module +++ b/core/modules/poll/poll.module @@ -389,8 +389,6 @@ function _poll_choice_form($key, $chid = NULL, $value = '', $votes = 0, $weight '#title' => $value !== '' ? t('Vote count for choice @label', array('@label' => $value)) : t('Vote count for new choice'), '#title_display' => 'invisible', '#default_value' => $votes, - '#size' => 5, - '#maxlength' => 7, '#min' => 0, '#parents' => array('choice', $key, 'chvotes'), '#access' => user_access('administer nodes'), diff --git a/core/modules/search/search.admin.inc b/core/modules/search/search.admin.inc index 5355c6a4909..bef8fd90d64 100644 --- a/core/modules/search/search.admin.inc +++ b/core/modules/search/search.admin.inc @@ -93,9 +93,8 @@ function search_admin_settings($form) { '#type' => 'number', '#title' => t('Minimum word length to index'), '#default_value' => variable_get('minimum_word_size', 3), - '#size' => 5, - '#maxlength' => 3, '#min' => 1, + '#max' => 1000, '#description' => t('The number of characters a word has to be to be indexed. A lower setting means better search result ranking, but also a larger database. Each search query must contain at least one keyword that is this size (or longer).') ); $form['indexing_settings']['overlap_cjk'] = array( diff --git a/core/modules/system/image.gd.inc b/core/modules/system/image.gd.inc index 4dd5ea1903d..b8dd8221b7c 100644 --- a/core/modules/system/image.gd.inc +++ b/core/modules/system/image.gd.inc @@ -23,8 +23,6 @@ function image_gd_settings() { '#type' => 'number', '#title' => t('JPEG quality'), '#description' => t('Define the image quality for JPEG manipulations. Ranges from 0 to 100. Higher values mean better image quality but bigger files.'), - '#size' => 10, - '#maxlength' => 3, '#min' => 0, '#max' => 100, '#default_value' => variable_get('image_jpeg_quality', 75), diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 34b6db2947e..c8df3c5b5f8 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -405,9 +405,7 @@ function system_element_info() { ); $types['number'] = array( '#input' => TRUE, - '#size' => 30, '#step' => 1, - '#maxlength' => 128, '#process' => array('ajax_process_form'), '#element_validate' => array('form_validate_number'), '#theme' => 'number', @@ -415,11 +413,9 @@ function system_element_info() { ); $types['range'] = array( '#input' => TRUE, - '#size' => 30, '#step' => 1, '#min' => 0, '#max' => 100, - '#maxlength' => 128, '#process' => array('ajax_process_form'), '#element_validate' => array('form_validate_number'), '#theme' => 'range', diff --git a/core/modules/system/tests/form.test b/core/modules/system/tests/form.test index b64fdd71823..ada1a1beb26 100644 --- a/core/modules/system/tests/form.test +++ b/core/modules/system/tests/form.test @@ -365,6 +365,20 @@ class FormsTestCase extends DrupalWebTestCase { } } + /** + * Tests default value handling of #type 'range' elements. + */ + function testRange() { + $values = json_decode($this->drupalPost('form-test/range', array(), 'Submit')); + $this->assertEqual($values->with_default_value, 18); + $this->assertEqual($values->float, 10.5); + $this->assertEqual($values->integer, 6); + $this->assertEqual($values->offset, 6.9); + + $this->drupalPost('form-test/range/invalid', array(), 'Submit'); + $this->assertFieldByXPath('//input[@type="range" and contains(@class, "error")]', NULL, 'Range element has the error class.'); + } + /** * Test handling of disabled elements. * diff --git a/core/modules/system/tests/modules/form_test/form_test.module b/core/modules/system/tests/modules/form_test/form_test.module index f42b5f5ddb4..e892f767f6e 100644 --- a/core/modules/system/tests/modules/form_test/form_test.module +++ b/core/modules/system/tests/modules/form_test/form_test.module @@ -145,6 +145,18 @@ function form_test_menu() { 'page arguments' => array('form_test_number', 'range'), 'access callback' => TRUE, ); + $items['form-test/range']= array( + 'title' => 'Range', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('form_test_range'), + 'access callback' => TRUE, + ); + $items['form-test/range/invalid'] = array( + 'title' => 'Invalid range', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('form_test_range_invalid'), + 'access callback' => TRUE, + ); $items['form-test/checkboxes-radios'] = array( 'title' => t('Checkboxes, Radios'), 'page callback' => 'drupal_get_form', @@ -1276,6 +1288,80 @@ function form_test_number($form, &$form_state, $element = 'number') { return $form; } +/** + * Form constructor for testing #type 'range' elements. + * + * @see form_test_range_submit() + * @ingroup forms + */ +function form_test_range($form, &$form_state) { + $form['with_default_value'] = array( + '#type' => 'range', + '#title' => 'Range with default value', + '#min' => 10, + '#max' => 20, + '#step' => 2, + '#default_value' => 18, + '#description' => 'The default value is 18.', + ); + $form['float'] = array( + '#type' => 'range', + '#title' => 'Float', + '#min' => 10, + '#max' => 11, + '#step' => 'any', + '#description' => 'Floating point number between 10 and 11.', + ); + $form['integer'] = array( + '#type' => 'range', + '#title' => 'Integer', + '#min' => 2, + '#max' => 8, + '#step' => 2, + '#description' => 'Even integer between 2 and 8.', + ); + $form['offset'] = array( + '#type' => 'range', + '#title' => 'Offset', + '#min' => 2.9, + '#max' => 10.9, + '#description' => 'Value between 2.9 and 10.9.', + ); + $form['submit'] = array( + '#type' => 'submit', + '#value' => 'Submit', + ); + return $form; +} + +/** + * Form submission handler for form_test_range(). + */ +function form_test_range_submit($form, &$form_state) { + drupal_json_output($form_state['values']); + exit; +} + +/** + * Form constructor for testing invalid #type 'range' elements. + * + * @ingroup forms + */ +function form_test_range_invalid($form, &$form_state) { + $form['minmax'] = array( + '#type' => 'range', + '#min' => 10, + '#max' => 5, + '#title' => 'Invalid range', + '#description' => 'Minimum greater than maximum.', + ); + $form['submit'] = array( + '#type' => 'submit', + '#value' => 'Submit', + ); + return $form; +} + /** * Builds a form to test the placeholder attribute. */ diff --git a/core/modules/user/user.admin.inc b/core/modules/user/user.admin.inc index 8de4fb92d9d..c65883ace6b 100644 --- a/core/modules/user/user.admin.inc +++ b/core/modules/user/user.admin.inc @@ -404,8 +404,6 @@ function user_admin_settings() { '#type' => 'number', '#title' => t('Picture upload file size'), '#default_value' => variable_get('user_picture_file_size', '30'), - '#size' => 10, - '#maxlength' => 10, '#min' => 0, '#field_suffix' => ' ' . t('KB'), '#description' => t('Maximum allowed file size for uploaded pictures. Upload size is normally limited only by the PHP maximum post and file upload settings, and images are automatically scaled down to the dimensions specified above.'), From bd30dbfc09eab7438f7ca4a60a4abeaddf49fbf2 Mon Sep 17 00:00:00 2001 From: catch Date: Tue, 8 May 2012 11:57:33 +0900 Subject: [PATCH 02/11] Issue #1481560 by nod_: Add 'use strict' to all core JavaScript to enforce clean code. --- core/misc/ajax.js | 2 ++ core/misc/authorize.js | 3 ++- core/misc/autocomplete.js | 2 ++ core/misc/batch.js | 2 ++ core/misc/collapse.js | 2 ++ core/misc/drupal.js | 2 ++ core/misc/form.js | 2 ++ core/misc/machine-name.js | 2 ++ core/misc/progress.js | 2 ++ core/misc/states.js | 2 ++ core/misc/tabledrag.js | 2 ++ core/misc/tableheader.js | 2 ++ core/misc/tableselect.js | 2 ++ core/misc/timezone.js | 2 ++ core/misc/vertical-tabs.js | 2 ++ core/modules/block/block.js | 2 ++ core/modules/book/book.js | 2 ++ core/modules/color/color.js | 2 ++ core/modules/color/preview.js | 3 +++ core/modules/comment/comment-node-form.js | 2 ++ core/modules/contextual/contextual.js | 2 ++ core/modules/dashboard/dashboard.js | 2 ++ core/modules/field/modules/text/text.js | 2 ++ core/modules/field_ui/field_ui.js | 2 ++ core/modules/file/file.js | 2 ++ core/modules/filter/filter.admin.js | 2 ++ core/modules/filter/filter.js | 2 ++ core/modules/locale/locale.datepicker.js | 2 ++ core/modules/menu/menu.admin.js | 2 ++ core/modules/menu/menu.js | 2 ++ core/modules/node/content_types.js | 2 ++ core/modules/node/node.js | 2 ++ core/modules/openid/openid.js | 2 ++ core/modules/overlay/overlay-child.js | 2 ++ core/modules/overlay/overlay-parent.js | 2 ++ core/modules/path/path.js | 2 ++ core/modules/shortcut/shortcut.admin.js | 2 ++ core/modules/simpletest/simpletest.js | 2 ++ core/modules/statistics/statistics.js | 3 +++ core/modules/system/system.cron.js | 2 ++ core/modules/system/system.js | 2 ++ core/modules/taxonomy/taxonomy.js | 2 ++ core/modules/toolbar/toolbar.js | 2 ++ core/modules/user/user.js | 3 +++ core/modules/user/user.permissions.js | 2 ++ core/themes/bartik/color/preview.js | 4 +++- 46 files changed, 96 insertions(+), 2 deletions(-) diff --git a/core/misc/ajax.js b/core/misc/ajax.js index 072cd2bf660..d599799ae67 100644 --- a/core/misc/ajax.js +++ b/core/misc/ajax.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + /** * Provides Ajax page updating via jQuery $.ajax (Asynchronous JavaScript and XML). * diff --git a/core/misc/authorize.js b/core/misc/authorize.js index d522a5ba9be..aa4575d8375 100644 --- a/core/misc/authorize.js +++ b/core/misc/authorize.js @@ -1,4 +1,3 @@ - /** * @file * Conditionally hide or show the appropriate settings and saved defaults @@ -7,6 +6,8 @@ (function ($) { +"use strict"; + Drupal.behaviors.authorizeFileTransferForm = { attach: function(context) { $('#edit-connection-settings-authorize-filetransfer-default').change(function() { diff --git a/core/misc/autocomplete.js b/core/misc/autocomplete.js index a4f63354f90..8b0dd7237f1 100644 --- a/core/misc/autocomplete.js +++ b/core/misc/autocomplete.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + /** * Attaches the autocomplete behavior to all required fields. */ diff --git a/core/misc/batch.js b/core/misc/batch.js index 6d28b69ad1f..b83776dd1f6 100644 --- a/core/misc/batch.js +++ b/core/misc/batch.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + /** * Attaches the batch behavior to progress bars. */ diff --git a/core/misc/collapse.js b/core/misc/collapse.js index 28281a1cb4a..b484a6fce3e 100644 --- a/core/misc/collapse.js +++ b/core/misc/collapse.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + /** * Toggle the visibility of a fieldset using smooth animations. */ diff --git a/core/misc/drupal.js b/core/misc/drupal.js index 5bbbf511023..43a78f3f062 100644 --- a/core/misc/drupal.js +++ b/core/misc/drupal.js @@ -5,6 +5,8 @@ jQuery.noConflict(); (function ($) { +"use strict"; + /** * Attach all registered behaviors to a page element. * diff --git a/core/misc/form.js b/core/misc/form.js index 4dc5b8c8bf3..0e7cf7b1359 100644 --- a/core/misc/form.js +++ b/core/misc/form.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + /** * Retrieves the summary for the first element. */ diff --git a/core/misc/machine-name.js b/core/misc/machine-name.js index ffe774f9101..3cb7351cac7 100644 --- a/core/misc/machine-name.js +++ b/core/misc/machine-name.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + /** * Attach the machine-readable name form element behavior. */ diff --git a/core/misc/progress.js b/core/misc/progress.js index b0e125cf32a..343b9ad8203 100644 --- a/core/misc/progress.js +++ b/core/misc/progress.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + /** * A progressbar object. Initialized with the given id. Must be inserted into * the DOM afterwards through progressBar.element. diff --git a/core/misc/states.js b/core/misc/states.js index 955e8625b81..fa7a1017523 100644 --- a/core/misc/states.js +++ b/core/misc/states.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + /** * The base States namespace. * diff --git a/core/misc/tabledrag.js b/core/misc/tabledrag.js index 16800e03428..273dcc1b28e 100644 --- a/core/misc/tabledrag.js +++ b/core/misc/tabledrag.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + /** * Drag and drop table rows with field manipulation. * diff --git a/core/misc/tableheader.js b/core/misc/tableheader.js index aa1c8bb4588..225cb7305ba 100644 --- a/core/misc/tableheader.js +++ b/core/misc/tableheader.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + /** * Attaches sticky table headers. */ diff --git a/core/misc/tableselect.js b/core/misc/tableselect.js index b7011e0eea1..2bf708efab6 100644 --- a/core/misc/tableselect.js +++ b/core/misc/tableselect.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + Drupal.behaviors.tableSelect = { attach: function (context, settings) { // Select the inner-most table in case of nested tables. diff --git a/core/misc/timezone.js b/core/misc/timezone.js index 6f82bc1d3ea..29a6650a449 100644 --- a/core/misc/timezone.js +++ b/core/misc/timezone.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + /** * Set the client's system time zone as default values of form fields. */ diff --git a/core/misc/vertical-tabs.js b/core/misc/vertical-tabs.js index 65e56831984..baae1d137b3 100644 --- a/core/misc/vertical-tabs.js +++ b/core/misc/vertical-tabs.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + /** * This script transforms a set of fieldsets into a stack of vertical * tabs. Another tab pane can be selected by clicking on the respective diff --git a/core/modules/block/block.js b/core/modules/block/block.js index dabb5701a51..e20001714e5 100644 --- a/core/modules/block/block.js +++ b/core/modules/block/block.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + /** * Provide the summary information for the block settings vertical tabs. */ diff --git a/core/modules/book/book.js b/core/modules/book/book.js index e6ab4facb96..b7a6713faa8 100644 --- a/core/modules/book/book.js +++ b/core/modules/book/book.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + Drupal.behaviors.bookFieldsetSummaries = { attach: function (context) { $(context).find('fieldset.book-outline-form').drupalSetSummary(function (context) { diff --git a/core/modules/color/color.js b/core/modules/color/color.js index d833a4b7177..31c526e79db 100644 --- a/core/modules/color/color.js +++ b/core/modules/color/color.js @@ -5,6 +5,8 @@ (function ($) { +"use strict"; + Drupal.behaviors.color = { attach: function (context, settings) { var i, j, colors, field_name; diff --git a/core/modules/color/preview.js b/core/modules/color/preview.js index 69c3897a762..9e1998515ce 100644 --- a/core/modules/color/preview.js +++ b/core/modules/color/preview.js @@ -4,6 +4,9 @@ */ (function ($) { + + "use strict"; + Drupal.color = { callback: function(context, settings, form, farb, height, width) { // Solid background. diff --git a/core/modules/comment/comment-node-form.js b/core/modules/comment/comment-node-form.js index 51ea4925690..0249d96dadc 100644 --- a/core/modules/comment/comment-node-form.js +++ b/core/modules/comment/comment-node-form.js @@ -5,6 +5,8 @@ (function ($) { +"use strict"; + Drupal.behaviors.commentFieldsetSummaries = { attach: function (context) { var $context = $(context); diff --git a/core/modules/contextual/contextual.js b/core/modules/contextual/contextual.js index 5c477264fd9..3b7aeeb5089 100644 --- a/core/modules/contextual/contextual.js +++ b/core/modules/contextual/contextual.js @@ -5,6 +5,8 @@ (function ($) { +"use strict"; + Drupal.contextualLinks = Drupal.contextualLinks || {}; /** diff --git a/core/modules/dashboard/dashboard.js b/core/modules/dashboard/dashboard.js index 39d87c20e9c..e1a43e02fa8 100644 --- a/core/modules/dashboard/dashboard.js +++ b/core/modules/dashboard/dashboard.js @@ -5,6 +5,8 @@ (function ($) { +"use strict"; + /** * Implements Drupal.behaviors for the Dashboard module. */ diff --git a/core/modules/field/modules/text/text.js b/core/modules/field/modules/text/text.js index 01a49a738af..efc5579fc5a 100644 --- a/core/modules/field/modules/text/text.js +++ b/core/modules/field/modules/text/text.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + /** * Auto-hide summary textarea if empty and show hide and unhide links. */ diff --git a/core/modules/field_ui/field_ui.js b/core/modules/field_ui/field_ui.js index 6de5c154389..87c10910c9a 100644 --- a/core/modules/field_ui/field_ui.js +++ b/core/modules/field_ui/field_ui.js @@ -5,6 +5,8 @@ (function($) { +"use strict"; + Drupal.behaviors.fieldUIFieldOverview = { attach: function (context, settings) { $(context).find('table#field-overview').once('field-overview', function () { diff --git a/core/modules/file/file.js b/core/modules/file/file.js index a934afe2d7e..cec3fe8ccba 100644 --- a/core/modules/file/file.js +++ b/core/modules/file/file.js @@ -9,6 +9,8 @@ (function ($) { +"use strict"; + /** * Attach behaviors to managed file element upload fields. */ diff --git a/core/modules/filter/filter.admin.js b/core/modules/filter/filter.admin.js index 43cda26ef56..b002041acdb 100644 --- a/core/modules/filter/filter.admin.js +++ b/core/modules/filter/filter.admin.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + Drupal.behaviors.filterStatus = { attach: function (context, settings) { var $context = $(context); diff --git a/core/modules/filter/filter.js b/core/modules/filter/filter.js index db5f42a4927..948273791fc 100644 --- a/core/modules/filter/filter.js +++ b/core/modules/filter/filter.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + /** * Automatically display the guidelines of the selected text format. */ diff --git a/core/modules/locale/locale.datepicker.js b/core/modules/locale/locale.datepicker.js index 81f1e17b3cf..024c1e291c1 100644 --- a/core/modules/locale/locale.datepicker.js +++ b/core/modules/locale/locale.datepicker.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + $.datepicker.regional['drupal-locale'] = { closeText: Drupal.t('Done'), prevText: Drupal.t('Prev'), diff --git a/core/modules/menu/menu.admin.js b/core/modules/menu/menu.admin.js index 42d69d533e1..8bbb6ad5413 100644 --- a/core/modules/menu/menu.admin.js +++ b/core/modules/menu/menu.admin.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + Drupal.behaviors.menuChangeParentItems = { attach: function (context, settings) { $('fieldset#edit-menu input').each(function () { diff --git a/core/modules/menu/menu.js b/core/modules/menu/menu.js index f315e7aa78e..f3bfb1c874b 100644 --- a/core/modules/menu/menu.js +++ b/core/modules/menu/menu.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + Drupal.behaviors.menuFieldsetSummaries = { attach: function (context) { $(context).find('fieldset.menu-link-form').drupalSetSummary(function (context) { diff --git a/core/modules/node/content_types.js b/core/modules/node/content_types.js index 43cfa378829..5c1c44e0f15 100644 --- a/core/modules/node/content_types.js +++ b/core/modules/node/content_types.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + Drupal.behaviors.contentTypes = { attach: function (context) { var $context = $(context); diff --git a/core/modules/node/node.js b/core/modules/node/node.js index 899016408d5..0899d3c50cb 100644 --- a/core/modules/node/node.js +++ b/core/modules/node/node.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + Drupal.behaviors.nodeFieldsetSummaries = { attach: function (context) { var $context = $(context); diff --git a/core/modules/openid/openid.js b/core/modules/openid/openid.js index 754efb157f6..53a0cb3d588 100644 --- a/core/modules/openid/openid.js +++ b/core/modules/openid/openid.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + Drupal.behaviors.openid = { attach: function (context) { var $context = $(context); diff --git a/core/modules/overlay/overlay-child.js b/core/modules/overlay/overlay-child.js index ff111d89d4b..29a97901251 100644 --- a/core/modules/overlay/overlay-child.js +++ b/core/modules/overlay/overlay-child.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + /** * Attach the child dialog behavior to new content. */ diff --git a/core/modules/overlay/overlay-parent.js b/core/modules/overlay/overlay-parent.js index aa90d9bb506..6537cb640f2 100644 --- a/core/modules/overlay/overlay-parent.js +++ b/core/modules/overlay/overlay-parent.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + /** * Open the overlay, or load content into it, when an admin link is clicked. */ diff --git a/core/modules/path/path.js b/core/modules/path/path.js index b20378e1da8..41b6e8f8e9b 100644 --- a/core/modules/path/path.js +++ b/core/modules/path/path.js @@ -4,6 +4,8 @@ */ (function ($) { +"use strict"; + Drupal.behaviors.pathFieldsetSummaries = { attach: function (context) { $(context).find('fieldset.path-form').drupalSetSummary(function (context) { diff --git a/core/modules/shortcut/shortcut.admin.js b/core/modules/shortcut/shortcut.admin.js index 2647f343e1a..4530df52f92 100644 --- a/core/modules/shortcut/shortcut.admin.js +++ b/core/modules/shortcut/shortcut.admin.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + /** * Handle the concept of a fixed number of slots. * diff --git a/core/modules/simpletest/simpletest.js b/core/modules/simpletest/simpletest.js index 2199fede78c..1e2d2465d14 100644 --- a/core/modules/simpletest/simpletest.js +++ b/core/modules/simpletest/simpletest.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + /** * Add the cool table collapsing on the testing overview page. */ diff --git a/core/modules/statistics/statistics.js b/core/modules/statistics/statistics.js index 65793d36e64..5618c55f2d5 100644 --- a/core/modules/statistics/statistics.js +++ b/core/modules/statistics/statistics.js @@ -1,4 +1,7 @@ (function ($) { + + "use strict"; + $(document).ready(function() { var nid = Drupal.settings.statistics.nid; var basePath = Drupal.settings.basePath diff --git a/core/modules/system/system.cron.js b/core/modules/system/system.cron.js index aa5b3511386..0686982dc3a 100644 --- a/core/modules/system/system.cron.js +++ b/core/modules/system/system.cron.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + /** * Checks to see if the cron should be automatically run. */ diff --git a/core/modules/system/system.js b/core/modules/system/system.js index ab00426b202..03bee22de06 100644 --- a/core/modules/system/system.js +++ b/core/modules/system/system.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + /** * Show/hide the 'Email site administrator when updates are available' checkbox * on the install page. diff --git a/core/modules/taxonomy/taxonomy.js b/core/modules/taxonomy/taxonomy.js index 035dc29640e..0fe6e9a9e9f 100644 --- a/core/modules/taxonomy/taxonomy.js +++ b/core/modules/taxonomy/taxonomy.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + /** * Move a block in the blocks table from one region to another via select list. * diff --git a/core/modules/toolbar/toolbar.js b/core/modules/toolbar/toolbar.js index d3452841460..ee8bddbdc62 100644 --- a/core/modules/toolbar/toolbar.js +++ b/core/modules/toolbar/toolbar.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + Drupal.toolbar = Drupal.toolbar || {}; /** diff --git a/core/modules/user/user.js b/core/modules/user/user.js index 59a178e89e1..147c4c2a7bb 100644 --- a/core/modules/user/user.js +++ b/core/modules/user/user.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + /** * Attach handlers to evaluate the strength of any password fields and to check * that its confirmation is correct. @@ -157,6 +159,7 @@ Drupal.evaluatePasswordStrength = function (password, translate) { strength = 5; } + var indicatorText; // Based on the strength, work out what text should be shown by the password strength meter. if (strength < 60) { indicatorText = translate.weak; diff --git a/core/modules/user/user.permissions.js b/core/modules/user/user.permissions.js index 896c9367874..4b6d4c957de 100644 --- a/core/modules/user/user.permissions.js +++ b/core/modules/user/user.permissions.js @@ -1,5 +1,7 @@ (function ($) { +"use strict"; + /** * Shows checked and disabled checkboxes for inherited permissions. */ diff --git a/core/themes/bartik/color/preview.js b/core/themes/bartik/color/preview.js index aeb41717737..531deecfe1c 100644 --- a/core/themes/bartik/color/preview.js +++ b/core/themes/bartik/color/preview.js @@ -2,8 +2,10 @@ * @file * Preview for the Bartik theme. */ - (function ($) { + + "use strict"; + Drupal.color = { logoChanged: false, callback: function(context, settings, form, farb, height, width) { From a82955bfd57c2262f272da7a51615aecc13555d8 Mon Sep 17 00:00:00 2001 From: catch Date: Tue, 8 May 2012 12:00:06 +0900 Subject: [PATCH 03/11] Issue #1174766 by Niklas Fiekas, ericduran: Added Support the #pattern FAPI property for native HTML5 pattern attribute. --- core/includes/form.inc | 50 ++++++++++++++++ core/modules/system/system.module | 10 ++-- core/modules/system/tests/form.test | 59 +++++++++++++++++++ .../tests/modules/form_test/form_test.module | 41 +++++++++++++ 4 files changed, 155 insertions(+), 5 deletions(-) diff --git a/core/includes/form.inc b/core/includes/form.inc index 6d577806d19..a555bf09a16 100644 --- a/core/includes/form.inc +++ b/core/includes/form.inc @@ -3213,6 +3213,56 @@ function form_process_actions($element, &$form_state) { return $element; } +/** + * #process callback for #pattern form element property. + * + * @param $element + * An associative array containing the properties and children of the + * generic input element. + * @param $form_state + * The $form_state array for the form this element belongs to. + * + * @return + * The processed element. + * + * @see form_validate_pattern() + */ +function form_process_pattern($element, &$form_state) { + if (isset($element['#pattern']) && !isset($element['#attributes']['pattern'])) { + $element['#attributes']['pattern'] = $element['#pattern']; + $element['#element_validate'][] = 'form_validate_pattern'; + } + + return $element; +} + +/** + * #element_validate callback for #pattern form element property. + * + * @param $element + * An associative array containing the properties and children of the + * generic form element. + * @param $form_state + * The $form_state array for the form this element belongs to. + * + * @see form_process_pattern() + */ +function form_validate_pattern($element, &$form_state) { + if ($element['#value'] !== '') { + // The pattern must match the entire string and should have the same + // behavior as the RegExp object in ECMA 262. + // - Use bracket-style delimiters to avoid introducing a special delimiter + // character like '/' that would have to be escaped. + // - Put in brackets so that the pattern can't interfere with what's + // prepended and appended. + $pattern = '{^(?:' . $element['#pattern'] . ')$}'; + + if (!preg_match($pattern, $element['#value'])) { + form_error($element, t('%name field is not in the right format.', array('%name' => $element['#title']))); + } + } +} + /** * Processes a container element. * diff --git a/core/modules/system/system.module b/core/modules/system/system.module index c8df3c5b5f8..987137b5526 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -361,7 +361,7 @@ function system_element_info() { '#size' => 60, '#maxlength' => 128, '#autocomplete_path' => FALSE, - '#process' => array('form_process_autocomplete', 'ajax_process_form'), + '#process' => array('form_process_autocomplete', 'ajax_process_form', 'form_process_pattern'), '#theme' => 'textfield', '#theme_wrappers' => array('form_element'), ); @@ -370,7 +370,7 @@ function system_element_info() { '#size' => 30, '#maxlength' => 128, '#autocomplete_path' => FALSE, - '#process' => array('form_process_autocomplete', 'ajax_process_form'), + '#process' => array('form_process_autocomplete', 'ajax_process_form', 'form_process_pattern'), '#theme' => 'tel', '#theme_wrappers' => array('form_element'), ); @@ -379,7 +379,7 @@ function system_element_info() { '#size' => 60, '#maxlength' => EMAIL_MAX_LENGTH, '#autocomplete_path' => FALSE, - '#process' => array('form_process_autocomplete', 'ajax_process_form'), + '#process' => array('form_process_autocomplete', 'ajax_process_form', 'form_process_pattern'), '#element_validate' => array('form_validate_email'), '#theme' => 'email', '#theme_wrappers' => array('form_element'), @@ -389,7 +389,7 @@ function system_element_info() { '#size' => 60, '#maxlength' => 255, '#autocomplete_path' => FALSE, - '#process' => array('form_process_autocomplete', 'ajax_process_form'), + '#process' => array('form_process_autocomplete', 'ajax_process_form', 'form_process_pattern'), '#element_validate' => array('form_validate_url'), '#theme' => 'url', '#theme_wrappers' => array('form_element'), @@ -437,7 +437,7 @@ function system_element_info() { '#input' => TRUE, '#size' => 60, '#maxlength' => 128, - '#process' => array('ajax_process_form'), + '#process' => array('ajax_process_form', 'form_process_pattern'), '#theme' => 'password', '#theme_wrappers' => array('form_element'), ); diff --git a/core/modules/system/tests/form.test b/core/modules/system/tests/form.test index ada1a1beb26..dbb2ff5367c 100644 --- a/core/modules/system/tests/form.test +++ b/core/modules/system/tests/form.test @@ -784,6 +784,65 @@ class FormValidationTestCase extends DrupalWebTestCase { $this->assertText(t('!name field is required.', array('!name' => 'Title'))); $this->assertText('Test element is invalid'); } + + /** + * Tests #pattern validation. + */ + function testPatternValidation() { + $textfield_error = t('%name field is not in the right format.', array('%name' => 'One digit followed by lowercase letters')); + $tel_error = t('%name field is not in the right format.', array('%name' => 'Everything except numbers')); + $password_error = t('%name field is not in the right format.', array('%name' => 'Password')); + + // Invalid textfield, valid tel. + $edit = array( + 'textfield' => 'invalid', + 'tel' => 'valid', + ); + $this->drupalPost('form-test/pattern', $edit, 'Submit'); + $this->assertRaw($textfield_error); + $this->assertNoRaw($tel_error); + $this->assertNoRaw($password_error); + + // Valid textfield, invalid tel, valid password. + $edit = array( + 'textfield' => '7seven', + 'tel' => '818937', + 'password' => '0100110', + ); + $this->drupalPost('form-test/pattern', $edit, 'Submit'); + $this->assertNoRaw($textfield_error); + $this->assertRaw($tel_error); + $this->assertNoRaw($password_error); + + // Non required fields are not validated if empty. + $edit = array( + 'textfield' => '', + 'tel' => '', + ); + $this->drupalPost('form-test/pattern', $edit, 'Submit'); + $this->assertNoRaw($textfield_error); + $this->assertNoRaw($tel_error); + $this->assertNoRaw($password_error); + + // Invalid password. + $edit = array( + 'password' => $this->randomName(), + ); + $this->drupalPost('form-test/pattern', $edit, 'Submit'); + $this->assertNoRaw($textfield_error); + $this->assertNoRaw($tel_error); + $this->assertRaw($password_error); + + // The pattern attribute overrides #pattern and is not validated on the + // server side. + $edit = array( + 'textfield' => '', + 'tel' => '', + 'url' => 'http://www.example.com/', + ); + $this->drupalPost('form-test/pattern', $edit, 'Submit'); + $this->assertNoRaw(t('%name field is not in the right format.', array('%name' => 'Client side validation'))); + } } /** diff --git a/core/modules/system/tests/modules/form_test/form_test.module b/core/modules/system/tests/modules/form_test/form_test.module index e892f767f6e..f681c75c691 100644 --- a/core/modules/system/tests/modules/form_test/form_test.module +++ b/core/modules/system/tests/modules/form_test/form_test.module @@ -37,6 +37,12 @@ function form_test_menu() { 'access callback' => TRUE, 'type' => MENU_CALLBACK, ); + $items['form-test/pattern'] = array( + 'title' => 'Pattern validation', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('form_test_pattern_form'), + 'access callback' => TRUE, + ); $items['form_test/tableselect/multiple-true'] = array( 'title' => 'Tableselect checkboxes test', @@ -531,6 +537,41 @@ function form_test_limit_validation_errors_form_partial_submit($form, $form_stat } } +/** + * Builds a simple form using the FAPI #pattern proterty. + */ +function form_test_pattern_form($form, &$form_state) { + $form['textfield'] = array( + '#type' => 'textfield', + '#title' => 'One digit followed by lowercase letters', + '#pattern' => '[0-9][a-z]+', + ); + $form['tel'] = array( + '#type' => 'tel', + '#title' => 'Everything except numbers', + '#pattern' => '[^\d]*', + ); + $form['password'] = array( + '#type' => 'password', + '#title' => 'Password', + '#pattern' => '[01]+', + ); + $form['url'] = array( + '#type' => 'url', + '#title' => 'Client side validation', + '#decription' => 'Just client side validation, using the #pattern attribute.', + '#attributes' => array( + 'pattern' => '.*foo.*', + ), + '#pattern' => 'ignored', + ); + $form['submit'] = array( + '#type' => 'submit', + '#value' => 'Submit', + ); + return $form; +} + /** * Create a header and options array. Helper function for callbacks. */ From 9be8c892ff0630381841aa1253b471e20fc745f1 Mon Sep 17 00:00:00 2001 From: catch Date: Tue, 8 May 2012 13:53:51 +0900 Subject: [PATCH 04/11] Issue #1541958 by sun, alexpott: Split setUp() into specific sub-methods. --- .../simpletest/drupal_web_test_case.php | 16 ++- .../modules/system/tests/upgrade/upgrade.test | 122 ++++-------------- 2 files changed, 36 insertions(+), 102 deletions(-) diff --git a/core/modules/simpletest/drupal_web_test_case.php b/core/modules/simpletest/drupal_web_test_case.php index ac74fc8c602..ede61046222 100644 --- a/core/modules/simpletest/drupal_web_test_case.php +++ b/core/modules/simpletest/drupal_web_test_case.php @@ -1600,10 +1600,15 @@ class DrupalWebTestCase extends DrupalTestCase { // Delete temporary files directory. file_unmanaged_delete_recursive($this->originalFileDirectory . '/simpletest/' . substr($this->databasePrefix, 10)); - // Remove all prefixed tables (all the tables in the schema). - $schema = drupal_get_schema(NULL, TRUE); - foreach ($schema as $name => $table) { - db_drop_table($name); + // Remove all prefixed tables. + $tables = db_find_tables($this->databasePrefix . '%'); + foreach ($tables as $table) { + if (db_drop_table(substr($table, strlen($this->databasePrefix)))) { + unset($tables[$table]); + } + } + if (!empty($tables)) { + $this->fail('Failed to drop all prefixed tables.'); } // Get back to the original connection. @@ -1637,6 +1642,9 @@ class DrupalWebTestCase extends DrupalTestCase { // Rebuild caches. $this->refreshVariables(); + // Reset public files directory. + $GLOBALS['conf']['file_public_path'] = $this->originalFileDirectory; + // Reset configuration globals. $GLOBALS['config_directory_name'] = $this->originalConfigDirectory; $GLOBALS['config_signature_key'] = $this->originalConfigSignatureKey; diff --git a/core/modules/system/tests/upgrade/upgrade.test b/core/modules/system/tests/upgrade/upgrade.test index f11e68aa0ef..aa1ad6f509e 100644 --- a/core/modules/system/tests/upgrade/upgrade.test +++ b/core/modules/system/tests/upgrade/upgrade.test @@ -62,7 +62,11 @@ abstract class UpgradePathTestCase extends DrupalWebTestCase { } /** - * Overrides DrupalWebTestCase::setUp() specialized for upgrade testing. + * Overrides DrupalWebTestCase::setUp() for upgrade testing. + * + * @see DrupalWebTestCase::prepareDatabasePrefix() + * @see DrupalWebTestCase::changeDatabasePrefix() + * @see DrupalWebTestCase::prepareEnvironment() */ protected function setUp() { global $user, $language_interface, $conf; @@ -76,54 +80,27 @@ abstract class UpgradePathTestCase extends DrupalWebTestCase { $this->loadedModules = module_list(); - // Generate a temporary prefixed database to ensure that tests have a clean starting point. - $this->databasePrefix = 'simpletest' . mt_rand(1000, 1000000); - db_update('simpletest_test_id') - ->fields(array('last_prefix' => $this->databasePrefix)) - ->condition('test_id', $this->testId) - ->execute(); + // Create the database prefix for this test. + $this->prepareDatabasePrefix(); - // Clone the current connection and replace the current prefix. - $connection_info = Database::getConnectionInfo('default'); - Database::renameConnection('default', 'simpletest_original_default'); - foreach ($connection_info as $target => $value) { - $connection_info[$target]['prefix'] = array( - 'default' => $value['prefix']['default'] . $this->databasePrefix, - ); - } - Database::addConnectionInfo('default', 'default', $connection_info['default']); + // Prepare the environment for running tests. + $this->prepareEnvironment(); - // Store necessary current values before switching to prefixed database. - $this->originalLanguage = $language_interface; - $this->originalLanguageDefault = variable_get('language_default'); - $this->originalFileDirectory = variable_get('file_public_path', conf_path() . '/files'); - $this->originalProfile = drupal_get_profile(); + // Reset all statics and variables to perform tests in a clean environment. + $conf = array(); + drupal_static_reset(); + + // Change the database prefix. + // All static variables need to be reset before the database prefix is + // changed, since Drupal\Core\Utility\CacheArray implementations attempt to + // write back to persistent caches when they are destructed. + $this->changeDatabasePrefix(); // Unregister the registry. // This is required to make sure that the database layer works properly. spl_autoload_unregister('drupal_autoload_class'); spl_autoload_unregister('drupal_autoload_interface'); - // Create test directories ahead of installation so fatal errors and debug - // information can be logged during installation process. - // Use mock files directories with the same prefix as the database. - $public_files_directory = $this->originalFileDirectory . '/simpletest/' . substr($this->databasePrefix, 10); - $private_files_directory = $public_files_directory . '/private'; - $temp_files_directory = $private_files_directory . '/temp'; - - // Create the directories. - file_prepare_directory($public_files_directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); - file_prepare_directory($private_files_directory, FILE_CREATE_DIRECTORY); - file_prepare_directory($temp_files_directory, FILE_CREATE_DIRECTORY); - $this->generatedTestFiles = FALSE; - - // Log fatal errors. - ini_set('log_errors', 1); - ini_set('error_log', $public_files_directory . '/error.log'); - - // Reset all statics and variables to perform tests in a clean environment. - $conf = array(); - // Load the database from the portable PHP dump. // The files may be gzipped. foreach ($this->databaseDumpFiles as $file) { @@ -134,15 +111,16 @@ abstract class UpgradePathTestCase extends DrupalWebTestCase { } // Set path variables. - $this->variable_set('file_public_path', $public_files_directory); - $this->variable_set('file_private_path', $private_files_directory); - $this->variable_set('file_temporary_path', $temp_files_directory); + $this->variable_set('file_public_path', $this->public_files_directory); + $this->variable_set('file_private_path', $this->private_files_directory); + $this->variable_set('file_temporary_path', $this->temp_files_directory); $this->pass('Finished loading the dump.'); - // Load user 1. - $this->originalUser = $user; + // Ensure that the session is not written to the new environment and replace + // the global $user session with uid 1 from the new test site. drupal_save_session(FALSE); + // Login as uid 1. $user = db_query('SELECT * FROM {users} WHERE uid = :uid', array(':uid' => 1))->fetchObject(); // Generate and set a D8-compatible session cookie. @@ -155,58 +133,6 @@ abstract class UpgradePathTestCase extends DrupalWebTestCase { $this->setup = TRUE; } - /** - * Override of DrupalWebTestCase::tearDown() specialized for upgrade testing. - */ - protected function tearDown() { - global $user, $language_interface; - - // In case a fatal error occurred that was not in the test process read the - // log to pick up any fatal errors. - simpletest_log_read($this->testId, $this->databasePrefix, get_class($this), TRUE); - - // Delete temporary files directory. - file_unmanaged_delete_recursive($this->originalFileDirectory . '/simpletest/' . substr($this->databasePrefix, 10)); - - // Get back to the original connection. - Database::removeConnection('default'); - Database::renameConnection('simpletest_original_default', 'default'); - - // Remove all prefixed tables. - $tables = db_find_tables($this->databasePrefix . '%'); - foreach ($tables as $table) { - db_drop_table($table); - } - - // Return the user to the original one. - $user = $this->originalUser; - drupal_save_session(TRUE); - - // Ensure that internal logged in variable and cURL options are reset. - $this->loggedInUser = FALSE; - $this->additionalCurlOptions = array(); - - // Reload module list and implementations to ensure that test module hooks - // aren't called after tests. - module_list(TRUE); - module_implements_reset(); - - // Reset the Field API. - field_cache_clear(); - - // Rebuild caches. - parent::refreshVariables(); - - // Reset language. - $language_interface = $this->originalLanguage; - if ($this->originalLanguageDefault) { - $GLOBALS['conf']['language_default'] = $this->originalLanguageDefault; - } - - // Close the CURL handler. - $this->curlClose(); - } - /** * Specialized variable_set() that works even if the child site is not upgraded. * From 4beaeab9fe87010eae5d8f566970ba9e098bffbd Mon Sep 17 00:00:00 2001 From: catch Date: Tue, 8 May 2012 13:59:45 +0900 Subject: [PATCH 05/11] Issue #1552236 by duellj: Move user language tests to user module. --- core/modules/locale/locale.test | 169 -------------------------------- core/modules/user/user.test | 169 ++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+), 169 deletions(-) diff --git a/core/modules/locale/locale.test b/core/modules/locale/locale.test index ded11ef68be..14e3dcb8509 100644 --- a/core/modules/locale/locale.test +++ b/core/modules/locale/locale.test @@ -1890,175 +1890,6 @@ class LocaleBrowserDetectionTest extends DrupalUnitTestCase { } } -/** - * Functional tests for a user's ability to change their default language. - */ -class LocaleUserLanguageFunctionalTest extends DrupalWebTestCase { - public static function getInfo() { - return array( - 'name' => 'User language settings', - 'description' => "Tests user's ability to change their default language.", - 'group' => 'Locale', - ); - } - - function setUp() { - parent::setUp('locale'); - } - - /** - * Test if user can change their default language. - */ - function testUserLanguageConfiguration() { - global $base_url; - - // User to add and remove language. - $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages')); - // User to change their default language. - $web_user = $this->drupalCreateUser(); - - // Add custom language. - $this->drupalLogin($admin_user); - // Code for the language. - $langcode = 'xx'; - // The English name for the language. - $name = $this->randomName(16); - $edit = array( - 'predefined_langcode' => 'custom', - 'langcode' => $langcode, - 'name' => $name, - 'direction' => '0', - ); - $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language')); - $this->drupalLogout(); - - // Login as normal user and edit account settings. - $this->drupalLogin($web_user); - $path = 'user/' . $web_user->uid . '/edit'; - $this->drupalGet($path); - // Ensure language settings fieldset is available. - $this->assertText(t('Language'), t('Language selector available.')); - // Ensure custom language is present. - $this->assertText($name, t('Language present on form.')); - // Switch to our custom language. - $edit = array( - 'preferred_langcode' => $langcode, - ); - $this->drupalPost($path, $edit, t('Save')); - // Ensure form was submitted successfully. - $this->assertText(t('The changes have been saved.'), t('Changes were saved.')); - // Check if language was changed. - $elements = $this->xpath('//input[@id=:id]', array(':id' => 'edit-preferred-langcode-' . $langcode)); - $this->assertTrue(isset($elements[0]) && !empty($elements[0]['checked']), t('Default language successfully updated.')); - - $this->drupalLogout(); - } -} - -/** - * Functional test for language handling during user creation. - */ -class LocaleUserCreationTest extends DrupalWebTestCase { - - public static function getInfo() { - return array( - 'name' => 'User creation', - 'description' => 'Tests whether proper language is stored for new users and access to language selector.', - 'group' => 'Locale', - ); - } - - function setUp() { - parent::setUp('locale'); - variable_set('user_register', USER_REGISTER_VISITORS); - } - - /** - * Functional test for language handling during user creation. - */ - function testLocalUserCreation() { - // User to add and remove language and create new users. - $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages', 'administer users')); - $this->drupalLogin($admin_user); - - // Add predefined language. - $langcode = 'fr'; - $edit = array( - 'predefined_langcode' => 'fr', - ); - $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language')); - $this->assertText('French', t('Language added successfully.')); - $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.')); - - // Set language negotiation. - $edit = array( - 'language_interface[enabled][language-url]' => TRUE, - ); - $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings')); - $this->assertText(t('Language negotiation configuration saved.'), t('Set language negotiation.')); - - // Check if the language selector is available on admin/people/create and - // set to the currently active language. - $this->drupalGet($langcode . '/admin/people/create'); - $this->assertFieldChecked("edit-preferred-langcode-$langcode", t('Global language set in the language selector.')); - - // Create a user with the admin/people/create form and check if the correct - // language is set. - $username = $this->randomName(10); - $edit = array( - 'name' => $username, - 'mail' => $this->randomName(4) . '@example.com', - 'pass[pass1]' => $username, - 'pass[pass2]' => $username, - ); - - $this->drupalPost($langcode . '/admin/people/create', $edit, t('Create new account')); - - $user = user_load_by_name($username); - $this->assertEqual($user->preferred_langcode, $langcode, t('New user has correct preferred language set.')); - $this->assertEqual($user->langcode, $langcode, t('New user has correct profile language set.')); - - // Register a new user and check if the language selector is hidden. - $this->drupalLogout(); - - $this->drupalGet($langcode . '/user/register'); - $this->assertNoFieldByName('language[fr]', t('Language selector is not accessible.')); - - $username = $this->randomName(10); - $edit = array( - 'name' => $username, - 'mail' => $this->randomName(4) . '@example.com', - ); - - $this->drupalPost($langcode . '/user/register', $edit, t('Create new account')); - - $user = user_load_by_name($username); - $this->assertEqual($user->preferred_langcode, $langcode, t('New user has correct preferred language set.')); - $this->assertEqual($user->langcode, $langcode, t('New user has correct profile language set.')); - - // Test if the admin can use the language selector and if the - // correct language is was saved. - $user_edit = $langcode . '/user/' . $user->uid . '/edit'; - - $this->drupalLogin($admin_user); - $this->drupalGet($user_edit); - $this->assertFieldChecked("edit-preferred-langcode-$langcode", t('Language selector is accessible and correct language is selected.')); - - // Set pass_raw so we can login the new user. - $user->pass_raw = $this->randomName(10); - $edit = array( - 'pass[pass1]' => $user->pass_raw, - 'pass[pass2]' => $user->pass_raw, - ); - - $this->drupalPost($user_edit, $edit, t('Save')); - - $this->drupalLogin($user); - $this->drupalGet($user_edit); - $this->assertFieldChecked("edit-preferred-langcode-$langcode", t('Language selector is accessible and correct language is selected.')); - } -} - /** * Functional tests for configuring a different path alias per language. */ diff --git a/core/modules/user/user.test b/core/modules/user/user.test index a4ebdd8882f..0ce68708e22 100644 --- a/core/modules/user/user.test +++ b/core/modules/user/user.test @@ -2416,3 +2416,172 @@ class UserEntityCallbacksTestCase extends DrupalWebTestCase { $this->assertEqual('user/' . $this->account->uid, $uri['path'], t('Correct user URI.')); } } + +/** + * Functional tests for a user's ability to change their default language. + */ +class UserLanguageFunctionalTest extends DrupalWebTestCase { + public static function getInfo() { + return array( + 'name' => 'User language settings', + 'description' => "Tests user's ability to change their default language.", + 'group' => 'User', + ); + } + + function setUp() { + parent::setUp(array('user', 'language')); + } + + /** + * Test if user can change their default language. + */ + function testUserLanguageConfiguration() { + global $base_url; + + // User to add and remove language. + $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages')); + // User to change their default language. + $web_user = $this->drupalCreateUser(); + + // Add custom language. + $this->drupalLogin($admin_user); + // Code for the language. + $langcode = 'xx'; + // The English name for the language. + $name = $this->randomName(16); + $edit = array( + 'predefined_langcode' => 'custom', + 'langcode' => $langcode, + 'name' => $name, + 'direction' => '0', + ); + $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language')); + $this->drupalLogout(); + + // Login as normal user and edit account settings. + $this->drupalLogin($web_user); + $path = 'user/' . $web_user->uid . '/edit'; + $this->drupalGet($path); + // Ensure language settings fieldset is available. + $this->assertText(t('Language'), t('Language selector available.')); + // Ensure custom language is present. + $this->assertText($name, t('Language present on form.')); + // Switch to our custom language. + $edit = array( + 'preferred_langcode' => $langcode, + ); + $this->drupalPost($path, $edit, t('Save')); + // Ensure form was submitted successfully. + $this->assertText(t('The changes have been saved.'), t('Changes were saved.')); + // Check if language was changed. + $elements = $this->xpath('//input[@id=:id]', array(':id' => 'edit-preferred-langcode-' . $langcode)); + $this->assertTrue(isset($elements[0]) && !empty($elements[0]['checked']), t('Default language successfully updated.')); + + $this->drupalLogout(); + } +} + +/** + * Functional test for language handling during user creation. + */ +class UserLanguageCreationTest extends DrupalWebTestCase { + + public static function getInfo() { + return array( + 'name' => 'User language creation', + 'description' => 'Tests whether proper language is stored for new users and access to language selector.', + 'group' => 'User', + ); + } + + function setUp() { + parent::setUp(array('user', 'language')); + variable_set('user_register', USER_REGISTER_VISITORS); + } + + /** + * Functional test for language handling during user creation. + */ + function testLocalUserCreation() { + // User to add and remove language and create new users. + $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages', 'administer users')); + $this->drupalLogin($admin_user); + + // Add predefined language. + $langcode = 'fr'; + $edit = array( + 'predefined_langcode' => 'fr', + ); + $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language')); + $this->assertText('French', t('Language added successfully.')); + $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.')); + + // Set language negotiation. + $edit = array( + 'language_interface[enabled][language-url]' => TRUE, + ); + $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings')); + $this->assertText(t('Language negotiation configuration saved.'), t('Set language negotiation.')); + + // Check if the language selector is available on admin/people/create and + // set to the currently active language. + $this->drupalGet($langcode . '/admin/people/create'); + $this->assertFieldChecked("edit-preferred-langcode-$langcode", t('Global language set in the language selector.')); + + // Create a user with the admin/people/create form and check if the correct + // language is set. + $username = $this->randomName(10); + $edit = array( + 'name' => $username, + 'mail' => $this->randomName(4) . '@example.com', + 'pass[pass1]' => $username, + 'pass[pass2]' => $username, + ); + + $this->drupalPost($langcode . '/admin/people/create', $edit, t('Create new account')); + + $user = user_load_by_name($username); + $this->assertEqual($user->preferred_langcode, $langcode, t('New user has correct preferred language set.')); + $this->assertEqual($user->langcode, $langcode, t('New user has correct profile language set.')); + + // Register a new user and check if the language selector is hidden. + $this->drupalLogout(); + + $this->drupalGet($langcode . '/user/register'); + $this->assertNoFieldByName('language[fr]', t('Language selector is not accessible.')); + + $username = $this->randomName(10); + $edit = array( + 'name' => $username, + 'mail' => $this->randomName(4) . '@example.com', + ); + + $this->drupalPost($langcode . '/user/register', $edit, t('Create new account')); + + $user = user_load_by_name($username); + $this->assertEqual($user->preferred_langcode, $langcode, t('New user has correct preferred language set.')); + $this->assertEqual($user->langcode, $langcode, t('New user has correct profile language set.')); + + // Test if the admin can use the language selector and if the + // correct language is was saved. + $user_edit = $langcode . '/user/' . $user->uid . '/edit'; + + $this->drupalLogin($admin_user); + $this->drupalGet($user_edit); + $this->assertFieldChecked("edit-preferred-langcode-$langcode", t('Language selector is accessible and correct language is selected.')); + + // Set pass_raw so we can login the new user. + $user->pass_raw = $this->randomName(10); + $edit = array( + 'pass[pass1]' => $user->pass_raw, + 'pass[pass2]' => $user->pass_raw, + ); + + $this->drupalPost($user_edit, $edit, t('Save')); + + $this->drupalLogin($user); + $this->drupalGet($user_edit); + $this->assertFieldChecked("edit-preferred-langcode-$langcode", t('Language selector is accessible and correct language is selected.')); + } +} From 263c6802b99c2a33bc72655ca484ab722c8cf149 Mon Sep 17 00:00:00 2001 From: catch Date: Tue, 8 May 2012 14:03:01 +0900 Subject: [PATCH 06/11] Issue #86461 by ergonlogic, davidjdagino, marcingy, emclaughlin, Bakus: Truncate long paths and path aliases on admin/build/path. --- core/modules/path/path.admin.inc | 9 +++++++-- core/modules/path/path.test | 12 ++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/core/modules/path/path.admin.inc b/core/modules/path/path.admin.inc index d45ba59a4fc..a45565ad1c9 100644 --- a/core/modules/path/path.admin.inc +++ b/core/modules/path/path.admin.inc @@ -42,8 +42,13 @@ function path_admin_overview($keys = NULL) { $destination = drupal_get_destination(); foreach ($result as $data) { $row = array(); - $row['data']['alias'] = l($data->alias, $data->source); - $row['data']['source'] = l($data->source, $data->source, array('alias' => TRUE)); + $row['data']['alias'] = l(truncate_utf8($data->alias, 50, FALSE, TRUE), $data->source, array( + 'attributes' => array('title' => $data->alias), + )); + $row['data']['source'] = l(truncate_utf8($data->source, 50, FALSE, TRUE), $data->source, array( + 'alias' => TRUE, + 'attributes' => array('title' => $data->source), + )); if ($multilanguage) { $row['data']['language_name'] = language_name($data->langcode); } diff --git a/core/modules/path/path.test b/core/modules/path/path.test index 0066071d0f4..7150e617f53 100644 --- a/core/modules/path/path.test +++ b/core/modules/path/path.test @@ -128,6 +128,18 @@ class PathAliasTestCase extends PathTestCase { $this->drupalGet($edit['alias']); $this->assertNoText($node1->title, 'Alias was successfully deleted.'); $this->assertResponse(404); + + // Create a really long alias. + $edit = array(); + $edit['source'] = 'node/' . $node1->nid; + $alias = $this->randomName(128); + $edit['alias'] = $alias; + // The alias is shortened to 50 characters counting the elipsis. + $truncated_alias = substr($alias, 0, 47); + $this->drupalPost('admin/config/search/path/add', $edit, t('Save')); + $this->assertNoText($alias, 'The untruncated alias was not found.'); + // The 'truncated' alias will always be found. + $this->assertText($truncated_alias, 'The truncated alias was found.'); } /** From d39081602322f78e51d5349395602dd550a62f80 Mon Sep 17 00:00:00 2001 From: catch Date: Tue, 8 May 2012 14:04:54 +0900 Subject: [PATCH 07/11] Issue #1444620 by dawehner, sun, heyrocker: Remove file signing from configuration system. --- core/includes/bootstrap.inc | 2 +- core/includes/config.inc | 19 +-- core/includes/install.core.inc | 7 +- core/includes/install.inc | 6 +- .../ConfigFileStorageSignatureException.php | 10 -- .../Config/DrupalConfigVerifiedStorage.php | 28 ++-- .../DrupalConfigVerifiedStorageInterface.php | 2 +- core/lib/Drupal/Core/Config/FileStorage.php | 96 ++++++++++++ .../Drupal/Core/Config/SignedFileStorage.php | 143 ------------------ core/modules/config/config.test | 55 +------ .../simpletest/drupal_web_test_case.php | 3 - sites/default/default.settings.php | 7 - 12 files changed, 124 insertions(+), 254 deletions(-) delete mode 100644 core/lib/Drupal/Core/Config/ConfigFileStorageSignatureException.php create mode 100644 core/lib/Drupal/Core/Config/FileStorage.php delete mode 100644 core/lib/Drupal/Core/Config/SignedFileStorage.php diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index af261160f8b..f65ab4c666e 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -596,7 +596,7 @@ function drupal_settings_initialize() { global $base_url, $base_path, $base_root, $script_path; // Export the following settings.php variables to the global namespace - global $databases, $cookie_domain, $conf, $installed_profile, $update_free_access, $db_url, $db_prefix, $drupal_hash_salt, $is_https, $base_secure_url, $base_insecure_url, $config_directory_name, $config_signature_key; + global $databases, $cookie_domain, $conf, $installed_profile, $update_free_access, $db_url, $db_prefix, $drupal_hash_salt, $is_https, $base_secure_url, $base_insecure_url, $config_directory_name; $conf = array(); if (file_exists(DRUPAL_ROOT . '/' . conf_path() . '/settings.php')) { diff --git a/core/includes/config.inc b/core/includes/config.inc index cb81acc7d55..5e6fa0083a3 100644 --- a/core/includes/config.inc +++ b/core/includes/config.inc @@ -71,7 +71,7 @@ function config_install_default_config($module) { * @return * An array of file names under a branch. */ -function config_get_signed_file_storage_names_with_prefix($prefix = '') { +function config_get_files_with_prefix($prefix = '') { $files = glob(config_get_config_directory() . '/' . $prefix . '*.xml'); $clean_name = function ($value) { return basename($value, '.xml'); @@ -79,23 +79,6 @@ function config_get_signed_file_storage_names_with_prefix($prefix = '') { return array_map($clean_name, $files); } -/** - * Generates a hash of a config file's contents using our encryption key. - * - * @param $data - * The contents of a configuration file. - * - * @return - * A hash of the data. - */ -function config_sign_data($data) { - // The configuration key is loaded from settings.php and imported into the global namespace - global $config_signature_key; - - // SHA-512 is both secure and very fast on 64 bit CPUs. - return hash_hmac('sha512', $data, $config_signature_key); -} - /** * @todo * diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 76ce3e67968..31ef052af30 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -1002,11 +1002,6 @@ function install_settings_form_submit($form, &$form_state) { 'required' => TRUE, ); - $settings['config_signature_key'] = array( - 'value' => drupal_hash_base64(drupal_random_bytes(55)), - 'required' => TRUE, - ); - // This duplicates drupal_get_token() because that function can't work yet. // Wondering if it makes sense to move this later in the process, but its // nice having all the settings stuff here. @@ -1016,7 +1011,7 @@ function install_settings_form_submit($form, &$form_state) { // already has the db stuff in it, and right now in that case your // config directory never gets created. So this needs to be moved elsewhere. $settings['config_directory_name'] = array( - 'value' => 'config_' . drupal_hmac_base64('', session_id() . $settings['config_signature_key']['value'] . $settings['drupal_hash_salt']['value']), + 'value' => 'config_' . drupal_hmac_base64('', session_id() . $settings['drupal_hash_salt']['value']), 'required' => TRUE, ); diff --git a/core/includes/install.inc b/core/includes/install.inc index 283e31ca7b2..f278a6a6a76 100644 --- a/core/includes/install.inc +++ b/core/includes/install.inc @@ -1,7 +1,7 @@ delete(); + $file_storage->delete(); } } diff --git a/core/lib/Drupal/Core/Config/ConfigFileStorageSignatureException.php b/core/lib/Drupal/Core/Config/ConfigFileStorageSignatureException.php deleted file mode 100644 index 65c5c59028e..00000000000 --- a/core/lib/Drupal/Core/Config/ConfigFileStorageSignatureException.php +++ /dev/null @@ -1,10 +0,0 @@ -signedFile)) { - $this->signedFile = new SignedFileStorage($this->name); + protected function fileStorage() { + if (!isset($this->fileStorage)) { + $this->fileStorage = new FileStorage($this->name); } - return $this->signedFile; + return $this->fileStorage; } /** @@ -50,7 +50,7 @@ abstract class DrupalConfigVerifiedStorage implements DrupalConfigVerifiedStorag * Implements DrupalConfigVerifiedStorageInterface::deleteFile(). */ public function deleteFile() { - return $this->signedFileStorage()->delete(); + return $this->fileStorage()->delete(); } /** @@ -67,7 +67,7 @@ abstract class DrupalConfigVerifiedStorage implements DrupalConfigVerifiedStorag * @todo */ public function readFromFile() { - return $this->signedFileStorage()->read($this->name); + return $this->fileStorage()->read($this->name); } /** @@ -89,7 +89,7 @@ abstract class DrupalConfigVerifiedStorage implements DrupalConfigVerifiedStorag * Implements DrupalConfigVerifiedStorageInterface::writeToFile(). */ public function writeToFile($data) { - return $this->signedFileStorage()->write($data); + return $this->fileStorage()->write($data); } /** diff --git a/core/lib/Drupal/Core/Config/DrupalConfigVerifiedStorageInterface.php b/core/lib/Drupal/Core/Config/DrupalConfigVerifiedStorageInterface.php index 47a5ddb81b2..8048e353e1b 100644 --- a/core/lib/Drupal/Core/Config/DrupalConfigVerifiedStorageInterface.php +++ b/core/lib/Drupal/Core/Config/DrupalConfigVerifiedStorageInterface.php @@ -6,7 +6,7 @@ namespace Drupal\Core\Config; * Defines an interface for verified storage manipulation. * * This class allows reading and writing configuration data from/to the - * verified storage and copying to/from the signed file storing the same data. + * verified storage and copying to/from the file storing the same data. */ interface DrupalConfigVerifiedStorageInterface { diff --git a/core/lib/Drupal/Core/Config/FileStorage.php b/core/lib/Drupal/Core/Config/FileStorage.php new file mode 100644 index 00000000000..77b8db535ff --- /dev/null +++ b/core/lib/Drupal/Core/Config/FileStorage.php @@ -0,0 +1,96 @@ +name = $name; + } + + /** + * Reads and returns a file. + * + * @return + * The data of the file. + * + * @throws + * Exception + */ + protected function readData() { + $data = file_get_contents($this->getFilePath()); + if ($data === FALSE) { + throw new \Exception('Read file is invalid.'); + } + return $data; + } + + /** + * Checks whether the XML configuration file already exists on disk. + * + * @return + * @todo + */ + protected function exists() { + return file_exists($this->getFilePath()); + } + + /** + * Returns the path to the XML configuration file. + * + * @return + * @todo + */ + public function getFilePath() { + return config_get_config_directory() . '/' . $this->name . '.xml'; + } + + /** + * Writes the contents of the configuration file to disk. + * + * @param $data + * The data to be written to the file. + * + * @throws + * Exception + */ + public function write($data) { + if (!file_put_contents($this->getFilePath(), $data)) { + throw new \Exception('Failed to write configuration file: ' . $this->getFilePath()); + } + } + + /** + * Returns the contents of the configuration file. + * + * @return + * @todo + */ + public function read() { + if ($this->exists()) { + $data = $this->readData(); + return $data; + } + return FALSE; + } + + /** + * Deletes a configuration file. + */ + public function delete() { + // Needs error handling and etc. + @drupal_unlink($this->getFilePath()); + } +} diff --git a/core/lib/Drupal/Core/Config/SignedFileStorage.php b/core/lib/Drupal/Core/Config/SignedFileStorage.php deleted file mode 100644 index c66902963d6..00000000000 --- a/core/lib/Drupal/Core/Config/SignedFileStorage.php +++ /dev/null @@ -1,143 +0,0 @@ -name = $name; - } - - /** - * Reads and returns a signed file and its signature. - * - * @return - * An array with "signature" and "data" keys. - * - * @throws - * Exception - */ - protected function readWithSignature() { - $content = file_get_contents($this->getFilePath()); - if ($content === FALSE) { - throw new \Exception('Read file is invalid.'); - } - $signature = file_get_contents($this->getFilePath() . '.sig'); - if ($signature === FALSE) { - throw new \Exception('Signature file is invalid.'); - } - return array('data' => $content, 'signature' => $signature); - } - - /** - * Checks whether the XML configuration file already exists on disk. - * - * @return - * @todo - */ - protected function exists() { - return file_exists($this->getFilePath()); - } - - /** - * Returns the path to the XML configuration file. - * - * @return - * @todo - */ - public function getFilePath() { - return config_get_config_directory() . '/' . $this->name . '.xml'; - } - - /** - * Recreates the signature for the file. - */ - public function resign() { - if ($this->exists()) { - $parts = $this->readWithSignature(); - $this->write($parts['data']); - } - } - - /** - * Cryptographically verifies the integrity of the configuration file. - * - * @param $contentOnSuccess - * Whether or not to return the contents of the verified configuration file. - * - * @return mixed - * If $contentOnSuccess was TRUE, returns the contents of the verified - * configuration file; otherwise returns TRUE on success. Always returns - * FALSE if the configuration file was not successfully verified. - */ - public function verify($contentOnSuccess = FALSE) { - if ($this->exists()) { - $split = $this->readWithSignature(); - $expected_signature = config_sign_data($split['data']); - if ($expected_signature === $split['signature']) { - if ($contentOnSuccess) { - return $split['data']; - } - return TRUE; - } - } - return FALSE; - } - - /** - * Writes the contents of the configuration file to disk. - * - * @param $data - * The data to be written to the file. - * - * @throws - * Exception - */ - public function write($data) { - $signature = config_sign_data($data); - if (!file_put_contents($this->getFilePath(), $data)) { - throw new \Exception('Failed to write configuration file: ' . $this->getFilePath()); - } - if (!file_put_contents($this->getFilePath() . '.sig', $signature)) { - throw new \Exception('Failed to write signature file: ' . $this->getFilePath()); - } - } - - /** - * Returns the contents of the configuration file. - * - * @return - * @todo - */ - public function read() { - if ($this->exists()) { - $verification = $this->verify(TRUE); - if ($verification === FALSE) { - throw new \Exception('Invalid signature in file header.'); - } - return $verification; - } - } - - /** - * Deletes a configuration file. - */ - public function delete() { - // Needs error handling and etc. - @drupal_unlink($this->getFilePath()); - @drupal_unlink($this->getFilePath() . '.sig'); - } -} diff --git a/core/modules/config/config.test b/core/modules/config/config.test index a164108c3d5..c111aba3310 100644 --- a/core/modules/config/config.test +++ b/core/modules/config/config.test @@ -5,14 +5,12 @@ * Tests for the Configuration module. */ -use Drupal\Core\Config\SignedFileStorage; +use Drupal\Core\Config\FileStorage; /** * Tests the secure file writer. */ class ConfigFileSecurityTestCase extends DrupalWebTestCase { - protected $profile = 'testing'; - protected $filename = 'foo.bar'; protected $testContent = 'Good morning, Denver!'; @@ -25,27 +23,11 @@ class ConfigFileSecurityTestCase extends DrupalWebTestCase { ); } - /** - * Tests that a file written by this system has a valid signature. - */ - function testFileVerify() { - $file = new SignedFileStorage($this->filename); - $file->write($this->testContent); - - $this->assertTrue($file->verify(), 'A file verifies after being written.'); - - unset($file); - - // Load the file again, so that there is no stale data from the old object. - $file = new SignedFileStorage($this->filename); - $this->assertTrue($file->verify(), 'A file verifies after being written and reloaded.'); - } - /** * Tests that a file written by this system can be successfully read back. */ function testFilePersist() { - $file = new SignedFileStorage($this->filename); + $file = new FileStorage($this->filename); $file->write($this->testContent); unset($file); @@ -54,7 +36,7 @@ class ConfigFileSecurityTestCase extends DrupalWebTestCase { // Note that if any other exception is thrown, we let the test system // handle catching and reporting it. try { - $file = new SignedFileStorage($this->filename); + $file = new FileStorage($this->filename); $saved_content = $file->read(); $this->assertEqual($saved_content, $this->testContent, 'A file can be read back successfully.'); @@ -63,35 +45,12 @@ class ConfigFileSecurityTestCase extends DrupalWebTestCase { $this->fail('File failed verification when being read.'); } } - - /** - * Tests that a file fails validation if it's been monkeyed with. - */ - function testFileNotVerify() { - $file = new SignedFileStorage($this->filename); - $file->write($this->testContent); - - // Manually overwrite the body of the secure file. Note that we skip the - // first line, which is reserved for the signature and such, to overwrite - // just the payload. - $raw_file = new SplFileObject($file->getFilePath(), 'a+'); - $raw_file->fwrite('Good morning, Detroit!'); - $raw_file->fflush(); - unset($raw_file); - - unset($file); - - $file = new SignedFileStorage($this->filename); - $this->assertFalse($file->verify(), 'Corrupted file does not verify.'); - } } /** * Tests reading and writing file contents. */ class ConfigFileContentTestCase extends DrupalWebTestCase { - protected $profile = 'testing'; - protected $fileExtension = 'xml'; public static function getInfo() { @@ -238,22 +197,22 @@ class ConfigFileContentTestCase extends DrupalWebTestCase { // Get file listing for all files starting with 'foo'. Should return // two elements. - $files = config_get_signed_file_storage_names_with_prefix('foo'); + $files = config_get_files_with_prefix('foo'); $this->assertEqual(count($files), 2, 'Two files listed with the prefix \'foo\'.'); // Get file listing for all files starting with 'biff'. Should return // one element. - $files = config_get_signed_file_storage_names_with_prefix('biff'); + $files = config_get_files_with_prefix('biff'); $this->assertEqual(count($files), 1, 'One file listed with the prefix \'biff\'.'); // Get file listing for all files starting with 'foo.bar'. Should return // one element. - $files = config_get_signed_file_storage_names_with_prefix('foo.bar'); + $files = config_get_files_with_prefix('foo.bar'); $this->assertEqual(count($files), 1, 'One file listed with the prefix \'foo.bar\'.'); // Get file listing for all files starting with 'bar'. Should return // an empty array. - $files = config_get_signed_file_storage_names_with_prefix('bar'); + $files = config_get_files_with_prefix('bar'); $this->assertEqual($files, array(), 'No files listed with the prefix \'bar\'.'); // Delete the configuration. diff --git a/core/modules/simpletest/drupal_web_test_case.php b/core/modules/simpletest/drupal_web_test_case.php index ede61046222..6fdd993a108 100644 --- a/core/modules/simpletest/drupal_web_test_case.php +++ b/core/modules/simpletest/drupal_web_test_case.php @@ -1344,7 +1344,6 @@ class DrupalWebTestCase extends DrupalTestCase { $this->originalLanguage = $language_interface; $this->originalLanguageDefault = variable_get('language_default'); $this->originalConfigDirectory = $GLOBALS['config_directory_name']; - $this->originalConfigSignatureKey = $GLOBALS['config_signature_key']; $this->originalFileDirectory = variable_get('file_public_path', conf_path() . '/files'); $this->originalProfile = drupal_get_profile(); $this->originalUser = $user; @@ -1377,7 +1376,6 @@ class DrupalWebTestCase extends DrupalTestCase { $GLOBALS['config_directory_name'] = 'simpletest/' . substr($this->databasePrefix, 10) . '/config'; $this->configFileDirectory = $this->originalFileDirectory . '/' . $GLOBALS['config_directory_name']; file_prepare_directory($this->configFileDirectory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); - $GLOBALS['config_signature_key'] = drupal_hash_base64(drupal_random_bytes(55)); // Log fatal errors. ini_set('log_errors', 1); @@ -1647,7 +1645,6 @@ class DrupalWebTestCase extends DrupalTestCase { // Reset configuration globals. $GLOBALS['config_directory_name'] = $this->originalConfigDirectory; - $GLOBALS['config_signature_key'] = $this->originalConfigSignatureKey; // Reset language. $language_interface = $this->originalLanguage; diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php index 4f3fab8ad69..a6c38e48fb4 100755 --- a/sites/default/default.settings.php +++ b/sites/default/default.settings.php @@ -251,13 +251,6 @@ $drupal_hash_salt = ''; */ $config_directory_name = ''; -/** - * Configuration signature key. - * - * Drupal configuration files are signed using this key. - */ -$config_signature_key = ''; - /** * Base URL (optional). * From 7c5214c71424eeebf47a6922866242f2d3408f89 Mon Sep 17 00:00:00 2001 From: catch Date: Tue, 8 May 2012 14:12:18 +0900 Subject: [PATCH 08/11] Issue #617562 by sun, matt2000: Remove underscore-to-dash conversion in path arguments for content types. --- core/modules/book/book.module | 2 +- core/modules/comment/comment.module | 8 +- core/modules/entity/entity.api.php | 2 +- .../field/modules/list/tests/list.test | 4 +- core/modules/field/modules/number/number.test | 6 +- core/modules/field/modules/text/text.test | 4 +- core/modules/field/tests/field.test | 14 +-- core/modules/field/tests/field_test.module | 3 +- core/modules/field_ui/field_ui.test | 40 ++++--- core/modules/forum/forum.module | 6 +- core/modules/node/content_types.inc | 11 +- core/modules/node/node.api.php | 5 +- core/modules/node/node.module | 101 +++++++----------- core/modules/node/node.test | 4 +- core/modules/poll/poll.module | 4 +- .../simpletest/drupal_web_test_case.php | 2 +- core/modules/taxonomy/taxonomy.test | 8 +- .../modules/translation/translation.pages.inc | 2 +- core/modules/translation/translation.test | 2 +- 19 files changed, 97 insertions(+), 131 deletions(-) diff --git a/core/modules/book/book.module b/core/modules/book/book.module index c102849c699..bbdfab33d82 100644 --- a/core/modules/book/book.module +++ b/core/modules/book/book.module @@ -102,7 +102,7 @@ function book_node_view_link(Node $node, $view_mode) { if ((user_access('add content to books') || user_access('administer book outlines')) && node_access('create', $child_type) && $node->status == 1 && $node->book['depth'] < MENU_MAX_DEPTH) { $links['book_add_child'] = array( 'title' => t('Add child page'), - 'href' => 'node/add/' . str_replace('_', '-', $child_type), + 'href' => 'node/add/' . $child_type, 'query' => array('parent' => $node->book['mlid']), ); } diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module index 179c46a09cb..79f2ecb459b 100644 --- a/core/modules/comment/comment.module +++ b/core/modules/comment/comment.module @@ -135,7 +135,7 @@ function comment_entity_info() { // See comment_node_type_load() and comment_menu_alter(). 'path' => 'admin/structure/types/manage/%comment_node_type/comment', 'bundle argument' => 4, - 'real path' => 'admin/structure/types/manage/' . str_replace('_', '-', $type) . '/comment', + 'real path' => 'admin/structure/types/manage/' . $type . '/comment', 'access arguments' => array('administer content types'), ), ); @@ -150,9 +150,7 @@ function comment_entity_info() { * This function is used as a menu loader callback in comment_menu(). * * @param $name - * The URL-formatted machine name of the node type whose comment fields are - * to be edited. 'URL-formatted' means that underscores are replaced by - * hyphens. + * The machine name of the node type whose comment fields are to be edited. * * @return * The comment bundle name corresponding to the node type. @@ -160,7 +158,7 @@ function comment_entity_info() { * @see comment_menu_alter() */ function comment_node_type_load($name) { - if ($type = node_type_get_type(strtr($name, array('-' => '_')))) { + if ($type = node_type_load($name)) { return 'comment_node_' . $type->type; } } diff --git a/core/modules/entity/entity.api.php b/core/modules/entity/entity.api.php index f49b76133b8..8f721cf0983 100644 --- a/core/modules/entity/entity.api.php +++ b/core/modules/entity/entity.api.php @@ -186,7 +186,7 @@ function hook_entity_info() { 'label' => $name, 'admin' => array( 'path' => 'admin/structure/types/manage/%node_type', - 'real path' => 'admin/structure/types/manage/' . str_replace('_', '-', $type), + 'real path' => 'admin/structure/types/manage/' . $type, 'bundle argument' => 4, 'access arguments' => array('administer content types'), ), diff --git a/core/modules/field/modules/list/tests/list.test b/core/modules/field/modules/list/tests/list.test index bdc96a63e68..8999b065f0b 100644 --- a/core/modules/field/modules/list/tests/list.test +++ b/core/modules/field/modules/list/tests/list.test @@ -222,8 +222,6 @@ class ListFieldUITestCase extends FieldTestCase { $type_name = 'test_' . strtolower($this->randomName()); $type = $this->drupalCreateContentType(array('name' => $type_name, 'type' => $type_name)); $this->type = $type->type; - // Store a valid URL name, with hyphens instead of underscores. - $this->hyphen_type = str_replace('_', '-', $this->type); } /** @@ -429,7 +427,7 @@ class ListFieldUITestCase extends FieldTestCase { ); field_create_instance($instance); - $this->admin_path = 'admin/structure/types/manage/' . $this->hyphen_type . '/fields/' . $this->field_name; + $this->admin_path = 'admin/structure/types/manage/' . $this->type . '/fields/' . $this->field_name; } /** diff --git a/core/modules/field/modules/number/number.test b/core/modules/field/modules/number/number.test index 99ec6f03287..e394aea37e4 100644 --- a/core/modules/field/modules/number/number.test +++ b/core/modules/field/modules/number/number.test @@ -56,7 +56,7 @@ class NumberFieldTestCase extends DrupalWebTestCase { field_create_instance($this->instance); // Display creation form. - $this->drupalGet('test-entity/add/test-bundle'); + $this->drupalGet('test-entity/add/test_bundle'); $langcode = LANGUAGE_NOT_SPECIFIED; $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][value]", '', t('Widget is displayed')); @@ -81,7 +81,7 @@ class NumberFieldTestCase extends DrupalWebTestCase { ); foreach ($wrong_entries as $wrong_entry) { - $this->drupalGet('test-entity/add/test-bundle'); + $this->drupalGet('test-entity/add/test_bundle'); $edit = array( "{$this->field['field_name']}[$langcode][0][value]" => $wrong_entry, ); @@ -99,7 +99,7 @@ class NumberFieldTestCase extends DrupalWebTestCase { ); foreach ($wrong_entries as $wrong_entry) { - $this->drupalGet('test-entity/add/test-bundle'); + $this->drupalGet('test-entity/add/test_bundle'); $edit = array( "{$this->field['field_name']}[$langcode][0][value]" => $wrong_entry, ); diff --git a/core/modules/field/modules/text/text.test b/core/modules/field/modules/text/text.test index d4f41f01cd4..77efce91a45 100644 --- a/core/modules/field/modules/text/text.test +++ b/core/modules/field/modules/text/text.test @@ -111,7 +111,7 @@ class TextFieldTestCase extends DrupalWebTestCase { $langcode = LANGUAGE_NOT_SPECIFIED; // Display creation form. - $this->drupalGet('test-entity/add/test-bundle'); + $this->drupalGet('test-entity/add/test_bundle'); $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", '', t('Widget is displayed')); $this->assertNoFieldByName("{$this->field_name}[$langcode][0][format]", '1', t('Format selector is not displayed')); @@ -180,7 +180,7 @@ class TextFieldTestCase extends DrupalWebTestCase { // Display the creation form. Since the user only has access to one format, // no format selector will be displayed. - $this->drupalGet('test-entity/add/test-bundle'); + $this->drupalGet('test-entity/add/test_bundle'); $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", '', t('Widget is displayed')); $this->assertNoFieldByName("{$this->field_name}[$langcode][0][format]", '', t('Format selector is not displayed')); diff --git a/core/modules/field/tests/field.test b/core/modules/field/tests/field.test index b8945a11e99..4b59fc8ac1e 100644 --- a/core/modules/field/tests/field.test +++ b/core/modules/field/tests/field.test @@ -1326,7 +1326,7 @@ class FieldFormTestCase extends FieldTestCase { $langcode = LANGUAGE_NOT_SPECIFIED; // Display creation form. - $this->drupalGet('test-entity/add/test-bundle'); + $this->drupalGet('test-entity/add/test_bundle'); $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", '', 'Widget is displayed'); $this->assertNoField("{$this->field_name}[$langcode][1][value]", 'No extraneous widget is displayed'); // TODO : check that the widget is populated with default value ? @@ -1381,7 +1381,7 @@ class FieldFormTestCase extends FieldTestCase { // Submit with missing required value. $edit = array(); - $this->drupalPost('test-entity/add/test-bundle', $edit, t('Save')); + $this->drupalPost('test-entity/add/test_bundle', $edit, t('Save')); $this->assertRaw(t('!name field is required.', array('!name' => $this->instance['label'])), 'Required field with no value fails validation'); // Create an entity @@ -1418,7 +1418,7 @@ class FieldFormTestCase extends FieldTestCase { $langcode = LANGUAGE_NOT_SPECIFIED; // Display creation form -> 1 widget. - $this->drupalGet('test-entity/add/test-bundle'); + $this->drupalGet('test-entity/add/test_bundle'); $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", '', 'Widget 1 is displayed'); $this->assertNoField("{$this->field_name}[$langcode][1][value]", 'No extraneous widget is displayed'); @@ -1516,7 +1516,7 @@ class FieldFormTestCase extends FieldTestCase { )); // Display creation form. - $this->drupalGet('test-entity/add/test-bundle'); + $this->drupalGet('test-entity/add/test_bundle'); // Press the 'Add more' button. $this->drupalPost(NULL, array(), t('Add another item')); @@ -1539,7 +1539,7 @@ class FieldFormTestCase extends FieldTestCase { $langcode = LANGUAGE_NOT_SPECIFIED; // Display creation form -> 1 widget. - $this->drupalGet('test-entity/add/test-bundle'); + $this->drupalGet('test-entity/add/test_bundle'); // Press 'add more' button a couple times -> 3 widgets. // drupalPostAJAX() will not work iteratively, so we add those through @@ -1599,7 +1599,7 @@ class FieldFormTestCase extends FieldTestCase { $langcode = LANGUAGE_NOT_SPECIFIED; // Display creation form. - $this->drupalGet('test-entity/add/test-bundle'); + $this->drupalGet('test-entity/add/test_bundle'); $this->assertFieldByName("{$this->field_name}[$langcode]", '', t('Widget is displayed.')); // Create entity with three values. @@ -1666,7 +1666,7 @@ class FieldFormTestCase extends FieldTestCase { $this->assertFalse($form[$field_name_no_access]['#access'], 'Field #access is FALSE for the field without edit access.'); // Display creation form. - $this->drupalGet('test-entity/add/test-bundle'); + $this->drupalGet('test-entity/add/test_bundle'); $this->assertNoFieldByName("{$field_name_no_access}[$langcode][0][value]", '', t('Widget is not displayed if field access is denied.')); // Create entity. diff --git a/core/modules/field/tests/field_test.module b/core/modules/field/tests/field_test.module index 90e25c8661c..205a624a6d2 100644 --- a/core/modules/field/tests/field_test.module +++ b/core/modules/field/tests/field_test.module @@ -42,8 +42,7 @@ function field_test_menu() { $bundles = field_info_bundles('test_entity'); foreach ($bundles as $bundle_name => $bundle_info) { - $bundle_url_str = str_replace('_', '-', $bundle_name); - $items['test-entity/add/' . $bundle_url_str] = array( + $items['test-entity/add/' . $bundle_name] = array( 'title' => t('Add %bundle test_entity', array('%bundle' => $bundle_info['label'])), 'page callback' => 'field_test_entity_add', 'page arguments' => array(2), diff --git a/core/modules/field_ui/field_ui.test b/core/modules/field_ui/field_ui.test index fb71c5d3d19..80edc383441 100644 --- a/core/modules/field_ui/field_ui.test +++ b/core/modules/field_ui/field_ui.test @@ -34,8 +34,6 @@ class FieldUITestCase extends DrupalWebTestCase { $type_name = strtolower($this->randomName(8)) . '_test'; $type = $this->drupalCreateContentType(array('name' => $type_name, 'type' => $type_name)); $this->type = $type->type; - // Store a valid URL name, with hyphens instead of underscores. - $this->hyphen_type = str_replace('_', '-', $this->type); } /** @@ -199,7 +197,7 @@ class FieldUIManageFieldsTestCase extends FieldUITestCase { * Tests the manage fields page. */ function manageFieldsPage() { - $this->drupalGet('admin/structure/types/manage/' . $this->hyphen_type . '/fields'); + $this->drupalGet('admin/structure/types/manage/' . $this->type . '/fields'); // Check all table columns. $table_headers = array( t('Label'), @@ -232,7 +230,7 @@ class FieldUIManageFieldsTestCase extends FieldUITestCase { 'fields[_add_new_field][label]' => $this->field_label, 'fields[_add_new_field][field_name]' => $this->field_name_input, ); - $this->fieldUIAddNewField('admin/structure/types/manage/' . $this->hyphen_type, $edit); + $this->fieldUIAddNewField('admin/structure/types/manage/' . $this->type, $edit); // Assert the field appears in the "add existing field" section for // different entity types; e.g. if a field was added in a node entity, it @@ -247,7 +245,7 @@ class FieldUIManageFieldsTestCase extends FieldUITestCase { */ function updateField() { // Go to the field edit page. - $this->drupalGet('admin/structure/types/manage/' . $this->hyphen_type . '/fields/' . $this->field_name); + $this->drupalGet('admin/structure/types/manage/' . $this->type . '/fields/' . $this->field_name); // Populate the field settings with new settings. $string = 'updated dummy test string'; @@ -330,7 +328,7 @@ class FieldUIManageFieldsTestCase extends FieldUITestCase { field_create_instance($instance); $langcode = LANGUAGE_NOT_SPECIFIED; - $admin_path = 'admin/structure/types/manage/' . $this->hyphen_type . '/fields/' . $field_name; + $admin_path = 'admin/structure/types/manage/' . $this->type . '/fields/' . $field_name; $element_id = "edit-$field_name-$langcode-0-value"; $element_name = "{$field_name}[$langcode][0][value]"; $this->drupalGet($admin_path); @@ -366,7 +364,7 @@ class FieldUIManageFieldsTestCase extends FieldUITestCase { */ function testDeleteField() { // Create a new field. - $bundle_path1 = 'admin/structure/types/manage/' . $this->hyphen_type; + $bundle_path1 = 'admin/structure/types/manage/' . $this->type; $edit1 = array( 'fields[_add_new_field][label]' => $this->field_label, 'fields[_add_new_field][field_name]' => $this->field_name_input, @@ -377,10 +375,9 @@ class FieldUIManageFieldsTestCase extends FieldUITestCase { $type_name2 = strtolower($this->randomName(8)) . '_test'; $type2 = $this->drupalCreateContentType(array('name' => $type_name2, 'type' => $type_name2)); $type_name2 = $type2->type; - $hyphen_type2 = str_replace('_', '-', $type_name2); // Add an instance to the second node type. - $bundle_path2 = 'admin/structure/types/manage/' . $hyphen_type2; + $bundle_path2 = 'admin/structure/types/manage/' . $type_name2; $edit2 = array( 'fields[_add_existing_field][label]' => $this->field_label, 'fields[_add_existing_field][field_name]' => $this->field_name, @@ -412,7 +409,7 @@ class FieldUIManageFieldsTestCase extends FieldUITestCase { * Tests that Field UI respects the 'no_ui' option in hook_field_info(). */ function testHiddenFields() { - $bundle_path = 'admin/structure/types/manage/' . $this->hyphen_type . '/fields/'; + $bundle_path = 'admin/structure/types/manage/' . $this->type . '/fields/'; // Check that the field type is not available in the 'add new field' row. $this->drupalGet($bundle_path); @@ -447,15 +444,14 @@ class FieldUIManageFieldsTestCase extends FieldUITestCase { * Tests renaming a bundle. */ function testRenameBundle() { - $type2 = strtolower($this->randomName(8)) . '_' .'test'; - $hyphen_type2 = str_replace('_', '-', $type2); + $type2 = strtolower($this->randomName(8)) . '_test'; $options = array( 'type' => $type2, ); - $this->drupalPost('admin/structure/types/manage/' . $this->hyphen_type, $options, t('Save content type')); + $this->drupalPost('admin/structure/types/manage/' . $this->type, $options, t('Save content type')); - $this->drupalGet('admin/structure/types/manage/' . $hyphen_type2 . '/fields'); + $this->drupalGet('admin/structure/types/manage/' . $type2 . '/fields'); } /** @@ -470,7 +466,7 @@ class FieldUIManageFieldsTestCase extends FieldUITestCase { 'fields[_add_new_field][type]' => 'taxonomy_term_reference', 'fields[_add_new_field][widget_type]' => 'options_select', ); - $url = 'admin/structure/types/manage/' . $this->hyphen_type . '/fields'; + $url = 'admin/structure/types/manage/' . $this->type . '/fields'; $this->drupalPost($url, $edit, t('Save')); $this->assertText(t('The machine-readable name is already in use. It must be unique.')); @@ -498,7 +494,7 @@ class FieldUIManageDisplayTestCase extends FieldUITestCase { * Tests formatter settings. */ function testFormatterUI() { - $manage_fields = 'admin/structure/types/manage/' . $this->hyphen_type; + $manage_fields = 'admin/structure/types/manage/' . $this->type; $manage_display = $manage_fields . '/display'; // Create a field, and a node with some data for the field. @@ -551,7 +547,7 @@ class FieldUIManageDisplayTestCase extends FieldUITestCase { 'fields[_add_new_field][label]' => 'Test field', 'fields[_add_new_field][field_name]' => 'test', ); - $this->fieldUIAddNewField('admin/structure/types/manage/' . $this->hyphen_type, $edit); + $this->fieldUIAddNewField('admin/structure/types/manage/' . $this->type, $edit); // For this test, use a formatter setting value that is an integer unlikely // to appear in a rendered node other than as part of the field being tested // (for example, unlikely to be part of the "Submitted by ... on ..." line). @@ -579,14 +575,14 @@ class FieldUIManageDisplayTestCase extends FieldUITestCase { $edit = array( 'fields[field_test][type]' => 'field_test_with_prepare_view', ); - $this->drupalPost('admin/structure/types/manage/' . $this->hyphen_type . '/display', $edit, t('Save')); + $this->drupalPost('admin/structure/types/manage/' . $this->type . '/display', $edit, t('Save')); $this->assertNodeViewText($node, 'rss', $output['field_test_with_prepare_view'], t("The field is displayed as expected in view modes that use 'default' settings.")); // Specialize the 'rss' mode, check that the field is displayed the same. $edit = array( "view_modes_custom[rss]" => TRUE, ); - $this->drupalPost('admin/structure/types/manage/' . $this->hyphen_type . '/display', $edit, t('Save')); + $this->drupalPost('admin/structure/types/manage/' . $this->type . '/display', $edit, t('Save')); $this->assertNodeViewText($node, 'rss', $output['field_test_with_prepare_view'], t("The field is displayed as expected in newly specialized 'rss' mode.")); // Set the field to 'hidden' in the view mode, check that the field is @@ -594,7 +590,7 @@ class FieldUIManageDisplayTestCase extends FieldUITestCase { $edit = array( 'fields[field_test][type]' => 'hidden', ); - $this->drupalPost('admin/structure/types/manage/' . $this->hyphen_type . '/display/rss', $edit, t('Save')); + $this->drupalPost('admin/structure/types/manage/' . $this->type . '/display/rss', $edit, t('Save')); $this->assertNodeViewNoText($node, 'rss', $value, t("The field is hidden in 'rss' mode.")); // Set the view mode back to 'default', check that the field is displayed @@ -602,14 +598,14 @@ class FieldUIManageDisplayTestCase extends FieldUITestCase { $edit = array( "view_modes_custom[rss]" => FALSE, ); - $this->drupalPost('admin/structure/types/manage/' . $this->hyphen_type . '/display', $edit, t('Save')); + $this->drupalPost('admin/structure/types/manage/' . $this->type . '/display', $edit, t('Save')); $this->assertNodeViewText($node, 'rss', $output['field_test_with_prepare_view'], t("The field is displayed as expected when 'rss' mode is set back to 'default' settings.")); // Specialize the view mode again. $edit = array( "view_modes_custom[rss]" => TRUE, ); - $this->drupalPost('admin/structure/types/manage/' . $this->hyphen_type . '/display', $edit, t('Save')); + $this->drupalPost('admin/structure/types/manage/' . $this->type . '/display', $edit, t('Save')); // Check that the previous settings for the view mode have been kept. $this->assertNodeViewNoText($node, 'rss', $value, t("The previous settings are kept when 'rss' mode is specialized again.")); } diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module index 1b0ab983232..07bee65c8a7 100644 --- a/core/modules/forum/forum.module +++ b/core/modules/forum/forum.module @@ -180,7 +180,7 @@ function forum_menu_local_tasks_alter(&$data, $router_item, $root_path) { '#theme' => 'menu_local_action', '#link' => array( 'title' => t('Add new @node_type', array('@node_type' => node_type_get_name($type))), - 'href' => 'node/add/' . str_replace('_', '-', $type) . '/' . $forum_term->tid, + 'href' => 'node/add/' . $type . '/' . $forum_term->tid, ), ); } @@ -710,8 +710,8 @@ function forum_block_view_pre_render($elements) { /** * Implements hook_form(). */ -function forum_form($node, $form_state) { - $type = node_type_get_type($node); +function forum_form(Node $node, &$form_state) { + $type = node_type_load($node->type); $form['title'] = array( '#type' => 'textfield', '#title' => check_plain($type->title_label), diff --git a/core/modules/node/content_types.inc b/core/modules/node/content_types.inc index 9ca1e15a7ad..9073379c592 100644 --- a/core/modules/node/content_types.inc +++ b/core/modules/node/content_types.inc @@ -20,22 +20,21 @@ function node_overview_types() { foreach ($names as $key => $name) { $type = $types[$key]; if (node_hook($type->type, 'form')) { - $type_url_str = str_replace('_', '-', $type->type); $row = array(theme('node_admin_overview', array('name' => $name, 'type' => $type))); // Set the edit column. - $row[] = array('data' => l(t('edit'), 'admin/structure/types/manage/' . $type_url_str)); + $row[] = array('data' => l(t('edit'), 'admin/structure/types/manage/' . $type->type)); if ($field_ui) { // Manage fields. - $row[] = array('data' => l(t('manage fields'), 'admin/structure/types/manage/' . $type_url_str . '/fields')); + $row[] = array('data' => l(t('manage fields'), 'admin/structure/types/manage/' . $type->type . '/fields')); // Display fields. - $row[] = array('data' => l(t('manage display'), 'admin/structure/types/manage/' . $type_url_str . '/display')); + $row[] = array('data' => l(t('manage display'), 'admin/structure/types/manage/' . $type->type . '/display')); } // Set the delete column. if ($type->custom) { - $row[] = array('data' => l(t('delete'), 'admin/structure/types/manage/' . $type_url_str . '/delete')); + $row[] = array('data' => l(t('delete'), 'admin/structure/types/manage/' . $type->type . '/delete')); } else { $row[] = array('data' => ''); @@ -319,7 +318,7 @@ function node_type_form_submit($form, &$form_state) { } if ($op == t('Delete content type')) { - $form_state['redirect'] = 'admin/structure/types/manage/' . str_replace('_', '-', $type->old_type) . '/delete'; + $form_state['redirect'] = 'admin/structure/types/manage/' . $type->old_type . '/delete'; return; } diff --git a/core/modules/node/node.api.php b/core/modules/node/node.api.php index 783bf6ec5c1..ce3b784bfef 100644 --- a/core/modules/node/node.api.php +++ b/core/modules/node/node.api.php @@ -605,7 +605,8 @@ function hook_node_load($nodes, $types) { function hook_node_access($node, $op, $account) { $type = is_string($node) ? $node : $node->type; - if (in_array($type, node_permissions_get_configured_types())) { + $configured_types = node_permissions_get_configured_types(); + if (isset($configured_types[$type])) { if ($op == 'create' && user_access('create ' . $type . ' content', $account)) { return NODE_ACCESS_ALLOW; } @@ -1096,7 +1097,7 @@ function hook_prepare(Drupal\node\Node $node) { * @ingroup node_api_hooks */ function hook_form(Drupal\node\Node $node, &$form_state) { - $type = node_type_get_type($node); + $type = node_type_load($node->type); $form['title'] = array( '#type' => 'textfield', diff --git a/core/modules/node/node.module b/core/modules/node/node.module index f9c213d2a24..8dbc060edbd 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -133,12 +133,12 @@ function node_help($path, $arg) { case 'node/%/edit': $node = node_load($arg[1]); - $type = node_type_get_type($node); + $type = node_type_load($node->type); return (!empty($type->help) ? '

' . filter_xss_admin($type->help) . '

' : ''); } if ($arg[0] == 'node' && $arg[1] == 'add' && $arg[2]) { - $type = node_type_get_type(str_replace('-', '_', $arg[2])); + $type = node_type_load($arg[2]); return (!empty($type->help) ? '

' . filter_xss_admin($type->help) . '

' : ''); } } @@ -247,7 +247,7 @@ function node_entity_info() { 'label' => $name, 'admin' => array( 'path' => 'admin/structure/types/manage/%node_type', - 'real path' => 'admin/structure/types/manage/' . str_replace('_', '-', $type), + 'real path' => 'admin/structure/types/manage/' . $type, 'bundle argument' => 4, 'access arguments' => array('administer content types'), ), @@ -408,31 +408,12 @@ function _node_extract_type($node) { * @return * An array of node types, as objects, keyed by the type. * - * @see node_type_get_type() + * @see node_type_load() */ function node_type_get_types() { return _node_types_build()->types; } -/** - * Returns the node type of the passed node or node type string. - * - * @param Drupal\node\Node|string $node - * A node entity or string that indicates the node type to return. - * - * @return - * A single node type, as an object, or FALSE if the node type is not found. - * The node type is an object containing fields from hook_node_info() return - * values, as well as the field 'type' (the machine-readable type) and other - * fields used internally and defined in _node_types_build(), - * hook_node_info(), and node_type_set_defaults(). - */ -function node_type_get_type($node) { - $type = _node_extract_type($node); - $types = _node_types_build()->types; - return isset($types[$type]) ? $types[$type] : FALSE; -} - /** * Returns the node type base of the passed node or node type string. * @@ -498,14 +479,14 @@ function node_types_rebuild() { * Menu argument loader: Loads a node type by string. * * @param $name - * The machine-readable name of a node type to load, where '_' is replaced - * with '-'. + * The machine name of a node type to load. * * @return * A node type object or FALSE if $name does not exist. */ function node_type_load($name) { - return node_type_get_type(strtr($name, array('-' => '_'))); + $types = _node_types_build()->types; + return isset($types[$name]) ? $types[$name] : FALSE; } /** @@ -648,16 +629,16 @@ function node_field_extra_fields() { /** * Deletes a node type from the database. * - * @param $type - * The machine-readable name of the node type to be deleted. + * @param $name + * The machine name of the node type to delete. */ -function node_type_delete($type) { - $info = node_type_get_type($type); +function node_type_delete($name) { + $type = node_type_load($name); db_delete('node_type') - ->condition('type', $type) + ->condition('type', $name) ->execute(); - field_attach_delete_bundle('node', $type); - module_invoke_all('node_type_delete', $info); + field_attach_delete_bundle('node', $name); + module_invoke_all('node_type_delete', $type); // Clear the node type cache. node_type_cache_reset(); @@ -1009,8 +990,8 @@ function node_object_prepare(Node $node) { * * @see node_form_validate() */ -function node_validate($node, $form, &$form_state) { - $type = node_type_get_type($node); +function node_validate(Node $node, $form, &$form_state) { + $type = node_type_load($node->type); if (isset($node->nid) && (node_last_changed($node->nid) > $node->changed)) { form_set_error('changed', t('The content on this page has either been modified by another user, or you have already submitted modifications using this form. As a result, your changes cannot be saved.')); @@ -1439,7 +1420,7 @@ function node_permission() { ); // Generate standard node permissions for all applicable node types. - foreach (node_permissions_get_configured_types() as $type) { + foreach (node_permissions_get_configured_types() as $name => $type) { $perms += node_list_permissions($type); } @@ -1898,8 +1879,7 @@ function node_menu() { ); // @todo Remove this loop when we have a 'description callback' property. foreach (node_type_get_types() as $type) { - $type_url_str = str_replace('_', '-', $type->type); - $items['node/add/' . $type_url_str] = array( + $items['node/add/' . $type->type] = array( 'title' => $type->name, 'title callback' => 'check_plain', 'page callback' => 'node_add', @@ -2924,7 +2904,8 @@ function node_access($op, $node, $account = NULL) { function node_node_access($node, $op, $account) { $type = is_string($node) ? $node : $node->type; - if (in_array($type, node_permissions_get_configured_types())) { + $configured_types = node_permissions_get_configured_types(); + if (isset($configured_types[$type])) { if ($op == 'create' && user_access('create ' . $type . ' content', $account)) { return NODE_ACCESS_ALLOW; } @@ -2948,34 +2929,31 @@ function node_node_access($node, $op, $account) { /** * Helper function to generate standard node permission list for a given type. * - * @param $type - * The machine-readable name of the node type. + * @param $name + * The machine name of the node type. * * @return array * An array of permission names and descriptions. */ function node_list_permissions($type) { - $info = node_type_get_type($type); - // Build standard list of node permissions for this type. $perms = array( - "create $type content" => array( - 'title' => t('%type_name: Create new content', array('%type_name' => $info->name)), + "create $type->type content" => array( + 'title' => t('%type_name: Create new content', array('%type_name' => $type->name)), ), - "edit own $type content" => array( - 'title' => t('%type_name: Edit own content', array('%type_name' => $info->name)), + "edit own $type->type content" => array( + 'title' => t('%type_name: Edit own content', array('%type_name' => $type->name)), ), - "edit any $type content" => array( - 'title' => t('%type_name: Edit any content', array('%type_name' => $info->name)), + "edit any $type->type content" => array( + 'title' => t('%type_name: Edit any content', array('%type_name' => $type->name)), ), - "delete own $type content" => array( - 'title' => t('%type_name: Delete own content', array('%type_name' => $info->name)), + "delete own $type->type content" => array( + 'title' => t('%type_name: Delete own content', array('%type_name' => $type->name)), ), - "delete any $type content" => array( - 'title' => t('%type_name: Delete any content', array('%type_name' => $info->name)), + "delete any $type->type content" => array( + 'title' => t('%type_name: Delete any content', array('%type_name' => $type->name)), ), ); - return $perms; } @@ -2994,15 +2972,12 @@ function node_list_permissions($type) { * An array of node types managed by this module. */ function node_permissions_get_configured_types() { - $configured_types = array(); - - foreach (node_type_get_types() as $type => $info) { - if (variable_get('node_permissions_' . $type, 1)) { - $configured_types[] = $type; + foreach (node_type_get_types() as $name => $type) { + if (variable_get('node_permissions_' . $name, 1)) { + $configured_types[$name] = $type; } } - return $configured_types; } @@ -3533,10 +3508,10 @@ function _node_access_rebuild_batch_finished($success, $results, $operations) { * Implements hook_form(). */ function node_content_form(Node $node, $form_state) { - // It is impossible to define a content type without implementing hook_form() - // @todo: remove this requirement. + // @todo It is impossible to define a content type without implementing + // hook_form(). Remove this requirement. $form = array(); - $type = node_type_get_type($node); + $type = node_type_load($node->type); if ($type->has_title) { $form['title'] = array( diff --git a/core/modules/node/node.test b/core/modules/node/node.test index 655bc0bf567..c908584f9d1 100644 --- a/core/modules/node/node.test +++ b/core/modules/node/node.test @@ -1317,7 +1317,7 @@ class NodeTypeTestCase extends NodeWebTestCase { $this->assertEqual($node_types['article']->name, $node_names['article'], t('Correct node type base has been returned.')); - $this->assertEqual($node_types['article'], node_type_get_type('article'), t('Correct node type has been returned.')); + $this->assertEqual($node_types['article'], node_type_load('article'), t('Correct node type has been returned.')); $this->assertEqual($node_types['article']->name, node_type_get_name('article'), t('Correct node type name has been returned.')); $this->assertEqual($node_types['page']->base, node_type_get_base('page'), t('Correct node type base has been returned.')); } @@ -1336,7 +1336,7 @@ class NodeTypeTestCase extends NodeWebTestCase { $web_user = $this->drupalCreateUser(array('create ' . $type->name . ' content')); $this->drupalLogin($web_user); - $this->drupalGet('node/add/' . str_replace('_', '-', $type->name)); + $this->drupalGet('node/add/' . $type->type); $this->assertResponse(200, 'The new content type can be accessed at node/add.'); // Create a content type via the user interface. diff --git a/core/modules/poll/poll.module b/core/modules/poll/poll.module index 7c3a27e24f4..2e36e0b8c49 100644 --- a/core/modules/poll/poll.module +++ b/core/modules/poll/poll.module @@ -218,12 +218,12 @@ function poll_field_extra_fields() { /** * Implements hook_form(). */ -function poll_form($node, &$form_state) { +function poll_form(Node $node, &$form_state) { global $user; $admin = user_access('bypass node access') || user_access('edit any poll content') || (user_access('edit own poll content') && $user->uid == $node->uid); - $type = node_type_get_type($node); + $type = node_type_load($node->type); // The submit handlers to add more poll choices require that this form is // cached, regardless of whether Ajax is used. diff --git a/core/modules/simpletest/drupal_web_test_case.php b/core/modules/simpletest/drupal_web_test_case.php index 6fdd993a108..8b85dfc57be 100644 --- a/core/modules/simpletest/drupal_web_test_case.php +++ b/core/modules/simpletest/drupal_web_test_case.php @@ -986,7 +986,7 @@ class DrupalWebTestCase extends DrupalTestCase { // Find a non-existent random type name. do { $name = strtolower($this->randomName(8)); - } while (node_type_get_type($name)); + } while (node_type_load($name)); // Populate defaults array. $defaults = array( diff --git a/core/modules/taxonomy/taxonomy.test b/core/modules/taxonomy/taxonomy.test index eaac99c78e9..93b86f975cd 100644 --- a/core/modules/taxonomy/taxonomy.test +++ b/core/modules/taxonomy/taxonomy.test @@ -1536,7 +1536,7 @@ class TaxonomyTermFieldTestCase extends TaxonomyWebTestCase { // Display creation form. $langcode = LANGUAGE_NOT_SPECIFIED; - $this->drupalGet('test-entity/add/test-bundle'); + $this->drupalGet('test-entity/add/test_bundle'); $this->assertFieldByName("{$this->field_name}[$langcode]", '', 'Widget is displayed.'); // Submit with some value. @@ -1558,7 +1558,7 @@ class TaxonomyTermFieldTestCase extends TaxonomyWebTestCase { // Delete the vocabulary and verify that the widget is gone. taxonomy_vocabulary_delete($this->vocabulary->vid); - $this->drupalGet('test-entity/add/test-bundle'); + $this->drupalGet('test-entity/add/test_bundle'); $this->assertNoFieldByName("{$this->field_name}[$langcode]", '', 'Widget is not displayed'); } @@ -1669,7 +1669,7 @@ class TaxonomyTermFieldMultipleVocabularyTestCase extends TaxonomyWebTestCase { // Submit an entity with both terms. $langcode = LANGUAGE_NOT_SPECIFIED; - $this->drupalGet('test-entity/add/test-bundle'); + $this->drupalGet('test-entity/add/test_bundle'); $this->assertFieldByName("{$this->field_name}[$langcode][]", '', 'Widget is displayed'); $edit = array( "{$this->field_name}[$langcode][]" => array($term1->tid, $term2->tid), @@ -1708,7 +1708,7 @@ class TaxonomyTermFieldMultipleVocabularyTestCase extends TaxonomyWebTestCase { $this->assertEqual(sizeof($field_info['settings']['allowed_values']), 1, 'Only one vocabulary is allowed for the field.'); // The widget should still be displayed. - $this->drupalGet('test-entity/add/test-bundle'); + $this->drupalGet('test-entity/add/test_bundle'); $this->assertFieldByName("{$this->field_name}[$langcode][]", '', 'Widget is still displayed'); // Term 1 should still pass validation. diff --git a/core/modules/translation/translation.pages.inc b/core/modules/translation/translation.pages.inc index d85b5e240dd..a6e8b3c26cb 100644 --- a/core/modules/translation/translation.pages.inc +++ b/core/modules/translation/translation.pages.inc @@ -62,7 +62,7 @@ function translation_node_overview(Node $node) { $title = t('n/a'); if (node_access('create', $node)) { $text = t('add translation'); - $path = 'node/add/' . str_replace('_', '-', $node->type); + $path = 'node/add/' . $node->type; $links = language_negotiation_get_switch_links($type, $path); $query = array('query' => array('translation' => $node->nid, 'target' => $langcode)); $options[] = empty($links->links[$langcode]['href']) ? l($text, $path, $query) : l($text, $links->links[$langcode]['href'], array_merge_recursive($links->links[$langcode], $query)); diff --git a/core/modules/translation/translation.test b/core/modules/translation/translation.test index 15a324e8194..c9b3dcb3327 100644 --- a/core/modules/translation/translation.test +++ b/core/modules/translation/translation.test @@ -75,7 +75,7 @@ class TranslationTestCase extends DrupalWebTestCase { $languages = language_list(); $prefixes = language_negotiation_url_prefixes(); $this->drupalGet('node/' . $node->nid . '/translate'); - $this->assertLinkByHref($prefixes['es'] . '/node/add/' . str_replace('_', '-', $node->type), 0, t('The "add translation" link for %language points to the localized path of the target language.', array('%language' => $languages['es']->name))); + $this->assertLinkByHref($prefixes['es'] . '/node/add/' . $node->type, 0, t('The "add translation" link for %language points to the localized path of the target language.', array('%language' => $languages['es']->name))); // Submit translation in Spanish. $node_translation_title = $this->randomName(); From eb745338f77d5e5bf9d8e7230e98c2d8c604689a Mon Sep 17 00:00:00 2001 From: Jennifer Hodgdon Date: Tue, 8 May 2012 11:20:05 -0700 Subject: [PATCH 09/11] Issue #1513580 by matt2000: Update hook_init and hook_boot docs to say whether themes are loaded when they run --- core/modules/system/system.api.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php index 74240154476..574a132b7be 100644 --- a/core/modules/system/system.api.php +++ b/core/modules/system/system.api.php @@ -1398,8 +1398,8 @@ function hook_forms($form_id, $args) { * used to set up global parameters that are needed later in the request. * * Only use this hook if your code must run even for cached page views. This - * hook is called before modules or most include files are loaded into memory. - * It happens while Drupal is still in bootstrap mode. + * hook is called before the theme, modules, or most include files are loaded + * into memory. It happens while Drupal is still in bootstrap mode. * * @see hook_init() */ @@ -1414,7 +1414,8 @@ function hook_boot() { * * This hook is run at the beginning of the page request. It is typically * used to set up global parameters that are needed later in the request. - * When this hook is called, all modules are already loaded in memory. + * When this hook is called, the theme and all modules are already loaded in + * memory. * * This hook is not run on cached pages. * From f263e898da2700e1eb1035fb67652877a27eb932 Mon Sep 17 00:00:00 2001 From: catch Date: Wed, 9 May 2012 13:38:47 +0900 Subject: [PATCH 10/11] Issue #1551626 by moshe weitzman: follow-up to disable page caching in cron callback --- core/modules/system/system.module | 1 + 1 file changed, 1 insertion(+) diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 987137b5526..f26bb07b93b 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -1120,6 +1120,7 @@ function system_menu() { * @see system_cron_access(). */ function system_cron_page() { + drupal_page_is_cacheable(FALSE); drupal_cron_run(); // Returning nothing causes no output to be generated. From 352645e4a636cadeb5576231b3547972eebdd8e5 Mon Sep 17 00:00:00 2001 From: catch Date: Wed, 9 May 2012 13:43:25 +0900 Subject: [PATCH 11/11] mlhess, coltrane, xjm, and jhodgdon, penyaskito: forward port DRUPAL-SA-CORE-2012-002 - Access bypass - forum listing. --- core/modules/forum/forum.module | 59 ++++++++++++++++++------------- core/modules/forum/forum.test | 62 +++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 24 deletions(-) diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module index 07bee65c8a7..ae52befd5de 100644 --- a/core/modules/forum/forum.module +++ b/core/modules/forum/forum.module @@ -547,32 +547,43 @@ function forum_field_storage_pre_insert($entity_type, $entity, &$skip_fields) { function forum_field_storage_pre_update($entity_type, $entity, &$skip_fields) { $first_call = &drupal_static(__FUNCTION__, array()); - if ($entity_type == 'node' && $entity->status && _forum_node_check_node_type($entity)) { - // We don't maintain data for old revisions, so clear all previous values - // from the table. Since this hook runs once per field, per object, make - // sure we only wipe values once. - if (!isset($first_call[$entity->nid])) { - $first_call[$entity->nid] = FALSE; + if ($entity_type == 'node' && _forum_node_check_node_type($entity)) { + + // If the node is published, update the forum index. + if ($entity->status) { + + // We don't maintain data for old revisions, so clear all previous values + // from the table. Since this hook runs once per field, per object, make + // sure we only wipe values once. + if (!isset($first_call[$entity->nid])) { + $first_call[$entity->nid] = FALSE; + db_delete('forum_index')->condition('nid', $entity->nid)->execute(); + } + $query = db_insert('forum_index')->fields(array('nid', 'title', 'tid', 'sticky', 'created', 'comment_count', 'last_comment_timestamp')); + foreach ($entity->taxonomy_forums as $language) { + foreach ($language as $item) { + $query->values(array( + 'nid' => $entity->nid, + 'title' => $entity->title, + 'tid' => $item['tid'], + 'sticky' => $entity->sticky, + 'created' => $entity->created, + 'comment_count' => 0, + 'last_comment_timestamp' => $entity->created, + )); + } + } + $query->execute(); + // The logic for determining last_comment_count is fairly complex, so + // call _forum_update_forum_index() too. + _forum_update_forum_index($entity->nid); + } + + // When a forum node is unpublished, remove it from the forum_index table. + else { db_delete('forum_index')->condition('nid', $entity->nid)->execute(); } - $query = db_insert('forum_index')->fields(array('nid', 'title', 'tid', 'sticky', 'created', 'comment_count', 'last_comment_timestamp')); - foreach ($entity->taxonomy_forums as $language) { - foreach ($language as $item) { - $query->values(array( - 'nid' => $entity->nid, - 'title' => $entity->title, - 'tid' => $item['tid'], - 'sticky' => $entity->sticky, - 'created' => $entity->created, - 'comment_count' => 0, - 'last_comment_timestamp' => $entity->created, - )); - } - } - $query->execute(); - // The logic for determining last_comment_count is fairly complex, so - // call _forum_update_forum_index() too. - _forum_update_forum_index($entity->nid); + } } diff --git a/core/modules/forum/forum.test b/core/modules/forum/forum.test index 135f551c331..9d8a9f1fc8e 100644 --- a/core/modules/forum/forum.test +++ b/core/modules/forum/forum.test @@ -590,3 +590,65 @@ class ForumTestCase extends DrupalWebTestCase { } } } + +/** + * Tests the forum index listing. + */ +class ForumIndexTestCase extends DrupalWebTestCase { + + public static function getInfo() { + return array( + 'name' => 'Forum index', + 'description' => 'Tests the forum index listing.', + 'group' => 'Forum', + ); + } + + function setUp() { + parent::setUp('taxonomy', 'comment', 'forum'); + + // Create a test user. + $web_user = $this->drupalCreateUser(array('create forum content', 'edit own forum content', 'edit any forum content', 'administer nodes')); + $this->drupalLogin($web_user); + } + + /** + * Tests the forum index for published and unpublished nodes. + */ + function testForumIndexStatus() { + + $langcode = LANGUAGE_NOT_SPECIFIED; + + // The forum ID to use. + $tid = 1; + + // Create a test node. + $title = $this->randomName(20); + $edit = array( + "title" => $title, + "body[$langcode][0][value]" => $this->randomName(200), + ); + + // Create the forum topic, preselecting the forum ID via a URL parameter. + $this->drupalPost('node/add/forum/' . $tid, $edit, t('Save')); + + // Check that the node exists in the database. + $node = $this->drupalGetNodeByTitle($title); + $this->assertTrue(!empty($node), 'New forum node found in database.'); + + // Verify that the node appears on the index. + $this->drupalGet('forum/' . $tid); + $this->assertText($title, 'Published forum topic appears on index.'); + + // Unpublish the node. + $edit = array( + 'status' => FALSE, + ); + $this->drupalPost("node/{$node->nid}/edit", $edit, t('Save')); + $this->assertText(t('Access denied'), 'Unpublished node is no longer accessible.'); + + // Verify that the node no longer appears on the index. + $this->drupalGet('forum/' . $tid); + $this->assertNoText($title, 'Unpublished forum topic no longer appears on index.'); + } +}