user.admin.inc 37.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
<?php

/**
 * @file
 * Admin page callback file for the user module.
 */

function user_admin($callback_arg = '') {
  $op = isset($_POST['op']) ? $_POST['op'] : $callback_arg;

  switch ($op) {
    case t('Create new account'):
    case 'create':
14
      $build['user_register'] = drupal_get_form('user_register_form');
15 16
      break;
    default:
17
      if (!empty($_POST['accounts']) && isset($_POST['operation']) && ($_POST['operation'] == 'cancel')) {
18
        $build['user_multiple_cancel_confirm'] = drupal_get_form('user_multiple_cancel_confirm');
19 20
      }
      else {
21 22
        $build['user_filter_form'] = drupal_get_form('user_filter_form');
        $build['user_admin_account'] = drupal_get_form('user_admin_account');
23 24
      }
  }
25
  return $build;
26 27 28 29
}

/**
 * Form builder; Return form for user administration filters.
30
 *
31
 * @ingroup forms
32
 * @see user_filter_form_submit()
33 34
 */
function user_filter_form() {
35
  $session = isset($_SESSION['user_overview_filter']) ? $_SESSION['user_overview_filter'] : array();
36 37 38
  $filters = user_filters();

  $i = 0;
39 40 41
  $form['filters'] = array(
    '#type' => 'fieldset',
    '#title' => t('Show only users where'),
42
    '#theme' => 'exposed_filters__user',
43
  );
44 45
  foreach ($session as $filter) {
    list($type, $value) = $filter;
46 47 48 49 50 51 52 53 54
    if ($type == 'permission') {
      // Merge arrays of module permissions into one.
      // Slice past the first element '[any]' whose value is not an array.
      $options = call_user_func_array('array_merge', array_slice($filters[$type]['options'], 1));
      $value = $options[$value];
    }
    else {
      $value = $filters[$type]['options'][$value];
    }
55
    $t_args = array('%property' => $filters[$type]['title'], '%value' => $value);
56
    if ($i++) {
57
      $form['filters']['current'][] = array('#markup' => t('and where %property is %value', $t_args));
58 59
    }
    else {
60
      $form['filters']['current'][] = array('#markup' => t('%property is %value', $t_args));
61
    }
62 63
  }

64 65 66 67 68 69 70 71 72
  $form['filters']['status'] = array(
    '#type' => 'container',
    '#attributes' => array('class' => array('clearfix')),
    '#prefix' => ($i ? '<div class="additional-filters">' . t('and where') . '</div>' : ''),
  );
  $form['filters']['status']['filters'] = array(
    '#type' => 'container',
    '#attributes' => array('class' => array('filters')),
  );
73
  foreach ($filters as $key => $filter) {
74
    $form['filters']['status']['filters'][$key] = array(
75 76
      '#type' => 'select',
      '#options' => $filter['options'],
77 78
      '#title' => $filter['title'],
      '#default_value' => '[any]',
79
    );
80 81
  }

82
  $form['filters']['status']['actions'] = array(
83 84
    '#type' => 'actions',
    '#attributes' => array('class' => array('container-inline')),
85
  );
86
  $form['filters']['status']['actions']['submit'] = array(
87 88 89
    '#type' => 'submit',
    '#value' => (count($session) ? t('Refine') : t('Filter')),
  );
90
  if (count($session)) {
91
    $form['filters']['status']['actions']['undo'] = array(
92 93 94
      '#type' => 'submit',
      '#value' => t('Undo'),
    );
95
    $form['filters']['status']['actions']['reset'] = array(
96 97 98
      '#type' => 'submit',
      '#value' => t('Reset'),
    );
99 100
  }

101
  drupal_add_library('system', 'drupal.form');
102

103 104 105 106 107 108 109 110 111 112
  return $form;
}

/**
 * Process result from user administration filter form.
 */
