diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/Command/User/Profile.php | 234 | ||||
-rw-r--r-- | core/l10n/gl.js | 2 | ||||
-rw-r--r-- | core/l10n/gl.json | 2 | ||||
-rw-r--r-- | core/l10n/lv.js | 9 | ||||
-rw-r--r-- | core/l10n/lv.json | 9 | ||||
-rw-r--r-- | core/l10n/nl.js | 1 | ||||
-rw-r--r-- | core/l10n/nl.json | 1 | ||||
-rw-r--r-- | core/l10n/ru.js | 5 | ||||
-rw-r--r-- | core/l10n/ru.json | 5 | ||||
-rw-r--r-- | core/register_command.php | 2 | ||||
-rw-r--r-- | core/src/OC/eventsource.js | 4 |
11 files changed, 262 insertions, 12 deletions
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/l10n/gl.js b/core/l10n/gl.js index 92a28bcbc32..6dcb3d53731 100644 --- a/core/l10n/gl.js +++ b/core/l10n/gl.js @@ -232,7 +232,7 @@ OC.L10N.register( "Continue with this unsupported browser" : "Continuar con este navegador non compatíbel", "Supported versions" : "Versións compatíbeis", "Search {types} …" : "Buscando {types}…", - "Choose {file}" : "Escoller {file}", + "Choose {file}" : "Escoller {file}", "Choose" : "Escoller", "Copy to {target}" : "Copiar en {target}", "Copy" : "Copiar", diff --git a/core/l10n/gl.json b/core/l10n/gl.json index bd56103b250..a3c2e30ff40 100644 --- a/core/l10n/gl.json +++ b/core/l10n/gl.json @@ -230,7 +230,7 @@ "Continue with this unsupported browser" : "Continuar con este navegador non compatíbel", "Supported versions" : "Versións compatíbeis", "Search {types} …" : "Buscando {types}…", - "Choose {file}" : "Escoller {file}", + "Choose {file}" : "Escoller {file}", "Choose" : "Escoller", "Copy to {target}" : "Copiar en {target}", "Copy" : "Copiar", diff --git a/core/l10n/lv.js b/core/l10n/lv.js index b5c4eb91dbf..701a410cef0 100644 --- a/core/l10n/lv.js +++ b/core/l10n/lv.js @@ -27,19 +27,20 @@ OC.L10N.register( "Could not complete login" : "Nevarēja pabeigt pieteikšanos", "State token missing" : "Trūkst stāvokļa tekstvienības", "Your login token is invalid or has expired" : "Pieteikšanās pilnvara nav derīga vai ir beigusies", - "This community release of Nextcloud is unsupported and push notifications are limited." : "Šī Nextcloud kopienas versija nav atbalstīta un push paziņojumi ir ierobežoti.", + "Please use original client" : "Lūgums izmantot sākotnējo klientu", + "This community release of Nextcloud is unsupported and push notifications are limited." : "Šis Nextcloud kopienas laidiens nav atbalstīts un pašpiegādes paziņojumi ir ierobežoti.", "Login" : "Pieteikumvārds", - "Unsupported email length (>255)" : "Neatbalstāms e-pasta garums (>255)", + "Unsupported email length (>255)" : "Neatbalstīts e-pasta adreses garums (>255)", "Password reset is disabled" : "Paroles atiestatīšana ir atspējota", "Could not reset password because the token is expired" : "Nevarēja atiestatīt paroli, jo ir beidzies tekstvienības derīgums", "Could not reset password because the token is invalid" : "Nevarēja atiestatīt paroli, jo tekstvienība ir nederīga", "Password is too long. Maximum allowed length is 469 characters." : "Parole ir pārāk gara. Lielākais atļautais garums ir 469 rakstzīmes.", - "%s password reset" : "%s paroles maiņa", + "%s password reset" : "%s paroles atiestatīšana", "Password reset" : "Parole atiestatīta", "Click the following button to reset your password. If you have not requested the password reset, then ignore this email." : "Jānospiež zemāk esošā poga, lai atiestatītu savu paroli. Šis e-pasta ziņojums nav jāņem vērā, ja paroles atiestatīšana netika pieprasīta.", "Click the following link to reset your password. If you have not requested the password reset, then ignore this email." : "Jāklikšķina uz zemāk esošās saites, lai atiestatītu savu paroli. Šis e-pasta ziņojums nav jāņem vērā, ja paroles atiestatīšana netika pieprasīta.", "Reset your password" : "Atiestatīt paroli", - "The given provider is not available" : "Norādītājs pakalpojuma sniedzējs nav pieejams", + "The given provider is not available" : "Norādītais nodrošinātājs nav pieejams", "Task not found" : "Uzdevums nav atrasts", "Internal error" : "Iekšēja kļūda", "Not found" : "Nav atrasts", diff --git a/core/l10n/lv.json b/core/l10n/lv.json index b0e26a06ba7..e49b799e59b 100644 --- a/core/l10n/lv.json +++ b/core/l10n/lv.json @@ -25,19 +25,20 @@ "Could not complete login" : "Nevarēja pabeigt pieteikšanos", "State token missing" : "Trūkst stāvokļa tekstvienības", "Your login token is invalid or has expired" : "Pieteikšanās pilnvara nav derīga vai ir beigusies", - "This community release of Nextcloud is unsupported and push notifications are limited." : "Šī Nextcloud kopienas versija nav atbalstīta un push paziņojumi ir ierobežoti.", + "Please use original client" : "Lūgums izmantot sākotnējo klientu", + "This community release of Nextcloud is unsupported and push notifications are limited." : "Šis Nextcloud kopienas laidiens nav atbalstīts un pašpiegādes paziņojumi ir ierobežoti.", "Login" : "Pieteikumvārds", - "Unsupported email length (>255)" : "Neatbalstāms e-pasta garums (>255)", + "Unsupported email length (>255)" : "Neatbalstīts e-pasta adreses garums (>255)", "Password reset is disabled" : "Paroles atiestatīšana ir atspējota", "Could not reset password because the token is expired" : "Nevarēja atiestatīt paroli, jo ir beidzies tekstvienības derīgums", "Could not reset password because the token is invalid" : "Nevarēja atiestatīt paroli, jo tekstvienība ir nederīga", "Password is too long. Maximum allowed length is 469 characters." : "Parole ir pārāk gara. Lielākais atļautais garums ir 469 rakstzīmes.", - "%s password reset" : "%s paroles maiņa", + "%s password reset" : "%s paroles atiestatīšana", "Password reset" : "Parole atiestatīta", "Click the following button to reset your password. If you have not requested the password reset, then ignore this email." : "Jānospiež zemāk esošā poga, lai atiestatītu savu paroli. Šis e-pasta ziņojums nav jāņem vērā, ja paroles atiestatīšana netika pieprasīta.", "Click the following link to reset your password. If you have not requested the password reset, then ignore this email." : "Jāklikšķina uz zemāk esošās saites, lai atiestatītu savu paroli. Šis e-pasta ziņojums nav jāņem vērā, ja paroles atiestatīšana netika pieprasīta.", "Reset your password" : "Atiestatīt paroli", - "The given provider is not available" : "Norādītājs pakalpojuma sniedzējs nav pieejams", + "The given provider is not available" : "Norādītais nodrošinātājs nav pieejams", "Task not found" : "Uzdevums nav atrasts", "Internal error" : "Iekšēja kļūda", "Not found" : "Nav atrasts", diff --git a/core/l10n/nl.js b/core/l10n/nl.js index b5de7558cdc..04a11c30493 100644 --- a/core/l10n/nl.js +++ b/core/l10n/nl.js @@ -27,6 +27,7 @@ OC.L10N.register( "Could not complete login" : "De login kon niet worden voltooid", "State token missing" : "Toestandstoken bestaat niet", "Your login token is invalid or has expired" : "Je inlogtoken is ongeldig of is vervallen", + "Please use original client" : "Gebruik alsjeblieft de originele client", "This community release of Nextcloud is unsupported and push notifications are limited." : "Deze community release van Nextcloud wordt niet ondersteund en meldingen zijn beperkt", "Login" : "Inloggen", "Unsupported email length (>255)" : "Niet ondersteunde e-maillengte (>255)", diff --git a/core/l10n/nl.json b/core/l10n/nl.json index d096601a4cb..cf651e8ed18 100644 --- a/core/l10n/nl.json +++ b/core/l10n/nl.json @@ -25,6 +25,7 @@ "Could not complete login" : "De login kon niet worden voltooid", "State token missing" : "Toestandstoken bestaat niet", "Your login token is invalid or has expired" : "Je inlogtoken is ongeldig of is vervallen", + "Please use original client" : "Gebruik alsjeblieft de originele client", "This community release of Nextcloud is unsupported and push notifications are limited." : "Deze community release van Nextcloud wordt niet ondersteund en meldingen zijn beperkt", "Login" : "Inloggen", "Unsupported email length (>255)" : "Niet ondersteunde e-maillengte (>255)", diff --git a/core/l10n/ru.js b/core/l10n/ru.js index 9a8542a6abe..3b3a18387d5 100644 --- a/core/l10n/ru.js +++ b/core/l10n/ru.js @@ -328,6 +328,11 @@ OC.L10N.register( "Login form is disabled." : "Форма входа отключена.", "The Nextcloud login form is disabled. Use another login option if available or contact your administration." : "Диалог входа отключен. Используйте другой способ входа или свяжитесь с администратором.", "More actions" : "Больше действий", + "User menu" : "Меню пользователя", + "You will be identified as {user} by the account owner." : "Владелец учётной записи будет видеть вас как {user}.", + "You are currently not identified." : "В данный момент вы не идентифицированы.", + "Set public name" : "Задать публичное имя", + "Change public name" : "Изменить публичное имя", "Password is too weak" : "Пароль слишком слабый", "Password is weak" : "Пароль слабый", "Password is average" : "Пароль средний", diff --git a/core/l10n/ru.json b/core/l10n/ru.json index 9e765e2dc41..f4f2442d2e4 100644 --- a/core/l10n/ru.json +++ b/core/l10n/ru.json @@ -326,6 +326,11 @@ "Login form is disabled." : "Форма входа отключена.", "The Nextcloud login form is disabled. Use another login option if available or contact your administration." : "Диалог входа отключен. Используйте другой способ входа или свяжитесь с администратором.", "More actions" : "Больше действий", + "User menu" : "Меню пользователя", + "You will be identified as {user} by the account owner." : "Владелец учётной записи будет видеть вас как {user}.", + "You are currently not identified." : "В данный момент вы не идентифицированы.", + "Set public name" : "Задать публичное имя", + "Change public name" : "Изменить публичное имя", "Password is too weak" : "Пароль слишком слабый", "Password is weak" : "Пароль слабый", "Password is average" : "Пароль средний", diff --git a/core/register_command.php b/core/register_command.php index 72a4b70f059..488317d2f5d 100644 --- a/core/register_command.php +++ b/core/register_command.php @@ -92,6 +92,7 @@ use OC\Core\Command\User\ClearGeneratedAvatarCacheCommand; use OC\Core\Command\User\Info; use OC\Core\Command\User\Keys\Verify; use OC\Core\Command\User\LastSeen; +use OC\Core\Command\User\Profile; use OC\Core\Command\User\Report; use OC\Core\Command\User\ResetPassword; use OC\Core\Command\User\Setting; @@ -206,6 +207,7 @@ if ($config->getSystemValueBool('installed', false)) { $application->add(Server::get(Report::class)); $application->add(Server::get(ResetPassword::class)); $application->add(Server::get(Setting::class)); + $application->add(Server::get(Profile::class)); $application->add(Server::get(Command\User\ListCommand::class)); $application->add(Server::get(ClearGeneratedAvatarCacheCommand::class)); $application->add(Server::get(Info::class)); diff --git a/core/src/OC/eventsource.js b/core/src/OC/eventsource.js index bfda0a73ad0..090c351c057 100644 --- a/core/src/OC/eventsource.js +++ b/core/src/OC/eventsource.js @@ -7,7 +7,7 @@ /* eslint-disable */ import $ from 'jquery' -import { getToken } from './requesttoken.ts' +import { getRequestToken } from './requesttoken.ts' /** * Create a new event source @@ -28,7 +28,7 @@ const OCEventSource = function(src, data) { dataStr += name + '=' + encodeURIComponent(data[name]) + '&' } } - dataStr += 'requesttoken=' + encodeURIComponent(getToken()) + dataStr += 'requesttoken=' + encodeURIComponent(getRequestToken()) if (!this.useFallBack && typeof EventSource !== 'undefined') { joinChar = '&' if (src.indexOf('?') === -1) { |