diff --git a/appinfo/info.xml b/appinfo/info.xml index 38951421a..c7f6db15a 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -62,6 +62,10 @@ And in the works for the [coming versions](https://github.com/nextcloud/spreed/m + OCA\Spreed\Command\Command\Add + OCA\Spreed\Command\Command\Delete + OCA\Spreed\Command\Command\ListCommand + OCA\Spreed\Command\Command\Update OCA\Spreed\Command\Stun\Add OCA\Spreed\Command\Stun\Delete OCA\Spreed\Command\Stun\ListCommand diff --git a/lib/Command/Command/Add.php b/lib/Command/Command/Add.php new file mode 100644 index 000000000..3a67d5936 --- /dev/null +++ b/lib/Command/Command/Add.php @@ -0,0 +1,104 @@ + + * + * @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 . + * + */ + +namespace OCA\Spreed\Command\Command; + +use OCA\Spreed\Service\CommandService; +use OC\Core\Command\Base; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class Add extends Base { + + use TRenderCommand; + + /** @var CommandService */ + private $service; + + public function __construct(CommandService $service) { + parent::__construct(); + $this->service = $service; + } + + protected function configure(): void { + $this + ->setName('talk:command:add') + ->setDescription('Add a new command') + ->addArgument( + 'cmd', + InputArgument::REQUIRED, + 'The command as used in the chat "/help" => "help"' + ) + ->addArgument( + 'name', + InputArgument::REQUIRED, + 'Name of the user posting the response' + ) + ->addArgument( + 'script', + InputArgument::REQUIRED, + 'Script to execute' + ) + ->addArgument( + 'response', + InputArgument::REQUIRED, + 'Who should see the response: 0 - No one, 1 - User, 2 - All' + ) + ->addArgument( + 'enabled', + InputArgument::REQUIRED, + 'Who can use this command: 0 - Disabled, 1 - Moderators, 2 - Users, 3 - Guests' + ) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $cmd = $input->getArgument('cmd'); + $name = $input->getArgument('name'); + $script = $input->getArgument('script'); + $response = (int) $input->getArgument('response'); + $enabled = (int) $input->getArgument('enabled'); + + try { + $command = $this->service->create('', $cmd, $name, $script, $response, $enabled); + } catch (\InvalidArgumentException $e) { + switch ($e->getCode()) { + case 1: + $output->writeln('The command already exists'); + break; + case 4: + $output->writeln('The response value is invalid'); + break; + case 5: + $output->writeln('The enabled value is invalid'); + break; + } + return 1; + } + + + $output->writeln('Command added'); + $output->writeln(''); + $this->renderCommands(Base::OUTPUT_FORMAT_PLAIN, $output, [$command]); + } +} diff --git a/lib/Command/Command/Delete.php b/lib/Command/Command/Delete.php new file mode 100644 index 000000000..3bcfd741e --- /dev/null +++ b/lib/Command/Command/Delete.php @@ -0,0 +1,65 @@ + + * + * @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 . + * + */ + +namespace OCA\Spreed\Command\Command; + +use OCA\Spreed\Service\CommandService; +use OC\Core\Command\Base; +use OCP\AppFramework\Db\DoesNotExistException; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class Delete extends Base { + + /** @var CommandService */ + private $service; + + public function __construct(CommandService $service) { + parent::__construct(); + $this->service = $service; + } + + protected function configure():void { + $this + ->setName('talk:command:delete') + ->setDescription('Remove an existing command') + ->addArgument( + 'command-id', + InputArgument::REQUIRED + ); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $id = (int) $input->getArgument('command-id'); + + try { + $this->service->delete($id); + } catch (DoesNotExistException $e) { + $output->writeln('The given command ID does not exist'); + return 1; + } catch (\InvalidArgumentException $e) { + $output->writeln('The help command cannot be deleted'); + return 2; + } + } +} diff --git a/lib/Command/Command/ListCommand.php b/lib/Command/Command/ListCommand.php new file mode 100644 index 000000000..785cdc575 --- /dev/null +++ b/lib/Command/Command/ListCommand.php @@ -0,0 +1,63 @@ + + * + * @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 . + * + */ + +namespace OCA\Spreed\Command\Command; + +use OCA\Spreed\Service\CommandService; +use OC\Core\Command\Base; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class ListCommand extends Base { + + use TRenderCommand; + + /** @var CommandService */ + private $service; + + public function __construct(CommandService $service) { + parent::__construct(); + $this->service = $service; + } + + protected function configure(): void { + parent::configure(); + + $this + ->setName('talk:command:list') + ->setDescription('List all available commands') + ->addArgument('app', InputArgument::OPTIONAL, 'Only list the commands of a specific app, "custom" to list all custom commands') + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $app = $input->getArgument('app'); + if ($app === null) { + $commands = $this->service->findAll(); + } else { + $commands = $this->service->findByApp($app === 'custom' ? '' : $app); + } + + $this->renderCommands($input->getOption('output'), $output, $commands, true); + } +} diff --git a/lib/Command/Command/TRenderCommand.php b/lib/Command/Command/TRenderCommand.php new file mode 100644 index 000000000..b4f37efbb --- /dev/null +++ b/lib/Command/Command/TRenderCommand.php @@ -0,0 +1,55 @@ + + * + * @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 . + * + */ + +namespace OCA\Spreed\Command\Command; + +use OCA\Spreed\Model\Command; +use OC\Core\Command\Base; +use Symfony\Component\Console\Helper\Table; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +trait TRenderCommand { + + protected function renderCommands(string $outputFormat, OutputInterface $output, array $commands, bool $showHelp = false): void { + $result = array_map(function(Command $command) { + return $command->asArray(); + }, $commands); + + if ($outputFormat === Base::OUTPUT_FORMAT_PLAIN) { + if ($showHelp) { + $output->writeln('Response values: 0 - No one, 1 - User, 2 - All'); + $output->writeln('Enabled values: 0 - Disabled, 1 - Moderators, 2 - Users, 3 - Guests'); + $output->writeln(''); + } + + $table = new Table($output); + if (isset($result[0])) { + $table->setHeaders(array_keys($result[0])); + } + $table->addRows($result); + $table->render(); + } else { + $this->writeMixedInOutputFormat($input, $output, $result); + } + } +} diff --git a/lib/Command/Command/Update.php b/lib/Command/Command/Update.php new file mode 100644 index 000000000..b96cd6ddf --- /dev/null +++ b/lib/Command/Command/Update.php @@ -0,0 +1,116 @@ + + * + * @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 . + * + */ + +namespace OCA\Spreed\Command\Command; + +use OCA\Spreed\Service\CommandService; +use OC\Core\Command\Base; +use OCP\AppFramework\Db\DoesNotExistException; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class Update extends Base { + + use TRenderCommand; + + /** @var CommandService */ + private $service; + + public function __construct(CommandService $service) { + parent::__construct(); + $this->service = $service; + } + + protected function configure(): void { + $this + ->setName('talk:command:update') + ->setDescription('Add a new command') + ->addArgument( + 'command-id', + InputArgument::REQUIRED + ) + ->addArgument( + 'cmd', + InputArgument::REQUIRED, + 'The command as used in the chat "/help" => "help"' + ) + ->addArgument( + 'name', + InputArgument::REQUIRED, + 'Name of the user posting the response' + ) + ->addArgument( + 'script', + InputArgument::REQUIRED, + 'Script to execute' + ) + ->addArgument( + 'response', + InputArgument::REQUIRED, + 'Who should see the response: 0 - No one, 1 - User, 2 - All' + ) + ->addArgument( + 'enabled', + InputArgument::REQUIRED, + 'Who can use this command: 0 - Disabled, 1 - Moderators, 2 - Users, 3 - Guests' + ) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $id = (int) $input->getArgument('command-id'); + $cmd = $input->getArgument('cmd'); + $name = $input->getArgument('name'); + $script = $input->getArgument('script'); + $response = (int) $input->getArgument('response'); + $enabled = (int) $input->getArgument('enabled'); + + try { + $command = $this->service->update($id, $cmd, $name, $script, $response, $enabled); + } catch (DoesNotExistException $e) { + $output->writeln('The given command ID does not exist'); + return 1; + } catch (\InvalidArgumentException $e) { + switch ($e->getCode()) { + case 0: + $output->writeln('The help command and predefined commands cannot be updated'); + break; + case 1: + $output->writeln('The command already exists'); + break; + case 4: + $output->writeln('The response value is invalid'); + break; + case 5: + $output->writeln('The enabled value is invalid'); + break; + } + return 2; + } + + + $output->writeln('Command updated'); + $output->writeln(''); + $this->renderCommands(Base::OUTPUT_FORMAT_PLAIN, $output, [$command]); + } +} diff --git a/lib/Controller/CommandController.php b/lib/Controller/CommandController.php index d61bd9e86..cc1e0e193 100644 --- a/lib/Controller/CommandController.php +++ b/lib/Controller/CommandController.php @@ -23,6 +23,7 @@ namespace OCA\Spreed\Controller; +use OCA\Spreed\Model\Command; use OCA\Spreed\Service\CommandService; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Http; @@ -53,18 +54,9 @@ class CommandController extends OCSController { public function index(): DataResponse { $commands = $this->commandService->findAll(); - $result = []; - foreach ($commands as $command) { - $result[] = [ - 'id' => $command->getId(), - 'app' => $command->getApp(), - 'name' => $command->getName(), - 'pattern' => $command->getCommand(), - 'script' => $command->getScript(), - 'response' => $command->getResponse(), - 'enabled' => $command->getEnabled(), - ]; - } + $result = array_map(function(Command $command) { + return $command->asArray(); + }, $commands); return new DataResponse($result); } @@ -84,15 +76,7 @@ class CommandController extends OCSController { return new DataResponse(['error' => $e->getMessage()], Http::STATUS_BAD_REQUEST); } - return new DataResponse([ - 'id' => $command->getId(), - 'app' => $command->getApp(), - 'name' => $command->getName(), - 'pattern' => $command->getCommand(), - 'script' => $command->getScript(), - 'response' => $command->getResponse(), - 'enabled' => $command->getEnabled(), - ]); + return new DataResponse($command->asArray()); } /** @@ -104,6 +88,8 @@ class CommandController extends OCSController { $this->commandService->delete($id); } catch (DoesNotExistException $e) { return new DataResponse([], Http::STATUS_NOT_FOUND); + } catch (\InvalidArgumentException $e) { + return new DataResponse(['error' => $e->getMessage()], Http::STATUS_BAD_REQUEST); } return new DataResponse(); diff --git a/lib/Model/Command.php b/lib/Model/Command.php index be8329f09..c6a949b11 100644 --- a/lib/Model/Command.php +++ b/lib/Model/Command.php @@ -75,4 +75,19 @@ class Command extends Entity { $this->addType('response', 'int'); $this->addType('enabled', 'int'); } + + /** + * @return array + */ + public function asArray(): array { + return [ + 'id' => $this->getId(), + 'app' => $this->getApp(), + 'name' => $this->getName(), + 'command' => $this->getCommand(), + 'script' => $this->getScript(), + 'response' => $this->getResponse(), + 'enabled' => $this->getEnabled(), + ]; + } } diff --git a/lib/Model/CommandMapper.php b/lib/Model/CommandMapper.php index 226e673fc..e3b842417 100644 --- a/lib/Model/CommandMapper.php +++ b/lib/Model/CommandMapper.php @@ -38,12 +38,12 @@ class CommandMapper extends QBMapper { * @return Command[] */ public function findAll(): array { - $qb = $this->db->getQueryBuilder(); - $qb->select('*') + $query = $this->db->getQueryBuilder(); + $query->select('*') ->from($this->getTableName()) ->orderBy('id', 'ASC'); - return $this->findEntities($qb); + return $this->findEntities($query); } /** @@ -60,6 +60,20 @@ class CommandMapper extends QBMapper { return $this->findEntity($query); } + /** + * @param string $app + * @return Command[] + */ + public function findByApp(string $app): array { + $query = $this->db->getQueryBuilder(); + $query->select('*') + ->from($this->getTableName()) + ->where($query->expr()->eq('app', $query->createNamedParameter($app))) + ->orderBy('id', 'ASC'); + + return $this->findEntities($query); + } + /** * @param string $app * @param string $cmd diff --git a/lib/Service/CommandService.php b/lib/Service/CommandService.php index 593223a0f..abe3869bd 100644 --- a/lib/Service/CommandService.php +++ b/lib/Service/CommandService.php @@ -100,6 +100,10 @@ class CommandService { */ public function update(int $id, string $cmd, string $name, string $script, int $response, int $enabled): Command { $command = $this->mapper->findById($id); + if ($command->getApp() !== '' || $command->getCommand() === 'help') { + throw new \InvalidArgumentException('app', 0); + } + if (!\in_array($response, [Command::RESPONSE_NONE, Command::RESPONSE_USER, Command::RESPONSE_ALL], true)) { throw new \InvalidArgumentException('response', 4); } @@ -108,10 +112,6 @@ class CommandService { throw new \InvalidArgumentException('enabled', 5); } - if ($command->getApp() !== '' || $command->getCommand() === 'help') { - throw new \InvalidArgumentException('app', 0); - } - if ($cmd !== $command->getCommand()) { try { $this->mapper->find('', $cmd); @@ -136,11 +136,18 @@ class CommandService { * @param int $id * @return Command * @throws DoesNotExistException + * @throws \InvalidArgumentException */ public function delete(int $id): Command { $command = $this->mapper->findById($id); + + if ($command->getApp() !== '' || $command->getCommand() === 'help') { + throw new \InvalidArgumentException('app', 0); + } + return $this->mapper->delete($command); } + /** * @param string $app * @param string $cmd @@ -151,6 +158,14 @@ class CommandService { return $this->mapper->find($app, $cmd); } + /** + * @param string $app + * @return Command[] + */ + public function findByApp(string $app): array { + return $this->mapper->findByApp($app); + } + /** * @param int $id * @return Command