function user_filter_form_submit($form, &$form_state) {
  $op = $form_state['values']['op'];
  $filters = user_filters();
  switch ($op) {
113 114 115 116 117 118 119 120 121 122 123
    case t('Filter'):
    case t('Refine'):
      // Apply every filter that has a choice selected other than 'any'.
      foreach ($filters as $filter => $options) {
        if (isset($form_state['values'][$filter]) && $form_state['values'][$filter] != '[any]') {
          // Merge an array of arrays into one if necessary.
          $options = ($filter == 'permission') ? form_options_flatten($filters[$filter]['options']) : $filters[$filter]['options'];
          // Only accept valid selections offered on the dropdown, block bad input.
          if (isset($options[$form_state['values'][$filter]])) {
            $_SESSION['user_overview_filter'][] = array($filter, $form_state['values'][$filter]);
          }
124 125 126 127 128 129 130
        }
      }
      break;
    case t('Undo'):
      array_pop($_SESSION['user_overview_filter']);
      break;
    case t('Reset'):
131
      $_SESSION['user_overview_filter'] = array();
132 133 134 135 136
      break;
    case t('Update'):
      return;
  }

137
  $form_state['redirect'] = 'admin/people';
138 139 140 141 142 143 144
  return;
}

/**
 * Form builder; User administration page.
 *
 * @ingroup forms
145 146
 * @see user_admin_account_validate()
 * @see user_admin_account_submit()
147 148 149 150
 */
function user_admin_account() {

  $header = array(
151 152 153 154 155 156
    'username' => array('data' => t('Username'), 'field' => 'u.name'),
    'status' => array('data' => t('Status'), 'field' => 'u.status'),
    'roles' => array('data' => t('Roles')),
    'member_for' => array('data' => t('Member for'), 'field' => 'u.created', 'sort' => 'desc'),
    'access' => array('data' => t('Last access'), 'field' => 'u.access'),
    'operations' => array('data' => t('Operations')),
157 158
  );

159
  $query = db_select('users', 'u');
160 161
  $query->condition('u.uid', 0, '<>');
  user_build_filter_query($query);
162

163
  $count_query = clone $query;
164
  $count_query->addExpression('COUNT(u.uid)');
165 166 167 168 169

  $query = $query->extend('PagerDefault')->extend('TableSort');
  $query
    ->fields('u', array('uid', 'name', 'status', 'created', 'access'))
    ->limit(50)
170
    ->orderByHeader($header)
171 172
    ->setCountQuery($count_query);
  $result = $query->execute();
173 174 175 176

  $form['options'] = array(
    '#type' => 'fieldset',
    '#title' => t('Update options'),
177
    '#attributes' => array('class' => array('container-inline')),
178 179 180 181 182 183 184
  );
  $options = array();
  foreach (module_invoke_all('user_operations') as $operation => $array) {
    $options[$operation] = $array['label'];
  }
  $form['options']['operation'] = array(
    '#type' => 'select',
185 186
    '#title' => t('Operation'),
    '#title_display' => 'invisible',
187 188 189
    '#options' => $options,
    '#default_value' => 'unblock',
  );
190
  $options = array();
191 192 193 194 195 196 197 198
  $form['options']['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Update'),
  );

  $destination = drupal_get_destination();

  $status = array(t('blocked'), t('active'));
199
  $roles = array_map('check_plain', user_roles(TRUE));
200
  $accounts = array();
201
  foreach ($result as $account) {
202
    $users_roles = array();
203 204
    $roles_result = db_query('SELECT rid FROM {users_roles} WHERE uid = :uid', array(':uid' => $account->uid));
    foreach ($roles_result as $user_role) {
205
      $users_roles[] = $roles[$user_role->rid];
206
    }
207
    asort($users_roles);
208

209
    $options[$account->uid] = array(
210
      'username' => theme('username', array('account' => $account)),
211
      'status' =>  $status[$account->status],
212
      'roles' => theme('item_list', array('items' => $users_roles)),
213 214
      'member_for' => format_interval(REQUEST_TIME - $account->created),
      'access' =>  $account->access ? t('@time ago', array('@time' => format_interval(REQUEST_TIME - $account->access))) : t('never'),
215
      'operations' => array('data' => array('#type' => 'link', '#title' => t('edit'), '#href' => "user/$account->uid/edit", '#options' => array('query' => $destination))),
216
    );
217
  }
218

219
  $form['accounts'] = array(
220 221 222 223
    '#type' => 'tableselect',
    '#header' => $header,
    '#options' => $options,
    '#empty' => t('No people available.'),
224
  );
