Simpletest Coverage - modules/user/user.pages.inc

1 <?php
2 // $Id: user.pages.inc,v 1.48 2009/08/12 12:36:05 dries Exp $
3
4 /**
5 * @file
6 * User page callback file for the user module.
7 */
8
9 /**
10 * Menu callback; Retrieve a JSON object containing autocomplete suggestions for existing users.
11 */
12 function user_autocomplete($string = '') {
13 $matches = array();
14 if ($string) {
15 $result = db_query_range("SELECT name FROM {users} WHERE LOWER(name) LIKE LOWER(:name)", array(':name' => $string . '%'), 0, 10);
16 foreach ($result as $user) {
17 $matches[$user->name] = check_plain($user->name);
18 }
19 }
20
21 drupal_json($matches);
22 }
23
24 /**
25 * Form builder; Request a password reset.
26 *
27 * @ingroup forms
28 * @see user_pass_validate()
29 * @see user_pass_submit()
30 */
31 function user_pass() {
32 $form['name'] = array(
33 '#type' => 'textfield',
34 '#title' => t('Username or e-mail address'),
35 '#size' => 60,
36 '#maxlength' => max(USERNAME_MAX_LENGTH, EMAIL_MAX_LENGTH),
37 '#required' => TRUE,
38 );
39 $form['submit'] = array('#type' => 'submit', '#value' => t('E-mail new password'));
40
41 return $form;
42 }
43
44 function user_pass_validate($form, &$form_state) {
45 $name = trim($form_state['values']['name']);
46 // Try to load by email.
47 $users = user_load_multiple(array(), array('mail' => $name, 'status' => '1'));
48 $account = reset($users);
49 if (!$account) {
50 // No success, try to load by name.
51 $users = user_load_multiple(array(), array('name' => $name, 'status' => '1'));
52 $account = reset($users);
53 }
54 if (isset($account->uid)) {
55 form_set_value(array('#parents' => array('account')), $account, $form_state);
56 }
57 else {
58 form_set_error('name', t('Sorry, %name is not recognized as a user name or an e-mail address.', array('%name' => $name)));
59 }
60 }
61
62 function user_pass_submit($form, &$form_state) {
63 global $language;
64
65 $account = $form_state['values']['account'];
66 // Mail one time login URL and instructions using current language.
67 _user_mail_notify('password_reset', $account, $language);
68 watchdog('user', 'Password reset instructions mailed to %name at %email.', array('%name' => $account->name, '%email' => $account->mail));
69 drupal_set_message(t('Further instructions have been sent to your e-mail address.'));
70
71 $form_state['redirect'] = 'user';
72 return;
73 }
74
75 /**
76 * Menu callback; process one time login link and redirects to the user page on success.
77 */
78 function user_pass_reset(&$form_state, $uid, $timestamp, $hashed_pass, $action = NULL) {
79 global $user;
80
81 // Check if the user is already logged in. The back button is often the culprit here.
82 if ($user->uid) {
83 drupal_set_message(t('You have already used this one-time login link. It is not necessary to use this link to login anymore. You are already logged in.'));
84 drupal_goto();
85 }
86 else {
87 // Time out, in seconds, until login URL expires. 24 hours = 86400 seconds.
88 $timeout = 86400;
89 $current = REQUEST_TIME;
90 // Some redundant checks for extra security ?
91 $users = user_load_multiple(array($uid), array('status' => '1'));
92 if ($timestamp <= $current && $account = reset($users)) {
93 // No time out for first time login.
94 if ($account->login && $current - $timestamp > $timeout) {
95 drupal_set_message(t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.'));
96 drupal_goto('user/password');
97 }
98 elseif ($account->uid && $timestamp >= $account->login && $timestamp <= $current && $hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login)) {
99 // First stage is a confirmation form, then login
100 if ($action == 'login') {
101 watchdog('user', 'User %name used one-time login link at time %timestamp.', array('%name' => $account->name, '%timestamp' => $timestamp));
102 // Set the new user.
103 $user = $account;
104 // user_login_finalize() also updates the login timestamp of the
105 // user, which invalidates further use of the one-time login link.
106 user_login_finalize();
107 drupal_set_message(t('You have just used your one-time login link. It is no longer necessary to use this link to login. Please change your password.'));
108 drupal_goto('user/' . $user->uid . '/edit');
109 }
110 else {
111 $form['message'] = array('#markup' => t('<p>This is a one-time login for %user_name and will expire on %expiration_date.</p><p>Click on this button to login to the site and change your password.</p>', array('%user_name' => $account->name, '%expiration_date' => format_date($timestamp + $timeout))));
112 $form['help'] = array('#markup' => '<p>' . t('This login can be used only once.') . '</p>');
113 $form['submit'] = array('#type' => 'submit', '#value' => t('Log in'));
114 $form['#action'] = url("user/reset/$uid/$timestamp/$hashed_pass/login");
115 return $form;
116 }
117 }
118 else {
119 drupal_set_message(t('You have tried to use a one-time login link which has either been used or is no longer valid. Please request a new one using the form below.'));
120 drupal_goto('user/password');
121 }
122 }
123 else {
124 // Deny access, no more clues.
125 // Everything will be in the watchdog's URL for the administrator to check.
126 drupal_access_denied();
127 }
128 }
129 }
130
131 /**
132 * Menu callback; logs the current user out, and redirects to the home page.
133 */
134 function user_logout() {
135 global $user;
136
137 watchdog('user', 'Session closed for %name.', array('%name' => $user->name));
138
139 module_invoke_all('user_logout', $user);
140
141 // Destroy the current session, and reset $user to the anonymous user.
142 session_destroy();
143
144 drupal_goto();
145 }
146
147 /**
148 * Menu callback; Displays a user or user profile page.
149 *
150 * The $page['content'] array for user profile pages contains:
151 *
152 * - $page['content']['Profile Category']:
153 * Profile categories keyed by their human-readable names.
154 * - $page['content']['Profile Category']['profile_machine_name']:
155 * Profile fields keyed by their machine-readable names.
156 * - $page['content']['user_picture']:
157 * User's rendered picture.
158 * - $page['content']['summary']:
159 * Contains the default "History" profile data for a user.
160 * - $page['content']['#account']:
161 * The user account of the profile being viewed.
162 *
163 * To theme user profiles, copy modules/user/user-profile.tpl.php
164 * to your theme directory, and edit it as instructed in that file's comments.
165 */
166 function user_view($account) {
167 drupal_set_title($account->name);
168 // Retrieve all profile fields and attach to $account->content.
169 user_build_content($account);
170
171 $build = $account->content;
172 $build += array(
173 '#theme' => 'user_profile',
174 '#account' => $account,
175 );
176
177 return $build;
178 }
179
180 /**
181 * Process variables for user-profile.tpl.php.
182 *
183 * The $variables array contains the following arguments:
184 * - $account
185 *
186 * @see user-profile.tpl.php
187 */
188 function template_preprocess_user_profile(&$variables) {
189 $account = $variables['elements']['#account'];
190 $variables['user_profile'] = $account->content;
191 }
192
193 /**
194 * Process variables for user-profile-item.tpl.php.
195 *
196 * The $variables array contains the following arguments:
197 * - $element
198 *
199 * @see user-profile-item.tpl.php
200 */
201 function template_preprocess_user_profile_item(&$variables) {
202 $variables['title'] = $variables['element']['#title'];
203 $variables['value'] = $variables['element']['#markup'];
204 $variables['attributes'] = '';
205 if (isset($variables['element']['#attributes'])) {
206 $variables['attributes'] = drupal_attributes($variables['element']['#attributes']);
207 }
208 }
209
210 /**
211 * Process variables for user-profile-category.tpl.php.
212 *
213 * The $variables array contains the following arguments:
214 * - $element
215 *
216 * @see user-profile-category.tpl.php
217 */
218 function template_preprocess_user_profile_category(&$variables) {
219 $variables['title'] = check_plain($variables['element']['#title']);
220 $variables['profile_items'] = $variables['element']['#children'];
221 $variables['attributes'] = '';
222 if (isset($variables['element']['#attributes'])) {
223 $variables['attributes'] = drupal_attributes($variables['element']['#attributes']);
224 }
225 }
226
227 /**
228 * Form builder; Present the form to edit a given user or profile category.
229 *
230 * @ingroup forms
231 * @see user_edit_validate()
232 * @see user_edit_submit()
233 */
234 function user_edit($account, $category = 'account') {
235 drupal_set_title($account->name);
236 return drupal_get_form('user_profile_form', $account, $category);
237 }
238
239 /**
240 * Form builder; edit a user account or one of their profile categories.
241 *
242 * @ingroup forms
243 * @see user_profile_form_validate()
244 * @see user_profile_form_submit()
245 * @see user_cancel_confirm_form_submit()
246 */
247 function user_profile_form($form_state, $account, $category = 'account') {
248 global $user;
249
250 $edit = (empty($form_state['values'])) ? (array)$account : $form_state['values'];
251
252 $form = _user_forms($edit, $account, $category);
253
254 // Attach field widgets.
255 field_attach_form('user', (object) $edit, $form, $form_state);
256
257 $form['_category'] = array('#type' => 'value', '#value' => $category);
258 $form['_account'] = array('#type' => 'value', '#value' => $account);
259 $form['submit'] = array('#type' => 'submit', '#value' => t('Save'), '#weight' => 30);
260 if (($account->uid == $user->uid && user_access('cancel account')) || user_access('administer users')) {
261 $form['cancel'] = array(
262 '#type' => 'submit',
263 '#value' => t('Cancel account'),
264 '#weight' => 31,
265 '#submit' => array('user_edit_cancel_submit'),
266 );
267 }
268
269 return $form;
270 }
271
272 /**
273 * Validation function for the user account and profile editing form.
274 */
275 function user_profile_form_validate($form, &$form_state) {
276 $edit = (object)$form_state['values'];
277 field_attach_form_validate('user', $edit, $form, $form_state);
278 $edit = (array)$edit;
279 user_module_invoke('validate', $edit, $form_state['values']['_account'], $form_state['values']['_category']);
280 // Validate input to ensure that non-privileged users can't alter protected data.
281 if ((!user_access('administer users') && array_intersect(array_keys($edit), array('uid', 'init', 'session'))) || (!user_access('administer permissions') && isset($form_state['values']['roles']))) {
282 watchdog('security', 'Detected malicious attempt to alter protected user fields.', array(), WATCHDOG_WARNING);
283 // set this to a value type field
284 form_set_error('category', t('Detected malicious attempt to alter protected user fields.'));
285 }
286 }
287
288 /**
289 * Submit function for the user account and profile editing form.
290 */
291 function user_profile_form_submit($form, &$form_state) {
292 $account = $form_state['values']['_account'];
293 $category = $form_state['values']['_category'];
294 unset($form_state['values']['_account'], $form_state['values']['op'], $form_state['values']['submit'], $form_state['values']['cancel'], $form_state['values']['form_token'], $form_state['values']['form_id'], $form_state['values']['_category'], $form_state['values']['form_build_id']);
295
296 $edit = (object)$form_state['values'];
297 field_attach_submit('user', $edit, $form, $form_state);
298 $edit = (array)$edit;
299 user_module_invoke('submit', $edit, $account, $category);
300 user_save($account, $edit, $category);
301
302 // Clear the page cache because pages can contain usernames and/or profile information:
303 cache_clear_all();
304
305 drupal_set_message(t('The changes have been saved.'));
306 return;
307 }
308
309 /**
310 * Submit function for the 'Cancel account' button on the user edit form.
311 */
312 function user_edit_cancel_submit($form, &$form_state) {
313 $destination = '';
314 if (isset($_REQUEST['destination'])) {
315 $destination = drupal_get_destination();
316 unset($_REQUEST['destination']);
317 }
318 // Note: We redirect from user/uid/edit to user/uid/cancel to make the tabs disappear.
319 $form_state['redirect'] = array("user/" . $form_state['values']['_account']->uid . "/cancel", $destination);
320 }
321
322 /**
323 * Form builder; confirm form for cancelling user account.
324 *
325 * @ingroup forms
326 * @see user_edit_cancel_submit()
327 */
328 function user_cancel_confirm_form(&$form_state, $account) {
329 global $user;
330
331 $form['_account'] = array('#type' => 'value', '#value' => $account);
332
333 // Display account cancellation method selection, if allowed.
334 $default_method = variable_get('user_cancel_method', 'user_cancel_block');
335 $admin_access = user_access('administer users');
336 $can_select_method = $admin_access || user_access('select account cancellation method');
337 $form['user_cancel_method'] = array(
338 '#type' => 'item',
339 '#title' => ($account->uid == $user->uid ? t('When cancelling your account') : t('When cancelling the account')),
340 '#access' => $can_select_method,
341 );
342 $form['user_cancel_method'] += user_cancel_methods();
343
344 // Allow user administrators to skip the account cancellation confirmation
345 // mail (by default), as long as they do not attempt to cancel their own
346 // account.
347 $override_access = $admin_access && ($account->uid != $user->uid);
348 $form['user_cancel_confirm'] = array(
349 '#type' => 'checkbox',
350 '#title' => t('Require e-mail confirmation to cancel account.'),
351 '#default_value' => ($override_access ? FALSE : TRUE),
352 '#access' => $override_access,
353 '#description' => t('When enabled, the user must confirm the account cancellation via e-mail.'),
354 );
355 // Also allow to send account canceled notification mail, if enabled.
356 $default_notify = variable_get('user_mail_status_canceled_notify', FALSE);
357 $form['user_cancel_notify'] = array(
358 '#type' => 'checkbox',
359 '#title' => t('Notify user when account is canceled.'),
360 '#default_value' => ($override_access ? FALSE : $default_notify),
361 '#access' => $override_access && $default_notify,
362 '#description' => t('When enabled, the user will receive an e-mail notification after the account has been cancelled.'),
363 );
364
365 // Prepare confirmation form page title and description.
366 if ($account->uid == $user->uid) {
367 $question = t('Are you sure you want to cancel your account?');
368 }
369 else {
370 $question = t('Are you sure you want to cancel the account %name?', array('%name' => $account->name));
371 }
372 $description = '';
373 if ($can_select_method) {
374 $description = t('Select the method to cancel the account above.');
375 foreach (element_children($form['user_cancel_method']) as $element) {
376 unset($form['user_cancel_method'][$element]['#description']);
377 }
378 }
379 else {
380 // The radio button #description is used as description for the confirmation
381 // form.
382 foreach (element_children($form['user_cancel_method']) as $element) {
383 if ($form['user_cancel_method'][$element]['#default_value'] == $form['user_cancel_method'][$element]['#return_value']) {
384 $description = $form['user_cancel_method'][$element]['#description'];
385 }
386 unset($form['user_cancel_method'][$element]['#description']);
387 }
388 }
389
390 return confirm_form($form,
391 $question,
392 'user/' . $account->uid,
393 $description . ' ' . t('This action cannot be undone.'),
394 t('Cancel account'), t('Cancel'));
395 }
396
397 /**
398 * Submit handler for the account cancellation confirm form.
399 *
400 * @see user_cancel_confirm_form()
401 * @see user_multiple_cancel_confirm_submit()
402 */
403 function user_cancel_confirm_form_submit($form, &$form_state) {
404 global $user;
405 $account = $form_state['values']['_account'];
406
407 // Cancel account immediately, if the current user has administrative
408 // privileges, no confirmation mail shall be sent, and the user does not
409 // attempt to cancel the own account.
410 if (user_access('administer users') && empty($form_state['values']['user_cancel_confirm']) && $account->uid != $user->uid) {
411 user_cancel($form_state['values'], $account->uid, $form_state['values']['user_cancel_method']);
412
413 if (!isset($_REQUEST['destination'])) {
414 $form_state['redirect'] = 'admin/people';
415 }
416 }
417 else {
418 // Store cancelling method and whether to notify the user in $account for
419 // user_cancel_confirm().
420 $edit = array(
421 'user_cancel_method' => $form_state['values']['user_cancel_method'],
422 'user_cancel_notify' => $form_state['values']['user_cancel_notify'],
423 );
424 $account = user_save($account, $edit);
425 _user_mail_notify('cancel_confirm', $account);
426 drupal_set_message(t('A confirmation request to cancel your account has been sent to your e-mail address.'));
427 watchdog('user', 'Sent account cancellation request to %name %email.', array('%name' => $account->name, '%email' => '<' . $account->mail . '>'), WATCHDOG_NOTICE);
428
429 if (!isset($_REQUEST['destination'])) {
430 $form_state['redirect'] = "user/$account->uid";
431 }
432 }
433 }
434
435 /**
436 * Helper function to return available account cancellation methods.
437 *
438 * Please refer to the documentation of hook_user_cancel_methods_alter().
439 *
440 * @return
441 * An array containing all account cancellation methods as form elements.
442 *
443 * @see hook_user_cancel_methods_alter()
444 * @see user_admin_settings()
445 * @see user_cancel_confirm_form()
446 * @see user_multiple_cancel_confirm()
447 */
448 function user_cancel_methods() {
449 $methods = array(
450 'user_cancel_block' => array(
451 'title' => t('Disable the account and keep all content.'),
452 'description' => t('Your account will be blocked and you will no longer be able to log in. All of your content will remain attributed to your user name.'),
453 ),
454 'user_cancel_block_unpublish' => array(
455 'title' => t('Disable the account and unpublish all content.'),
456 'description' => t('Your account will be blocked and you will no longer be able to log in. All of your content will be hidden from everyone but administrators.'),
457 ),
458 'user_cancel_reassign' => array(
459 'title' => t('Delete the account and make all content belong to the %anonymous-name user.', array('%anonymous-name' => variable_get('anonymous', t('Anonymous')))),
460 'description' => t('Your account will be removed and all account information deleted. All of your content will be assigned to the %anonymous-name user.', array('%anonymous-name' => variable_get('anonymous', t('Anonymous')))),
461 ),
462 'user_cancel_delete' => array(
463 'title' => t('Delete the account and all content.'),
464 'description' => t('Your account will be removed and all account information deleted. All of your content will also be deleted.'),
465 'access' => user_access('administer users'),
466 ),
467 );
468 // Allow modules to customize account cancellation methods.
469 drupal_alter('user_cancel_methods', $methods);
470
471 // Turn all methods into real form elements.
472 $default_method = variable_get('user_cancel_method', 'user_cancel_block');
473 $form = array();
474 foreach ($methods as $name => $method) {
475 $form[$name] = array(
476 '#type' => 'radio',
477 '#title' => $method['title'],
478 '#description' => (isset($method['description']) ? $method['description'] : NULL),
479 '#return_value' => $name,
480 '#default_value' => $default_method,
481 '#parents' => array('user_cancel_method'),
482 '#required' => TRUE,
483 );
484 }
485 return $form;
486 }
487
488 /**
489 * Menu callback; Cancel a user account via e-mail confirmation link.
490 *
491 * @see user_cancel_confirm_form()
492 * @see user_cancel_url()
493 */
494 function user_cancel_confirm($account, $timestamp = 0, $hashed_pass = '') {
495 // Time out in seconds until cancel URL expires; 24 hours = 86400 seconds.
496 $timeout = 86400;
497 $current = REQUEST_TIME;
498
499 // Basic validation of arguments.
500 if (isset($account->user_cancel_method) && !empty($timestamp) && !empty($hashed_pass)) {
501 // Validate expiration and hashed password/login.
502 if ($timestamp <= $current && $current - $timestamp < $timeout && $account->uid && $timestamp >= $account->login && $hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login)) {
503 $edit = array(
504 'user_cancel_notify' => isset($account->user_cancel_notify) ? $account->user_cancel_notify : variable_get('user_mail_status_canceled_notify', FALSE),
505 );
506 user_cancel($edit, $account->uid, $account->user_cancel_method);
507 // Since user_cancel() is not invoked via Form API, batch processing needs
508 // to be invoked manually and should redirect to the front page after
509 // completion.
510 batch_process('');
511 }
512 else {
513 drupal_set_message(t('You have tried to use an account cancellation link that has expired. Please request a new one using the form below.'));
514 drupal_goto("user/$account->uid/cancel");
515 }
516 }
517 drupal_access_denied();
518 }
519
520 function user_edit_validate($form, &$form_state) {
521 user_module_invoke('validate', $form_state['values'], $form_state['values']['_account'], $form_state['values']['_category']);
522 // Validate input to ensure that non-privileged users can't alter protected data.
523 if ((!user_access('administer users') && array_intersect(array_keys($form_state['values']), array('uid', 'init', 'session'))) || (!user_access('administer permissions') && isset($form_state['values']['roles']))) {
524 watchdog('security', 'Detected malicious attempt to alter protected user fields.', array(), WATCHDOG_WARNING);
525 // set this to a value type field
526 form_set_error('category', t('Detected malicious attempt to alter protected user fields.'));
527 }
528 }
529
530 function user_edit_submit($form, &$form_state) {
531 $account = $form_state['values']['_account'];
532 $category = $form_state['values']['_category'];
533 unset($form_state['values']['_account'], $form_state['values']['op'], $form_state['values']['submit'], $form_state['values']['cancel'], $form_state['values']['form_token'], $form_state['values']['form_id'], $form_state['values']['_category'], $form_state['values']['form_build_id']);
534 user_module_invoke('submit', $form_state['values'], $account, $category);
535 user_save($account, $form_state['values'], $category);
536
537 // Clear the page cache because pages can contain usernames and/or profile information:
538 cache_clear_all();
539
540 drupal_set_message(t('The changes have been saved.'));
541 return;
542 }
543
544 /**
545 * Access callback for path /user.
546 *
547 * Displays user profile if user is logged in, or login form for anonymous
548 * users.
549 */
550 function user_page() {
551 global $user;
552 if ($user->uid) {
553 menu_set_active_item('user/' . $user->uid);
554 return menu_execute_active_handler();
555 }
556 else {
557 return drupal_get_form('user_login');
558 }
559 }
560

Legend

Missed
lines code that were not excersized during program execution.
Covered
lines code were excersized during program execution.
Comment/non executable
Comment or non-executable line of code.
Dead
lines of code that according to xdebug could not be executed. This is counted as coverage code because in almost all cases it is code that runnable.