aboutsummaryrefslogtreecommitdiffstats
path: root/core/Command/User
diff options
context:
space:
mode:
Diffstat (limited to 'core/Command/User')
-rw-r--r--core/Command/User/Add.php6
-rw-r--r--core/Command/User/AuthTokens/Add.php4
-rw-r--r--core/Command/User/AuthTokens/Delete.php1
-rw-r--r--core/Command/User/AuthTokens/ListCommand.php1
-rw-r--r--core/Command/User/Info.php4
-rw-r--r--core/Command/User/LastSeen.php2
-rw-r--r--core/Command/User/ListCommand.php1
-rw-r--r--core/Command/User/Profile.php234
-rw-r--r--core/Command/User/ResetPassword.php6
-rw-r--r--core/Command/User/SyncAccountDataCommand.php10
-rw-r--r--core/Command/User/Welcome.php14
11 files changed, 255 insertions, 28 deletions
diff --git a/core/Command/User/Add.php b/core/Command/User/Add.php
index 033d2bdc9a2..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')) {
diff --git a/core/Command/User/AuthTokens/Add.php b/core/Command/User/AuthTokens/Add.php
index ad4bf732bd0..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()) {
diff --git a/core/Command/User/AuthTokens/Delete.php b/core/Command/User/AuthTokens/Delete.php
index f2c75a8ad99..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
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/Info.php b/core/Command/User/Info.php
index 6487b533fa2..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;
@@ -84,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 dbb611a4fff..984def72cd6 100644
--- a/core/Command/User/LastSeen.php
+++ b/core/Command/User/LastSeen.php
@@ -68,7 +68,7 @@ class LastSeen extends Base {
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.');
diff --git a/core/Command/User/ListCommand.php b/core/Command/User/ListCommand.php
index e7fb3de71f0..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
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 2f18c3d473e..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()) {
diff --git a/core/Command/User/SyncAccountDataCommand.php b/core/Command/User/SyncAccountDataCommand.php
index 640b66581e1..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();
}
diff --git a/core/Command/User/Welcome.php b/core/Command/User/Welcome.php
index c383811f982..65637759689 100644
--- a/core/Command/User/Welcome.php
+++ b/core/Command/User/Welcome.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2023 FedericoHeichou <federicoheichou@gmail.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
@@ -15,24 +16,15 @@ use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class Welcome extends Base {
- /** @var IUserManager */
- protected $userManager;
-
- /** @var NewUserMailHelper */
- private $newUserMailHelper;
-
/**
* @param IUserManager $userManager
* @param NewUserMailHelper $newUserMailHelper
*/
public function __construct(
- IUserManager $userManager,
- NewUserMailHelper $newUserMailHelper,
+ protected IUserManager $userManager,
+ private NewUserMailHelper $newUserMailHelper,
) {
parent::__construct();
-
- $this->userManager = $userManager;
- $this->newUserMailHelper = $newUserMailHelper;
}
/**