225
  $form['pager'] = array('#markup' => theme('pager'));
226 227 228 229 230 231 232 233

  return $form;
}

/**
 * Submit the user administration update form.
 */
function user_admin_account_submit($form, &$form_state) {
234
  $operations = module_invoke_all('user_operations', $form, $form_state);
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
  $operation = $operations[$form_state['values']['operation']];
  // Filter out unchecked accounts.
  $accounts = array_filter($form_state['values']['accounts']);
  if ($function = $operation['callback']) {
    // Add in callback arguments if present.
    if (isset($operation['callback arguments'])) {
      $args = array_merge(array($accounts), $operation['callback arguments']);
    }
    else {
      $args = array($accounts);
    }
    call_user_func_array($function, $args);

    drupal_set_message(t('The update has been performed.'));
  }
}

function user_admin_account_validate($form, &$form_state) {
  $form_state['values']['accounts'] = array_filter($form_state['values']['accounts']);
  if (count($form_state['values']['accounts']) == 0) {
    form_set_error('', t('No users selected.'));
  }
}

/**
 * Form builder; Configure user settings for this site.
 *
 * @ingroup forms
263
 * @see system_settings_form()
264 265
 */
function user_admin_settings() {
266 267 268 269 270 271 272 273 274 275 276 277
  // Settings for anonymous users.
  $form['anonymous_settings'] = array(
    '#type' => 'fieldset',
    '#title' => t('Anonymous users'),
  );
  $form['anonymous_settings']['anonymous'] = array(
    '#type' => 'textfield',
    '#title' => t('Name'),
    '#default_value' => variable_get('anonymous', t('Anonymous')),
    '#description' => t('The name used to indicate anonymous users.'),
    '#required' => TRUE,
  );
278

279 280 281
  // Administrative role option.
  $form['admin_role'] = array(
    '#type' => 'fieldset',
282
    '#title' => t('Administrator role'),
283 284
  );

285
  // Do not allow users to set the anonymous or authenticated user roles as the
286 287
  // administrator role.
  $roles = user_roles();
288 289
  unset($roles[DRUPAL_ANONYMOUS_RID]);
  unset($roles[DRUPAL_AUTHENTICATED_RID]);
290 291 292 293 294 295 296 297 298 299
  $roles[0] = t('disabled');

  $form['admin_role']['user_admin_role'] = array(
    '#type' => 'select',
    '#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.'),
  );

300 301
  // User registration settings.
  $form['registration_cancellation'] = array(
302
    '#type' => 'fieldset',
303 304 305 306 307
    '#title' => t('Registration and cancellation'),
  );
  $form['registration_cancellation']['user_register'] = array(
    '#type' => 'radios',
    '#title' => t('Who can register accounts?'),
308
    '#default_value' => variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL),
309
    '#options' => array(
310 311 312
      USER_REGISTER_ADMINISTRATORS_ONLY => t('Administrators only'),
      USER_REGISTER_VISITORS => t('Visitors'),
      USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL => t('Visitors, but administrator approval is required'),
313 314 315 316 317 318
    )
  );
  $form['registration_cancellation']['user_email_verification'] = array(
    '#type' => 'checkbox',
    '#title' => t('Require e-mail verification when a visitor creates an account.'),
    '#default_value' => variable_get('user_email_verification', TRUE),
319
    '#description' => t('New users will be required to validate their e-mail address prior to logging into the site, and will be assigned a system-generated password. With this setting disabled, users will be logged in immediately upon registering, and may select their own passwords during registration.')
320
  );
321 322
  module_load_include('inc', 'user', 'user.pages');
  $form['registration_cancellation']['user_cancel_method'] = array(
323 324
    '#type' => 'item',
    '#title' => t('When cancelling a user account'),
325
    '#description' => t('Users with the %select-cancel-method or %administer-users <a href="@permissions-url">permissions</a> can override this default method.', array('%select-cancel-method' => t('Select method for cancelling account'), '%administer-users' => t('Administer users'), '@permissions-url' => url('admin/people/permissions'))),
326
  );
