? 371235-patched-benchmarks.txt ? 371235-unpatched-benchmarks.txt ? sites/all/modules/cvs Index: modules/comment/comment.test =================================================================== RCS file: /cvs/drupal/drupal/modules/comment/comment.test,v retrieving revision 1.25 diff -u -p -r1.25 comment.test --- modules/comment/comment.test 7 Feb 2009 20:10:40 -0000 1.25 +++ modules/comment/comment.test 24 Feb 2009 20:56:12 -0000 @@ -9,12 +9,9 @@ class CommentHelperCase extends DrupalWe function setUp() { parent::setUp('comment'); // Create users. - $this->admin_user = $this->drupalCreateUser(array('administer content types', 'administer comments', 'administer permissions', 'administer blocks')); + $this->admin_user = $this->drupalCreateUser(array('administer content types', 'administer comments', 'administer blocks')); $this->web_user = $this->drupalCreateUser(array('access comments', 'post comments', 'create article content')); - - $this->drupalLogin($this->web_user); - $this->node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1)); - $this->drupalLogout(); + $this->node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1, 'uid' => $this->web_user->uid)); } /** @@ -162,23 +159,6 @@ class CommentHelperCase extends DrupalWe } /** - * Set anonymous comment setting. - * - * @param boolean $enabled - * Allow anonymous commenting. - * @param boolean $without_approval - * Allow anonymous commenting without approval. - */ - function setAnonymousUserComment($enabled, $without_approval) { - $edit = array(); - $edit['1[access comments]'] = $enabled; - $edit['1[post comments]'] = $enabled; - $edit['1[post comments without approval]'] = $without_approval; - $this->drupalPost('admin/user/permissions', $edit, t('Save permissions')); - $this->assertText(t('The changes have been saved.'), t('Anonymous user comments ' . ($enabled ? 'enabled' : 'disabled') . '.')); - } - - /** * Check for contact info. * * @return boolean Contact info is available. @@ -373,7 +353,7 @@ class CommentAnonymous extends CommentHe function testAnonymous() { $this->drupalLogin($this->admin_user); // Enabled anonymous user comments. - $this->setAnonymousUserComment(TRUE, TRUE); + $this->drupalSetPermissions('anonymous user', array('access content', 'access comments', 'post comments', 'post comments without approval')); $this->setCommentAnonymous('0'); // Ensure that doesn't require contact info. $this->drupalLogout(); @@ -433,15 +413,14 @@ class CommentAnonymous extends CommentHe $this->drupalGet('admin/content/comment'); $this->assertNoRaw('comments[' . $anonymous_comment3->id . ']', t('Comment was deleted.')); + $this->drupalLogout(); - // Reset. - $this->drupalLogin($this->admin_user); - $this->setAnonymousUserComment(FALSE, FALSE); + // Reset permissions. + $this->drupalSetPermissions('anonymous user', array('access content')); // Attempt to view comments while disallowed. // NOTE: if authenticated user has permission to post comments, then a // "Login or register to post comments" type link may be shown. - $this->drupalLogout(); $this->drupalGet('node/' . $this->node->nid); $this->assertNoRaw('
', t('Comments were not displayed.')); $this->assertNoLink('Add new comment', t('Link to add comment was found.')); @@ -470,7 +449,7 @@ class CommentApprovalTest extends Commen $this->drupalLogin($this->admin_user); // Set anonymous comments to require approval. - $this->setAnonymousUserComment(TRUE, FALSE); + $this->drupalSetPermissions('anonymous user', array('access content', 'access comments', 'post comments')); $this->setCommentAnonymous('0'); // Ensure that doesn't require contact info. $this->drupalLogout(); @@ -504,7 +483,7 @@ class CommentApprovalTest extends Commen $this->drupalLogin($this->admin_user); // Set anonymous comments to require approval. - $this->setAnonymousUserComment(TRUE, FALSE); + $this->drupalSetPermissions('anonymous user', array('access content', 'access comments', 'post comments')); $this->setCommentAnonymous('0'); // Ensure that doesn't require contact info. $this->drupalLogout(); Index: modules/contact/contact.test =================================================================== RCS file: /cvs/drupal/drupal/modules/contact/contact.test,v retrieving revision 1.14 diff -u -p -r1.14 contact.test --- modules/contact/contact.test 30 Dec 2008 16:43:16 -0000 1.14 +++ modules/contact/contact.test 24 Feb 2009 20:56:12 -0000 @@ -22,7 +22,7 @@ class ContactSitewideTestCase extends Dr */ function testSiteWideContact() { // Create and login administrative user. - $admin_user = $this->drupalCreateUser(array('administer site-wide contact form', 'administer permissions')); + $admin_user = $this->drupalCreateUser(array('administer site-wide contact form')); $this->drupalLogin($admin_user); // Set settings. @@ -38,7 +38,7 @@ class ContactSitewideTestCase extends Dr $this->deleteCategories(); // Ensure that the contact form won't be shown without categories. - $this->setPermission('anonymous user', array('access site-wide contact form' => TRUE)); + $this->drupalSetPermissions('anonymous user', array('access site-wide contact form')); $this->drupalLogout(); $this->drupalGet('contact'); $this->assertText(t('The contact form has not been configured.'), t('Contact form will not work without categories configured.')); @@ -73,7 +73,7 @@ class ContactSitewideTestCase extends Dr $this->assertRaw(t('Category %category has been updated.', array('%category' => $category)), t('Category successfully updated.')); // Ensure that the contact form is shown without a category selection input. - $this->setPermission('anonymous user', array('access site-wide contact form' => TRUE)); + $this->drupalSetPermissions('anonymous user', array('access site-wide contact form')); $this->drupalLogout(); $this->drupalGet('contact'); $this->assertText($contact_form_information, t('Contact form is shown when there is one category.')); @@ -91,17 +91,14 @@ class ContactSitewideTestCase extends Dr $this->assertTrue(db_query('DELETE FROM {flood}'), t('Flood table emptied.')); // Check to see that anonymous user cannot see contact page without permission. - $this->setPermission('anonymous user', array('access site-wide contact form' => FALSE)); + $this->drupalSetPermissions('anonymous user'); $this->drupalLogout(); $this->drupalGet('contact'); $this->assertResponse(403, t('Access denied to anonymous user without permission.')); // Give anonymous user permission and see that page is viewable. - $this->drupalLogin($admin_user); - $this->setPermission('anonymous user', array('access site-wide contact form' => TRUE)); - $this->drupalLogout(); - + $this->drupalSetPermissions('anonymous user', array('access site-wide contact form')); $this->drupalGet('contact'); $this->assertResponse(200, t('Access granted to anonymous user with permission.')); @@ -227,29 +224,6 @@ class ContactSitewideTestCase extends Dr } return $categories; } - - /** - * Set permission. - * - * @param string $role User role to set permissions for. - * @param array $permissions Key-value array of permissions to set. - */ - function setPermission($role, $permissions) { - // Get role id (rid) for specified role. - $rid = db_result(db_query("SELECT rid FROM {role} WHERE name = '%s'", array($role))); - if ($rid === FALSE) { - $this->fail(t(' [permission] Role "' . $role . '" not found.')); - } - - // Create edit array from permission. - $edit = array(); - foreach ($permissions as $name => $value) { - $edit[$rid . '[' . $name . ']'] = $value; - } - - $this->drupalPost('admin/user/permissions', $edit, t('Save permissions')); - $this->assertText(t('The changes have been saved.'), t(' [permission] Saved changes.')); - } } /** Index: modules/simpletest/drupal_web_test_case.php =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/drupal_web_test_case.php,v retrieving revision 1.86 diff -u -p -r1.86 drupal_web_test_case.php --- modules/simpletest/drupal_web_test_case.php 22 Feb 2009 20:12:03 -0000 1.86 +++ modules/simpletest/drupal_web_test_case.php 24 Feb 2009 20:56:14 -0000 @@ -651,9 +651,13 @@ class DrupalWebTestCase { * A fully loaded user object with pass_raw property, or FALSE if account * creation fails. */ - protected function drupalCreateUser($permissions = NULL) { - // Create a role with the given permission set. - if (!($rid = $this->_drupalCreateRole($permissions))) { + protected function drupalCreateUser(array $permissions = array('access comments', 'access content', 'post comments', 'post comments without approval')) { + // Create a new role and assign permissions ot the new role. + $edit = array(); + $edit['name'] = $this->randomName(); + $rid = user_role_save($edit); + $this->assertTrue($rid, t('Created role of name: @role_name, id: @rid', array('@role_name' => $edit['name'], '@rid' => $rid)), t('Role')); + if (!$this->drupalSetPermissions($rid, $permissions)) { return FALSE; } @@ -678,39 +682,51 @@ class DrupalWebTestCase { } /** - * Internal helper function; Create a role with specified permissions. + * Assign permissions to a user role. * + * @param $role + * A string with the role name, or an integer with the role ID. * @param $permissions * Array of permission names to assign to role. + * @param $merge + * A boolean if TRUE, will only add permissions instead of clearing all + * existing permissions and then adding permissions. * @return - * Role ID of newly created role, or FALSE if role creation failed. + * TRUE if the role is a valid role and the permissions have been + * assigned, otherwise FALSE. */ - protected function _drupalCreateRole(array $permissions = NULL) { - // Generate string version of permissions list. - if ($permissions === NULL) { - $permissions = array('access comments', 'access content', 'post comments', 'post comments without approval'); + protected function drupalSetPermissions($role, array $permissions = array(), $merge = FALSE) { + $rid = $role; + if (!is_numeric($role)) { + $rid = user_role_get_id($role); + } + + if (!$rid) { + $this->fail(t('Role %role not found.', array('%role' => $role))); + return FALSE; } + // Check the all the permissions strings are valid. if (!$this->checkPermissions($permissions)) { return FALSE; } - // Create new role. - $role_name = $this->randomName(); - db_query("INSERT INTO {role} (name) VALUES ('%s')", $role_name); - $role = db_fetch_object(db_query("SELECT * FROM {role} WHERE name = '%s'", $role_name)); - $this->assertTrue($role, t('Created role of name: @role_name, id: @rid', array('@role_name' => $role_name, '@rid' => (isset($role->rid) ? $role->rid : t('-n/a-')))), t('Role')); - if ($role && !empty($role->rid)) { - // Assign permissions to role and mark it for clean-up. - foreach ($permissions as $permission_string) { - db_query("INSERT INTO {role_permission} (rid, permission) VALUES (%d, '%s')", $role->rid, $permission_string); - } - $count = db_result(db_query("SELECT COUNT(*) FROM {role_permission} WHERE rid = %d", $role->rid)); - $this->assertTrue($count == count($permissions), t('Created permissions: @perms', array('@perms' => implode(', ', $permissions))), t('Role')); - return $role->rid; + // Check if there are new permissions to add. + $permissions_before = db_query("SELECT permission FROM {role_permission} WHERE rid = :rid", array(':rid' => $rid))->fetchCol(); + $count_before = count($permissions_before); + $permissions_diff = array_diff($permissions, $permissions_before); + + if ($permissions_diff) { + // Assign the user permissions. + user_role_set_permissions($rid, $permissions, $merge); + $count_after = db_query("SELECT COUNT(*) FROM {role_permission} WHERE rid = :rid", array(':rid' => $rid))->fetchField(); + $result = $count_before + count($permissions_diff) == $count_after; + $this->assertTrue($result, t('Assigned permissions to role %role: @perms', array('%role' => $role, '@perms' => implode(', ', $permissions_diff))), t('Role')); + return $result; } else { - return FALSE; + $this->pass(t('No new permissions to assign to role %role.', array('%role' => $role)), t('Role')); + return TRUE; } } @@ -2054,4 +2070,3 @@ class DrupalWebTestCase { return $instance; } } - Index: modules/simpletest/simpletest.test =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/simpletest.test,v retrieving revision 1.16 diff -u -p -r1.16 simpletest.test --- modules/simpletest/simpletest.test 22 Jan 2009 12:46:06 -0000 1.16 +++ modules/simpletest/simpletest.test 24 Feb 2009 20:56:14 -0000 @@ -13,6 +13,8 @@ class SimpleTestFunctionalTest extends D */ protected $test_ids = array(); + private $test_user; + function getInfo() { return array( 'name' => t('SimpleTest functionality'), @@ -108,7 +110,8 @@ class SimpleTestFunctionalTest extends D $this->pass($this->pass); $this->fail($this->fail); - $this->drupalCreateUser(array($this->valid_permission)); + $account = $this->drupalCreateUser(array($this->valid_permission)); + $this->drupalSetPermissions(end($account->roles), array($this->valid_permission)); $this->drupalCreateUser(array($this->invalid_permission)); $this->pass(t('Test ID is @id.', array('@id' => $this->testId))); @@ -137,7 +140,9 @@ class SimpleTestFunctionalTest extends D $this->assertAssertion($this->pass, 'Other', 'Pass', 'simpletest.test', 'SimpleTestFunctionalTest->stubTest()'); $this->assertAssertion($this->fail, 'Other', 'Fail', 'simpletest.test', 'SimpleTestFunctionalTest->stubTest()'); - $this->assertAssertion(t('Created permissions: @perms', array('@perms' => $this->valid_permission)), 'Role', 'Pass', 'simpletest.test', 'SimpleTestFunctionalTest->stubTest()'); + $this->assertAssertion(t('Assigned permissions to role'), 'Role', 'Pass', 'simpletest.test', 'SimpleTestFunctionalTest->stubTest()'); + $this->assertAssertion(t('@perms', array('@perms' => $this->valid_permission)), 'Role', 'Pass', 'simpletest.test', 'SimpleTestFunctionalTest->stubTest()'); + $this->assertAssertion(t('No new permissions to assign to role'), 'Role', 'Pass', 'simpletest.test', 'SimpleTestFunctionalTest->stubTest()'); $this->assertAssertion(t('Invalid permission %permission.', array('%permission' => $this->invalid_permission)), 'Role', 'Fail', 'simpletest.test', 'SimpleTestFunctionalTest->stubTest()'); // Check that a warning is catched by simpletest. Index: modules/system/system.install =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.install,v retrieving revision 1.308 diff -u -p -r1.308 system.install --- modules/system/system.install 18 Feb 2009 15:19:56 -0000 1.308 +++ modules/system/system.install 24 Feb 2009 20:56:17 -0000 @@ -354,19 +354,10 @@ function system_install() { // This sets uid 1 (superuser). We skip uid 2 but that's not a big problem. db_query("UPDATE {user} SET uid = 1 WHERE name = '%s'", 'placeholder-for-uid-1'); - // Built-in roles. + // Add built-in roles. db_query("INSERT INTO {role} (name) VALUES ('%s')", 'anonymous user'); db_query("INSERT INTO {role} (name) VALUES ('%s')", 'authenticated user'); - // Anonymous role permissions. - db_query("INSERT INTO {role_permission} (rid, permission) VALUES (%d, '%s')", 1, 'access content'); - - // Authenticated role permissions. - db_query("INSERT INTO {role_permission} (rid, permission) VALUES (%d, '%s')", 2, 'access comments'); - db_query("INSERT INTO {role_permission} (rid, permission) VALUES (%d, '%s')", 2, 'access content'); - db_query("INSERT INTO {role_permission} (rid, permission) VALUES (%d, '%s')", 2, 'post comments'); - db_query("INSERT INTO {role_permission} (rid, permission) VALUES (%d, '%s')", 2, 'post comments without approval'); - db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')", 'theme_default', 's:7:"garland";'); db_query("UPDATE {system} SET status = %d WHERE type = '%s' AND name = '%s'", 1, 'theme', 'garland'); Index: modules/user/user.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/user/user.admin.inc,v retrieving revision 1.39 diff -u -p -r1.39 user.admin.inc --- modules/user/user.admin.inc 18 Feb 2009 15:19:57 -0000 1.39 +++ modules/user/user.admin.inc 24 Feb 2009 20:56:18 -0000 @@ -544,17 +544,17 @@ function user_admin_settings() { function user_admin_perm($form_state, $rid = NULL) { // Retrieve role names for columns. - $role_names = user_roles(); + $roles = user_roles(); if (is_numeric($rid)) { - $role_names = array($rid => $role_names[$rid]); + $roles = array($rid => $roles[$rid]); } // Fetch permissions for all roles or the one selected role. - $role_permissions = user_role_permissions($role_names); + $role_permissions = user_role_get_permissions(array_keys($roles)); // Store $role_names for use when saving the data. - $form['role_names'] = array( + $form['roles'] = array( '#type' => 'value', - '#value' => $role_names, + '#value' => $roles, ); // Render role/permission overview: $options = array(); @@ -572,7 +572,7 @@ function user_admin_perm($form_state, $r '#markup' => $perm_item['title'], '#description' => $hide_descriptions ? $perm_item['description'] : NULL, ); - foreach ($role_names as $rid => $name) { + foreach ($roles as $rid => $name) { // Builds arrays for checked boxes for each role if (isset($role_permissions[$rid][$perm])) { $status[$rid][] = $perm; @@ -583,7 +583,7 @@ function user_admin_perm($form_state, $r } // Have to build checkboxes here after checkbox arrays are built - foreach ($role_names as $rid => $name) { + foreach ($roles as $rid => $name) { $form['checkboxes'][$rid] = array('#type' => 'checkboxes', '#options' => $options, '#default_value' => isset($status[$rid]) ? $status[$rid] : array()); $form['role_names'][$rid] = array('#markup' => $name, '#tree' => TRUE); } @@ -598,13 +598,9 @@ function user_admin_perm($form_state, $r * @see user_admin_perm */ function user_admin_perm_submit($form, &$form_state) { - foreach ($form_state['values']['role_names'] as $rid => $name) { - $checked = array_filter($form_state['values'][$rid]); - // Delete existing permissions for the role. This handles "unchecking" checkboxes. - db_query("DELETE FROM {role_permission} WHERE rid = %d", $rid); - foreach ($checked as $permission) { - db_query("INSERT INTO {role_permission} (rid, permission) VALUES (%d, '%s')", $rid, $permission); - } + foreach (array_keys($form_state['values']['roles']) as $rid) { + $permissions = array_filter($form_state['values'][$rid]); + user_role_set_permissions($rid, $permissions); } drupal_set_message(t('The changes have been saved.')); @@ -710,14 +706,15 @@ function user_admin_role() { } function user_admin_role_validate($form, &$form_state) { + $form_state['values']['name'] = trim($form_state['values']['name']); if ($form_state['values']['name']) { if ($form_state['values']['op'] == t('Save role')) { - if (db_result(db_query("SELECT COUNT(*) FROM {role} WHERE name = '%s' AND rid != %d", $form_state['values']['name'], $form_state['values']['rid']))) { + if (($rid = user_role_get_id($form_state['values']['name'])) && $rid != $form_state['values']['rid']) { form_set_error('name', t('The role name %name already exists. Please choose another role name.', array('%name' => $form_state['values']['name']))); } } elseif ($form_state['values']['op'] == t('Add role')) { - if (db_result(db_query("SELECT COUNT(*) FROM {role} WHERE name = '%s'", $form_state['values']['name']))) { + if (user_role_get_id($form_state['values']['name'])) { form_set_error('name', t('The role name %name already exists. Please choose another role name.', array('%name' => $form_state['values']['name']))); } } @@ -729,19 +726,15 @@ function user_admin_role_validate($form, function user_admin_role_submit($form, &$form_state) { if ($form_state['values']['op'] == t('Save role')) { - db_query("UPDATE {role} SET name = '%s' WHERE rid = %d", $form_state['values']['name'], $form_state['values']['rid']); + user_role_save($form_state['values']); drupal_set_message(t('The role has been renamed.')); } elseif ($form_state['values']['op'] == t('Delete role')) { - db_query('DELETE FROM {role} WHERE rid = %d', $form_state['values']['rid']); - db_query('DELETE FROM {role_permission} WHERE rid = %d', $form_state['values']['rid']); - // Update the users who have this role set: - db_query('DELETE FROM {user_role} WHERE rid = %d', $form_state['values']['rid']); - + user_role_delete($form_state['values']['rid']); drupal_set_message(t('The role has been deleted.')); } elseif ($form_state['values']['op'] == t('Add role')) { - db_query("INSERT INTO {role} (name) VALUES ('%s')", $form_state['values']['name']); + user_role_save($form_state['values']); drupal_set_message(t('The role has been added.')); } $form_state['redirect'] = 'admin/user/roles'; Index: modules/user/user.module =================================================================== RCS file: /cvs/drupal/drupal/modules/user/user.module,v retrieving revision 1.965 diff -u -p -r1.965 user.module --- modules/user/user.module 19 Feb 2009 12:09:30 -0000 1.965 +++ modules/user/user.module 24 Feb 2009 20:56:20 -0000 @@ -535,59 +535,6 @@ function user_password($length = 10) { } /** - * Determine the permissions for one or more roles. - * - * @param $roles - * An array whose keys are the role IDs of interest, such as $user->roles. - * @param $reset - * Optional parameter - if TRUE data in the static variable is rebuilt. - * - * @return - * An array indexed by role ID. Each value is an array whose keys are the - * permission strings for the given role ID. - */ -function user_role_permissions($roles = array(), $reset = FALSE) { - static $stored_permissions = array(); - - if ($reset) { - // Clear the data cached in the static variable. - $stored_permissions = array(); - } - - $role_permissions = $fetch = array(); - - if ($roles) { - foreach ($roles as $rid => $name) { - if (isset($stored_permissions[$rid])) { - $role_permissions[$rid] = $stored_permissions[$rid]; - } - else { - // Add this rid to the list of those needing to be fetched. - $fetch[] = $rid; - // Prepare in case no permissions are returned. - $stored_permissions[$rid] = array(); - } - } - - if ($fetch) { - // Get from the database permissions that were not in the static variable. - // Only role IDs with at least one permission assigned will return rows. - $result = db_query("SELECT rid, permission FROM {role_permission} WHERE rid IN (:fetch)", array(':fetch' => $fetch)); - - foreach ($result as $row) { - $stored_permissions[$row->rid][$row->permission] = TRUE; - } - foreach ($fetch as $rid) { - // For every rid, we know we at least assigned an empty array. - $role_permissions[$rid] = $stored_permissions[$rid]; - } - } - } - - return $role_permissions; -} - -/** * Determine whether the user has a given privilege. * * @param $string @@ -626,7 +573,7 @@ function user_access($string, $account = // To reduce the number of SQL queries, we cache the user's permissions // in a static variable. if (!isset($perm[$account->uid])) { - $role_permissions = user_role_permissions($account->roles, $reset); + $role_permissions = user_role_get_permissions(array_keys($account->roles), $reset); $perms = array(); foreach ($role_permissions as $one_role) { @@ -2784,3 +2731,167 @@ function _user_forms(&$edit, $account, $ return empty($groups) ? FALSE : $groups; } +/** + * Get the role ID of a role name. + * + * @param $role_name + * The name of the role. + * @return + * An integer of the role's ID, or FALSE if the role was not found. + */ +function user_role_get_id($role_name) { + return db_query("SELECT rid FROM {role} WHERE name = :name", array(':name' => $role_name))->fetchField(); +} + +/** + * Save changes to a user role or add a new role. + * + * @param $role + * The role object to modify or add. If $role->rid is unspecified, a new + * role will be created. + * @param $permissions + * An optional array of permissions to assign to the role. + * @return + * The role ID of the role. + */ +function user_role_save($role, array $permissions = NULL) { + $role = (object) $role; + + // Save the role to the database. + drupal_write_record('role', $role, !empty($role->rid) ? 'rid' : array()); + + if (isset($permissions)) { + // Assign the permissions to the role. + user_role_set_permissions($role->rid, $permissions); + } + + return $role->rid; +} + +/** + * Delete a user role. + * + * @param $role + * A string with the role name, or an integer with the role ID. + * @return + * TRUE on success, FALSE otherwise. + */ +function user_role_delete($role) { + $rid = $role; + if (!is_numeric($role)) { + // Fetch the role ID if $role is a role name. + $rid = user_role_get_id($role); + } + + if (!$rid) { + return FALSE; + } + + db_delete('role')->condition('rid', $rid)->execute(); + db_delete('role_permission')->condition('rid', $rid)->execute(); + db_delete('user_role')->condition('rid', $rid)->execute(); + + // Clear the user access cache. + user_access(NULL, NULL, TRUE); + + return TRUE; +} + +/** + * Determine the permissions for one or more roles. + * + * @param $roles + * An array of role IDs. + * @param $reset + * Optional parameter - if TRUE data in the static variable is rebuilt. + * @return + * An array indexed by role ID. Each value is an array whose keys are the + * permission strings for the given role ID. + */ +function user_role_get_permissions(array $roles = array(), $reset = FALSE) { + static $stored_permissions = array(); + + if ($reset) { + // Clear the data cached in the static variable. + $stored_permissions = array(); + } + + $role_permissions = $fetch = array(); + + if ($roles) { + foreach ($roles as $rid) { + if (isset($stored_permissions[$rid])) { + $role_permissions[$rid] = $stored_permissions[$rid]; + } + else { + // Add this rid to the list of those needing to be fetched. + $fetch[] = $rid; + // Prepare in case no permissions are returned. + $stored_permissions[$rid] = array(); + } + } + + if ($fetch) { + // Get from the database permissions that were not in the static variable. + // Only role IDs with at least one permission assigned will return rows. + $result = db_query("SELECT rid, permission FROM {role_permission} WHERE rid IN (:fetch)", array(':fetch' => $fetch)); + + foreach ($result as $row) { + $stored_permissions[$row->rid][$row->permission] = TRUE; + } + foreach ($fetch as $rid) { + // For every rid, we know we at least assigned an empty array. + $role_permissions[$rid] = $stored_permissions[$rid]; + } + } + } + + return $role_permissions; +} + +/** + * Assign an array of permissions to a role. + * + * @param $role + * A string with the role name, or an integer with the role ID. + * @param $permissions + * An array of permissions strings. + * @param $merge + * A boolean if TRUE, will only add permissions instead of clearing all + * existing permissions and then adding permissions. + * @return + * TRUE on success, FALSE otherwise. + */ +function user_role_set_permissions($role, array $permissions = array(), $merge = FALSE) { + $rid = $role; + if (!is_numeric($role)) { + // Fetch the role ID if $role is a role name. + $rid = user_role_get_id($role); + } + + if (!$rid) { + return FALSE; + } + + if (!$merge) { + // Delete existing permissions for the role. + db_delete('role_permission') + ->condition('rid', $rid) + ->execute(); + } + + // Assign the new permissions for the role. + foreach ($permissions as $permission_string) { + db_merge('role_permission') + ->key(array( + 'rid' => $rid, + 'permission' => $permission_string, + )) + ->execute(); + } + + // Clear the user access cache. + user_access(NULL, NULL, TRUE); + + return TRUE; +} Index: modules/user/user.test =================================================================== RCS file: /cvs/drupal/drupal/modules/user/user.test,v retrieving revision 1.29 diff -u -p -r1.29 user.test --- modules/user/user.test 22 Feb 2009 17:55:30 -0000 1.29 +++ modules/user/user.test 24 Feb 2009 20:56:21 -0000 @@ -699,55 +699,98 @@ class UserPictureTestCase extends Drupal } } - -class UserPermissionsTestCase extends DrupalWebTestCase { - protected $admin_user; - protected $rid; - +/** + * Test the user role and permission functionality. + */ +class UserRolesPermissionsFunctionalTest extends DrupalWebTestCase { function getInfo() { return array( - 'name' => t('Role permissions'), - 'description' => t('Verify that role permissions can be added and removed via the permissions page.'), - 'group' => t('User') + 'name' => t('User roles and permissions'), + 'description' => t('Test the user roles and permissions functionality.'), + 'group' => t('User'), ); } - function setUp() { - parent::setUp(); - - $this->admin_user = $this->drupalCreateUser(array('administer permissions', 'access user profiles')); - - // Find the new role ID - it must be the maximum. - $all_rids = array_keys($this->admin_user->roles); - sort($all_rids); - $this->rid = array_pop($all_rids); - } - /** - * Change user permissions and check user_access(). + * Test user role and permission interfaces. */ - function testUserPermissionChanges() { - $this->drupalLogin($this->admin_user); - $rid = $this->rid; - $account = $this->admin_user; + function testRolesAndPermissions() { + $test_user = $this->drupalCreateUser(); + $admin_user = $this->drupalCreateUser(array('administer permissions', 'administer users')); + $this->drupalLogin($admin_user); + $perm = 'access user profiles'; + + // Add a new user role and fetch it's role ID. + $role = $this->randomName(4, 'role_'); + $this->drupalPost('admin/user/roles', array('name' => $role), t('Add role')); + $this->assertText(t('The role has been added.')); + $role_id = user_role_get_id($role); + + // Try to add another role with duplicate names. + $this->drupalPost('admin/user/roles', array('name' => 'anonymous user'), t('Add role')); + $this->assertRaw(t('The role name %role already exists. Please choose another role name.', array('%role' => 'anonymous user')), t('Could not add a duplicate role name.')); + $this->drupalPost('admin/user/roles/edit/'. $role_id, array('name' => 'anonymous user'), t('Save role')); + $this->assertRaw(t('The role name %role already exists. Please choose another role name.', array('%role' => 'anonymous user')), t('Could not add a duplicate role name.')); + + // Try to add an invalid role name. + $this->drupalPost('admin/user/roles', array('name' => ' '), t('Add role')); + $this->assertText(t('You must specify a valid role name.')); + + // Try to edit the locked anonymous and authenticated user roles. + foreach (array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID) as $invalid_rid) { + $this->drupalGet('admin/user/roles/edit/' . $invalid_rid); + $this->assertEqual(url('admin/user/roles', array('absolute' => TRUE)), $this->getUrl(), t('Cannot edit locked user role.')); + } + + // Rename the new role. + $this->clickLink(t('edit role'), 0); + $role = $this->randomName(4, 'role_'); + $this->drupalPost(NULL, array('name' => $role), t('Save role')); + $this->assertText(t('The role has been renamed.')); + $this->assertEqual($role_id, user_role_get_id($role), t('Role ID unchanged.')); - // Add a permission. - $this->assertFalse(user_access('administer nodes', $account, TRUE), t('User does not have "administer nodes" permission.')); + // Add a permission to the new role. + $this->clickLink(t('edit permissions'), 2); $edit = array(); - $edit[$rid . '[administer nodes]'] = TRUE; + $edit[$role_id . '[' . $perm . ']'] = TRUE; $this->drupalPost('admin/user/permissions', $edit, t('Save permissions')); - $this->assertText(t('The changes have been saved.'), t('Successful save message displayed.')); - $this->assertTrue(user_access('administer nodes', $account, TRUE), t('User now has "administer nodes" permission.')); + $this->assertText(t('The changes have been saved.')); - // Remove a permission. - $this->assertTrue(user_access('access user profiles', $account, TRUE), t('User has "access user profiles" permission.')); + // Assign a user to the new role. + $this->drupalGet('user/' . $test_user->uid . '/edit'); + $this->assertFieldByXPath('//input[@type="checkbox" and @name="roles[' . DRUPAL_AUTHENTICATED_RID . ']" and @disabled="disabled" and @checked="checked"]', TRUE, t('The authenticated user role checkbox is checked but disabled.')); $edit = array(); - $edit[$rid . '[access user profiles]'] = FALSE; + // For some reason, the FormAPI will show an 'invalid choice selected' + // without the following line, so it is needed to complete the POST. + $edit['roles[' . DRUPAL_AUTHENTICATED_RID . ']'] = FALSE; + $edit['roles[' . $role_id . ']'] = TRUE; + $this->drupalPost(NULL, $edit, t('Save')); + $this->assertText(t('The changes have been saved.')); + + // Test that the user has the assigned role permissions. + $test_user = user_load($test_user->uid); + $this->assertTrue(user_access($perm, $test_user, TRUE), t('User has "access user profiles" permission.')); + + // Delete the role and reload the user since it's roles have changed. + $this->drupalPost('admin/user/roles/edit/' . $role_id, array(), t('Delete role')); + $this->assertText(t('The role has been deleted.')); + $test_user = user_load($test_user->uid); + + // Test that the user no longer has the assigned role permission. + $this->assertFalse(user_access($perm, $test_user, TRUE), t('User does not have "access user profiles" permission.')); + $this->assertFalse(user_access($perm, drupal_anonymous_user()), t('Anonymous user does not have "access user profiles" permission.')); + + // Assign a permission to the anonymous and authenticated user role. + $edit = array(); + $edit[DRUPAL_ANONYMOUS_RID . '[' . $perm . ']'] = TRUE; + $edit[DRUPAL_AUTHENTICATED_RID . '[' . $perm . ']'] = TRUE; $this->drupalPost('admin/user/permissions', $edit, t('Save permissions')); - $this->assertText(t('The changes have been saved.'), t('Successful save message displayed.')); - $this->assertFalse(user_access('access user profiles', $account, TRUE), t('User no longer has "access user profiles" permission.')); - } + $this->assertText(t('The changes have been saved.')); + // Test that both anonymous and authenticated users have the permission. + $this->assertTrue(user_access($perm, $test_user, TRUE), t('User has "access user profiles" permission.')); + $this->assertTrue(user_access($perm, drupal_anonymous_user()), t('Anonymous user has "access user profiles" permission.')); + } } class UserAdminTestCase extends DrupalWebTestCase { Index: profiles/default/default.profile =================================================================== RCS file: /cvs/drupal/drupal/profiles/default/default.profile,v retrieving revision 1.37 diff -u -p -r1.37 default.profile --- profiles/default/default.profile 3 Feb 2009 12:30:14 -0000 1.37 +++ profiles/default/default.profile 24 Feb 2009 20:56:21 -0000 @@ -90,7 +90,11 @@ function default_profile_task_list() { * modify the $task, otherwise discarded. */ function default_profile_tasks(&$task, $url) { - + + // Enable default permissions. + user_role_set_permissions(DRUPAL_ANONYMOUS_RID, array('access content')); + user_role_set_permissions(DRUPAL_AUTHENTICATED_RID, array('access content', 'access comments', 'post comments', 'post comments without approval')); + // Enable 3 standard blocks. db_query("INSERT INTO {block} (module, delta, theme, status, weight, region, pages, cache) VALUES ('%s', '%s', '%s', %d, %d, '%s', '%s', %d)", 'user', 'login', 'garland', 1, 0, 'left', '', -1); db_query("INSERT INTO {block} (module, delta, theme, status, weight, region, pages, cache) VALUES ('%s', '%s', '%s', %d, %d, '%s', '%s', %d)", 'user', 'navigation', 'garland', 1, 0, 'left', '', -1);