Index: includes/form.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/form.inc,v retrieving revision 1.324 diff -u -p -r1.324 form.inc --- includes/form.inc 14 Mar 2009 20:13:26 -0000 1.324 +++ includes/form.inc 26 Mar 2009 20:08:59 -0000 @@ -1914,25 +1914,49 @@ function form_process_radios($element) { * @see system_elements(), filter_form() */ function form_process_text_format($element) { - if (isset($element['#text_format'])) { - // Determine the form element parents and element name to use for the input - // format widget. This simulates the 'element' and 'element_format' pair of - // parents that filter_form() expects. - $element_parents = $element['#parents']; - $element_name = array_pop($element_parents); - $element_parents[] = $element_name . '_format'; - - // We need to break references, otherwise form_builder recurses infinitely. - $element['value'] = (array)$element; - $element['#type'] = 'markup'; - $element['#theme'] = NULL; - $element['#theme_wrapper'] = NULL; - $element['format'] = filter_form($element['#text_format'], 1, $element_parents); - - // We need to clear the #text_format from the new child otherwise we - // would get into an infinite loop. - unset($element['value']['#text_format']); - $element['value']['#weight'] = 0; + if (isset($element['#text_format'])) { + if (filter_access($element['#text_format'])) { // Determine the form element parents and element name to use for the input + // format widget. This simulates the 'element' and 'element_format' pair of + // parents that filter_form() expects. + $element_parents = $element['#parents']; + $element_name = array_pop($element_parents); + $element_parents[] = $element_name . '_format'; + + // We need to break references, otherwise form_builder recurses infinitely. + $element['value'] = (array)$element; + $element['#type'] = 'markup'; + $element['#theme'] = NULL; + $element['#theme_wrapper'] = NULL; + $element['format'] = filter_form($element['#text_format'], 1, $element_parents); + + // We need to clear the #text_format from the new child otherwise we + // would get into an infinite loop. + unset($element['value']['#text_format']); + $element['value']['#weight'] = 0; + } + else { + // Disable field, ensure #value is the #default_value and limit height + $element['#disabled'] = TRUE; + $element['#value'] = $element['#default_value']; + if (isset($element['#rows']) && $element['#rows'] > 5) { + $element['#rows'] = 5; + } + // Disabled attribute is needed because #disabled has already been processed. + $element['#attributes']['disabled'] = 'disabled'; + + // Add read only title and description. + $element['#title'] .= t(' (read only)'); + $element['#description'] .= t(' You are not allowed to change this field.'); + + // Disable unecessary resizable. + $element['#resizable'] = FALSE; + + // Add fixed format. + $element['body_format'] = array( + '#type' => 'value', + '#value' => $element['#text_format'], + ); + } } return $element; } Index: modules/node/node.module =================================================================== RCS file: /cvs/drupal/drupal/modules/node/node.module,v retrieving revision 1.1032 diff -u -p -r1.1032 node.module --- modules/node/node.module 20 Mar 2009 19:18:10 -0000 1.1032 +++ modules/node/node.module 26 Mar 2009 20:09:45 -0000 @@ -291,8 +291,17 @@ function node_mark($nid, $timestamp) { /** * See if the user used JS to submit a teaser. + * + * Disables teaser feature if body field is disabled. */ function node_teaser_js(&$form, &$form_state) { + + // Disable teaser fields when body is disabled + if (!empty($form['body']['#disabled'])) { + unset($form['teaser_js']); + unset($form_state['values']['teaser_js']); + } + if (isset($form_state['input']['teaser_js'])) { // Glue the teaser to the body. if (trim($form_state['values']['teaser_js'])) { @@ -330,6 +339,12 @@ function node_teaser_js(&$form, &$form_s function node_teaser_include_verify(&$form, &$form_state) { $message = ''; + // Disable teaser fields when body is disabled, form state needs to be unset so that it is ignored + if (!empty($form['body']['#disabled'])) { + unset($form['teaser_include']); + unset($form_state['values']['teaser_include']); + } + // $form_state['input'] is set only when the form is built for preview/submit. if (isset($form_state['input']['body']) && isset($form_state['values']['teaser_include']) && !$form_state['values']['teaser_include']) { // "teaser_include" checkbox is present and unchecked. @@ -1947,7 +1962,7 @@ function node_feed($nids = FALSE, $chann $item->body = $content; unset($item->teaser); } - + // Allow modules to modify the fully-built node. node_invoke_node($item, 'alter', $teaser, FALSE); } @@ -2312,11 +2327,6 @@ function node_access($op, $node, $accoun if (empty($account)) { $account = $user; } - // If the node is in a restricted format, disallow editing. - if ($op == 'update' && !filter_access($node->format)) { - return FALSE; - } - if (user_access('bypass node access', $account)) { return TRUE; } Index: modules/node/node.test =================================================================== RCS file: /cvs/drupal/drupal/modules/node/node.test,v retrieving revision 1.17 diff -u -p -r1.17 node.test --- modules/node/node.test 8 Mar 2009 04:25:04 -0000 1.17 +++ modules/node/node.test 26 Mar 2009 20:09:47 -0000 @@ -363,6 +363,110 @@ class PageEditTestCase extends DrupalWeb $this->assertText($edit['title'], t('Title displayed.')); $this->assertText($edit['body'], t('Body displayed.')); } + /** + * Test edit page with special text format. + * + * Test if a normal user is able to edit the page but is not allowed to change + * the fields which use a text format he's not allowed to use. + */ + function testEditLimitedPermission() { + $admin_user = $this->drupalCreateUser(array('administer filters', 'edit any page content', 'create page content')); + $normal_user = $this->drupalCreateUser(array('edit any page content', 'create page content')); + + $this->drupalLogout(); + $this->drupalLogin($admin_user); + // Create node to edit. + + + list($filtered, $full) = $this->checkFilterFormats(); + + $edit = array(); + $edit['title'] = $this->randomName(8); + $edit['body'] = $this->randomName(16); + $edit['body_format'] = $full; + $this->drupalPost('node/add/page', $edit, t('Save')); + + // Check that the node exists in the database. + $node = $this->drupalGetNodeByTitle($edit['title']); + $this->assertTrue($node, t('Node found in database.')); + + // Check that "edit" link points to correct page. + $this->clickLink(t('Edit')); + $edit_url = url("node/$node->nid/edit", array('absolute' => true)); + $actual_url = $this->getURL(); + $this->assertEqual($edit_url, $actual_url, t('On edit page.')); + + // Check that the title and body fields are displayed with the correct values. + $this->assertLink(t('Edit'), 0, t('Edit tab found.')); + $this->assertFieldByName('title', $edit['title'], t('Title field displayed.')); + $this->assertFieldByName('body', '' . $edit['body'], t('Body field displayed.')); + + // Edit the content of the node. + $edit = array(); + $edit['title'] = $this->randomName(8); + $edit['body'] = $this->randomName(16); + // Stay on the current page, without reloading. + $this->drupalPost(NULL, $edit, t('Save')); + + // Check that the title and body fields are displayed with the updated values. + $this->assertText($edit['title'], t('Title displayed.')); + $this->assertText($edit['body'], t('Body displayed.')); + + // Try to edit with normal user + $this->drupalLogout(); + $this->drupalLogin($normal_user); + + $this->drupalGet("node/$node->nid"); + + // Check that "edit" link points to correct page. + $this->clickLink(t('Edit')); + $edit_url = url("node/$node->nid/edit", array('absolute' => true)); + $actual_url = $this->getURL(); + $this->assertEqual($edit_url, $actual_url, t('On edit page.')); + + // Check if body field is read only + $this->assertText(t('(read only)'), t('Body is marked read only')); + $this->assertText(t('You are not allowed to change this field.'), t('Description is available')); + $this->assertFieldByXPath("//textarea[@disabled='disabled' and @id='edit-body']", '' . $edit['body'], t('Body field is disabled')); + + // Check if teaser is disabled + $this->assertNoFieldByXPath("//input[@class='teaser-button']", t('Join summary'), t('Join button is not available')); + $this->assertNoField('teaser_js', t('Teaser field is not available')); + $this->assertNoField('teaser_include', t('Teaser include checkbox is not available')); + + // Try to "force" the change + $new_edit = array(); + $new_edit['title'] = $this->randomName(8); + $new_edit['body'] = $this->randomName(16); + // Stay on the current page, without reloading. + $this->drupalPost(NULL, $new_edit, t('Save')); + + // Check that only the title is displayed with the updated values, the body should use the old values + $this->assertText($new_edit['title'], t('New title displayed.')); + $this->assertText($edit['body'], t('Old body displayed.')); + } + + /** + * Query the database to get the two basic formats. + * + * @return Array Array containing filtered and full filter ids. + */ + function checkFilterFormats() { + $result = db_query('SELECT format, name FROM {filter_format}'); + + $filtered = -1; + $full = -1; + while ($format = db_fetch_object($result)) { + if ($format->name == 'Filtered HTML') { + $filtered = $format->format; + } + elseif ($format->name == 'Full HTML') { + $full = $format->format; + } + } + + return array($filtered, $full); + } } class PagePreviewTestCase extends DrupalWebTestCase {