327 328
  $form['registration_cancellation']['user_cancel_method'] += user_cancel_methods();
  foreach (element_children($form['registration_cancellation']['user_cancel_method']) as $element) {
329 330
    // Remove all account cancellation methods that have #access defined, as
    // those cannot be configured as default method.
331 332
    if (isset($form['registration_cancellation']['user_cancel_method'][$element]['#access'])) {
      $form['registration_cancellation']['user_cancel_method'][$element]['#access'] = FALSE;
333 334 335
    }
    // Remove the description (only displayed on the confirmation form).
    else {
336
      unset($form['registration_cancellation']['user_cancel_method'][$element]['#description']);
337 338 339
    }
  }

340 341
  // Account settings.
  $form['personalization'] = array(
342
    '#type' => 'fieldset',
343 344 345 346 347 348 349 350 351
    '#title' => t('Personalization'),
  );
  $form['personalization']['user_signatures'] = array(
    '#type' => 'checkbox',
    '#title' => t('Enable signatures.'),
    '#default_value' => variable_get('user_signatures', 0),
  );
  // If picture support is enabled, check whether the picture directory exists.
  if (variable_get('user_pictures', 0)) {
352
    $picture_path =  file_default_scheme() . '://' . variable_get('user_picture_path', 'pictures');
353 354
    if (!file_prepare_directory($picture_path, FILE_CREATE_DIRECTORY)) {
      form_set_error('user_picture_path', t('The directory %directory does not exist or is not writable.', array('%directory' => $picture_path)));
355
      watchdog('file system', 'The directory %directory does not exist or is not writable.', array('%directory' => $picture_path), WATCHDOG_ERROR);
356
    }
357 358 359 360 361 362 363 364 365
  }
  $picture_support = variable_get('user_pictures', 0);
  $form['personalization']['user_pictures'] = array(
    '#type' => 'checkbox',
    '#title' => t('Enable user pictures.'),
    '#default_value' => $picture_support,
  );
  drupal_add_js(drupal_get_path('module', 'user') . '/user.js');
  $form['personalization']['pictures'] = array(
366 367 368 369 370 371 372
    '#type' => 'container',
    '#states' => array(
      // Hide the additional picture settings when user pictures are disabled.
      'invisible' => array(
        'input[name="user_pictures"]' => array('checked' => FALSE),
      ),
    ),
373 374 375 376 377 378 379
  );
  $form['personalization']['pictures']['user_picture_path'] = array(
    '#type' => 'textfield',
    '#title' => t('Picture directory'),
    '#default_value' => variable_get('user_picture_path', 'pictures'),
    '#size' => 30,
    '#maxlength' => 255,
380
    '#description' => t('Subdirectory in the file upload directory where pictures will be stored.'),
381 382 383 384 385 386 387 388 389
  );
  $form['personalization']['pictures']['user_picture_default'] = array(
    '#type' => 'textfield',
    '#title' => t('Default picture'),
    '#default_value' => variable_get('user_picture_default', ''),
    '#size' => 30,
    '#maxlength' => 255,
    '#description' => t('URL of picture to display for users with no custom picture selected. Leave blank for none.'),
  );
390 391 392
  if (module_exists('image')) {
    $form['personalization']['pictures']['settings']['user_picture_style'] = array(
      '#type' => 'select',
393
      '#title' => t('Picture display style'),
394 395
      '#options' => image_style_options(TRUE),
      '#default_value' => variable_get('user_picture_style', ''),
396
      '#description' => t('The style selected will be used on display, while the original image is retained. Styles may be configured in the <a href="!url">Image styles</a> administration area.', array('!url' => url('admin/config/media/image-styles'))),
397 398
    );
  }
