role_expire.module in Role Expire 7
Same filename and directory in other branches
Role Expire module
Enables user roles to expire on given time.
File
role_expire.moduleView source
<?php
/**
* @file
* Role Expire module
*
* Enables user roles to expire on given time.
*/
/*******************************************************************************
* API functions
******************************************************************************/
/**
* API function; Get expiration time of a user role.
* @param $uid
* User ID.
* @param $rid
* Role ID.
* @return
* Array with the expiration time.
*/
function role_expire_get_user_role_expiry_time($uid, $rid) {
$result = db_query("SELECT expiry_timestamp FROM {role_expire} WHERE uid = :uid AND rid = :rid", array(
':uid' => $uid,
':rid' => $rid,
))
->fetchField();
return !empty($result) ? $result : '';
}
/**
* API function; Get expiration of all roles of a user.
* @param $uid
* User ID.
* @return
* Array with the expiration time.
*/
function role_expire_get_all_user_records($uid) {
$return = array();
$result = db_query("SELECT rid, expiry_timestamp FROM {role_expire} WHERE uid = :uid", array(
':uid' => $uid,
));
foreach ($result as $row) {
$return[$row->rid] = $row->expiry_timestamp;
}
return $return;
}
/**
* API function; Delete a record from the database.
*
* @param $uid
* User ID.
* @param $rid
* Role ID.
* @return
*/
function role_expire_delete_record($uid, $rid) {
db_delete('role_expire')
->condition('uid', $uid)
->condition('rid', $rid)
->execute();
// Delete the user's sessions so they have login again with their new access.
drupal_session_destroy_uid($uid);
}
/**
* API function; Delete all records for role.
*
* @param $rid
* Role ID.
* @return
*/
function role_expire_delete_role_records($rid) {
db_delete('role_expire')
->condition('rid', $rid)
->execute();
}
/**
* API function; Delete all user expirations.
*
* @param $uid
* User ID.
* @return
*/
function role_expire_delete_user_records($uid) {
db_delete('role_expire')
->condition('uid', $uid)
->execute();
// Delete the user's sessions so they have login again with their new access.
drupal_session_destroy_uid($uid);
}
/**
* API function; Insert or update a record in the database.
*
* @param $uid
* User ID.
* @param $rid
* Role ID.
* @param $expiry_time
* The expiration timestamp.
*/
function role_expire_write_record($uid, $rid, $expiry_timestamp) {
$existing = db_query("SELECT expiry_timestamp FROM {role_expire} WHERE uid = :uid AND rid = :rid", array(
':uid' => $uid,
':rid' => $rid,
))
->fetchField();
if ($existing && $expiry_timestamp != $existing) {
$result = db_update('role_expire')
->fields(array(
'expiry_timestamp' => $expiry_timestamp,
))
->condition('uid', $uid)
->condition('rid', $rid)
->execute();
}
elseif ($existing == FALSE) {
$id = db_insert('role_expire')
->fields(array(
'uid' => $uid,
'rid' => $rid,
'expiry_timestamp' => $expiry_timestamp,
))
->execute();
}
}
/**
* API function; Get the default duration for a role.
* @param $rid
* Required. The role_id to check.
* @return
* String containing the strtotime compatible default duration of the role
* or empty string if not set.
*/
function role_expire_get_default_duration($rid) {
// Because this function is called a couple times during the same page load,
// remember the result from the first call.
static $default_duration = array();
if (!isset($default_duration[$rid])) {
$result = db_query("SELECT duration FROM {role_expire_length} WHERE rid = :rid", array(
':rid' => $rid,
))
->fetchField();
$default_duration[$rid] = $result;
}
return $default_duration[$rid];
}
/**
* API function; Set the default expiry duration for a role.
*
* @param $rid
* Role ID.
* @param $duration
* The strtotime-compatible duration string.
*/
function role_expire_set_default_duration($rid, $duration) {
if (!empty($duration)) {
// Do we have a value already?
$prev_duration = role_expire_get_default_duration($rid);
// If we have a previous duration, attempt to do an UPDATE.
if ($prev_duration) {
$result = db_update('role_expire_length')
->fields(array(
'duration' => check_plain($duration),
))
->condition('rid', $rid)
->execute();
}
else {
$id = db_insert('role_expire_length')
->fields(array(
'rid' => $rid,
'duration' => check_plain($duration),
))
->execute();
}
}
}
/**
* API function; Delete default duration(s) for a role.
* @param $rid
* Required. The role_id to remove.
*/
function role_expire_delete_default_duration($rid) {
db_delete('role_expire_length')
->condition('rid', $rid)
->execute();
}
/**
* API function; Get all records that should be expired.
*
* @param $time
* Optional. The time to check, if not set it will check current time.
*/
function role_expire_get_expired($time = '') {
$return = array();
if (!$time) {
$time = REQUEST_TIME;
}
$result = db_query("SELECT rid, uid, expiry_timestamp FROM {role_expire} WHERE expiry_timestamp <= :expiry_timestamp", array(
':expiry_timestamp' => $time,
));
foreach ($result as $row) {
$return[] = $row;
}
return $return;
}
/**
* API function; Get roles to assign on expiration (global configuration).
*
* @return array
* Returns an array where the key is the original rid and the value the
* one that has to be assigned on expiration. The array will be empty if
* configuration is not set.
*/
function role_expire_get_roles_after_expiration() {
$values_raw = variable_get('role_expire_default_roles', '');
$values = empty($values_raw) ? array() : json_decode($values_raw, TRUE);
return $values;
}
/*******************************************************************************
* Hook implementations
******************************************************************************/
/**
* Implements hook_menu().
*/
function role_expire_menu() {
$items = array();
$items['admin/config/people/role_expire'] = array(
'title' => 'Role expire',
'description' => 'Change default role when each role expires',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'role_expire_admin_settings',
),
'access arguments' => array(
'administer site configuration',
),
'type' => MENU_NORMAL_ITEM,
'file' => 'role_expire.admin.inc',
);
return $items;
}
/**
* Implements hook_user_role_delete().
*/
function role_expire_user_role_delete($role) {
// Delete the duration row for that role if exists.
role_expire_delete_default_duration($role->rid);
// Delete all expire information for that role.
role_expire_delete_role_records($role->rid);
}
/**
* Implements hook_views_api().
*/
function role_expire_views_api() {
// Any Views 3 version is fine.
$current_views_version = views_api_version();
if (preg_match('/^3\\./', $current_views_version)) {
return array(
'api' => $current_views_version,
);
}
}
/**
* Implements hook_migrate_init().
*/
function role_expire_migrate_init() {
// Don't load migration support unless we need it
$path = drupal_get_path('module', 'role_expire') . '/role_expire.migrate.inc';
include_once DRUPAL_ROOT . '/' . $path;
}
/**
* Implements hook_permission().
*/
function role_expire_permission() {
return array(
'administer role expire' => array(
'title' => t('administer role expire'),
'description' => t('For each role, manage default role expiration dates (admin/people/permissions/roles/edit/#) and user role expiration dates (user/#/edit).'),
),
);
}
/**
* Implements hook_form_FORM-ID_alter().
*/
function role_expire_form_user_register_form_alter(&$form, $form_state) {
role_expire_add_expiration_input($form);
}
/**
* Implements hook_form_FORM-ID_alter().
*/
function role_expire_form_user_profile_form_alter(&$form, $form_state) {
role_expire_add_expiration_input($form);
}
/**
* Implements hook_form_FORM-ID_alter().
*
* Support for Role Delegation + Contextual Admin modules.
* @see https://www.drupal.org/node/2700759
*/
function role_expire_form_context_admin_user_create_menu_render_form_alter(&$form, $form_state) {
role_expire_add_expiration_input($form);
}
/**
* Implements hook_form_FORM-ID_alter().
*/
function role_expire_form_user_admin_role_alter(&$form, $form_state) {
$form['role_expire'] = array(
'#title' => t("Default duration for the role %role", array(
'%role' => drupal_ucfirst($form['name']['#default_value']),
)),
'#type' => 'textfield',
'#size' => 10,
'#default_value' => role_expire_get_default_duration($form['rid']['#value']),
'#maxlength' => 32,
'#attributes' => array(
'class' => array(
'role-expire-role-expiry',
),
),
'#description' => t('Enter the time span you want to set as the default duration for this role. Examples: 12 hours, 1 day, 3 days, 4 weeks, 3 months, 1 year. Leave blank for no default duration. (If you speak php, this value may be any !l-compatible relative form.)', array(
'!l' => l('strtotime', 'http://php.net/manual/en/function.strtotime.php'),
)),
);
// Reposition the submit button and delete.
$form['submit']['#weight'] = 2;
if (arg(4)) {
$form['delete']['#weight'] = 3;
}
$form['#validate'][] = 'role_expire_user_admin_role_validate';
$form['#submit'][] = 'role_expire_user_admin_role_submit';
}
/**
* Form validation handler invoked by role_expire_form_user_admin_role_alter.
* Ensure that the specified duration is a valid, relative, positive strtotime-
* compatible string.
*
* @param $form
* @param $form_state
*/
function role_expire_user_admin_role_validate($form, &$form_state) {
if (!empty($form_state['values']['role_expire'])) {
// Capture the duration from the form
$duration_string = check_plain($form_state['values']['role_expire']);
// Make sure it's a *relative* duration string. That is, it will result in a
// different strtotime when a different 'now' value is used.
$now = time();
$timestamp = strtotime($duration_string, $now);
$timestamp2 = strtotime($duration_string, $now - 100);
if ($timestamp === FALSE || $timestamp < 0) {
form_set_error('role_expire', t('Role expiry default duration must be a strtotime-compatible string.'));
}
elseif ($timestamp < $now) {
form_set_error('role_expire', t('Role expiry default duration must be a <strong>future</strong> strtotime-compatible string.'));
}
elseif ($timestamp == $timestamp2) {
// This is an absolute (or special) timestamp. That's not allowed.
form_set_error('role_expire', t('Role expiry default duration must be a <strong>relative</strong> strtotime-compatible string.'));
}
// not relative
}
// !empty
}
/**
* Form submit handler invoked by role_expire_form_user_admin_role_alter.
* Updates default duration in database.
*/
function role_expire_user_admin_role_submit($form, &$form_state) {
// If the role is being deleted, delete the default duration.
// OR, if the new default duration is blank (empty), delete the default duration.
if ($form_state['values']['op'] == t('Delete role') || empty($form_state['values']['role_expire'])) {
role_expire_delete_default_duration($form_state['values']['rid']);
}
elseif ($form_state['values']['op'] == t('Save role')) {
// Set the default duration to what's specified.
role_expire_set_default_duration($form_state['values']['rid'], $form_state['values']['role_expire']);
drupal_set_message('New default role expiration set.');
}
}
/**
* Implements hook_user_update().
*/
function role_expire_user_update(&$edit, $account, $category) {
if ($category == 'account' && (user_access('administer role expire') || user_access('administer users'))) {
// Add roles expiry information for the user role.
foreach (array_keys($edit) as $name) {
if (strpos($name, 'role_expire_') === 0) {
$value = $edit[$name];
$rid = substr($name, strlen('role_expire_'));
if ($value != '' && array_key_exists($rid, $edit['roles'])) {
$expiry_timestamp = strtotime($value);
role_expire_write_record($account->uid, $rid, $expiry_timestamp);
}
else {
role_expire_delete_record($account->uid, $rid);
}
}
}
if (isset($edit['roles'])) {
// Add default expiration to any new roles that have been given to the user.
$new_roles = array_diff(array_keys($edit['roles']), array_keys($edit['original']->roles));
if (isset($new_roles)) {
// We have the new roles, loop over them and see whether we need to assign expiry to them.
foreach ($new_roles as $role_id) {
role_expire_process_default_role_duration_for_user($role_id, $account->uid);
}
}
// Remove expiration for roles that have been removed from the user.
$del_roles = array_diff(array_keys($edit['original']->roles), array_keys($edit['roles']));
if (isset($del_roles)) {
// We have the deleted roles, loop over them and remove their expiry info.
foreach ($del_roles as $role_id) {
role_expire_delete_record($account->uid, $role_id);
}
}
}
// if edit[roles]
}
// if category && user_access
}
/**
* Implements hook_user_insert().
*/
function role_expire_user_insert(&$edit, $account, $category) {
if ($category == 'account' && (user_access('administer role expire') || user_access('administer users'))) {
// Add roles expiry information for the user role.
foreach (array_keys($edit) as $name) {
if (strpos($name, 'role_expire_') === 0) {
$value = $edit[$name];
$rid = substr($name, strlen('role_expire_'));
// No need to call role_expire_delete_record because it's a new user.
if ($value != '' && array_key_exists($rid, $edit['roles'])) {
$expiry_timestamp = strtotime($value);
role_expire_write_record($account->uid, $rid, $expiry_timestamp);
}
}
}
// Role delegation module adds a separate "roles_change" array to manage
// access. This is merged into the "roles" array prior to saving.
$roles_key = module_exists('role_delegation') && !user_access('administer permissions') ? 'roles_change' : 'roles';
if (isset($edit[$roles_key])) {
// Add default expiration to any new roles that have been given to the user.
if ($roles_key == 'roles' && isset($edit['original'])) {
$new_roles = array_diff(array_keys($edit[$roles_key]), array_keys($edit['original']->roles));
}
else {
$new_roles = array_filter($edit[$roles_key]);
}
if (isset($new_roles)) {
// We have the new roles, loop over them and see whether we need to assign expiry to them.
foreach (array_keys($edit[$roles_key]) as $role_id) {
role_expire_process_default_role_duration_for_user($role_id, $account->uid);
}
}
}
// if edit[roles] or edit[roles_change]
}
// if category && user_access
}
/**
* Implements hook_user_cancel().
*/
function role_expire_user_cancel($edit, $account, $method) {
// Delete user records.
role_expire_delete_user_records($account->uid);
}
/**
* Implements hook_user_delete().
*/
function role_expire_user_delete($account) {
// Delete user records.
role_expire_delete_user_records($account->uid);
}
/**
* Implements hook_user_load().
*/
function role_expire_user_load($users) {
// We don't load the information to the user object. Other modules can use
// our API to query the information.
/**
* Load the starter roles into a static cache so it is easy to
* see what has changed later on.
*
* TODO. Support multiple users that are being loaded here. Not sure yet
* what that means for Role Expire 7.
*/
foreach ($users as $account) {
_role_static_user_roles($account->uid, $account->roles);
}
}
/**
* Implements hook_user_view().
*/
function role_expire_user_view($account, $view_mode) {
global $user;
if (user_access('administer role expire') || user_access('administer users') || $user->uid == $account->uid) {
$roles = array();
$expiry_roles = role_expire_get_all_user_records($account->uid);
foreach ($account->roles as $key => $val) {
if (array_key_exists($key, $expiry_roles)) {
$roles[$key] = t("%role role expiration date: %timedate", array(
'%role' => ucfirst($val),
'%timedate' => format_date($expiry_roles[$key]),
));
}
}
if ($roles) {
$account->content['summary']['role_expire'] = array(
'#type' => 'user_profile_item',
'#title' => t('Role expiration'),
'#markup' => theme('item_list', array(
'items' => $roles,
)),
'#attributes' => array(
'class' => array(
'role-expiry-roles',
),
),
);
}
}
}
/**
* Implements hook_cron().
*/
function role_expire_cron() {
if ($expires = role_expire_get_expired()) {
$roles = _role_expire_get_role();
foreach ($expires as $expire) {
// Remove the role expiration record from the role_expires table.
role_expire_delete_record($expire->uid, $expire->rid);
// Remove the role from the user.
// TODO Convert "user_load" to "user_load_multiple" if "$expire['uid']" is other than a uid.
// To return a single user object, wrap "user_load_multiple" with "array_shift" or equivalent.
// Example: array_shift(user_load_multiple(array(), $expire['uid']))
$account = user_load($expire->uid);
// If the account *does* exist, update it.
if (!empty($account)) {
// Assign a new role after expiration if requested given configuration.
$new_roles = role_expire_get_roles_after_expiration();
if (!empty($new_roles) && isset($new_roles[$expire->rid]) && $new_roles[$expire->rid] != 0) {
$new_rid = $new_roles[$expire->rid];
$new_role = user_role_load($new_rid);
$account->roles[$new_rid] = $new_role->name;
role_expire_process_default_role_duration_for_user($new_rid, $account->uid);
}
$edit = $account->roles;
unset($edit[$expire->rid]);
// In the documentation for the role_expire implementation of hook_user we
// state to use $category = 'account'. We don't do that here because
// that would cause the delete to occur twice.
user_save($account, array(
'roles' => $edit,
), NULL);
// Handle the bizarre case of role_expire not being a valid role.
$role_name = isset($roles[$expire->rid]) ? $roles[$expire->rid] : t('-unset-');
watchdog('role expire', 'Removed role @role from user @account.', array(
'@role' => $role_name,
'@account' => $account->name,
));
if (module_exists('rules')) {
rules_invoke_event('role_expire_rules_event_role_expires', $account, $role_name);
}
}
else {
// The account doesn't exist. Database altered outside of Drupal.
// Throw a warning message.
watchdog('role expire', 'Data integrity warning: Role_expire table updated, but no user with uid @uid.', array(
'@uid' => $expire->uid,
), WATCHDOG_WARNING);
}
}
}
}
/**
* Add form elements to the given form that accept the role expiration times.
*
* @param array $form
* The user edit form to which role expire input elements will be added.
*/
function role_expire_add_expiration_input(array &$form) {
// Role delegation module adds a separate "roles_change" array to manage
// access. This is merged into the "roles" array prior to saving.
$roles_key = module_exists('role_delegation') && !user_access('administer permissions') ? 'roles_change' : 'roles';
// Add expiration fields to each checkbox, based on permissions.
if ((user_access('administer users') || user_access('administer role expire')) && !empty($form['account'][$roles_key])) {
// Get $uid of currently viewed user.
$uid = !empty($form['#user']) && is_object($form['#user']) && !empty($form['#user']->uid) ? $form['#user']->uid : NULL;
// Attach CSS class and JavaScript file to the form field.
$form['account'][$roles_key]['#attributes']['class'][] = 'role-expire-roles';
$form['account'][$roles_key]['#attached']['js'][] = drupal_get_path('module', 'role_expire') . '/role_expire.js';
// Loop through each roles checkbox and add an expiration field.
foreach ($form['account'][$roles_key]['#options'] as $rid => $role) {
$expiry_timestamp = $uid !== NULL ? role_expire_get_user_role_expiry_time($uid, $rid) : '';
$form['role_expire_' . $rid] = array(
'#title' => t("%role role expiration date/time", array(
'%role' => drupal_ucfirst($role),
)),
'#type' => 'textfield',
'#default_value' => !empty($expiry_timestamp) ? date("Y-m-d H:i:s", $expiry_timestamp) : '',
'#attributes' => array(
'class' => array(
'role-expire-role-expiry',
),
),
'#description' => t("Leave blank for default role expiry (never, or the duration you have set for the role), enter date and time in format: <em>yyyy-mm-dd hh:mm:ss</em> or use relative time i.e. 1 day, 2 months, 1 year, 3 years."),
);
}
$form['#validate'][] = '_role_expire_validate_role_expires';
}
}
/*******************************************************************************
* Helper functions
******************************************************************************/
/**
* Helper function; Store user roles for this page request.
* @return
* array of roles
*/
function _role_static_user_roles($id, $roles = '') {
static $user_roles = array();
if (!isset($user_roles[$id]) && is_array($roles)) {
$user_roles[$id] = $roles;
}
if (!isset($user_roles[$id])) {
return FALSE;
}
else {
return $user_roles[$id];
}
}
/**
* Helper function; Get valid roles.
* @return unknown_type
*/
function _role_expire_get_role() {
$roles = user_roles(TRUE);
unset($roles[DRUPAL_AUTHENTICATED_RID]);
return $roles;
}
/**
* Form validation handler for the role expiration on the user_profile_form().
*
* @see user_profile_form()
*/
function _role_expire_validate_role_expires(&$form, &$form_state) {
$time = REQUEST_TIME;
foreach ($form_state['values'] as $name => $value) {
if (strpos($name, 'role_expire_') === 0 && trim($value) != '') {
$expiry_time = strtotime($value);
if (!$expiry_time) {
form_set_error($name, t("Role expiry is not in correct format."));
}
if ($expiry_time <= $time) {
form_set_error($name, t("Role expiry must be in the future."));
}
}
}
}
/**
* Sets the default role duration for the current user/role combination.
* @param $role_id
* The ID of the role.
* @param $uid
* The user ID.
*/
function role_expire_process_default_role_duration_for_user($role_id, $uid) {
// Does a default expiry exist for this role?
$default_duration = role_expire_get_default_duration($role_id);
if ($default_duration) {
$user_role_expiry = role_expire_get_user_role_expiry_time($uid, $role_id);
// If the expiry is empty then we act!.
if (!$user_role_expiry) {
// Use strtotime of default duration.
role_expire_write_record($uid, $role_id, strtotime($default_duration));
}
}
}
/**
* Implementation of hook_feeds_node_processor_targets_alter().
*/
function role_expire_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
global $user;
$roles = user_roles();
foreach ($roles as $rid => $rname) {
if ($entity_type == 'user') {
$targets['role_expire_' . $rid] = array(
'name' => t('Role expire date (' . $rname . ')'),
'description' => t("Expire date for role " . $rname),
'callback' => 'role_expire_set_target',
);
}
}
}
/**
* Callback for mapping. Here is where the actual mapping happens.
*/
function role_expire_set_target($source, $entity, $target, $value) {
$entity->{$target} = $value[0];
}
Functions
Name | Description |
---|---|
role_expire_add_expiration_input | Add form elements to the given form that accept the role expiration times. |
role_expire_cron | Implements hook_cron(). |
role_expire_delete_default_duration | API function; Delete default duration(s) for a role. |
role_expire_delete_record | API function; Delete a record from the database. |
role_expire_delete_role_records | API function; Delete all records for role. |
role_expire_delete_user_records | API function; Delete all user expirations. |
role_expire_feeds_processor_targets_alter | Implementation of hook_feeds_node_processor_targets_alter(). |
role_expire_form_context_admin_user_create_menu_render_form_alter | Implements hook_form_FORM-ID_alter(). |
role_expire_form_user_admin_role_alter | Implements hook_form_FORM-ID_alter(). |
role_expire_form_user_profile_form_alter | Implements hook_form_FORM-ID_alter(). |
role_expire_form_user_register_form_alter | Implements hook_form_FORM-ID_alter(). |
role_expire_get_all_user_records | API function; Get expiration of all roles of a user. |
role_expire_get_default_duration | API function; Get the default duration for a role. |
role_expire_get_expired | API function; Get all records that should be expired. |
role_expire_get_roles_after_expiration | API function; Get roles to assign on expiration (global configuration). |
role_expire_get_user_role_expiry_time | API function; Get expiration time of a user role. |
role_expire_menu | Implements hook_menu(). |
role_expire_migrate_init | Implements hook_migrate_init(). |
role_expire_permission | Implements hook_permission(). |
role_expire_process_default_role_duration_for_user | Sets the default role duration for the current user/role combination. |
role_expire_set_default_duration | API function; Set the default expiry duration for a role. |
role_expire_set_target | Callback for mapping. Here is where the actual mapping happens. |
role_expire_user_admin_role_submit | Form submit handler invoked by role_expire_form_user_admin_role_alter. Updates default duration in database. |
role_expire_user_admin_role_validate | Form validation handler invoked by role_expire_form_user_admin_role_alter. Ensure that the specified duration is a valid, relative, positive strtotime- compatible string. |
role_expire_user_cancel | Implements hook_user_cancel(). |
role_expire_user_delete | Implements hook_user_delete(). |
role_expire_user_insert | Implements hook_user_insert(). |
role_expire_user_load | Implements hook_user_load(). |
role_expire_user_role_delete | Implements hook_user_role_delete(). |
role_expire_user_update | Implements hook_user_update(). |
role_expire_user_view | Implements hook_user_view(). |
role_expire_views_api | Implements hook_views_api(). |
role_expire_write_record | API function; Insert or update a record in the database. |
_role_expire_get_role | Helper function; Get valid roles. |
_role_expire_validate_role_expires | Form validation handler for the role expiration on the user_profile_form(). |
_role_static_user_roles | Helper function; Store user roles for this page request. |