spreed/lib/Service/CommandService.php

242 строки
6.3 KiB
PHP

<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2019 Joas Schilling <coding@schilljs.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/>.
*
*/
namespace OCA\Talk\Service;
use OCA\Talk\Chat\Command\ShellExecutor;
use OCA\Talk\Model\Command;
use OCA\Talk\Model\CommandMapper;
use OCP\AppFramework\Db\DoesNotExistException;
class CommandService {
/** @var CommandMapper */
protected $mapper;
/** @var ShellExecutor */
protected $shellExecutor;
public function __construct(CommandMapper $mapper, ShellExecutor $shellExecutor) {
$this->mapper = $mapper;
$this->shellExecutor = $shellExecutor;
}
/**
* @param string $app
* @param string $cmd
* @param string $name
* @param string $script
* @param int $response
* @param int $enabled
* @return Command
* @throws \InvalidArgumentException
*/
public function create(string $app, string $cmd, string $name, string $script, int $response, int $enabled): Command {
try {
$this->mapper->find($app, $cmd);
throw new \InvalidArgumentException('command', 1);
} catch (DoesNotExistException $e) {
}
$command = new Command();
$command->setApp($app);
$command->setCommand($cmd);
$command->setName($name);
$command->setScript($script);
$command->setResponse($response);
$command->setEnabled($enabled);
$this->validateCommand($command);
return $this->mapper->insert($command);
}
/**
* @param int $id
* @param int $response
* @param int $enabled
* @return Command
* @throws \InvalidArgumentException
* @throws DoesNotExistException
*/
public function updateFromWeb(int $id, int $response, int $enabled): Command {
$command = $this->mapper->findById($id);
return $this->update($id, $command->getCommand(), $command->getName(), $command->getScript(), $response, $enabled);
}
/**
* @param int $id
* @param string $cmd
* @param string $name
* @param string $script
* @param int $response
* @param int $enabled
* @return Command
* @throws \InvalidArgumentException
* @throws DoesNotExistException
*/
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);
}
$command->setName($name);
$command->setScript($script);
$command->setResponse($response);
$command->setEnabled($enabled);
if ($cmd !== $command->getCommand()) {
try {
$this->mapper->find('', $cmd);
throw new \InvalidArgumentException('command', 1);
} catch (DoesNotExistException $e) {
$command->setCommand($cmd);
}
}
$this->validateCommand($command);
return $this->mapper->update($command);
}
/**
* @param Command $command
* @throws \InvalidArgumentException
*/
protected function validateCommand(Command $command): void {
if (preg_match('/^[a-z0-9]{1..64}$/', $command->getCommand())) {
throw new \InvalidArgumentException('command', 1);
}
if (preg_match('/^.{1..64}$/', $command->getName())) {
throw new \InvalidArgumentException('name', 2);
}
if ($command->getApp() === '') {
$script = $command->getScript();
if (strpos($script, 'alias:') === 0) {
try {
$this->resolveAlias($command);
} catch (DoesNotExistException $e) {
throw new \InvalidArgumentException('script', 3);
}
} else {
try {
$this->shellExecutor->execShell($script, '--help');
} catch (\InvalidArgumentException $e) {
throw new \InvalidArgumentException('script', 3);
}
}
}
if (!\in_array($command->getResponse(), [Command::RESPONSE_NONE, Command::RESPONSE_USER, Command::RESPONSE_ALL], true)) {
throw new \InvalidArgumentException('response', 4);
}
if (!\in_array($command->getEnabled(), [Command::ENABLED_OFF, Command::ENABLED_MODERATOR, Command::ENABLED_USERS, Command::ENABLED_ALL], true)) {
throw new \InvalidArgumentException('enabled', 5);
}
}
/**
* @param Command $command
* @return Command
* @throws DoesNotExistException
*/
public function resolveAlias(Command $command): Command {
$script = $command->getScript();
if (strpos($script, 'alias:') === 0) {
$alias = explode(':', $script, 3);
if (isset($alias[2])) {
[, $app, $cmd] = $alias;
} else {
$app = '';
$cmd = $alias[1];
}
if ($app === $command->getApp() && $cmd === $command->getCommand()) {
throw new DoesNotExistException('The command is an alias for itself');
}
try {
return $this->find($app, $cmd);
} catch (DoesNotExistException $e) {
throw new DoesNotExistException('The command for ' . $command->getCommand() . ' does not exist');
}
}
return $command;
}
/**
* @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
* @return Command
* @throws DoesNotExistException
*/
public function find(string $app, string $cmd): Command {
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
* @throws DoesNotExistException
*/
public function findById(int $id): Command {
return $this->mapper->findById($id);
}
/**
* @return Command[]
*/
public function findAll(): array {
return $this->mapper->findAll();
}
}