$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();
}
/**
* 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();
}
/**
* 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) {
$result = db_query("SELECT duration FROM {role_expire_length} WHERE rid = :rid", array(':rid' => $rid))->fetchField();
return (!empty($result)) ? $result : '';
}
/**
* 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)) {
$result = db_update('role_expire_length')
->fields(array('duration' => check_plain($duration),))
->condition('rid', $rid)
->execute();
if (!$result) {
$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;
}
/*******************************************************************************
* Hook implementations
******************************************************************************/
/**
* Implements hook_views_api().
*/
function role_expire_views_api() {
// We can't just return "what is the currently installed views API version!
// We have to specify which version of the API we designed this implementation
// around.
// return array("api" => views_api_version());
return array('api' => '3.0');
}
/**
* 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) {
$form = array_merge_recursive($form, role_expire_add_expiration_input());
}
/**
* Implements hook_form_FORM-ID_alter().
*/
function role_expire_form_user_profile_form_alter(&$form, $form_state) {
$form = array_merge_recursive($form, role_expire_add_expiration_input($form['#user']));
}
/**
* 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', 'Role expiry default duration must be a strtotime-compatible string.');
} // invalid format
elseif ($timestamp < $now) {
form_set_error('role_expire', 'Role expiry default duration must be a future strtotime-compatible string.');
} // in the past
elseif ($timestamp == $timestamp2) {
// This is an absolute (or special) timestamp. That's not allowed.
form_set_error('role_expire', 'Role expiry default duration must be a relative 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 ($form_state['values']['op'] == t('Delete role')) {
role_expire_delete_default_duration($form_state['values']['rid']);
}
elseif ($form_state['values']['op'] == t('Save role')) {
// If the form doesn't specify a default duration, then delete default duration.
// Otherwise, set the default duration to what's specified.
$new_default_duration = $form_state['values']['role_expire'];
if (is_numeric($new_default_duration) && $new_default_duration > 0) {
role_expire_set_default_duration($form_state['values']['rid'], $form_state['values']['role_expire']);
drupal_set_message('New default role expiration set.');
}
else {
role_expire_delete_default_duration($form_state['values']['rid']);
}
}
}
/**
* 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'))) {
// This adds default expiration to any new roles that have been given to the user.
$new_roles = array_keys($edit['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);
}
}
}
/**
* 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_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)) {
$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)
);
}
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 element that accepts the role expiration time.
*
* @param $account
* The user object.
* @return
* Form element.
*/
function role_expire_add_expiration_input($account = NULL) {
$form = array();
if (user_access('administer users') || user_access('administer role expire')) {
drupal_add_js(drupal_get_path('module', 'role_expire') . '/role_expire.js');
$form['roles']['#attributes'] = array('class' => array('role-expire-roles'));
foreach (_role_expire_get_role() as $rid => $role) {
if (is_object($account) and array_key_exists('uid', $account)) {
$expiry_timestamp = role_expire_get_user_role_expiry_time($account->uid, $rid);
}
else {
$expiry_timestamp = '';
}
$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: yyyy-mm-dd hh:mm:ss or use relative time i.e. 1 day, 2 months, 1 year, 3 years.")
);
}
$form['#validate'][] = '_role_expire_validate_role_expires';
}
return $form;
}
/*******************************************************************************
* 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));
}
}
}