399 400
  $form['personalization']['pictures']['user_picture_dimensions'] = array(
    '#type' => 'textfield',
401
    '#title' => t('Picture upload dimensions'),
402
    '#default_value' => variable_get('user_picture_dimensions', '85x85'),
403
    '#size' => 10,
404
    '#maxlength' => 10,
405
    '#field_suffix' => ' ' . t('pixels'),
406
    '#description' => t('Pictures larger than this will be scaled down to this size.'),
407 408 409
  );
  $form['personalization']['pictures']['user_picture_file_size'] = array(
    '#type' => 'textfield',
410
    '#title' => t('Picture upload file size'),
411
    '#default_value' => variable_get('user_picture_file_size', '30'),
412
    '#size' => 10,
413
    '#maxlength' => 10,
414
    '#field_suffix' => ' ' . t('KB'),
415
    '#description' => t('Maximum allowed file size for uploaded pictures. Upload size is normally limited only by the PHP maximum post and file upload settings, and images are automatically scaled down to the dimensions specified above.'),
416 417 418 419 420 421 422 423 424 425 426 427 428 429
  );
  $form['personalization']['pictures']['user_picture_guidelines'] = array(
    '#type' => 'textarea',
    '#title' => t('Picture guidelines'),
    '#default_value' => variable_get('user_picture_guidelines', ''),
    '#description' => t("This text is displayed at the picture upload form in addition to the default guidelines. It's useful for helping or instructing your users."),
  );

  $form['email_title'] = array(
    '#type' => 'item',
    '#title' => t('E-mails'),
  );
  $form['email'] = array(
    '#type' => 'vertical_tabs',
430 431 432
  );
  // These email tokens are shared for all settings, so just define
  // the list once to help ensure they stay in sync.
433
  $email_token_help = t('Available variables are: [site:name], [site:url], [user:name], [user:mail], [site:login-url], [site:url-brief], [user:edit-url], [user:one-time-login-url], [user:cancel-url].');
434

435
  $form['email_admin_created'] = array(
436
    '#type' => 'fieldset',
437
    '#title' => t('Welcome (new user created by administrator)'),
438
    '#collapsible' => TRUE,
439
    '#collapsed' => (variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) != USER_REGISTER_ADMINISTRATORS_ONLY),
440
    '#description' => t('Edit the welcome e-mail messages sent to new member accounts created by an administrator.') . ' ' . $email_token_help,
441
    '#group' => 'email',
442
  );
443
  $form['email_admin_created']['user_mail_register_admin_created_subject'] = array(
444 445
    '#type' => 'textfield',
    '#title' => t('Subject'),
446
    '#default_value' => _user_mail_text('register_admin_created_subject', NULL, array(), FALSE),
447 448
    '#maxlength' => 180,
  );
449
  $form['email_admin_created']['user_mail_register_admin_created_body'] = array(
450 451
    '#type' => 'textarea',
    '#title' => t('Body'),
452
    '#default_value' => _user_mail_text('register_admin_created_body', NULL, array(), FALSE),
453 454 455
    '#rows' => 15,
  );

456
  $form['email_pending_approval'] = array(
457
    '#type' => 'fieldset',
458
    '#title' => t('Welcome (awaiting approval)'),
459
    '#collapsible' => TRUE,
460
    '#collapsed' => (variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) != USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL),
461
    '#description' => t('Edit the welcome e-mail messages sent to new members upon registering, when administrative approval is required.') . ' ' . $email_token_help,
462
    '#group' => 'email',
463
  );
464
  $form['email_pending_approval']['user_mail_register_pending_approval_subject'] = array(
465 466
    '#type' => 'textfield',
    '#title' => t('Subject'),
467
    '#default_value' => _user_mail_text('register_pending_approval_subject', NULL, array(), FALSE),
468 469
    '#maxlength' => 180,
  );
470
  $form['email_pending_approval']['user_mail_register_pending_approval_body'] = array(
471 472
    '#type' => 'textarea',
    '#title' => t('Body'),
473
    '#default_value' => _user_mail_text('register_pending_approval_body', NULL, array(), FALSE),
474
    '#rows' => 8,
475 476
  );

477
  $form['email_no_approval_required'] = array(
478
    '#type' => 'fieldset',
479
    '#title' => t('Welcome (no approval required)'),
480
    '#collapsible' => TRUE,
481
    '#collapsed' => (variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) != USER_REGISTER_VISITORS),
482
    '#description' => t('Edit the welcome e-mail messages sent to new members upon registering, when no administrator approval is required.') . ' ' . $email_token_help,
483
    '#group' => 'email',
484
  );
485
  $form['email_no_approval_required']['user_mail_register_no_approval_required_subject'] = array(
486 487
    '#type' => 'textfield',
    '#title' => t('Subject'),
488
    '#default_value' => _user_mail_text('register_no_approval_required_subject', NULL, array(), FALSE),
489 490
    '#maxlength' => 180,
  );
