diff options
author | Joas Schilling <213943+nickvergessen@users.noreply.github.com> | 2020-05-08 18:00:15 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-08 18:00:15 +0300 |
commit | f6efeba96b5a2cf2a54962aa1e48ed055c9f721a (patch) | |
tree | c5bcf0eebd0bba2f205c5be804ebe161e8f80263 /lib | |
parent | 2b6a0b86775b07611fd7d09ea3094746ebe6192b (diff) | |
parent | 02f887acfe4206a876b5f31e52f5ed25252ebdbd (diff) |
Merge pull request #3465 from PhrozenByte/feature/cmd-room
Add talk:room:* CLI commands
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Command/Room/Add.php | 110 | ||||
-rw-r--r-- | lib/Command/Room/Create.php | 147 | ||||
-rw-r--r-- | lib/Command/Room/Delete.php | 76 | ||||
-rw-r--r-- | lib/Command/Room/Demote.php | 94 | ||||
-rw-r--r-- | lib/Command/Room/Promote.php | 94 | ||||
-rw-r--r-- | lib/Command/Room/Remove.php | 94 | ||||
-rw-r--r-- | lib/Command/Room/TRoomCommand.php | 338 | ||||
-rw-r--r-- | lib/Command/Room/Update.php | 152 |
8 files changed, 1105 insertions, 0 deletions
diff --git a/lib/Command/Room/Add.php b/lib/Command/Room/Add.php new file mode 100644 index 000000000..d213beb1e --- /dev/null +++ b/lib/Command/Room/Add.php @@ -0,0 +1,110 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2020 Daniel Rudolf <nextcloud.com@daniel-rudolf.de> + * + * @author Daniel Rudolf <nextcloud.com@daniel-rudolf.de> + * + * @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/>. + * + */ + +namespace OCA\Talk\Command\Room; + +use Exception; +use OC\Core\Command\Base; +use OCA\Talk\Exceptions\RoomNotFoundException; +use OCA\Talk\Manager; +use OCA\Talk\Room; +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 Add extends Base { + use TRoomCommand; + + /** @var IUserManager */ + public $userManager; + + /** @var Manager */ + public $manager; + + public function __construct(IUserManager $userManager, Manager $manager) { + parent::__construct(); + + $this->userManager = $userManager; + $this->manager = $manager; + } + + protected function configure(): void { + $this + ->setName('talk:room:add') + ->setDescription('Adds users to a room') + ->addArgument( + 'token', + InputArgument::REQUIRED, + 'Token of the room to add users to' + )->addOption( + 'user', + null, + InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, + 'Invites the given users to the room' + )->addOption( + 'group', + null, + InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, + 'Invites all members of the given groups to the room' + )->addOption( + 'circle', + null, + InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, + 'Invites all members of the given circles to the room' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output): ?int { + $token = $input->getArgument('token'); + $users = $input->getOption('user'); + $groups = $input->getOption('group'); + $circles = $input->getOption('circle'); + + try { + $room = $this->manager->getRoomByToken($token); + } catch (RoomNotFoundException $e) { + $output->writeln('<error>Room not found.</error>'); + return 1; + } + + if (!in_array($room->getType(), [Room::GROUP_CALL, Room::PUBLIC_CALL], true)) { + $output->writeln('<error>Room is no group call.</error>'); + return 1; + } + + try { + $this->addRoomParticipants($room, $users); + $this->addRoomParticipantsByGroup($room, $groups); + $this->addRoomParticipantsByCircle($room, $circles); + } catch (Exception $e) { + $output->writeln(sprintf('<error>%s</error>', $e->getMessage())); + return 1; + } + + $output->writeln('<info>Users successfully added to room.</info>'); + return 0; + } +} diff --git a/lib/Command/Room/Create.php b/lib/Command/Room/Create.php new file mode 100644 index 000000000..f2003e45d --- /dev/null +++ b/lib/Command/Room/Create.php @@ -0,0 +1,147 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2020 Daniel Rudolf <nextcloud.com@daniel-rudolf.de> + * + * @author Daniel Rudolf <nextcloud.com@daniel-rudolf.de> + * + * @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/>. + * + */ + +namespace OCA\Talk\Command\Room; + +use Exception; +use OC\Core\Command\Base; +use OCA\Talk\Manager; +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 Create extends Base { + use TRoomCommand; + + /** @var IUserManager */ + public $userManager; + + /** @var Manager */ + public $manager; + + public function __construct(IUserManager $userManager, Manager $manager) { + parent::__construct(); + + $this->userManager = $userManager; + $this->manager = $manager; + } + + protected function configure(): void { + $this + ->setName('talk:room:create') + ->setDescription('Create a new room') + ->addArgument( + 'name', + InputArgument::REQUIRED, + 'The name of the room to create' + )->addOption( + 'user', + null, + InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, + 'Invites the given users to the room to create' + )->addOption( + 'group', + null, + InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, + 'Invites all members of the given group to the room to create' + )->addOption( + 'circle', + null, + InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, + 'Invites all members of the given circle to the room to create' + )->addOption( + 'public', + null, + InputOption::VALUE_NONE, + 'Creates the room as public room if set' + )->addOption( + 'readonly', + null, + InputOption::VALUE_NONE, + 'Creates the room with read-only access only if set' + )->addOption( + 'password', + null, + InputOption::VALUE_REQUIRED, + 'Protects the room to create with the given password' + )->addOption( + 'owner', + null, + InputOption::VALUE_REQUIRED, + 'Sets the given user as owner of the room to create' + )->addOption( + 'moderator', + null, + InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, + 'Promotes the given users to moderators' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output): ?int { + $name = $input->getArgument('name'); + $users = $input->getOption('user'); + $groups = $input->getOption('group'); + $circles = $input->getOption('circle'); + $public = $input->getOption('public'); + $readonly = $input->getOption('readonly'); + $password = $input->getOption('password'); + $owner = $input->getOption('owner'); + $moderators = $input->getOption('moderator'); + + $name = trim($name); + if (!$this->validateRoomName($name)) { + $output->writeln("<error>Invalid room name.</error>"); + return 1; + } + + $room = $public ? $this->manager->createPublicRoom($name): $this->manager->createGroupRoom($name); + + try { + $this->setRoomReadOnly($room, $readonly); + + if ($password !== null) { + $this->setRoomPassword($room, $password); + } + + $this->addRoomParticipants($room, $users); + $this->addRoomParticipantsByGroup($room, $groups); + $this->addRoomParticipantsByCircle($room, $circles); + $this->addRoomModerators($room, $moderators); + + if ($owner !== null) { + $this->setRoomOwner($room, $owner); + } + } catch (Exception $e) { + $room->deleteRoom(); + + $output->writeln(sprintf('<error>%s</error>', $e->getMessage())); + return 1; + } + + $output->writeln('<info>Room successfully created.</info>'); + return 0; + } +} diff --git a/lib/Command/Room/Delete.php b/lib/Command/Room/Delete.php new file mode 100644 index 000000000..d065cc469 --- /dev/null +++ b/lib/Command/Room/Delete.php @@ -0,0 +1,76 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2020 Daniel Rudolf <nextcloud.com@daniel-rudolf.de> + * + * @author Daniel Rudolf <nextcloud.com@daniel-rudolf.de> + * + * @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/>. + * + */ + +namespace OCA\Talk\Command\Room; + +use OC\Core\Command\Base; +use OCA\Talk\Exceptions\RoomNotFoundException; +use OCA\Talk\Manager; +use OCA\Talk\Room; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class Delete extends Base { + /** @var Manager */ + public $manager; + + public function __construct(Manager $manager) { + parent::__construct(); + + $this->manager = $manager; + } + + protected function configure(): void { + $this + ->setName('talk:room:delete') + ->setDescription('Deletes a room') + ->addArgument( + 'token', + InputArgument::REQUIRED, + 'Token of the room to delete' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output): ?int { + $token = $input->getArgument('token'); + + try { + $room = $this->manager->getRoomByToken($token); + } catch (RoomNotFoundException $e) { + $output->writeln('<error>Room not found.</error>'); + return 1; + } + + if (!in_array($room->getType(), [Room::GROUP_CALL, Room::PUBLIC_CALL], true)) { + $output->writeln('<error>Room is no group call.</error>'); + return 1; + } + + $room->deleteRoom(); + + $output->writeln('<info>Room successfully deleted.</info>'); + return 0; + } +} diff --git a/lib/Command/Room/Demote.php b/lib/Command/Room/Demote.php new file mode 100644 index 000000000..008030811 --- /dev/null +++ b/lib/Command/Room/Demote.php @@ -0,0 +1,94 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2020 Daniel Rudolf <nextcloud.com@daniel-rudolf.de> + * + * @author Daniel Rudolf <nextcloud.com@daniel-rudolf.de> + * + * @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/>. + * + */ + +namespace OCA\Talk\Command\Room; + +use Exception; +use OC\Core\Command\Base; +use OCA\Talk\Exceptions\RoomNotFoundException; +use OCA\Talk\Manager; +use OCA\Talk\Room; +use OCP\IUserManager; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class Demote extends Base { + use TRoomCommand; + + /** @var IUserManager */ + public $userManager; + + /** @var Manager */ + public $manager; + + public function __construct(IUserManager $userManager, Manager $manager) { + parent::__construct(); + + $this->userManager = $userManager; + $this->manager = $manager; + } + + protected function configure(): void { + $this + ->setName('talk:room:demote') + ->setDescription('Demotes participants of a room to regular users') + ->addArgument( + 'token', + InputArgument::REQUIRED, + 'Token of the room in which users should be demoted' + )->addArgument( + 'participant', + InputArgument::REQUIRED | InputArgument::IS_ARRAY, + 'Demotes the given participants of the room to regular users' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output): ?int { + $token = $input->getArgument('token'); + $users = $input->getArgument('participant'); + + try { + $room = $this->manager->getRoomByToken($token); + } catch (RoomNotFoundException $e) { + $output->writeln('<error>Room not found.</error>'); + return 1; + } + + if (!in_array($room->getType(), [Room::GROUP_CALL, Room::PUBLIC_CALL], true)) { + $output->writeln('<error>Room is no group call.</error>'); + return 1; + } + + try { + $this->removeRoomModerators($room, $users); + } catch (Exception $e) { + $output->writeln(sprintf('<error>%s</error>', $e->getMessage())); + return 1; + } + + $output->writeln('<info>Users successfully remove from room.</info>'); + return 0; + } +} diff --git a/lib/Command/Room/Promote.php b/lib/Command/Room/Promote.php new file mode 100644 index 000000000..c55315343 --- /dev/null +++ b/lib/Command/Room/Promote.php @@ -0,0 +1,94 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2020 Daniel Rudolf <nextcloud.com@daniel-rudolf.de> + * + * @author Daniel Rudolf <nextcloud.com@daniel-rudolf.de> + * + * @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/>. + * + */ + +namespace OCA\Talk\Command\Room; + +use Exception; +use OC\Core\Command\Base; +use OCA\Talk\Exceptions\RoomNotFoundException; +use OCA\Talk\Manager; +use OCA\Talk\Room; +use OCP\IUserManager; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class Promote extends Base { + use TRoomCommand; + + /** @var IUserManager */ + public $userManager; + + /** @var Manager */ + public $manager; + + public function __construct(IUserManager $userManager, Manager $manager) { + parent::__construct(); + + $this->userManager = $userManager; + $this->manager = $manager; + } + + protected function configure(): void { + $this + ->setName('talk:room:promote') + ->setDescription('Promotes participants of a room to moderators') + ->addArgument( + 'token', + InputArgument::REQUIRED, + 'Token of the room in which users should be promoted' + )->addArgument( + 'participant', + InputArgument::REQUIRED | InputArgument::IS_ARRAY, + 'Promotes the given participants of the room to moderators' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output): ?int { + $token = $input->getArgument('token'); + $users = $input->getArgument('participant'); + + try { + $room = $this->manager->getRoomByToken($token); + } catch (RoomNotFoundException $e) { + $output->writeln('<error>Room not found.</error>'); + return 1; + } + + if (!in_array($room->getType(), [Room::GROUP_CALL, Room::PUBLIC_CALL], true)) { + $output->writeln('<error>Room is no group call.</error>'); + return 1; + } + + try { + $this->addRoomModerators($room, $users); + } catch (Exception $e) { + $output->writeln(sprintf('<error>%s</error>', $e->getMessage())); + return 1; + } + + $output->writeln('<info>Users successfully added to room.</info>'); + return 0; + } +} diff --git a/lib/Command/Room/Remove.php b/lib/Command/Room/Remove.php new file mode 100644 index 000000000..0c0f77012 --- /dev/null +++ b/lib/Command/Room/Remove.php @@ -0,0 +1,94 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2020 Daniel Rudolf <nextcloud.com@daniel-rudolf.de> + * + * @author Daniel Rudolf <nextcloud.com@daniel-rudolf.de> + * + * @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/>. + * + */ + +namespace OCA\Talk\Command\Room; + +use Exception; +use OC\Core\Command\Base; +use OCA\Talk\Exceptions\RoomNotFoundException; +use OCA\Talk\Manager; +use OCA\Talk\Room; +use OCP\IUserManager; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class Remove extends Base { + use TRoomCommand; + + /** @var IUserManager */ + public $userManager; + + /** @var Manager */ + public $manager; + + public function __construct(IUserManager $userManager, Manager $manager) { + parent::__construct(); + + $this->userManager = $userManager; + $this->manager = $manager; + } + + protected function configure(): void { + $this + ->setName('talk:room:remove') + ->setDescription('Remove users from a room') + ->addArgument( + 'token', + InputArgument::REQUIRED, + 'Token of the room to remove users from' + )->addArgument( + 'user', + InputArgument::REQUIRED | InputArgument::IS_ARRAY, + 'Removes the given users from the room' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output): ?int { + $token = $input->getArgument('token'); + $users = $input->getArgument('user'); + + try { + $room = $this->manager->getRoomByToken($token); + } catch (RoomNotFoundException $e) { + $output->writeln('<error>Room not found.</error>'); + return 1; + } + + if (!in_array($room->getType(), [Room::GROUP_CALL, Room::PUBLIC_CALL], true)) { + $output->writeln('<error>Room is no group call.</error>'); + return 1; + } + + try { + $this->removeRoomParticipants($room, $users); + } catch (Exception $e) { + $output->writeln(sprintf('<error>%s</error>', $e->getMessage())); + return 1; + } + + $output->writeln('<info>Users successfully remove from room.</info>'); + return 0; + } +} diff --git a/lib/Command/Room/TRoomCommand.php b/lib/Command/Room/TRoomCommand.php new file mode 100644 index 000000000..1b65d8d0d --- /dev/null +++ b/lib/Command/Room/TRoomCommand.php @@ -0,0 +1,338 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2020 Daniel Rudolf <nextcloud.com@daniel-rudolf.de> + * + * @author Daniel Rudolf <nextcloud.com@daniel-rudolf.de> + * + * @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/>. + * + */ + +namespace OCA\Talk\Command\Room; + +use InvalidArgumentException; +use OCA\Circles\Api\v1\Circles; +use OCA\Circles\Model\Member; +use OCA\Talk\Exceptions\ParticipantNotFoundException; +use OCA\Talk\Participant; +use OCA\Talk\Room; +use OCP\IUser; + +trait TRoomCommand +{ + /** + * @param Room $room + * @param string $name + * + * @throws InvalidArgumentException + */ + protected function setRoomName(Room $room, string $name): void { + $name = trim($name); + if ($name === $room->getName()) { + return; + } + + if (!$this->validateRoomName($name)) { + throw new InvalidArgumentException('Invalid room name.'); + } + + if (!$room->setName($name)) { + throw new InvalidArgumentException('Unable to change room name.'); + } + } + + /** + * @param string $name + * + * @return bool + * + * @throws InvalidArgumentException + */ + protected function validateRoomName(string $name): bool { + $name = trim($name); + return (($name !== '') && !isset($name[255])); + } + + /** + * @param Room $room + * @param bool $public + * + * @throws InvalidArgumentException + */ + protected function setRoomPublic(Room $room, bool $public): void { + if ($public === ($room->getType() === Room::PUBLIC_CALL)) { + return; + } + + if (!$public && $room->hasPassword()) { + throw new InvalidArgumentException('Unable to change password protected public room to private room.'); + } + + if (!$room->setType($public ? Room::PUBLIC_CALL : Room::GROUP_CALL)) { + throw new InvalidArgumentException('Unable to change room type.'); + } + } + + /** + * @param Room $room + * @param bool $readOnly + * + * @throws InvalidArgumentException + */ + protected function setRoomReadOnly(Room $room, bool $readOnly): void { + if ($readOnly === ($room->getReadOnly() === Room::READ_ONLY)) { + return; + } + + if (!$room->setReadOnly($readOnly ? Room::READ_ONLY : Room::READ_WRITE)) { + throw new InvalidArgumentException('Unable to change room state.'); + } + } + + /** + * @param Room $room + * @param string $password + * + * @throws InvalidArgumentException + */ + protected function setRoomPassword(Room $room, string $password): void { + if ($room->hasPassword() ? $room->verifyPassword($password)['result'] : ($password === '')) { + return; + } + + if (($password !== '') && ($room->getType() !== Room::PUBLIC_CALL)) { + throw new InvalidArgumentException('Unable to add password protection to private room.'); + } + + if (!$room->setPassword($password)) { + throw new InvalidArgumentException('Unable to change room password.'); + } + } + + /** + * @param Room $room + * @param string $userId + * + * @throws InvalidArgumentException + */ + protected function setRoomOwner(Room $room, string $userId): void { + try { + $participant = $room->getParticipant($userId); + } catch (ParticipantNotFoundException $e) { + throw new InvalidArgumentException(sprintf("User '%s' is no participant.", $userId)); + } + + $room->setParticipantType($participant, Participant::OWNER); + } + + /** + * @param Room $room + * + * @throws InvalidArgumentException + */ + protected function unsetRoomOwner(Room $room): void { + foreach ($room->getParticipants() as $participant) { + if ($participant->getParticipantType() === Participant::OWNER) { + $room->setParticipantType($participant, Participant::USER); + } + } + } + + /** + * @param Room $room + * @param string[] $groupIds + * + * @throws InvalidArgumentException + */ + protected function addRoomParticipantsByGroup(Room $room, array $groupIds): void { + if (!$groupIds) { + return; + } + + $groupManager = \OC::$server->getGroupManager(); + + $users = []; + foreach ($groupIds as $groupId) { + $group = $groupManager->get($groupId); + if ($group === null) { + throw new InvalidArgumentException(sprintf("Group '%s' not found.", $groupId)); + } + + $groupUsers = array_map(function (IUser $user) { + return $user->getUID(); + }, $group->getUsers()); + + $users = array_merge($users, array_values($groupUsers)); + } + + $this->addRoomParticipants($room, $users); + } + + /** + * @param Room $room + * @param string[] $circleIds + * + * @throws InvalidArgumentException + */ + protected function addRoomParticipantsByCircle(Room $room, array $circleIds): void { + if (!$circleIds) { + return; + } + + if (!\OC::$server->getAppManager()->isEnabledForUser('circles')) { + throw new InvalidArgumentException("App 'circles' is not enabled."); + } + + $users = []; + foreach ($circleIds as $circleId) { + try { + $circle = Circles::detailsCircle($circleId); + } catch (\Exception $e) { + throw new InvalidArgumentException(sprintf("Circle '%s' not found.", $circleId)); + } + + $circleUsers = array_filter($circle->getMembers(), function (Member $member) { + if (($member->getType() !== Member::TYPE_USER) || ($member->getUserId() === '')) { + return false; + } + + return in_array($member->getStatus(), [Member::STATUS_INVITED, Member::STATUS_MEMBER], true); + }); + + $users = array_merge($users, $circleUsers); + } + + $this->addRoomParticipants($room, $users); + } + + /** + * @param Room $room + * @param string[] $userIds + * + * @throws InvalidArgumentException + */ + protected function addRoomParticipants(Room $room, array $userIds): void { + if (!$userIds) { + return; + } + + $userManager = \OC::$server->getUserManager(); + + $participants = []; + foreach ($userIds as $userId) { + $user = $userManager->get($userId); + if ($user === null) { + throw new InvalidArgumentException(sprintf("User '%s' not found.", $userId)); + } + + if (isset($participants[$user->getUID()])) { + // nothing to do, user is going to be a participant already + continue; + } + + try { + $room->getParticipant($user->getUID()); + + // nothing to do, user is a participant already + continue; + } catch (ParticipantNotFoundException $e) { + // we expect the user not to be a participant yet + } + + $participants[$user->getUID()] = [ + 'userId' => $user->getUID(), + ]; + } + + \call_user_func_array([$room, 'addUsers'], $participants); + } + + /** + * @param Room $room + * @param string[] $userIds + * + * @throws InvalidArgumentException + */ + protected function removeRoomParticipants(Room $room, array $userIds): void { + $userManager = \OC::$server->getUserManager(); + + $users = []; + foreach ($userIds as $userId) { + try { + $room->getParticipant($userId); + } catch (ParticipantNotFoundException $e) { + throw new InvalidArgumentException(sprintf("User '%s' is no participant.", $userId)); + } + + $users[] = $userManager->get($userId); + } + + foreach ($users as $user) { + $room->removeUser($user, Room::PARTICIPANT_REMOVED); + } + } + + /** + * @param Room $room + * @param string[] $userIds + * + * @throws InvalidArgumentException + */ + protected function addRoomModerators(Room $room, array $userIds): void { + $participants = []; + foreach ($userIds as $userId) { + try { + $participant = $room->getParticipant($userId); + } catch (ParticipantNotFoundException $e) { + throw new InvalidArgumentException(sprintf("User '%s' is no participant.", $userId)); + } + + if ($participant->getParticipantType() !== Participant::OWNER) { + $participants[] = $participant; + } + } + + foreach ($participants as $participant) { + $room->setParticipantType($participant, Participant::MODERATOR); + } + } + + /** + * @param Room $room + * @param string[] $userIds + * + * @throws InvalidArgumentException + */ + protected function removeRoomModerators(Room $room, array $userIds): void { + $participants = []; + foreach ($userIds as $userId) { + try { + $participant = $room->getParticipant($userId); + } catch (ParticipantNotFoundException $e) { + throw new InvalidArgumentException(sprintf("User '%s' is no participant.", $userId)); + } + + if ($participant->getParticipantType() === Participant::MODERATOR) { + $participants[] = $participant; + } + } + + foreach ($participants as $participant) { + $room->setParticipantType($participant, Participant::USER); + } + } +} diff --git a/lib/Command/Room/Update.php b/lib/Command/Room/Update.php new file mode 100644 index 000000000..500e898a8 --- /dev/null +++ b/lib/Command/Room/Update.php @@ -0,0 +1,152 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2020 Daniel Rudolf <nextcloud.com@daniel-rudolf.de> + * + * @author Daniel Rudolf <nextcloud.com@daniel-rudolf.de> + * + * @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/>. + * + */ + +namespace OCA\Talk\Command\Room; + +use Exception; +use OC\Core\Command\Base; +use OCA\Talk\Exceptions\RoomNotFoundException; +use OCA\Talk\Manager; +use OCA\Talk\Room; +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 Update extends Base { + use TRoomCommand; + + /** @var IUserManager */ + public $userManager; + + /** @var Manager */ + public $manager; + + public function __construct(IUserManager $userManager, Manager $manager) { + parent::__construct(); + + $this->userManager = $userManager; + $this->manager = $manager; + } + + protected function configure(): void { + $this + ->setName('talk:room:update') + ->setDescription('Updates a room') + ->addArgument( + 'token', + InputArgument::REQUIRED, + 'The token of the room to update' + )->addOption( + 'name', + null, + InputOption::VALUE_REQUIRED, + 'Sets a new name for the room' + )->addOption( + 'public', + null, + InputOption::VALUE_REQUIRED, + 'Modifies the room to be a public room (value 1) or private room (value 0)' + )->addOption( + 'readonly', + null, + InputOption::VALUE_REQUIRED, + 'Modifies the room to be read-only (value 1) or read-write (value 0)' + )->addOption( + 'password', + null, + InputOption::VALUE_REQUIRED, + 'Sets a new password for the room; pass an empty value to remove password protection' + )->addOption( + 'owner', + null, + InputOption::VALUE_REQUIRED, + 'Sets the given user as owner of the room; pass an empty value to remove the owner' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output): ?int { + $token = $input->getArgument('token'); + $name = $input->getOption('name'); + $public = $input->getOption('public'); + $readOnly = $input->getOption('readonly'); + $password = $input->getOption('password'); + $owner = $input->getOption('owner'); + + if (!in_array($public, [null, '0', '1'], true)) { + $output->writeln('<error>Invalid value for option "--public" given.</error>'); + return 1; + } + + if (!in_array($readOnly, [null, '0', '1'], true)) { + $output->writeln('<error>Invalid value for option "--readonly" given.</error>'); + return 1; + } + + try { + $room = $this->manager->getRoomByToken($token); + } catch (RoomNotFoundException $e) { + $output->writeln('<error>Room not found.</error>'); + return 1; + } + + if (!in_array($room->getType(), [Room::GROUP_CALL, Room::PUBLIC_CALL], true)) { + $output->writeln('<error>Room is no group call.</error>'); + return 1; + } + + try { + if ($name !== null) { + $this->setRoomName($room, $name); + } + + if ($public !== null) { + $this->setRoomPublic($room, ($public === '1')); + } + + if ($readOnly !== null) { + $this->setRoomReadOnly($room, ($readOnly === '1')); + } + + if ($password !== null) { + $this->setRoomPassword($room, $password); + } + + if ($owner !== null) { + if ($owner !== '') { + $this->setRoomOwner($room, $owner); + } else { + $this->unsetRoomOwner($room); + } + } + } catch (Exception $e) { + $output->writeln(sprintf('<error>%s</error>', $e->getMessage())); + return 1; + } + + $output->writeln('<info>Room successfully updated.</info>'); + return 0; + } +} |