diff options
Diffstat (limited to 'core/Command/User')
-rw-r--r-- | core/Command/User/Add.php | 37 | ||||
-rw-r--r-- | core/Command/User/AuthTokens/Add.php | 28 | ||||
-rw-r--r-- | core/Command/User/AuthTokens/Delete.php | 24 | ||||
-rw-r--r-- | core/Command/User/AuthTokens/ListCommand.php | 22 | ||||
-rw-r--r-- | core/Command/User/ClearGeneratedAvatarCacheCommand.php | 24 | ||||
-rw-r--r-- | core/Command/User/Delete.php | 25 | ||||
-rw-r--r-- | core/Command/User/Disable.php | 24 | ||||
-rw-r--r-- | core/Command/User/Enable.php | 24 | ||||
-rw-r--r-- | core/Command/User/Info.php | 40 | ||||
-rw-r--r-- | core/Command/User/Keys/Verify.php | 21 | ||||
-rw-r--r-- | core/Command/User/LastSeen.php | 35 | ||||
-rw-r--r-- | core/Command/User/ListCommand.php | 61 | ||||
-rw-r--r-- | core/Command/User/Profile.php | 234 | ||||
-rw-r--r-- | core/Command/User/Report.php | 26 | ||||
-rw-r--r-- | core/Command/User/ResetPassword.php | 44 | ||||
-rw-r--r-- | core/Command/User/Setting.php | 36 | ||||
-rw-r--r-- | core/Command/User/SyncAccountDataCommand.php | 33 | ||||
-rw-r--r-- | core/Command/User/Welcome.php | 78 |
18 files changed, 434 insertions, 382 deletions
diff --git a/core/Command/User/Add.php b/core/Command/User/Add.php index 3411946fdeb..4de4e247991 100644 --- a/core/Command/User/Add.php +++ b/core/Command/User/Add.php @@ -1,28 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Anupam Kumar <kyteinsky@gmail.com> - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Joas Schilling <coding@schilljs.com> - * @author Laurens Post <lkpost@scept.re> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Core\Command\User; @@ -71,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', @@ -110,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')) { @@ -133,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 e055d210447..89b20535c63 100644 --- a/core/Command/User/AuthTokens/Add.php +++ b/core/Command/User/AuthTokens/Add.php @@ -3,26 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, NextCloud, Inc. - * - * @author Bjoern Schiessle <bjoern@schiessle.org> - * @author Sean Molenaar <sean@seanmolenaar.eu> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\Core\Command\User\AuthTokens; @@ -80,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()) { @@ -99,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 56bfcf787f8..2047d2eae2a 100644 --- a/core/Command/User/AuthTokens/Delete.php +++ b/core/Command/User/AuthTokens/Delete.php @@ -1,24 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2023 Lucas Azevedo <lhs_azevedo@hotmail.com> - * - * @author Lucas Azevedo <lhs_azevedo@hotmail.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\Core\Command\User\AuthTokens; @@ -63,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 0bcd2e55225..b36aa717505 100644 --- a/core/Command/User/AuthTokens/ListCommand.php +++ b/core/Command/User/AuthTokens/ListCommand.php @@ -1,24 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2023 Lucas Azevedo <lhs_azevedo@hotmail.com> - * - * @author Lucas Azevedo <lhs_azevedo@hotmail.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\Core\Command\User\AuthTokens; diff --git a/core/Command/User/ClearGeneratedAvatarCacheCommand.php b/core/Command/User/ClearGeneratedAvatarCacheCommand.php index 45ee4d36051..515b3a913b7 100644 --- a/core/Command/User/ClearGeneratedAvatarCacheCommand.php +++ b/core/Command/User/ClearGeneratedAvatarCacheCommand.php @@ -3,24 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2024, Nextcloud GmbH - * - * @author Kareem <yemkareems@gmail.com> - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\Core\Command\User; @@ -43,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/Delete.php b/core/Command/User/Delete.php index 94390a3f070..c5d0578f5f8 100644 --- a/core/Command/User/Delete.php +++ b/core/Command/User/Delete.php @@ -1,26 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Jens-Christian Fischer <jens-christian.fischer@switch.ch> - * @author Joas Schilling <coding@schilljs.com> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Core\Command\User; diff --git a/core/Command/User/Disable.php b/core/Command/User/Disable.php index 3fdf6220f45..4713950bf30 100644 --- a/core/Command/User/Disable.php +++ b/core/Command/User/Disable.php @@ -1,25 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Joas Schilling <coding@schilljs.com> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Core\Command\User; diff --git a/core/Command/User/Enable.php b/core/Command/User/Enable.php index 2055bd30cec..23f56e5dd4f 100644 --- a/core/Command/User/Enable.php +++ b/core/Command/User/Enable.php @@ -1,25 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Joas Schilling <coding@schilljs.com> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Core\Command\User; diff --git a/core/Command/User/Info.php b/core/Command/User/Info.php index a8fb62099e2..e7fc9286e74 100644 --- a/core/Command/User/Info.php +++ b/core/Command/User/Info.php @@ -1,30 +1,13 @@ <?php + /** - * @copyright Copyright (c) 2016 Robin Appelman <robin@icewind.nl> - * - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <robin@icewind.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2016 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\Files\NotFoundException; use OCP\IGroupManager; use OCP\IUser; use OCP\IUserManager; @@ -75,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() ]; @@ -83,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 @@ -92,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/Keys/Verify.php b/core/Command/User/Keys/Verify.php index c4264457572..024e9346072 100644 --- a/core/Command/User/Keys/Verify.php +++ b/core/Command/User/Keys/Verify.php @@ -3,25 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2024, Marcel Müller <marcel.mueller@nextcloud.com> - * - * @author Marcel Müller <marcel.mueller@nextcloud.com> - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\Core\Command\User\Keys; diff --git a/core/Command/User/LastSeen.php b/core/Command/User/LastSeen.php index d78d8661ecf..984def72cd6 100644 --- a/core/Command/User/LastSeen.php +++ b/core/Command/User/LastSeen.php @@ -1,27 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Joas Schilling <coding@schilljs.com> - * @author Pierre Ozoux <pierre@ozoux.net> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Core\Command\User; @@ -61,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)) { @@ -74,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 c30d2a55395..66b831c793b 100644 --- a/core/Command/User/ListCommand.php +++ b/core/Command/User/ListCommand.php @@ -1,26 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2016 Robin Appelman <robin@icewind.nl> - * - * @author Joas Schilling <coding@schilljs.com> - * @author John Molakvoæ <skjnldsv@protonmail.com> - * @author Robin Appelman <robin@icewind.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\Core\Command\User; @@ -77,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'))); @@ -88,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(), @@ -107,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/Report.php b/core/Command/User/Report.php index b54ec2b0308..c0f054adb00 100644 --- a/core/Command/User/Report.php +++ b/core/Command/User/Report.php @@ -3,29 +3,9 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Core\Command\User; diff --git a/core/Command/User/ResetPassword.php b/core/Command/User/ResetPassword.php index a94be81fed8..0e8b1325770 100644 --- a/core/Command/User/ResetPassword.php +++ b/core/Command/User/ResetPassword.php @@ -1,29 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Andreas Fischer <bantu@owncloud.com> - * @author Christopher Schäpers <kondou@ts.unde.re> - * @author Clark Tomlinson <fallen013@gmail.com> - * @author Joas Schilling <coding@schilljs.com> - * @author Laurens Post <lkpost@scept.re> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Sujith H <sharidasan@owncloud.com> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Core\Command\User; @@ -61,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' ) ; } @@ -76,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()) { @@ -101,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; } @@ -110,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; } @@ -127,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 9134d174418..7fc5aab1dc7 100644 --- a/core/Command/User/Setting.php +++ b/core/Command/User/Setting.php @@ -1,27 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Joas Schilling <coding@schilljs.com> - * @author Johannes Leuker <j.leuker@hosting.de> - * @author Kim Brose <kim.brose@rwth-aachen.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Core\Command\User; @@ -173,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')) { @@ -237,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])) { @@ -248,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 6a4a600ea03..c353df6fe9f 100644 --- a/core/Command/User/SyncAccountDataCommand.php +++ b/core/Command/User/SyncAccountDataCommand.php @@ -1,24 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2023 Julius Härrtl <jus@bitgrid.net> - * - * @author Julius Härrtl <jus@bitgrid.net> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\Core\Command\User; @@ -33,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(); } @@ -65,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; + } +} |