491
  $form['email_no_approval_required']['user_mail_register_no_approval_required_body'] = array(
492 493
    '#type' => 'textarea',
    '#title' => t('Body'),
494
    '#default_value' => _user_mail_text('register_no_approval_required_body', NULL, array(), FALSE),
495
    '#rows' => 15,
496
  );
497

498
  $form['email_password_reset'] = array(
499
    '#type' => 'fieldset',
500
    '#title' => t('Password recovery'),
501 502
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
503
    '#description' => t('Edit the e-mail messages sent to users who request a new password.') . ' ' . $email_token_help,
504 505
    '#group' => 'email',
    '#weight' => 10,
506
  );
507
  $form['email_password_reset']['user_mail_password_reset_subject'] = array(
508 509
    '#type' => 'textfield',
    '#title' => t('Subject'),
510
    '#default_value' => _user_mail_text('password_reset_subject', NULL, array(), FALSE),
511 512
    '#maxlength' => 180,
  );
513
  $form['email_password_reset']['user_mail_password_reset_body'] = array(
514 515
    '#type' => 'textarea',
    '#title' => t('Body'),
516
    '#default_value' => _user_mail_text('password_reset_body', NULL, array(), FALSE),
517 518 519
    '#rows' => 12,
  );

520
  $form['email_activated'] = array(
521
    '#type' => 'fieldset',
522
    '#title' => t('Account activation'),
523 524
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
525
    '#description' => t('Enable and edit e-mail messages sent to users upon account activation (when an administrator activates an account of a user who has already registered, on a site where administrative approval is required).') . ' ' . $email_token_help,
526
    '#group' => 'email',
527
  );
528
  $form['email_activated']['user_mail_status_activated_notify'] = array(
529 530 531 532
    '#type' => 'checkbox',
    '#title' => t('Notify user when account is activated.'),
    '#default_value' => variable_get('user_mail_status_activated_notify', TRUE),
  );
533 534 535 536 537 538 539 540 541 542
  $form['email_activated']['settings'] = array(
    '#type' => 'container',
    '#states' => array(
      // Hide the additional settings when this email is disabled.
      'invisible' => array(
        'input[name="user_mail_status_activated_notify"]' => array('checked' => FALSE),
      ),
    ),
  );
  $form['email_activated']['settings']['user_mail_status_activated_subject'] = array(
543 544
    '#type' => 'textfield',
    '#title' => t('Subject'),
545
    '#default_value' => _user_mail_text('status_activated_subject', NULL, array(), FALSE),
546 547
    '#maxlength' => 180,
  );
548
  $form['email_activated']['settings']['user_mail_status_activated_body'] = array(
549 550
    '#type' => 'textarea',
    '#title' => t('Body'),
551
    '#default_value' => _user_mail_text('status_activated_body', NULL, array(), FALSE),
552 553 554
    '#rows' => 15,
  );

555
  $form['email_blocked'] = array(
556
    '#type' => 'fieldset',
557
    '#title' => t('Account blocked'),
558 559
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
560
    '#description' => t('Enable and edit e-mail messages sent to users when their accounts are blocked.') . ' ' . $email_token_help,
561
    '#group' => 'email',
562
  );
563
  $form['email_blocked']['user_mail_status_blocked_notify'] = array(
564 565 566 567
    '#type' => 'checkbox',
    '#title' => t('Notify user when account is blocked.'),
    '#default_value' => variable_get('user_mail_status_blocked_notify', FALSE),
  );
568 569 570 571 572 573 574 575 576 577
  $form['email_blocked']['settings'] = array(
    '#type' => 'container',
    '#states' => array(
      // Hide the additional settings when the blocked email is disabled.
      'invisible' => array(
        'input[name="user_mail_status_blocked_notify"]' => array('checked' => FALSE),
      ),
    ),
  );
  $form['email_blocked']['settings']['user_mail_status_blocked_subject'] = array(
578 579
    '#type' => 'textfield',
    '#title' => t('Subject'),
580
    '#default_value' => _user_mail_text('status_blocked_subject', NULL, array(), FALSE),
581 582
    '#maxlength' => 180,
  );
