| 1 |
<?php
|
| 2 |
// $Id$
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @file
|
| 6 |
* Logs changes to user roles.
|
| 7 |
*/
|
| 8 |
|
| 9 |
define('SUPERUSER_RID', -1);
|
| 10 |
define('IN_ARRAY', TRUE);
|
| 11 |
define('NOT_IN_ARRAY', FALSE);
|
| 12 |
|
| 13 |
/**
|
| 14 |
* Implementation of hook_help().
|
| 15 |
*/
|
| 16 |
function role_watchdog_help($section) {
|
| 17 |
switch ($section) {
|
| 18 |
case 'admin/help#role_watchdog':
|
| 19 |
return
|
| 20 |
'<p>' . t('Role Watchdog has three modes of operation. The module will automatically start recording all role changes in the watchdog log. No further configuration is necessary for this functionality, the module will do this "out of the box".') . '</p>' .
|
| 21 |
'<p>' . t('Role Watchdog can optionally email members of selected Notify roles when selected Monitor roles are added or removed. This was specifically added to keep a closer eye on certain role changes, such as an Administrator role. At least one Monitor role and one Notify role must be selected for this functionality.') . '</p>' .
|
| 22 |
'<p>' . t('Role Watchdog can optionally log role changes in its own table and display the role history on each user\'s page. Users will need either "View role history" or "View own role history" access permissions to view the tab. This functionality was added for a more permanent audit of role history.') . '</p>';
|
| 23 |
}
|
| 24 |
}
|
| 25 |
|
| 26 |
/**
|
| 27 |
* Implementation of hook_perm()
|
| 28 |
*/
|
| 29 |
function role_watchdog_perm() {
|
| 30 |
return array('view role history', 'view own role history');
|
| 31 |
}
|
| 32 |
|
| 33 |
/**
|
| 34 |
* Implementation of hook_menu().
|
| 35 |
*/
|
| 36 |
function role_watchdog_menu($may_cache) {
|
| 37 |
$items = array();
|
| 38 |
|
| 39 |
if ($may_cache) {
|
| 40 |
$items[] = array(
|
| 41 |
'path' => 'admin/user/roles/role_watchdog',
|
| 42 |
'title' => 'Role watchdog',
|
| 43 |
'description' => t('Logs changes to user roles.'),
|
| 44 |
'callback' => 'drupal_get_form',
|
| 45 |
'callback arguments' => 'role_watchdog_admin_settings',
|
| 46 |
'type' => MENU_NORMAL_ITEM,
|
| 47 |
'access' => user_access('administer site configuration'), //do we *really* need yet another permission??
|
| 48 |
);
|
| 49 |
}
|
| 50 |
|
| 51 |
else {
|
| 52 |
if (arg(0) == 'user' && (int)arg(1) && variable_get('role_watchdog_history', 0)) {
|
| 53 |
if ($account = user_load(array('uid' => arg(1)))) {
|
| 54 |
|
| 55 |
$access = user_access('view role history');
|
| 56 |
if (!$access) {
|
| 57 |
global $user;
|
| 58 |
$access = ($user->uid == $account->uid && user_access('view own role history')) ? true: false;
|
| 59 |
}
|
| 60 |
|
| 61 |
$items[] = array(
|
| 62 |
'path' => 'user/' .arg(1). '/role_history',
|
| 63 |
'title' => t('Role History'),
|
| 64 |
'callback' => 'role_watchdog_history',
|
| 65 |
'callback arguments' => array($account),
|
| 66 |
'type' => MENU_LOCAL_TASK,
|
| 67 |
'access' => $access,
|
| 68 |
);
|
| 69 |
|
| 70 |
}
|
| 71 |
}
|
| 72 |
}
|
| 73 |
return $items;
|
| 74 |
}
|
| 75 |
|
| 76 |
/**
|
| 77 |
* Menu callback
|
| 78 |
*
|
| 79 |
* @return
|
| 80 |
* array of form content.
|
| 81 |
*/
|
| 82 |
function role_watchdog_admin_settings() {
|
| 83 |
$form = array();
|
| 84 |
|
| 85 |
$role_names = array();
|
| 86 |
$sql = "SELECT * FROM {role} r WHERE r.rid > 2 ORDER BY name";
|
| 87 |
$results = db_query($sql);
|
| 88 |
while ($result = db_fetch_object($results)) {
|
| 89 |
$role_names[$result->rid] = $result->name;
|
| 90 |
}
|
| 91 |
|
| 92 |
if (!count($role_names)) {
|
| 93 |
$form['watchdog'] = array(
|
| 94 |
'#type' => 'fieldset',
|
| 95 |
'#title' => t('No roles found'),
|
| 96 |
'#description' => t('Role Watchdog requires custom roles to function. !add', array('!add' => l(t('Add Roles'), 'admin/user/roles'))),
|
| 97 |
);
|
| 98 |
|
| 99 |
return $form;
|
| 100 |
}
|
| 101 |
|
| 102 |
$form['watchdog'] = array(
|
| 103 |
'#type' => 'fieldset',
|
| 104 |
'#title' => t('Watchdog Logging'),
|
| 105 |
'#description' => t('Role Watchdog automatically logs all role changes made. No further configuration is necessary for this functionality.'),
|
| 106 |
);
|
| 107 |
$form['watchdog']['description'] = array(
|
| 108 |
'#type' => 'checkbox',
|
| 109 |
'#title' => t('Enable Watchdog Logging'),
|
| 110 |
'#default_value' => TRUE,
|
| 111 |
'#attributes' => array('disabled' => 'disabled'),
|
| 112 |
);
|
| 113 |
|
| 114 |
$form['email'] = array(
|
| 115 |
'#type' => 'fieldset',
|
| 116 |
'#title' => t('Email Notification'),
|
| 117 |
'#description' => t('Role Watchdog can monitor one or more roles for changes and notify members of selected roles via email whenever a change occurs. At least one Monitor and one Notify role must be selected for this functionality.'),
|
| 118 |
);
|
| 119 |
$form['email']['role_watchdog_monitor_roles'] = array(
|
| 120 |
'#type' => 'select',
|
| 121 |
'#title' => t('Monitor for change'),
|
| 122 |
'#options' => $role_names,
|
| 123 |
'#default_value' => variable_get('role_watchdog_monitor_roles', NULL),
|
| 124 |
'#description' => t('Select roles to monitor for change.'),
|
| 125 |
'#multiple' => TRUE,
|
| 126 |
);
|
| 127 |
$form['email']['role_watchdog_notify_roles'] = array(
|
| 128 |
'#type' => 'select',
|
| 129 |
'#title' => t('Notify on change'),
|
| 130 |
'#options' => array(SUPERUSER_RID => 'Superuser (uid 1)') + $role_names,
|
| 131 |
'#default_value' => variable_get('role_watchdog_notify_roles', NULL),
|
| 132 |
'#description' => t('Select roles to notify on change.'),
|
| 133 |
'#multiple' => TRUE,
|
| 134 |
);
|
| 135 |
|
| 136 |
if (db_table_exists('role_watchdog')) {
|
| 137 |
$form['history'] = array(
|
| 138 |
'#type' => 'fieldset',
|
| 139 |
'#title' => t('Role History'),
|
| 140 |
'#description' => t('Role Watchdog can log role changes in its own table and display the role history on each user\'s page. Users will need either "View role history" or "View own role history" !access to view the tab.', array('!access' => l(t('access permissions'), 'admin/user/access', NULL, NULL, 'module-role_watchdog'))),
|
| 141 |
);
|
| 142 |
$form['history']['role_watchdog_history'] = array(
|
| 143 |
'#type' => 'checkbox',
|
| 144 |
'#title' => t('Enable Role History'),
|
| 145 |
'#default_value' => variable_get('role_watchdog_history', 0),
|
| 146 |
);
|
| 147 |
}
|
| 148 |
else {
|
| 149 |
drupal_set_message(t('Your database schema is out of date. Please run !update.php to access the module\'s latest features.', array('!update.php' => l('update.php', 'update.php'))), 'warning');
|
| 150 |
}
|
| 151 |
|
| 152 |
return system_settings_form($form);
|
| 153 |
}
|
| 154 |
|
| 155 |
/**
|
| 156 |
* Implementation of hook_user().
|
| 157 |
*
|
| 158 |
* Adds submit hook to monitor role changes.
|
| 159 |
*/
|
| 160 |
function role_watchdog_user($type, &$edit, &$account, $category = NULL) {
|
| 161 |
switch ($type) {
|
| 162 |
case 'update':
|
| 163 |
global $user;
|
| 164 |
if ($user->uid != $account->uid) {
|
| 165 |
if (isset($edit['roles'])) {
|
| 166 |
role_watchdog_user_save((isset($account->uid) ? $account->uid : FALSE), $edit, $account);
|
| 167 |
}
|
| 168 |
}
|
| 169 |
break;
|
| 170 |
|
| 171 |
case 'delete':
|
| 172 |
if (db_table_exists('role_watchdog')) {
|
| 173 |
db_query('DELETE FROM {role_watchdog} WHERE aid=%d', $account->uid);
|
| 174 |
db_query('UPDATE {role_watchdog} SET uid=0 WHERE uid=%d', $account->uid);
|
| 175 |
}
|
| 176 |
break;
|
| 177 |
}
|
| 178 |
}
|
| 179 |
|
| 180 |
/**
|
| 181 |
* Process role add/remove.
|
| 182 |
*/
|
| 183 |
function role_watchdog_user_save($uid, &$form, $account) {
|
| 184 |
$old_roles = array_keys($account->roles);
|
| 185 |
$new_roles = array_keys($form['roles']);
|
| 186 |
|
| 187 |
//is role added?
|
| 188 |
foreach ($new_roles as $rid) {
|
| 189 |
$count += _role_watchdog_add_role($rid, $old_roles, $account);
|
| 190 |
}
|
| 191 |
//is role removed?
|
| 192 |
foreach ($old_roles as $rid) {
|
| 193 |
$count += _role_watchdog_remove_role($rid, $new_roles, $account, NOT_IN_ARRAY);
|
| 194 |
}
|
| 195 |
_role_watchdog_set_message($count);
|
| 196 |
}
|
| 197 |
|
| 198 |
/**
|
| 199 |
* Internal function
|
| 200 |
*
|
| 201 |
* Handles addition of roles.
|
| 202 |
*/
|
| 203 |
function _role_watchdog_add_role($rid, $old_roles = array(), $account) {
|
| 204 |
if (!in_array($rid, $old_roles)) {
|
| 205 |
global $user;
|
| 206 |
$roles = user_roles();
|
| 207 |
$message = t('Role %role added to %account by %user', array('%user' => $user->name, '%role' => $roles[$rid], '%account' => $account->name));
|
| 208 |
|
| 209 |
watchdog('user', $message);
|
| 210 |
_role_watchdog_notification($rid, $message);
|
| 211 |
if (variable_get('role_watchdog_history', 0)) {
|
| 212 |
db_query('INSERT INTO {role_watchdog} (aid, rid, action, uid, stamp) VALUES (%d, %d, %d, %d, %d)', $account->uid, $rid, 1, $user->uid, time());
|
| 213 |
}
|
| 214 |
|
| 215 |
return 1;
|
| 216 |
}
|
| 217 |
return 0;
|
| 218 |
}
|
| 219 |
|
| 220 |
/**
|
| 221 |
* Internal function
|
| 222 |
*
|
| 223 |
* Handles removal of roles.
|
| 224 |
*/
|
| 225 |
function _role_watchdog_remove_role($rid, $old_roles = array(), $account, $in_array = TRUE) {
|
| 226 |
if ($rid > 2 && (in_array($rid, $old_roles) xor !$in_array)) {
|
| 227 |
global $user;
|
| 228 |
$roles = user_roles();
|
| 229 |
$message = t('Role %role removed from %account by %user', array('%user' => $user->name, '%role' => $roles[$rid], '%account' => $account->name));
|
| 230 |
|
| 231 |
watchdog('user', $message);
|
| 232 |
_role_watchdog_notification($rid, $message);
|
| 233 |
if (variable_get('role_watchdog_history', 0)) {
|
| 234 |
db_query('INSERT INTO {role_watchdog} (aid, rid, action, uid, stamp) VALUES (%d, %d, %d, %d, %d)', $account->uid, $rid, 0, $user->uid, time());
|
| 235 |
}
|
| 236 |
|
| 237 |
return 1;
|
| 238 |
}
|
| 239 |
return 0;
|
| 240 |
}
|
| 241 |
|
| 242 |
/**
|
| 243 |
* Internal function
|
| 244 |
*
|
| 245 |
* Handles user message for any changes.
|
| 246 |
*/
|
| 247 |
function _role_watchdog_set_message($count) {
|
| 248 |
if ($count) {
|
| 249 |
drupal_set_message(t('Role !change_has been logged.', array('!change_has' => format_plural($count, 'change has', 'changes have'))));
|
| 250 |
}
|
| 251 |
}
|
| 252 |
|
| 253 |
/**
|
| 254 |
* Internal function
|
| 255 |
*
|
| 256 |
* Handles notification of changes in selected roles.
|
| 257 |
*/
|
| 258 |
function _role_watchdog_notification($rid, $message) {
|
| 259 |
$monitor_roles = variable_get('role_watchdog_monitor_roles', NULL);
|
| 260 |
if (in_array($rid, (array)$monitor_roles)) {
|
| 261 |
$site_name = variable_get('site_name', 'Drupal');
|
| 262 |
$from = "$site_name <" . variable_get('site_mail', ini_get('sendmail_from')) . '>';
|
| 263 |
$subject = t('Role Watchdog notification on !site_name', array('!site_name' => $site_name));
|
| 264 |
$message = strip_tags($message);
|
| 265 |
|
| 266 |
foreach (_role_watchdog_get_notification_list() as $recipient) {
|
| 267 |
if (drupal_mail('role_watchdog_notification', $recipient, $subject, $message, $from)) {
|
| 268 |
watchdog('role_watchdog', t('Sent email to %recipient', array('%recipient' => $recipient)));
|
| 269 |
}
|
| 270 |
else {
|
| 271 |
watchdog('error', t('Unable to send email to %recipient', array('%recipient' => $recipient)));
|
| 272 |
}
|
| 273 |
}
|
| 274 |
}
|
| 275 |
}
|
| 276 |
|
| 277 |
/**
|
| 278 |
* Internal function
|
| 279 |
*
|
| 280 |
* Handles building notification list
|
| 281 |
*/
|
| 282 |
function _role_watchdog_get_notification_list() {
|
| 283 |
static $role_watchdog_notification_list;
|
| 284 |
|
| 285 |
if (!isset($role_watchdog_notification_list)) {
|
| 286 |
$role_watchdog_notification_list = array();
|
| 287 |
$notification_roles = variable_get('role_watchdog_notify_roles', NULL);
|
| 288 |
|
| 289 |
if (count($notification_roles)) {
|
| 290 |
$sql = "SELECT DISTINCT u.mail FROM {users} u INNER JOIN {users_roles} r ON u.uid = r.uid WHERE r.rid IN (%s)";
|
| 291 |
$result = db_query($sql, implode(',', $notification_roles));
|
| 292 |
|
| 293 |
while($account = db_fetch_object($result)) {
|
| 294 |
$role_watchdog_notification_list[] = $account->mail;
|
| 295 |
}
|
| 296 |
|
| 297 |
//special case: superuser
|
| 298 |
if (in_array(SUPERUSER_RID, (array)$notification_roles)) {
|
| 299 |
$sql = "SELECT u.mail FROM {users} u WHERE u.uid = %d";
|
| 300 |
$result = db_result(db_query($sql, 1));
|
| 301 |
if (!in_array($result, $role_watchdog_notification_list)) {
|
| 302 |
$role_watchdog_notification_list[] = $result;
|
| 303 |
}
|
| 304 |
}
|
| 305 |
}
|
| 306 |
}
|
| 307 |
|
| 308 |
return $role_watchdog_notification_list;
|
| 309 |
}
|
| 310 |
|
| 311 |
/**
|
| 312 |
* Display tab page from menu callback.
|
| 313 |
*
|
| 314 |
* @param $account
|
| 315 |
* User object.
|
| 316 |
*/
|
| 317 |
function role_watchdog_history(&$account) {
|
| 318 |
if (!variable_get('role_watchdog_history', 0)) drupal_access_denied();
|
| 319 |
drupal_set_title($account->name);
|
| 320 |
|
| 321 |
$roles = $account->roles;
|
| 322 |
unset($roles[2]);
|
| 323 |
$output = sizeof($roles) ? '<h3>' . t('Roles') . '</h3>' . implode(", ", array_keys(array_flip($roles))) : '';
|
| 324 |
|
| 325 |
$view_profile = user_access('access user profiles');
|
| 326 |
|
| 327 |
$sql = 'SELECT rw.action, rw.uid, rw.stamp, u.name, r.name AS role FROM {role_watchdog} rw INNER JOIN {users} u USING (uid) INNER JOIN {role} r USING (rid) WHERE rw.aid=%d ORDER BY rw.stamp DESC';
|
| 328 |
$result = db_query($sql, $account->uid);
|
| 329 |
while ($row = db_fetch_object($result)) {
|
| 330 |
$rows[] = array(
|
| 331 |
format_date($row->stamp),
|
| 332 |
$row->role,
|
| 333 |
$row->action ? t('added by') : t('removed by'),
|
| 334 |
$view_profile ? l($row->name, 'user/' . $row->uid) : $row->name,
|
| 335 |
);
|
| 336 |
}
|
| 337 |
|
| 338 |
if (sizeof($rows)) {
|
| 339 |
$header = array(
|
| 340 |
array('data' => 'Date', 'style' => 'width: 25%;'),
|
| 341 |
array('data' => 'Role', 'style' => 'width: 30%;'),
|
| 342 |
array('data' => 'Change', 'style' => 'width: 15%;'),
|
| 343 |
array('data' => 'User', 'style' => 'width: 40%;')
|
| 344 |
);
|
| 345 |
|
| 346 |
$output .= '<h3>' . t('Role History') . '</h3>' . theme('table', $header, $rows, array('style' => 'width: 99%;'));
|
| 347 |
}
|
| 348 |
|
| 349 |
$sql = 'SELECT rw.action, rw.aid, rw.stamp, u.name, r.name AS role FROM {role_watchdog} rw INNER JOIN {users} u ON (rw.aid = u.uid) INNER JOIN {role} r USING (rid) WHERE rw.uid=%d ORDER BY rw.stamp DESC';
|
| 350 |
$result = db_query($sql, $account->uid);
|
| 351 |
while ($row = db_fetch_object($result)) {
|
| 352 |
$rows2[] = array(
|
| 353 |
format_date($row->stamp),
|
| 354 |
$row->role,
|
| 355 |
$row->action ? t('added to') : t('removed from'),
|
| 356 |
$view_profile ? l($row->name, 'user/' . $row->aid) : $row->name,
|
| 357 |
);
|
| 358 |
}
|
| 359 |
|
| 360 |
if (sizeof($rows2)) {
|
| 361 |
$header = array(
|
| 362 |
array('data' => 'Date', 'style' => 'width: 25%;'),
|
| 363 |
array('data' => 'Role', 'style' => 'width: 30%;'),
|
| 364 |
array('data' => 'Change', 'style' => 'width: 15%;'),
|
| 365 |
array('data' => 'User', 'style' => 'width: 40%;')
|
| 366 |
);
|
| 367 |
|
| 368 |
$output .= '<h3>' . t('Role Changes Made') . '</h3>' . theme('table', $header, $rows2, array('style' => 'width: 99%;'));
|
| 369 |
}
|
| 370 |
|
| 371 |
if (!$output) $output = t('No Role History found.');
|
| 372 |
|
| 373 |
return $output;
|
| 374 |
}
|