diff --git a/core/modules/user/user.admin.inc b/core/modules/user/user.admin.inc index c65883a..0b69afe 100644 --- a/core/modules/user/user.admin.inc +++ b/core/modules/user/user.admin.inc @@ -289,7 +289,7 @@ function user_admin_settings() { '#title' => t('Administrator role'), '#default_value' => variable_get('user_admin_role', 0), '#options' => $roles, - '#description' => t('This role will be automatically assigned new permissions whenever a module is enabled. Changing this setting will not affect existing permissions.'), + '#description' => t('This role will be automatically assigned new permissions whenever a module is installed. Changing this setting will not affect existing permissions.'), ); // User registration settings. diff --git a/core/modules/user/user.api.php b/core/modules/user/user.api.php index 8c7286e..868eba9 100644 --- a/core/modules/user/user.api.php +++ b/core/modules/user/user.api.php @@ -454,5 +454,49 @@ function hook_user_role_delete($role) { } /** ++ * Inform other modules that a user role has been deleted. ++ * ++ * Allows you act when a user role has been deleted. If your module stores references to roles, ++ * it's recommended that you implement this hook and delete existing instances of the deleted role in your module database tables ++ * ++ * @param $role ++ * The name of the role you're trying to find. ++ */ +function hook_user_permissions_insert($permissions) { +} + +/** ++ * Allows you act when a permission is enabled for a user. ++ * ++ * @param $permissions ++ * An array of permissions. ++ */ + +function hook_user_permissions_delete($permissions) { +} + +/** ++ * Inform other modules that a user role has been deleted. ++ * ++ * Allows you act when a user role has been deleted. If your module stores references to roles, ++ * it's recommended that you implement this hook and delete existing instances of the deleted role in your module database tables ++ * ++ * @param $role ++ * The name of the role you're trying to find. ++ */ +function hook_user_permissions_insert($permissions) { +} + +/** ++ * Allows you act when a permission is enabled for a user. ++ * ++ * @param $permissions ++ * An array of permissions. ++ */ + +function hook_user_permissions_delete($permissions) { +} + +/** * @} End of "addtogroup hooks". */ diff --git a/core/modules/user/user.module b/core/modules/user/user.module index cfde270..f0e6fe6 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -2918,6 +2918,96 @@ function user_role_revoke_permissions($rid, array $permissions = array()) { } /** + * Adds new user permissions to the site. + * + * Modules should call this function when the list of permissions that the + * module provides has changed (for example, a dynamic permission has + * appeared). + * + * @todo: Change documentation since modules don't always have to call it. + * + * @param $permissions + * A list of permission names to add. + */ +function user_permissions_insert(array $permissions = array()) { + // Allow modules to react on new permissions. + module_invoke_all('user_permissions_insert', $permissions); + + // Grant any new permissions to the administration role. + $rid = variable_get('user_admin_role', 0); + if ($rid && !empty($permissions)) { + user_role_grant_permissions($rid, $permissions); + } +} + +/** + * Removes user permissions that are no longer available. + * + * Modules should call this function when the list of permissions that the + * module provides has changed (for example, a dynamic permission has + * disappeared). + * + * @todo: Change documentation, or make all core modules actually call it. + * + * @param $permissions + * A list of permission names to delete. + */ +function user_permissions_delete(array $permissions = array()) { + // Allow modules to act on the deleted permissions before they are removed. + module_invoke_all('user_permissions_delete', $permissions); + + // Delete all records that currently reference the permissions. + db_delete('role_permission') + ->condition('permission', $permissions, 'IN') + ->execute(); +} + +/** + * Adds new user permissions to the site. + * + * Modules should call this function when the list of permissions that the + * module provides has changed (for example, a dynamic permission has + * appeared). + * + * @todo: Change documentation since modules don't always have to call it. + * + * @param $permissions + * A list of permission names to add. + */ +function user_permissions_insert(array $permissions = array()) { + // Allow modules to react on new permissions. + module_invoke_all('user_permissions_insert', $permissions); + + // Grant any new permissions to the administration role. + $rid = variable_get('user_admin_role', 0); + if ($rid && !empty($permissions)) { + user_role_grant_permissions($rid, $permissions); + } +} + +/** + * Removes user permissions that are no longer available. + * + * Modules should call this function when the list of permissions that the + * module provides has changed (for example, a dynamic permission has + * disappeared). + * + * @todo: Change documentation, or make all core modules actually call it. + * + * @param $permissions + * A list of permission names to delete. + */ +function user_permissions_delete(array $permissions = array()) { + // Allow modules to act on the deleted permissions before they are removed. + module_invoke_all('user_permissions_delete', $permissions); + + // Delete all records that currently reference the permissions. + db_delete('role_permission') + ->condition('permission', $permissions, 'IN') + ->execute(); +} + +/** * Implements hook_user_operations(). */ function user_user_operations($form = array(), $form_state = array()) { @@ -3666,21 +3756,31 @@ function user_register_submit($form, &$form_state) { } /** + * Implements hook_modules_to_be_installed(). + */ +function user_modules_to_be_installed($modules) { + // Record all currently defined permissions, for later use in + // user_modules_installed(). + $all_permissions = &drupal_static(__FUNCTION__); + $all_permissions = array_keys(module_invoke_all('permission')); +} + +/** * Implements hook_modules_installed(). */ function user_modules_installed($modules) { - // Assign all available permissions to the administrator role. - $rid = variable_get('user_admin_role', 0); - if ($rid) { - $permissions = array(); - foreach ($modules as $module) { - if ($module_permissions = module_invoke($module, 'permission')) { - $permissions = array_merge($permissions, array_keys($module_permissions)); - } - } - if (!empty($permissions)) { - user_role_grant_permissions($rid, $permissions); - } + // Find all permissions which were newly-added as a result of this module + // being installed. This could include permissions defined by the module + // itself as well as permissions defined by other modules in response to it + // (for example, new node permissions will appear if the module defines a + // content type). + $previous_permissions = &drupal_static('user_modules_to_be_installed', array()); + $current_permissions = array_keys(module_invoke_all('permission')); + $new_permissions = array_diff($current_permissions, $previous_permissions); + + // Add the new permissions to the site. + if (!empty($new_permissions)) { + user_permissions_insert($new_permissions); } } @@ -3688,9 +3788,15 @@ function user_modules_installed($modules) { * Implements hook_modules_uninstalled(). */ function user_modules_uninstalled($modules) { - db_delete('role_permission') - ->condition('module', $modules, 'IN') - ->execute(); + // Remove any permissions defined by this module from the site. + // @todo: This will skip any permissions that are not in the database (i.e., + // that are not assigned to any roles). This doesn't matter for our + // purposes, but in theory it's a problem since user_permissions_delete() + // invokes a hook which should get the full list of "deleted" permissions. + $permissions = db_query('SELECT DISTINCT(permission) FROM {role_permission} WHERE module IN (:modules)', array(':modules' => $modules))->fetchCol(); + if (!empty($permissions)) { + user_permissions_delete($permissions); + } } /**