
| Current Path : /var/www/html/konvbav/vendor/drush/drush/src/Commands/core/ |
Linux ift1.ift-informatik.de 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64 |
| Current File : /var/www/html/konvbav/vendor/drush/drush/src/Commands/core/UserCommands.php |
<?php
declare(strict_types=1);
namespace Drush\Commands\core;
use Consolidation\AnnotatedCommand\Hooks\HookManager;
use Drupal\Core\Datetime\DateFormatterInterface;
use Consolidation\AnnotatedCommand\CommandData;
use Consolidation\AnnotatedCommand\CommandError;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
use Drupal\user\Entity\Role;
use Drupal\user\Entity\User;
use Drush\Attributes as CLI;
use Drush\Commands\DrushCommands;
use Drush\Utils\StringUtils;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\DependencyInjection\ContainerInterface;
final class UserCommands extends DrushCommands
{
const INFORMATION = 'user:information';
const BLOCK = 'user:block';
const UNBLOCK = 'user:unblock';
const ROLE_ADD = 'user:role:add';
const ROLE_REMOVE = 'user:role:remove';
const CREATE = 'user:create';
const CANCEL = 'user:cancel';
const PASSWORD = 'user:password';
const INF_LABELS = [
'uid' => 'User ID',
'name' => 'User name',
'pass' => 'Password',
'mail' => 'User mail',
'theme' => 'User theme',
'signature' => 'Signature',
'signature_format' => 'Signature format',
'user_created' => 'User created',
'created' => 'Created',
'user_access' => 'User last access',
'access' => 'Last access',
'user_login' => 'User last login',
'login' => 'Last login',
'user_status' => 'User status',
'status' => 'Status',
'timezone' => 'Time zone',
'picture' => 'User picture',
'init' => 'Initial user mail',
'roles' => 'User roles',
'group_audience' => 'Group Audience',
'langcode' => 'Language code',
'uuid' => 'Uuid',
];
const INF_DEFAULT_FIELDS = ['uid', 'name', 'mail', 'roles', 'user_status'];
public function __construct(protected DateFormatterInterface $dateFormatter)
{
}
public static function create(ContainerInterface $container): self
{
$commandHandler = new static(
$container->get('date.formatter')
);
return $commandHandler;
}
/**
* Print information about the specified user(s).
*/
#[CLI\Command(name: self::INFORMATION, aliases: ['uinf', 'user-information'])]
#[CLI\Argument(name: 'names', description: 'A comma delimited list of user names.')]
#[CLI\Option(name: 'uid', description: 'A comma delimited list of user ids to lookup (an alternative to names).')]
#[CLI\Option(name: 'mail', description: 'A comma delimited list of emails to lookup (an alternative to names).')]
#[CLI\Usage(name: 'drush user:information someguy,somegal', description: 'Display information about the someguy and somegal user accounts.')]
#[CLI\Usage(name: 'drush user:information --mail=someguy@somegal.com', description: 'Display information for a given email account.')]
#[CLI\Usage(name: 'drush user:information --uid=5', description: 'Display information for a given user id.')]
#[CLI\Usage(name: 'drush uinf --uid=$(drush sqlq "SELECT GROUP_CONCAT(entity_id) FROM user__roles WHERE roles_target_id = \'administrator\'")', description: 'Display information for all administrators.')]
#[CLI\FieldLabels(labels: self::INF_LABELS)]
#[CLI\DefaultTableFields(fields: self::INF_DEFAULT_FIELDS)]
#[CLI\FilterDefaultField(field: 'name')]
public function information(string $names = '', $options = ['format' => 'table', 'uid' => self::REQ, 'mail' => self::REQ]): RowsOfFields
{
$accounts = [];
if ($mails = StringUtils::csvToArray($options['mail'])) {
foreach ($mails as $mail) {
if ($account = user_load_by_mail($mail)) {
$accounts[$account->id()] = $account;
}
}
}
if ($uids = StringUtils::csvToArray($options['uid'])) {
if ($loaded = User::loadMultiple($uids)) {
$accounts += $loaded;
}
}
if ($names = StringUtils::csvToArray($names)) {
foreach ($names as $name) {
if ($account = user_load_by_name($name)) {
$accounts[$account->id()] = $account;
}
}
}
if (empty($accounts)) {
throw new \Exception(dt('Unable to find a matching user'));
}
foreach ($accounts as $id => $account) {
$outputs[$id] = $this->infoArray($account);
}
$result = new RowsOfFields($outputs);
$result->addRendererFunction([$this, 'renderRolesCell']);
return $result;
}
public function renderRolesCell($key, $cellData, FormatterOptions $options)
{
if (is_array($cellData)) {
return implode("\n", $cellData);
}
return $cellData;
}
/**
* Block the specified user(s).
*/
#[CLI\Command(name: self::BLOCK, aliases: ['ublk', 'user-block'])]
#[CLI\Argument(name: 'names', description: 'A comma delimited list of user names.')]
#[CLI\Option(name: 'uid', description: 'A comma delimited list of user ids to lookup (an alternative to names).')]
#[CLI\Option(name: 'mail', description: 'A comma delimited list of emails to lookup (an alternative to names).')]
#[CLI\Usage(name: 'drush user:block user3', description: 'Block the user whose name is <info>user3</info>')]
#[CLI\Usage(name: 'drush user:cancel user3 --delete-content', description: '<info>Delete</info> the user whose name is <info>user3</info> and delete her content.')]
#[CLI\Usage(name: 'drush user:cancel user3 --reassign-content', description: '<info>Delete</info> the user whose name is <info>user3</info> and reassign her content to the anonymous user.')]
public function block(string $names = '', $options = ['uid' => self::REQ, 'mail' => self::REQ]): void
{
$accounts = $this->getAccounts($names, $options);
foreach ($accounts as $id => $account) {
$account->block();
$account->save();
$this->logger->success(dt('Blocked user(s): !user', ['!user' => $account->getAccountName()]));
}
}
/**
* Unblock the specified user(s).
*/
#[CLI\Command(name: self::UNBLOCK, aliases: ['uublk', 'user-unblock'])]
#[CLI\Argument(name: 'names', description: 'A comma delimited list of user names.')]
#[CLI\Option(name: 'uid', description: 'A comma delimited list of user ids to lookup (an alternative to names).')]
#[CLI\Option(name: 'mail', description: 'A comma delimited list of emails to lookup (an alternative to names).')]
#[CLI\Usage(name: 'drush user:unblock user3', description: 'Unblock the user whose name is <info>user3</info>')]
public function unblock(string $names = '', $options = ['uid' => self::REQ, 'mail' => self::REQ]): void
{
$accounts = $this->getAccounts($names, $options);
foreach ($accounts as $id => $account) {
$account->activate();
$account->save();
$this->logger->success(dt('Unblocked user(s): !user', ['!user' => $account->getAccountName()]));
}
}
/**
* Add a role to the specified user accounts.
*/
#[CLI\Command(name: self::ROLE_ADD, aliases: ['urol', 'user-add-role'])]
#[CLI\Argument(name: 'role', description: 'The machine name of the role to add.')]
#[CLI\Argument(name: 'names', description: 'A comma delimited list of user names.')]
#[CLI\Option(name: 'uid', description: 'A comma delimited list of user ids to lookup (an alternative to names).')]
#[CLI\Option(name: 'mail', description: 'A comma delimited list of emails to lookup (an alternative to names).')]
#[CLI\Usage(name: 'drush user:role:add \'editor\' user3', description: 'Add the editor role to user3')]
#[CLI\ValidateEntityLoad(entityType: 'user_role', argumentName: 'role')]
#[CLI\Complete(method_name_or_callable: 'roleComplete')]
public function addRole(string $role, string $names = '', $options = ['uid' => self::REQ, 'mail' => self::REQ]): void
{
$accounts = $this->getAccounts($names, $options);
foreach ($accounts as $id => $account) {
$account->addRole($role);
$account->save();
$this->logger->success(dt('Added !role role to !user', [
'!role' => $role,
'!user' => $account->getAccountName(),
]));
}
}
/**
* Remove a role from the specified user accounts.
*/
#[CLI\Command(name: self::ROLE_REMOVE, aliases: ['urrol', 'user-remove-role'])]
#[CLI\Argument(name: 'role', description: 'The machine name of the role to add.')]
#[CLI\Argument(name: 'names', description: 'A comma delimited list of user names.')]
#[CLI\Option(name: 'uid', description: 'A comma delimited list of user ids to lookup (an alternative to names).')]
#[CLI\Option(name: 'mail', description: 'A comma delimited list of emails to lookup (an alternative to names).')]
#[CLI\Usage(name: "drush user:role:remove 'power_user' user3", description: "Remove the power_user role from user3")]
#[CLI\ValidateEntityLoad(entityType: 'user_role', argumentName: 'role')]
#[CLI\Complete(method_name_or_callable: 'roleComplete')]
public function removeRole(string $role, string $names = '', $options = ['uid' => self::REQ, 'mail' => self::REQ]): void
{
$accounts = $this->getAccounts($names, $options);
foreach ($accounts as $id => $account) {
$account->removeRole($role);
$account->save();
$this->logger->success(dt('Removed !role role from !user', [
'!role' => $role,
'!user' => $account->getAccountName(),
]));
}
}
/**
* Create a user account.
*/
#[CLI\Command(name: self::CREATE, aliases: ['ucrt', 'user-create'])]
#[CLI\Argument(name: 'name', description: 'The name of the account to add')]
#[CLI\Option(name: 'password', description: 'The password for the new account')]
#[CLI\Option(name: 'mail', description: 'The email address for the new account')]
#[CLI\FieldLabels(labels: self::INF_LABELS)]
#[CLI\DefaultTableFields(fields: self::INF_DEFAULT_FIELDS)]
#[CLI\FilterDefaultField(field: 'name')]
#[CLI\Usage(name: "drush user:create newuser --mail='person@example.com' --password='letmein'", description: 'Create a new user account with the name newuser, the email address person@example.com, and the password letmein')]
public function createUser(string $name, $options = ['format' => 'table', 'password' => self::REQ, 'mail' => self::REQ]): RowsOfFields|CommandError
{
$new_user = [
'name' => $name,
'pass' => $options['password'],
'mail' => $options['mail'],
'access' => '0',
'status' => 1,
];
if (!$this->getConfig()->simulate()) {
if ($account = User::create($new_user)) {
$account->save();
$this->logger()->success(dt('Created a new user with uid !uid', ['!uid' => $account->id()]));
$outputs[$account->id()] = $this->infoArray($account);
$result = new RowsOfFields($outputs);
$result->addRendererFunction([$this, 'renderRolesCell']);
return $result;
} else {
return new CommandError("Could not create a new user account with the name " . $name . ".");
}
} else {
return new RowsOfFields([]);
}
}
/**
* Assure that provided username is available.
*/
#[CLI\Hook(type: HookManager::ARGUMENT_VALIDATOR, target: self::CREATE)]
public function createValidate(CommandData $commandData): void
{
if ($mail = $commandData->input()->getOption('mail')) {
if (user_load_by_mail($mail)) {
throw new \Exception(dt('There is already a user account with the email !mail', ['!mail' => $mail]));
}
}
$name = $commandData->input()->getArgument('name');
if (user_load_by_name($name)) {
throw new \Exception((dt('There is already a user account with the name !name', ['!name' => $name])));
}
}
/**
* Block or delete user account(s) with the specified name(s).
*
* - Existing content may be deleted or reassigned to the Anonymous user. See options.
* - By default only nodes are deleted or reassigned. Custom entity types need own code to
* support cancellation. See https://www.drupal.org/project/drupal/issues/3043725 for updates.
*/
#[CLI\Command(name: self::CANCEL, aliases: ['ucan', 'user-cancel'])]
#[CLI\Argument(name: 'names', description: 'A comma delimited list of user names.')]
#[CLI\Option(name: 'uid', description: 'A comma delimited list of user ids to lookup (an alternative to names).')]
#[CLI\Option(name: 'mail', description: 'A comma delimited list of emails to lookup (an alternative to names).')]
#[CLI\Option(name: 'reassign-content', description: 'Delete the user and make its content belong to the anonymous user.')]
#[CLI\Option(name: 'delete-content', description: 'Delete the user, and delete all content created by that user.')]
#[CLI\Usage(name: 'drush user:cancel username', description: 'Block the user account with the name username.')]
#[CLI\Usage(name: 'drush user:cancel --delete-content username', description: 'Delete the user account with the name <info>username<info> and delete all content created by that user.')]
#[CLI\Usage(name: 'drush user:cancel --reassign-content username', description: 'Delete the user account with the name <info>username<info> and assign all her content to the anonymous user.')]
public function cancel(string $names = '', $options = ['delete-content' => false, 'reassign-content' => false, 'uid' => self::REQ, 'mail' => self::REQ]): void
{
$accounts = $this->getAccounts($names, $options);
foreach ($accounts as $id => $account) {
if ($options['delete-content']) {
$this->logger()->warning(dt('All content created by !name will be deleted.', ['!name' => $account->getAccountName()]));
} elseif ($options['reassign-content']) {
$this->logger()->warning(dt('All content created by !name will be assigned to anonymous user.', ['!name' => $account->getAccountName()]));
}
if ($this->io()->confirm('Cancel user account?: ')) {
$method = $options['delete-content'] ? 'user_cancel_delete' : ($options['reassign-content'] ? 'user_cancel_reassign' : 'user_cancel_block');
user_cancel([], $account->id(), $method);
drush_backend_batch_process();
// Drupal logs a message for us.
}
}
}
/**
* Set the password for the user account with the specified name.
*/
#[CLI\Command(name: self::PASSWORD, aliases: ['upwd', 'user-password'])]
#[CLI\Argument(name: 'name', description: 'The name of the account to modify.')]
#[CLI\Argument(name: 'password', description: 'The new password for the account.')]
#[CLI\Usage(name: "drush user:password someuser 'correct horse battery staple'", description: 'Set the password for the username someuser. See https://xkcd.com/936')]
public function password(string $name, string $password): void
{
if ($account = user_load_by_name($name)) {
if (!$this->getConfig()->simulate()) {
$account->setpassword($password);
$account->save();
$this->logger()->success(dt('Changed password for !name.', ['!name' => $name]));
}
} else {
throw new \Exception(dt('Unable to load user: !user', ['!user' => $name]));
}
}
/**
* A flatter and simpler array presentation of a Drupal $user object.
*/
public function infoArray($account): array
{
return [
'uid' => $account->id(),
'name' => $account->getAccountName(),
'pass' => $account->getPassword(),
'mail' => $account->getEmail(),
'user_created' => $account->getCreatedTime(),
'created' => $this->dateFormatter->format($account->getCreatedTime()),
'user_access' => $account->getLastAccessedTime(),
'access' => $this->dateFormatter->format($account->getLastAccessedTime()),
'user_login' => $account->getLastLoginTime(),
'login' => $this->dateFormatter->format($account->getLastLoginTime()),
'user_status' => $account->get('status')->value,
'status' => $account->isActive() ? 'active' : 'blocked',
'timezone' => $account->getTimeZone(),
'roles' => $account->getRoles(),
'langcode' => $account->getPreferredLangcode(),
'uuid' => $account->uuid->value,
];
}
/**
* Get accounts from name variables or uid & mail options.
*
* @param string $names
* @param array $options
*
* A array of loaded accounts.
* @throws \Exception
*/
protected function getAccounts(string $names = '', array $options = []): array
{
$accounts = [];
if (isset($options['mail']) && $mails = StringUtils::csvToArray($options['mail'])) {
foreach ($mails as $mail) {
if ($account = user_load_by_mail($mail)) {
$accounts[$account->id()] = $account;
} else {
$this->logger->warning(dt('Unable to load user: !mail', ['!mail' => $mail]));
}
}
}
if (isset($options['uid']) && $uids = StringUtils::csvToArray($options['uid'])) {
foreach ($uids as $uid) {
if ($account = User::load($uid)) {
$accounts[$account->id()] = $account;
} else {
$this->logger->warning(dt('Unable to load user: !uid', ['!uid' => $uid]));
}
}
}
if ($names = StringUtils::csvToArray($names)) {
foreach ($names as $name) {
if ($account = user_load_by_name($name)) {
$accounts[$account->id()] = $account;
} else {
$this->logger->warning(dt('Unable to load user: !user', ['!user' => $name]));
}
}
}
if (empty($accounts)) {
throw new \Exception(dt('Unable to find any matching user'));
}
return $accounts;
}
public function roleComplete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
if ($input->mustSuggestArgumentValuesFor('role')) {
$suggestions->suggestValues(array_keys(Role::loadMultiple()));
}
}
}