diff options
Diffstat (limited to 'modules')
-rw-r--r-- | modules/block/block.install | 38 | ||||
-rw-r--r-- | modules/block/block.module | 4 | ||||
-rw-r--r-- | modules/comment/comment.install | 33 | ||||
-rw-r--r-- | modules/filter/filter.install | 2 | ||||
-rw-r--r-- | modules/filter/filter.module | 31 | ||||
-rw-r--r-- | modules/filter/filter.test | 114 | ||||
-rw-r--r-- | modules/node/node.install | 25 | ||||
-rw-r--r-- | modules/simpletest/drupal_web_test_case.php | 25 | ||||
-rw-r--r-- | modules/taxonomy/taxonomy.admin.inc | 2 | ||||
-rw-r--r-- | modules/taxonomy/taxonomy.install | 10 | ||||
-rw-r--r-- | modules/taxonomy/taxonomy.test | 2 | ||||
-rw-r--r-- | modules/user/user.install | 54 |
12 files changed, 272 insertions, 68 deletions
diff --git a/modules/block/block.install b/modules/block/block.install index 1a6ec333a..b45c5e5e2 100644 --- a/modules/block/block.install +++ b/modules/block/block.install @@ -156,9 +156,8 @@ function block_schema() { ), 'format' => array( 'type' => 'int', - 'size' => 'small', - 'not null' => TRUE, - 'default' => 0, + 'unsigned' => TRUE, + 'not null' => FALSE, 'description' => 'The {filter_format}.format of the block body.', ), ), @@ -189,6 +188,19 @@ function block_install() { } /** + * Implements hook_update_dependencies(). + */ +function block_update_dependencies() { + // Block update 7005 needs to query the list of existing text formats and + // therefore must run after filter_update_7000(). + $dependencies['block'][7005] = array( + 'filter' => 7000, + ); + + return $dependencies; +} + +/** * @defgroup updates-6.x-to-7.x Block updates from 6.x to 7.x * @{ */ @@ -397,13 +409,25 @@ function block_update_7004() { * Update the {block_custom}.format column. */ function block_update_7005() { - // It was previously possible for a value of "0" to be stored in database - // tables to indicate that a particular piece of text should be filtered - // using the default text format. + // For an explanation of these updates, see the code comments in + // user_update_7010(). + db_change_field('block_custom', 'format', 'format', array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => FALSE, + 'description' => 'The {filter_format}.format of the block body.', + )); + db_update('block_custom') + ->fields(array('format' => NULL)) + ->condition('body', '') + ->condition('format', 0) + ->execute(); + $existing_formats = db_query("SELECT format FROM {filter_format}")->fetchCol(); $default_format = variable_get('filter_default_format', 1); db_update('block_custom') ->fields(array('format' => $default_format)) - ->condition('format', 0) + ->isNotNull('format') + ->condition('format', $existing_formats, 'NOT IN') ->execute(); } diff --git a/modules/block/block.module b/modules/block/block.module index ba2f8001d..3a0be2520 100644 --- a/modules/block/block.module +++ b/modules/block/block.module @@ -219,10 +219,12 @@ function block_block_info() { * Implements hook_block_configure(). */ function block_block_configure($delta = 0) { - $custom_block = array('format' => filter_default_format()); if ($delta) { $custom_block = block_custom_block_get($delta); } + else { + $custom_block = array(); + } return block_custom_block_form($custom_block); } diff --git a/modules/comment/comment.install b/modules/comment/comment.install index 03b21860c..6a7b03427 100644 --- a/modules/comment/comment.install +++ b/modules/comment/comment.install @@ -87,6 +87,12 @@ function comment_update_dependencies() { 'system' => 7021, ); + // Comment update 7006 needs to query the list of existing text formats and + // therefore must run after filter_update_7000(). + $dependencies['comment'][7006] = array( + 'filter' => 7000, + ); + return $dependencies; } @@ -300,24 +306,31 @@ function comment_update_7006(&$sandbox) { $query->addField('c', 'comment', 'comment_body_value'); $query->addField('c', 'format', 'comment_body_format'); - $comment_body_table = 'field_data_comment_body'; - - db_insert($comment_body_table) + db_insert('field_data_comment_body') ->from($query) ->execute(); - // Update the comment body format in a similar manner as is done for other - // modules in filter_update_7005(), but we do this one here since we are - // already migrating the data. - db_update($comment_body_table) - ->fields(array('comment_body_format' => variable_get('filter_default_format', 1))) - ->condition('comment_body_format', 0) - ->execute(); $sandbox['#finished'] = 1 - count($sandbox['types']) / $sandbox['total']; } // On the last pass of the update, $sandbox['types'] will be empty. if (empty($sandbox['types'])) { + // Update the comment body text formats. For an explanation of these + // updates, see the code comments in user_update_7010(). + db_update('field_data_comment_body') + ->fields(array('comment_body_format' => NULL)) + ->condition('comment_body_value', '') + ->condition('comment_body_format', 0) + ->execute(); + $existing_formats = db_query("SELECT format FROM {filter_format}")->fetchCol(); + $default_format = variable_get('filter_default_format', 1); + db_update('field_data_comment_body') + ->fields(array('comment_body_format' => $default_format)) + ->isNotNull('comment_body_format') + ->condition('comment_body_format', $existing_formats, 'NOT IN') + ->execute(); + + // Finally, remove the old comment data. db_drop_field('comment', 'comment'); db_drop_field('comment', 'format'); } diff --git a/modules/filter/filter.install b/modules/filter/filter.install index 534b9296a..a02712140 100644 --- a/modules/filter/filter.install +++ b/modules/filter/filter.install @@ -435,7 +435,7 @@ function filter_update_7005() { ->execute(); // We do not delete the 'filter_default_format' variable, since other modules - // may need it in their update functions. + // need it in their update functions; for an example, see user_update_7010(). // @todo This variable can be deleted in Drupal 8. } diff --git a/modules/filter/filter.module b/modules/filter/filter.module index 669996319..ccd1b2cfc 100644 --- a/modules/filter/filter.module +++ b/modules/filter/filter.module @@ -751,8 +751,8 @@ function check_markup($text, $format_id = NULL, $langcode = '', $cache = FALSE) * The form element to process. Properties used: * - #base_type: The form element #type to use for the 'value' element. * 'textarea' by default. - * - #format: (optional) The text format id to preselect. If 0, NULL, or not - * set, the default format for the current user will be used. + * - #format: (optional) The text format id to preselect. If NULL or not set, + * the default format for the current user will be used. * * @return * The expanded element. @@ -820,9 +820,10 @@ function filter_process_format($element) { } // Use the default format for this user if none was selected. - if (empty($element['#format'])) { + if (!isset($element['#format'])) { $element['#format'] = filter_default_format($user); } + $element['format']['format'] = array( '#type' => 'select', '#title' => t('Text format'), @@ -841,20 +842,30 @@ function filter_process_format($element) { '#weight' => 0, ); - // Lastly, disallow editing of this field if the user is not allowed to use - // the stored and preselected text format. But only, if that format actually - // exists. $all_formats = filter_formats(); - if (!isset($formats[$element['#format']]) && isset($all_formats[$element['#format']])) { + $format_exists = isset($all_formats[$element['#format']]); + $user_has_access = isset($formats[$element['#format']]); + $user_is_admin = user_access('administer filters'); + + // If the stored format does not exist, administrators have to assign a new + // format. + if (!$format_exists && $user_is_admin) { + $element['format']['format']['#default_value'] = NULL; + // Force access to the format selector (it may have been denied above if + // the user only has access to a single format). + $element['format']['format']['#access'] = TRUE; + } + // Disable this widget, if the user is not allowed to use the stored format, + // or if the stored format does not exist. The 'administer filters' permission + // only grants access to the filter administration, not to all formats. + elseif (!$user_has_access || !$format_exists) { // Overload default values into #value to make them unalterable. $element['value']['#value'] = $element['value']['#default_value']; $element['format']['format']['#value'] = $element['format']['format']['#default_value']; // Prepend #pre_render callback to replace field value with user notice // prior to rendering. - if (!isset($element['value']['#pre_render'])) { - $element['value']['#pre_render'] = array(); - } + $element['value'] += array('#pre_render' => array()); array_unshift($element['value']['#pre_render'], 'filter_form_access_denied'); // Cosmetic adjustments. diff --git a/modules/filter/filter.test b/modules/filter/filter.test index 9297356e2..6f98dd941 100644 --- a/modules/filter/filter.test +++ b/modules/filter/filter.test @@ -396,6 +396,7 @@ class FilterAdminTestCase extends DrupalWebTestCase { class FilterFormatAccessTestCase extends DrupalWebTestCase { protected $admin_user; + protected $filter_admin_user; protected $web_user; protected $allowed_format; protected $disallowed_format; @@ -411,16 +412,16 @@ class FilterFormatAccessTestCase extends DrupalWebTestCase { function setUp() { parent::setUp(); - $this->full_html_format = db_query_range('SELECT * FROM {filter_format} WHERE name = :name', 0, 1, array(':name' => 'Full HTML'))->fetchObject(); - - // Create two text formats and grant a regular user access to one of them. - $this->admin_user = $this->drupalCreateUser(array( + // Create a user who can administer text formats, but does not have + // specific permission to use any of them. + $this->filter_admin_user = $this->drupalCreateUser(array( 'administer filters', 'create page content', 'edit any page content', - filter_permission_name($this->full_html_format), )); - $this->drupalLogin($this->admin_user); + + // Create two text formats. + $this->drupalLogin($this->filter_admin_user); $formats = array(); for ($i = 0; $i < 2; $i++) { $edit = array('name' => $this->randomName()); @@ -430,11 +431,23 @@ class FilterFormatAccessTestCase extends DrupalWebTestCase { $formats[] = filter_format_load($format_id); } list($this->allowed_format, $this->disallowed_format) = $formats; + $this->drupalLogout(); + // Create a regular user with access to one of the formats. $this->web_user = $this->drupalCreateUser(array( 'create page content', + 'edit any page content', filter_permission_name($this->allowed_format), )); + + // Create an administrative user who has access to use both formats. + $this->admin_user = $this->drupalCreateUser(array( + 'administer filters', + 'create page content', + 'edit any page content', + filter_permission_name($this->allowed_format), + filter_permission_name($this->disallowed_format), + )); } function testFormatPermissions() { @@ -487,8 +500,11 @@ class FilterFormatAccessTestCase extends DrupalWebTestCase { /** * Test editing a page using a disallowed text format. * - * Verifies that a regular user is able to edit a page, but is not allowed to - * change the fields which use an inaccessible text format. + * Verifies that regular users and administrators are able to edit a page, + * but not allowed to change the fields which use an inaccessible text + * format. Also verifies that fields which use a text format that does not + * exist can be edited by administrators only, but that the administrator is + * forced to choose a new format before saving the page. */ function testFormatWidgetPermissions() { $langcode = LANGUAGE_NONE; @@ -501,16 +517,12 @@ class FilterFormatAccessTestCase extends DrupalWebTestCase { $edit = array(); $edit['title'] = $this->randomName(8); $edit[$body_value_key] = $this->randomName(16); - $edit[$body_format_key] = $this->full_html_format->format; + $edit[$body_format_key] = $this->disallowed_format->format; $this->drupalPost('node/add/page', $edit, t('Save')); $node = $this->drupalGetNodeByTitle($edit['title']); // Try to edit with a less privileged user. - $this->moderator = $this->drupalCreateUser(array( - 'edit any page content', - 'create page content', - )); - $this->drupalLogin($this->moderator); + $this->drupalLogin($this->web_user); $this->drupalGet('node/' . $node->nid); $this->clickLink(t('Edit')); @@ -529,14 +541,82 @@ class FilterFormatAccessTestCase extends DrupalWebTestCase { $this->assertText($new_edit['title'], t('New title found.')); $this->assertText($edit[$body_value_key], t('Old body found.')); - // Disable the Full HTML text format. - filter_format_disable($this->full_html_format); + // Check that even an administrator with "administer filters" permission + // cannot edit the body field if they do not have specific permission to + // use its stored format. (This must be disallowed so that the + // administrator is never forced to switch the text format to something + // else.) + $this->drupalLogin($this->filter_admin_user); + $this->drupalGet('node/' . $node->nid . '/edit'); + $this->assertFieldByXPath("//textarea[@name='$body_value_key' and @disabled='disabled']", t('This field has been disabled because you do not have sufficient permissions to edit it.'), t('Text format access denied message found.')); + + // Disable the text format used above. + filter_format_disable($this->disallowed_format); $this->resetFilterCaches(); - // Verify that body field can be edited and a new format can be selected. + // Log back in as the less privileged user and verify that the body field + // is still disabled, since the less privileged user should not be able to + // edit content that does not have an assigned format. + $this->drupalLogin($this->web_user); + $this->drupalGet('node/' . $node->nid . '/edit'); + $this->assertFieldByXPath("//textarea[@name='$body_value_key' and @disabled='disabled']", t('This field has been disabled because you do not have sufficient permissions to edit it.'), t('Text format access denied message found.')); + + // Log back in as the filter administrator and verify that the body field + // can be edited. + $this->drupalLogin($this->filter_admin_user); $this->drupalGet('node/' . $node->nid . '/edit'); $this->assertNoFieldByXPath("//textarea[@name='$body_value_key' and @disabled='disabled']", NULL, t('Text format access denied message not found.')); $this->assertFieldByXPath("//select[@name='$body_format_key']", NULL, t('Text format selector found.')); + + // Verify that trying to save the node without selecting a new text format + // produces an error message, and does not result in the node being saved. + $old_title = $new_edit['title']; + $new_title = $this->randomName(8); + $edit = array('title' => $new_title); + $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save')); + $this->assertText(t('!name field is required.', array('!name' => t('Text format'))), t('Error message is displayed.')); + $this->drupalGet('node/' . $node->nid); + $this->assertText($old_title, t('Old title found.')); + $this->assertNoText($new_title, t('New title not found.')); + + // Now select a new text format and make sure the node can be saved. + $edit[$body_format_key] = filter_fallback_format(); + $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save')); + $this->assertUrl('node/' . $node->nid); + $this->assertText($new_title, t('New title found.')); + $this->assertNoText($old_title, t('Old title not found.')); + + // Switch the text format to a new one, then disable that format and all + // other formats on the site (leaving only the fallback format). + $this->drupalLogin($this->admin_user); + $edit = array($body_format_key => $this->allowed_format->format); + $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save')); + $this->assertUrl('node/' . $node->nid); + foreach (filter_formats() as $format) { + if ($format->format != filter_fallback_format()) { + filter_format_disable($format); + } + } + + // Since there is now only one available text format, the widget for + // selecting a text format would normally not display when the content is + // edited. However, we need to verify that the filter administrator still + // is forced to make a conscious choice to reassign the text to a different + // format. + $this->drupalLogin($this->filter_admin_user); + $old_title = $new_title; + $new_title = $this->randomName(8); + $edit = array('title' => $new_title); + $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save')); + $this->assertText(t('!name field is required.', array('!name' => t('Text format'))), t('Error message is displayed.')); + $this->drupalGet('node/' . $node->nid); + $this->assertText($old_title, t('Old title found.')); + $this->assertNoText($new_title, t('New title not found.')); + $edit[$body_format_key] = filter_fallback_format(); + $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save')); + $this->assertUrl('node/' . $node->nid); + $this->assertText($new_title, t('New title found.')); + $this->assertNoText($old_title, t('Old title not found.')); } /** diff --git a/modules/node/node.install b/modules/node/node.install index 14f1b9de8..f63caa1e7 100644 --- a/modules/node/node.install +++ b/modules/node/node.install @@ -411,6 +411,9 @@ function node_update_dependencies() { // the Field module has been enabled, but before upgrading field data. $dependencies['node'][7006] = array( 'system' => 7049, + // It must also run after filter_update_7000() because it needs to query + // the list of existing text formats. + 'filter' => 7000, ); $dependencies['system'][7050] = array( 'node' => 7006, @@ -567,6 +570,9 @@ function node_update_7006(&$sandbox) { ); } + // Used below when updating the stored text format of each node body. + $sandbox['existing_text_formats'] = db_query("SELECT format FROM {filter_format}")->fetchCol(); + // Initialize state for future calls. $sandbox['last'] = 0; $sandbox['count'] = 0; @@ -625,11 +631,20 @@ function node_update_7006(&$sandbox) { $revision->body = substr($revision->body, strlen($break)); } $node->body[$langcode][0]['value'] = $revision->body; - // Explicitly store the current default text format if the revision - // did not have its own text format. Similar conversions for other - // core modules are performed in filter_update_7005(), but we do this - // one here since we are already migrating the data. - $node->body[$langcode][0]['format'] = !empty($revision->format) ? $revision->format : variable_get('filter_default_format', 1); + // Update the revision's text format for the changes to the Drupal 7 + // filter system. This uses the same kind of logic that occurs, for + // example, in user_update_7010(), but we do this here rather than + // via a separate set of database queries, since we are already + // migrating the data. + if (empty($revision->body) && empty($revision->format)) { + $node->body[$langcode][0]['format'] = NULL; + } + elseif (!in_array($revision->format, $sandbox['existing_text_formats'])) { + $node->body[$langcode][0]['format'] = variable_get('filter_default_format', 1); + } + else { + $node->body[$langcode][0]['format'] = $revision->format; + } // This is a core update and no contrib modules are enabled yet, so // we can assume default field storage for a faster update. field_sql_storage_field_storage_write('node', $node, FIELD_STORAGE_INSERT, array($body_field_id)); diff --git a/modules/simpletest/drupal_web_test_case.php b/modules/simpletest/drupal_web_test_case.php index b6c901695..d75f761d6 100644 --- a/modules/simpletest/drupal_web_test_case.php +++ b/modules/simpletest/drupal_web_test_case.php @@ -2518,6 +2518,31 @@ class DrupalWebTestCase extends DrupalTestCase { } /** + * Pass if the internal browser's URL matches the given path. + * + * @param $path + * The expected system path. + * @param $options + * (optional) Any additional options to pass for $path to url(). + * @param $message + * Message to display. + * @param $group + * The group this message belongs to, defaults to 'Other'. + * + * @return + * TRUE on pass, FALSE on fail. + */ + protected function assertUrl($path, array $options = array(), $message = '', $group = 'Other') { + if (!$message) { + $message = t('Current URL is @url.', array( + '@url' => var_export(url($path, $options), TRUE), + )); + } + $options['absolute'] = TRUE; + return $this->assertEqual($this->getUrl(), url($path, $options), $message, $group); + } + + /** * Pass if the raw text IS found on the loaded page, fail otherwise. Raw text * refers to the raw HTML that the page generated. * diff --git a/modules/taxonomy/taxonomy.admin.inc b/modules/taxonomy/taxonomy.admin.inc index e89923ba9..8cdd14b2d 100644 --- a/modules/taxonomy/taxonomy.admin.inc +++ b/modules/taxonomy/taxonomy.admin.inc @@ -656,7 +656,7 @@ function taxonomy_form_term($form, &$form_state, $edit = array(), $vocabulary = $defaults = array( 'name' => '', 'description' => '', - 'format' => filter_default_format(), + 'format' => NULL, 'vocabulary_machine_name' => isset($vocabulary) ? $vocabulary->machine_name : NULL, 'tid' => NULL, 'weight' => 0, diff --git a/modules/taxonomy/taxonomy.install b/modules/taxonomy/taxonomy.install index 51444fe3d..8bd3a31db 100644 --- a/modules/taxonomy/taxonomy.install +++ b/modules/taxonomy/taxonomy.install @@ -52,9 +52,8 @@ function taxonomy_schema() { ), 'format' => array( 'type' => 'int', - 'size' => 'small', - 'not null' => TRUE, - 'default' => 0, + 'unsigned' => TRUE, + 'not null' => FALSE, 'description' => 'The {filter_format}.format of the description.', ), 'weight' => array( @@ -736,9 +735,8 @@ function taxonomy_update_7005(&$sandbox) { function taxonomy_update_7006() { db_add_field('taxonomy_term_data', 'format', array( 'type' => 'int', - 'size' => 'small', - 'not null' => TRUE, - 'default' => 0, + 'unsigned' => TRUE, + 'not null' => FALSE, 'description' => 'The {filter_format}.format of the description.', )); } diff --git a/modules/taxonomy/taxonomy.test b/modules/taxonomy/taxonomy.test index b71cc62c5..9edc6c70f 100644 --- a/modules/taxonomy/taxonomy.test +++ b/modules/taxonomy/taxonomy.test @@ -34,6 +34,8 @@ class TaxonomyWebTestCase extends DrupalWebTestCase { $term = new stdClass(); $term->name = $this->randomName(); $term->description = $this->randomName(); + // Use the first available text format. + $term->format = db_query_range('SELECT format FROM {filter_format}', 0, 1)->fetchField(); $term->vid = $vocabulary->vid; taxonomy_term_save($term); return $term; diff --git a/modules/user/user.install b/modules/user/user.install index 2eeb31764..00afd2dc0 100644 --- a/modules/user/user.install +++ b/modules/user/user.install @@ -168,9 +168,8 @@ function user_schema() { ), 'signature_format' => array( 'type' => 'int', - 'size' => 'small', - 'not null' => TRUE, - 'default' => 0, + 'unsigned' => TRUE, + 'not null' => FALSE, 'description' => 'The {filter_format}.format of the signature.', ), 'created' => array( @@ -346,8 +345,9 @@ function user_update_dependencies() { $dependencies['system'][7000] = array( 'user' => 7008, ); - // user_update_7006 relies on filter_update_7002. - // TODO: move user_update_7006 down below in the upgrade process. + // Both user_update_7006() and user_update_7010() need to query the list of + // existing text formats and therefore must run after filter_update_7003(). + // @todo: move user_update_7006 down below in the upgrade process. $dependencies['user'][7006] = array( 'filter' => 7003, ); @@ -633,17 +633,51 @@ function user_update_7009() { * Update the {user}.signature_format column. */ function user_update_7010() { - // It was previously possible for a value of "0" to be stored in database - // tables to indicate that a particular piece of text should be filtered - // using the default text format. + // Update the database column to allow NULL values. + db_change_field('users', 'signature_format', 'signature_format', array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => FALSE, + 'description' => 'The {filter_format}.format of the signature.', + )); + + // Replace the signature format with NULL if the signature is empty and does + // not already have a stored text format. + // + // In Drupal 6, "0" (the former FILTER_FORMAT_DEFAULT constant) could be used + // to indicate this situation, but in Drupal 7, only NULL is supported. This + // update therefore preserves the ability of user accounts which were never + // given a signature (for example, if the site did not have user signatures + // enabled, or if the user never edited their account information) to not + // have a particular text format assumed for them the first time the + // signature is edited. + db_update('users') + ->fields(array('signature_format' => NULL)) + ->condition('signature', '') + ->condition('signature_format', 0) + ->execute(); + + // There are a number of situations in which a Drupal 6 site could store + // content with a nonexistent text format. This includes text formats that + // had later been deleted, or non-empty content stored with a value of "0" + // (the former FILTER_FORMAT_DEFAULT constant). Drupal 6 would filter this + // content using whatever the site-wide default text format was at the moment + // the text was being displayed. + // + // In Drupal 7, this behavior is no longer supported, and all content must be + // stored with an explicit text format (or it will not be displayed when it + // is filtered). Therefore, to preserve the behavior of the site after the + // upgrade, we must replace all instances described above with the current + // value of the (old) site-wide default format at the moment of the upgrade. + $existing_formats = db_query("SELECT format FROM {filter_format}")->fetchCol(); $default_format = variable_get('filter_default_format', 1); db_update('users') ->fields(array('signature_format' => $default_format)) - ->condition('signature_format', 0) + ->isNotNull('signature_format') + ->condition('signature_format', $existing_formats, 'NOT IN') ->execute(); } - /** * Updates email templates to use new tokens. * |