aboutsummaryrefslogtreecommitdiffstats
path: root/core/Command/User
diff options
context:
space:
mode:
Diffstat (limited to 'core/Command/User')
-rw-r--r--core/Command/User/Add.php10
-rw-r--r--core/Command/User/AuthTokens/Add.php6
-rw-r--r--core/Command/User/AuthTokens/Delete.php3
-rw-r--r--core/Command/User/AuthTokens/ListCommand.php1
-rw-r--r--core/Command/User/ClearGeneratedAvatarCacheCommand.php4
-rw-r--r--core/Command/User/Info.php17
-rw-r--r--core/Command/User/LastSeen.php9
-rw-r--r--core/Command/User/ListCommand.php38
-rw-r--r--core/Command/User/Profile.php234
-rw-r--r--core/Command/User/ResetPassword.php16
-rw-r--r--core/Command/User/Setting.php10
-rw-r--r--core/Command/User/SyncAccountDataCommand.php12
-rw-r--r--core/Command/User/Welcome.php78
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;
+ }
+}