Commit b3ef2ab3 authored by webchick's avatar webchick

Issue #1946466 by tim.plunkett, andypost, jibran, Unitoch, Crell, disasm |...

Issue #1946466 by tim.plunkett, andypost, jibran, Unitoch, Crell, disasm | mtift: Convert all confirm_form() in user.module and user.pages.inc to the new form interface and convert route.
parent 2dfecb5e
......@@ -355,10 +355,10 @@ function _batch_next_set() {
if (isset($batch['sets'][$batch['current_set'] + 1])) {
$batch['current_set']++;
$current_set = &_batch_current_set();
if (isset($current_set['form_submit']) && ($function = $current_set['form_submit']) && function_exists($function)) {
if (isset($current_set['form_submit']) && ($function = $current_set['form_submit']) && is_callable($function)) {
// We use our stored copies of $form and $form_state to account for
// possible alterations by previous form submit handlers.
$function($batch['form_state']['complete_form'], $batch['form_state']);
call_user_func_array($function, array($batch['form_state']['complete_form'], &$batch['form_state']));
}
return TRUE;
}
......
......@@ -134,7 +134,6 @@ public function buildForm(array $form, array &$form_state) {
'#title' => $this->t('Enable password strength indicator'),
'#default_value' => $config->get('password_strength'),
);
form_load_include($form_state, 'inc', 'user', 'user.pages');
$form['registration_cancellation']['user_cancel_method'] = array(
'#type' => 'radios',
'#title' => $this->t('When cancelling a user account'),
......
......@@ -27,6 +27,7 @@
* "render" = "Drupal\Core\Entity\EntityRenderController",
* "form" = {
* "default" = "Drupal\user\ProfileFormController",
* "cancel" = "Drupal\user\Form\UserCancelForm",
* "register" = "Drupal\user\RegisterFormController"
* },
* "translation" = "Drupal\user\ProfileTranslationController"
......
<?php
/**
* @file
* Contains \Drupal\user\Form\UserCancelForm.
*/
namespace Drupal\user\Form;
use Drupal\Core\Config\ConfigFactory;
use Drupal\Core\Entity\EntityNGConfirmFormBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a confirmation form for cancelling user account.
*/
class UserCancelForm extends EntityNGConfirmFormBase {
/**
* Available account cancellation methods.
*
* @var array
*/
protected $cancelMethods;
/**
* The config factory.
*
* @var \Drupal\Core\Config\ConfigFactory
*/
protected $configFactory;
/**
* The user being cancelled.
*
* @var \Drupal\user\UserInterface
*/
protected $entity;
/**
* Constructs an EntityFormController object.
*
* @param \Drupal\Core\Config\ConfigFactory $config_factory
* The config factory.
*/
public function __construct(ConfigFactory $config_factory) {
$this->configFactory = $config_factory;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('config.factory')
);
}
/**
* {@inheritdoc}
*/
public function getQuestion() {
if ($this->entity->id() == $this->currentUser()->id()) {
return $this->t('Are you sure you want to cancel your account?');
}
return $this->t('Are you sure you want to cancel the account %name?', array('%name' => $this->entity->label()));
}
/**
* {@inheritdoc}
*/
public function getCancelRoute() {
}
/**
* {@inheritdoc}
*/
public function getDescription() {
$description = '';
$default_method = $this->configFactory->get('user.settings')->get('cancel_method');
if ($this->currentUser()->hasPermission('administer users') || $this->currentUser()->hasPermission('select account cancellation method')) {
$description = $this->t('Select the method to cancel the account above.');
}
// Options supplied via user_cancel_methods() can have a custom
// #confirm_description property for the confirmation form description.
elseif (isset($this->cancelMethods[$default_method]['#confirm_description'])) {
$description = $this->cancelMethods[$default_method]['#confirm_description'];
}
return $description . ' ' . $this->t('This action cannot be undone.');
}
/**
* {@inheritdoc}
*/
public function getConfirmText() {
return $this->t('Cancel account');
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, array &$form_state) {
$user = $this->currentUser();
$this->cancelMethods = user_cancel_methods();
// Display account cancellation method selection, if allowed.
$admin_access = $user->hasPermission('administer users');
$form['user_cancel_method'] = array(
'#type' => 'radios',
'#title' => ($this->entity->id() == $user->id() ? $this->t('When cancelling your account') : $this->t('When cancelling the account')),
'#access' => $admin_access || $user->hasPermission('select account cancellation method'),
);
$form['user_cancel_method'] += $this->cancelMethods;
// 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 && ($this->entity->id() != $user->id());
$form['user_cancel_confirm'] = array(
'#type' => 'checkbox',
'#title' => $this->t('Require e-mail confirmation to cancel account.'),
'#default_value' => !$override_access,
'#access' => $override_access,
'#description' => $this->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 = $this->configFactory->get('user.settings')->get('notify.status_canceled');
$form['user_cancel_notify'] = array(
'#type' => 'checkbox',
'#title' => $this->t('Notify user when account is canceled.'),
'#default_value' => ($override_access ? FALSE : $default_notify),
'#access' => $override_access && $default_notify,
'#description' => $this->t('When enabled, the user will receive an e-mail notification after the account has been canceled.'),
);
// Always provide entity id in the same form key as in the entity edit form.
$form['uid'] = array('#type' => 'value', '#value' => $this->entity->id());
$form = parent::buildForm($form, $form_state);
// @todo Convert to getCancelRoute() after https://drupal.org/node/1987896.
$uri = $this->entity->uri();
$form['actions']['cancel']['#href'] = $uri['path'];
return $form;
}
/**
* {@inheritdoc}
*/
public function submit(array $form, array &$form_state) {
// 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 ($this->currentUser()->hasPermission('administer users') && empty($form_state['values']['user_cancel_confirm']) && $this->entity->id() != $this->currentUser()->id()) {
user_cancel($form_state['values'], $this->entity->id(), $form_state['values']['user_cancel_method']);
$form_state['redirect'] = 'admin/people';
}
else {
// Store cancelling method and whether to notify the user in
// $this->entity for user_cancel_confirm().
$this->entity->user_cancel_method = $form_state['values']['user_cancel_method'];
$this->entity->user_cancel_notify = $form_state['values']['user_cancel_notify'];
$this->entity->save();
_user_mail_notify('cancel_confirm', $this->entity);
drupal_set_message($this->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' => $this->entity->label(), '%email' => '<' . $this->entity->getEmail() . '>'), WATCHDOG_NOTICE);
$form_state['redirect'] = 'user/' . $this->entity->id();
}
}
}
<?php
/**
* @file
* Contains \Drupal\user\Form\UserMultipleCancelConfirm.
*/
namespace Drupal\user\Form;
use Drupal\Component\Utility\String;
use Drupal\Core\Config\ConfigFactory;
use Drupal\Core\Entity\EntityManager;
use Drupal\Core\Form\ConfirmFormBase;
use Drupal\Core\Routing\UrlGeneratorInterface;
use Drupal\user\TempStoreFactory;
use Drupal\user\UserStorageControllerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
/**
* Provides a confirmation form for cancelling multiple user accounts.
*/
class UserMultipleCancelConfirm extends ConfirmFormBase {
/**
* The temp store factory.
*
* @var \Drupal\user\TempStoreFactory
*/
protected $tempStoreFactory;
/**
* The config factory.
*
* @var \Drupal\Core\Config\ConfigFactory
*/
protected $configFactory;
/**
* The user storage controller.
*
* @var \Drupal\user\UserStorageControllerInterface
*/
protected $userStorage;
/**
* The entity manager.
*
* @var \Drupal\Core\Entity\EntityManager
*/
protected $entityManager;
/**
* Constructs a new UserMultipleCancelConfirm.
*
* @param \Drupal\user\TempStoreFactory $temp_store_factory
* The temp store factory.
* @param \Drupal\Core\Config\ConfigFactory $config_factory
* The config factory.
* @param \Drupal\user\UserStorageControllerInterface $user_storage
* The user storage controller.
* @param \Drupal\Core\Entity\EntityManager $entity_manager
* The entity manager.
*/
public function __construct(TempStoreFactory $temp_store_factory, ConfigFactory $config_factory, UserStorageControllerInterface $user_storage, EntityManager $entity_manager) {
$this->tempStoreFactory = $temp_store_factory;
$this->configFactory = $config_factory;
$this->userStorage = $user_storage;
$this->entityManager = $entity_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('user.tempstore'),
$container->get('config.factory'),
$container->get('entity.manager')->getStorageController('user'),
$container->get('entity.manager')
);
}
/**
* {@inheritdoc}
*/
public function getFormID() {
return 'user_multiple_cancel_confirm';
}
/**
* {@inheritdoc}
*/
public function getQuestion() {
return $this->t('Are you sure you want to cancel these user accounts?');
}
/**
* {@inheritdoc}
*/
public function getCancelRoute() {
}
/**
* {@inheritdoc}
*/
public function getConfirmText() {
return $this->t('Cancel accounts');
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, array &$form_state) {
// Retrieve the accounts to be canceled from the temp store.
$accounts = $this->tempStoreFactory
->get('user_user_operations_cancel')
->get($this->currentUser()->id());
if (!$accounts) {
return new RedirectResponse($this->urlGenerator()->generateFromPath('admin/people', array('absolute' => TRUE)));
}
$form['accounts'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
foreach ($accounts as $uid => $account) {
// Prevent user 1 from being canceled.
if ($uid <= 1) {
continue;
}
$form['accounts'][$uid] = array(
'#type' => 'hidden',
'#value' => $uid,
'#prefix' => '<li>',
'#suffix' => String::checkPlain($account->label()) . "</li>\n",
);
}
// Output a notice that user 1 cannot be canceled.
if (isset($accounts[1])) {
$redirect = (count($accounts) == 1);
$message = $this->t('The user account %name cannot be canceled.', array('%name' => $accounts[1]->label()));
drupal_set_message($message, $redirect ? 'error' : 'warning');
// If only user 1 was selected, redirect to the overview.
if ($redirect) {
return new RedirectResponse($this->urlGenerator()->generateFromPath('admin/people', array('absolute' => TRUE)));
}
}
$form['operation'] = array('#type' => 'hidden', '#value' => 'cancel');
$form['user_cancel_method'] = array(
'#type' => 'radios',
'#title' => $this->t('When cancelling these accounts'),
);
$form['user_cancel_method'] += user_cancel_methods();
// Allow to send the account cancellation confirmation mail.
$form['user_cancel_confirm'] = array(
'#type' => 'checkbox',
'#title' => $this->t('Require e-mail confirmation to cancel account.'),
'#default_value' => FALSE,
'#description' => $this->t('When enabled, the user must confirm the account cancellation via e-mail.'),
);
// Also allow to send account canceled notification mail, if enabled.
$form['user_cancel_notify'] = array(
'#type' => 'checkbox',
'#title' => $this->t('Notify user when account is canceled.'),
'#default_value' => FALSE,
'#access' => $this->configFactory->get('user.settings')->get('notify.status_canceled'),
'#description' => $this->t('When enabled, the user will receive an e-mail notification after the account has been canceled.'),
);
$form = parent::buildForm($form, $form_state);
// @todo Convert to getCancelRoute() after https://drupal.org/node/1938884.
$form['actions']['cancel']['#href'] = 'admin/people';
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, array &$form_state) {
$current_user_id = $this->currentUser()->id();
// Clear out the accounts from the temp store.
$this->tempStoreFactory->get('user_user_operations_cancel')->delete($current_user_id);
if ($form_state['values']['confirm']) {
foreach ($form_state['values']['accounts'] as $uid => $value) {
// Prevent programmatic form submissions from cancelling user 1.
if ($uid <= 1) {
continue;
}
// Prevent user administrators from deleting themselves without confirmation.
if ($uid == $current_user_id) {
$admin_form_mock = array();
$admin_form_state = $form_state;
unset($admin_form_state['values']['user_cancel_confirm']);
// The $user global is not a complete user entity, so load the full
// entity.
$account = $this->userStorage->load($uid);
$admin_form = $this->entityManager->getFormController('user', 'cancel');
$admin_form->setEntity($account);
// Calling this directly required to init form object with $account.
$admin_form->buildForm($admin_form_mock, $admin_form_state, $this->request);
$admin_form->submit($admin_form_mock, $admin_form_state);
}
else {
user_cancel($form_state['values'], $uid, $form_state['values']['user_cancel_method']);
}
}
}
$form_state['redirect'] = 'admin/people';
}
}
......@@ -824,14 +824,6 @@ function user_menu() {
'route_name' => 'user_admin_create',
'type' => MENU_LOCAL_ACTION,
);
$items['admin/people/cancel'] = array(
'title' => 'Cancel user',
'page callback' => 'drupal_get_form',
'page arguments' => array('user_multiple_cancel_confirm'),
'access arguments' => array('administer users'),
'file' => 'user.admin.inc',
'type' => MENU_CALLBACK,
);
// Administration pages.
$items['admin/config/people'] = array(
......@@ -867,12 +859,7 @@ function user_menu() {
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$items['user/%user/cancel'] = array(
'title' => 'Cancel account',
'page callback' => 'drupal_get_form',
'page arguments' => array('user_cancel_confirm_form', 1),
'access callback' => 'entity_page_access',
'access arguments' => array(1, 'delete'),
'file' => 'user.pages.inc',
'route_name' => 'user_cancel_confirm',
);
$items['user/%user/cancel/confirm/%/%'] = array(
'title' => 'Confirm account cancellation',
......@@ -1304,6 +1291,62 @@ function _user_cancel_session_regenerate() {
drupal_session_regenerate();
}
/**
* Helper function to return available account cancellation methods.
*
* See documentation of hook_user_cancel_methods_alter().
*
* @return array
* An array containing all account cancellation methods as form elements.
*
* @see hook_user_cancel_methods_alter()
* @see user_admin_settings()
*/
function user_cancel_methods() {
$user_settings = Drupal::config('user.settings');
$anonymous_name = $user_settings->get('anonymous');
$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' => $anonymous_name)),
'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' => $anonymous_name)),
),
'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' => Drupal::request()->attributes->get('_account')->hasPermission('administer users'),
),
);
// Allow modules to customize account cancellation methods.
Drupal::moduleHandler()->alter('user_cancel_methods', $methods);
// Turn all methods into real form elements.
$form = array(
'#options' => array(),
'#default_value' => $user_settings->get('cancel_method'),
);
foreach ($methods as $name => $method) {
$form['#options'][$name] = $method['title'];
// Add the description for the confirmation form. This description is never
// shown for the cancel method option, only on the confirmation form.
// Therefore, we use a custom #confirm_description property.
if (isset($method['description'])) {
$form[$name]['#confirm_description'] = $method['description'];
}
if (isset($method['access'])) {
$form[$name]['#access'] = $method['access'];
}
}
return $form;
}
/**
* Delete a user.
*
......@@ -1663,100 +1706,6 @@ function user_role_revoke_permissions($rid, array $permissions = array()) {
$role->save();
}
function user_multiple_cancel_confirm($form, &$form_state) {
// Retrieve the accounts to be canceled from the temp store.
$accounts = Drupal::service('user.tempstore')->get('user_user_operations_cancel')->get($GLOBALS['user']->id());
$form['accounts'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
foreach ($accounts as $account) {
$uid = $account->id();
// Prevent user 1 from being canceled.
if ($uid <= 1) {
continue;
}
$form['accounts'][$uid] = array(
'#type' => 'hidden',
'#value' => $uid,
'#prefix' => '<li>',
'#suffix' => check_plain($account->getUsername()) . "</li>\n",
);
}
// Output a notice that user 1 cannot be canceled.
if (isset($accounts[1])) {
$redirect = (count($accounts) == 1);
$message = t('The user account %name cannot be cancelled.', array('%name' => $accounts[1]->name->value));
drupal_set_message($message, $redirect ? 'error' : 'warning');
// If only user 1 was selected, redirect to the overview.
if ($redirect) {
return new RedirectResponse(url('admin/people', array('absolute' => TRUE)));
}
}
$form['operation'] = array('#type' => 'hidden', '#value' => 'cancel');
form_load_include($form_state, 'inc', 'user', 'user.pages');
$form['user_cancel_method'] = array(
'#type' => 'radios',
'#title' => t('When cancelling these accounts'),
);
$form['user_cancel_method'] += user_cancel_methods();
// Allow to send the account cancellation confirmation mail.
$form['user_cancel_confirm'] = array(
'#type' => 'checkbox',
'#title' => t('Require e-mail confirmation to cancel account.'),
'#default_value' => FALSE,
'#description' => t('When enabled, the user must confirm the account cancellation via e-mail.'),
);
// Also allow to send account canceled notification mail, if enabled.
$form['user_cancel_notify'] = array(
'#type' => 'checkbox',
'#title' => t('Notify user when account is canceled.'),
'#default_value' => FALSE,
'#access' => Drupal::config('user.settings')->get('notify.status_canceled'),
'#description' => t('When enabled, the user will receive an e-mail notification after the account has been cancelled.'),
);
return confirm_form($form,
t('Are you sure you want to cancel these user accounts?'),
'admin/people', t('This action cannot be undone.'),
t('Cancel accounts'), t('Cancel'));
}
/**
* Submit handler for mass-account cancellation form.
*
* @see user_multiple_cancel_confirm()
* @see user_cancel_confirm_form_submit()
*/
function user_multiple_cancel_confirm_submit($form, &$form_state) {
global $user;
// Clear out the accounts from the temp store.
Drupal::service('user.tempstore')->get('user_user_operations_cancel')->delete($user->id());
if ($form_state['values']['confirm']) {
foreach ($form_state['values']['accounts'] as $uid => $value) {
// Prevent programmatic form submissions from cancelling user 1.
if ($uid <= 1) {
continue;
}
// Prevent user administrators from deleting themselves without confirmation.
if ($uid == $user->id()) {
$admin_form_state = $form_state;
unset($admin_form_state['values']['user_cancel_confirm']);
// The $user global is not a complete user entity, so load the full
// entity.
$admin_form_state['values']['_account'] = user_load($user->id());
user_cancel_confirm_form_submit(array(), $admin_form_state);
}
else {
user_cancel($form_state['values'], $uid, $form_state['values']['user_cancel_method']);
}
}
}
$form_state['redirect'] = 'admin/people';
}
/**
* Returns HTML for a user signature.
*
......
......@@ -118,165 +118,6 @@ function template_preprocess_user(&$variables) {
$variables['attributes']['class'][] = 'profile';
}
/**
* 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' => 'radios',
'#title' => ($account->id() == $user->id() ? 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->id() != $user->id());
$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 = Drupal::config('user.settings')->get('notify.status_canceled');
$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->id() == $user->id()) {
$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->getUsername()));
}
$default_method = Drupal::config('user.settings')->get('cancel_method');
$description = NULL;
if ($can_select_method) {
$description = t('Select the method to cancel the account above.');
}
// Options supplied via user_cancel_methods() can have a custom
// #confirm_description property for the confirmation form description.
elseif (isset($form['user_cancel_method'][$default_method]['#confirm_description'])) {
$description = $form['user_cancel_method'][$default_method]['#confirm_description'];
}
// Always provide entity id in the same form key as in the entity edit form.
$form['uid'] = array('#type' => 'value', '#value' => $account->id());
return confirm_form($form,
$question,
'user/' . $account->id(),
$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->id() != $user->id()) {
user_cancel($form_state['values'], $account->id(), $form_state['values']['user_cancel_method']);
$form_state['redirect'] = 'admin/people';
}