config: removed support for --config option. deprecated the use backend_name as argument.
This commit is contained in:
@@ -33,8 +33,8 @@ final class AddCommand extends Command
|
||||
{
|
||||
$this->setName(self::ROUTE)
|
||||
->setDescription('Add new backend.')
|
||||
->addOption('config', 'c', InputOption::VALUE_REQUIRED, 'Use Alternative config file.')
|
||||
->addArgument('backend', InputArgument::OPTIONAL, 'Backend name', null)
|
||||
->addOption('select-backend', 's', InputOption::VALUE_REQUIRED, 'Select backend.')
|
||||
->setHelp(
|
||||
r(
|
||||
<<<HELP
|
||||
@@ -44,7 +44,7 @@ final class AddCommand extends Command
|
||||
|
||||
This command is shortcut for running the following command:
|
||||
|
||||
{cmd} <cmd>{manage_route}</cmd> --add -- <value>backend_name</value>
|
||||
{cmd} <cmd>{manage_route}</cmd> <flag>--add -s</flag> <value>backend_name</value>
|
||||
|
||||
HELP,
|
||||
[
|
||||
@@ -103,10 +103,19 @@ final class AddCommand extends Command
|
||||
$opts['--' . $option] = $val;
|
||||
}
|
||||
|
||||
$backend = $input->getArgument('backend');
|
||||
if (null !== ($name = $input->getOption('select-backend'))) {
|
||||
$name = explode(',', $name, 2)[0];
|
||||
}
|
||||
|
||||
if (null !== $backend) {
|
||||
$opts['backend'] = strtolower($backend);
|
||||
if (empty($name) && null !== ($name = $input->getArgument('backend'))) {
|
||||
$name = $input->getArgument('backend');
|
||||
$output->writeln(
|
||||
'<notice>WARNING: The use of backend name as argument is deprecated and will be removed from future versions. Please use [-s, --select-backend] option instead.</notice>'
|
||||
);
|
||||
}
|
||||
|
||||
if (null !== $name) {
|
||||
$opts['backend'] = strtolower($name);
|
||||
} else {
|
||||
// -- $backend.token
|
||||
$opts['backend'] = (function () use (&$opts, $input, $output) {
|
||||
@@ -144,7 +153,7 @@ final class AddCommand extends Command
|
||||
return (new QuestionHelper())->ask($input, $output, $question);
|
||||
})();
|
||||
$output->writeln('');
|
||||
$opts['backend'] = strtolower($opts['backend']);
|
||||
$opts['--select-backend'] = strtolower($opts['backend']);
|
||||
}
|
||||
|
||||
return $this->getApplication()?->find(ManageCommand::ROUTE)->run(new ArrayInput($opts), $output) ?? 1;
|
||||
|
||||
@@ -7,15 +7,15 @@ namespace App\Commands\Config;
|
||||
use App\Command;
|
||||
use App\Libs\Attributes\Route\Cli;
|
||||
use App\Libs\Config;
|
||||
use App\Libs\ConfigFile;
|
||||
use App\Libs\Database\DatabaseInterface as iDB;
|
||||
use App\Libs\Stream;
|
||||
use PDO;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
/**
|
||||
* Class DeleteCommand
|
||||
@@ -30,16 +30,9 @@ final class DeleteCommand extends Command
|
||||
public const ROUTE = 'config:delete';
|
||||
private PDO $pdo;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param iDB $db The iDB instance used for database interaction.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(private iDB $db)
|
||||
public function __construct(private LoggerInterface $logger, iDB $db)
|
||||
{
|
||||
$this->pdo = $this->db->getPDO();
|
||||
$this->pdo = $db->getPDO();
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
@@ -51,8 +44,8 @@ final class DeleteCommand extends Command
|
||||
{
|
||||
$this->setName(self::ROUTE)
|
||||
->setDescription('Delete Local backend data.')
|
||||
->addOption('config', 'c', InputOption::VALUE_REQUIRED, 'Use Alternative config file.')
|
||||
->addArgument('backend', InputArgument::REQUIRED, 'Backend name.')
|
||||
->addOption('select-backend', 's', InputOption::VALUE_REQUIRED, 'Select backend.')
|
||||
->addArgument('backend', InputArgument::OPTIONAL, 'Backend name.')
|
||||
->setHelp(
|
||||
r(
|
||||
<<<HELP
|
||||
@@ -117,26 +110,21 @@ final class DeleteCommand extends Command
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$custom = false;
|
||||
|
||||
// -- Use Custom servers.yaml file.
|
||||
if (($config = $input->getOption('config'))) {
|
||||
try {
|
||||
$custom = true;
|
||||
$backends = (array)Yaml::parseFile($this->checkCustomBackendsFile($config));
|
||||
} catch (\App\Libs\Exceptions\RuntimeException $e) {
|
||||
$output->writeln(r('<error>ERROR:</error> {error}', ['error' => $e->getMessage()]));
|
||||
return self::FAILURE;
|
||||
}
|
||||
} else {
|
||||
$config = Config::get('path') . '/config/servers.yaml';
|
||||
if (!file_exists($config)) {
|
||||
touch($config);
|
||||
}
|
||||
$backends = (array)Config::get('servers', []);
|
||||
if (null !== ($name = $input->getOption('select-backend'))) {
|
||||
$name = explode(',', $name, 2)[0];
|
||||
}
|
||||
|
||||
$name = $input->getArgument('backend');
|
||||
if (empty($name) && null !== ($name = $input->getArgument('backend'))) {
|
||||
$name = $input->getArgument('backend');
|
||||
$output->writeln(
|
||||
'<notice>WARNING: The use of backend name as argument is deprecated and will be removed from future versions. Please use [-s, --select-backend] option instead.</notice>'
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($name)) {
|
||||
$output->writeln(r('<error>ERROR: Backend not specified. Please use [-s, --select-backend].</error>'));
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
if (!isValidName($name) || strtolower($name) !== $name) {
|
||||
$output->writeln(
|
||||
@@ -150,7 +138,10 @@ final class DeleteCommand extends Command
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
if (null === ag($backends, "{$name}.type", null)) {
|
||||
$configFile = ConfigFile::open(Config::get('backends_file'), 'yaml');
|
||||
$configFile->setLogger($this->logger);
|
||||
|
||||
if (null === $configFile->get("{$name}.type", null)) {
|
||||
$output->writeln(
|
||||
r('<error>ERROR:</error> No backend named [<value>{backend}</value>] was found.', [
|
||||
'backend' => $name,
|
||||
@@ -164,7 +155,7 @@ final class DeleteCommand extends Command
|
||||
$question = new ConfirmationQuestion(
|
||||
r(
|
||||
<<<HELP
|
||||
<question>Are you sure you want to remove [<value>{name}</value>] data?</question>? {default}
|
||||
<question>Are you sure you want to remove [<value>{name}</value>] data?</question> {default}
|
||||
------------------
|
||||
<notice>WARNING:</notice> This command will remove entries from database related to the backend.
|
||||
Database records will be removed if [<value>{name}</value>] was the only backend referencing them.
|
||||
@@ -240,15 +231,7 @@ final class DeleteCommand extends Command
|
||||
);
|
||||
}
|
||||
|
||||
if (false === $custom) {
|
||||
copy($config, $config . '.bak');
|
||||
}
|
||||
|
||||
$backends = ag_delete($backends, $name);
|
||||
|
||||
$stream = new Stream($config, 'w');
|
||||
$stream->write(Yaml::dump($backends, 8, 2));
|
||||
$stream->close();
|
||||
$configFile->delete($name)->persist();
|
||||
|
||||
$output->writeln('<info>Config updated.</info>');
|
||||
|
||||
|
||||
@@ -7,14 +7,14 @@ namespace App\Commands\Config;
|
||||
use App\Command;
|
||||
use App\Libs\Attributes\Route\Cli;
|
||||
use App\Libs\Config;
|
||||
use App\Libs\Stream;
|
||||
use App\Libs\ConfigFile;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
@@ -27,6 +27,11 @@ final class EditCommand extends Command
|
||||
{
|
||||
public const ROUTE = 'config:edit';
|
||||
|
||||
public function __construct(private LoggerInterface $logger)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the command.
|
||||
*/
|
||||
@@ -36,10 +41,11 @@ final class EditCommand extends Command
|
||||
->setDescription('Edit backend settings inline.')
|
||||
->addOption('config', 'c', InputOption::VALUE_REQUIRED, 'Use Alternative config file.')
|
||||
->addOption('key', 'k', InputOption::VALUE_REQUIRED, 'Key to update.')
|
||||
->addOption('set', 's', InputOption::VALUE_REQUIRED, 'Value to set.')
|
||||
->addOption('set', 'e', InputOption::VALUE_REQUIRED, 'Value to set.')
|
||||
->addOption('delete', 'd', InputOption::VALUE_NONE, 'Delete value.')
|
||||
->addOption('regenerate-webhook-token', 'g', InputOption::VALUE_NONE, 'Re-generate backend webhook token.')
|
||||
->addArgument('backend', InputArgument::REQUIRED, 'Backend name')
|
||||
->addOption('select-backend', 's', InputOption::VALUE_REQUIRED, 'Select backend.')
|
||||
->addArgument('backend', InputArgument::OPTIONAL, 'Backend name')
|
||||
->setHelp(
|
||||
r(
|
||||
<<<HELP
|
||||
@@ -56,11 +62,11 @@ final class EditCommand extends Command
|
||||
|
||||
<question># How to edit config setting?</question>
|
||||
|
||||
{cmd} <cmd>{route}</cmd> <flag>--key</flag> <value>key</value> <flag>--set</flag> <value>value</value> -- <value>backend_name</value>
|
||||
{cmd} <cmd>{route}</cmd> <flag>--key</flag> <value>key</value> <flag>--set</flag> <value>value</value> <flag>-s</flag> <value>backend_name</value>
|
||||
|
||||
<question># How to change the webhook token?</question>
|
||||
<question># How to change the re-generate webhook token?</question>
|
||||
|
||||
{cmd} <cmd>{route}</cmd> <flag>--regenerate-webhook-token</flag> -- <value>backend_name</value>
|
||||
{cmd} <cmd>{route}</cmd> <flag>-g -s</flag> <value>backend_name</value>
|
||||
|
||||
HELP,
|
||||
[
|
||||
@@ -96,25 +102,21 @@ final class EditCommand extends Command
|
||||
*/
|
||||
protected function runCommand(InputInterface $input, OutputInterface $output, null|array $rerun = null): int
|
||||
{
|
||||
// -- Use Custom servers.yaml file.
|
||||
if (($config = $input->getOption('config'))) {
|
||||
try {
|
||||
$custom = true;
|
||||
$backends = Yaml::parseFile($this->checkCustomBackendsFile($config));
|
||||
} catch (\App\Libs\Exceptions\RuntimeException $e) {
|
||||
$output->writeln(r('<error>{error}</error>', ['error' => $e->getMessage()]));
|
||||
return self::FAILURE;
|
||||
}
|
||||
} else {
|
||||
$custom = false;
|
||||
$config = Config::get('path') . '/config/servers.yaml';
|
||||
if (!file_exists($config)) {
|
||||
touch($config);
|
||||
}
|
||||
$backends = (array)Config::get('servers', []);
|
||||
if (null !== ($name = $input->getOption('select-backend'))) {
|
||||
$name = explode(',', $name, 2)[0];
|
||||
}
|
||||
|
||||
$name = $input->getArgument('backend');
|
||||
if (empty($name) && null !== ($name = $input->getArgument('backend'))) {
|
||||
$name = $input->getArgument('backend');
|
||||
$output->writeln(
|
||||
'<notice>WARNING: The use of backend name as argument is deprecated and will be removed from future versions. Please use [-s, --select-backend] option instead.</notice>'
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($name)) {
|
||||
$output->writeln(r('<error>ERROR: Backend not specified. Please use [-s, --select-backend].</error>'));
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
if (!isValidName($name) || strtolower($name) !== $name) {
|
||||
$output->writeln(
|
||||
@@ -128,7 +130,10 @@ final class EditCommand extends Command
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
if (null === ($backend = ag($backends, $name, null))) {
|
||||
$configFile = ConfigFile::open(Config::get('backends_file'), 'yaml');
|
||||
$configFile->setLogger($this->logger);
|
||||
|
||||
if (null === $configFile->get("{$name}.type", null)) {
|
||||
$output->writeln(r('<error>ERROR: Backend \'{name}\' not found.</error>', ['name' => $name]));
|
||||
return self::FAILURE;
|
||||
}
|
||||
@@ -137,14 +142,12 @@ final class EditCommand extends Command
|
||||
try {
|
||||
$webhookToken = bin2hex(random_bytes(Config::get('webhook.tokenLength')));
|
||||
|
||||
$output->writeln(
|
||||
r('<info>The webhook token for \'{name}\' is: \'{token}\'.</info>', [
|
||||
'name' => $name,
|
||||
'token' => $webhookToken
|
||||
])
|
||||
);
|
||||
$output->writeln(r('<info>The webhook token for \'{name}\' is: \'{token}\'.</info>', [
|
||||
'name' => $name,
|
||||
'token' => $webhookToken
|
||||
]));
|
||||
|
||||
$backend = ag_set($backend, 'webhook.token', $webhookToken);
|
||||
$configFile->set("{$name}.webhook.token", $webhookToken);
|
||||
} catch (Throwable $e) {
|
||||
$output->writeln(r('<error>ERROR: {error}</error>', ['error' => $e->getMessage()]));
|
||||
return self::FAILURE;
|
||||
@@ -166,7 +169,12 @@ final class EditCommand extends Command
|
||||
}
|
||||
|
||||
if (null === $value && !$input->getOption('delete')) {
|
||||
$val = ag($backend, $key, '[No value]');
|
||||
if ($configFile->has("{$name}.{$key}")) {
|
||||
$val = $configFile->get("{$name}.{$key}", '[No value]');
|
||||
} else {
|
||||
$val = '[Not set]';
|
||||
}
|
||||
|
||||
$output->writeln(is_scalar($val) ? (string)$val : r('Type({type})', ['type' => get_debug_type($val)]));
|
||||
return self::SUCCESS;
|
||||
}
|
||||
@@ -182,50 +190,38 @@ final class EditCommand extends Command
|
||||
$value = (string)$value;
|
||||
}
|
||||
|
||||
if ($value === ag($backend, $key, null)) {
|
||||
if ($value === $configFile->get("{$name}.{$key}", null)) {
|
||||
$output->writeln('<comment>Not updating. Value already matches.</comment>');
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
$backend = ag_set($backend, $key, $value);
|
||||
$configFile->set("{$name}.{$key}", $value);
|
||||
|
||||
$output->writeln(
|
||||
r("<info>{name}: Updated '{key}' key value to '{value}'.</info>", [
|
||||
'name' => $name,
|
||||
'key' => $key,
|
||||
'value' => is_bool($value) ? (true === $value ? 'true' : 'false') : $value,
|
||||
])
|
||||
);
|
||||
$output->writeln(r("<info>{name}: Updated '{key}' key value to '{value}'.</info>", [
|
||||
'name' => $name,
|
||||
'key' => $key,
|
||||
'value' => is_bool($value) ? (true === $value ? 'true' : 'false') : $value,
|
||||
]));
|
||||
}
|
||||
|
||||
if ($input->getOption('delete')) {
|
||||
if (false === ag_exists($backend, $key)) {
|
||||
$output->writeln(
|
||||
r("<error>{name}: '{key}' key does not exist.</error>", [
|
||||
'name' => $name,
|
||||
'key' => $key
|
||||
])
|
||||
);
|
||||
if (false === $configFile->has("{$name}.{$key}")) {
|
||||
$output->writeln(r("<error>{name}: '{key}' key does not exist.</error>", [
|
||||
'name' => $name,
|
||||
'key' => $key
|
||||
]));
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$backend = ag_delete($backend, $key);
|
||||
$output->writeln(
|
||||
r("<info>{name}: Removed '{key}' key.</info>", [
|
||||
'name' => $name,
|
||||
'key' => $key
|
||||
])
|
||||
);
|
||||
$configFile->delete("{$name}.{$key}");
|
||||
$output->writeln(r("<info>{name}: Removed '{key}' key.</info>", [
|
||||
'name' => $name,
|
||||
'key' => $key
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
if (false === $custom) {
|
||||
copy($config, $config . '.bak');
|
||||
}
|
||||
|
||||
$stream = Stream::make($config, 'w');
|
||||
$stream->write(Yaml::dump(ag_set($backends, $name, $backend), 8, 2));
|
||||
$stream->close();
|
||||
$configFile->persist();
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
@@ -10,9 +10,7 @@ use App\Libs\Config;
|
||||
use App\Libs\Options;
|
||||
use DateTimeInterface;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
#[Cli(command: self::ROUTE)]
|
||||
final class ListCommand extends Command
|
||||
@@ -25,15 +23,8 @@ final class ListCommand extends Command
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setName(self::ROUTE)
|
||||
->addOption('config', 'c', InputOption::VALUE_REQUIRED, 'Use Alternative config file.')
|
||||
->setDescription('List Added backends.')
|
||||
->setHelp(
|
||||
<<<HELP
|
||||
|
||||
This command list your configured backends.
|
||||
|
||||
HELP
|
||||
);
|
||||
->setHelp('This command list your configured backends.');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -46,16 +37,6 @@ final class ListCommand extends Command
|
||||
*/
|
||||
protected function runCommand(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
// -- Use Custom servers.yaml file.
|
||||
if (($config = $input->getOption('config'))) {
|
||||
try {
|
||||
Config::save('servers', Yaml::parseFile($this->checkCustomBackendsFile($config)));
|
||||
} catch (\App\Libs\Exceptions\RuntimeException $e) {
|
||||
$output->writeln(sprintf('<error>%s</error>', $e->getMessage()));
|
||||
return self::FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
$list = [];
|
||||
|
||||
foreach (Config::get('servers', []) as $name => $backend) {
|
||||
|
||||
@@ -9,8 +9,9 @@ use App\Commands\State\ImportCommand;
|
||||
use App\Commands\System\IndexCommand;
|
||||
use App\Libs\Attributes\Route\Cli;
|
||||
use App\Libs\Config;
|
||||
use App\Libs\ConfigFile;
|
||||
use App\Libs\Options;
|
||||
use App\Libs\Stream;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Console\Exception\ExceptionInterface;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
@@ -32,13 +33,18 @@ final class ManageCommand extends Command
|
||||
{
|
||||
public const ROUTE = 'config:manage';
|
||||
|
||||
public function __construct(private LoggerInterface $logger)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setName(self::ROUTE)
|
||||
->setDescription('Manage backend settings.')
|
||||
->addOption('add', 'a', InputOption::VALUE_NONE, 'Add Backend.')
|
||||
->addOption('config', 'c', InputOption::VALUE_REQUIRED, 'Use Alternative config file.')
|
||||
->addArgument('backend', InputArgument::REQUIRED, 'Backend name.')
|
||||
->addOption('select-backend', 's', InputOption::VALUE_REQUIRED, 'Select backend.')
|
||||
->addArgument('backend', InputArgument::OPTIONAL, 'Backend name.')
|
||||
->setHelp(
|
||||
r(
|
||||
<<<HELP
|
||||
@@ -89,27 +95,26 @@ final class ManageCommand extends Command
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$custom = false;
|
||||
|
||||
// -- Use Custom servers.yaml file.
|
||||
if (($config = $input->getOption('config'))) {
|
||||
try {
|
||||
$custom = true;
|
||||
$backends = (array)Yaml::parseFile($this->checkCustomBackendsFile($config));
|
||||
} catch (\App\Libs\Exceptions\RuntimeException $e) {
|
||||
$output->writeln(r('<error>ERROR:</error> {error}', ['error' => $e->getMessage()]));
|
||||
return self::FAILURE;
|
||||
}
|
||||
} else {
|
||||
$config = Config::get('path') . '/config/servers.yaml';
|
||||
if (!file_exists($config)) {
|
||||
touch($config);
|
||||
}
|
||||
$backends = (array)Config::get('servers', []);
|
||||
if (null !== ($name = $input->getOption('select-backend'))) {
|
||||
$name = explode(',', $name, 2)[0];
|
||||
}
|
||||
|
||||
if (empty($name) && null !== ($name = $input->getArgument('backend'))) {
|
||||
$name = $input->getArgument('backend');
|
||||
$output->writeln(
|
||||
'<notice>WARNING: The use of backend name as argument is deprecated and will be removed from future versions. Please use [-s, --select-backend] option instead.</notice>'
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($name)) {
|
||||
$output->writeln(r('<error>ERROR: Backend not specified. Please use [-s, --select-backend].</error>'));
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$configFile = ConfigFile::open(Config::get('backends_file'), 'yaml', autoCreate: true);
|
||||
$configFile->setLogger($this->logger);
|
||||
|
||||
$add = $input->getOption('add');
|
||||
$name = $input->getArgument('backend');
|
||||
|
||||
if (!isValidName($name) || strtolower($name) !== $name) {
|
||||
$output->writeln(
|
||||
@@ -124,7 +129,7 @@ final class ManageCommand extends Command
|
||||
}
|
||||
|
||||
if (true === $add) {
|
||||
if (null !== ag($backends, "{$name}.type", null)) {
|
||||
if (null !== $configFile->get("{$name}.type", null)) {
|
||||
$output->writeln(
|
||||
r(
|
||||
'<error>ERROR:</error> Backend with [<value>{backend}</value>] name already exists. Omit the [<flag>--add</flag>] flag if you want to edit the backend settings.',
|
||||
@@ -135,7 +140,7 @@ final class ManageCommand extends Command
|
||||
);
|
||||
return self::FAILURE;
|
||||
}
|
||||
} elseif (null === ag($backends, "{$name}.type", null)) {
|
||||
} elseif (null === $configFile->get("{$name}.type", null)) {
|
||||
$output->writeln(
|
||||
r(
|
||||
'<error>ERROR:</error> No backend named [<value>{backend}</value>] was found. Append [<flag>--add</flag>] to add as new backend.',
|
||||
@@ -147,7 +152,7 @@ final class ManageCommand extends Command
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$u = $rerun ?? ag($backends, $name, []);
|
||||
$u = $rerun ?? $configFile->get($name, []);
|
||||
$u['name'] = $name;
|
||||
|
||||
$output->writeln('');
|
||||
@@ -392,19 +397,11 @@ final class ManageCommand extends Command
|
||||
return $this->runCommand($input, $output, $u);
|
||||
}
|
||||
|
||||
if (false === $custom) {
|
||||
copy($config, $config . '.bak');
|
||||
}
|
||||
|
||||
$backends = ag_set($backends, $name, $u);
|
||||
|
||||
$stream = new Stream($config, 'w');
|
||||
$stream->write(Yaml::dump($backends, 8, 2));
|
||||
$stream->close();
|
||||
$configFile->set($name, $u)->persist();
|
||||
|
||||
$output->writeln('<info>Config updated.</info>');
|
||||
|
||||
if (false === $custom && $input->getOption('add')) {
|
||||
if ($input->getOption('add')) {
|
||||
$helper = $this->getHelper('question');
|
||||
$text =
|
||||
<<<TEXT
|
||||
@@ -452,15 +449,9 @@ final class ManageCommand extends Command
|
||||
'type' => $importType
|
||||
])
|
||||
);
|
||||
|
||||
$cmd = $this->getApplication()?->find(ImportCommand::ROUTE);
|
||||
$cmd->run(
|
||||
new ArrayInput([
|
||||
'--quiet',
|
||||
'--config' => $config,
|
||||
'--select-backends' => $name
|
||||
]),
|
||||
$output
|
||||
);
|
||||
$cmd->run(new ArrayInput(['--quiet', '--select-backends' => $name]), $output);
|
||||
}
|
||||
|
||||
$output->writeln('<info>Import complete</info>');
|
||||
|
||||
@@ -1,264 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Commands\Config;
|
||||
|
||||
use App\Command;
|
||||
use App\Libs\Attributes\Route\Cli;
|
||||
use App\Libs\Config;
|
||||
use App\Libs\Stream;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Class UnifyCommand
|
||||
*
|
||||
* UnifyCommand is a command that unifies the webhook tokens of backend types.
|
||||
*
|
||||
* @package Your\Namespace
|
||||
*/
|
||||
#[Cli(command: self::ROUTE)]
|
||||
final class UnifyCommand extends Command
|
||||
{
|
||||
public const ROUTE = 'config:unify';
|
||||
|
||||
/**
|
||||
* Configure the command.
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setName(self::ROUTE)
|
||||
->setDescription('Unify backend type webhook tokens.')
|
||||
->addOption('select-backends', 's', InputOption::VALUE_OPTIONAL, 'Select backends. comma , seperated.', '')
|
||||
->addOption('config', 'c', InputOption::VALUE_REQUIRED, 'Use Alternative config file.')
|
||||
->addArgument(
|
||||
'type',
|
||||
InputArgument::REQUIRED,
|
||||
sprintf(
|
||||
'Backend type to unify. Expecting one of [%s]',
|
||||
implode('|', array_keys(Config::get('supported', [])))
|
||||
),
|
||||
)
|
||||
->setHelp(
|
||||
r(
|
||||
<<<HELP
|
||||
|
||||
This command is mainly intended for <notice>Plex</notice> multi server users.
|
||||
You shouldn't use this command unless told by the team.
|
||||
|
||||
Due to <notice>Plex</notice> webhook limitation you cannot use multiple webhook tokens for one PlexPass account.
|
||||
And as workaround we have to use one webhook token for all of your <notice>Plex</notice> backends.
|
||||
|
||||
This command will do the following.
|
||||
|
||||
3. Update backends unique identifier (uuid).
|
||||
1. Change the selected backend's webhook tokens to be replica of each other.
|
||||
2. Enable limit backend webhook requests to matching unique identifier.
|
||||
|
||||
To execute the command, you can do the following
|
||||
|
||||
{cmd} <cmd>{route}</cmd> -- <value>plex</value>
|
||||
|
||||
HELP,
|
||||
[
|
||||
'cmd' => trim(commandContext()),
|
||||
'route' => self::ROUTE,
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the command.
|
||||
*
|
||||
* @param InputInterface $input The input interface.
|
||||
* @param OutputInterface $output The output interface.
|
||||
*
|
||||
* @return int Returns the exit code.
|
||||
*/
|
||||
protected function runCommand(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
// -- Use Custom servers.yaml file.
|
||||
if (($config = $input->getOption('config'))) {
|
||||
try {
|
||||
$custom = true;
|
||||
Config::save('servers', Yaml::parseFile($this->checkCustomBackendsFile($config)));
|
||||
} catch (\App\Libs\Exceptions\RuntimeException $e) {
|
||||
$output->writeln(sprintf('<error>%s</error>', $e->getMessage()));
|
||||
return self::FAILURE;
|
||||
}
|
||||
} else {
|
||||
$custom = false;
|
||||
$config = Config::get('path') . '/config/servers.yaml';
|
||||
if (!file_exists($config)) {
|
||||
touch($config);
|
||||
}
|
||||
}
|
||||
|
||||
$type = strtolower((string)$input->getArgument('type'));
|
||||
|
||||
if (!array_key_exists($type, Config::get('supported', []))) {
|
||||
$message = r("<error>Invalid type was given. Expecting one of [{backends}] but got '{backend}' instead.", [
|
||||
'backends' => implode('|', array_keys(Config::get('supported', []))),
|
||||
'backend' => $type,
|
||||
]);
|
||||
|
||||
$output->writeln($message);
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$selectBackends = (string)$input->getOption('select-backends');
|
||||
|
||||
$selected = explode(',', $selectBackends);
|
||||
$selected = array_map('trim', $selected);
|
||||
$isCustom = !empty($selectBackends) && count($selected) >= 1;
|
||||
|
||||
$list = $keys = [];
|
||||
|
||||
foreach (Config::get('servers', []) as $backendName => $backend) {
|
||||
if (ag($backend, 'type') !== $type) {
|
||||
$output->writeln(
|
||||
sprintf(
|
||||
'<comment>Ignoring \'%s\' backend, not of %s type. (type: %s).</comment>',
|
||||
$backendName,
|
||||
$type,
|
||||
ag($backend, 'type')
|
||||
),
|
||||
OutputInterface::VERBOSITY_DEBUG
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($isCustom && !in_array($backendName, $selected, true)) {
|
||||
$output->writeln(
|
||||
sprintf(
|
||||
'<comment>Ignoring \'%s\' as requested by [-s, --select-backends] filter.</comment>',
|
||||
$backendName
|
||||
),
|
||||
OutputInterface::VERBOSITY_DEBUG
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
$backend['name'] = $backendName;
|
||||
$backend['ref'] = "servers.{$backendName}";
|
||||
|
||||
$list[$backendName] = $backend;
|
||||
|
||||
if (null === ($apiToken = ag($backend, 'webhook.token', null))) {
|
||||
try {
|
||||
$apiToken = bin2hex(random_bytes(Config::get('webhook.tokenLength')));
|
||||
} catch (Throwable $e) {
|
||||
$output->writeln(sprintf('<error>%s</error>', $e->getMessage()));
|
||||
return self::FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
$keys[$apiToken] = 1;
|
||||
}
|
||||
|
||||
$count = count($list);
|
||||
|
||||
if (0 === $count) {
|
||||
$message = sprintf(
|
||||
$isCustom ? '[-s, --select-backends] did not return any %s backends.' : 'No %s backends were found.',
|
||||
$type
|
||||
);
|
||||
$output->writeln(sprintf('<error>%s</error>', $message));
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
if (1 === $count) {
|
||||
$output->writeln(sprintf('<info>We found only one %s backend, therefore, no need to unify.</info>', $type));
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
if (count($keys) <= 1) {
|
||||
$output->writeln(sprintf('<info>[%s] Webhook tokens are already unified.</info>', ucfirst($type)));
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
// -- check for server unique identifier before unifying.
|
||||
foreach ($list as $backendName => $backend) {
|
||||
$ref = ag($backend, 'ref');
|
||||
|
||||
if (null !== Config::get("{$ref}.uuid", null)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$client = makeBackend(Config::get($ref), $backendName);
|
||||
|
||||
$uuid = $client->getContext()->backendId ?? $client->getIdentifier(true);
|
||||
|
||||
if (empty($uuid)) {
|
||||
$output->writeln(
|
||||
sprintf('<error>ERROR %s: does not have backend unique id set.</error>', $backendName)
|
||||
);
|
||||
$output->writeln('<comment>Please run this command to update backend info.</comment>');
|
||||
$output->writeln(sprintf(commandContext() . 'config:manage \'%s\' ', $backendName));
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
Config::save("{$ref}.uuid", $uuid);
|
||||
}
|
||||
|
||||
try {
|
||||
$apiToken = array_keys($keys ?? [])[0] ?? bin2hex(random_bytes(Config::get('webhook.tokenLength')));
|
||||
} catch (Throwable $e) {
|
||||
$output->writeln(sprintf('<error>%s</error>', $e->getMessage()));
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
foreach ($list as $backend) {
|
||||
$ref = ag($backend, 'ref');
|
||||
Config::save("{$ref}.webhook.token", $apiToken);
|
||||
Config::save("{$ref}.webhook.match.uuid", true);
|
||||
}
|
||||
|
||||
if (false === $custom) {
|
||||
copy($config, $config . '.bak');
|
||||
}
|
||||
|
||||
$stream = new Stream($config, 'w');
|
||||
$stream->write(Yaml::dump(Config::get('servers', []), 8, 2));
|
||||
$stream->close();
|
||||
|
||||
$output->writeln(
|
||||
sprintf('<comment>Unified the webhook token of %d %s backends.</comment>', count($list), $type)
|
||||
);
|
||||
$output->writeln(sprintf('<info>%s global webhook API key is: %s</info>', ucfirst($type), $apiToken));
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Completes the input with suggestions based on the "type" argument.
|
||||
*
|
||||
* @param CompletionInput $input The completion input object.
|
||||
* @param CompletionSuggestions $suggestions The completion suggestions object.
|
||||
*/
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
parent::complete($input, $suggestions);
|
||||
|
||||
if ($input->mustSuggestArgumentValuesFor('type')) {
|
||||
$currentValue = $input->getCompletionValue();
|
||||
|
||||
$suggest = [];
|
||||
|
||||
foreach (array_keys(Config::get('supported', [])) as $name) {
|
||||
if (empty($currentValue) || str_starts_with($name, $currentValue)) {
|
||||
$suggest[] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
$suggestions->suggestValues($suggest);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,9 +45,8 @@ final class ViewCommand extends Command
|
||||
{
|
||||
$this->setName(self::ROUTE)
|
||||
->setDescription('View Backends settings.')
|
||||
->addOption('select-backends', 's', InputOption::VALUE_OPTIONAL, 'Select backends. comma , seperated.', '')
|
||||
->addOption('select-backends', 's', InputOption::VALUE_REQUIRED, 'Select backends. comma , seperated.')
|
||||
->addOption('exclude', null, InputOption::VALUE_NONE, 'Inverse --select-backends logic.')
|
||||
->addOption('config', 'c', InputOption::VALUE_REQUIRED, 'Use Alternative config file.')
|
||||
->addOption('expose', 'x', InputOption::VALUE_NONE, 'Expose the secret tokens in the view.')
|
||||
->addArgument(
|
||||
'filter',
|
||||
@@ -99,16 +98,6 @@ final class ViewCommand extends Command
|
||||
*/
|
||||
protected function runCommand(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
// -- Use Custom servers.yaml file.
|
||||
if (($config = $input->getOption('config'))) {
|
||||
try {
|
||||
Config::save('servers', Yaml::parseFile($this->checkCustomBackendsFile($config)));
|
||||
} catch (RuntimeException $e) {
|
||||
$output->writeln(sprintf('<error>%s</error>', $e->getMessage()));
|
||||
return self::FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
$selectBackends = (string)$input->getOption('select-backends');
|
||||
|
||||
$list = [];
|
||||
@@ -118,10 +107,9 @@ final class ViewCommand extends Command
|
||||
|
||||
foreach (Config::get('servers', []) as $backendName => $backend) {
|
||||
if ($isCustom && $input->getOption('exclude') === in_array($backendName, $selected)) {
|
||||
$output->writeln(
|
||||
sprintf('%s: Ignoring backend as requested by [-s, --select-backends].', $backendName),
|
||||
OutputInterface::VERBOSITY_VERY_VERBOSE
|
||||
);
|
||||
$output->writeln(r('Ignoring backend \'{backend}\' as requested by [-s, --select-backends].', [
|
||||
'backend' => $backendName
|
||||
]), OutputInterface::VERBOSITY_VERY_VERBOSE);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -154,7 +142,7 @@ final class ViewCommand extends Command
|
||||
|
||||
if ('table' === $mode) {
|
||||
(new Table($output))->setStyle('box')
|
||||
->setHeaders(['Backend', 'Filter: ' . (empty($filter) ? 'None' : $filter)]
|
||||
->setHeaders(['Backend', 'Data (Filter: ' . (empty($filter) ? 'None' : $filter) . ')']
|
||||
)->setRows($rows)
|
||||
->render();
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user