Parse request for backend settings.

This commit is contained in:
abdulmohsen
2024-04-20 00:39:53 +03:00
parent ca4ec1ae76
commit d573505dea
6 changed files with 119 additions and 38 deletions

View File

@@ -4,15 +4,20 @@ declare(strict_types=1);
namespace App\API\Backends;
use App\Backends\Common\Cache as BackendCache;
use App\Backends\Common\ClientInterface;
use App\Backends\Common\Context;
use App\Libs\Attributes\Route\Post;
use App\Libs\Config;
use App\Libs\ConfigFile;
use App\Libs\Container;
use App\Libs\DataUtil;
use App\Libs\Exceptions\Backends\InvalidContextException;
use App\Libs\Exceptions\RuntimeException;
use App\Libs\HTTP_STATUS;
use App\Libs\Options;
use App\Libs\Traits\APITraits;
use App\Libs\Uri;
use Psr\Http\Message\ResponseInterface as iResponse;
use Psr\Http\Message\ServerRequestInterface as iRequest;
@@ -48,16 +53,28 @@ final class Add
}
$instance = Container::getNew($class);
assert($instance instanceof ClientInterface, new \RuntimeException('Invalid client class.'));
assert($instance instanceof ClientInterface, new RuntimeException('Invalid client class.'));
try {
$context = $instance->fromRequest($request);
$config = DataUtil::fromArray($this->fromRequest($type, $request, $instance));
$context = new Context(
clientName: $type,
backendName: $name,
backendUrl: new Uri($config->get('url')),
cache: Container::get(BackendCache::class),
backendId: $config->get('uuid', null),
backendToken: $config->get('token'),
backendUser: $config->get('user', null),
options: $config->get('options', []),
);
if (false === $instance->validateContext($context)) {
throw new InvalidContextException('Invalid context.');
return api_error('Invalid context information was given.', HTTP_STATUS::HTTP_BAD_REQUEST);
}
$configFile = ConfigFile::open(Config::get('backends_file'), 'yaml', autoSave: false);
$configFile->set($name, $context);
$configFile = ConfigFile::open(Config::get('backends_file'), 'yaml');
$configFile->set($name, $config);
$configFile->persist();
} catch (InvalidContextException $e) {
return api_error($e->getMessage(), HTTP_STATUS::HTTP_BAD_REQUEST);
@@ -70,4 +87,53 @@ final class Add
return api_response(HTTP_STATUS::HTTP_OK, $response);
}
private function fromRequest(string $type, iRequest $request, ClientInterface|null $client = null): array
{
$data = DataUtil::fromArray($request->getParsedBody());
$config = [
'type' => $type,
'url' => $data->get('url'),
'token' => $data->get('token'),
'user' => $data->get('user'),
'uuid' => $data->get('uuid'),
'export' => [
'enabled' => (bool)$data->get('export.enabled', false),
'lastSync' => (int)$data->get('export.lastSync', 0),
],
'import' => [
'enabled' => (bool)$data->get('import.enabled', false),
'lastSync' => (int)$data->get('import.lastSync', 0),
],
'webhook' => [
'token' => $data->get('webhook.token'),
'match' => [
'user' => (bool)$data->get('webhook.match.user', false),
'uuid' => (bool)$data->get('webhook.match.uuid', false),
],
],
'options' => [],
];
$optionals = [
Options::DUMP_PAYLOAD => 'bool',
Options::LIBRARY_SEGMENT => 'int',
Options::IGNORE => 'string',
];
foreach ($optionals as $key => $type) {
if (null !== ($value = $data->get($key))) {
$val = $data->get($value, $type);
settype($val, $type);
$config = ag_set($config, "options.{$key}", $val);
}
}
if (null !== $client) {
$config = ag_set($config, 'options', $client->fromRequest($request));
}
return $config;
}
}

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace App\Backends\Common;
use App\Libs\Entity\StateInterface;
use App\Libs\Exceptions\Backends\InvalidContextException;
use App\Libs\Mappers\ImportInterface as iImport;
use App\Libs\QueueRequests;
use DateTimeInterface as iDate;
@@ -201,12 +202,12 @@ interface ClientInterface
public function listLibraries(array $opts = []): array;
/**
* Parse backend config from request context.
* Parse client specific options.
*
* @param ServerRequestInterface $request request to parse.
* @return Context Returns a valid {@see Context} instance.
* @return array parsed options.
*/
public function fromRequest(ServerRequestInterface $request): Context;
public function fromRequest(ServerRequestInterface $request): array;
/**
* Validate backend context.
@@ -214,7 +215,7 @@ interface ClientInterface
* @param Context $context context to validate.
*
* @return bool Returns true if context is valid.
* @throws
* @throws InvalidContextException if unable to validate context.
*/
public function validateContext(Context $context): bool;

View File

@@ -539,9 +539,9 @@ class EmbyClient implements iClient
/**
* @inheritdoc
*/
public function fromRequest(ServerRequestInterface $request): Context
public function fromRequest(ServerRequestInterface $request): array
{
return $this->context;
return [];
}
/**
@@ -549,7 +549,7 @@ class EmbyClient implements iClient
*/
public function validateContext(Context $context): bool
{
return true;
return false;
}
/**

View File

@@ -572,9 +572,9 @@ class JellyfinClient implements iClient
/**
* @inheritdoc
*/
public function fromRequest(ServerRequestInterface $request): Context
public function fromRequest(ServerRequestInterface $request): array
{
return $this->context;
return [];
}
/**
@@ -582,7 +582,7 @@ class JellyfinClient implements iClient
*/
public function validateContext(Context $context): bool
{
return true;
return false;
}
/**

View File

@@ -29,6 +29,7 @@ use App\Backends\Plex\Action\SearchId;
use App\Backends\Plex\Action\SearchQuery;
use App\Libs\Config;
use App\Libs\Container;
use App\Libs\DataUtil;
use App\Libs\Entity\StateInterface as iState;
use App\Libs\Exceptions\Backends\RuntimeException;
use App\Libs\Exceptions\HttpException;
@@ -553,9 +554,21 @@ class PlexClient implements iClient
/**
* @inheritdoc
*/
public function fromRequest(ServerRequestInterface $request): Context
public function fromRequest(ServerRequestInterface $request): array
{
return $this->context;
$params = DataUtil::fromArray($request->getParsedBody());
$opts = [];
if (null !== ($uuid = $params->get('plex_user_uuid'))) {
$opts['plex_user_uuid'] = $uuid;
}
if (null !== ($adminToken = $params->get(Options::ADMIN_TOKEN))) {
$opts[Options::ADMIN_TOKEN] = $adminToken;
}
return $opts;
}
/**
@@ -563,7 +576,7 @@ class PlexClient implements iClient
*/
public function validateContext(Context $context): bool
{
return true;
return false;
}
/**

View File

@@ -9,26 +9,27 @@ namespace App\Libs;
*/
final class Options
{
public const DRY_RUN = 'DRY_RUN';
public const NO_CACHE = 'NO_CACHE';
public const CACHE_TTL = 'CACHE_TTL';
public const FORCE_FULL = 'FORCE_FULL';
public const DEBUG_TRACE = 'DEBUG_TRACE';
public const IGNORE_DATE = 'IGNORE_DATE';
public const EXPORT_ALLOWED_TIME_DIFF = 'EXPORT_TIME_DIFF';
public const RAW_RESPONSE = 'SHOW_RAW_RESPONSE';
public const MAPPER_ALWAYS_UPDATE_META = 'ALWAYS_UPDATE_META';
public const MAPPER_DISABLE_AUTOCOMMIT = 'DISABLE_AUTOCOMMIT';
public const IMPORT_METADATA_ONLY = 'IMPORT_METADATA_ONLY';
public const MISMATCH_DEEP_SCAN = 'MISMATCH_DEEP_SCAN';
public const DISABLE_GUID = 'DISABLE_GUID';
public const LIBRARY_SEGMENT = 'LIBRARY_SEGMENT';
public const STATE_UPDATE_EVENT = 'STATE_UPDATE_EVENT';
public const DUMP_PAYLOAD = 'DUMP_PAYLOAD';
public const ADMIN_TOKEN = 'ADMIN_TOKEN';
public const NO_THROW = 'NO_THROW';
public const NO_LOGGING = 'NO_LOGGING';
public const MAX_EPISODE_RANGE = 'MAX_EPISODE_RANGE';
public const string DRY_RUN = 'DRY_RUN';
public const string NO_CACHE = 'NO_CACHE';
public const string CACHE_TTL = 'CACHE_TTL';
public const string FORCE_FULL = 'FORCE_FULL';
public const string DEBUG_TRACE = 'DEBUG_TRACE';
public const string IGNORE_DATE = 'IGNORE_DATE';
public const string EXPORT_ALLOWED_TIME_DIFF = 'EXPORT_TIME_DIFF';
public const string RAW_RESPONSE = 'SHOW_RAW_RESPONSE';
public const string MAPPER_ALWAYS_UPDATE_META = 'ALWAYS_UPDATE_META';
public const string MAPPER_DISABLE_AUTOCOMMIT = 'DISABLE_AUTOCOMMIT';
public const string IMPORT_METADATA_ONLY = 'IMPORT_METADATA_ONLY';
public const string MISMATCH_DEEP_SCAN = 'MISMATCH_DEEP_SCAN';
public const string DISABLE_GUID = 'DISABLE_GUID';
public const string LIBRARY_SEGMENT = 'LIBRARY_SEGMENT';
public const string STATE_UPDATE_EVENT = 'STATE_UPDATE_EVENT';
public const string DUMP_PAYLOAD = 'DUMP_PAYLOAD';
public const string ADMIN_TOKEN = 'ADMIN_TOKEN';
public const string NO_THROW = 'NO_THROW';
public const string NO_LOGGING = 'NO_LOGGING';
public const string MAX_EPISODE_RANGE = 'MAX_EPISODE_RANGE';
public const string IGNORE = 'ignore';
private function __construct()
{