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; namespace App\API\Backends;
use App\Backends\Common\Cache as BackendCache;
use App\Backends\Common\ClientInterface; use App\Backends\Common\ClientInterface;
use App\Backends\Common\Context;
use App\Libs\Attributes\Route\Post; use App\Libs\Attributes\Route\Post;
use App\Libs\Config; use App\Libs\Config;
use App\Libs\ConfigFile; use App\Libs\ConfigFile;
use App\Libs\Container; use App\Libs\Container;
use App\Libs\DataUtil; use App\Libs\DataUtil;
use App\Libs\Exceptions\Backends\InvalidContextException; use App\Libs\Exceptions\Backends\InvalidContextException;
use App\Libs\Exceptions\RuntimeException;
use App\Libs\HTTP_STATUS; use App\Libs\HTTP_STATUS;
use App\Libs\Options;
use App\Libs\Traits\APITraits; use App\Libs\Traits\APITraits;
use App\Libs\Uri;
use Psr\Http\Message\ResponseInterface as iResponse; use Psr\Http\Message\ResponseInterface as iResponse;
use Psr\Http\Message\ServerRequestInterface as iRequest; use Psr\Http\Message\ServerRequestInterface as iRequest;
@@ -48,16 +53,28 @@ final class Add
} }
$instance = Container::getNew($class); $instance = Container::getNew($class);
assert($instance instanceof ClientInterface, new \RuntimeException('Invalid client class.')); assert($instance instanceof ClientInterface, new RuntimeException('Invalid client class.'));
try { 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)) { 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 = ConfigFile::open(Config::get('backends_file'), 'yaml');
$configFile->set($name, $context); $configFile->set($name, $config);
$configFile->persist(); $configFile->persist();
} catch (InvalidContextException $e) { } catch (InvalidContextException $e) {
return api_error($e->getMessage(), HTTP_STATUS::HTTP_BAD_REQUEST); 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); 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; namespace App\Backends\Common;
use App\Libs\Entity\StateInterface; use App\Libs\Entity\StateInterface;
use App\Libs\Exceptions\Backends\InvalidContextException;
use App\Libs\Mappers\ImportInterface as iImport; use App\Libs\Mappers\ImportInterface as iImport;
use App\Libs\QueueRequests; use App\Libs\QueueRequests;
use DateTimeInterface as iDate; use DateTimeInterface as iDate;
@@ -201,12 +202,12 @@ interface ClientInterface
public function listLibraries(array $opts = []): array; public function listLibraries(array $opts = []): array;
/** /**
* Parse backend config from request context. * Parse client specific options.
* *
* @param ServerRequestInterface $request request to parse. * @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. * Validate backend context.
@@ -214,7 +215,7 @@ interface ClientInterface
* @param Context $context context to validate. * @param Context $context context to validate.
* *
* @return bool Returns true if context is valid. * @return bool Returns true if context is valid.
* @throws * @throws InvalidContextException if unable to validate context.
*/ */
public function validateContext(Context $context): bool; public function validateContext(Context $context): bool;

View File

@@ -539,9 +539,9 @@ class EmbyClient implements iClient
/** /**
* @inheritdoc * @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 public function validateContext(Context $context): bool
{ {
return true; return false;
} }
/** /**

View File

@@ -572,9 +572,9 @@ class JellyfinClient implements iClient
/** /**
* @inheritdoc * @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 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\Backends\Plex\Action\SearchQuery;
use App\Libs\Config; use App\Libs\Config;
use App\Libs\Container; use App\Libs\Container;
use App\Libs\DataUtil;
use App\Libs\Entity\StateInterface as iState; use App\Libs\Entity\StateInterface as iState;
use App\Libs\Exceptions\Backends\RuntimeException; use App\Libs\Exceptions\Backends\RuntimeException;
use App\Libs\Exceptions\HttpException; use App\Libs\Exceptions\HttpException;
@@ -553,9 +554,21 @@ class PlexClient implements iClient
/** /**
* @inheritdoc * @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 public function validateContext(Context $context): bool
{ {
return true; return false;
} }
/** /**

View File

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