diff options
Diffstat (limited to 'core/Command/User')
-rw-r--r-- | core/Command/User/Add.php | 10 | ||||
-rw-r--r-- | core/Command/User/AuthTokens/Add.php | 6 | ||||
-rw-r--r-- | core/Command/User/AuthTokens/Delete.php | 3 | ||||
-rw-r--r-- | core/Command/User/AuthTokens/ListCommand.php | 1 | ||||
-rw-r--r-- | core/Command/User/ClearGeneratedAvatarCacheCommand.php | 4 | ||||
-rw-r--r-- | core/Command/User/Info.php | 17 | ||||
-rw-r--r-- | core/Command/User/LastSeen.php | 9 | ||||
-rw-r--r-- | core/Command/User/ListCommand.php | 38 | ||||
-rw-r--r-- | core/Command/User/Profile.php | 234 | ||||
-rw-r--r-- | core/Command/User/ResetPassword.php | 16 | ||||
-rw-r--r-- | core/Command/User/Setting.php | 10 | ||||
-rw-r--r-- | core/Command/User/SyncAccountDataCommand.php | 12 | ||||
-rw-r--r-- | core/Command/User/Welcome.php | 78 |
13 files changed, 387 insertions, 51 deletions
diff --git a/core/Command/User/Add.php b/core/Command/User/Add.php index 60cf67e8df3..4de4e247991 100644 --- a/core/Command/User/Add.php +++ b/core/Command/User/Add.php @@ -52,7 +52,7 @@ class Add extends Command { 'password-from-env', null, InputOption::VALUE_NONE, - 'read password from environment variable OC_PASS' + 'read password from environment variable NC_PASS/OC_PASS' ) ->addOption( 'generate-password', @@ -91,10 +91,10 @@ class Add extends Command { // Setup password. if ($input->getOption('password-from-env')) { - $password = getenv('OC_PASS'); + $password = getenv('NC_PASS') ?: getenv('OC_PASS'); if (!$password) { - $output->writeln('<error>--password-from-env given, but OC_PASS is empty!</error>'); + $output->writeln('<error>--password-from-env given, but NC_PASS/OC_PASS is empty!</error>'); return 1; } } elseif ($input->getOption('generate-password')) { @@ -114,11 +114,11 @@ class Add extends Command { $confirm = $helper->ask($input, $output, $question); if ($password !== $confirm) { - $output->writeln("<error>Passwords did not match!</error>"); + $output->writeln('<error>Passwords did not match!</error>'); return 1; } } else { - $output->writeln("<error>Interactive input or --password-from-env or --generate-password is needed for setting a password!</error>"); + $output->writeln('<error>Interactive input or --password-from-env or --generate-password is needed for setting a password!</error>'); return 1; } diff --git a/core/Command/User/AuthTokens/Add.php b/core/Command/User/AuthTokens/Add.php index 43386b7709a..89b20535c63 100644 --- a/core/Command/User/AuthTokens/Add.php +++ b/core/Command/User/AuthTokens/Add.php @@ -62,9 +62,9 @@ class Add extends Command { } if ($input->getOption('password-from-env')) { - $password = getenv('NC_PASS') ?? getenv('OC_PASS'); + $password = getenv('NC_PASS') ?: getenv('OC_PASS'); if (!$password) { - $output->writeln('<error>--password-from-env given, but NC_PASS is empty!</error>'); + $output->writeln('<error>--password-from-env given, but NC_PASS/OC_PASS is empty!</error>'); return 1; } } elseif ($input->isInteractive()) { @@ -81,7 +81,7 @@ class Add extends Command { $output->writeln('<info>No password provided. The generated app password will therefore have limited capabilities. Any operation that requires the login password will fail.</info>'); } - $token = $this->random->generate(72, ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_DIGITS); + $token = $this->random->generate(72, ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_DIGITS); $generatedToken = $this->tokenProvider->generateToken( $token, $user->getUID(), diff --git a/core/Command/User/AuthTokens/Delete.php b/core/Command/User/AuthTokens/Delete.php index 65c0147aa24..2047d2eae2a 100644 --- a/core/Command/User/AuthTokens/Delete.php +++ b/core/Command/User/AuthTokens/Delete.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later @@ -46,7 +47,7 @@ class Delete extends Base { protected function execute(InputInterface $input, OutputInterface $output): int { $uid = $input->getArgument('uid'); - $id = (int) $input->getArgument('id'); + $id = (int)$input->getArgument('id'); $before = $input->getOption('last-used-before'); if ($before) { diff --git a/core/Command/User/AuthTokens/ListCommand.php b/core/Command/User/AuthTokens/ListCommand.php index 1ebd4a0f0b4..b36aa717505 100644 --- a/core/Command/User/AuthTokens/ListCommand.php +++ b/core/Command/User/AuthTokens/ListCommand.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/core/Command/User/ClearGeneratedAvatarCacheCommand.php b/core/Command/User/ClearGeneratedAvatarCacheCommand.php index fc9d70709c8..515b3a913b7 100644 --- a/core/Command/User/ClearGeneratedAvatarCacheCommand.php +++ b/core/Command/User/ClearGeneratedAvatarCacheCommand.php @@ -27,9 +27,9 @@ class ClearGeneratedAvatarCacheCommand extends Base { } protected function execute(InputInterface $input, OutputInterface $output): int { - $output->writeln("Clearing avatar cache has started"); + $output->writeln('Clearing avatar cache has started'); $this->avatarManager->clearCachedAvatars(); - $output->writeln("Cleared avatar cache successfully"); + $output->writeln('Cleared avatar cache successfully'); return 0; } } diff --git a/core/Command/User/Info.php b/core/Command/User/Info.php index 55298f0164c..e7fc9286e74 100644 --- a/core/Command/User/Info.php +++ b/core/Command/User/Info.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later @@ -6,6 +7,7 @@ namespace OC\Core\Command\User; use OC\Core\Command\Base; +use OCP\Files\NotFoundException; use OCP\IGroupManager; use OCP\IUser; use OCP\IUserManager; @@ -56,7 +58,8 @@ class Info extends Base { 'groups' => $groups, 'quota' => $user->getQuota(), 'storage' => $this->getStorageInfo($user), - 'last_seen' => date(\DateTimeInterface::ATOM, $user->getLastLogin()), // ISO-8601 + 'first_seen' => $this->formatLoginDate($user->getFirstLogin()), + 'last_seen' => $this->formatLoginDate($user->getLastLogin()), 'user_directory' => $user->getHome(), 'backend' => $user->getBackendClassName() ]; @@ -64,6 +67,16 @@ class Info extends Base { return 0; } + private function formatLoginDate(int $timestamp): string { + if ($timestamp < 0) { + return 'unknown'; + } elseif ($timestamp === 0) { + return 'never'; + } else { + return date(\DateTimeInterface::ATOM, $timestamp); // ISO-8601 + } + } + /** * @param IUser $user * @return array @@ -73,7 +86,7 @@ class Info extends Base { \OC_Util::setupFS($user->getUID()); try { $storage = \OC_Helper::getStorageInfo('/'); - } catch (\OCP\Files\NotFoundException $e) { + } catch (NotFoundException $e) { return []; } return [ diff --git a/core/Command/User/LastSeen.php b/core/Command/User/LastSeen.php index 3c2ec828d41..984def72cd6 100644 --- a/core/Command/User/LastSeen.php +++ b/core/Command/User/LastSeen.php @@ -43,6 +43,7 @@ class LastSeen extends Base { protected function execute(InputInterface $input, OutputInterface $output): int { $singleUserId = $input->getArgument('uid'); + if ($singleUserId) { $user = $this->userManager->get($singleUserId); if (is_null($user)) { @@ -56,25 +57,25 @@ class LastSeen extends Base { } else { $date = new \DateTime(); $date->setTimestamp($lastLogin); - $output->writeln($user->getUID() . "'s last login: " . $date->format('Y-m-d H:i')); + $output->writeln($user->getUID() . "'s last login: " . $date->format('Y-m-d H:i:s T')); } return 0; } if (!$input->getOption('all')) { - $output->writeln("<error>Please specify a username, or \"--all\" to list all</error>"); + $output->writeln('<error>Please specify a username, or "--all" to list all</error>'); return 1; } - $this->userManager->callForAllUsers(static function (IUser $user) use ($output) { + $this->userManager->callForAllUsers(static function (IUser $user) use ($output): void { $lastLogin = $user->getLastLogin(); if ($lastLogin === 0) { $output->writeln($user->getUID() . ' has never logged in.'); } else { $date = new \DateTime(); $date->setTimestamp($lastLogin); - $output->writeln($user->getUID() . "'s last login: " . $date->format('Y-m-d H:i')); + $output->writeln($user->getUID() . "'s last login: " . $date->format('Y-m-d H:i:s T')); } }); return 0; diff --git a/core/Command/User/ListCommand.php b/core/Command/User/ListCommand.php index bb798759511..66b831c793b 100644 --- a/core/Command/User/ListCommand.php +++ b/core/Command/User/ListCommand.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later @@ -58,9 +59,9 @@ class ListCommand extends Base { protected function execute(InputInterface $input, OutputInterface $output): int { if ($input->getOption('disabled')) { - $users = $this->userManager->getDisabledUsers((int) $input->getOption('limit'), (int) $input->getOption('offset')); + $users = $this->userManager->getDisabledUsers((int)$input->getOption('limit'), (int)$input->getOption('offset')); } else { - $users = $this->userManager->searchDisplayName('', (int) $input->getOption('limit'), (int) $input->getOption('offset')); + $users = $this->userManager->searchDisplayName('', (int)$input->getOption('limit'), (int)$input->getOption('offset')); } $this->writeArrayInOutputFormat($input, $output, $this->formatUsers($users, (bool)$input->getOption('info'))); @@ -69,18 +70,13 @@ class ListCommand extends Base { /** * @param IUser[] $users - * @param bool [$detailed=false] - * @return array + * @return \Generator<string,string|array> */ - private function formatUsers(array $users, bool $detailed = false) { - $keys = array_map(function (IUser $user) { - return $user->getUID(); - }, $users); - - $values = array_map(function (IUser $user) use ($detailed) { + private function formatUsers(array $users, bool $detailed = false): \Generator { + foreach ($users as $user) { if ($detailed) { $groups = $this->groupManager->getUserGroupIds($user); - return [ + $value = [ 'user_id' => $user->getUID(), 'display_name' => $user->getDisplayName(), 'email' => (string)$user->getSystemEMailAddress(), @@ -88,13 +84,25 @@ class ListCommand extends Base { 'enabled' => $user->isEnabled(), 'groups' => $groups, 'quota' => $user->getQuota(), - 'last_seen' => date(\DateTimeInterface::ATOM, $user->getLastLogin()), // ISO-8601 + 'first_seen' => $this->formatLoginDate($user->getFirstLogin()), + 'last_seen' => $this->formatLoginDate($user->getLastLogin()), 'user_directory' => $user->getHome(), 'backend' => $user->getBackendClassName() ]; + } else { + $value = $user->getDisplayName(); } - return $user->getDisplayName(); - }, $users); - return array_combine($keys, $values); + yield $user->getUID() => $value; + } + } + + private function formatLoginDate(int $timestamp): string { + if ($timestamp < 0) { + return 'unknown'; + } elseif ($timestamp === 0) { + return 'never'; + } else { + return date(\DateTimeInterface::ATOM, $timestamp); // ISO-8601 + } } } diff --git a/core/Command/User/Profile.php b/core/Command/User/Profile.php new file mode 100644 index 00000000000..fd5fbed08cd --- /dev/null +++ b/core/Command/User/Profile.php @@ -0,0 +1,234 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OC\Core\Command\User; + +use OC\Core\Command\Base; +use OCP\Accounts\IAccount; +use OCP\Accounts\IAccountManager; +use OCP\Accounts\PropertyDoesNotExistException; +use OCP\IUser; +use OCP\IUserManager; +use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +class Profile extends Base { + public function __construct( + protected IUserManager $userManager, + protected IAccountManager $accountManager, + ) { + parent::__construct(); + } + + protected function configure() { + parent::configure(); + $this + ->setName('user:profile') + ->setDescription('Read and modify user profile properties') + ->addArgument( + 'uid', + InputArgument::REQUIRED, + 'Account ID used to login' + ) + ->addArgument( + 'key', + InputArgument::OPTIONAL, + 'Profile property to set, get or delete', + '' + ) + + // Get + ->addOption( + 'default-value', + null, + InputOption::VALUE_REQUIRED, + '(Only applicable on get) If no default value is set and the property does not exist, the command will exit with 1' + ) + + // Set + ->addArgument( + 'value', + InputArgument::OPTIONAL, + 'The new value of the property', + null + ) + ->addOption( + 'update-only', + null, + InputOption::VALUE_NONE, + 'Only updates the value, if it is not set before, it is not being added' + ) + + // Delete + ->addOption( + 'delete', + null, + InputOption::VALUE_NONE, + 'Specify this option to delete the property value' + ) + ->addOption( + 'error-if-not-exists', + null, + InputOption::VALUE_NONE, + 'Checks whether the property exists before deleting it' + ) + ; + } + + protected function checkInput(InputInterface $input): IUser { + $uid = $input->getArgument('uid'); + $user = $this->userManager->get($uid); + if (!$user) { + throw new \InvalidArgumentException('The user "' . $uid . '" does not exist.'); + } + // normalize uid + $input->setArgument('uid', $user->getUID()); + + $key = $input->getArgument('key'); + if ($key === '') { + if ($input->hasParameterOption('--default-value')) { + throw new \InvalidArgumentException('The "default-value" option can only be used when specifying a key.'); + } + if ($input->getArgument('value') !== null) { + throw new \InvalidArgumentException('The value argument can only be used when specifying a key.'); + } + if ($input->getOption('delete')) { + throw new \InvalidArgumentException('The "delete" option can only be used when specifying a key.'); + } + } + + if ($input->getArgument('value') !== null && $input->hasParameterOption('--default-value')) { + throw new \InvalidArgumentException('The value argument can not be used together with "default-value".'); + } + if ($input->getOption('update-only') && $input->getArgument('value') === null) { + throw new \InvalidArgumentException('The "update-only" option can only be used together with "value".'); + } + + if ($input->getOption('delete') && $input->hasParameterOption('--default-value')) { + throw new \InvalidArgumentException('The "delete" option can not be used together with "default-value".'); + } + if ($input->getOption('delete') && $input->getArgument('value') !== null) { + throw new \InvalidArgumentException('The "delete" option can not be used together with "value".'); + } + if ($input->getOption('error-if-not-exists') && !$input->getOption('delete')) { + throw new \InvalidArgumentException('The "error-if-not-exists" option can only be used together with "delete".'); + } + + return $user; + } + + protected function execute(InputInterface $input, OutputInterface $output): int { + try { + $user = $this->checkInput($input); + } catch (\InvalidArgumentException $e) { + $output->writeln('<error>' . $e->getMessage() . '</error>'); + return self::FAILURE; + } + + $uid = $input->getArgument('uid'); + $key = $input->getArgument('key'); + $userAccount = $this->accountManager->getAccount($user); + + if ($key === '') { + $settings = $this->getAllProfileProperties($userAccount); + $this->writeArrayInOutputFormat($input, $output, $settings); + return self::SUCCESS; + } + + $value = $this->getStoredValue($userAccount, $key); + $inputValue = $input->getArgument('value'); + if ($inputValue !== null) { + if ($input->hasParameterOption('--update-only') && $value === null) { + $output->writeln('<error>The property does not exist for user "' . $uid . '".</error>'); + return self::FAILURE; + } + + return $this->editProfileProperty($output, $userAccount, $key, $inputValue); + } elseif ($input->hasParameterOption('--delete')) { + if ($input->hasParameterOption('--error-if-not-exists') && $value === null) { + $output->writeln('<error>The property does not exist for user "' . $uid . '".</error>'); + return self::FAILURE; + } + + return $this->deleteProfileProperty($output, $userAccount, $key); + } elseif ($value !== null) { + $output->writeln($value); + } elseif ($input->hasParameterOption('--default-value')) { + $output->writeln($input->getOption('default-value')); + } else { + $output->writeln('<error>The property does not exist for user "' . $uid . '".</error>'); + return self::FAILURE; + } + + return self::SUCCESS; + } + + private function deleteProfileProperty(OutputInterface $output, IAccount $userAccount, string $key): int { + return $this->editProfileProperty($output, $userAccount, $key, ''); + } + + private function editProfileProperty(OutputInterface $output, IAccount $userAccount, string $key, string $value): int { + try { + $userAccount->getProperty($key)->setValue($value); + } catch (PropertyDoesNotExistException $exception) { + $output->writeln('<error>' . $exception->getMessage() . '</error>'); + return self::FAILURE; + } + + $this->accountManager->updateAccount($userAccount); + return self::SUCCESS; + } + + private function getStoredValue(IAccount $userAccount, string $key): ?string { + try { + $property = $userAccount->getProperty($key); + } catch (PropertyDoesNotExistException) { + return null; + } + return $property->getValue() === '' ? null : $property->getValue(); + } + + private function getAllProfileProperties(IAccount $userAccount): array { + $properties = []; + + foreach ($userAccount->getAllProperties() as $property) { + if ($property->getValue() !== '') { + $properties[$property->getName()] = $property->getValue(); + } + } + + return $properties; + } + + /** + * @param string $argumentName + * @param CompletionContext $context + * @return string[] + */ + public function completeArgumentValues($argumentName, CompletionContext $context): array { + if ($argumentName === 'uid') { + return array_map(static fn (IUser $user) => $user->getUID(), $this->userManager->search($context->getCurrentWord())); + } + if ($argumentName === 'key') { + $userId = $context->getWordAtIndex($context->getWordIndex() - 1); + $user = $this->userManager->get($userId); + if (!($user instanceof IUser)) { + return []; + } + + $account = $this->accountManager->getAccount($user); + + $properties = $this->getAllProfileProperties($account); + return array_keys($properties); + } + return []; + } +} diff --git a/core/Command/User/ResetPassword.php b/core/Command/User/ResetPassword.php index 3233424ff4c..0e8b1325770 100644 --- a/core/Command/User/ResetPassword.php +++ b/core/Command/User/ResetPassword.php @@ -41,7 +41,7 @@ class ResetPassword extends Base { 'password-from-env', null, InputOption::VALUE_NONE, - 'read password from environment variable OC_PASS' + 'read password from environment variable NC_PASS/OC_PASS' ) ; } @@ -56,9 +56,9 @@ class ResetPassword extends Base { } if ($input->getOption('password-from-env')) { - $password = getenv('OC_PASS'); + $password = getenv('NC_PASS') ?: getenv('OC_PASS'); if (!$password) { - $output->writeln('<error>--password-from-env given, but OC_PASS is empty!</error>'); + $output->writeln('<error>--password-from-env given, but NC_PASS/OC_PASS is empty!</error>'); return 1; } } elseif ($input->isInteractive()) { @@ -81,7 +81,7 @@ class ResetPassword extends Base { $password = $helper->ask($input, $output, $question); if ($password === null) { - $output->writeln("<error>Password cannot be empty!</error>"); + $output->writeln('<error>Password cannot be empty!</error>'); return 1; } @@ -90,11 +90,11 @@ class ResetPassword extends Base { $confirm = $helper->ask($input, $output, $question); if ($password !== $confirm) { - $output->writeln("<error>Passwords did not match!</error>"); + $output->writeln('<error>Passwords did not match!</error>'); return 1; } } else { - $output->writeln("<error>Interactive input or --password-from-env is needed for entering a new password!</error>"); + $output->writeln('<error>Interactive input or --password-from-env is needed for entering a new password!</error>'); return 1; } @@ -107,9 +107,9 @@ class ResetPassword extends Base { } if ($success) { - $output->writeln("<info>Successfully reset password for " . $username . "</info>"); + $output->writeln('<info>Successfully reset password for ' . $username . '</info>'); } else { - $output->writeln("<error>Error while resetting password!</error>"); + $output->writeln('<error>Error while resetting password!</error>'); return 1; } return 0; diff --git a/core/Command/User/Setting.php b/core/Command/User/Setting.php index e2e65f7d5f9..7fc5aab1dc7 100644 --- a/core/Command/User/Setting.php +++ b/core/Command/User/Setting.php @@ -155,7 +155,8 @@ class Setting extends Base { $user = $this->userManager->get($uid); if ($user instanceof IUser) { if ($key === 'email') { - $user->setEMailAddress($input->getArgument('value')); + $email = $input->getArgument('value'); + $user->setSystemEMailAddress(mb_strtolower(trim($email))); } elseif ($key === 'display_name') { if (!$user->setDisplayName($input->getArgument('value'))) { if ($user->getDisplayName() === $input->getArgument('value')) { @@ -219,7 +220,7 @@ class Setting extends Base { } } - protected function getUserSettings($uid, $app) { + protected function getUserSettings(string $uid, string $app): array { $settings = $this->config->getAllUserValues($uid); if ($app !== '') { if (isset($settings[$app])) { @@ -230,7 +231,10 @@ class Setting extends Base { } $user = $this->userManager->get($uid); - $settings['settings']['display_name'] = $user->getDisplayName(); + if ($user !== null) { + // Only add the display name if the user exists + $settings['settings']['display_name'] = $user->getDisplayName(); + } return $settings; } diff --git a/core/Command/User/SyncAccountDataCommand.php b/core/Command/User/SyncAccountDataCommand.php index 6a70f1239f6..c353df6fe9f 100644 --- a/core/Command/User/SyncAccountDataCommand.php +++ b/core/Command/User/SyncAccountDataCommand.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later @@ -16,15 +17,10 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class SyncAccountDataCommand extends Base { - protected IUserManager $userManager; - protected IAccountManager $accountManager; - public function __construct( - IUserManager $userManager, - IAccountManager $accountManager + protected IUserManager $userManager, + protected IAccountManager $accountManager, ) { - $this->userManager = $userManager; - $this->accountManager = $accountManager; parent::__construct(); } @@ -48,7 +44,7 @@ class SyncAccountDataCommand extends Base { } protected function execute(InputInterface $input, OutputInterface $output): int { - $users = $this->userManager->searchDisplayName('', (int) $input->getOption('limit'), (int) $input->getOption('offset')); + $users = $this->userManager->searchDisplayName('', (int)$input->getOption('limit'), (int)$input->getOption('offset')); foreach ($users as $user) { $this->updateUserAccount($user, $output); diff --git a/core/Command/User/Welcome.php b/core/Command/User/Welcome.php new file mode 100644 index 00000000000..65637759689 --- /dev/null +++ b/core/Command/User/Welcome.php @@ -0,0 +1,78 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2023 FedericoHeichou <federicoheichou@gmail.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OC\Core\Command\User; + +use OC\Core\Command\Base; +use OCA\Settings\Mailer\NewUserMailHelper; +use OCP\IUserManager; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +class Welcome extends Base { + /** + * @param IUserManager $userManager + * @param NewUserMailHelper $newUserMailHelper + */ + public function __construct( + protected IUserManager $userManager, + private NewUserMailHelper $newUserMailHelper, + ) { + parent::__construct(); + } + + /** + * @return void + */ + protected function configure() { + $this + ->setName('user:welcome') + ->setDescription('Sends the welcome email') + ->addArgument( + 'user', + InputArgument::REQUIRED, + 'The user to send the email to' + ) + ->addOption( + 'reset-password', + 'r', + InputOption::VALUE_NONE, + 'Add the reset password link to the email' + ) + ; + } + + /** + * @param InputInterface $input + * @param OutputInterface $output + * @return int + */ + protected function execute(InputInterface $input, OutputInterface $output): int { + $userId = $input->getArgument('user'); + // check if user exists + $user = $this->userManager->get($userId); + if ($user === null) { + $output->writeln('<error>User does not exist</error>'); + return 1; + } + $email = $user->getEMailAddress(); + if ($email === '' || $email === null) { + $output->writeln('<error>User does not have an email address</error>'); + return 1; + } + try { + $emailTemplate = $this->newUserMailHelper->generateTemplate($user, $input->getOption('reset-password')); + $this->newUserMailHelper->sendMail($user, $emailTemplate); + } catch (\Exception $e) { + $output->writeln('<error>Failed to send email: ' . $e->getMessage() . '</error>'); + return 1; + } + return 0; + } +} |