First commit
This commit is contained in:
commit
c6e2478c40
13918 changed files with 2303184 additions and 0 deletions
12
modules/user/tests/user_form_test.info
Normal file
12
modules/user/tests/user_form_test.info
Normal file
|
@ -0,0 +1,12 @@
|
|||
name = "User module form tests"
|
||||
description = "Support module for user form testing."
|
||||
package = Testing
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
82
modules/user/tests/user_form_test.module
Normal file
82
modules/user/tests/user_form_test.module
Normal file
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Dummy module implementing a form to test user password validation
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*
|
||||
* Sets up a form that allows a user to validate password.
|
||||
*/
|
||||
function user_form_test_menu() {
|
||||
$items = array();
|
||||
$items['user_form_test_current_password/%user'] = array(
|
||||
'title' => 'User form test for current password validation',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('user_form_test_current_password',1),
|
||||
'access arguments' => array('administer users'),
|
||||
'type' => MENU_SUGGESTED_ITEM,
|
||||
);
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* A test form for user_validate_current_pass().
|
||||
*/
|
||||
function user_form_test_current_password($form, &$form_state, $account) {
|
||||
$account->user_form_test_field = '';
|
||||
$form['#user'] = $account;
|
||||
|
||||
$form['user_form_test_field'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Test field'),
|
||||
'#description' => t('A field that would require a correct password to change.'),
|
||||
'#required' => TRUE,
|
||||
);
|
||||
|
||||
$form['current_pass'] = array(
|
||||
'#type' => 'password',
|
||||
'#title' => t('Current password'),
|
||||
'#size' => 25,
|
||||
'#description' => t('Enter your current password'),
|
||||
);
|
||||
|
||||
$form['current_pass_required_values'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => array('user_form_test_field' => t('Test field')),
|
||||
);
|
||||
|
||||
$form['#validate'][] = 'user_validate_current_pass';
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Test'),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit function for the test form for user_validate_current_pass().
|
||||
*/
|
||||
function user_form_test_current_password_submit($form, &$form_state) {
|
||||
drupal_set_message(t('The password has been validated and the form submitted successfully.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_form_FORM_ID_alter().
|
||||
*/
|
||||
function user_form_test_form_user_profile_form_alter(&$form, &$form_state) {
|
||||
if (variable_get('user_form_test_user_profile_form_rebuild', FALSE)) {
|
||||
$form['#submit'][] = 'user_form_test_user_account_submit';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit function for user_profile_form().
|
||||
*/
|
||||
function user_form_test_user_account_submit($form, &$form_state) {
|
||||
// Rebuild the form instead of letting the process end. This allows us to
|
||||
// test for bugs that can be triggered in contributed modules.
|
||||
$form_state['rebuild'] = TRUE;
|
||||
}
|
23
modules/user/user-picture.tpl.php
Normal file
23
modules/user/user-picture.tpl.php
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Default theme implementation to present a picture configured for the
|
||||
* user's account.
|
||||
*
|
||||
* Available variables:
|
||||
* - $user_picture: Image set by the user or the site's default. Will be linked
|
||||
* depending on the viewer's permission to view the user's profile page.
|
||||
* - $account: Array of account information. Potentially unsafe. Be sure to
|
||||
* check_plain() before use.
|
||||
*
|
||||
* @see template_preprocess_user_picture()
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
?>
|
||||
<?php if ($user_picture): ?>
|
||||
<div class="<?php print $classes; ?>">
|
||||
<?php print $user_picture; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
33
modules/user/user-profile-category.tpl.php
Normal file
33
modules/user/user-profile-category.tpl.php
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Default theme implementation to present profile categories (groups of
|
||||
* profile items).
|
||||
*
|
||||
* Categories are defined when configuring user profile fields for the site.
|
||||
* It can also be defined by modules. All profile items for a category will be
|
||||
* output through the $profile_items variable.
|
||||
*
|
||||
* @see user-profile-item.tpl.php
|
||||
* where each profile item is rendered. It is implemented as a definition
|
||||
* list by default.
|
||||
* @see user-profile.tpl.php
|
||||
* where all items and categories are collected and printed out.
|
||||
*
|
||||
* Available variables:
|
||||
* - $title: Category title for the group of items.
|
||||
* - $profile_items: All the items for the group rendered through
|
||||
* user-profile-item.tpl.php.
|
||||
* - $attributes: HTML attributes. Usually renders classes.
|
||||
*
|
||||
* @see template_preprocess_user_profile_category()
|
||||
*/
|
||||
?>
|
||||
<?php if ($title): ?>
|
||||
<h3><?php print $title; ?></h3>
|
||||
<?php endif; ?>
|
||||
|
||||
<dl<?php print $attributes; ?>>
|
||||
<?php print $profile_items; ?>
|
||||
</dl>
|
26
modules/user/user-profile-item.tpl.php
Normal file
26
modules/user/user-profile-item.tpl.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Default theme implementation to present profile items (values from user
|
||||
* account profile fields or modules).
|
||||
*
|
||||
* This template is used to loop through and render each field configured
|
||||
* for the user's account. It can also be the data from modules. The output is
|
||||
* grouped by categories.
|
||||
*
|
||||
* @see user-profile-category.tpl.php
|
||||
* for the parent markup. Implemented as a definition list by default.
|
||||
* @see user-profile.tpl.php
|
||||
* where all items and categories are collected and printed out.
|
||||
*
|
||||
* Available variables:
|
||||
* - $title: Field title for the profile item.
|
||||
* - $value: User defined value for the profile item or data from a module.
|
||||
* - $attributes: HTML attributes. Usually renders classes.
|
||||
*
|
||||
* @see template_preprocess_user_profile_item()
|
||||
*/
|
||||
?>
|
||||
<dt<?php print $attributes; ?>><?php print $title; ?></dt>
|
||||
<dd<?php print $attributes; ?>><?php print $value; ?></dd>
|
39
modules/user/user-profile.tpl.php
Normal file
39
modules/user/user-profile.tpl.php
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Default theme implementation to present all user profile data.
|
||||
*
|
||||
* This template is used when viewing a registered member's profile page,
|
||||
* e.g., example.com/user/123. 123 being the users ID.
|
||||
*
|
||||
* Use render($user_profile) to print all profile items, or print a subset
|
||||
* such as render($user_profile['user_picture']). Always call
|
||||
* render($user_profile) at the end in order to print all remaining items. If
|
||||
* the item is a category, it will contain all its profile items. By default,
|
||||
* $user_profile['summary'] is provided, which contains data on the user's
|
||||
* history. Other data can be included by modules. $user_profile['user_picture']
|
||||
* is available for showing the account picture.
|
||||
*
|
||||
* Available variables:
|
||||
* - $user_profile: An array of profile items. Use render() to print them.
|
||||
* - Field variables: for each field instance attached to the user a
|
||||
* corresponding variable is defined; e.g., $account->field_example has a
|
||||
* variable $field_example defined. When needing to access a field's raw
|
||||
* values, developers/themers are strongly encouraged to use these
|
||||
* variables. Otherwise they will have to explicitly specify the desired
|
||||
* field language, e.g. $account->field_example['en'], thus overriding any
|
||||
* language negotiation rule that was previously applied.
|
||||
*
|
||||
* @see user-profile-category.tpl.php
|
||||
* Where the html is handled for the group.
|
||||
* @see user-profile-item.tpl.php
|
||||
* Where the html is handled for each item in the group.
|
||||
* @see template_preprocess_user_profile()
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
?>
|
||||
<div class="profile"<?php print $attributes; ?>>
|
||||
<?php print render($user_profile); ?>
|
||||
</div>
|
34
modules/user/user-rtl.css
Normal file
34
modules/user/user-rtl.css
Normal file
|
@ -0,0 +1,34 @@
|
|||
|
||||
#permissions td.permission {
|
||||
padding-left: 0;
|
||||
padding-right: 1.5em;
|
||||
}
|
||||
|
||||
#user-admin-roles .form-item-name {
|
||||
float: right;
|
||||
margin-left: 1em;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Password strength indicator.
|
||||
*/
|
||||
.password-strength {
|
||||
float: left;
|
||||
}
|
||||
.password-strength-text {
|
||||
float: left;
|
||||
}
|
||||
div.password-confirm {
|
||||
float: left;
|
||||
}
|
||||
.confirm-parent,
|
||||
.password-parent {
|
||||
clear: right;
|
||||
}
|
||||
|
||||
/* Generated by user.module but used by profile.module: */
|
||||
.profile .user-picture {
|
||||
float: left;
|
||||
margin: 0 0 1em 1em;
|
||||
}
|
1053
modules/user/user.admin.inc
Normal file
1053
modules/user/user.admin.inc
Normal file
File diff suppressed because it is too large
Load diff
477
modules/user/user.api.php
Normal file
477
modules/user/user.api.php
Normal file
|
@ -0,0 +1,477 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Hooks provided by the User module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup hooks
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Act on user objects when loaded from the database.
|
||||
*
|
||||
* Due to the static cache in user_load_multiple() you should not use this
|
||||
* hook to modify the user properties returned by the {users} table itself
|
||||
* since this may result in unreliable results when loading from cache.
|
||||
*
|
||||
* @param $users
|
||||
* An array of user objects, indexed by uid.
|
||||
*
|
||||
* @see user_load_multiple()
|
||||
* @see profile_user_load()
|
||||
*/
|
||||
function hook_user_load($users) {
|
||||
$result = db_query('SELECT uid, foo FROM {my_table} WHERE uid IN (:uids)', array(':uids' => array_keys($users)));
|
||||
foreach ($result as $record) {
|
||||
$users[$record->uid]->foo = $record->foo;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Respond to user deletion.
|
||||
*
|
||||
* This hook is invoked from user_delete_multiple() before field_attach_delete()
|
||||
* is called and before users are actually removed from the database.
|
||||
*
|
||||
* Modules should additionally implement hook_user_cancel() to process stored
|
||||
* user data for other account cancellation methods.
|
||||
*
|
||||
* @param $account
|
||||
* The account that is being deleted.
|
||||
*
|
||||
* @see user_delete_multiple()
|
||||
*/
|
||||
function hook_user_delete($account) {
|
||||
db_delete('mytable')
|
||||
->condition('uid', $account->uid)
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Act on user account cancellations.
|
||||
*
|
||||
* This hook is invoked from user_cancel() before a user account is canceled.
|
||||
* Depending on the account cancellation method, the module should either do
|
||||
* nothing, unpublish content, or anonymize content. See user_cancel_methods()
|
||||
* for the list of default account cancellation methods provided by User module.
|
||||
* Modules may add further methods via hook_user_cancel_methods_alter().
|
||||
*
|
||||
* This hook is NOT invoked for the 'user_cancel_delete' account cancellation
|
||||
* method. To react on this method, implement hook_user_delete() instead.
|
||||
*
|
||||
* Expensive operations should be added to the global account cancellation batch
|
||||
* by using batch_set().
|
||||
*
|
||||
* @param $edit
|
||||
* The array of form values submitted by the user.
|
||||
* @param $account
|
||||
* The user object on which the operation is being performed.
|
||||
* @param $method
|
||||
* The account cancellation method.
|
||||
*
|
||||
* @see user_cancel_methods()
|
||||
* @see hook_user_cancel_methods_alter()
|
||||
*/
|
||||
function hook_user_cancel($edit, $account, $method) {
|
||||
switch ($method) {
|
||||
case 'user_cancel_block_unpublish':
|
||||
// Unpublish nodes (current revisions).
|
||||
module_load_include('inc', 'node', 'node.admin');
|
||||
$nodes = db_select('node', 'n')
|
||||
->fields('n', array('nid'))
|
||||
->condition('uid', $account->uid)
|
||||
->execute()
|
||||
->fetchCol();
|
||||
node_mass_update($nodes, array('status' => 0));
|
||||
break;
|
||||
|
||||
case 'user_cancel_reassign':
|
||||
// Anonymize nodes (current revisions).
|
||||
module_load_include('inc', 'node', 'node.admin');
|
||||
$nodes = db_select('node', 'n')
|
||||
->fields('n', array('nid'))
|
||||
->condition('uid', $account->uid)
|
||||
->execute()
|
||||
->fetchCol();
|
||||
node_mass_update($nodes, array('uid' => 0));
|
||||
// Anonymize old revisions.
|
||||
db_update('node_revision')
|
||||
->fields(array('uid' => 0))
|
||||
->condition('uid', $account->uid)
|
||||
->execute();
|
||||
// Clean history.
|
||||
db_delete('history')
|
||||
->condition('uid', $account->uid)
|
||||
->execute();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify account cancellation methods.
|
||||
*
|
||||
* By implementing this hook, modules are able to add, customize, or remove
|
||||
* account cancellation methods. All defined methods are turned into radio
|
||||
* button form elements by user_cancel_methods() after this hook is invoked.
|
||||
* The following properties can be defined for each method:
|
||||
* - title: The radio button's title.
|
||||
* - description: (optional) A description to display on the confirmation form
|
||||
* if the user is not allowed to select the account cancellation method. The
|
||||
* description is NOT used for the radio button, but instead should provide
|
||||
* additional explanation to the user seeking to cancel their account.
|
||||
* - access: (optional) A boolean value indicating whether the user can access
|
||||
* a method. If access is defined, the method cannot be configured as the
|
||||
* default method.
|
||||
*
|
||||
* @param $methods
|
||||
* An array containing user account cancellation methods, keyed by method id.
|
||||
*
|
||||
* @see user_cancel_methods()
|
||||
* @see user_cancel_confirm_form()
|
||||
*/
|
||||
function hook_user_cancel_methods_alter(&$methods) {
|
||||
// Limit access to disable account and unpublish content method.
|
||||
$methods['user_cancel_block_unpublish']['access'] = user_access('administer site configuration');
|
||||
|
||||
// Remove the content re-assigning method.
|
||||
unset($methods['user_cancel_reassign']);
|
||||
|
||||
// Add a custom zero-out method.
|
||||
$methods['mymodule_zero_out'] = array(
|
||||
'title' => t('Delete the account and remove all content.'),
|
||||
'description' => t('All your content will be replaced by empty strings.'),
|
||||
// access should be used for administrative methods only.
|
||||
'access' => user_access('access zero-out account cancellation method'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add mass user operations.
|
||||
*
|
||||
* This hook enables modules to inject custom operations into the mass operations
|
||||
* dropdown found at admin/people, by associating a callback function with
|
||||
* the operation, which is called when the form is submitted. The callback function
|
||||
* receives one initial argument, which is an array of the checked users.
|
||||
*
|
||||
* @return
|
||||
* An array of operations. Each operation is an associative array that may
|
||||
* contain the following key-value pairs:
|
||||
* - "label": Required. The label for the operation, displayed in the dropdown menu.
|
||||
* - "callback": Required. The function to call for the operation.
|
||||
* - "callback arguments": Optional. An array of additional arguments to pass to
|
||||
* the callback function.
|
||||
*
|
||||
*/
|
||||
function hook_user_operations() {
|
||||
$operations = array(
|
||||
'unblock' => array(
|
||||
'label' => t('Unblock the selected users'),
|
||||
'callback' => 'user_user_operations_unblock',
|
||||
),
|
||||
'block' => array(
|
||||
'label' => t('Block the selected users'),
|
||||
'callback' => 'user_user_operations_block',
|
||||
),
|
||||
'cancel' => array(
|
||||
'label' => t('Cancel the selected user accounts'),
|
||||
),
|
||||
);
|
||||
return $operations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a list of user settings or profile information categories.
|
||||
*
|
||||
* There are two steps to using hook_user_categories():
|
||||
* - Create the category with hook_user_categories().
|
||||
* - Display that category on the form ID of "user_profile_form" with
|
||||
* hook_form_FORM_ID_alter().
|
||||
*
|
||||
* Step one builds out the category but it won't be visible on your form until
|
||||
* you explicitly tell it to do so.
|
||||
*
|
||||
* The function in step two should contain the following code in order to
|
||||
* display your new category:
|
||||
* @code
|
||||
* if ($form['#user_category'] == 'mycategory') {
|
||||
* // Return your form here.
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @return
|
||||
* An array of associative arrays. Each inner array has elements:
|
||||
* - "name": The internal name of the category.
|
||||
* - "title": The human-readable, localized name of the category.
|
||||
* - "weight": An integer specifying the category's sort ordering.
|
||||
* - "access callback": Name of the access callback function to use to
|
||||
* determine whether the user can edit the category. Defaults to using
|
||||
* user_edit_access(). See hook_menu() for more information on access
|
||||
* callbacks.
|
||||
* - "access arguments": Arguments for the access callback function. Defaults
|
||||
* to array(1).
|
||||
*/
|
||||
function hook_user_categories() {
|
||||
return array(array(
|
||||
'name' => 'account',
|
||||
'title' => t('Account settings'),
|
||||
'weight' => 1,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* A user account is about to be created or updated.
|
||||
*
|
||||
* This hook is primarily intended for modules that want to store properties in
|
||||
* the serialized {users}.data column, which is automatically loaded whenever a
|
||||
* user account object is loaded, modules may add to $edit['data'] in order
|
||||
* to have their data serialized on save.
|
||||
*
|
||||
* @param $edit
|
||||
* The array of form values submitted by the user. Assign values to this
|
||||
* array to save changes in the database.
|
||||
* @param $account
|
||||
* The user object on which the operation is performed. Values assigned in
|
||||
* this object will not be saved in the database.
|
||||
* @param $category
|
||||
* The active category of user information being edited.
|
||||
*
|
||||
* @see hook_user_insert()
|
||||
* @see hook_user_update()
|
||||
*/
|
||||
function hook_user_presave(&$edit, $account, $category) {
|
||||
// Make sure that our form value 'mymodule_foo' is stored as
|
||||
// 'mymodule_bar' in the 'data' (serialized) column.
|
||||
if (isset($edit['mymodule_foo'])) {
|
||||
$edit['data']['mymodule_bar'] = $edit['mymodule_foo'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A user account was created.
|
||||
*
|
||||
* The module should save its custom additions to the user object into the
|
||||
* database.
|
||||
*
|
||||
* @param $edit
|
||||
* The array of form values submitted by the user.
|
||||
* @param $account
|
||||
* The user object on which the operation is being performed.
|
||||
* @param $category
|
||||
* The active category of user information being edited.
|
||||
*
|
||||
* @see hook_user_presave()
|
||||
* @see hook_user_update()
|
||||
*/
|
||||
function hook_user_insert(&$edit, $account, $category) {
|
||||
db_insert('mytable')
|
||||
->fields(array(
|
||||
'myfield' => $edit['myfield'],
|
||||
'uid' => $account->uid,
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* A user account was updated.
|
||||
*
|
||||
* Modules may use this hook to update their user data in a custom storage
|
||||
* after a user account has been updated.
|
||||
*
|
||||
* @param $edit
|
||||
* The array of form values submitted by the user.
|
||||
* @param $account
|
||||
* The user object on which the operation is performed.
|
||||
* @param $category
|
||||
* The active category of user information being edited.
|
||||
*
|
||||
* @see hook_user_presave()
|
||||
* @see hook_user_insert()
|
||||
*/
|
||||
function hook_user_update(&$edit, $account, $category) {
|
||||
db_insert('user_changes')
|
||||
->fields(array(
|
||||
'uid' => $account->uid,
|
||||
'changed' => time(),
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* The user just logged in.
|
||||
*
|
||||
* @param $edit
|
||||
* The array of form values submitted by the user.
|
||||
* @param $account
|
||||
* The user object on which the operation was just performed.
|
||||
*/
|
||||
function hook_user_login(&$edit, $account) {
|
||||
// If the user has a NULL time zone, notify them to set a time zone.
|
||||
if (!$account->timezone && variable_get('configurable_timezones', 1) && variable_get('empty_timezone_message', 0)) {
|
||||
drupal_set_message(t('Configure your <a href="@user-edit">account time zone setting</a>.', array('@user-edit' => url("user/$account->uid/edit", array('query' => drupal_get_destination(), 'fragment' => 'edit-timezone')))));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The user just logged out.
|
||||
*
|
||||
* Note that when this hook is invoked, the changes have not yet been written to
|
||||
* the database, because a database transaction is still in progress. The
|
||||
* transaction is not finalized until the save operation is entirely completed
|
||||
* and user_save() goes out of scope. You should not rely on data in the
|
||||
* database at this time as it is not updated yet. You should also note that any
|
||||
* write/update database queries executed from this hook are also not committed
|
||||
* immediately. Check user_save() and db_transaction() for more info.
|
||||
*
|
||||
* @param $account
|
||||
* The user object on which the operation was just performed.
|
||||
*/
|
||||
function hook_user_logout($account) {
|
||||
db_insert('logouts')
|
||||
->fields(array(
|
||||
'uid' => $account->uid,
|
||||
'time' => time(),
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* The user's account information is being displayed.
|
||||
*
|
||||
* The module should format its custom additions for display and add them to the
|
||||
* $account->content array.
|
||||
*
|
||||
* @param $account
|
||||
* The user object on which the operation is being performed.
|
||||
* @param $view_mode
|
||||
* View mode, e.g. 'full'.
|
||||
* @param $langcode
|
||||
* The language code used for rendering.
|
||||
*
|
||||
* @see hook_user_view_alter()
|
||||
* @see hook_entity_view()
|
||||
*/
|
||||
function hook_user_view($account, $view_mode, $langcode) {
|
||||
if (user_access('create blog content', $account)) {
|
||||
$account->content['summary']['blog'] = array(
|
||||
'#type' => 'user_profile_item',
|
||||
'#title' => t('Blog'),
|
||||
'#markup' => l(t('View recent blog entries'), "blog/$account->uid", array('attributes' => array('title' => t("Read !username's latest blog entries.", array('!username' => format_username($account)))))),
|
||||
'#attributes' => array('class' => array('blog')),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The user was built; the module may modify the structured content.
|
||||
*
|
||||
* This hook is called after the content has been assembled in a structured array
|
||||
* and may be used for doing processing which requires that the complete user
|
||||
* content structure has been built.
|
||||
*
|
||||
* If the module wishes to act on the rendered HTML of the user rather than the
|
||||
* structured content array, it may use this hook to add a #post_render callback.
|
||||
* Alternatively, it could also implement hook_preprocess_user_profile(). See
|
||||
* drupal_render() and theme() documentation respectively for details.
|
||||
*
|
||||
* @param $build
|
||||
* A renderable array representing the user.
|
||||
*
|
||||
* @see user_view()
|
||||
* @see hook_entity_view_alter()
|
||||
*/
|
||||
function hook_user_view_alter(&$build) {
|
||||
// Check for the existence of a field added by another module.
|
||||
if (isset($build['an_additional_field'])) {
|
||||
// Change its weight.
|
||||
$build['an_additional_field']['#weight'] = -10;
|
||||
}
|
||||
|
||||
// Add a #post_render callback to act on the rendered HTML of the user.
|
||||
$build['#post_render'][] = 'my_module_user_post_render';
|
||||
}
|
||||
|
||||
/**
|
||||
* Act on a user role being inserted or updated.
|
||||
*
|
||||
* Modules implementing this hook can act on the user role object before
|
||||
* it has been saved to the database.
|
||||
*
|
||||
* @param $role
|
||||
* A user role object.
|
||||
*
|
||||
* @see hook_user_role_insert()
|
||||
* @see hook_user_role_update()
|
||||
*/
|
||||
function hook_user_role_presave($role) {
|
||||
// Set a UUID for the user role if it doesn't already exist
|
||||
if (empty($role->uuid)) {
|
||||
$role->uuid = uuid_uuid();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Respond to creation of a new user role.
|
||||
*
|
||||
* Modules implementing this hook can act on the user role object when saved to
|
||||
* the database. It's recommended that you implement this hook if your module
|
||||
* adds additional data to user roles object. The module should save its custom
|
||||
* additions to the database.
|
||||
*
|
||||
* @param $role
|
||||
* A user role object.
|
||||
*/
|
||||
function hook_user_role_insert($role) {
|
||||
// Save extra fields provided by the module to user roles.
|
||||
db_insert('my_module_table')
|
||||
->fields(array(
|
||||
'rid' => $role->rid,
|
||||
'role_description' => $role->description,
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Respond to updates to a user role.
|
||||
*
|
||||
* Modules implementing this hook can act on the user role object when updated.
|
||||
* It's recommended that you implement this hook if your module adds additional
|
||||
* data to user roles object. The module should save its custom additions to
|
||||
* the database.
|
||||
*
|
||||
* @param $role
|
||||
* A user role object.
|
||||
*/
|
||||
function hook_user_role_update($role) {
|
||||
// Save extra fields provided by the module to user roles.
|
||||
db_merge('my_module_table')
|
||||
->key(array('rid' => $role->rid))
|
||||
->fields(array(
|
||||
'role_description' => $role->description
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Respond to user role deletion.
|
||||
*
|
||||
* This hook allows you act when a user role has been deleted.
|
||||
* If your module stores references to roles, it's recommended that you
|
||||
* implement this hook and delete existing instances of the deleted role
|
||||
* in your module database tables.
|
||||
*
|
||||
* @param $role
|
||||
* The $role object being deleted.
|
||||
*/
|
||||
function hook_user_role_delete($role) {
|
||||
// Delete existing instances of the deleted role.
|
||||
db_delete('my_module_table')
|
||||
->condition('rid', $role->rid)
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @} End of "addtogroup hooks".
|
||||
*/
|
102
modules/user/user.css
Normal file
102
modules/user/user.css
Normal file
|
@ -0,0 +1,102 @@
|
|||
|
||||
#permissions td.module {
|
||||
font-weight: bold;
|
||||
}
|
||||
#permissions td.permission {
|
||||
padding-left: 1.5em; /* LTR */
|
||||
}
|
||||
#permissions tr.odd .form-item,
|
||||
#permissions tr.even .form-item {
|
||||
white-space: normal;
|
||||
}
|
||||
#user-admin-settings fieldset .fieldset-description {
|
||||
font-size: 0.85em;
|
||||
padding-bottom: .5em;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override default textfield float to put the "Add role" button next to
|
||||
* the input textfield.
|
||||
*/
|
||||
#user-admin-roles td.edit-name {
|
||||
clear: both;
|
||||
}
|
||||
#user-admin-roles .form-item-name {
|
||||
float: left; /* LTR */
|
||||
margin-right: 1em; /* LTR */
|
||||
}
|
||||
|
||||
/**
|
||||
* Password strength indicator.
|
||||
*/
|
||||
.password-strength {
|
||||
width: 17em;
|
||||
float: right; /* LTR */
|
||||
margin-top: 1.4em;
|
||||
}
|
||||
.password-strength-title {
|
||||
display: inline;
|
||||
}
|
||||
.password-strength-text {
|
||||
float: right; /* LTR */
|
||||
font-weight: bold;
|
||||
}
|
||||
.password-indicator {
|
||||
background-color: #C4C4C4;
|
||||
height: 0.3em;
|
||||
width: 100%;
|
||||
}
|
||||
.password-indicator div {
|
||||
height: 100%;
|
||||
width: 0%;
|
||||
background-color: #47C965;
|
||||
}
|
||||
input.password-confirm,
|
||||
input.password-field {
|
||||
width: 16em;
|
||||
margin-bottom: 0.4em;
|
||||
}
|
||||
div.password-confirm {
|
||||
float: right; /* LTR */
|
||||
margin-top: 1.5em;
|
||||
visibility: hidden;
|
||||
width: 17em;
|
||||
}
|
||||
div.form-item div.password-suggestions {
|
||||
padding: 0.2em 0.5em;
|
||||
margin: 0.7em 0;
|
||||
width: 38.5em;
|
||||
border: 1px solid #B4B4B4;
|
||||
}
|
||||
div.password-suggestions ul {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.confirm-parent,
|
||||
.password-parent {
|
||||
clear: left; /* LTR */
|
||||
margin: 0;
|
||||
width: 36.3em;
|
||||
}
|
||||
|
||||
/* Generated by user.module but used by profile.module: */
|
||||
.profile {
|
||||
clear: both;
|
||||
margin: 1em 0;
|
||||
}
|
||||
.profile .user-picture {
|
||||
float: right; /* LTR */
|
||||
margin: 0 1em 1em 0; /* LTR */
|
||||
}
|
||||
.profile h3 {
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
.profile dl {
|
||||
margin: 0 0 1.5em 0;
|
||||
}
|
||||
.profile dt {
|
||||
margin: 0 0 0.2em 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
.profile dd {
|
||||
margin: 0 0 1em 0;
|
||||
}
|
16
modules/user/user.info
Normal file
16
modules/user/user.info
Normal file
|
@ -0,0 +1,16 @@
|
|||
name = User
|
||||
description = Manages the user registration and login system.
|
||||
package = Core
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
files[] = user.module
|
||||
files[] = user.test
|
||||
required = TRUE
|
||||
configure = admin/config/people
|
||||
stylesheets[all][] = user.css
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
927
modules/user/user.install
Normal file
927
modules/user/user.install
Normal file
|
@ -0,0 +1,927 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Install, update and uninstall functions for the user module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_schema().
|
||||
*/
|
||||
function user_schema() {
|
||||
$schema['authmap'] = array(
|
||||
'description' => 'Stores distributed authentication mapping.',
|
||||
'fields' => array(
|
||||
'aid' => array(
|
||||
'description' => 'Primary Key: Unique authmap ID.',
|
||||
'type' => 'serial',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
),
|
||||
'uid' => array(
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'description' => "User's {users}.uid.",
|
||||
),
|
||||
'authname' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 128,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => 'Unique authentication name.',
|
||||
),
|
||||
'module' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 128,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => 'Module which is controlling the authentication.',
|
||||
),
|
||||
),
|
||||
'unique keys' => array(
|
||||
'authname' => array('authname'),
|
||||
),
|
||||
'primary key' => array('aid'),
|
||||
'foreign keys' => array(
|
||||
'user' => array(
|
||||
'table' => 'users',
|
||||
'columns' => array('uid' => 'uid'),
|
||||
),
|
||||
),
|
||||
'indexes' => array(
|
||||
'uid_module' => array('uid', 'module'),
|
||||
),
|
||||
);
|
||||
|
||||
$schema['role_permission'] = array(
|
||||
'description' => 'Stores the permissions assigned to user roles.',
|
||||
'fields' => array(
|
||||
'rid' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'description' => 'Foreign Key: {role}.rid.',
|
||||
),
|
||||
'permission' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 128,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => 'A single permission granted to the role identified by rid.',
|
||||
),
|
||||
'module' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => "The module declaring the permission.",
|
||||
),
|
||||
),
|
||||
'primary key' => array('rid', 'permission'),
|
||||
'indexes' => array(
|
||||
'permission' => array('permission'),
|
||||
),
|
||||
'foreign keys' => array(
|
||||
'role' => array(
|
||||
'table' => 'role',
|
||||
'columns' => array('rid' => 'rid'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$schema['role'] = array(
|
||||
'description' => 'Stores user roles.',
|
||||
'fields' => array(
|
||||
'rid' => array(
|
||||
'type' => 'serial',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'description' => 'Primary Key: Unique role ID.',
|
||||
),
|
||||
'name' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 64,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => 'Unique role name.',
|
||||
'translatable' => TRUE,
|
||||
),
|
||||
'weight' => array(
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'description' => 'The weight of this role in listings and the user interface.',
|
||||
),
|
||||
),
|
||||
'unique keys' => array(
|
||||
'name' => array('name'),
|
||||
),
|
||||
'primary key' => array('rid'),
|
||||
'indexes' => array(
|
||||
'name_weight' => array('name', 'weight'),
|
||||
),
|
||||
);
|
||||
|
||||
// The table name here is plural, despite Drupal table naming standards,
|
||||
// because "user" is a reserved word in many databases.
|
||||
$schema['users'] = array(
|
||||
'description' => 'Stores user data.',
|
||||
'fields' => array(
|
||||
'uid' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'description' => 'Primary Key: Unique user ID.',
|
||||
'default' => 0,
|
||||
),
|
||||
'name' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 60,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => 'Unique user name.',
|
||||
),
|
||||
'pass' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 128,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => "User's password (hashed).",
|
||||
),
|
||||
'mail' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 254,
|
||||
'not null' => FALSE,
|
||||
'default' => '',
|
||||
'description' => "User's e-mail address.",
|
||||
),
|
||||
'theme' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => "User's default theme.",
|
||||
),
|
||||
'signature' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => "User's signature.",
|
||||
),
|
||||
'signature_format' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => FALSE,
|
||||
'description' => 'The {filter_format}.format of the signature.',
|
||||
),
|
||||
'created' => array(
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'description' => 'Timestamp for when user was created.',
|
||||
),
|
||||
'access' => array(
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'description' => 'Timestamp for previous time user accessed the site.',
|
||||
),
|
||||
'login' => array(
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'description' => "Timestamp for user's last login.",
|
||||
),
|
||||
'status' => array(
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'size' => 'tiny',
|
||||
'description' => 'Whether the user is active(1) or blocked(0).',
|
||||
),
|
||||
'timezone' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 32,
|
||||
'not null' => FALSE,
|
||||
'description' => "User's time zone.",
|
||||
),
|
||||
'language' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 12,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => "User's default language.",
|
||||
),
|
||||
'picture' => array(
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'description' => "Foreign key: {file_managed}.fid of user's picture.",
|
||||
),
|
||||
'init' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 254,
|
||||
'not null' => FALSE,
|
||||
'default' => '',
|
||||
'description' => 'E-mail address used for initial account creation.',
|
||||
),
|
||||
'data' => array(
|
||||
'type' => 'blob',
|
||||
'not null' => FALSE,
|
||||
'size' => 'big',
|
||||
'serialize' => TRUE,
|
||||
'description' => 'A serialized array of name value pairs that are related to the user. Any form values posted during user edit are stored and are loaded into the $user object during user_load(). Use of this field is discouraged and it will likely disappear in a future version of Drupal.',
|
||||
),
|
||||
),
|
||||
'indexes' => array(
|
||||
'access' => array('access'),
|
||||
'created' => array('created'),
|
||||
'mail' => array('mail'),
|
||||
'picture' => array('picture'),
|
||||
),
|
||||
'unique keys' => array(
|
||||
'name' => array('name'),
|
||||
),
|
||||
'primary key' => array('uid'),
|
||||
'foreign keys' => array(
|
||||
'signature_format' => array(
|
||||
'table' => 'filter_format',
|
||||
'columns' => array('signature_format' => 'format'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$schema['users_roles'] = array(
|
||||
'description' => 'Maps users to roles.',
|
||||
'fields' => array(
|
||||
'uid' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'description' => 'Primary Key: {users}.uid for user.',
|
||||
),
|
||||
'rid' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'description' => 'Primary Key: {role}.rid for role.',
|
||||
),
|
||||
),
|
||||
'primary key' => array('uid', 'rid'),
|
||||
'indexes' => array(
|
||||
'rid' => array('rid'),
|
||||
),
|
||||
'foreign keys' => array(
|
||||
'user' => array(
|
||||
'table' => 'users',
|
||||
'columns' => array('uid' => 'uid'),
|
||||
),
|
||||
'role' => array(
|
||||
'table' => 'role',
|
||||
'columns' => array('rid' => 'rid'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_install().
|
||||
*/
|
||||
function user_install() {
|
||||
// Insert a row for the anonymous user.
|
||||
db_insert('users')
|
||||
->fields(array(
|
||||
'uid' => 0,
|
||||
'name' => '',
|
||||
'mail' => '',
|
||||
))
|
||||
->execute();
|
||||
|
||||
// We need some placeholders here as name and mail are uniques and data is
|
||||
// presumed to be a serialized array. This will be changed by the settings
|
||||
// form in the installer.
|
||||
db_insert('users')
|
||||
->fields(array(
|
||||
'uid' => 1,
|
||||
'name' => 'placeholder-for-uid-1',
|
||||
'mail' => 'placeholder-for-uid-1',
|
||||
'created' => REQUEST_TIME,
|
||||
'status' => 1,
|
||||
'data' => NULL,
|
||||
))
|
||||
->execute();
|
||||
|
||||
// Built-in roles.
|
||||
$rid_anonymous = db_insert('role')
|
||||
->fields(array('name' => 'anonymous user', 'weight' => 0))
|
||||
->execute();
|
||||
$rid_authenticated = db_insert('role')
|
||||
->fields(array('name' => 'authenticated user', 'weight' => 1))
|
||||
->execute();
|
||||
|
||||
// Sanity check to ensure the anonymous and authenticated role IDs are the
|
||||
// same as the drupal defined constants. In certain situations, this will
|
||||
// not be true.
|
||||
if ($rid_anonymous != DRUPAL_ANONYMOUS_RID) {
|
||||
db_update('role')
|
||||
->fields(array('rid' => DRUPAL_ANONYMOUS_RID))
|
||||
->condition('rid', $rid_anonymous)
|
||||
->execute();
|
||||
}
|
||||
if ($rid_authenticated != DRUPAL_AUTHENTICATED_RID) {
|
||||
db_update('role')
|
||||
->fields(array('rid' => DRUPAL_AUTHENTICATED_RID))
|
||||
->condition('rid', $rid_authenticated)
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_update_dependencies().
|
||||
*/
|
||||
function user_update_dependencies() {
|
||||
// user_update_7006() updates data in the {role_permission} table, so it must
|
||||
// run after system_update_7007(), which populates that table.
|
||||
$dependencies['user'][7006] = array(
|
||||
'system' => 7007,
|
||||
);
|
||||
|
||||
// user_update_7010() needs to query the {filter_format} table to get a list
|
||||
// of existing text formats, so it must run after filter_update_7000(), which
|
||||
// creates that table.
|
||||
$dependencies['user'][7010] = array(
|
||||
'filter' => 7000,
|
||||
);
|
||||
|
||||
// user_update_7012() uses the file API and inserts records into the
|
||||
// {file_managed} table, so it therefore must run after system_update_7061(),
|
||||
// which inserts files with specific IDs into the table and therefore relies
|
||||
// on the table being empty (otherwise it would accidentally overwrite
|
||||
// existing records).
|
||||
$dependencies['user'][7012] = array(
|
||||
'system' => 7061,
|
||||
);
|
||||
|
||||
// user_update_7013() uses the file usage API, which relies on the
|
||||
// {file_usage} table, so it must run after system_update_7059(), which
|
||||
// creates that table.
|
||||
$dependencies['user'][7013] = array(
|
||||
'system' => 7059,
|
||||
);
|
||||
|
||||
return $dependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function: grant a set of permissions to a role during update.
|
||||
*
|
||||
* This function is valid for a database schema version 7000.
|
||||
*
|
||||
* @param $rid
|
||||
* The role ID.
|
||||
* @param $permissions
|
||||
* An array of permissions names.
|
||||
* @param $module
|
||||
* The name of the module defining the permissions.
|
||||
* @ingroup update_api
|
||||
*/
|
||||
function _update_7000_user_role_grant_permissions($rid, array $permissions, $module) {
|
||||
// Grant new permissions for the role.
|
||||
foreach ($permissions as $name) {
|
||||
db_merge('role_permission')
|
||||
->key(array(
|
||||
'rid' => $rid,
|
||||
'permission' => $name,
|
||||
))
|
||||
->fields(array(
|
||||
'module' => $module,
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @addtogroup updates-6.x-to-7.x
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Increase the length of the password field to accommodate better hashes.
|
||||
*
|
||||
* Also re-hashes all current passwords to improve security. This may be a
|
||||
* lengthy process, and is performed batch-wise.
|
||||
*/
|
||||
function user_update_7000(&$sandbox) {
|
||||
$sandbox['#finished'] = 0;
|
||||
// Lower than DRUPAL_HASH_COUNT to make the update run at a reasonable speed.
|
||||
$hash_count_log2 = 11;
|
||||
// Multi-part update.
|
||||
if (!isset($sandbox['user_from'])) {
|
||||
db_change_field('users', 'pass', 'pass', array('type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => ''));
|
||||
$sandbox['user_from'] = 0;
|
||||
$sandbox['user_count'] = db_query("SELECT COUNT(uid) FROM {users}")->fetchField();
|
||||
}
|
||||
else {
|
||||
require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
|
||||
// Hash again all current hashed passwords.
|
||||
$has_rows = FALSE;
|
||||
// Update this many per page load.
|
||||
$count = 1000;
|
||||
$result = db_query_range("SELECT uid, pass FROM {users} WHERE uid > 0 ORDER BY uid", $sandbox['user_from'], $count);
|
||||
foreach ($result as $account) {
|
||||
$has_rows = TRUE;
|
||||
|
||||
// If the $account->pass value is not a MD5 hash (a 32 character
|
||||
// hexadecimal string) then skip it.
|
||||
if (!preg_match('/^[0-9a-f]{32}$/', $account->pass)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$new_hash = user_hash_password($account->pass, $hash_count_log2);
|
||||
if ($new_hash) {
|
||||
// Indicate an updated password.
|
||||
$new_hash = 'U' . $new_hash;
|
||||
db_update('users')
|
||||
->fields(array('pass' => $new_hash))
|
||||
->condition('uid', $account->uid)
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
$sandbox['#finished'] = $sandbox['user_from']/$sandbox['user_count'];
|
||||
$sandbox['user_from'] += $count;
|
||||
if (!$has_rows) {
|
||||
$sandbox['#finished'] = 1;
|
||||
return t('User passwords rehashed to improve security');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the 'threshold', 'mode' and 'sort' columns from the {users} table.
|
||||
*
|
||||
* These fields were previously used to store per-user comment settings.
|
||||
*/
|
||||
|
||||
function user_update_7001() {
|
||||
db_drop_field('users', 'threshold');
|
||||
db_drop_field('users', 'mode');
|
||||
db_drop_field('users', 'sort');
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert user time zones from time zone offsets to time zone names.
|
||||
*/
|
||||
function user_update_7002(&$sandbox) {
|
||||
$sandbox['#finished'] = 0;
|
||||
|
||||
// Multi-part update.
|
||||
if (!isset($sandbox['user_from'])) {
|
||||
db_change_field('users', 'timezone', 'timezone', array('type' => 'varchar', 'length' => 32, 'not null' => FALSE));
|
||||
$sandbox['user_from'] = 0;
|
||||
$sandbox['user_count'] = db_query("SELECT COUNT(uid) FROM {users}")->fetchField();
|
||||
$sandbox['user_not_migrated'] = 0;
|
||||
}
|
||||
else {
|
||||
$timezones = system_time_zones();
|
||||
// Update this many per page load.
|
||||
$count = 10000;
|
||||
$contributed_date_module = db_field_exists('users', 'timezone_name');
|
||||
$contributed_event_module = db_field_exists('users', 'timezone_id');
|
||||
|
||||
$results = db_query_range("SELECT uid FROM {users} ORDER BY uid", $sandbox['user_from'], $count);
|
||||
foreach ($results as $account) {
|
||||
$timezone = NULL;
|
||||
// If the contributed Date module has created a users.timezone_name
|
||||
// column, use this data to set each user's time zone.
|
||||
if ($contributed_date_module) {
|
||||
$date_timezone = db_query("SELECT timezone_name FROM {users} WHERE uid = :uid", array(':uid' => $account->uid))->fetchField();
|
||||
if (isset($timezones[$date_timezone])) {
|
||||
$timezone = $date_timezone;
|
||||
}
|
||||
}
|
||||
// If the contributed Event module has stored user time zone information
|
||||
// use that information to update the user accounts.
|
||||
if (!$timezone && $contributed_event_module) {
|
||||
try {
|
||||
$event_timezone = db_query("SELECT t.name FROM {users} u LEFT JOIN {event_timezones} t ON u.timezone_id = t.timezone WHERE u.uid = :uid", array(':uid' => $account->uid))->fetchField();
|
||||
$event_timezone = str_replace(' ', '_', $event_timezone);
|
||||
if (isset($timezones[$event_timezone])) {
|
||||
$timezone = $event_timezone;
|
||||
}
|
||||
}
|
||||
catch (PDOException $e) {
|
||||
// Ignore error if event_timezones table does not exist or unexpected
|
||||
// schema found.
|
||||
}
|
||||
}
|
||||
if ($timezone) {
|
||||
db_update('users')
|
||||
->fields(array('timezone' => $timezone))
|
||||
->condition('uid', $account->uid)
|
||||
->execute();
|
||||
}
|
||||
else {
|
||||
$sandbox['user_not_migrated']++;
|
||||
db_update('users')
|
||||
->fields(array('timezone' => NULL))
|
||||
->condition('uid', $account->uid)
|
||||
->execute();
|
||||
}
|
||||
$sandbox['user_from']++;
|
||||
}
|
||||
|
||||
$sandbox['#finished'] = $sandbox['user_from'] / $sandbox['user_count'];
|
||||
if ($sandbox['user_from'] == $sandbox['user_count']) {
|
||||
if ($sandbox['user_not_migrated'] > 0) {
|
||||
variable_set('empty_timezone_message', 1);
|
||||
drupal_set_message(format_string('Some user time zones have been emptied and need to be set to the correct values. Use the new <a href="@config-url">time zone options</a> to choose whether to remind users at login to set the correct time zone.', array('@config-url' => url('admin/config/regional/settings'))), 'warning');
|
||||
}
|
||||
return t('Migrated user time zones');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user settings for cancelling user accounts.
|
||||
*
|
||||
* Prior to 7.x, users were not able to cancel their accounts. When
|
||||
* administrators deleted an account, all contents were assigned to uid 0,
|
||||
* which is the same as the 'user_cancel_reassign' method now.
|
||||
*/
|
||||
function user_update_7003() {
|
||||
// Set the default account cancellation method.
|
||||
variable_set('user_cancel_method', 'user_cancel_reassign');
|
||||
// Re-assign notification setting.
|
||||
if ($setting = variable_get('user_mail_status_deleted_notify', FALSE)) {
|
||||
variable_set('user_mail_status_canceled_notify', $setting);
|
||||
variable_del('user_mail_status_deleted_notify');
|
||||
}
|
||||
// Re-assign "Account deleted" mail strings to "Account canceled" mail.
|
||||
if ($setting = variable_get('user_mail_status_deleted_subject', FALSE)) {
|
||||
variable_set('user_mail_status_canceled_subject', $setting);
|
||||
variable_del('user_mail_status_deleted_subject');
|
||||
}
|
||||
if ($setting = variable_get('user_mail_status_deleted_body', FALSE)) {
|
||||
variable_set('user_mail_status_canceled_body', $setting);
|
||||
variable_del('user_mail_status_deleted_body');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the users table to allow longer e-mail addresses.
|
||||
*/
|
||||
function user_update_7005(&$sandbox) {
|
||||
$mail_field = array(
|
||||
'type' => 'varchar',
|
||||
'length' => 254,
|
||||
'not null' => FALSE,
|
||||
'default' => '',
|
||||
'description' => "User's e-mail address.",
|
||||
);
|
||||
$init_field = array(
|
||||
'type' => 'varchar',
|
||||
'length' => 254,
|
||||
'not null' => FALSE,
|
||||
'default' => '',
|
||||
'description' => 'E-mail address used for initial account creation.',
|
||||
);
|
||||
db_drop_index('users', 'mail');
|
||||
db_change_field('users', 'mail', 'mail', $mail_field, array('indexes' => array('mail' => array('mail'))));
|
||||
db_change_field('users', 'init', 'init', $init_field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add module data to {role_permission}.
|
||||
*/
|
||||
function user_update_7006(&$sandbox) {
|
||||
$module_field = array(
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => "The module declaring the permission.",
|
||||
);
|
||||
// Check that the field hasn't been updated in an aborted run of this
|
||||
// update.
|
||||
if (!db_field_exists('role_permission', 'module')) {
|
||||
// Add a new field for the fid.
|
||||
db_add_field('role_permission', 'module', $module_field);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a weight column to user roles.
|
||||
*/
|
||||
function user_update_7007() {
|
||||
db_add_field('role', 'weight', array('type' => 'int', 'not null' => TRUE, 'default' => 0));
|
||||
db_add_index('role', 'name_weight', array('name', 'weight'));
|
||||
}
|
||||
|
||||
/**
|
||||
* If 'user_register' variable was unset in Drupal 6, set it to be the same as
|
||||
* the Drupal 6 default setting.
|
||||
*/
|
||||
function user_update_7008() {
|
||||
if (!isset($GLOBALS['conf']['user_register'])) {
|
||||
// Set to the Drupal 6 default, "visitors can create accounts".
|
||||
variable_set('user_register', USER_REGISTER_VISITORS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts fields that store serialized variables from text to blob.
|
||||
*/
|
||||
function user_update_7009() {
|
||||
$spec = array(
|
||||
'type' => 'blob',
|
||||
'not null' => FALSE,
|
||||
'size' => 'big',
|
||||
'serialize' => TRUE,
|
||||
'description' => 'A serialized array of name value pairs that are related to the user. Any form values posted during user edit are stored and are loaded into the $user object during user_load(). Use of this field is discouraged and it will likely disappear in a future version of Drupal.',
|
||||
);
|
||||
db_change_field('users', 'data', 'data', $spec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the {user}.signature_format column.
|
||||
*/
|
||||
function user_update_7010() {
|
||||
// Update the database column to allow NULL values.
|
||||
db_change_field('users', 'signature_format', 'signature_format', array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => FALSE,
|
||||
'description' => 'The {filter_format}.format of the signature.',
|
||||
));
|
||||
|
||||
// Replace the signature format with NULL if the signature is empty and does
|
||||
// not already have a stored text format.
|
||||
//
|
||||
// In Drupal 6, "0" (the former FILTER_FORMAT_DEFAULT constant) could be used
|
||||
// to indicate this situation, but in Drupal 7, only NULL is supported. This
|
||||
// update therefore preserves the ability of user accounts which were never
|
||||
// given a signature (for example, if the site did not have user signatures
|
||||
// enabled, or if the user never edited their account information) to not
|
||||
// have a particular text format assumed for them the first time the
|
||||
// signature is edited.
|
||||
db_update('users')
|
||||
->fields(array('signature_format' => NULL))
|
||||
->condition('signature', '')
|
||||
->condition('signature_format', 0)
|
||||
->execute();
|
||||
|
||||
// There are a number of situations in which a Drupal 6 site could store
|
||||
// content with a nonexistent text format. This includes text formats that
|
||||
// had later been deleted, or non-empty content stored with a value of "0"
|
||||
// (the former FILTER_FORMAT_DEFAULT constant). Drupal 6 would filter this
|
||||
// content using whatever the site-wide default text format was at the moment
|
||||
// the text was being displayed.
|
||||
//
|
||||
// In Drupal 7, this behavior is no longer supported, and all content must be
|
||||
// stored with an explicit text format (or it will not be displayed when it
|
||||
// is filtered). Therefore, to preserve the behavior of the site after the
|
||||
// upgrade, we must replace all instances described above with the current
|
||||
// value of the (old) site-wide default format at the moment of the upgrade.
|
||||
$existing_formats = db_query("SELECT format FROM {filter_format}")->fetchCol();
|
||||
$default_format = variable_get('filter_default_format', 1);
|
||||
db_update('users')
|
||||
->fields(array('signature_format' => $default_format))
|
||||
->isNotNull('signature_format')
|
||||
->condition('signature_format', $existing_formats, 'NOT IN')
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Placeholder function.
|
||||
*
|
||||
* As a fix for user_update_7011() not updating email templates to use the new
|
||||
* tokens, user_update_7017() now targets email templates of Drupal 6 sites and
|
||||
* already upgraded sites.
|
||||
*/
|
||||
function user_update_7011() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the user's pictures to the {file_managed} table and make them managed
|
||||
* files.
|
||||
*/
|
||||
function user_update_7012(&$sandbox) {
|
||||
|
||||
$picture_field = array(
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'description' => "Foreign key: {file_managed}.fid of user's picture.",
|
||||
);
|
||||
|
||||
if (!isset($sandbox['progress'])) {
|
||||
// Check that the field hasn't been updated in an aborted run of this
|
||||
// update.
|
||||
if (!db_field_exists('users', 'picture_fid')) {
|
||||
// Add a new field for the fid.
|
||||
db_add_field('users', 'picture_fid', $picture_field);
|
||||
}
|
||||
|
||||
// Initialize batch update information.
|
||||
$sandbox['progress'] = 0;
|
||||
$sandbox['last_user_processed'] = -1;
|
||||
$sandbox['max'] = db_query("SELECT COUNT(*) FROM {users} WHERE picture <> ''")->fetchField();
|
||||
}
|
||||
|
||||
// As a batch operation move the photos into the {file_managed} table and
|
||||
// update the {users} records.
|
||||
$limit = 500;
|
||||
$result = db_query_range("SELECT uid, picture FROM {users} WHERE picture <> '' AND uid > :uid ORDER BY uid", 0, $limit, array(':uid' => $sandbox['last_user_processed']));
|
||||
foreach ($result as $user) {
|
||||
// Don't bother adding files that don't exist.
|
||||
if (file_exists($user->picture)) {
|
||||
|
||||
// Check if the file already exists.
|
||||
$files = file_load_multiple(array(), array('uri' => $user->picture));
|
||||
if (count($files)) {
|
||||
$file = reset($files);
|
||||
}
|
||||
else {
|
||||
// Create a file object.
|
||||
$file = new stdClass();
|
||||
$file->uri = $user->picture;
|
||||
$file->filename = drupal_basename($file->uri);
|
||||
$file->filemime = file_get_mimetype($file->uri);
|
||||
$file->uid = $user->uid;
|
||||
$file->status = FILE_STATUS_PERMANENT;
|
||||
$file = file_save($file);
|
||||
}
|
||||
|
||||
db_update('users')
|
||||
->fields(array('picture_fid' => $file->fid))
|
||||
->condition('uid', $user->uid)
|
||||
->execute();
|
||||
}
|
||||
|
||||
// Update our progress information for the batch update.
|
||||
$sandbox['progress']++;
|
||||
$sandbox['last_user_processed'] = $user->uid;
|
||||
}
|
||||
|
||||
// Indicate our current progress to the batch update system. If there's no
|
||||
// max value then there's nothing to update and we're finished.
|
||||
$sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['progress'] / $sandbox['max']);
|
||||
|
||||
// When we're finished, drop the old picture field and rename the new one to
|
||||
// replace it.
|
||||
if (isset($sandbox['#finished']) && $sandbox['#finished'] == 1) {
|
||||
db_drop_field('users', 'picture');
|
||||
db_change_field('users', 'picture_fid', 'picture', $picture_field);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add user module file usage entries.
|
||||
*/
|
||||
function user_update_7013(&$sandbox) {
|
||||
if (!isset($sandbox['progress'])) {
|
||||
// Initialize batch update information.
|
||||
$sandbox['progress'] = 0;
|
||||
$sandbox['last_uid_processed'] = -1;
|
||||
$sandbox['max'] = db_query("SELECT COUNT(*) FROM {users} u WHERE u.picture <> 0")->fetchField();
|
||||
}
|
||||
|
||||
// Add usage entries for the user picture files.
|
||||
$limit = 500;
|
||||
$result = db_query_range('SELECT f.*, u.uid as user_uid FROM {users} u INNER JOIN {file_managed} f ON u.picture = f.fid WHERE u.picture <> 0 AND u.uid > :uid ORDER BY u.uid', 0, $limit, array(':uid' => $sandbox['last_uid_processed']))->fetchAllAssoc('fid', PDO::FETCH_ASSOC);
|
||||
foreach ($result as $row) {
|
||||
$uid = $row['user_uid'];
|
||||
$file = (object) $row;
|
||||
file_usage_add($file, 'user', 'user', $uid);
|
||||
|
||||
// Update our progress information for the batch update.
|
||||
$sandbox['progress']++;
|
||||
$sandbox['last_uid_processed'] = $uid;
|
||||
}
|
||||
|
||||
// Indicate our current progress to the batch update system.
|
||||
$sandbox['#finished'] = empty($sandbox['max']) || ($sandbox['progress'] / $sandbox['max']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename the 'post comments without approval' permission.
|
||||
*
|
||||
* In Drupal 7, this permission has been renamed to 'skip comment approval'.
|
||||
*/
|
||||
function user_update_7014() {
|
||||
db_update('role_permission')
|
||||
->fields(array('permission' => 'skip comment approval'))
|
||||
->condition('permission', 'post comments without approval')
|
||||
->execute();
|
||||
|
||||
return t("Renamed the 'post comments without approval' permission to 'skip comment approval'.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Change {users}.signature_format into varchar.
|
||||
*/
|
||||
function user_update_7015() {
|
||||
db_change_field('users', 'signature_format', 'signature_format', array(
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => FALSE,
|
||||
'description' => 'The {filter_format}.format of the signature.',
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @} End of "addtogroup updates-6.x-to-7.x".
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup updates-7.x-extra
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Update the database to match the schema.
|
||||
*/
|
||||
function user_update_7016() {
|
||||
// Add field default.
|
||||
db_change_field('users', 'uid', 'uid', array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update email templates to use new tokens.
|
||||
*
|
||||
* This function upgrades customized email templates from the old !token format
|
||||
* to the new core tokens format. Additionally, in Drupal 7 we no longer e-mail
|
||||
* plain text passwords to users, and there is no token for a plain text
|
||||
* password in the new token system. Therefore, it also modifies any saved
|
||||
* templates using the old '!password' token such that the token is removed, and
|
||||
* displays a warning to users that they may need to go and modify the wording
|
||||
* of their templates.
|
||||
*/
|
||||
function user_update_7017() {
|
||||
$message = '';
|
||||
|
||||
$tokens = array(
|
||||
'!site' => '[site:name]',
|
||||
'!username' => '[user:name]',
|
||||
'!mailto' => '[user:mail]',
|
||||
'!login_uri' => '[site:login-url]',
|
||||
'!uri_brief' => '[site:url-brief]',
|
||||
'!edit_uri' => '[user:edit-url]',
|
||||
'!login_url' => '[user:one-time-login-url]',
|
||||
'!uri' => '[site:url]',
|
||||
'!date' => '[date:medium]',
|
||||
'!password' => '',
|
||||
);
|
||||
|
||||
$result = db_select('variable', 'v')
|
||||
->fields('v', array('name'))
|
||||
->condition('name', db_like('user_mail_') . '%', 'LIKE')
|
||||
->execute();
|
||||
|
||||
foreach ($result as $row) {
|
||||
// Use variable_get() to get the unserialized value for free.
|
||||
if ($value = variable_get($row->name, FALSE)) {
|
||||
|
||||
if (empty($message) && (strpos($value, '!password') !== FALSE)) {
|
||||
$message = t('The ability to send users their passwords in plain text has been removed in Drupal 7. Your existing email templates have been modified to remove it. You should <a href="@template-url">review these templates</a> to make sure they read properly.', array('@template-url' => url('admin/config/people/accounts')));
|
||||
}
|
||||
|
||||
variable_set($row->name, str_replace(array_keys($tokens), $tokens, $value));
|
||||
}
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure there is an index on {users}.picture.
|
||||
*/
|
||||
function user_update_7018() {
|
||||
if (!db_index_exists('users', 'picture')) {
|
||||
db_add_index('users', 'picture', array('picture'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure there is a combined index on {authmap}.uid and {authmap}.module.
|
||||
*/
|
||||
function user_update_7019() {
|
||||
// Check first in case it was already added manually.
|
||||
if (!db_index_exists('authmap', 'uid_module')) {
|
||||
db_add_index('authmap', 'uid_module', array('uid', 'module'));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @} End of "addtogroup updates-7.x-extra".
|
||||
*/
|
198
modules/user/user.js
Normal file
198
modules/user/user.js
Normal file
|
@ -0,0 +1,198 @@
|
|||
(function ($) {
|
||||
|
||||
/**
|
||||
* Attach handlers to evaluate the strength of any password fields and to check
|
||||
* that its confirmation is correct.
|
||||
*/
|
||||
Drupal.behaviors.password = {
|
||||
attach: function (context, settings) {
|
||||
var translate = settings.password;
|
||||
$('input.password-field', context).once('password', function () {
|
||||
var passwordInput = $(this);
|
||||
var innerWrapper = $(this).parent();
|
||||
var outerWrapper = $(this).parent().parent();
|
||||
|
||||
// Add identifying class to password element parent.
|
||||
innerWrapper.addClass('password-parent');
|
||||
|
||||
// Add the password confirmation layer.
|
||||
$('input.password-confirm', outerWrapper).parent().prepend('<div class="password-confirm">' + translate['confirmTitle'] + ' <span></span></div>').addClass('confirm-parent');
|
||||
var confirmInput = $('input.password-confirm', outerWrapper);
|
||||
var confirmResult = $('div.password-confirm', outerWrapper);
|
||||
var confirmChild = $('span', confirmResult);
|
||||
|
||||
// Add the description box.
|
||||
var passwordMeter = '<div class="password-strength"><div class="password-strength-text" aria-live="assertive"></div><div class="password-strength-title">' + translate['strengthTitle'] + '</div><div class="password-indicator"><div class="indicator"></div></div></div>';
|
||||
$(confirmInput).parent().after('<div class="password-suggestions description"></div>');
|
||||
$(innerWrapper).prepend(passwordMeter);
|
||||
var passwordDescription = $('div.password-suggestions', outerWrapper).hide();
|
||||
|
||||
// Check the password strength.
|
||||
var passwordCheck = function () {
|
||||
|
||||
// Evaluate the password strength.
|
||||
var result = Drupal.evaluatePasswordStrength(passwordInput.val(), settings.password);
|
||||
|
||||
// Update the suggestions for how to improve the password.
|
||||
if (passwordDescription.html() != result.message) {
|
||||
passwordDescription.html(result.message);
|
||||
}
|
||||
|
||||
// Only show the description box if there is a weakness in the password.
|
||||
if (result.strength == 100) {
|
||||
passwordDescription.hide();
|
||||
}
|
||||
else {
|
||||
passwordDescription.show();
|
||||
}
|
||||
|
||||
// Adjust the length of the strength indicator.
|
||||
$(innerWrapper).find('.indicator').css('width', result.strength + '%');
|
||||
|
||||
// Update the strength indication text.
|
||||
$(innerWrapper).find('.password-strength-text').html(result.indicatorText);
|
||||
|
||||
passwordCheckMatch();
|
||||
};
|
||||
|
||||
// Check that password and confirmation inputs match.
|
||||
var passwordCheckMatch = function () {
|
||||
|
||||
if (confirmInput.val()) {
|
||||
var success = passwordInput.val() === confirmInput.val();
|
||||
|
||||
// Show the confirm result.
|
||||
confirmResult.css({ visibility: 'visible' });
|
||||
|
||||
// Remove the previous styling if any exists.
|
||||
if (this.confirmClass) {
|
||||
confirmChild.removeClass(this.confirmClass);
|
||||
}
|
||||
|
||||
// Fill in the success message and set the class accordingly.
|
||||
var confirmClass = success ? 'ok' : 'error';
|
||||
confirmChild.html(translate['confirm' + (success ? 'Success' : 'Failure')]).addClass(confirmClass);
|
||||
this.confirmClass = confirmClass;
|
||||
}
|
||||
else {
|
||||
confirmResult.css({ visibility: 'hidden' });
|
||||
}
|
||||
};
|
||||
|
||||
// Monitor keyup and blur events.
|
||||
// Blur must be used because a mouse paste does not trigger keyup.
|
||||
passwordInput.keyup(passwordCheck).focus(passwordCheck).blur(passwordCheck);
|
||||
confirmInput.keyup(passwordCheckMatch).blur(passwordCheckMatch);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Evaluate the strength of a user's password.
|
||||
*
|
||||
* Returns the estimated strength and the relevant output message.
|
||||
*/
|
||||
Drupal.evaluatePasswordStrength = function (password, translate) {
|
||||
password = $.trim(password);
|
||||
|
||||
var weaknesses = 0, strength = 100, msg = [];
|
||||
|
||||
var hasLowercase = /[a-z]+/.test(password);
|
||||
var hasUppercase = /[A-Z]+/.test(password);
|
||||
var hasNumbers = /[0-9]+/.test(password);
|
||||
var hasPunctuation = /[^a-zA-Z0-9]+/.test(password);
|
||||
|
||||
// If there is a username edit box on the page, compare password to that, otherwise
|
||||
// use value from the database.
|
||||
var usernameBox = $('input.username');
|
||||
var username = (usernameBox.length > 0) ? usernameBox.val() : translate.username;
|
||||
|
||||
// Lose 5 points for every character less than 6, plus a 30 point penalty.
|
||||
if (password.length < 6) {
|
||||
msg.push(translate.tooShort);
|
||||
strength -= ((6 - password.length) * 5) + 30;
|
||||
}
|
||||
|
||||
// Count weaknesses.
|
||||
if (!hasLowercase) {
|
||||
msg.push(translate.addLowerCase);
|
||||
weaknesses++;
|
||||
}
|
||||
if (!hasUppercase) {
|
||||
msg.push(translate.addUpperCase);
|
||||
weaknesses++;
|
||||
}
|
||||
if (!hasNumbers) {
|
||||
msg.push(translate.addNumbers);
|
||||
weaknesses++;
|
||||
}
|
||||
if (!hasPunctuation) {
|
||||
msg.push(translate.addPunctuation);
|
||||
weaknesses++;
|
||||
}
|
||||
|
||||
// Apply penalty for each weakness (balanced against length penalty).
|
||||
switch (weaknesses) {
|
||||
case 1:
|
||||
strength -= 12.5;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
strength -= 25;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
strength -= 40;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
strength -= 40;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if password is the same as the username.
|
||||
if (password !== '' && password.toLowerCase() === username.toLowerCase()) {
|
||||
msg.push(translate.sameAsUsername);
|
||||
// Passwords the same as username are always very weak.
|
||||
strength = 5;
|
||||
}
|
||||
|
||||
// Based on the strength, work out what text should be shown by the password strength meter.
|
||||
if (strength < 60) {
|
||||
indicatorText = translate.weak;
|
||||
} else if (strength < 70) {
|
||||
indicatorText = translate.fair;
|
||||
} else if (strength < 80) {
|
||||
indicatorText = translate.good;
|
||||
} else if (strength <= 100) {
|
||||
indicatorText = translate.strong;
|
||||
}
|
||||
|
||||
// Assemble the final message.
|
||||
msg = translate.hasWeaknesses + '<ul><li>' + msg.join('</li><li>') + '</li></ul>';
|
||||
return { strength: strength, message: msg, indicatorText: indicatorText };
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Field instance settings screen: force the 'Display on registration form'
|
||||
* checkbox checked whenever 'Required' is checked.
|
||||
*/
|
||||
Drupal.behaviors.fieldUserRegistration = {
|
||||
attach: function (context, settings) {
|
||||
var $checkbox = $('form#field-ui-field-edit-form input#edit-instance-settings-user-register-form');
|
||||
|
||||
if ($checkbox.length) {
|
||||
$('input#edit-instance-required', context).once('user-register-form-checkbox', function () {
|
||||
$(this).bind('change', function (e) {
|
||||
if ($(this).attr('checked')) {
|
||||
$checkbox.attr('checked', true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery);
|
4085
modules/user/user.module
Normal file
4085
modules/user/user.module
Normal file
File diff suppressed because it is too large
Load diff
601
modules/user/user.pages.inc
Normal file
601
modules/user/user.pages.inc
Normal file
|
@ -0,0 +1,601 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* User page callback file for the user module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Menu callback; Retrieve a JSON object containing autocomplete suggestions for existing users.
|
||||
*/
|
||||
function user_autocomplete($string = '') {
|
||||
$matches = array();
|
||||
if ($string) {
|
||||
$result = db_select('users')->fields('users', array('name'))->condition('name', db_like($string) . '%', 'LIKE')->range(0, 10)->execute();
|
||||
foreach ($result as $user) {
|
||||
$matches[$user->name] = check_plain($user->name);
|
||||
}
|
||||
}
|
||||
|
||||
drupal_json_output($matches);
|
||||
}
|
||||
|
||||
/**
|
||||
* Form builder; Request a password reset.
|
||||
*
|
||||
* @ingroup forms
|
||||
* @see user_pass_validate()
|
||||
* @see user_pass_submit()
|
||||
*/
|
||||
function user_pass() {
|
||||
global $user;
|
||||
|
||||
$form['name'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Username or e-mail address'),
|
||||
'#size' => 60,
|
||||
'#maxlength' => max(USERNAME_MAX_LENGTH, EMAIL_MAX_LENGTH),
|
||||
'#required' => TRUE,
|
||||
'#default_value' => isset($_GET['name']) ? $_GET['name'] : '',
|
||||
);
|
||||
// Allow logged in users to request this also.
|
||||
if ($user->uid > 0) {
|
||||
$form['name']['#type'] = 'value';
|
||||
$form['name']['#value'] = $user->mail;
|
||||
$form['mail'] = array(
|
||||
'#prefix' => '<p>',
|
||||
// As of https://www.drupal.org/node/889772 the user no longer must log
|
||||
// out (if they are still logged in when using the password reset link,
|
||||
// they will be logged out automatically then), but this text is kept as
|
||||
// is to avoid breaking translations as well as to encourage the user to
|
||||
// log out manually at a time of their own choosing (when it will not
|
||||
// interrupt anything else they may have been in the middle of doing).
|
||||
'#markup' => t('Password reset instructions will be mailed to %email. You must log out to use the password reset link in the e-mail.', array('%email' => $user->mail)),
|
||||
'#suffix' => '</p>',
|
||||
);
|
||||
}
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit'] = array('#type' => 'submit', '#value' => t('E-mail new password'));
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form validation handler for user_pass().
|
||||
*
|
||||
* @see user_pass_submit()
|
||||
*/
|
||||
function user_pass_validate($form, &$form_state) {
|
||||
$name = trim($form_state['values']['name']);
|
||||
// Try to load by email.
|
||||
$users = user_load_multiple(array(), array('mail' => $name, 'status' => '1'));
|
||||
$account = reset($users);
|
||||
if (!$account) {
|
||||
// No success, try to load by name.
|
||||
$users = user_load_multiple(array(), array('name' => $name, 'status' => '1'));
|
||||
$account = reset($users);
|
||||
}
|
||||
if (isset($account->uid)) {
|
||||
form_set_value(array('#parents' => array('account')), $account, $form_state);
|
||||
}
|
||||
else {
|
||||
form_set_error('name', t('Sorry, %name is not recognized as a user name or an e-mail address.', array('%name' => $name)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Form submission handler for user_pass().
|
||||
*
|
||||
* @see user_pass_validate()
|
||||
*/
|
||||
function user_pass_submit($form, &$form_state) {
|
||||
global $language;
|
||||
|
||||
$account = $form_state['values']['account'];
|
||||
// Mail one time login URL and instructions using current language.
|
||||
$mail = _user_mail_notify('password_reset', $account, $language);
|
||||
if (!empty($mail)) {
|
||||
watchdog('user', 'Password reset instructions mailed to %name at %email.', array('%name' => $account->name, '%email' => $account->mail));
|
||||
drupal_set_message(t('Further instructions have been sent to your e-mail address.'));
|
||||
}
|
||||
|
||||
$form_state['redirect'] = 'user';
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback; process one time login link and redirects to the user page on success.
|
||||
*/
|
||||
function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $action = NULL) {
|
||||
global $user;
|
||||
|
||||
// When processing the one-time login link, we have to make sure that a user
|
||||
// isn't already logged in.
|
||||
if ($user->uid) {
|
||||
// The existing user is already logged in. Log them out and reload the
|
||||
// current page so the password reset process can continue.
|
||||
if ($user->uid == $uid) {
|
||||
// Preserve the current destination (if any) and ensure the redirect goes
|
||||
// back to the current page; any custom destination set in
|
||||
// hook_user_logout() and intended for regular logouts would not be
|
||||
// appropriate here.
|
||||
$destination = array();
|
||||
if (isset($_GET['destination'])) {
|
||||
$destination = drupal_get_destination();
|
||||
}
|
||||
user_logout_current_user();
|
||||
unset($_GET['destination']);
|
||||
drupal_goto(current_path(), array('query' => drupal_get_query_parameters() + $destination));
|
||||
}
|
||||
// A different user is already logged in on the computer.
|
||||
else {
|
||||
$reset_link_account = user_load($uid);
|
||||
if (!empty($reset_link_account)) {
|
||||
drupal_set_message(t('Another user (%other_user) is already logged into the site on this computer, but you tried to use a one-time link for user %resetting_user. Please <a href="!logout">logout</a> and try using the link again.',
|
||||
array('%other_user' => $user->name, '%resetting_user' => $reset_link_account->name, '!logout' => url('user/logout'))), 'warning');
|
||||
} else {
|
||||
// Invalid one-time link specifies an unknown user.
|
||||
drupal_set_message(t('The one-time login link you clicked is invalid.'), 'error');
|
||||
}
|
||||
drupal_goto();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Time out, in seconds, until login URL expires. Defaults to 24 hours =
|
||||
// 86400 seconds.
|
||||
$timeout = variable_get('user_password_reset_timeout', 86400);
|
||||
$current = REQUEST_TIME;
|
||||
// Some redundant checks for extra security ?
|
||||
$users = user_load_multiple(array($uid), array('status' => '1'));
|
||||
if ($timestamp <= $current && $account = reset($users)) {
|
||||
// No time out for first time login.
|
||||
if ($account->login && $current - $timestamp > $timeout) {
|
||||
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.'), 'error');
|
||||
drupal_goto('user/password');
|
||||
}
|
||||
elseif ($account->uid && $timestamp >= $account->login && $timestamp <= $current && $hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid)) {
|
||||
// First stage is a confirmation form, then login
|
||||
if ($action == 'login') {
|
||||
// Set the new user.
|
||||
$user = $account;
|
||||
// user_login_finalize() also updates the login timestamp of the
|
||||
// user, which invalidates further use of the one-time login link.
|
||||
user_login_finalize();
|
||||
watchdog('user', 'User %name used one-time login link at time %timestamp.', array('%name' => $account->name, '%timestamp' => $timestamp));
|
||||
drupal_set_message(t('You have just used your one-time login link. It is no longer necessary to use this link to log in. Please change your password.'));
|
||||
// Let the user's password be changed without the current password check.
|
||||
$token = drupal_random_key();
|
||||
$_SESSION['pass_reset_' . $user->uid] = $token;
|
||||
drupal_goto('user/' . $user->uid . '/edit', array('query' => array('pass-reset-token' => $token)));
|
||||
}
|
||||
else {
|
||||
$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 log in to the site and change your password.</p>', array('%user_name' => $account->name, '%expiration_date' => format_date($timestamp + $timeout))));
|
||||
$form['help'] = array('#markup' => '<p>' . t('This login can be used only once.') . '</p>');
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Log in'));
|
||||
$form['#action'] = url("user/reset/$uid/$timestamp/$hashed_pass/login");
|
||||
return $form;
|
||||
}
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.'), 'error');
|
||||
drupal_goto('user/password');
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Deny access, no more clues.
|
||||
// Everything will be in the watchdog's URL for the administrator to check.
|
||||
drupal_access_denied();
|
||||
drupal_exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback; logs the current user out, and redirects to the home page.
|
||||
*/
|
||||
function user_logout() {
|
||||
user_logout_current_user();
|
||||
drupal_goto();
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the current user out.
|
||||
*/
|
||||
function user_logout_current_user() {
|
||||
global $user;
|
||||
|
||||
watchdog('user', 'Session closed for %name.', array('%name' => $user->name));
|
||||
|
||||
module_invoke_all('user_logout', $user);
|
||||
|
||||
// Destroy the current session, and reset $user to the anonymous user.
|
||||
session_destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process variables for user-profile.tpl.php.
|
||||
*
|
||||
* @param array $variables
|
||||
* An associative array containing:
|
||||
* - elements: An associative array containing the user information and any
|
||||
* fields attached to the user. Properties used:
|
||||
* - #account: The user account of the profile being viewed.
|
||||
*
|
||||
* @see user-profile.tpl.php
|
||||
*/
|
||||
function template_preprocess_user_profile(&$variables) {
|
||||
$account = $variables['elements']['#account'];
|
||||
|
||||
// Helpful $user_profile variable for templates.
|
||||
foreach (element_children($variables['elements']) as $key) {
|
||||
$variables['user_profile'][$key] = $variables['elements'][$key];
|
||||
}
|
||||
|
||||
// Preprocess fields.
|
||||
field_attach_preprocess('user', $account, $variables['elements'], $variables);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process variables for user-profile-item.tpl.php.
|
||||
*
|
||||
* The $variables array contains the following arguments:
|
||||
* - $element
|
||||
*
|
||||
* @see user-profile-item.tpl.php
|
||||
*/
|
||||
function template_preprocess_user_profile_item(&$variables) {
|
||||
$variables['title'] = $variables['element']['#title'];
|
||||
$variables['value'] = $variables['element']['#markup'];
|
||||
$variables['attributes'] = '';
|
||||
if (isset($variables['element']['#attributes'])) {
|
||||
$variables['attributes'] = drupal_attributes($variables['element']['#attributes']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process variables for user-profile-category.tpl.php.
|
||||
*
|
||||
* The $variables array contains the following arguments:
|
||||
* - $element
|
||||
*
|
||||
* @see user-profile-category.tpl.php
|
||||
*/
|
||||
function template_preprocess_user_profile_category(&$variables) {
|
||||
$variables['title'] = check_plain($variables['element']['#title']);
|
||||
$variables['profile_items'] = $variables['element']['#children'];
|
||||
$variables['attributes'] = '';
|
||||
if (isset($variables['element']['#attributes'])) {
|
||||
$variables['attributes'] = drupal_attributes($variables['element']['#attributes']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Form builder; edit a user account or one of their profile categories.
|
||||
*
|
||||
* @ingroup forms
|
||||
* @see user_account_form()
|
||||
* @see user_account_form_validate()
|
||||
* @see user_profile_form_validate()
|
||||
* @see user_profile_form_submit()
|
||||
* @see user_cancel_confirm_form_submit()
|
||||
*/
|
||||
function user_profile_form($form, &$form_state, $account, $category = 'account') {
|
||||
global $user;
|
||||
|
||||
// During initial form build, add the entity to the form state for use during
|
||||
// form building and processing. During a rebuild, use what is in the form
|
||||
// state.
|
||||
if (!isset($form_state['user'])) {
|
||||
$form_state['user'] = $account;
|
||||
}
|
||||
else {
|
||||
$account = $form_state['user'];
|
||||
}
|
||||
|
||||
// @todo Legacy support. Modules are encouraged to access the entity using
|
||||
// $form_state. Remove in Drupal 8.
|
||||
$form['#user'] = $account;
|
||||
$form['#user_category'] = $category;
|
||||
|
||||
if ($category == 'account') {
|
||||
user_account_form($form, $form_state);
|
||||
// Attach field widgets.
|
||||
$langcode = entity_language('user', $account);
|
||||
field_attach_form('user', $account, $form, $form_state, $langcode);
|
||||
}
|
||||
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Save'),
|
||||
);
|
||||
if ($category == 'account') {
|
||||
$form['actions']['cancel'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Cancel account'),
|
||||
'#submit' => array('user_edit_cancel_submit'),
|
||||
'#access' => $account->uid > 1 && (($account->uid == $user->uid && user_access('cancel account')) || user_access('administer users')),
|
||||
);
|
||||
}
|
||||
|
||||
$form['#validate'][] = 'user_profile_form_validate';
|
||||
// Add the final user profile form submit handler.
|
||||
$form['#submit'][] = 'user_profile_form_submit';
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form validation handler for user_profile_form().
|
||||
*
|
||||
* @see user_profile_form_submit()
|
||||
*/
|
||||
function user_profile_form_validate($form, &$form_state) {
|
||||
entity_form_field_validate('user', $form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Form submission handler for user_profile_form().
|
||||
*
|
||||
* @see user_profile_form_validate()
|
||||
*/
|
||||
function user_profile_form_submit($form, &$form_state) {
|
||||
$account = $form_state['user'];
|
||||
$category = $form['#user_category'];
|
||||
// Remove unneeded values.
|
||||
form_state_values_clean($form_state);
|
||||
|
||||
// Before updating the account entity, keep an unchanged copy for use with
|
||||
// user_save() later. This is necessary for modules implementing the user
|
||||
// hooks to be able to react on changes by comparing the values of $account
|
||||
// and $edit.
|
||||
$account_unchanged = clone $account;
|
||||
|
||||
entity_form_submit_build_entity('user', $account, $form, $form_state);
|
||||
|
||||
// Populate $edit with the properties of $account, which have been edited on
|
||||
// this form by taking over all values, which appear in the form values too.
|
||||
$edit = array_intersect_key((array) $account, $form_state['values']);
|
||||
|
||||
user_save($account_unchanged, $edit, $category);
|
||||
$form_state['values']['uid'] = $account->uid;
|
||||
|
||||
if ($category == 'account' && !empty($edit['pass'])) {
|
||||
// Remove the password reset tag since a new password was saved.
|
||||
unset($_SESSION['pass_reset_'. $account->uid]);
|
||||
}
|
||||
// Clear the page cache because pages can contain usernames and/or profile information:
|
||||
cache_clear_all();
|
||||
|
||||
drupal_set_message(t('The changes have been saved.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit function for the 'Cancel account' button on the user edit form.
|
||||
*/
|
||||
function user_edit_cancel_submit($form, &$form_state) {
|
||||
$destination = array();
|
||||
if (isset($_GET['destination'])) {
|
||||
$destination = drupal_get_destination();
|
||||
unset($_GET['destination']);
|
||||
}
|
||||
// Note: We redirect from user/uid/edit to user/uid/cancel to make the tabs disappear.
|
||||
$form_state['redirect'] = array("user/" . $form['#user']->uid . "/cancel", array('query' => $destination));
|
||||
}
|
||||
|
||||
/**
|
||||
* Form builder; confirm form for cancelling user account.
|
||||
*
|
||||
* @ingroup forms
|
||||
* @see user_edit_cancel_submit()
|
||||
*/
|
||||
function user_cancel_confirm_form($form, &$form_state, $account) {
|
||||
global $user;
|
||||
|
||||
$form['_account'] = array('#type' => 'value', '#value' => $account);
|
||||
|
||||
// Display account cancellation method selection, if allowed.
|
||||
$admin_access = user_access('administer users');
|
||||
$can_select_method = $admin_access || user_access('select account cancellation method');
|
||||
$form['user_cancel_method'] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => ($account->uid == $user->uid ? t('When cancelling your account') : t('When cancelling the account')),
|
||||
'#access' => $can_select_method,
|
||||
);
|
||||
$form['user_cancel_method'] += user_cancel_methods();
|
||||
|
||||
// Allow user administrators to skip the account cancellation confirmation
|
||||
// mail (by default), as long as they do not attempt to cancel their own
|
||||
// account.
|
||||
$override_access = $admin_access && ($account->uid != $user->uid);
|
||||
$form['user_cancel_confirm'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Require e-mail confirmation to cancel account.'),
|
||||
'#default_value' => ($override_access ? FALSE : TRUE),
|
||||
'#access' => $override_access,
|
||||
'#description' => t('When enabled, the user must confirm the account cancellation via e-mail.'),
|
||||
);
|
||||
// Also allow to send account canceled notification mail, if enabled.
|
||||
$default_notify = variable_get('user_mail_status_canceled_notify', FALSE);
|
||||
$form['user_cancel_notify'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Notify user when account is canceled.'),
|
||||
'#default_value' => ($override_access ? FALSE : $default_notify),
|
||||
'#access' => $override_access && $default_notify,
|
||||
'#description' => t('When enabled, the user will receive an e-mail notification after the account has been cancelled.'),
|
||||
);
|
||||
|
||||
// Prepare confirmation form page title and description.
|
||||
if ($account->uid == $user->uid) {
|
||||
$question = t('Are you sure you want to cancel your account?');
|
||||
}
|
||||
else {
|
||||
$question = t('Are you sure you want to cancel the account %name?', array('%name' => $account->name));
|
||||
}
|
||||
$description = '';
|
||||
if ($can_select_method) {
|
||||
$description = t('Select the method to cancel the account above.');
|
||||
foreach (element_children($form['user_cancel_method']) as $element) {
|
||||
unset($form['user_cancel_method'][$element]['#description']);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// The radio button #description is used as description for the confirmation
|
||||
// form.
|
||||
foreach (element_children($form['user_cancel_method']) as $element) {
|
||||
if ($form['user_cancel_method'][$element]['#default_value'] == $form['user_cancel_method'][$element]['#return_value']) {
|
||||
$description = $form['user_cancel_method'][$element]['#description'];
|
||||
}
|
||||
unset($form['user_cancel_method'][$element]['#description']);
|
||||
}
|
||||
}
|
||||
|
||||
// Always provide entity id in the same form key as in the entity edit form.
|
||||
$form['uid'] = array('#type' => 'value', '#value' => $account->uid);
|
||||
return confirm_form($form,
|
||||
$question,
|
||||
'user/' . $account->uid,
|
||||
$description . ' ' . t('This action cannot be undone.'),
|
||||
t('Cancel account'), t('Cancel'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for the account cancellation confirm form.
|
||||
*
|
||||
* @see user_cancel_confirm_form()
|
||||
* @see user_multiple_cancel_confirm_submit()
|
||||
*/
|
||||
function user_cancel_confirm_form_submit($form, &$form_state) {
|
||||
global $user;
|
||||
$account = $form_state['values']['_account'];
|
||||
|
||||
// Cancel account immediately, if the current user has administrative
|
||||
// privileges, no confirmation mail shall be sent, and the user does not
|
||||
// attempt to cancel the own account.
|
||||
if (user_access('administer users') && empty($form_state['values']['user_cancel_confirm']) && $account->uid != $user->uid) {
|
||||
user_cancel($form_state['values'], $account->uid, $form_state['values']['user_cancel_method']);
|
||||
|
||||
$form_state['redirect'] = 'admin/people';
|
||||
}
|
||||
else {
|
||||
// Store cancelling method and whether to notify the user in $account for
|
||||
// user_cancel_confirm().
|
||||
$edit = array(
|
||||
'user_cancel_method' => $form_state['values']['user_cancel_method'],
|
||||
'user_cancel_notify' => $form_state['values']['user_cancel_notify'],
|
||||
);
|
||||
$account = user_save($account, $edit);
|
||||
_user_mail_notify('cancel_confirm', $account);
|
||||
drupal_set_message(t('A confirmation request to cancel your account has been sent to your e-mail address.'));
|
||||
watchdog('user', 'Sent account cancellation request to %name %email.', array('%name' => $account->name, '%email' => '<' . $account->mail . '>'), WATCHDOG_NOTICE);
|
||||
|
||||
$form_state['redirect'] = "user/$account->uid";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to return available account cancellation methods.
|
||||
*
|
||||
* See documentation of hook_user_cancel_methods_alter().
|
||||
*
|
||||
* @return
|
||||
* An array containing all account cancellation methods as form elements.
|
||||
*
|
||||
* @see hook_user_cancel_methods_alter()
|
||||
* @see user_admin_settings()
|
||||
* @see user_cancel_confirm_form()
|
||||
* @see user_multiple_cancel_confirm()
|
||||
*/
|
||||
function user_cancel_methods() {
|
||||
$methods = array(
|
||||
'user_cancel_block' => array(
|
||||
'title' => t('Disable the account and keep its content.'),
|
||||
'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.'),
|
||||
),
|
||||
'user_cancel_block_unpublish' => array(
|
||||
'title' => t('Disable the account and unpublish its content.'),
|
||||
'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.'),
|
||||
),
|
||||
'user_cancel_reassign' => array(
|
||||
'title' => t('Delete the account and make its content belong to the %anonymous-name user.', array('%anonymous-name' => variable_get('anonymous', t('Anonymous')))),
|
||||
'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')))),
|
||||
),
|
||||
'user_cancel_delete' => array(
|
||||
'title' => t('Delete the account and its content.'),
|
||||
'description' => t('Your account will be removed and all account information deleted. All of your content will also be deleted.'),
|
||||
'access' => user_access('administer users'),
|
||||
),
|
||||
);
|
||||
// Allow modules to customize account cancellation methods.
|
||||
drupal_alter('user_cancel_methods', $methods);
|
||||
|
||||
// Turn all methods into real form elements.
|
||||
$default_method = variable_get('user_cancel_method', 'user_cancel_block');
|
||||
foreach ($methods as $name => $method) {
|
||||
$form[$name] = array(
|
||||
'#type' => 'radio',
|
||||
'#title' => $method['title'],
|
||||
'#description' => (isset($method['description']) ? $method['description'] : NULL),
|
||||
'#return_value' => $name,
|
||||
'#default_value' => $default_method,
|
||||
'#parents' => array('user_cancel_method'),
|
||||
);
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback; Cancel a user account via e-mail confirmation link.
|
||||
*
|
||||
* @see user_cancel_confirm_form()
|
||||
* @see user_cancel_url()
|
||||
*/
|
||||
function user_cancel_confirm($account, $timestamp = 0, $hashed_pass = '') {
|
||||
// Time out in seconds until cancel URL expires; 24 hours = 86400 seconds.
|
||||
$timeout = 86400;
|
||||
$current = REQUEST_TIME;
|
||||
|
||||
// Basic validation of arguments.
|
||||
if (isset($account->data['user_cancel_method']) && !empty($timestamp) && !empty($hashed_pass)) {
|
||||
// Validate expiration and hashed password/login.
|
||||
if ($timestamp <= $current && $current - $timestamp < $timeout && $account->uid && $timestamp >= $account->login && $hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid)) {
|
||||
$edit = array(
|
||||
'user_cancel_notify' => isset($account->data['user_cancel_notify']) ? $account->data['user_cancel_notify'] : variable_get('user_mail_status_canceled_notify', FALSE),
|
||||
);
|
||||
user_cancel($edit, $account->uid, $account->data['user_cancel_method']);
|
||||
// Since user_cancel() is not invoked via Form API, batch processing needs
|
||||
// to be invoked manually and should redirect to the front page after
|
||||
// completion.
|
||||
batch_process('');
|
||||
}
|
||||
else {
|
||||
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.'), 'error');
|
||||
drupal_goto("user/$account->uid/cancel");
|
||||
}
|
||||
}
|
||||
return MENU_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Page callback: Displays the user page.
|
||||
*
|
||||
* Displays user profile if user is logged in, or login form for anonymous
|
||||
* users.
|
||||
*
|
||||
* @return
|
||||
* A render array for either a user profile or a login form.
|
||||
*
|
||||
* @see user_view_page()
|
||||
* @see user_login()
|
||||
*/
|
||||
function user_page() {
|
||||
global $user;
|
||||
if ($user->uid) {
|
||||
menu_set_active_item('user/' . $user->uid);
|
||||
return menu_execute_active_handler(NULL, FALSE);
|
||||
}
|
||||
else {
|
||||
return drupal_get_form('user_login');
|
||||
}
|
||||
}
|
69
modules/user/user.permissions.js
Normal file
69
modules/user/user.permissions.js
Normal file
|
@ -0,0 +1,69 @@
|
|||
(function ($) {
|
||||
|
||||
/**
|
||||
* Shows checked and disabled checkboxes for inherited permissions.
|
||||
*/
|
||||
Drupal.behaviors.permissions = {
|
||||
attach: function (context) {
|
||||
var self = this;
|
||||
$('table#permissions').once('permissions', function () {
|
||||
// On a site with many roles and permissions, this behavior initially has
|
||||
// to perform thousands of DOM manipulations to inject checkboxes and hide
|
||||
// them. By detaching the table from the DOM, all operations can be
|
||||
// performed without triggering internal layout and re-rendering processes
|
||||
// in the browser.
|
||||
var $table = $(this);
|
||||
if ($table.prev().length) {
|
||||
var $ancestor = $table.prev(), method = 'after';
|
||||
}
|
||||
else {
|
||||
var $ancestor = $table.parent(), method = 'append';
|
||||
}
|
||||
$table.detach();
|
||||
|
||||
// Create dummy checkboxes. We use dummy checkboxes instead of reusing
|
||||
// the existing checkboxes here because new checkboxes don't alter the
|
||||
// submitted form. If we'd automatically check existing checkboxes, the
|
||||
// permission table would be polluted with redundant entries. This
|
||||
// is deliberate, but desirable when we automatically check them.
|
||||
var $dummy = $('<input type="checkbox" class="dummy-checkbox" disabled="disabled" checked="checked" />')
|
||||
.attr('title', Drupal.t("This permission is inherited from the authenticated user role."))
|
||||
.hide();
|
||||
|
||||
$('input[type=checkbox]', this).not('.rid-2, .rid-1').addClass('real-checkbox').each(function () {
|
||||
$dummy.clone().insertAfter(this);
|
||||
});
|
||||
|
||||
// Initialize the authenticated user checkbox.
|
||||
$('input[type=checkbox].rid-2', this)
|
||||
.bind('click.permissions', self.toggle)
|
||||
// .triggerHandler() cannot be used here, as it only affects the first
|
||||
// element.
|
||||
.each(self.toggle);
|
||||
|
||||
// Re-insert the table into the DOM.
|
||||
$ancestor[method]($table);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggles all dummy checkboxes based on the checkboxes' state.
|
||||
*
|
||||
* If the "authenticated user" checkbox is checked, the checked and disabled
|
||||
* checkboxes are shown, the real checkboxes otherwise.
|
||||
*/
|
||||
toggle: function () {
|
||||
var authCheckbox = this, $row = $(this).closest('tr');
|
||||
// jQuery performs too many layout calculations for .hide() and .show(),
|
||||
// leading to a major page rendering lag on sites with many roles and
|
||||
// permissions. Therefore, we toggle visibility directly.
|
||||
$row.find('.real-checkbox').each(function () {
|
||||
this.style.display = (authCheckbox.checked ? 'none' : '');
|
||||
});
|
||||
$row.find('.dummy-checkbox').each(function () {
|
||||
this.style.display = (authCheckbox.checked ? '' : 'none');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery);
|
2636
modules/user/user.test
Normal file
2636
modules/user/user.test
Normal file
File diff suppressed because it is too large
Load diff
131
modules/user/user.tokens.inc
Normal file
131
modules/user/user.tokens.inc
Normal file
|
@ -0,0 +1,131 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Builds placeholder replacement tokens for user-related data.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_token_info().
|
||||
*/
|
||||
function user_token_info() {
|
||||
$types['user'] = array(
|
||||
'name' => t('Users'),
|
||||
'description' => t('Tokens related to individual user accounts.'),
|
||||
'needs-data' => 'user',
|
||||
);
|
||||
$types['current-user'] = array(
|
||||
'name' => t('Current user'),
|
||||
'description' => t('Tokens related to the currently logged in user.'),
|
||||
'type' => 'user',
|
||||
);
|
||||
|
||||
$user['uid'] = array(
|
||||
'name' => t('User ID'),
|
||||
'description' => t("The unique ID of the user account."),
|
||||
);
|
||||
$user['name'] = array(
|
||||
'name' => t("Name"),
|
||||
'description' => t("The login name of the user account."),
|
||||
);
|
||||
$user['mail'] = array(
|
||||
'name' => t("Email"),
|
||||
'description' => t("The email address of the user account."),
|
||||
);
|
||||
$user['url'] = array(
|
||||
'name' => t("URL"),
|
||||
'description' => t("The URL of the account profile page."),
|
||||
);
|
||||
$user['edit-url'] = array(
|
||||
'name' => t("Edit URL"),
|
||||
'description' => t("The URL of the account edit page."),
|
||||
);
|
||||
|
||||
$user['last-login'] = array(
|
||||
'name' => t("Last login"),
|
||||
'description' => t("The date the user last logged in to the site."),
|
||||
'type' => 'date',
|
||||
);
|
||||
$user['created'] = array(
|
||||
'name' => t("Created"),
|
||||
'description' => t("The date the user account was created."),
|
||||
'type' => 'date',
|
||||
);
|
||||
|
||||
return array(
|
||||
'types' => $types,
|
||||
'tokens' => array('user' => $user),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_tokens().
|
||||
*/
|
||||
function user_tokens($type, $tokens, array $data = array(), array $options = array()) {
|
||||
$url_options = array('absolute' => TRUE);
|
||||
if (isset($options['language'])) {
|
||||
$url_options['language'] = $options['language'];
|
||||
$language_code = $options['language']->language;
|
||||
}
|
||||
else {
|
||||
$language_code = NULL;
|
||||
}
|
||||
$sanitize = !empty($options['sanitize']);
|
||||
|
||||
$replacements = array();
|
||||
|
||||
if ($type == 'user' && !empty($data['user'])) {
|
||||
$account = $data['user'];
|
||||
foreach ($tokens as $name => $original) {
|
||||
switch ($name) {
|
||||
// Basic user account information.
|
||||
case 'uid':
|
||||
// In the case of hook user_presave uid is not set yet.
|
||||
$replacements[$original] = !empty($account->uid) ? $account->uid : t('not yet assigned');
|
||||
break;
|
||||
|
||||
case 'name':
|
||||
$name = format_username($account);
|
||||
$replacements[$original] = $sanitize ? check_plain($name) : $name;
|
||||
break;
|
||||
|
||||
case 'mail':
|
||||
$replacements[$original] = $sanitize ? check_plain($account->mail) : $account->mail;
|
||||
break;
|
||||
|
||||
case 'url':
|
||||
$replacements[$original] = !empty($account->uid) ? url("user/$account->uid", $url_options) : t('not yet assigned');
|
||||
break;
|
||||
|
||||
case 'edit-url':
|
||||
$replacements[$original] = !empty($account->uid) ? url("user/$account->uid/edit", $url_options) : t('not yet assigned');
|
||||
break;
|
||||
|
||||
// These tokens are default variations on the chained tokens handled below.
|
||||
case 'last-login':
|
||||
$replacements[$original] = !empty($account->login) ? format_date($account->login, 'medium', '', NULL, $language_code) : t('never');
|
||||
break;
|
||||
|
||||
case 'created':
|
||||
// In the case of user_presave the created date may not yet be set.
|
||||
$replacements[$original] = !empty($account->created) ? format_date($account->created, 'medium', '', NULL, $language_code) : t('not yet created');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($login_tokens = token_find_with_prefix($tokens, 'last-login')) {
|
||||
$replacements += token_generate('date', $login_tokens, array('date' => $account->login), $options);
|
||||
}
|
||||
|
||||
if ($registered_tokens = token_find_with_prefix($tokens, 'created')) {
|
||||
$replacements += token_generate('date', $registered_tokens, array('date' => $account->created), $options);
|
||||
}
|
||||
}
|
||||
|
||||
if ($type == 'current-user') {
|
||||
$account = user_load($GLOBALS['user']->uid);
|
||||
$replacements += token_generate('user', $tokens, array('user' => $account), $options);
|
||||
}
|
||||
|
||||
return $replacements;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue