Index: includes/module.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/module.inc,v retrieving revision 1.97 diff -u -p -r1.97 module.inc --- includes/module.inc 31 Jan 2007 15:49:22 -0000 1.97 +++ includes/module.inc 1 Feb 2007 00:20:26 -0000 @@ -255,6 +255,8 @@ function module_enable($module_list) { module_list(TRUE, FALSE); // Force to regenerate the stored list of hook implementations. module_implements('', FALSE, TRUE); + // Check for new permissions. + user_update_permissions(); } foreach ($invoke_modules as $module) { Index: modules/system/system.install =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.install,v retrieving revision 1.76 diff -u -p -r1.76 system.install --- modules/system/system.install 31 Jan 2007 21:26:56 -0000 1.76 +++ modules/system/system.install 1 Feb 2007 00:20:27 -0000 @@ -434,14 +434,21 @@ function system_install() { ) /*!40100 DEFAULT CHARACTER SET UTF8 */ "); db_query("CREATE TABLE {permission} ( - rid int unsigned NOT NULL default '0', - perm longtext, - tid int unsigned NOT NULL default '0', - KEY rid (rid) + pid int(10) unsigned NOT NULL default '0', + perm varchar(255) NOT NULL default '', + module varchar(255) NOT NULL default '', + PRIMARY KEY (pid), + UNIQUE KEY perm (perm) + ) /*!40100 DEFAULT CHARACTER SET UTF8 */ "); + + db_query("CREATE TABLE {permission_role} ( + pid int(10) unsigned NOT NULL, + rid int(10) unsigned NOT NULL, + PRIMARY KEY (pid,rid) ) /*!40100 DEFAULT CHARACTER SET UTF8 */ "); db_query("CREATE TABLE {role} ( - rid int unsigned NOT NULL auto_increment, + rid int unsigned NOT NULL, name varchar(64) NOT NULL default '', PRIMARY KEY (rid), UNIQUE KEY name (name) @@ -906,19 +913,26 @@ function system_install() { )"); db_query("CREATE INDEX {url_alias}_src_idx ON {url_alias} (src)"); + db_query("CREATE TABLE {role} ( + rid int_unsigned NOT NULL default '0', + name varchar(64) NOT NULL default '', + PRIMARY KEY (rid), + UNIQUE (name) + )"); + db_query("CREATE TABLE {permission} ( rid int_unsigned NOT NULL default '0', - perm text, - tid int_unsigned NOT NULL default '0' + perm varchar(255) NOT NULL default '', + module varchar(255) NOT NULL default '', )"); db_query("CREATE INDEX {permission}_rid_idx ON {permission} (rid)"); + db_query("CREATE INDEX {permission}_perm_idx ON {permission} (perm)"); - db_query("CREATE TABLE {role} ( - rid serial CHECK (rid >= 0), - name varchar(64) NOT NULL default '', - PRIMARY KEY (rid), - UNIQUE (name) + db_query("CREATE TABLE {permission_role} ( + pid int_unsigned NOT NULL default '0', + rid int_unsigned NOT NULL default '0' )"); + db_query("CREATE INDEX {permission_role}_pid_rid_idx ON {permission_role} (rid, pid)"); db_query("CREATE TABLE {blocks_roles} ( module varchar(64) NOT NULL, @@ -1090,11 +1104,18 @@ function system_install() { db_query("INSERT INTO {users} (uid,name,mail) VALUES(0,'','')"); - db_query("INSERT INTO {role} (name) VALUES ('anonymous user')"); - db_query("INSERT INTO {role} (name) VALUES ('authenticated user')"); + db_query("INSERT INTO {role} (rid, name) VALUES (1, 'anonymous user')"); + db_query("INSERT INTO {role} (rid, name) VALUES (2, 'authenticated user')"); + db_query("INSERT INTO {sequences} (name, id) VALUES ('{role}_rid', 2)"); + + db_query("INSERT INTO {permission} (pid, perm, module) VALUES (1, 'access content', 'node')"); + db_query("INSERT INTO {permission} (pid, perm, module) VALUES (2, 'access comments', 'comment')"); + db_query("INSERT INTO {permission} (pid, perm, module) VALUES (3, 'post comments', 'comment')"); + db_query("INSERT INTO {permission} (pid, perm, module) VALUES (4, 'post comments without approval', 'comment')"); + db_query("INSERT INTO {sequences} (name, id) VALUES ('{permission}_pid', 4)"); - db_query("INSERT INTO {permission} VALUES (1,'access content',0)"); - db_query("INSERT INTO {permission} VALUES (2,'access comments, access content, post comments, post comments without approval',0)"); + // Assign default permissions + db_query("INSERT INTO {permission_role} (pid, rid) VALUES (1, 1), (1, 2), (2, 2), (3, 2), (4, 2)"); db_query("INSERT INTO {variable} (name,value) VALUES('theme_default', 's:7:\"garland\";')"); Index: modules/user/user.module =================================================================== RCS file: /cvs/drupal/drupal/modules/user/user.module,v retrieving revision 1.752 diff -u -p -r1.752 user.module --- modules/user/user.module 31 Jan 2007 21:26:56 -0000 1.752 +++ modules/user/user.module 1 Feb 2007 00:20:27 -0000 @@ -354,27 +354,20 @@ function user_access($string, $account = $account = $user; } - // User #1 has all privileges: + // User #1 has all privileges. if ($account->uid == 1) { return TRUE; } - // 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 DISTINCT(p.perm) FROM {role} r INNER JOIN {permission} p ON p.rid = r.rid WHERE r.rid IN (%s)", implode(',', array_keys($account->roles))); + $role_string = implode(',', array_keys($account->roles)); - $perm[$account->uid] = ''; + $result = db_query("SELECT p.perm FROM {permission_role} pr INNER JOIN {permission} p ON pr.pid = p.pid WHERE pr.rid IN (%s)", $role_string); while ($row = db_fetch_object($result)) { - $perm[$account->uid] .= "$row->perm, "; + $perm[$account->uid][$row->perm] = 1; } } - - if (isset($perm[$account->uid])) { - return strpos($perm[$account->uid], "$string, ") !== FALSE; - } - - return FALSE; + return isset($perm[$account->uid][$string]); } /** @@ -1845,7 +1838,7 @@ function user_roles($membersonly = 0, $p $roles = array(); if ($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 {permission_role} pr ON r.rid = pr.rid INNER JOIN {permission} p ON pr.pid = p.pid WHERE p.perm = '%s' ORDER BY r.name", $permission); } else { $result = db_query('SELECT * FROM {role} ORDER BY name'); @@ -1862,106 +1855,120 @@ function user_roles($membersonly = 0, $p * Menu callback: administer permissions. */ function user_admin_perm($rid = NULL) { + // Compile permissions map. + $status = array(); 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); + $result = db_query('SELECT pr.rid, pr.pid FROM {permission_role} pr INNER JOIN {permission} p ON pr.pid = p.pid WHERE pr.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'); + $result = db_query('SELECT pr.rid, pr.pid FROM {permission_role} pr INNER JOIN {permission} p ON pr.pid = p.pid'); } - - // 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 .','; + while ($row = db_fetch_object($result)) { + $status[$row->rid][$row->pid] = TRUE; } + // Compile role list. + $role_names = array(); if (is_numeric($rid)) { - $result = db_query('SELECT rid, name FROM {role} r WHERE r.rid = %d ORDER BY name', $rid); + $result = db_query('SELECT rid, name FROM {role} WHERE rid = %d',$rid); } else { - $result = db_query('SELECT rid, name FROM {role} ORDER BY name'); + $result = db_query('SELECT rid, name FROM {role}'); } - - $role_names = array(); while ($role = db_fetch_object($result)) { $role_names[$role->rid] = $role->name; } + $form['permission'] = array( + '#type' => 'markup', + '#theme' => 'user_admin_perm_table', + '#header' => array_merge(t('Permission'), $role_names), + ); + // Render role/permission overview: $options = array(); foreach (module_list(FALSE, FALSE, TRUE) as $module) { if ($permissions = module_invoke($module, 'perm')) { - $form['permission'][] = array( - '#value' => $module, + $form['permission'][$module] = array( + '#type' => 'fieldset', + '#title' => t('@module module',array('@module'=>$module)), ); asort($permissions); foreach ($permissions as $perm) { - $options[$perm] = ''; - $form['permission'][$perm] = array('#value' => t($perm)); - foreach ($role_names as $rid => $name) { - // Builds arrays for checked boxes for each role - if (strpos($role_permissions[$rid], $perm .',') !== FALSE) { - $status[$rid][] = $perm; - } + $result = db_query("SELECT pid FROM {permission} WHERE perm = '%s'",$perm); + $pid = db_result($result); + + // Add permission as an option + $form['permission'][$module][$pid] = array( + '#type' => 'fieldset', + '#title' => t($perm), + '#tree' => TRUE, + ); + foreach ($role_names as $k => $v) { + $form['permission'][$module][$pid][$k] = array( + '#type' => 'checkbox', + '#title' => '', + '#default_value' => (isset($status[$k]) && isset($status[$k][$pid])), + ); } } } } - // Have to build checkboxes here after checkbox arrays are built - foreach ($role_names as $rid => $name) { - $form['checkboxes'][$rid] = array('#type' => 'checkboxes', '#options' => $options, '#default_value' => $status[$rid]); - $form['role_names'][$rid] = array('#value' => $name, '#tree' => TRUE); - } $form['submit'] = array('#type' => 'submit', '#value' => t('Save permissions')); - return $form; } -function theme_user_admin_perm($form) { - foreach (element_children($form['permission']) as $key) { - // Don't take form control structures - if (is_array($form['permission'][$key])) { +function theme_user_admin_perm_table($element) { + $ncols = count($element['#header']); + $rows = array(); + foreach (element_children($element) as $module) { + // Module header + $rows[] = array( + 'data' => array( + array( + 'data' => $element[$module]['#title'], + 'colspan' => $ncols, + 'id' => 'module-'. $element[$module]['#title'], + 'class' => 'module', + ), + ), + ); + + // Permissions of the module + foreach (element_children($element[$module]) as $permission) { $row = array(); - // Module name - if (is_numeric($key)) { - $row[] = array('data' => t('@module module', array('@module' => drupal_render($form['permission'][$key]))), 'class' => 'module', 'id' => 'module-'. $form['permission'][$key]['#value'], 'colspan' => count($form['role_names']) + 1); - } - else { - $row[] = array('data' => drupal_render($form['permission'][$key]), 'class' => 'permission'); - foreach (element_children($form['checkboxes']) as $rid) { - if (is_array($form['checkboxes'][$rid])) { - $row[] = array('data' => drupal_render($form['checkboxes'][$rid][$key]), 'align' => 'center', 'title' => t($key)); - } - } + // Title + $row[] = array( + 'data' => $element[$module][$permission]['#title'], + 'class' => 'permission', + ); + foreach (element_children($element[$module][$permission]) as $role) { + // Role + $row[] = array( + 'align' => 'center', + 'title' => $element[$module][$permission]['#title'], + 'data' => drupal_render($element[$module][$permission][$role]), + ); } $rows[] = $row; } } - $header[] = (t('Permission')); - foreach (element_children($form['role_names']) as $rid) { - if (is_array($form['role_names'][$rid])) { - $header[] = drupal_render($form['role_names'][$rid]); - } - } - $output = theme('table', $header, $rows, array('id' => 'permissions')); - $output .= drupal_render($form); - return $output; + return theme('table', $element['#header'], $rows, array('id' => 'permissions')); } function user_admin_perm_submit($form_id, $form_values) { // Save permissions: - $result = db_query('SELECT * FROM {role}'); - while ($role = db_fetch_object($result)) { - if (isset($form_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_values[$role->rid] = array_filter($form_values[$role->rid]); - if (count($form_values[$role->rid])) { - db_query("INSERT INTO {permission} (rid, perm) VALUES (%d, '%s')", $role->rid, implode(', ', array_keys($form_values[$role->rid]))); + $result = db_query('SELECT * FROM {permission}'); + while ($perm = db_fetch_object($result)) { + if (isset($form_values[$perm->pid])) { + foreach ($form_values[$perm->pid] as $rid => $val) { + // We have to remove it first in case the box state went from checked -> unchecked. + db_query('DELETE FROM {permission_role} WHERE pid = %d AND rid = %d', $perm->pid, $rid); + if ($val) { + // Add if checked. + db_query('INSERT INTO {permission_role} (pid, rid) VALUES (%d, %d)', $perm->pid, $rid); + } } } } @@ -2045,10 +2052,10 @@ function user_admin_role_submit($form_id drupal_set_message(t('The role has been renamed.')); } else if ($form_values['op'] == t('Delete role')) { - db_query('DELETE FROM {role} WHERE rid = %d', $form_values['rid']); - db_query('DELETE FROM {permission} WHERE rid = %d', $form_values['rid']); + db_query('DELETE FROM {permission_role} WHERE rid = %d',$form_values['rid']); // Update the users who have this role set: db_query('DELETE FROM {users_roles} WHERE rid = %d', $form_values['rid']); + db_query('DELETE FROM {role} WHERE rid = %d', $form_values['rid']); drupal_set_message(t('The role has been deleted.')); } @@ -2746,3 +2753,63 @@ function user_forms() { return $forms; } +/** + * Pick up any new permissions that modules are advertising. + */ +function user_update_permissions() { + // Build permission list + $old_perms = array(); + $result = db_query('SELECT perm FROM {permission}'); + while ($perm = db_fetch_object($result)) { + $old_perms[$perm->perm] = 1; + } + + foreach (module_implements('perm') as $module) { + foreach (module_invoke($module, 'perm') as $permission) { + if (!isset($old_perms[$permission])) { + user_permission_add_permission($permission, $module); + db_query("INSERT INTO {permission} (pid,perm,module) VALUES (%d,'%s','%s')",db_next_id('{permission}_pid'), $permission, $module); + } + } + } +} + +/** + * Add a permission. + * This function will add a permission to the permission table and return the pid. + * If the permission already exists, its pid will be returned instead. + */ +function user_permission_add_permission($perm, $module='') { + if ($pid = db_result(db_query("SELECT pid FROM {permission} WHERE perm = '%s'",$perm))) { + return $pid; + } + $pid = db_next_id('{permission}_pid'); + db_query("INSERT INTO {permission} (pid,perm,module) VALUES (%d,'%s','%s')",$pid,$perm,$module); + return $pid; +} + +/** + * Delete a permission. + * This function will permanently remove a permission. + */ +function user_permission_delete_permission($perm) { + if ($pid = db_result(db_query("SELECT pid FROM {permission} WHERE perm = '%s'",$perm))) { + db_query("DELETE FROM {permission_role} WHERE pid = %d",$pid); + db_query("DELETE FROM {permission} WHERE pid = %d",$pid); + } +} + +/** + * Change a permission. + * This function will change the name and (optionally) owner of a permission. + */ +function user_permission_change_permission($old_perm, $perm, $module = '') { + $pid = db_result(db_query("SELECT pid FROM {permission} WHERE perm = '%s'", $old_perm)); + if (!empty($module)) { + db_query("UPDATE {permission} SET perm = '%s', module = '%s' WHERE pid = %d", $perm, $module, $pid); + } + else { + db_query("UPDATE {permission} SET perm = '%s' WHERE pid = %d", $perm, $pid); + } + return $pid; +}