Setting.php 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  5. * SPDX-License-Identifier: AGPL-3.0-only
  6. */
  7. namespace OC\Core\Command\User;
  8. use OC\Core\Command\Base;
  9. use OCP\IConfig;
  10. use OCP\IUser;
  11. use OCP\IUserManager;
  12. use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext;
  13. use Symfony\Component\Console\Input\InputArgument;
  14. use Symfony\Component\Console\Input\InputInterface;
  15. use Symfony\Component\Console\Input\InputOption;
  16. use Symfony\Component\Console\Output\OutputInterface;
  17. class Setting extends Base {
  18. public function __construct(
  19. protected IUserManager $userManager,
  20. protected IConfig $config,
  21. ) {
  22. parent::__construct();
  23. }
  24. protected function configure() {
  25. parent::configure();
  26. $this
  27. ->setName('user:setting')
  28. ->setDescription('Read and modify user settings')
  29. ->addArgument(
  30. 'uid',
  31. InputArgument::REQUIRED,
  32. 'Account ID used to login'
  33. )
  34. ->addArgument(
  35. 'app',
  36. InputArgument::OPTIONAL,
  37. 'Restrict the settings to a given app',
  38. ''
  39. )
  40. ->addArgument(
  41. 'key',
  42. InputArgument::OPTIONAL,
  43. 'Setting key to set, get or delete',
  44. ''
  45. )
  46. ->addOption(
  47. 'ignore-missing-user',
  48. null,
  49. InputOption::VALUE_NONE,
  50. 'Use this option to ignore errors when the user does not exist'
  51. )
  52. // Get
  53. ->addOption(
  54. 'default-value',
  55. null,
  56. InputOption::VALUE_REQUIRED,
  57. '(Only applicable on get) If no default value is set and the config does not exist, the command will exit with 1'
  58. )
  59. // Set
  60. ->addArgument(
  61. 'value',
  62. InputArgument::OPTIONAL,
  63. 'The new value of the setting',
  64. null
  65. )
  66. ->addOption(
  67. 'update-only',
  68. null,
  69. InputOption::VALUE_NONE,
  70. 'Only updates the value, if it is not set before, it is not being added'
  71. )
  72. // Delete
  73. ->addOption(
  74. 'delete',
  75. null,
  76. InputOption::VALUE_NONE,
  77. 'Specify this option to delete the config'
  78. )
  79. ->addOption(
  80. 'error-if-not-exists',
  81. null,
  82. InputOption::VALUE_NONE,
  83. 'Checks whether the setting exists before deleting it'
  84. )
  85. ;
  86. }
  87. protected function checkInput(InputInterface $input) {
  88. if (!$input->getOption('ignore-missing-user')) {
  89. $uid = $input->getArgument('uid');
  90. $user = $this->userManager->get($uid);
  91. if (!$user) {
  92. throw new \InvalidArgumentException('The user "' . $uid . '" does not exist.');
  93. }
  94. // normalize uid
  95. $input->setArgument('uid', $user->getUID());
  96. }
  97. if ($input->getArgument('key') === '' && $input->hasParameterOption('--default-value')) {
  98. throw new \InvalidArgumentException('The "default-value" option can only be used when specifying a key.');
  99. }
  100. if ($input->getArgument('key') === '' && $input->getArgument('value') !== null) {
  101. throw new \InvalidArgumentException('The value argument can only be used when specifying a key.');
  102. }
  103. if ($input->getArgument('value') !== null && $input->hasParameterOption('--default-value')) {
  104. throw new \InvalidArgumentException('The value argument can not be used together with "default-value".');
  105. }
  106. if ($input->getOption('update-only') && $input->getArgument('value') === null) {
  107. throw new \InvalidArgumentException('The "update-only" option can only be used together with "value".');
  108. }
  109. if ($input->getArgument('key') === '' && $input->getOption('delete')) {
  110. throw new \InvalidArgumentException('The "delete" option can only be used when specifying a key.');
  111. }
  112. if ($input->getOption('delete') && $input->hasParameterOption('--default-value')) {
  113. throw new \InvalidArgumentException('The "delete" option can not be used together with "default-value".');
  114. }
  115. if ($input->getOption('delete') && $input->getArgument('value') !== null) {
  116. throw new \InvalidArgumentException('The "delete" option can not be used together with "value".');
  117. }
  118. if ($input->getOption('error-if-not-exists') && !$input->getOption('delete')) {
  119. throw new \InvalidArgumentException('The "error-if-not-exists" option can only be used together with "delete".');
  120. }
  121. }
  122. protected function execute(InputInterface $input, OutputInterface $output): int {
  123. try {
  124. $this->checkInput($input);
  125. } catch (\InvalidArgumentException $e) {
  126. $output->writeln('<error>' . $e->getMessage() . '</error>');
  127. return 1;
  128. }
  129. $uid = $input->getArgument('uid');
  130. $app = $input->getArgument('app');
  131. $key = $input->getArgument('key');
  132. if ($key !== '') {
  133. $value = $this->config->getUserValue($uid, $app, $key, null);
  134. if ($input->getArgument('value') !== null) {
  135. if ($input->hasParameterOption('--update-only') && $value === null) {
  136. $output->writeln('<error>The setting does not exist for user "' . $uid . '".</error>');
  137. return 1;
  138. }
  139. if ($app === 'settings' && in_array($key, ['email', 'display_name'])) {
  140. $user = $this->userManager->get($uid);
  141. if ($user instanceof IUser) {
  142. if ($key === 'email') {
  143. $user->setEMailAddress($input->getArgument('value'));
  144. } elseif ($key === 'display_name') {
  145. if (!$user->setDisplayName($input->getArgument('value'))) {
  146. if ($user->getDisplayName() === $input->getArgument('value')) {
  147. $output->writeln('<error>New and old display name are the same</error>');
  148. } elseif ($input->getArgument('value') === '') {
  149. $output->writeln('<error>New display name can\'t be empty</error>');
  150. } else {
  151. $output->writeln('<error>Could not set display name</error>');
  152. }
  153. return 1;
  154. }
  155. }
  156. // setEmailAddress and setDisplayName both internally set the value
  157. return 0;
  158. }
  159. }
  160. $this->config->setUserValue($uid, $app, $key, $input->getArgument('value'));
  161. return 0;
  162. } elseif ($input->hasParameterOption('--delete')) {
  163. if ($input->hasParameterOption('--error-if-not-exists') && $value === null) {
  164. $output->writeln('<error>The setting does not exist for user "' . $uid . '".</error>');
  165. return 1;
  166. }
  167. if ($app === 'settings' && in_array($key, ['email', 'display_name'])) {
  168. $user = $this->userManager->get($uid);
  169. if ($user instanceof IUser) {
  170. if ($key === 'email') {
  171. $user->setEMailAddress('');
  172. // setEmailAddress already deletes the value
  173. return 0;
  174. } elseif ($key === 'display_name') {
  175. $output->writeln('<error>Display name can\'t be deleted.</error>');
  176. return 1;
  177. }
  178. }
  179. }
  180. $this->config->deleteUserValue($uid, $app, $key);
  181. return 0;
  182. } elseif ($value !== null) {
  183. $output->writeln($value);
  184. return 0;
  185. } elseif ($input->hasParameterOption('--default-value')) {
  186. $output->writeln($input->getOption('default-value'));
  187. return 0;
  188. } else {
  189. if ($app === 'settings' && $key === 'display_name') {
  190. $user = $this->userManager->get($uid);
  191. $output->writeln($user->getDisplayName());
  192. return 0;
  193. }
  194. $output->writeln('<error>The setting does not exist for user "' . $uid . '".</error>');
  195. return 1;
  196. }
  197. } else {
  198. $settings = $this->getUserSettings($uid, $app);
  199. $this->writeArrayInOutputFormat($input, $output, $settings);
  200. return 0;
  201. }
  202. }
  203. protected function getUserSettings($uid, $app) {
  204. $settings = $this->config->getAllUserValues($uid);
  205. if ($app !== '') {
  206. if (isset($settings[$app])) {
  207. $settings = [$app => $settings[$app]];
  208. } else {
  209. $settings = [];
  210. }
  211. }
  212. $user = $this->userManager->get($uid);
  213. $settings['settings']['display_name'] = $user->getDisplayName();
  214. return $settings;
  215. }
  216. /**
  217. * @param string $argumentName
  218. * @param CompletionContext $context
  219. * @return string[]
  220. */
  221. public function completeArgumentValues($argumentName, CompletionContext $context) {
  222. if ($argumentName === 'uid') {
  223. return array_map(static fn (IUser $user) => $user->getUID(), $this->userManager->search($context->getCurrentWord()));
  224. }
  225. if ($argumentName === 'app') {
  226. $userId = $context->getWordAtIndex($context->getWordIndex() - 1);
  227. $settings = $this->getUserSettings($userId, '');
  228. return array_keys($settings);
  229. }
  230. if ($argumentName === 'key') {
  231. $userId = $context->getWordAtIndex($context->getWordIndex() - 2);
  232. $app = $context->getWordAtIndex($context->getWordIndex() - 1);
  233. $settings = $this->getUserSettings($userId, $app);
  234. return array_keys($settings[$app]);
  235. }
  236. return [];
  237. }
  238. }