Index: includes/install.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/install.inc,v retrieving revision 1.31 diff -u -p -r1.31 install.inc --- includes/install.inc 2 Jan 2007 05:05:38 -0000 1.31 +++ includes/install.inc 25 Jan 2007 07:44:53 -0000 @@ -739,3 +739,28 @@ function drupal_check_module($module) { } return TRUE; } + +/** + * 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 drupal_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 permanetly remove a permission. + */ +function drupal_del_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); + } +} Index: includes/module.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/module.inc,v retrieving revision 1.94 diff -u -p -r1.94 module.inc --- includes/module.inc 24 Jan 2007 14:48:35 -0000 1.94 +++ includes/module.inc 25 Jan 2007 07:44:53 -0000 @@ -253,6 +253,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/comment/comment.install =================================================================== RCS file: /cvs/drupal/drupal/modules/comment/comment.install,v retrieving revision 1.2 diff -u -p -r1.2 comment.install --- modules/comment/comment.install 13 Dec 2006 22:44:54 -0000 1.2 +++ modules/comment/comment.install 25 Jan 2007 07:44:53 -0000 @@ -9,3 +9,12 @@ function comment_enable() { db_query_temporary("SELECT n.nid, n.created, n.uid FROM {node} n LEFT JOIN {node_comment_statistics} c ON n.nid = c.nid WHERE c.comment_count IS NULL", 'missing_nids'); db_query("INSERT INTO {node_comment_statistics} (nid, last_comment_timestamp, last_comment_name, last_comment_uid, comment_count) SELECT n.nid, n.created, NULL, n.uid, 0 FROM missing_nids n"); } + +/** + * Implementation of hook_install(). + */ +function comment_install() { + drupal_add_permission('access comments','comment'); + drupal_add_permission('post comments','comment'); + drupal_add_permission('post comments without approval','comment'); +} Index: modules/system/system.install =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.install,v retrieving revision 1.73 diff -u -p -r1.73 system.install --- modules/system/system.install 24 Jan 2007 14:48:36 -0000 1.73 +++ modules/system/system.install 25 Jan 2007 07:44:53 -0000 @@ -226,6 +226,7 @@ function system_install() { PRIMARY KEY (cid), INDEX expire (expire) ) /*!40100 DEFAULT CHARACTER SET UTF8 */ "); + db_query("CREATE TABLE {cache_filter} ( cid varchar(255) NOT NULL default '', data longblob, @@ -430,14 +431,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) @@ -898,19 +906,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, @@ -1082,11 +1097,14 @@ 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)"); + + drupal_add_permission('access content','node'); - 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)"); +// 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)"); 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.746 diff -u -p -r1.746 user.module --- modules/user/user.module 24 Jan 2007 14:48:36 -0000 1.746 +++ modules/user/user.module 25 Jan 2007 07:44:54 -0000 @@ -348,33 +348,29 @@ function user_password($length = 10) { */ function user_access($string, $account = NULL) { global $user; - static $perm = array(); + static $perm = array(), $role_string = array(); if (is_null($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))); - - $perm[$account->uid] = ''; - while ($row = db_fetch_object($result)) { - $perm[$account->uid] .= "$row->perm, "; - } + // Fold user's roles into an SQL fragment. + if (!isset($role_string[$account->uid])) { + $role_string[$account->uid] = implode(',', array_keys($account->roles)); } - if (isset($perm[$account->uid])) { - return strpos($perm[$account->uid], "$string, ") !== FALSE; + // If we don't have this permission cached yet, get it. + if (!isset($perm[$account->uid][$string])) { + $perm[$account->uid][$string] = db_num_rows(db_query_range("SELECT p.pid FROM {permission_role} pr INNER JOIN {permission} p ON pr.pid = p.pid WHERE perm = '%s' AND rid IN (%s)", $string, $role_string[$account->uid], 0, 1)); } - return FALSE; + // If the permission was set and granted to the role, access is granted. + return isset($perm[$account->uid][$string]) && $perm[$account->uid][$string]; } /** @@ -1842,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'); @@ -1859,26 +1855,27 @@ 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: - while ($role = db_fetch_object($result)) { - $role_permissions[$role->rid] = $role->perm; + while ($row = db_fetch_object($result)) { + $status[$row->rid][] = $row->pid; } + // 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; } @@ -1887,19 +1884,18 @@ function user_admin_perm($rid = NULL) { $options = array(); foreach (module_list(FALSE, FALSE, TRUE) as $module) { if ($permissions = module_invoke($module, 'perm')) { - $form['permission'][] = array( + $form['permission'][$module] = array( '#value' => $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 (strstr($role_permissions[$rid], $perm)) { - $status[$rid][] = $perm; - } - } + $result = db_query("SELECT pid FROM {permission} WHERE perm = '%s'",$perm); + $pid = db_result($result); + + // Add permission as an option + $options[$pid] = ''; + $form['permission'][$pid] = array('#value' => t($perm)); + } } } @@ -1920,7 +1916,7 @@ function theme_user_admin_perm($form) { if (is_array($form['permission'][$key])) { $row = array(); // Module name - if (is_numeric($key)) { + 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 { @@ -1952,10 +1948,10 @@ function user_admin_perm_submit($form_id 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); + db_query('DELETE FROM {permission_role} 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]))); + foreach ($form_values[$role->rid] AS $perm => $pid) { + db_query('INSERT INTO {permission_role} (pid, rid) VALUES (%d, %d)',$pid,$role->rid); } } } @@ -2039,10 +2035,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.')); } @@ -2737,3 +2733,15 @@ function user_forms() { return $forms; } +/** + * Pick up any new permissions that modules are advertising. + */ +function user_update_permissions() { + foreach (module_implements('perm') as $module) { + foreach (module_invoke($module, 'perm') as $permission) { + if (!db_result(db_query("SELECT COUNT(*) FROM {permission} WHERE perm = '%s'", $permission))) { + db_query("INSERT INTO {permission} (pid,perm,module) VALUES (%d,'%s','%s')",db_next_id('{permission}_pid'), $permission, $module); + } + } + } +}