583
  $form['email_blocked']['settings']['user_mail_status_blocked_body'] = array(
584 585
    '#type' => 'textarea',
    '#title' => t('Body'),
586
    '#default_value' => _user_mail_text('status_blocked_body', NULL, array(), FALSE),
587 588 589
    '#rows' => 3,
  );

590
  $form['email_cancel_confirm'] = array(
591
    '#type' => 'fieldset',
592
    '#title' => t('Account cancellation confirmation'),
593 594
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
595
    '#description' => t('Edit the e-mail messages sent to users when they attempt to cancel their accounts.') . ' ' . $email_token_help,
596
    '#group' => 'email',
597
  );
598
  $form['email_cancel_confirm']['user_mail_cancel_confirm_subject'] = array(
599 600
    '#type' => 'textfield',
    '#title' => t('Subject'),
601
    '#default_value' => _user_mail_text('cancel_confirm_subject', NULL, array(), FALSE),
602 603
    '#maxlength' => 180,
  );
604
  $form['email_cancel_confirm']['user_mail_cancel_confirm_body'] = array(
605 606
    '#type' => 'textarea',
    '#title' => t('Body'),
607
    '#default_value' => _user_mail_text('cancel_confirm_body', NULL, array(), FALSE),
608 609 610
    '#rows' => 3,
  );

611
  $form['email_canceled'] = array(
612
    '#type' => 'fieldset',
613
    '#title' => t('Account canceled'),
614 615
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
616
    '#description' => t('Enable and edit e-mail messages sent to users when their accounts are canceled.') . ' ' . $email_token_help,
617
    '#group' => 'email',
618
  );
619
  $form['email_canceled']['user_mail_status_canceled_notify'] = array(
620
    '#type' => 'checkbox',
621 622
    '#title' => t('Notify user when account is canceled.'),
    '#default_value' => variable_get('user_mail_status_canceled_notify', FALSE),
623
  );
624 625 626
  $form['email_canceled']['settings'] = array(
    '#type' => 'container',
    '#states' => array(
627
      // Hide the settings when the cancel notify checkbox is disabled.
628 629 630 631 632 633
      'invisible' => array(
        'input[name="user_mail_status_canceled_notify"]' => array('checked' => FALSE),
      ),
    ),
  );
  $form['email_canceled']['settings']['user_mail_status_canceled_subject'] = array(
634 635
    '#type' => 'textfield',
    '#title' => t('Subject'),
636
    '#default_value' => _user_mail_text('status_canceled_subject', NULL, array(), FALSE),
637 638
    '#maxlength' => 180,
  );
639
  $form['email_canceled']['settings']['user_mail_status_canceled_body'] = array(
640 641
    '#type' => 'textarea',
    '#title' => t('Body'),
642
    '#default_value' => _user_mail_text('status_canceled_body', NULL, array(), FALSE),
643 644 645
    '#rows' => 3,
  );

646
  return system_settings_form($form);
647 648 649 650
}

/**
 * Menu callback: administer permissions.
651
 *
652
 * @ingroup forms
653 654
 * @see user_admin_permissions_submit()
 * @see theme_user_admin_permissions()
655
 */
