1<?php
2
3/**
4 * @file
5 * Admin page callback file for the user module.
6 */
7
8/**
9 * Page callback: Generates the appropriate user administration form.
10 *
11 * This function generates the user registration, multiple user cancellation,
12 * or filtered user list admin form, depending on the argument and the POST
13 * form values.
14 *
15 * @param string $callback_arg
16 *   (optional) Indicates which form to build. Defaults to '', which will
17 *   trigger the user filter form. If the POST value 'op' is present, this
18 *   function uses that value as the callback argument.
19 *
20 * @return string
21 *   A renderable form array for the respective request.
22 */
23function user_admin($callback_arg = '') {
24  $op = isset($_POST['op']) ? $_POST['op'] : $callback_arg;
25
26  switch ($op) {
27    case t('Create new account'):
28    case 'create':
29      $build['user_register'] = drupal_get_form('user_register_form');
30      break;
31    default:
32      if (!empty($_POST['accounts']) && isset($_POST['operation']) && ($_POST['operation'] == 'cancel')) {
33        $build['user_multiple_cancel_confirm'] = drupal_get_form('user_multiple_cancel_confirm');
34      }
35      else {
36        $build['user_filter_form'] = drupal_get_form('user_filter_form');
37        $build['user_admin_account'] = drupal_get_form('user_admin_account');
38      }
39  }
40  return $build;
41}
42
43/**
44 * Form builder; Return form for user administration filters.
45 *
46 * @ingroup forms
47 * @see user_filter_form_submit()
48 */
49function user_filter_form() {
50  $session = isset($_SESSION['user_overview_filter']) ? $_SESSION['user_overview_filter'] : array();
51  $filters = user_filters();
52
53  $i = 0;
54  $form['filters'] = array(
55    '#type' => 'fieldset',
56    '#title' => t('Show only users where'),
57    '#theme' => 'exposed_filters__user',
58  );
59  foreach ($session as $filter) {
60    list($type, $value) = $filter;
61    if ($type == 'permission') {
62      // Merge arrays of module permissions into one.
63      // Slice past the first element '[any]' whose value is not an array.
64      $options = call_user_func_array('array_merge', array_values(array_slice($filters[$type]['options'], 1)));
65      $value = $options[$value];
66    }
67    else {
68      $value = $filters[$type]['options'][$value];
69    }
70    $t_args = array('%property' => $filters[$type]['title'], '%value' => $value);
71    if ($i++) {
72      $form['filters']['current'][] = array('#markup' => t('and where %property is %value', $t_args));
73    }
74    else {
75      $form['filters']['current'][] = array('#markup' => t('%property is %value', $t_args));
76    }
77  }
78
79  $form['filters']['status'] = array(
80    '#type' => 'container',
81    '#attributes' => array('class' => array('clearfix')),
82    '#prefix' => ($i ? '<div class="additional-filters">' . t('and where') . '</div>' : ''),
83  );
84  $form['filters']['status']['filters'] = array(
85    '#type' => 'container',
86    '#attributes' => array('class' => array('filters')),
87  );
88  foreach ($filters as $key => $filter) {
89    $form['filters']['status']['filters'][$key] = array(
90      '#type' => 'select',
91      '#options' => $filter['options'],
92      '#title' => $filter['title'],
93      '#default_value' => '[any]',
94    );
95  }
96
97  $form['filters']['status']['actions'] = array(
98    '#type' => 'actions',
99    '#attributes' => array('class' => array('container-inline')),
100  );
101  $form['filters']['status']['actions']['submit'] = array(
102    '#type' => 'submit',
103    '#value' => (count($session) ? t('Refine') : t('Filter')),
104  );
105  if (count($session)) {
106    $form['filters']['status']['actions']['undo'] = array(
107      '#type' => 'submit',
108      '#value' => t('Undo'),
109    );
110    $form['filters']['status']['actions']['reset'] = array(
111      '#type' => 'submit',
112      '#value' => t('Reset'),
113    );
114  }
115
116  drupal_add_library('system', 'drupal.form');
117
118  return $form;
119}
120
121/**
122 * Process result from user administration filter form.
123 */
124function user_filter_form_submit($form, &$form_state) {
125  $op = $form_state['values']['op'];
126  $filters = user_filters();
127  switch ($op) {
128    case t('Filter'):
129    case t('Refine'):
130      // Apply every filter that has a choice selected other than 'any'.
131      foreach ($filters as $filter => $options) {
132        if (isset($form_state['values'][$filter]) && $form_state['values'][$filter] != '[any]') {
133          // Merge an array of arrays into one if necessary.
134          $options = ($filter == 'permission') ? form_options_flatten($filters[$filter]['options']) : $filters[$filter]['options'];
135          // Only accept valid selections offered on the dropdown, block bad input.
136          if (isset($options[$form_state['values'][$filter]])) {
137            $_SESSION['user_overview_filter'][] = array($filter, $form_state['values'][$filter]);
138          }
139        }
140      }
141      break;
142    case t('Undo'):
143      array_pop($_SESSION['user_overview_filter']);
144      break;
145    case t('Reset'):
146      $_SESSION['user_overview_filter'] = array();
147      break;
148    case t('Update'):
149      return;
150  }
151
152  $form_state['redirect'] = 'admin/people';
153  return;
154}
155
156/**
157 * Form builder; User administration page.
158 *
159 * @ingroup forms
160 * @see user_admin_account_validate()
161 * @see user_admin_account_submit()
162 */
163function user_admin_account() {
164
165  $header = array(
166    'username' => array('data' => t('Username'), 'field' => 'u.name'),
167    'status' => array('data' => t('Status'), 'field' => 'u.status'),
168    'roles' => array('data' => t('Roles')),
169    'member_for' => array('data' => t('Member for'), 'field' => 'u.created', 'sort' => 'desc'),
170    'access' => array('data' => t('Last access'), 'field' => 'u.access'),
171    'operations' => array('data' => t('Operations')),
172  );
173
174  $query = db_select('users', 'u');
175  $query->condition('u.uid', 0, '<>');
176  user_build_filter_query($query);
177
178  $count_query = clone $query;
179  $count_query->addExpression('COUNT(u.uid)');
180
181  $query = $query->extend('PagerDefault')->extend('TableSort');
182  $query
183    ->fields('u', array('uid', 'name', 'status', 'created', 'access'))
184    ->limit(50)
185    ->orderByHeader($header)
186    ->setCountQuery($count_query);
187  $result = $query->execute();
188
189  $form['options'] = array(
190    '#type' => 'fieldset',
191    '#title' => t('Update options'),
192    '#attributes' => array('class' => array('container-inline')),
193  );
194  $options = array();
195  foreach (module_invoke_all('user_operations') as $operation => $array) {
196    $options[$operation] = $array['label'];
197  }
198  $form['options']['operation'] = array(
199    '#type' => 'select',
200    '#title' => t('Operation'),
201    '#title_display' => 'invisible',
202    '#options' => $options,
203    '#default_value' => 'unblock',
204  );
205  $options = array();
206  $form['options']['submit'] = array(
207    '#type' => 'submit',
208    '#value' => t('Update'),
209  );
210
211  $destination = drupal_get_destination();
212
213  $status = array(t('blocked'), t('active'));
214  $roles = array_map('check_plain', user_roles(TRUE));
215  $accounts = array();
216  foreach ($result as $account) {
217    $users_roles = array();
218    $roles_result = db_query('SELECT rid FROM {users_roles} WHERE uid = :uid', array(':uid' => $account->uid));
219    foreach ($roles_result as $user_role) {
220      $users_roles[] = $roles[$user_role->rid];
221    }
222    asort($users_roles);
223
224    $options[$account->uid] = array(
225      'username' => theme('username', array('account' => $account)),
226      'status' =>  $status[$account->status],
227      'roles' => theme('item_list', array('items' => $users_roles)),
228      'member_for' => format_interval(REQUEST_TIME - $account->created),
229      'access' =>  $account->access ? t('@time ago', array('@time' => format_interval(REQUEST_TIME - $account->access))) : t('never'),
230      'operations' => array('data' => array('#type' => 'link', '#title' => t('edit'), '#href' => "user/$account->uid/edit", '#options' => array('query' => $destination))),
231    );
232  }
233
234  $form['accounts'] = array(
235    '#type' => 'tableselect',
236    '#header' => $header,
237    '#options' => $options,
238    '#empty' => t('No people available.'),
239  );
240  $form['pager'] = array('#markup' => theme('pager'));
241
242  return $form;
243}
244
245/**
246 * Submit the user administration update form.
247 */
248function user_admin_account_submit($form, &$form_state) {
249  $operations = module_invoke_all('user_operations', $form, $form_state);
250  $operation = $operations[$form_state['values']['operation']];
251  // Filter out unchecked accounts.
252  $accounts = array_filter($form_state['values']['accounts']);
253  if ($function = $operation['callback']) {
254    // Add in callback arguments if present.
255    if (isset($operation['callback arguments'])) {
256      $args = array_merge(array($accounts), $operation['callback arguments']);
257    }
258    else {
259      $args = array($accounts);
260    }
261    call_user_func_array($function, $args);
262
263    drupal_set_message(t('The update has been performed.'));
264  }
265}
266
267function user_admin_account_validate($form, &$form_state) {
268  $form_state['values']['accounts'] = array_filter($form_state['values']['accounts']);
269  if (count($form_state['values']['accounts']) == 0) {
270    form_set_error('', t('No users selected.'));
271  }
272}
273
274/**
275 * Form builder; Configure user settings for this site.
276 *
277 * @ingroup forms
278 * @see system_settings_form()
279 */
280function user_admin_settings() {
281  // Settings for anonymous users.
282  $form['anonymous_settings'] = array(
283    '#type' => 'fieldset',
284    '#title' => t('Anonymous users'),
285  );
286  $form['anonymous_settings']['anonymous'] = array(
287    '#type' => 'textfield',
288    '#title' => t('Name'),
289    '#default_value' => variable_get('anonymous', t('Anonymous')),
290    '#description' => t('The name used to indicate anonymous users.'),
291    '#required' => TRUE,
292  );
293
294  // Administrative role option.
295  $form['admin_role'] = array(
296    '#type' => 'fieldset',
297    '#title' => t('Administrator role'),
298  );
299
300  // Do not allow users to set the anonymous or authenticated user roles as the
301  // administrator role.
302  $roles = user_roles();
303  unset($roles[DRUPAL_ANONYMOUS_RID]);
304  unset($roles[DRUPAL_AUTHENTICATED_RID]);
305  $roles[0] = t('disabled');
306
307  $form['admin_role']['user_admin_role'] = array(
308    '#type' => 'select',
309    '#title' => t('Administrator role'),
310    '#default_value' => variable_get('user_admin_role', 0),
311    '#options' => $roles,
312    '#description' => t('This role will be automatically assigned new permissions whenever a module is enabled. Changing this setting will not affect existing permissions.'),
313  );
314
315  // User registration settings.
316  $form['registration_cancellation'] = array(
317    '#type' => 'fieldset',
318    '#title' => t('Registration and cancellation'),
319  );
320  $form['registration_cancellation']['user_register'] = array(
321    '#type' => 'radios',
322    '#title' => t('Who can register accounts?'),
323    '#default_value' => variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL),
324    '#options' => array(
325      USER_REGISTER_ADMINISTRATORS_ONLY => t('Administrators only'),
326      USER_REGISTER_VISITORS => t('Visitors'),
327      USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL => t('Visitors, but administrator approval is required'),
328    )
329  );
330  $form['registration_cancellation']['user_email_verification'] = array(
331    '#type' => 'checkbox',
332    '#title' => t('Require e-mail verification when a visitor creates an account.'),
333    '#default_value' => variable_get('user_email_verification', TRUE),
334    '#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.')
335  );
336  module_load_include('inc', 'user', 'user.pages');
337  $form['registration_cancellation']['user_cancel_method'] = array(
338    '#type' => 'item',
339    '#title' => t('When cancelling a user account'),
340    '#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'))),
341  );
342  $form['registration_cancellation']['user_cancel_method'] += user_cancel_methods();
343  foreach (element_children($form['registration_cancellation']['user_cancel_method']) as $element) {
344    // Remove all account cancellation methods that have #access defined, as
345    // those cannot be configured as default method.
346    if (isset($form['registration_cancellation']['user_cancel_method'][$element]['#access'])) {
347      $form['registration_cancellation']['user_cancel_method'][$element]['#access'] = FALSE;
348    }
349    // Remove the description (only displayed on the confirmation form).
350    else {
351      unset($form['registration_cancellation']['user_cancel_method'][$element]['#description']);
352    }
353  }
354
355  // Account settings.
356  $form['personalization'] = array(
357    '#type' => 'fieldset',
358    '#title' => t('Personalization'),
359  );
360  $form['personalization']['user_signatures'] = array(
361    '#type' => 'checkbox',
362    '#title' => t('Enable signatures.'),
363    '#default_value' => variable_get('user_signatures', 0),
364  );
365  // If picture support is enabled, check whether the picture directory exists.
366  if (variable_get('user_pictures', 0)) {
367    $picture_path =  file_default_scheme() . '://' . variable_get('user_picture_path', 'pictures');
368    if (!file_prepare_directory($picture_path, FILE_CREATE_DIRECTORY)) {
369      form_set_error('user_picture_path', t('The directory %directory does not exist or is not writable.', array('%directory' => $picture_path)));
370      watchdog('file system', 'The directory %directory does not exist or is not writable.', array('%directory' => $picture_path), WATCHDOG_ERROR);
371    }
372  }
373  $picture_support = variable_get('user_pictures', 0);
374  $form['personalization']['user_pictures'] = array(
375    '#type' => 'checkbox',
376    '#title' => t('Enable user pictures.'),
377    '#default_value' => $picture_support,
378  );
379  drupal_add_js(drupal_get_path('module', 'user') . '/user.js');
380  $form['personalization']['pictures'] = array(
381    '#type' => 'container',
382    '#states' => array(
383      // Hide the additional picture settings when user pictures are disabled.
384      'invisible' => array(
385        'input[name="user_pictures"]' => array('checked' => FALSE),
386      ),
387    ),
388  );
389  $form['personalization']['pictures']['user_picture_path'] = array(
390    '#type' => 'textfield',
391    '#title' => t('Picture directory'),
392    '#default_value' => variable_get('user_picture_path', 'pictures'),
393    '#size' => 30,
394    '#maxlength' => 255,
395    '#description' => t('Subdirectory in the file upload directory where pictures will be stored.'),
396  );
397  $form['personalization']['pictures']['user_picture_default'] = array(
398    '#type' => 'textfield',
399    '#title' => t('Default picture'),
400    '#default_value' => variable_get('user_picture_default', ''),
401    '#size' => 30,
402    '#maxlength' => 255,
403    '#description' => t('URL of picture to display for users with no custom picture selected. Leave blank for none.'),
404  );
405  if (module_exists('image')) {
406    $form['personalization']['pictures']['settings']['user_picture_style'] = array(
407      '#type' => 'select',
408      '#title' => t('Picture display style'),
409      '#options' => image_style_options(TRUE, PASS_THROUGH),
410      '#default_value' => variable_get('user_picture_style', ''),
411      '#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'))),
412    );
413  }
414  $form['personalization']['pictures']['user_picture_dimensions'] = array(
415    '#type' => 'textfield',
416    '#title' => t('Picture upload dimensions'),
417    '#default_value' => variable_get('user_picture_dimensions', '85x85'),
418    '#size' => 10,
419    '#maxlength' => 10,
420    '#field_suffix' => ' ' . t('pixels'),
421    '#description' => t('Pictures larger than this will be scaled down to this size.'),
422  );
423  $form['personalization']['pictures']['user_picture_file_size'] = array(
424    '#type' => 'textfield',
425    '#title' => t('Picture upload file size'),
426    '#default_value' => variable_get('user_picture_file_size', '30'),
427    '#size' => 10,
428    '#maxlength' => 10,
429    '#field_suffix' => ' ' . t('KB'),
430    '#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.'),
431    '#element_validate' => array('element_validate_integer_positive'),
432  );
433  $form['personalization']['pictures']['user_picture_guidelines'] = array(
434    '#type' => 'textarea',
435    '#title' => t('Picture guidelines'),
436    '#default_value' => variable_get('user_picture_guidelines', ''),
437    '#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."),
438  );
439
440  $form['email_title'] = array(
441    '#type' => 'item',
442    '#title' => t('E-mails'),
443  );
444  $form['email'] = array(
445    '#type' => 'vertical_tabs',
446  );
447  // These email tokens are shared for all settings, so just define
448  // the list once to help ensure they stay in sync.
449  $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].');
450
451  $form['email_admin_created'] = array(
452    '#type' => 'fieldset',
453    '#title' => t('Welcome (new user created by administrator)'),
454    '#collapsible' => TRUE,
455    '#collapsed' => (variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) != USER_REGISTER_ADMINISTRATORS_ONLY),
456    '#description' => t('Edit the welcome e-mail messages sent to new member accounts created by an administrator.') . ' ' . $email_token_help,
457    '#group' => 'email',
458  );
459  $form['email_admin_created']['user_mail_register_admin_created_subject'] = array(
460    '#type' => 'textfield',
461    '#title' => t('Subject'),
462    '#default_value' => _user_mail_text('register_admin_created_subject', NULL, array(), FALSE),
463    '#maxlength' => 180,
464  );
465  $form['email_admin_created']['user_mail_register_admin_created_body'] = array(
466    '#type' => 'textarea',
467    '#title' => t('Body'),
468    '#default_value' => _user_mail_text('register_admin_created_body', NULL, array(), FALSE),
469    '#rows' => 15,
470  );
471
472  $form['email_pending_approval'] = array(
473    '#type' => 'fieldset',
474    '#title' => t('Welcome (awaiting approval)'),
475    '#collapsible' => TRUE,
476    '#collapsed' => (variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) != USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL),
477    '#description' => t('Edit the welcome e-mail messages sent to new members upon registering, when administrative approval is required.') . ' ' . $email_token_help,
478    '#group' => 'email',
479  );
480  $form['email_pending_approval']['user_mail_register_pending_approval_subject'] = array(
481    '#type' => 'textfield',
482    '#title' => t('Subject'),
483    '#default_value' => _user_mail_text('register_pending_approval_subject', NULL, array(), FALSE),
484    '#maxlength' => 180,
485  );
486  $form['email_pending_approval']['user_mail_register_pending_approval_body'] = array(
487    '#type' => 'textarea',
488    '#title' => t('Body'),
489    '#default_value' => _user_mail_text('register_pending_approval_body', NULL, array(), FALSE),
490    '#rows' => 8,
491  );
492
493  $form['email_no_approval_required'] = array(
494    '#type' => 'fieldset',
495    '#title' => t('Welcome (no approval required)'),
496    '#collapsible' => TRUE,
497    '#collapsed' => (variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) != USER_REGISTER_VISITORS),
498    '#description' => t('Edit the welcome e-mail messages sent to new members upon registering, when no administrator approval is required.') . ' ' . $email_token_help,
499    '#group' => 'email',
500  );
501  $form['email_no_approval_required']['user_mail_register_no_approval_required_subject'] = array(
502    '#type' => 'textfield',
503    '#title' => t('Subject'),
504    '#default_value' => _user_mail_text('register_no_approval_required_subject', NULL, array(), FALSE),
505    '#maxlength' => 180,
506  );
507  $form['email_no_approval_required']['user_mail_register_no_approval_required_body'] = array(
508    '#type' => 'textarea',
509    '#title' => t('Body'),
510    '#default_value' => _user_mail_text('register_no_approval_required_body', NULL, array(), FALSE),
511    '#rows' => 15,
512  );
513
514  $form['email_password_reset'] = array(
515    '#type' => 'fieldset',
516    '#title' => t('Password recovery'),
517    '#collapsible' => TRUE,
518    '#collapsed' => TRUE,
519    '#description' => t('Edit the e-mail messages sent to users who request a new password.') . ' ' . $email_token_help,
520    '#group' => 'email',
521    '#weight' => 10,
522  );
523  $form['email_password_reset']['user_mail_password_reset_subject'] = array(
524    '#type' => 'textfield',
525    '#title' => t('Subject'),
526    '#default_value' => _user_mail_text('password_reset_subject', NULL, array(), FALSE),
527    '#maxlength' => 180,
528  );
529  $form['email_password_reset']['user_mail_password_reset_body'] = array(
530    '#type' => 'textarea',
531    '#title' => t('Body'),
532    '#default_value' => _user_mail_text('password_reset_body', NULL, array(), FALSE),
533    '#rows' => 12,
534  );
535
536  $form['email_activated'] = array(
537    '#type' => 'fieldset',
538    '#title' => t('Account activation'),
539    '#collapsible' => TRUE,
540    '#collapsed' => TRUE,
541    '#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,
542    '#group' => 'email',
543  );
544  $form['email_activated']['user_mail_status_activated_notify'] = array(
545    '#type' => 'checkbox',
546    '#title' => t('Notify user when account is activated.'),
547    '#default_value' => variable_get('user_mail_status_activated_notify', TRUE),
548  );
549  $form['email_activated']['settings'] = array(
550    '#type' => 'container',
551    '#states' => array(
552      // Hide the additional settings when this email is disabled.
553      'invisible' => array(
554        'input[name="user_mail_status_activated_notify"]' => array('checked' => FALSE),
555      ),
556    ),
557  );
558  $form['email_activated']['settings']['user_mail_status_activated_subject'] = array(
559    '#type' => 'textfield',
560    '#title' => t('Subject'),
561    '#default_value' => _user_mail_text('status_activated_subject', NULL, array(), FALSE),
562    '#maxlength' => 180,
563  );
564  $form['email_activated']['settings']['user_mail_status_activated_body'] = array(
565    '#type' => 'textarea',
566    '#title' => t('Body'),
567    '#default_value' => _user_mail_text('status_activated_body', NULL, array(), FALSE),
568    '#rows' => 15,
569  );
570
571  $form['email_blocked'] = array(
572    '#type' => 'fieldset',
573    '#title' => t('Account blocked'),
574    '#collapsible' => TRUE,
575    '#collapsed' => TRUE,
576    '#description' => t('Enable and edit e-mail messages sent to users when their accounts are blocked.') . ' ' . $email_token_help,
577    '#group' => 'email',
578  );
579  $form['email_blocked']['user_mail_status_blocked_notify'] = array(
580    '#type' => 'checkbox',
581    '#title' => t('Notify user when account is blocked.'),
582    '#default_value' => variable_get('user_mail_status_blocked_notify', FALSE),
583  );
584  $form['email_blocked']['settings'] = array(
585    '#type' => 'container',
586    '#states' => array(
587      // Hide the additional settings when the blocked email is disabled.
588      'invisible' => array(
589        'input[name="user_mail_status_blocked_notify"]' => array('checked' => FALSE),
590      ),
591    ),
592  );
593  $form['email_blocked']['settings']['user_mail_status_blocked_subject'] = array(
594    '#type' => 'textfield',
595    '#title' => t('Subject'),
596    '#default_value' => _user_mail_text('status_blocked_subject', NULL, array(), FALSE),
597    '#maxlength' => 180,
598  );
599  $form['email_blocked']['settings']['user_mail_status_blocked_body'] = array(
600    '#type' => 'textarea',
601    '#title' => t('Body'),
602    '#default_value' => _user_mail_text('status_blocked_body', NULL, array(), FALSE),
603    '#rows' => 3,
604  );
605
606  $form['email_cancel_confirm'] = array(
607    '#type' => 'fieldset',
608    '#title' => t('Account cancellation confirmation'),
609    '#collapsible' => TRUE,
610    '#collapsed' => TRUE,
611    '#description' => t('Edit the e-mail messages sent to users when they attempt to cancel their accounts.') . ' ' . $email_token_help,
612    '#group' => 'email',
613  );
614  $form['email_cancel_confirm']['user_mail_cancel_confirm_subject'] = array(
615    '#type' => 'textfield',
616    '#title' => t('Subject'),
617    '#default_value' => _user_mail_text('cancel_confirm_subject', NULL, array(), FALSE),
618    '#maxlength' => 180,
619  );
620  $form['email_cancel_confirm']['user_mail_cancel_confirm_body'] = array(
621    '#type' => 'textarea',
622    '#title' => t('Body'),
623    '#default_value' => _user_mail_text('cancel_confirm_body', NULL, array(), FALSE),
624    '#rows' => 3,
625  );
626
627  $form['email_canceled'] = array(
628    '#type' => 'fieldset',
629    '#title' => t('Account canceled'),
630    '#collapsible' => TRUE,
631    '#collapsed' => TRUE,
632    '#description' => t('Enable and edit e-mail messages sent to users when their accounts are canceled.') . ' ' . $email_token_help,
633    '#group' => 'email',
634  );
635  $form['email_canceled']['user_mail_status_canceled_notify'] = array(
636    '#type' => 'checkbox',
637    '#title' => t('Notify user when account is canceled.'),
638    '#default_value' => variable_get('user_mail_status_canceled_notify', FALSE),
639  );
640  $form['email_canceled']['settings'] = array(
641    '#type' => 'container',
642    '#states' => array(
643      // Hide the settings when the cancel notify checkbox is disabled.
644      'invisible' => array(
645        'input[name="user_mail_status_canceled_notify"]' => array('checked' => FALSE),
646      ),
647    ),
648  );
649  $form['email_canceled']['settings']['user_mail_status_canceled_subject'] = array(
650    '#type' => 'textfield',
651    '#title' => t('Subject'),
652    '#default_value' => _user_mail_text('status_canceled_subject', NULL, array(), FALSE),
653    '#maxlength' => 180,
654  );
655  $form['email_canceled']['settings']['user_mail_status_canceled_body'] = array(
656    '#type' => 'textarea',
657    '#title' => t('Body'),
658    '#default_value' => _user_mail_text('status_canceled_body', NULL, array(), FALSE),
659    '#rows' => 3,
660  );
661
662  return system_settings_form($form);
663}
664
665/**
666 * Menu callback: administer permissions.
667 *
668 * @ingroup forms
669 * @see user_admin_permissions_submit()
670 * @see theme_user_admin_permissions()
671 */
672function user_admin_permissions($form, $form_state, $rid = NULL) {
673
674  // Retrieve role names for columns.
675  $role_names = user_roles();
676  if (is_numeric($rid)) {
677    $role_names = array($rid => $role_names[$rid]);
678  }
679  // Fetch permissions for all roles or the one selected role.
680  $role_permissions = user_role_permissions($role_names);
681
682  // Store $role_names for use when saving the data.
683  $form['role_names'] = array(
684    '#type' => 'value',
685    '#value' => $role_names,
686  );
687  // Render role/permission overview:
688  $options = array();
689  $module_info = system_get_info('module');
690  $hide_descriptions = system_admin_compact_mode();
691
692  // Get a list of all the modules implementing a hook_permission() and sort by
693  // display name.
694  $modules = array();
695  foreach (module_implements('permission') as $module) {
696    $modules[$module] = $module_info[$module]['name'];
697  }
698  asort($modules);
699
700  foreach ($modules as $module => $display_name) {
701    if ($permissions = module_invoke($module, 'permission')) {
702      $form['permission'][] = array(
703        '#markup' => $module_info[$module]['name'],
704        '#id' => $module,
705      );
706      foreach ($permissions as $perm => $perm_item) {
707        // Fill in default values for the permission.
708        $perm_item += array(
709          'description' => '',
710          'restrict access' => FALSE,
711          'warning' => !empty($perm_item['restrict access']) ? t('Warning: Give to trusted roles only; this permission has security implications.') : '',
712        );
713        $options[$perm] = '';
714        $form['permission'][$perm] = array(
715          '#type' => 'item',
716          '#markup' => $perm_item['title'],
717          '#description' => theme('user_permission_description', array('permission_item' => $perm_item, 'hide' => $hide_descriptions)),
718        );
719        foreach ($role_names as $rid => $name) {
720          // Builds arrays for checked boxes for each role
721          if (isset($role_permissions[$rid][$perm])) {
722            $status[$rid][] = $perm;
723          }
724        }
725      }
726    }
727  }
728
729  // Have to build checkboxes here after checkbox arrays are built
730  foreach ($role_names as $rid => $name) {
731    $form['checkboxes'][$rid] = array(
732      '#type' => 'checkboxes',
733      '#options' => $options,
734      '#default_value' => isset($status[$rid]) ? $status[$rid] : array(),
735      '#attributes' => array('class' => array('rid-' . $rid)),
736    );
737    $form['role_names'][$rid] = array('#markup' => check_plain($name), '#tree' => TRUE);
738  }
739
740  $form['actions'] = array('#type' => 'actions');
741  $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save permissions'));
742
743  $form['#attached']['js'][] = drupal_get_path('module', 'user') . '/user.permissions.js';
744
745  return $form;
746}
747
748/**
749 * Save permissions selected on the administer permissions page.
750 *
751 * @see user_admin_permissions()
752 */
753function user_admin_permissions_submit($form, &$form_state) {
754  foreach ($form_state['values']['role_names'] as $rid => $name) {
755    user_role_change_permissions($rid, $form_state['values'][$rid]);
756  }
757
758  drupal_set_message(t('The changes have been saved.'));
759
760  // Clear the cached pages and blocks.
761  cache_clear_all();
762}
763
764/**
765 * Returns HTML for the administer permissions page.
766 *
767 * @param $variables
768 *   An associative array containing:
769 *   - form: A render element representing the form.
770 *
771 * @ingroup themeable
772 */
773function theme_user_admin_permissions($variables) {
774  $form = $variables['form'];
775
776  $roles = user_roles();
777  foreach (element_children($form['permission']) as $key) {
778    $row = array();
779    // Module name
780    if (is_numeric($key)) {
781      $row[] = array('data' => drupal_render($form['permission'][$key]), 'class' => array('module'), 'id' => 'module-' . $form['permission'][$key]['#id'], 'colspan' => count($form['role_names']['#value']) + 1);
782    }
783    else {
784      // Permission row.
785      $row[] = array(
786        'data' => drupal_render($form['permission'][$key]),
787        'class' => array('permission'),
788      );
789      foreach (element_children($form['checkboxes']) as $rid) {
790        $form['checkboxes'][$rid][$key]['#title'] = $roles[$rid] . ': ' . $form['permission'][$key]['#markup'];
791        $form['checkboxes'][$rid][$key]['#title_display'] = 'invisible';
792        $row[] = array('data' => drupal_render($form['checkboxes'][$rid][$key]), 'class' => array('checkbox'));
793      }
794    }
795    $rows[] = $row;
796  }
797  $header[] = (t('Permission'));
798  foreach (element_children($form['role_names']) as $rid) {
799    $header[] = array('data' => drupal_render($form['role_names'][$rid]), 'class' => array('checkbox'));
800  }
801  $output = theme('system_compact_link');
802  $output .= theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'permissions')));
803  $output .= drupal_render_children($form);
804  return $output;
805}
806
807/**
808 * Returns HTML for an individual permission description.
809 *
810 * @param $variables
811 *   An associative array containing:
812 *   - permission_item: An associative array representing the permission whose
813 *     description is being themed. Useful keys include:
814 *     - description: The text of the permission description.
815 *     - warning: A security-related warning message about the permission (if
816 *       there is one).
817 *   - hide: A boolean indicating whether or not the permission description was
818 *     requested to be hidden rather than shown.
819 *
820 * @ingroup themeable
821 */
822function theme_user_permission_description($variables) {
823  if (!$variables['hide']) {
824    $description = array();
825    $permission_item = $variables['permission_item'];
826    if (!empty($permission_item['description'])) {
827      $description[] = $permission_item['description'];
828    }
829    if (!empty($permission_item['warning'])) {
830      $description[] = '<em class="permission-warning">' . $permission_item['warning'] . '</em>';
831    }
832    if (!empty($description)) {
833      return implode(' ', $description);
834    }
835  }
836}
837
838/**
839 * Form to re-order roles or add a new one.
840 *
841 * @ingroup forms
842 * @see theme_user_admin_roles()
843 */
844function user_admin_roles($form, $form_state) {
845  $roles = user_roles();
846
847  $form['roles'] = array(
848    '#tree' => TRUE,
849  );
850  $order = 0;
851  foreach ($roles as $rid => $name) {
852    $form['roles'][$rid]['#role'] = (object) array(
853      'rid' => $rid,
854      'name' => $name,
855      'weight' => $order,
856    );
857    $form['roles'][$rid]['#weight'] = $order;
858    $form['roles'][$rid]['weight'] = array(
859      '#type' => 'textfield',
860      '#title' => t('Weight for @title', array('@title' => $name)),
861      '#title_display' => 'invisible',
862      '#size' => 4,
863      '#default_value' => $order,
864      '#attributes' => array('class' => array('role-weight')),
865    );
866    $order++;
867  }
868
869  $form['name'] = array(
870    '#type' => 'textfield',
871    '#title' => t('Name'),
872    '#title_display' => 'invisible',
873    '#size' => 32,
874    '#maxlength' => 64,
875  );
876  $form['add'] = array(
877    '#type' => 'submit',
878    '#value' => t('Add role'),
879    '#validate' => array('user_admin_role_validate'),
880    '#submit' => array('user_admin_role_submit'),
881  );
882  $form['actions'] = array('#type' => 'actions');
883  $form['actions']['submit'] = array(
884    '#type' => 'submit',
885    '#value' => t('Save order'),
886    '#submit' => array('user_admin_roles_order_submit'),
887  );
888
889  return $form;
890}
891
892/**
893 * Form submit function. Update the role weights.
894 */
895function user_admin_roles_order_submit($form, &$form_state) {
896  foreach ($form_state['values']['roles'] as $rid => $role_values) {
897    $role = $form['roles'][$rid]['#role'];
898    $role->weight = $role_values['weight'];
899    user_role_save($role);
900  }
901  drupal_set_message(t('The role settings have been updated.'));
902}
903
904/**
905 * Returns HTML for the role order and new role form.
906 *
907 * @param $variables
908 *   An associative array containing:
909 *   - form: A render element representing the form.
910 *
911 * @ingroup themeable
912 */
913function theme_user_admin_roles($variables) {
914  $form = $variables['form'];
915
916  $header = array(t('Name'), t('Weight'), array('data' => t('Operations'), 'colspan' => 2));
917  foreach (element_children($form['roles']) as $rid) {
918    $name = $form['roles'][$rid]['#role']->name;
919    $row = array();
920    if (in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
921      $row[] = t('@name <em>(locked)</em>', array('@name' => $name));
922      $row[] = drupal_render($form['roles'][$rid]['weight']);
923      $row[] = '';
924      $row[] = l(t('edit permissions'), 'admin/people/permissions/' . $rid);
925    }
926    else {
927      $row[] = check_plain($name);
928      $row[] = drupal_render($form['roles'][$rid]['weight']);
929      $row[] = l(t('edit role'), 'admin/people/permissions/roles/edit/' . $rid);
930      $row[] = l(t('edit permissions'), 'admin/people/permissions/' . $rid);
931    }
932    $rows[] = array('data' => $row, 'class' => array('draggable'));
933  }
934  $rows[] = array(array('data' => drupal_render($form['name']) . drupal_render($form['add']), 'colspan' => 4, 'class' => 'edit-name'));
935
936  drupal_add_tabledrag('user-roles', 'order', 'sibling', 'role-weight');
937
938  $output = theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'user-roles')));
939  $output .= drupal_render_children($form);
940
941  return $output;
942}
943
944/**
945 * Form to configure a single role.
946 *
947 * @ingroup forms
948 * @see user_admin_role_validate()
949 * @see user_admin_role_submit()
950 */
951function user_admin_role($form, $form_state, $role) {
952  if ($role->rid == DRUPAL_ANONYMOUS_RID || $role->rid == DRUPAL_AUTHENTICATED_RID) {
953    drupal_goto('admin/people/permissions/roles');
954  }
955
956  // Display the edit role form.
957  $form['name'] = array(
958    '#type' => 'textfield',
959    '#title' => t('Role name'),
960    '#default_value' => $role->name,
961    '#size' => 30,
962    '#required' => TRUE,
963    '#maxlength' => 64,
964    '#description' => t('The name for this role. Example: "moderator", "editorial board", "site architect".'),
965  );
966  $form['rid'] = array(
967    '#type' => 'value',
968    '#value' => $role->rid,
969  );
970  $form['weight'] = array(
971    '#type' => 'value',
972    '#value' => $role->weight,
973  );
974  $form['actions'] = array('#type' => 'actions');
975  $form['actions']['submit'] = array(
976    '#type' => 'submit',
977    '#value' => t('Save role'),
978  );
979  $form['actions']['delete'] = array(
980    '#type' => 'submit',
981    '#value' => t('Delete role'),
982    '#submit' => array('user_admin_role_delete_submit'),
983  );
984
985  return $form;
986}
987
988/**
989 * Form validation handler for the user_admin_role() form.
990 */
991function user_admin_role_validate($form, &$form_state) {
992  if (!empty($form_state['values']['name'])) {
993    if ($form_state['values']['op'] == t('Save role')) {
994      $role = user_role_load_by_name($form_state['values']['name']);
995      if ($role && $role->rid != $form_state['values']['rid']) {
996        form_set_error('name', t('The role name %name already exists. Choose another role name.', array('%name' => $form_state['values']['name'])));
997      }
998    }
999    elseif ($form_state['values']['op'] == t('Add role')) {
1000      if (user_role_load_by_name($form_state['values']['name'])) {
1001        form_set_error('name', t('The role name %name already exists. Choose another role name.', array('%name' => $form_state['values']['name'])));
1002      }
1003    }
1004  }
1005  else {
1006    form_set_error('name', t('You must specify a valid role name.'));
1007  }
1008}
1009
1010/**
1011 * Form submit handler for the user_admin_role() form.
1012 */
1013function user_admin_role_submit($form, &$form_state) {
1014  $role = (object) $form_state['values'];
1015  if ($form_state['values']['op'] == t('Save role')) {
1016    user_role_save($role);
1017    drupal_set_message(t('The role has been renamed.'));
1018  }
1019  elseif ($form_state['values']['op'] == t('Add role')) {
1020    user_role_save($role);
1021    drupal_set_message(t('The role has been added.'));
1022  }
1023  $form_state['redirect'] = 'admin/people/permissions/roles';
1024  return;
1025}
1026
1027/**
1028 * Form submit handler for the user_admin_role() form.
1029 */
1030function user_admin_role_delete_submit($form, &$form_state) {
1031  $form_state['redirect'] = 'admin/people/permissions/roles/delete/' . $form_state['values']['rid'];
1032}
1033
1034/**
1035 * Form to confirm role delete operation.
1036 */
1037function user_admin_role_delete_confirm($form, &$form_state, $role) {
1038  $form['rid'] = array(
1039    '#type' => 'value',
1040    '#value' => $role->rid,
1041  );
1042  return confirm_form($form, t('Are you sure you want to delete the role %name ?', array('%name' => $role->name)), 'admin/people/permissions/roles', t('This action cannot be undone.'), t('Delete'));
1043}
1044
1045/**
1046 * Form submit handler for user_admin_role_delete_confirm().
1047 */
1048function user_admin_role_delete_confirm_submit($form, &$form_state) {
1049  user_role_delete((int) $form_state['values']['rid']);
1050  drupal_set_message(t('The role has been deleted.'));
1051  $form_state['redirect'] = 'admin/people/permissions/roles';
1052}
1053