summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDries Buytaert <dries@buytaert.net>2008-05-07 19:34:24 +0000
committerDries Buytaert <dries@buytaert.net>2008-05-07 19:34:24 +0000
commitb9f1018ea4fe429656de0fad91fcde51d9507e50 (patch)
tree20648c37c14f84c119f13c49ce75c97f02c07336
parent48e293a6b3d647d79b7b3ce58ab467f9c3fd6de7 (diff)
downloadbrdo-b9f1018ea4fe429656de0fad91fcde51d9507e50.tar.gz
brdo-b9f1018ea4fe429656de0fad91fcde51d9507e50.tar.bz2
- Patch #73874 by pwolanin: normalize the permissions table and wrote simpletests for the (new) permission handling. At last.
-rw-r--r--modules/simpletest/drupal_web_test_case.php11
-rw-r--r--modules/system/system.install56
-rw-r--r--modules/user/user.admin.inc49
-rw-r--r--modules/user/user.install34
-rw-r--r--modules/user/user.module65
-rw-r--r--modules/user/user.test54
6 files changed, 205 insertions, 64 deletions
diff --git a/modules/simpletest/drupal_web_test_case.php b/modules/simpletest/drupal_web_test_case.php
index 16ded5e77..782666375 100644
--- a/modules/simpletest/drupal_web_test_case.php
+++ b/modules/simpletest/drupal_web_test_case.php
@@ -273,9 +273,7 @@ class DrupalWebTestCase extends UnitTestCase {
private function _drupalCreateRole($permissions = NULL) {
// Generate string version of permissions list.
if ($permissions === NULL) {
- $permission_string = 'access comments, access content, post comments, post comments without approval';
- } else {
- $permission_string = implode(', ', $permissions);
+ $permissions = array('access comments', 'access content', 'post comments', 'post comments without approval');
}
// Create new role.
@@ -285,8 +283,11 @@ class DrupalWebTestCase extends UnitTestCase {
$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.
- db_query("INSERT INTO {permission} (rid, perm) VALUES (%d, '%s')", $role->rid, $permission_string);
- $this->assertTrue(db_affected_rows(), t('Created permissions: @perms', array('@perms' => $permission_string)), t('Role'));
+ 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;
}
else {
diff --git a/modules/system/system.install b/modules/system/system.install
index 9207e6e2d..89c2afde2 100644
--- a/modules/system/system.install
+++ b/modules/system/system.install
@@ -366,11 +366,18 @@ function system_install() {
// This sets uid 1 (superuser). We skip uid 2 but that's not a big problem.
db_query("UPDATE {users} SET uid = 1 WHERE name = '%s'", 'placeholder-for-uid-1');
+ // Built-in roles.
db_query("INSERT INTO {role} (name) VALUES ('%s')", 'anonymous user');
db_query("INSERT INTO {role} (name) VALUES ('%s')", 'authenticated user');
- db_query("INSERT INTO {permission} (rid, perm, tid) VALUES (%d, '%s', %d)", 1, 'access content', 0);
- db_query("INSERT INTO {permission} (rid, perm, tid) VALUES (%d, '%s', %d)", 2, 'access comments, access content, post comments, post comments without approval', 0);
+ // 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');
@@ -2945,6 +2952,51 @@ function system_update_7006() {
}
/**
+ * Convert to new method of storing permissions.
+ *
+ * This update is in system.install rather than user.install so that
+ * all modules can use the updated permission scheme during their updates.
+ */
+function system_update_7007() {
+ $ret = array();
+
+ $schema['role_permission'] = array(
+ 'fields' => array(
+ 'rid' => array(
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ ),
+ 'permission' => array(
+ 'type' => 'varchar',
+ 'length' => 64,
+ 'not null' => TRUE,
+ 'default' => '',
+ ),
+ ),
+ 'primary key' => array('rid', 'permission'),
+ 'indexes' => array(
+ 'permission' => array('permission'),
+ ),
+ );
+
+ db_create_table($ret, 'role_permission', $schema['role_permission']);
+
+ // Copy the permissions from the old {permission} table to the new {role_permission} table.
+ $result = db_query("SELECT rid, perm FROM {permission} ORDER BY rid ASC");
+ while ($role = db_fetch_object($result)) {
+ foreach (explode(', ', $role->perm) as $perm) {
+ db_query("INSERT INTO {role_permission} (rid, permission) VALUES (%d, '%s')", $role->rid, $perm);
+ }
+ $ret[] = array('success' => TRUE, 'query' => "Inserted into {role_permission} the permissions for role ID " . $role->rid);
+ }
+ db_drop_table($ret, 'permission');
+
+ return $ret;
+}
+
+
+/**
* @} End of "defgroup updates-6.x-to-7.x"
* The next series of updates should start at 8000.
*/
diff --git a/modules/user/user.admin.inc b/modules/user/user.admin.inc
index 3884698f7..36bca54e0 100644
--- a/modules/user/user.admin.inc
+++ b/modules/user/user.admin.inc
@@ -493,27 +493,20 @@ function user_admin_settings() {
* @see theme_user_admin_perm()
*/
function user_admin_perm($form_state, $rid = NULL) {
- if (is_numeric($rid)) {
- $result = db_query('SELECT r.rid, p.perm FROM {role} r LEFT JOIN {permission} p ON r.rid = p.rid WHERE r.rid = %d', $rid);
- }
- else {
- $result = db_query('SELECT r.rid, p.perm FROM {role} r LEFT JOIN {permission} p ON r.rid = p.rid ORDER BY name');
- }
-
- // Compile role array:
- // Add a comma at the end so when searching for a permission, we can
- // always search for "$perm," to make sure we do not confuse
- // permissions that are substrings of each other.
- while ($role = db_fetch_object($result)) {
- $role_permissions[$role->rid] = $role->perm . ',';
- }
// Retrieve role names for columns.
$role_names = user_roles();
if (is_numeric($rid)) {
$role_names = array($rid => $role_names[$rid]);
}
+ // Fetch permissions for all roles or the one selected role.
+ $role_permissions = user_role_permissions($role_names);
+ // Store $role_names for use when saving the data.
+ $form['role_names'] = array(
+ '#type' => 'value',
+ '#value' => $role_names,
+ );
// Render role/permission overview:
$options = array();
$hide_descriptions = !system_admin_compact_mode();
@@ -537,7 +530,7 @@ function user_admin_perm($form_state, $rid = NULL) {
);
foreach ($role_names as $rid => $name) {
// Builds arrays for checked boxes for each role
- if (strpos($role_permissions[$rid], $perm . ',') !== FALSE) {
+ if (isset($role_permissions[$rid][$perm])) {
$status[$rid][] = $perm;
}
}
@@ -555,24 +548,24 @@ function user_admin_perm($form_state, $rid = NULL) {
return $form;
}
+/**
+ * Save permissions selected on the administer permissions page.
+ *
+ * @see user_admin_perm
+ */
function user_admin_perm_submit($form, &$form_state) {
- // Save permissions:
- $result = db_query('SELECT * FROM {role}');
- while ($role = db_fetch_object($result)) {
- if (isset($form_state['values'][$role->rid])) {
- // Delete, so if we clear every checkbox we reset that role;
- // otherwise permissions are active and denied everywhere.
- db_query('DELETE FROM {permission} WHERE rid = %d', $role->rid);
- $form_state['values'][$role->rid] = array_filter($form_state['values'][$role->rid]);
- if (count($form_state['values'][$role->rid])) {
- db_query("INSERT INTO {permission} (rid, perm) VALUES (%d, '%s')", $role->rid, implode(', ', array_keys($form_state['values'][$role->rid])));
- }
+ 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);
}
}
drupal_set_message(t('The changes have been saved.'));
- // Clear the cached pages
+ // Clear the cached pages and blocks.
cache_clear_all();
}
@@ -697,7 +690,7 @@ function user_admin_role_submit($form, &$form_state) {
}
else if ($form_state['values']['op'] == t('Delete role')) {
db_query('DELETE FROM {role} WHERE rid = %d', $form_state['values']['rid']);
- db_query('DELETE FROM {permission} 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 {users_roles} WHERE rid = %d', $form_state['values']['rid']);
diff --git a/modules/user/user.install b/modules/user/user.install
index 80d03de52..df4b2670d 100644
--- a/modules/user/user.install
+++ b/modules/user/user.install
@@ -41,38 +41,26 @@ function user_schema() {
'primary key' => array('aid'),
);
- $schema['permission'] = array(
- 'description' => t('Stores permissions for users.'),
+ $schema['role_permission'] = array(
+ 'description' => t('Stores the permissions assigned to user roles.'),
'fields' => array(
- 'pid' => array(
- 'type' => 'serial',
- 'not null' => TRUE,
- 'description' => t('Primary Key: Unique permission ID.'),
- ),
'rid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
- 'default' => 0,
- 'description' => t('The {role}.rid to which the permissions are assigned.'),
- ),
- 'perm' => array(
- 'type' => 'text',
- 'not null' => FALSE,
- 'size' => 'big',
- 'description' => t('List of permissions being assigned.'),
+ 'description' => t('Foreign Key: {role}.rid.'),
),
- 'tid' => array(
- 'type' => 'int',
- 'unsigned' => TRUE,
+ 'permission' => array(
+ 'type' => 'varchar',
+ 'length' => 64,
'not null' => TRUE,
- 'default' => 0,
- 'description' => t('Originally intended for taxonomy-based permissions, but never used.'),
+ 'default' => '',
+ 'description' => t('A single permission granted to the role identified by rid.'),
),
),
- 'primary key' => array('pid'),
+ 'primary key' => array('rid', 'permission'),
'indexes' => array(
- 'rid' => array('rid'),
+ 'permission' => array('permission'),
),
);
@@ -83,7 +71,7 @@ function user_schema() {
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
- 'description' => t('Primary Key: Unique role id.'),
+ 'description' => t('Primary Key: Unique role ID.'),
),
'name' => array(
'type' => 'varchar',
diff --git a/modules/user/user.module b/modules/user/user.module
index 3fa75e296..b7ea58c8d 100644
--- a/modules/user/user.module
+++ b/modules/user/user.module
@@ -434,6 +434,59 @@ 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 r.rid, p.permission FROM {role} r INNER JOIN {role_permission} p ON p.rid = r.rid WHERE r.rid IN (" . db_placeholders($fetch) . ")", $fetch);
+
+ while ($row = db_fetch_array($result)) {
+ $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
@@ -472,11 +525,11 @@ function user_access($string, $account = NULL, $reset = FALSE) {
// To reduce the number of SQL queries, we cache the user's permissions
// in a static variable.
if (!isset($perm[$account->uid])) {
- $result = db_query("SELECT p.perm FROM {role} r INNER JOIN {permission} p ON p.rid = r.rid WHERE r.rid IN (" . db_placeholders($account->roles) . ")", array_keys($account->roles));
+ $role_permissions = user_role_permissions($account->roles, $reset);
$perms = array();
- while ($row = db_fetch_object($result)) {
- $perms += array_flip(explode(', ', $row->perm));
+ foreach ($role_permissions as $one_role) {
+ $perms += $one_role;
}
$perm[$account->uid] = $perms;
}
@@ -1590,7 +1643,7 @@ function user_roles($membersonly = FALSE, $permission = NULL) {
);
if (!empty($permission)) {
- $result = db_query("SELECT r.* FROM {role} r INNER JOIN {permission} p ON r.rid = p.rid WHERE p.perm LIKE '%%%s%%' ORDER BY r.name", $permission);
+ $result = db_query("SELECT r.* FROM {role} r INNER JOIN {role_permission} p ON r.rid = p.rid WHERE p.permission = '%s' ORDER BY r.name", $permission);
}
else {
$result = db_query('SELECT * FROM {role} ORDER BY name');
@@ -1854,8 +1907,8 @@ function user_filters() {
ksort($options);
$filters['permission'] = array(
'title' => t('permission'),
- 'join' => 'LEFT JOIN {permission} p ON ur.rid = p.rid',
- 'where' => " ((p.perm IS NOT NULL AND p.perm LIKE '%%%s%%') OR u.uid = 1) ",
+ 'join' => 'LEFT JOIN {role_permission} p ON ur.rid = p.rid',
+ 'where' => " (p.permission = '%s' OR u.uid = 1) ",
'options' => $options,
);
diff --git a/modules/user/user.test b/modules/user/user.test
index 6c1570d2b..0e38def11 100644
--- a/modules/user/user.test
+++ b/modules/user/user.test
@@ -207,3 +207,57 @@ class UserDeleteTestCase extends DrupalWebTestCase {
$this->assertFalse(user_load($edit), t('User is not found in the database'));
}
}
+
+
+class UserPermissionsTestCase extends DrupalWebTestCase {
+ protected $admin_user;
+ protected $rid;
+
+ /**
+ * Implementation of getInfo().
+ */
+ 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')
+ );
+ }
+
+ 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().
+ */
+ function testUserPermissionChanges() {
+ $this->drupalLogin($this->admin_user);
+ $rid = $this->rid;
+ $account = $this->admin_user;
+
+ // Add a permission.
+ $this->assertFalse(user_access('administer nodes', $account, TRUE), t('User does not have "administer nodes" permission.'));
+ $edit = array();
+ $edit[$rid . '[administer nodes]'] = 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.'));
+
+ // Remove a permission.
+ $this->assertTrue(user_access('access user profiles', $account, TRUE), t('User has "access user profiles" permission.'));
+ $edit = array();
+ $edit[$rid . '[access user profiles]'] = FALSE;
+ $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.'));
+ }
+
+}