656
function user_admin_permissions($form, $form_state, $rid = NULL) {
657

658 659
  // Retrieve role names for columns.
  $role_names = user_roles();
660
  if (is_numeric($rid)) {
661
    $role_names = array($rid => $role_names[$rid]);
662
  }
663 664
  // Fetch permissions for all roles or the one selected role.
  $role_permissions = user_role_permissions($role_names);
665

666 667 668 669 670
  // Store $role_names for use when saving the data.
  $form['role_names'] = array(
    '#type' => 'value',
    '#value' => $role_names,
  );
671 672
  // Render role/permission overview:
  $options = array();
673
  $module_info = system_get_info('module');
674
  $hide_descriptions = system_admin_compact_mode();
675 676 677 678

  // Get a list of all the modules implementing a hook_permission() and sort by
  // display name.
  $modules = array();
679
  foreach (module_implements('permission') as $module) {
680
    $modules[$module] = $module_info[$module]['name'];
681
  }
682
  asort($modules);
683

684
  foreach ($modules as $module => $display_name) {
685
    if ($permissions = module_invoke($module, 'permission')) {
686
      $form['permission'][] = array(
687
        '#markup' => $module_info[$module]['name'],
688
        '#id' => $module,
689
      );
690
      foreach ($permissions as $perm => $perm_item) {
691 692 693 694 695 696
        // Fill in default values for the permission.
        $perm_item += array(
          'description' => '',
          'restrict access' => FALSE,
          'warning' => !empty($perm_item['restrict access']) ? t('Warning: Give to trusted roles only; this permission has security implications.') : '',
        );
697
        $options[$perm] = '';
698 699
        $form['permission'][$perm] = array(
          '#type' => 'item',
700
          '#markup' => $perm_item['title'],
701
          '#description' => theme('user_permission_description', array('permission_item' => $perm_item, 'hide' => $hide_descriptions)),
702
        );
703 704
        foreach ($role_names as $rid => $name) {
          // Builds arrays for checked boxes for each role
705
          if (isset($role_permissions[$rid][$perm])) {
706 707 708 709 710 711 712 713 714
            $status[$rid][] = $perm;
          }
        }
      }
    }
  }

  // Have to build checkboxes here after checkbox arrays are built
  foreach ($role_names as $rid => $name) {
715 716 717 718 719 720
    $form['checkboxes'][$rid] = array(
      '#type' => 'checkboxes',
      '#options' => $options,
      '#default_value' => isset($status[$rid]) ? $status[$rid] : array(),
      '#attributes' => array('class' => array('rid-' . $rid)),
    );
721
    $form['role_names'][$rid] = array('#markup' => check_plain($name), '#tree' => TRUE);
722
  }
723

724
  $form['actions'] = array('#type' => 'actions');
725
  $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save permissions'));
726

727
  $form['#attached']['js'][] = drupal_get_path('module', 'user') . '/user.permissions.js';
728

729 730 731
  return $form;
}

732 733 734
/**
 * Save permissions selected on the administer permissions page.
 *
735
 * @see user_admin_permissions()
736
 */
737
function user_admin_permissions_submit($form, &$form_state) {
738
  foreach ($form_state['values']['role_names'] as $rid => $name) {
739
    user_role_change_permissions($rid, $form_state['values'][$rid]);
740 741 742 743
  }

  drupal_set_message(t('The changes have been saved.'));

744
  // Clear the cached pages and blocks.
745 746 747 748
  cache_clear_all();
}

/**
749 750 751 752 753
 * Returns HTML for the administer permissions page.
 *
 * @param $variables
 *   An associative array containing:
 *   - form: A render element representing the form.
754 755 756
 *
 * @ingroup themeable
 */
757 758 759
function theme_user_admin_permissions($variables) {
  $form = $variables['form'];

760
  $roles = user_roles();
761
  foreach (element_children($form['permission']) as $key) {
762 763 764
    $row = array();
    // Module name
    if (is_numeric($key)) {
765
      $row[] = array('data' => drupal_render($form['permission'][$key]), 'class' => array('module'), 'id' => 'module-' . $form['permission'][$key]['#id'], 'colspan' => count($form['role_names']['#value']) + 1);
766 767 768 769 770
    }
    else {
      // Permission row.
      $row[] = array(
        'data' => drupal_render($form['permission'][$key]),
771
        'class' => array('permission'),
772 773
      );
      foreach (element_children($form['checkboxes']) as $rid) {
774
        $form['checkboxes'][$rid][$key]['#title'] = $roles[$rid] . ': ' . $form['permission'][$key]['#markup'];
775 776
        $form['checkboxes'][$rid][$key]['#title_display'] = 'invisible';
        $row[] = array('data' => drupal_render($form['checkboxes'][$rid][$key]), 'class' => array('checkbox'));
777 778
      }
    }
779
    $rows[] = $row;
780 781 782
  }
  $header[] = (t('Permission'));
  foreach (element_children($form['role_names']) as $rid) {
783
    $header[] = array('data' => drupal_render($form['role_names'][$rid]), 'class' => array('checkbox'));
784
  }
785
  $output = theme('system_compact_link');
786
  $output .= theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'permissions')));
787
  $output .= drupal_render_children($form);
788 789 790
  return $output;
}

791
/**
792
 * Returns HTML for an individual permission description.
793 794 795 796 797 798 799 800 801 802 803 804 805 806 807