Added better constraints checks with more to follow.
This commit is contained in:
@@ -1,37 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Last update: 2024-04-26
|
|
||||||
*
|
|
||||||
* servers.yaml backend spec.
|
|
||||||
* This file defines the backend spec.
|
|
||||||
* The dot (.) notation means the key is subarray of the parent key.
|
|
||||||
* the boolean at the end of the key means if the key should be visible in the config:edit/view command.
|
|
||||||
*/
|
|
||||||
return [
|
|
||||||
'name' => true,
|
|
||||||
'type' => true,
|
|
||||||
'url' => true,
|
|
||||||
'token' => true,
|
|
||||||
'uuid' => true,
|
|
||||||
'user' => true,
|
|
||||||
'export.enabled' => true,
|
|
||||||
'export.lastSync' => true,
|
|
||||||
'import.enabled' => true,
|
|
||||||
'import.lastSync' => true,
|
|
||||||
'webhook.token' => true,
|
|
||||||
'webhook.match.user' => true,
|
|
||||||
'webhook.match.uuid' => true,
|
|
||||||
'options.ignore' => true,
|
|
||||||
'options.LIBRARY_SEGMENT' => true,
|
|
||||||
'options.ADMIN_TOKEN' => false,
|
|
||||||
'options.DUMP_PAYLOAD' => false,
|
|
||||||
'options.DEBUG_TRACE' => false,
|
|
||||||
'options.IMPORT_METADATA_ONLY' => false,
|
|
||||||
'options.DRY_RUN' => false,
|
|
||||||
'options.client.timeout' => false,
|
|
||||||
'options.client.http_version' => false,
|
|
||||||
'options.use_old_progress_endpoint' => false,
|
|
||||||
'options.MAX_EPISODE_RANGE' => false,
|
|
||||||
];
|
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Last update: 2024-05-14
|
* Last update: 2024-05-17
|
||||||
*
|
*
|
||||||
* servers.yaml backend spec.
|
* servers.yaml backend spec.
|
||||||
*
|
*
|
||||||
@@ -14,13 +14,15 @@ return [
|
|||||||
'type' => 'string',
|
'type' => 'string',
|
||||||
'visible' => true,
|
'visible' => true,
|
||||||
'description' => 'The name of the backend.',
|
'description' => 'The name of the backend.',
|
||||||
|
'immutable' => true,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'key' => 'type',
|
'key' => 'type',
|
||||||
'type' => 'string',
|
'type' => 'string',
|
||||||
'visible' => true,
|
'visible' => true,
|
||||||
'description' => 'The type of the backend.',
|
'description' => 'The type of the backend.',
|
||||||
'choices' => ['plex', 'emby', 'jellyfin']
|
'choices' => ['plex', 'emby', 'jellyfin'],
|
||||||
|
'immutable' => true,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'key' => 'url',
|
'key' => 'url',
|
||||||
@@ -54,7 +56,7 @@ return [
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
'key' => 'export.lastSync',
|
'key' => 'export.lastSync',
|
||||||
'type' => 'integer',
|
'type' => 'int',
|
||||||
'visible' => true,
|
'visible' => true,
|
||||||
'description' => 'The last time data was exported to the backend.',
|
'description' => 'The last time data was exported to the backend.',
|
||||||
],
|
],
|
||||||
@@ -66,7 +68,7 @@ return [
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
'key' => 'import.lastSync',
|
'key' => 'import.lastSync',
|
||||||
'type' => 'integer',
|
'type' => 'int',
|
||||||
'visible' => true,
|
'visible' => true,
|
||||||
'description' => 'The last time data was imported from the backend.',
|
'description' => 'The last time data was imported from the backend.',
|
||||||
],
|
],
|
||||||
@@ -139,7 +141,7 @@ return [
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
'key' => 'options.client.timeout',
|
'key' => 'options.client.timeout',
|
||||||
'type' => 'integer',
|
'type' => 'int',
|
||||||
'visible' => false,
|
'visible' => false,
|
||||||
'description' => 'The http timeout per request to the backend.',
|
'description' => 'The http timeout per request to the backend.',
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -31,26 +31,39 @@ final class Option
|
|||||||
return api_error('Invalid value for option path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
return api_error('Invalid value for option path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (false === str_starts_with($option, 'options.')) {
|
||||||
|
return api_error(
|
||||||
|
"Invalid option. Option path parameter keys must start with 'options.'",
|
||||||
|
HTTP_STATUS::HTTP_BAD_REQUEST
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$spec = getServerColumnSpec($option);
|
||||||
|
if (empty($spec)) {
|
||||||
|
return api_error(r("Invalid option '{key}'.", ['key' => $option]), HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
$list = ConfigFile::open(Config::get('backends_file'), 'yaml', autoCreate: true);
|
$list = ConfigFile::open(Config::get('backends_file'), 'yaml', autoCreate: true);
|
||||||
|
|
||||||
if (false === $list->has($name)) {
|
if (false === $list->has($name)) {
|
||||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), HTTP_STATUS::HTTP_NOT_FOUND);
|
return api_error(r("Backend '{name}' not found.", ['name' => $name]), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
$key = $name . '.options.' . $option;
|
if (false === $list->has($name . '.' . $option)) {
|
||||||
|
return api_error(r("Option '{option}' not found in backend '{name}' config.", [
|
||||||
if (false === $list->has($key)) {
|
|
||||||
return api_error(r("Option '{option}' not found in backend '{name}'.", [
|
|
||||||
'option' => $option,
|
'option' => $option,
|
||||||
'name' => $name
|
'name' => $name
|
||||||
]), HTTP_STATUS::HTTP_NOT_FOUND);
|
]), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
$value = $list->get($key);
|
$value = $list->get($name . '.' . $option);
|
||||||
|
settype($value, ag($spec, 'type', 'string'));
|
||||||
|
|
||||||
return api_response(HTTP_STATUS::HTTP_OK, [
|
return api_response(HTTP_STATUS::HTTP_OK, [
|
||||||
'key' => $option,
|
'key' => $spec['key'],
|
||||||
'value' => $value,
|
'value' => $value,
|
||||||
'type' => get_debug_type($value),
|
'type' => ag($spec, 'type', 'string'),
|
||||||
|
'description' => ag($spec, 'description', ''),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,31 +83,38 @@ final class Option
|
|||||||
$data = DataUtil::fromRequest($request);
|
$data = DataUtil::fromRequest($request);
|
||||||
|
|
||||||
if (null === ($option = $data->get('key'))) {
|
if (null === ($option = $data->get('key'))) {
|
||||||
return api_error('Invalid value for key.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
return api_error('No option key was given.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
$spec = require __DIR__ . '/../../../config/backend.spec.php';
|
if (false === str_starts_with($option, 'options.')) {
|
||||||
$found = false;
|
return api_error(
|
||||||
|
"Invalid option key was given. Option keys must start with 'options.'",
|
||||||
foreach ($spec as $supportedKey => $_) {
|
HTTP_STATUS::HTTP_BAD_REQUEST
|
||||||
if (str_ends_with($supportedKey, 'options.' . $option)) {
|
);
|
||||||
$found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (false === $found) {
|
$spec = getServerColumnSpec($option);
|
||||||
return api_error(r("Option '{key}' is not supported.", ['key' => $option]), HTTP_STATUS::HTTP_BAD_REQUEST);
|
if (empty($spec)) {
|
||||||
|
return api_error(r("Invalid option '{key}'.", ['key' => $option]), HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($list->has($name . '.' . $option)) {
|
||||||
|
return api_error(r("Option '{option}' already exists in backend '{name}'.", [
|
||||||
|
'option' => $option,
|
||||||
|
'name' => $name
|
||||||
|
]), HTTP_STATUS::HTTP_CONFLICT);
|
||||||
}
|
}
|
||||||
|
|
||||||
$value = $data->get('value');
|
$value = $data->get('value');
|
||||||
|
settype($value, ag($spec, 'type', 'string'));
|
||||||
|
|
||||||
$list->set($name . '.options.' . $option, $value)->persist();
|
$list->set($name . '.' . $option, $value)->persist();
|
||||||
|
|
||||||
return api_response(HTTP_STATUS::HTTP_OK, [
|
return api_response(HTTP_STATUS::HTTP_OK, [
|
||||||
'key' => $option,
|
'key' => $option,
|
||||||
'value' => $value,
|
'value' => $value,
|
||||||
'type' => get_debug_type($value),
|
'type' => ag($spec, 'type', 'string'),
|
||||||
|
'description' => ag($spec, 'description', ''),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,34 +129,60 @@ final class Option
|
|||||||
return api_error('Invalid value for option parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
return api_error('Invalid value for option parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
$list = ConfigFile::open(Config::get('backends_file'), 'yaml', autoCreate: true);
|
if (false === str_starts_with($option, 'options.')) {
|
||||||
|
return api_error(
|
||||||
|
"Invalid option key was given. Option keys must start with 'options.'",
|
||||||
|
HTTP_STATUS::HTTP_BAD_REQUEST
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$spec = getServerColumnSpec($option);
|
||||||
|
if (empty($spec)) {
|
||||||
|
return api_error(r("Invalid option '{key}'.", ['key' => $option]), HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
$list = ConfigFile::open(Config::get('backends_file'), 'yaml', autoCreate: true);
|
||||||
if (false === $list->has($name)) {
|
if (false === $list->has($name)) {
|
||||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), HTTP_STATUS::HTTP_NOT_FOUND);
|
return api_error(r("Backend '{name}' not found.", ['name' => $name]), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
$key = $name . '.options.' . $option;
|
if (false === $list->has($name . '.' . $option)) {
|
||||||
if (false === $list->has($key)) {
|
return api_error(r("Option '{option}' not found in backend '{name}' config.", [
|
||||||
return api_error(r("Option '{option}' not found in backend '{name}'.", [
|
|
||||||
'option' => $option,
|
'option' => $option,
|
||||||
'name' => $name
|
'name' => $name
|
||||||
]), HTTP_STATUS::HTTP_NOT_FOUND);
|
]), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (true === (bool)ag($spec, 'immutable', false)) {
|
||||||
|
return api_error(r("Option '{option}' is immutable.", [
|
||||||
|
'option' => $option,
|
||||||
|
]), HTTP_STATUS::HTTP_CONFLICT);
|
||||||
|
}
|
||||||
|
|
||||||
$data = DataUtil::fromRequest($request);
|
$data = DataUtil::fromRequest($request);
|
||||||
|
|
||||||
if (null === ($value = $data->get('value'))) {
|
if (null === ($value = $data->get('value'))) {
|
||||||
return api_error(r("No value was provided for '{key}'.", [
|
return api_error(r("No value was provided for '{key}'.", [
|
||||||
'key' => $key,
|
'key' => $option,
|
||||||
]), HTTP_STATUS::HTTP_BAD_REQUEST);
|
]), HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
$list->set($key, $value)->persist();
|
settype($value, ag($spec, 'type', 'string'));
|
||||||
|
|
||||||
|
$oldValue = $list->get($name . '.' . $option);
|
||||||
|
if (null !== $oldValue) {
|
||||||
|
settype($oldValue, ag($spec, 'type', 'string'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($oldValue !== $value) {
|
||||||
|
$list->set($name . '.' . $option, $value)->persist();
|
||||||
|
}
|
||||||
|
|
||||||
return api_response(HTTP_STATUS::HTTP_OK, [
|
return api_response(HTTP_STATUS::HTTP_OK, [
|
||||||
'key' => $option,
|
'key' => $option,
|
||||||
'value' => $value,
|
'value' => $value,
|
||||||
'type' => get_debug_type($value),
|
'type' => ag($spec, 'type', 'string'),
|
||||||
|
'description' => ag($spec, 'description', ''),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,21 +197,40 @@ final class Option
|
|||||||
return api_error('Invalid value for option option parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
return api_error('Invalid value for option option parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
$list = ConfigFile::open(Config::get('backends_file'), 'yaml', autoCreate: true);
|
if (false === str_starts_with($option, 'options.')) {
|
||||||
|
return api_error(
|
||||||
|
"Invalid option key was given. Option keys must start with 'options.'",
|
||||||
|
HTTP_STATUS::HTTP_BAD_REQUEST
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$spec = getServerColumnSpec($option);
|
||||||
|
if (empty($spec)) {
|
||||||
|
return api_error(r("Invalid option '{key}'.", ['key' => $option]), HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
$list = ConfigFile::open(Config::get('backends_file'), 'yaml', autoCreate: true);
|
||||||
if (false === $list->has($name)) {
|
if (false === $list->has($name)) {
|
||||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), HTTP_STATUS::HTTP_NOT_FOUND);
|
return api_error(r("Backend '{name}' not found.", ['name' => $name]), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
$key = $name . '.options.' . $option;
|
if (false === $list->has($name . '.' . $option)) {
|
||||||
|
return api_error(r("Option '{option}' not found in backend '{name}' config.", [
|
||||||
|
'option' => $option,
|
||||||
|
'name' => $name
|
||||||
|
]), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
$value = $list->get($key);
|
$value = $list->get($name . '.' . $option);
|
||||||
$list->delete($key)->persist();
|
settype($value, ag($spec, 'type', 'string'));
|
||||||
|
|
||||||
|
$list->delete($option)->persist();
|
||||||
|
|
||||||
return api_response(HTTP_STATUS::HTTP_OK, [
|
return api_response(HTTP_STATUS::HTTP_OK, [
|
||||||
'key' => $option,
|
'key' => $option,
|
||||||
'value' => $value,
|
'value' => $value,
|
||||||
'type' => get_debug_type($value),
|
'type' => ag($spec, 'type', 'string'),
|
||||||
|
'description' => ag($spec, 'description', ''),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,16 @@ final class Update
|
|||||||
{
|
{
|
||||||
use APITraits;
|
use APITraits;
|
||||||
|
|
||||||
|
private const array IMMUTABLE_KEYS = [
|
||||||
|
'name',
|
||||||
|
'type',
|
||||||
|
'options',
|
||||||
|
'webhook',
|
||||||
|
'webhook.match',
|
||||||
|
'import',
|
||||||
|
'export',
|
||||||
|
];
|
||||||
|
|
||||||
private ConfigFile $backendFile;
|
private ConfigFile $backendFile;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
@@ -72,20 +82,23 @@ final class Update
|
|||||||
HTTP_STATUS::HTTP_BAD_REQUEST);
|
HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
$spec = array_keys(require __DIR__ . '/../../../config/backend.spec.php');
|
|
||||||
|
|
||||||
foreach ($data as $update) {
|
foreach ($data as $update) {
|
||||||
$key = ag($update, 'key');
|
|
||||||
$value = ag($update, 'value');
|
$value = ag($update, 'value');
|
||||||
|
|
||||||
if (null === $key) {
|
if (null === ($key = ag($update, 'key'))) {
|
||||||
return api_error('No key to update was present.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
return api_error('No key to update was present.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (false === in_array($key, $spec, true)) {
|
$spec = getServerColumnSpec($key);
|
||||||
|
|
||||||
|
if (empty($spec)) {
|
||||||
return api_error(r('Invalid key to update: {key}', ['key' => $key]), HTTP_STATUS::HTTP_BAD_REQUEST);
|
return api_error(r('Invalid key to update: {key}', ['key' => $key]), HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (in_array($key, self::IMMUTABLE_KEYS, true)) {
|
||||||
|
return api_error(r('Key {key} is immutable.', ['key' => $key]), HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
$this->backendFile->set("{$name}.{$key}", $value);
|
$this->backendFile->set("{$name}.{$key}", $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,14 +138,15 @@ final class Update
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$spec = require __DIR__ . '/../../../config/backend.spec.php';
|
|
||||||
|
|
||||||
foreach ($data->get('options', []) as $key => $value) {
|
foreach ($data->get('options', []) as $key => $value) {
|
||||||
if (false === ag_exists($spec, "options.{$key}") || null === $value) {
|
$key = "options.{$key}";
|
||||||
|
$spec = getServerColumnSpec($key);
|
||||||
|
|
||||||
|
if (empty($spec) || null === $value) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$newData = ag_set($newData, "options.{$key}", $value);
|
$newData = ag_set($newData, $key, $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return deepArrayMerge([$config, $client->fromRequest($newData, $request)]);
|
return deepArrayMerge([$config, $client->fromRequest($newData, $request)]);
|
||||||
|
|||||||
@@ -148,14 +148,15 @@ final class Add
|
|||||||
'options' => [],
|
'options' => [],
|
||||||
];
|
];
|
||||||
|
|
||||||
$spec = require __DIR__ . '/../../../config/backend.spec.php';
|
|
||||||
|
|
||||||
foreach ($data->get('options', []) as $key => $value) {
|
foreach ($data->get('options', []) as $key => $value) {
|
||||||
if (false === ag_exists($spec, "options.{$key}") || null === $value) {
|
$key = "options.{$key}";
|
||||||
|
$spec = getServerColumnSpec($key);
|
||||||
|
|
||||||
|
if (empty($spec) || null === $value) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$config = ag_set($config, "options.{$key}", $value);
|
$config = ag_set($config, $key, $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $client->fromRequest($config, $request);
|
return $client->fromRequest($config, $request);
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ use Throwable;
|
|||||||
#[Cli(command: self::ROUTE)]
|
#[Cli(command: self::ROUTE)]
|
||||||
final class EditCommand extends Command
|
final class EditCommand extends Command
|
||||||
{
|
{
|
||||||
public const ROUTE = 'config:edit';
|
public const string ROUTE = 'config:edit';
|
||||||
|
|
||||||
public function __construct(private LoggerInterface $logger)
|
public function __construct(private LoggerInterface $logger)
|
||||||
{
|
{
|
||||||
@@ -75,13 +75,7 @@ final class EditCommand extends Command
|
|||||||
', ',
|
', ',
|
||||||
array_map(
|
array_map(
|
||||||
fn($val) => '<value>' . $val . '</value>',
|
fn($val) => '<value>' . $val . '</value>',
|
||||||
array_keys(
|
array_column(require __DIR__ . '/../../../config/servers.spec.php', 'key')
|
||||||
array_filter(
|
|
||||||
array: require __DIR__ . '/../../../config/backend.spec.php',
|
|
||||||
callback: fn($val, $key) => $val,
|
|
||||||
mode: ARRAY_FILTER_USE_BOTH
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
@@ -232,13 +226,13 @@ final class EditCommand extends Command
|
|||||||
|
|
||||||
$suggest = [];
|
$suggest = [];
|
||||||
|
|
||||||
foreach (require __DIR__ . '/../../../config/backend.spec.php' as $name => $val) {
|
foreach (require __DIR__ . '/../../../config/servers.spec.php' as $column) {
|
||||||
if (false === $val) {
|
if (false === (bool)ag($column, 'visible', false)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($currentValue) || str_starts_with($name, $currentValue)) {
|
if (empty($currentValue) || str_starts_with(ag($column, 'key', ''), $currentValue)) {
|
||||||
$suggest[] = $name;
|
$suggest[] = ag($column, 'key', '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ use Symfony\Component\Yaml\Yaml;
|
|||||||
#[Cli(command: self::ROUTE)]
|
#[Cli(command: self::ROUTE)]
|
||||||
final class ViewCommand extends Command
|
final class ViewCommand extends Command
|
||||||
{
|
{
|
||||||
public const ROUTE = 'config:view';
|
public const string ROUTE = 'config:view';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure the command.
|
* Configure the command.
|
||||||
@@ -177,8 +177,10 @@ final class ViewCommand extends Command
|
|||||||
|
|
||||||
$suggest = [];
|
$suggest = [];
|
||||||
|
|
||||||
foreach (require __DIR__ . '/../../../config/backend.spec.php' as $name => $val) {
|
foreach (require __DIR__ . '/../../../config/servers.spec.php' as $column) {
|
||||||
if (true === $val && (empty($currentValue) || str_starts_with($name, $currentValue))) {
|
$name = ag($column, 'key', '');
|
||||||
|
$visible = (bool)ag($column, 'visible', false);
|
||||||
|
if ($visible && (empty($currentValue) || str_starts_with($name, $currentValue))) {
|
||||||
$suggest[] = $name;
|
$suggest[] = $name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1442,3 +1442,55 @@ if (!function_exists('APIRequest')) {
|
|||||||
return new APIResponse($response->getStatusCode(), $response->getHeaders(), [], $response->getBody());
|
return new APIResponse($response->getStatusCode(), $response->getHeaders(), [], $response->getBody());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!function_exists('getServerColumnSpec')) {
|
||||||
|
/**
|
||||||
|
* Returns the spec for the given server column.
|
||||||
|
*
|
||||||
|
* @param string $column
|
||||||
|
*
|
||||||
|
* @return array The spec for the given column. Otherwise, an empty array.
|
||||||
|
*/
|
||||||
|
function getServerColumnSpec(string $column): array
|
||||||
|
{
|
||||||
|
static $_serverSpec = null;
|
||||||
|
|
||||||
|
if (null === $_serverSpec) {
|
||||||
|
$_serverSpec = require __DIR__ . '/../../config/servers.spec.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($_serverSpec as $spec) {
|
||||||
|
if (ag($spec, 'key') === $column) {
|
||||||
|
return $spec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!function_exists('getEnvSpec')) {
|
||||||
|
/**
|
||||||
|
* Returns the spec for the given environment variable.
|
||||||
|
*
|
||||||
|
* @param string $env
|
||||||
|
*
|
||||||
|
* @return array The spec for the given column. Otherwise, an empty array.
|
||||||
|
*/
|
||||||
|
function getEnvSpec(string $env): array
|
||||||
|
{
|
||||||
|
static $_envSpec = null;
|
||||||
|
|
||||||
|
if (null === $_envSpec) {
|
||||||
|
$_envSpec = require __DIR__ . '/../../config/env.spec.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($_envSpec as $spec) {
|
||||||
|
if (ag($spec, 'key') === $env) {
|
||||||
|
return $spec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user