Massive API & WebUI changes.
This commit is contained in:
@@ -2,47 +2,43 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\API\Plex;
|
||||
namespace App\API\Backend;
|
||||
|
||||
use App\Libs\Attributes\Route\Post;
|
||||
use App\Libs\DataUtil;
|
||||
use App\Libs\Exceptions\RuntimeException;
|
||||
use App\Libs\Exceptions\InvalidArgumentException;
|
||||
use App\Libs\HTTP_STATUS;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface as iHttp;
|
||||
use Throwable;
|
||||
|
||||
final class GenerateAccessToken
|
||||
final class AccessToken
|
||||
{
|
||||
use APITraits;
|
||||
|
||||
public const string URL = '%{api.prefix}/plex/accesstoken';
|
||||
|
||||
public function __construct(private iHttp $http)
|
||||
public function __construct(private readonly iHttp $http)
|
||||
{
|
||||
}
|
||||
|
||||
#[Post(self::URL . '/{id:backend}[/]', name: 'plex.accesstoken')]
|
||||
public function gAccesstoken(iRequest $request, array $args = []): iResponse
|
||||
#[Post(Index::URL . '/{name:backend}/accesstoken[/]', name: 'backend.accesstoken')]
|
||||
public function __invoke(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
$backend = ag($args, 'id');
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$data = DataUtil::fromArray($request->getParsedBody());
|
||||
|
||||
if (null === ($uuid = $data->get('uuid'))) {
|
||||
return api_error('No User (uuid) was given.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
try {
|
||||
$client = $this->getClient($backend);
|
||||
} catch (RuntimeException $e) {
|
||||
return api_error($e->getMessage(), HTTP_STATUS::HTTP_INTERNAL_SERVER_ERROR);
|
||||
if (null === ($id = $data->get('id'))) {
|
||||
return api_error('No id was given.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
try {
|
||||
$client = $this->getClient(name: $name);
|
||||
$token = $client->getUserToken(
|
||||
userId: $uuid,
|
||||
userId: $id,
|
||||
username: $data->get('username', $client->getContext()->backendName . '_user'),
|
||||
);
|
||||
|
||||
@@ -59,7 +55,9 @@ final class GenerateAccessToken
|
||||
}
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, $arr);
|
||||
} catch (\Throwable $e) {
|
||||
} catch (InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||
} catch (Throwable $e) {
|
||||
return api_error($e->getMessage(), HTTP_STATUS::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
49
src/API/Backend/Discover.php
Normal file
49
src/API/Backend/Discover.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\API\Backend;
|
||||
|
||||
use App\Backends\Plex\PlexClient;
|
||||
use App\Libs\Attributes\Route\Get;
|
||||
use App\Libs\Exceptions\InvalidArgumentException;
|
||||
use App\Libs\HTTP_STATUS;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface as iHttp;
|
||||
use Throwable;
|
||||
|
||||
final class Discover
|
||||
{
|
||||
use APITraits;
|
||||
|
||||
public function __construct(private readonly iHttp $http)
|
||||
{
|
||||
}
|
||||
|
||||
#[Get(Index::URL . '/{name:backend}/discover[/]', name: 'backend.discover')]
|
||||
public function __invoke(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
try {
|
||||
$client = $this->getClient(name: $name);
|
||||
|
||||
if (PlexClient::CLIENT_NAME !== $client->getType()) {
|
||||
return api_error('Discover is only available for Plex backends.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
assert($client instanceof PlexClient);
|
||||
|
||||
$list = $client::discover($this->http, $client->getContext()->backendToken);
|
||||
return api_response(HTTP_STATUS::HTTP_OK, ag($list, 'list', []));
|
||||
} catch (InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||
} catch (Throwable $e) {
|
||||
return api_error($e->getMessage(), HTTP_STATUS::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,11 +27,11 @@ final class Ignore
|
||||
$this->file = new ConfigFile(Config::get('path') . '/config/ignore.yaml', type: 'yaml', autoCreate: true);
|
||||
}
|
||||
|
||||
#[Get(Index::URL . '/{name:backend}/ignore[/]', name: 'backends.backend.ignoredIds')]
|
||||
#[Get(Index::URL . '/{name:backend}/ignore[/]', name: 'backend.ignoredIds')]
|
||||
public function ignoredIds(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('No backend was given.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
return api_error('Invalid value for name path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$list = [];
|
||||
@@ -61,22 +61,23 @@ final class Ignore
|
||||
'created' => makeDate($date),
|
||||
];
|
||||
}
|
||||
$apiUrl = $request->getUri()->withHost('')->withPort(0)->withScheme('');
|
||||
|
||||
$response = [
|
||||
'ignore' => $list,
|
||||
'links' => [
|
||||
'self' => (string)$apiUrl,
|
||||
'list' => (string)$apiUrl->withPath(parseConfigValue(Index::URL)),
|
||||
],
|
||||
];
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, $response);
|
||||
return api_response(HTTP_STATUS::HTTP_OK, $list);
|
||||
}
|
||||
|
||||
#[Delete(Index::URL . '/{name:backend}/ignore[/]', name: 'backends.backend.ignoredIds.delete')]
|
||||
#[Delete(Index::URL . '/{name:backend}/ignore[/]', name: 'backend.ignoredIds.delete')]
|
||||
public function deleteRule(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$data = $this->getBackends(name: $name);
|
||||
|
||||
if (empty($data)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$params = DataUtil::fromRequest($request);
|
||||
|
||||
if (null === ($rule = $params->get('rule'))) {
|
||||
@@ -98,11 +99,11 @@ final class Ignore
|
||||
return api_response(HTTP_STATUS::HTTP_OK);
|
||||
}
|
||||
|
||||
#[Post(Index::URL . '/{name:backend}/ignore[/]', name: 'backends.backend.ignoredIds.add')]
|
||||
#[Post(Index::URL . '/{name:backend}/ignore[/]', name: 'backend.ignoredIds.add')]
|
||||
public function addRule(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('No backend was given.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
return api_error('Invalid value for name path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$data = $this->getBackends(name: $name);
|
||||
|
||||
@@ -16,11 +16,11 @@ final class Index
|
||||
|
||||
public const string URL = '%{api.prefix}/backend';
|
||||
|
||||
#[Get(self::URL . '/{name:backend}[/]', name: 'backends.view')]
|
||||
#[Get(self::URL . '/{name:backend}[/]', name: 'backend.view')]
|
||||
public function __invoke(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for id path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
return api_error('Invalid value for name path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$data = $this->getBackends(name: $name);
|
||||
@@ -29,17 +29,8 @@ final class Index
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$apiUrl = $request->getUri()->withHost('')->withPort(0)->withScheme('');
|
||||
$data = array_pop($data);
|
||||
|
||||
$response = [
|
||||
...$data,
|
||||
'links' => [
|
||||
'self' => (string)$apiUrl,
|
||||
'list' => (string)$apiUrl->withPath(parseConfigValue(Index::URL)),
|
||||
],
|
||||
];
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, ['backend' => $response]);
|
||||
return api_response(HTTP_STATUS::HTTP_OK, $data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,11 +18,11 @@ final class Info
|
||||
{
|
||||
use APITraits;
|
||||
|
||||
#[Get(Index::URL . '/{name:backend}/info[/]', name: 'backends.backend.info')]
|
||||
public function backendsView(iRequest $request, array $args = []): iResponse
|
||||
#[Get(Index::URL . '/{name:backend}/info[/]', name: 'backend.info')]
|
||||
public function __invoke(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for id path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
return api_error('Invalid value for name path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -40,20 +40,9 @@ final class Info
|
||||
|
||||
try {
|
||||
$data = $client->getInfo($opts);
|
||||
return api_response(HTTP_STATUS::HTTP_OK, $data);
|
||||
} catch (Throwable $e) {
|
||||
return api_error($e->getMessage(), HTTP_STATUS::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
$apiUrl = $request->getUri()->withHost('')->withPort(0)->withScheme('');
|
||||
|
||||
$response = [
|
||||
'data' => $data,
|
||||
'links' => [
|
||||
'self' => (string)$apiUrl,
|
||||
'list' => (string)$apiUrl->withPath(parseConfigValue(Index::URL)),
|
||||
],
|
||||
];
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, $response);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,32 +2,51 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\API\Backend\Library;
|
||||
namespace App\API\Backend;
|
||||
|
||||
use App\API\Backend\Index as BackendsIndex;
|
||||
use App\Libs\Attributes\Route\Get;
|
||||
use App\Libs\Attributes\Route\Route;
|
||||
use App\Libs\Config;
|
||||
use App\Libs\ConfigFile;
|
||||
use App\Libs\DataUtil;
|
||||
use App\Libs\Exceptions\RuntimeException;
|
||||
use App\Libs\HTTP_STATUS;
|
||||
use App\Libs\Options;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
use Throwable;
|
||||
|
||||
final class Ignore
|
||||
final class Library
|
||||
{
|
||||
use APITraits;
|
||||
|
||||
#[Route(['POST', 'DELETE'], BackendsIndex::URL . '/{name:backend}/library[/]', name: 'backends.library.ignore')]
|
||||
public function _invoke(iRequest $request, array $args = []): iResponse
|
||||
#[Get(BackendsIndex::URL . '/{name:backend}/library[/]', name: 'backend.library')]
|
||||
public function listLibraries(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('No backend was given.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
return api_error('Invalid value for name path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
if (null === ($id = DataUtil::fromRequest($request, true)->get('id', null))) {
|
||||
return api_error('No library id was given.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
try {
|
||||
$client = $this->getClient(name: $name);
|
||||
return api_response(HTTP_STATUS::HTTP_OK, $client->listLibraries());
|
||||
} catch (RuntimeException $e) {
|
||||
return api_error($e->getMessage(), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||
} catch (Throwable $e) {
|
||||
return api_error($e->getMessage(), HTTP_STATUS::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
#[Route(['POST', 'DELETE'], BackendsIndex::URL . '/{name:backend}/library/{id}[/]', name: 'backend.library.ignore')]
|
||||
public function ignoreLibrary(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
if (null === ($id = ag($args, 'id'))) {
|
||||
return api_error('Invalid value for id path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$remove = 'DELETE' === $request->getMethod();
|
||||
@@ -75,13 +94,6 @@ final class Ignore
|
||||
|
||||
$config->set("{$name}.options." . Options::IGNORE, implode(',', array_values($ignoreIds)))->persist();
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, [
|
||||
'type' => $config->get("{$name}.type"),
|
||||
'libraries' => $libraries,
|
||||
'links' => [
|
||||
'self' => (string)parseConfigValue(BackendsIndex::URL . "/{$name}/library"),
|
||||
'backend' => (string)parseConfigValue(BackendsIndex::URL . "/{$name}"),
|
||||
],
|
||||
]);
|
||||
return api_response(HTTP_STATUS::HTTP_OK, $libraries);
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\API\Backend\Library;
|
||||
|
||||
use App\API\Backend\Index as BackendsIndex;
|
||||
use App\Libs\Attributes\Route\Get;
|
||||
use App\Libs\Config;
|
||||
use App\Libs\Exceptions\RuntimeException;
|
||||
use App\Libs\HTTP_STATUS;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
|
||||
final class Index
|
||||
{
|
||||
use APITraits;
|
||||
|
||||
#[Get(BackendsIndex::URL . '/{name:backend}/library[/]', name: 'backends.library.list')]
|
||||
public function listLibraries(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('No backend was given.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
try {
|
||||
$client = $this->getClient(name: $name);
|
||||
} catch (RuntimeException $e) {
|
||||
return api_error($e->getMessage(), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$response = [
|
||||
'type' => ag(array_flip(Config::get('supported')), $client::class),
|
||||
'libraries' => $client->listLibraries(),
|
||||
'links' => [
|
||||
'self' => (string)$request->getUri()->withHost('')->withPort(0)->withScheme(''),
|
||||
'backend' => (string)parseConfigValue(BackendsIndex::URL . "/{$name}"),
|
||||
],
|
||||
];
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, $response);
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\API\Backend\Library;
|
||||
namespace App\API\Backend;
|
||||
|
||||
use App\API\Backend\Index as BackendsIndex;
|
||||
use App\API\Backend\Index as backendIndex;
|
||||
use App\Commands\Backend\Library\MismatchCommand;
|
||||
use App\Libs\Attributes\Route\Get;
|
||||
use App\Libs\DataUtil;
|
||||
@@ -19,11 +19,11 @@ final class Mismatched
|
||||
{
|
||||
use APITraits;
|
||||
|
||||
#[Get(BackendsIndex::URL . '/{name:backend}/mismatched[/[{id}[/]]]', name: 'backends.library.mismatched')]
|
||||
public function listLibraries(iRequest $request, array $args = []): iResponse
|
||||
#[Get(backendIndex::URL . '/{name:backend}/mismatched[/[{id}[/]]]', name: 'backend.mismatched')]
|
||||
public function __invoke(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('No backend was given.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
return api_error('Invalid value for name path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$params = DataUtil::fromArray($request->getQueryParams());
|
||||
@@ -74,15 +74,6 @@ final class Mismatched
|
||||
$list[] = $processed;
|
||||
}
|
||||
}
|
||||
|
||||
$response = [
|
||||
'items' => $list,
|
||||
'links' => [
|
||||
'self' => (string)$request->getUri()->withHost('')->withPort(0)->withScheme(''),
|
||||
'backend' => (string)parseConfigValue(BackendsIndex::URL . "/{$name}"),
|
||||
],
|
||||
];
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, $response);
|
||||
return api_response(HTTP_STATUS::HTTP_OK, $list);
|
||||
}
|
||||
}
|
||||
171
src/API/Backend/Option.php
Normal file
171
src/API/Backend/Option.php
Normal file
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\API\Backend;
|
||||
|
||||
use App\Libs\Attributes\Route\Delete;
|
||||
use App\Libs\Attributes\Route\Get;
|
||||
use App\Libs\Attributes\Route\Patch;
|
||||
use App\Libs\Attributes\Route\Post;
|
||||
use App\Libs\Config;
|
||||
use App\Libs\ConfigFile;
|
||||
use App\Libs\DataUtil;
|
||||
use App\Libs\HTTP_STATUS;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
|
||||
final class Option
|
||||
{
|
||||
use APITraits;
|
||||
|
||||
#[Get(Index::URL . '/{name:backend}/option/{option}[/]', name: 'backend.option')]
|
||||
public function viewOption(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
if (null === ($option = ag($args, 'option'))) {
|
||||
return api_error('Invalid value for option path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$list = ConfigFile::open(Config::get('backends_file'), 'yaml', autoCreate: true);
|
||||
|
||||
if (false === $list->has($name)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$key = $name . '.options.' . $option;
|
||||
|
||||
if (false === $list->has($key)) {
|
||||
return api_error(r("Option '{option}' not found in backend '{name}'.", [
|
||||
'option' => $option,
|
||||
'name' => $name
|
||||
]), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$value = $list->get($key);
|
||||
return api_response(HTTP_STATUS::HTTP_OK, [
|
||||
'key' => $option,
|
||||
'value' => $value,
|
||||
'type' => get_debug_type($value),
|
||||
]);
|
||||
}
|
||||
|
||||
#[Post(Index::URL . '/{name:backend}/option[/]', name: 'backend.option.add')]
|
||||
public function addOption(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$list = ConfigFile::open(Config::get('backends_file'), 'yaml', autoCreate: true);
|
||||
|
||||
if (false === $list->has($name)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$data = DataUtil::fromRequest($request);
|
||||
|
||||
if (null === ($option = $data->get('key'))) {
|
||||
return api_error('Invalid value for key.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$spec = require __DIR__ . '/../../../config/backend.spec.php';
|
||||
$found = false;
|
||||
|
||||
foreach ($spec as $supportedKey => $_) {
|
||||
if (str_ends_with($supportedKey, 'options.' . $option)) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (false === $found) {
|
||||
return api_error(r("Option '{key}' is not supported.", ['key' => $option]), HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$value = $data->get('value');
|
||||
|
||||
$list->set($name . '.options.' . $option, $value)->persist();
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, [
|
||||
'key' => $option,
|
||||
'value' => $value,
|
||||
'type' => get_debug_type($value),
|
||||
]);
|
||||
}
|
||||
|
||||
#[Patch(Index::URL . '/{name:backend}/option/{option}[/]', name: 'backend.option.update')]
|
||||
public function updateOption(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
if (null === ($option = ag($args, 'option'))) {
|
||||
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 === $list->has($name)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$key = $name . '.options.' . $option;
|
||||
if (false === $list->has($key)) {
|
||||
return api_error(r("Option '{option}' not found in backend '{name}'.", [
|
||||
'option' => $option,
|
||||
'name' => $name
|
||||
]), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$data = DataUtil::fromRequest($request);
|
||||
|
||||
if (null === ($value = $data->get('value'))) {
|
||||
return api_error(r("No value was provided for '{key}'.", [
|
||||
'key' => $key,
|
||||
]), HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$list->set($key, $value)->persist();
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, [
|
||||
'key' => $option,
|
||||
'value' => $value,
|
||||
'type' => get_debug_type($value),
|
||||
]);
|
||||
}
|
||||
|
||||
#[Delete(Index::URL . '/{name:backend}/option/{option}[/]', name: 'backend.option.delete')]
|
||||
public function deleteOption(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
if (null === ($option = ag($args, 'option'))) {
|
||||
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 === $list->has($name)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$key = $name . '.options.' . $option;
|
||||
|
||||
$value = $list->get($key);
|
||||
$list->delete($key)->persist();
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, [
|
||||
'key' => $option,
|
||||
'value' => $value,
|
||||
'type' => get_debug_type($value),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\API\Backend;
|
||||
|
||||
use App\Libs\Attributes\Route\Patch;
|
||||
use App\Libs\Config;
|
||||
use App\Libs\ConfigFile;
|
||||
use App\Libs\HTTP_STATUS;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use JsonException;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
|
||||
final class PartialUpdate
|
||||
{
|
||||
use APITraits;
|
||||
|
||||
#[Patch(Index::URL . '/{name:backend}[/]', name: 'backends.view')]
|
||||
public function __invoke(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$list = ConfigFile::open(Config::get('backends_file'), 'yaml', autoCreate: true);
|
||||
|
||||
if (false === $list->has($name)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
try {
|
||||
$data = json_decode((string)$request->getBody(), true, flags: JSON_THROW_ON_ERROR);
|
||||
} catch (JsonException $e) {
|
||||
return api_error(r('Invalid JSON data. {error}', ['error' => $e->getMessage()]),
|
||||
HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
foreach ($data as $update) {
|
||||
if (!ag_exists($update, 'key')) {
|
||||
return api_error('No key to update was present.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$list->set($name . '.' . ag($update, 'key'), ag($update, 'value'));
|
||||
}
|
||||
|
||||
$apiUrl = $request->getUri()->withHost('')->withPort(0)->withScheme('');
|
||||
|
||||
$list->persist();
|
||||
|
||||
$backend = $this->getBackends(name: $name);
|
||||
|
||||
if (empty($backend)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||
}
|
||||
$backend = array_pop($backend);
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, [
|
||||
'backend' => array_filter(
|
||||
$backend,
|
||||
fn($key) => false === in_array($key, ['options', 'webhook'], true),
|
||||
ARRAY_FILTER_USE_KEY
|
||||
),
|
||||
'links' => [
|
||||
'self' => (string)$apiUrl,
|
||||
'list' => (string)$apiUrl->withPath(parseConfigValue(Index::URL)),
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -17,8 +17,8 @@ final class Search
|
||||
{
|
||||
use APITraits;
|
||||
|
||||
#[Get(Index::URL . '/{name:backend}/search[/[{id}[/]]]', name: 'backends.backend.search.id')]
|
||||
public function searchById(iRequest $request, array $args = []): iResponse
|
||||
#[Get(Index::URL . '/{name:backend}/search[/[{id}[/]]]', name: 'backend.search')]
|
||||
public function __invoke(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
@@ -55,14 +55,8 @@ final class Search
|
||||
]), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$apiUrl = $request->getUri()->withHost('')->withPort(0)->withScheme('');
|
||||
$response = [
|
||||
'results' => $id ? [$data] : $data,
|
||||
'links' => [
|
||||
'self' => (string)$apiUrl,
|
||||
'backend' => (string)$apiUrl->withPath(parseConfigValue(Index::URL . '/' . $name)),
|
||||
'list' => (string)$apiUrl->withPath(parseConfigValue(Index::URL)),
|
||||
],
|
||||
'options' => [
|
||||
'raw' => (bool)$params->get('raw', false),
|
||||
],
|
||||
|
||||
@@ -18,11 +18,11 @@ final class Sessions
|
||||
{
|
||||
use APITraits;
|
||||
|
||||
#[Get(Index::URL . '/{name:backend}/sessions[/]', name: 'backends.backend.sessions')]
|
||||
public function backendsView(iRequest $request, array $args = []): iResponse
|
||||
#[Get(Index::URL . '/{name:backend}/sessions[/]', name: 'backend.sessions')]
|
||||
public function __invoke(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for id path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
return api_error('Invalid value for name path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -40,20 +40,9 @@ final class Sessions
|
||||
|
||||
try {
|
||||
$sessions = $client->getSessions($opts);
|
||||
return api_response(HTTP_STATUS::HTTP_OK, ag($sessions, 'sessions', []));
|
||||
} catch (Throwable $e) {
|
||||
return api_error($e->getMessage(), HTTP_STATUS::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
$apiUrl = $request->getUri()->withHost('')->withPort(0)->withScheme('');
|
||||
|
||||
$response = [
|
||||
'sessions' => ag($sessions, 'sessions', []),
|
||||
'links' => [
|
||||
'self' => (string)$apiUrl,
|
||||
'list' => (string)$apiUrl->withPath(parseConfigValue(Index::URL)),
|
||||
],
|
||||
];
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, $response);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\API\Backend\Library;
|
||||
namespace App\API\Backend;
|
||||
|
||||
use App\API\Backend\Index as BackendsIndex;
|
||||
use App\API\Backend\Index as backendIndex;
|
||||
use App\Libs\Attributes\Route\Get;
|
||||
use App\Libs\DataUtil;
|
||||
use App\Libs\Exceptions\RuntimeException;
|
||||
@@ -18,11 +18,11 @@ final class Unmatched
|
||||
{
|
||||
use APITraits;
|
||||
|
||||
#[Get(BackendsIndex::URL . '/{name:backend}/unmatched[/[{id}[/]]]', name: 'backends.library.unmatched')]
|
||||
public function listLibraries(iRequest $request, array $args = []): iResponse
|
||||
#[Get(backendIndex::URL . '/{name:backend}/unmatched[/[{id}[/]]]', name: 'backend.unmatched')]
|
||||
public function __invoke(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('No backend was given.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
return api_error('Invalid value for name path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$params = DataUtil::fromArray($request->getQueryParams());
|
||||
@@ -63,14 +63,6 @@ final class Unmatched
|
||||
}
|
||||
}
|
||||
|
||||
$response = [
|
||||
'items' => $list,
|
||||
'links' => [
|
||||
'self' => (string)$request->getUri()->withHost('')->withPort(0)->withScheme(''),
|
||||
'backend' => (string)parseConfigValue(BackendsIndex::URL . "/{$name}"),
|
||||
],
|
||||
];
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, $response);
|
||||
return api_response(HTTP_STATUS::HTTP_OK, $list);
|
||||
}
|
||||
}
|
||||
144
src/API/Backend/Update.php
Normal file
144
src/API/Backend/Update.php
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\API\Backend;
|
||||
|
||||
use App\Backends\Common\ClientInterface as iClient;
|
||||
use App\Libs\Attributes\Route\Patch;
|
||||
use App\Libs\Attributes\Route\Put;
|
||||
use App\Libs\Config;
|
||||
use App\Libs\ConfigFile;
|
||||
use App\Libs\DataUtil;
|
||||
use App\Libs\HTTP_STATUS;
|
||||
use App\Libs\Options;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use JsonException;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
|
||||
final class Update
|
||||
{
|
||||
use APITraits;
|
||||
|
||||
private ConfigFile $backendFile;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->backendFile = ConfigFile::open(Config::get('backends_file'), 'yaml', autoCreate: true);
|
||||
}
|
||||
|
||||
#[Put(Index::URL . '/{name:backend}[/]', name: 'backend.update')]
|
||||
public function update(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
if (false === $this->backendFile->has($name)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$this->backendFile->set(
|
||||
$name,
|
||||
$this->fromRequest($this->backendFile->get($name), $request, $this->getClient($name))
|
||||
)->persist();
|
||||
|
||||
$backend = $this->getBackends(name: $name);
|
||||
|
||||
if (empty($backend)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$backend = array_pop($backend);
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, $backend);
|
||||
}
|
||||
|
||||
#[Patch(Index::URL . '/{name:backend}[/]', name: 'backend.patch')]
|
||||
public function patchUpdate(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
if (false === $this->backendFile->has($name)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
try {
|
||||
$data = json_decode((string)$request->getBody(), true, flags: JSON_THROW_ON_ERROR);
|
||||
} catch (JsonException $e) {
|
||||
return api_error(r('Invalid JSON data. {error}', ['error' => $e->getMessage()]),
|
||||
HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$spec = require __DIR__ . '/../../../config/backend.spec.php';
|
||||
|
||||
foreach ($data as $update) {
|
||||
$key = ag($update, 'key');
|
||||
$value = ag($update, 'value');
|
||||
|
||||
if (null === $key) {
|
||||
return api_error('No key to update was present.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
if (false === in_array($key, $spec, true)) {
|
||||
return api_error(r('Invalid key to update: {key}', ['key' => $key]), HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$this->backendFile->set("{$name}.{$key}", $value);
|
||||
}
|
||||
|
||||
$this->backendFile->persist();
|
||||
|
||||
$backend = $this->getBackends(name: $name);
|
||||
|
||||
if (empty($backend)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$backend = array_pop($backend);
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, $backend);
|
||||
}
|
||||
|
||||
private function fromRequest(array $config, iRequest $request, iClient $client): array
|
||||
{
|
||||
$data = DataUtil::fromArray($request->getParsedBody());
|
||||
|
||||
$newData = [
|
||||
'url' => $data->get('url'),
|
||||
'token' => $data->get('token'),
|
||||
'user' => $data->get('user'),
|
||||
'uuid' => $data->get('uuid'),
|
||||
'export' => [
|
||||
'enabled' => (bool)$data->get('export.enabled', false),
|
||||
],
|
||||
'import' => [
|
||||
'enabled' => (bool)$data->get('import.enabled', false),
|
||||
],
|
||||
'webhook' => [
|
||||
'match' => [
|
||||
'user' => (bool)$data->get('webhook.match.user'),
|
||||
'uuid' => (bool)$data->get('webhook.match.uuid'),
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$optionals = [
|
||||
Options::DUMP_PAYLOAD => 'bool',
|
||||
Options::LIBRARY_SEGMENT => 'int',
|
||||
Options::IGNORE => 'string',
|
||||
];
|
||||
|
||||
foreach ($optionals as $key => $type) {
|
||||
if (null !== ($value = $data->get('options.' . $key))) {
|
||||
settype($value, $type);
|
||||
$newData = ag_set($newData, "options.{$key}", $value);
|
||||
}
|
||||
}
|
||||
|
||||
return deepArrayMerge([$config, $client->fromRequest($newData, $request)]);
|
||||
}
|
||||
}
|
||||
@@ -18,19 +18,13 @@ final class Users
|
||||
{
|
||||
use APITraits;
|
||||
|
||||
#[Get(Index::URL . '/{name:backend}/users[/]', name: 'backends.backend.users')]
|
||||
public function backendsView(iRequest $request, array $args = []): iResponse
|
||||
#[Get(Index::URL . '/{name:backend}/users[/]', name: 'backend.users')]
|
||||
public function __invoke(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for id path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
try {
|
||||
$client = $this->getClient(name: $name);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$opts = [];
|
||||
$params = DataUtil::fromRequest($request, true);
|
||||
|
||||
@@ -43,21 +37,11 @@ final class Users
|
||||
}
|
||||
|
||||
try {
|
||||
$users = $client->getUsersList($opts);
|
||||
return api_response(HTTP_STATUS::HTTP_OK, $this->getClient(name: $name)->getUsersList($opts));
|
||||
} catch (InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||
} catch (Throwable $e) {
|
||||
return api_error($e->getMessage(), HTTP_STATUS::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
$apiUrl = $request->getUri()->withHost('')->withPort(0)->withScheme('');
|
||||
|
||||
$response = [
|
||||
'users' => $users,
|
||||
'links' => [
|
||||
'self' => (string)$apiUrl,
|
||||
'list' => (string)$apiUrl->withPath(parseConfigValue(Index::URL)),
|
||||
],
|
||||
];
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, $response);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,8 @@ declare(strict_types=1);
|
||||
namespace App\API\Backend;
|
||||
|
||||
use App\Libs\Attributes\Route\Get;
|
||||
use App\Libs\DataUtil;
|
||||
use App\Libs\Exceptions\InvalidArgumentException;
|
||||
use App\Libs\HTTP_STATUS;
|
||||
use App\Libs\Options;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
@@ -18,42 +16,19 @@ final class Version
|
||||
{
|
||||
use APITraits;
|
||||
|
||||
#[Get(Index::URL . '/{name:backend}/version[/]', name: 'backends.backend.info')]
|
||||
public function backendsView(iRequest $request, array $args = []): iResponse
|
||||
#[Get(Index::URL . '/{name:backend}/version[/]', name: 'backend.version')]
|
||||
public function __invoke(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for id path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
try {
|
||||
$client = $this->getClient(name: $name);
|
||||
return api_response(HTTP_STATUS::HTTP_OK, ['version' => $this->getClient(name: $name)->getVersion()]);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$opts = [];
|
||||
$params = DataUtil::fromRequest($request, true);
|
||||
|
||||
if (true === (bool)$params->get('raw', false)) {
|
||||
$opts[Options::RAW_RESPONSE] = true;
|
||||
}
|
||||
|
||||
try {
|
||||
$version = $client->getVersion($opts);
|
||||
} catch (Throwable $e) {
|
||||
return api_error($e->getMessage(), HTTP_STATUS::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
$apiUrl = $request->getUri()->withHost('')->withPort(0)->withScheme('');
|
||||
|
||||
$response = [
|
||||
'version' => $version,
|
||||
'links' => [
|
||||
'self' => (string)$apiUrl,
|
||||
'list' => (string)$apiUrl->withPath(parseConfigValue(Index::URL)),
|
||||
],
|
||||
];
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, $response);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,20 +27,20 @@ final class Webhooks
|
||||
{
|
||||
use APITraits;
|
||||
|
||||
private iLogger $accessLog;
|
||||
private iLogger $logfile;
|
||||
|
||||
public function __construct(private iCache $cache)
|
||||
{
|
||||
$this->accessLog = new Logger(name: 'http', processors: [new LogMessageProcessor()]);
|
||||
$this->logfile = new Logger(name: 'webhook', processors: [new LogMessageProcessor()]);
|
||||
|
||||
$level = Config::get('webhook.debug') ? Level::Debug : Level::Info;
|
||||
|
||||
if (null !== ($logfile = Config::get('webhook.logfile'))) {
|
||||
$this->accessLog = $this->accessLog->pushHandler(new StreamHandler($logfile, $level, true));
|
||||
$this->logfile = $this->logfile->pushHandler(new StreamHandler($logfile, $level, true));
|
||||
}
|
||||
|
||||
if (true === inContainer()) {
|
||||
$this->accessLog->pushHandler(new StreamHandler('php://stderr', $level, true));
|
||||
$this->logfile->pushHandler(new StreamHandler('php://stderr', $level, true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,13 +53,27 @@ final class Webhooks
|
||||
* @return iResponse The response object.
|
||||
* @throws InvalidArgumentException if cache key is invalid.
|
||||
*/
|
||||
#[Route(['POST', 'PUT'], Index::URL . '/{name:backend}/webhook[/]', name: 'webhooks.receive')]
|
||||
#[Route(['POST', 'PUT'], Index::URL . '/{name:backend}/webhook[/]', name: 'backend.webhook')]
|
||||
public function __invoke(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for id path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
return $this->process($name, $request)->withHeader('X-Log-Response', '0');
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the incoming webhook request.
|
||||
*
|
||||
* @param string $name The backend name.
|
||||
* @param iRequest $request The incoming request object.
|
||||
*
|
||||
* @return iResponse The response object.
|
||||
* @throws InvalidArgumentException if cache key is invalid.
|
||||
*/
|
||||
private function process(string $name, iRequest $request): iResponse
|
||||
{
|
||||
try {
|
||||
$backend = $this->getBackends(name: $name);
|
||||
if (empty($backend)) {
|
||||
@@ -84,7 +98,7 @@ final class Webhooks
|
||||
if (null === ($requestUser = ag($attr, 'user.id'))) {
|
||||
$message = "Request payload didn't contain a user id. Backend requires a user check.";
|
||||
$this->write($request, Level::Info, $message);
|
||||
return api_error($message, HTTP_STATUS::HTTP_BAD_REQUEST)->withHeader('X-Log-Response', '0');
|
||||
return api_error($message, HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
if (false === hash_equals((string)$userId, (string)$requestUser)) {
|
||||
@@ -93,7 +107,7 @@ final class Webhooks
|
||||
'config_user' => $userId,
|
||||
]);
|
||||
$this->write($request, Level::Info, $message);
|
||||
return api_error($message, HTTP_STATUS::HTTP_BAD_REQUEST)->withHeader('X-Log-Response', '0');
|
||||
return api_error($message, HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +115,7 @@ final class Webhooks
|
||||
if (null === ($requestBackendId = ag($attr, 'backend.id'))) {
|
||||
$message = "Request payload didn't contain the backend unique id.";
|
||||
$this->write($request, Level::Info, $message);
|
||||
return api_error($message, HTTP_STATUS::HTTP_BAD_REQUEST)->withHeader('X-Log-Response', '0');
|
||||
return api_error($message, HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
if (false === hash_equals((string)$uuid, (string)$requestBackendId)) {
|
||||
@@ -110,7 +124,7 @@ final class Webhooks
|
||||
'config_uid' => $uuid,
|
||||
]);
|
||||
$this->write($request, Level::Info, $message);
|
||||
return api_error($message, HTTP_STATUS::HTTP_BAD_REQUEST)->withHeader('X-Log-Response', '0');
|
||||
return api_error($message, HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +142,7 @@ final class Webhooks
|
||||
'backend' => $client->getName(),
|
||||
]), forceContext: true);
|
||||
|
||||
return $response->withHeader('X-Log-Response', '0');
|
||||
return $response;
|
||||
}
|
||||
|
||||
$entity = $client->parseWebhook($request);
|
||||
@@ -151,7 +165,7 @@ final class Webhooks
|
||||
]
|
||||
);
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_NOT_MODIFIED)->withHeader('X-Log-Response', '0');
|
||||
return api_response(HTTP_STATUS::HTTP_NOT_MODIFIED);
|
||||
}
|
||||
|
||||
if ((0 === (int)$entity->episode || null === $entity->season) && $entity->isEpisode()) {
|
||||
@@ -170,7 +184,7 @@ final class Webhooks
|
||||
]
|
||||
);
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_NOT_MODIFIED)->withHeader('X-Log-Response', '0');
|
||||
return api_response(HTTP_STATUS::HTTP_NOT_MODIFIED);
|
||||
}
|
||||
|
||||
$items = $this->cache->get('requests', []);
|
||||
@@ -211,7 +225,7 @@ final class Webhooks
|
||||
]
|
||||
);
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK)->withHeader('X-Log-Response', '0');
|
||||
return api_response(HTTP_STATUS::HTTP_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -257,9 +271,9 @@ final class Webhooks
|
||||
}
|
||||
|
||||
if (true === (Config::get('logs.context') || $forceContext)) {
|
||||
$this->accessLog->log($level, $message, $context);
|
||||
$this->logfile->log($level, $message, $context);
|
||||
} else {
|
||||
$this->accessLog->log($level, r($message, $context));
|
||||
$this->logfile->log($level, r($message, $context));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ declare(strict_types=1);
|
||||
namespace App\API\Backends;
|
||||
|
||||
use App\Backends\Common\Cache as BackendCache;
|
||||
use App\Backends\Common\ClientInterface;
|
||||
use App\Backends\Common\ClientInterface as iClient;
|
||||
use App\Backends\Common\Context;
|
||||
use App\Libs\Attributes\Route\Post;
|
||||
use App\Libs\Config;
|
||||
@@ -80,7 +80,7 @@ final class Add
|
||||
}
|
||||
|
||||
$instance = Container::getNew($class);
|
||||
assert($instance instanceof ClientInterface, new RuntimeException('Invalid client class.'));
|
||||
assert($instance instanceof iClient, new RuntimeException('Invalid client class.'));
|
||||
|
||||
try {
|
||||
$config = DataUtil::fromArray($this->fromRequest($type, $request, $instance));
|
||||
@@ -118,15 +118,10 @@ final class Add
|
||||
$data = $this->getBackends(name: $name);
|
||||
$data = array_pop($data);
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_CREATED, [
|
||||
...$data,
|
||||
'links' => [
|
||||
'self' => parseConfigValue(Index::URL) . '/' . $name,
|
||||
],
|
||||
]);
|
||||
return api_response(HTTP_STATUS::HTTP_CREATED, $data);
|
||||
}
|
||||
|
||||
private function fromRequest(string $type, iRequest $request, ClientInterface|null $client = null): array
|
||||
private function fromRequest(string $type, iRequest $request, iClient $client): array
|
||||
{
|
||||
$data = DataUtil::fromArray($request->getParsedBody());
|
||||
|
||||
@@ -162,16 +157,11 @@ final class Add
|
||||
|
||||
foreach ($optionals as $key => $type) {
|
||||
if (null !== ($value = $data->get('options.' . $key))) {
|
||||
$val = $data->get($value, $type);
|
||||
settype($val, $type);
|
||||
$config = ag_set($config, "options.{$key}", $val);
|
||||
settype($value, $type);
|
||||
$config = ag_set($config, "options.{$key}", $value);
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $client) {
|
||||
$config = $client->fromRequest($config, $request);
|
||||
}
|
||||
|
||||
return $config;
|
||||
return $client->fromRequest($config, $request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,36 +23,19 @@ final class Index
|
||||
'options.' . Options::ADMIN_TOKEN
|
||||
];
|
||||
|
||||
#[Get(self::URL . '[/]', name: 'backends.index')]
|
||||
#[Get(self::URL . '[/]', name: 'backends')]
|
||||
public function __invoke(iRequest $request): iResponse
|
||||
{
|
||||
$apiUrl = $request->getUri()->withHost('')->withPort(0)->withScheme('');
|
||||
$urlPath = $request->getUri()->getPath();
|
||||
|
||||
$response = [
|
||||
'backends' => [],
|
||||
'links' => [
|
||||
'self' => (string)$apiUrl,
|
||||
],
|
||||
];
|
||||
$list = [];
|
||||
|
||||
foreach ($this->getBackends() as $backend) {
|
||||
$backend = array_filter(
|
||||
$list[] = array_filter(
|
||||
$backend,
|
||||
fn($key) => false === in_array($key, ['options', 'webhook'], true),
|
||||
ARRAY_FILTER_USE_KEY
|
||||
);
|
||||
|
||||
$backend['links'] = [
|
||||
'self' => (string)$apiUrl->withPath(
|
||||
parseConfigValue(\App\API\Backend\Index::URL) . '/' . $backend['name']
|
||||
),
|
||||
];
|
||||
|
||||
$response['backends'][] = $backend;
|
||||
}
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, $response);
|
||||
return api_response(HTTP_STATUS::HTTP_OK, $list);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
38
src/API/Backends/UUid.php
Normal file
38
src/API/Backends/UUid.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\API\Backends;
|
||||
|
||||
use App\Libs\Attributes\Route\Route;
|
||||
use App\Libs\DataUtil;
|
||||
use App\Libs\Exceptions\InvalidArgumentException;
|
||||
use App\Libs\HTTP_STATUS;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
|
||||
final class UUid
|
||||
{
|
||||
use APITraits;
|
||||
|
||||
#[Route(['GET', 'POST'], Index::URL . '/uuid/{type}[/]', name: 'backends.get.unique_id')]
|
||||
public function __invoke(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($type = ag($args, 'type'))) {
|
||||
return api_error('Invalid value for type path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
try {
|
||||
$client = $this->getBasicClient($type, DataUtil::fromRequest($request, true));
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, [
|
||||
'identifier' => $client->getIdentifier(true)
|
||||
]);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
} catch (\Throwable $e) {
|
||||
return api_error($e->getMessage(), HTTP_STATUS::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
47
src/API/Backends/Users.php
Normal file
47
src/API/Backends/Users.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\API\Backends;
|
||||
|
||||
use App\Libs\Attributes\Route\Route;
|
||||
use App\Libs\DataUtil;
|
||||
use App\Libs\Exceptions\InvalidArgumentException;
|
||||
use App\Libs\HTTP_STATUS;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
use Throwable;
|
||||
|
||||
final class Users
|
||||
{
|
||||
use APITraits;
|
||||
|
||||
#[Route(['GET', 'POST'], Index::URL . '/users/{type}[/]', name: 'backends.get.users')]
|
||||
public function __invoke(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($type = ag($args, 'type'))) {
|
||||
return api_error('Invalid value for type path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
try {
|
||||
$client = $this->getBasicClient($type, DataUtil::fromRequest($request, true));
|
||||
} catch (InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
try {
|
||||
$users = [];
|
||||
foreach ($client->getUsersList() as $user) {
|
||||
$users[] = [
|
||||
'id' => $user['id'],
|
||||
'name' => $user['name']
|
||||
];
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
return api_error($e->getMessage(), HTTP_STATUS::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, $users);
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ final class Index
|
||||
$this->pdo = $this->db->getPDO();
|
||||
}
|
||||
|
||||
#[Get(self::URL . '[/]', name: 'history.index')]
|
||||
#[Get(self::URL . '[/]', name: 'history')]
|
||||
public function historyIndex(iRequest $request): iResponse
|
||||
{
|
||||
$es = fn(string $val) => $this->db->identifier($val);
|
||||
@@ -334,22 +334,12 @@ final class Index
|
||||
return api_error('Not found', HTTP_STATUS::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$apiUrl = $request->getUri()->withHost('')->withPort(0)->withScheme('');
|
||||
|
||||
$item = $item->getAll();
|
||||
|
||||
$item[iState::COLUMN_WATCHED] = $entity->isWatched();
|
||||
$item[iState::COLUMN_UPDATED] = makeDate($entity->updated);
|
||||
|
||||
$item = [
|
||||
...$item,
|
||||
'links' => [
|
||||
'self' => (string)$apiUrl,
|
||||
'list' => (string)$apiUrl->withPath(parseConfigValue(Index::URL)),
|
||||
],
|
||||
];
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, ['history' => $item]);
|
||||
return api_response(HTTP_STATUS::HTTP_OK, $item);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ final class Index
|
||||
private const int DEFAULT_LIMIT = 1000;
|
||||
private int $counter = 1;
|
||||
|
||||
#[Get(self::URL . '[/]', name: 'logs.list')]
|
||||
#[Get(self::URL . '[/]', name: 'logs')]
|
||||
public function logsList(iRequest $request): iResponse
|
||||
{
|
||||
$path = fixPath(Config::get('tmpDir') . '/logs');
|
||||
@@ -38,7 +38,6 @@ final class Index
|
||||
|
||||
foreach (glob($path . '/*.*.log') as $file) {
|
||||
preg_match('/(\w+)\.(\w+)\.log/i', basename($file), $matches);
|
||||
$url = $apiUrl->withPath(parseConfigValue(self::URL . "/" . basename($file)));
|
||||
|
||||
$builder = [
|
||||
'filename' => basename($file),
|
||||
@@ -46,23 +45,19 @@ final class Index
|
||||
'date' => $matches[2] ?? '??',
|
||||
'size' => filesize($file),
|
||||
'modified' => makeDate(filemtime($file)),
|
||||
'urls' => [
|
||||
'self' => (string)$url,
|
||||
'stream' => (string)$url->withQuery($query),
|
||||
],
|
||||
];
|
||||
|
||||
$list[] = $builder;
|
||||
}
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, ['logs' => $list]);
|
||||
return api_response(HTTP_STATUS::HTTP_OK, $list);
|
||||
}
|
||||
|
||||
#[Get(Index::URL . '/{filename}[/]', name: 'logs.view')]
|
||||
public function logView(iRequest $request, array $args = []): iResponse
|
||||
{
|
||||
if (null === ($filename = ag($args, 'filename'))) {
|
||||
return api_error('Invalid value for id path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
return api_error('Invalid value for filename path parameter.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$path = realpath(fixPath(Config::get('tmpDir') . '/logs'));
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\API\Plex;
|
||||
|
||||
use App\Backends\Plex\PlexClient;
|
||||
use App\Libs\Attributes\Route\Post;
|
||||
use App\Libs\DataUtil;
|
||||
use App\Libs\HTTP_STATUS;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface as iHttp;
|
||||
|
||||
final class Discover
|
||||
{
|
||||
public const string URL = '%{api.prefix}/plex/discover';
|
||||
|
||||
public function __construct(private iHttp $http)
|
||||
{
|
||||
}
|
||||
|
||||
#[Post(self::URL . '[/]', name: 'plex.discover')]
|
||||
public function plexDiscover(iRequest $request): iResponse
|
||||
{
|
||||
$data = DataUtil::fromArray($request->getParsedBody());
|
||||
|
||||
if (null === ($token = $data->get('token'))) {
|
||||
return api_error('No token was given.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
try {
|
||||
$list = PlexClient::discover($this->http, $token);
|
||||
} catch (\Throwable $e) {
|
||||
return api_error($e->getMessage(), HTTP_STATUS::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, ag($list, 'list', []));
|
||||
}
|
||||
}
|
||||
@@ -22,11 +22,11 @@ final class Env
|
||||
'WS_CACHE_URL'
|
||||
];
|
||||
|
||||
private EnvFile $envfile;
|
||||
private EnvFile $envFile;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->envfile = (new EnvFile(file: Config::get('path') . '/config/.env', create: true));
|
||||
$this->envFile = (new EnvFile(file: Config::get('path') . '/config/.env', create: true));
|
||||
}
|
||||
|
||||
#[Get(self::URL . '[/]', name: 'system.env')]
|
||||
@@ -35,12 +35,9 @@ final class Env
|
||||
$response = [
|
||||
'data' => [],
|
||||
'file' => Config::get('path') . '/config/.env',
|
||||
'links' => [
|
||||
'self' => (string)$request->getUri()->withHost('')->withPort(0)->withScheme(''),
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($this->envfile->getAll() as $key => $val) {
|
||||
foreach ($this->envFile->getAll() as $key => $val) {
|
||||
if (false === str_starts_with($key, 'WS_')) {
|
||||
continue;
|
||||
}
|
||||
@@ -49,9 +46,6 @@ final class Env
|
||||
'key' => $key,
|
||||
'value' => $val,
|
||||
'mask' => in_array($key, self::MASK),
|
||||
'urls' => [
|
||||
'self' => (string)$request->getUri()->withPath(parseConfigValue(self::URL . '/' . $key)),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -70,13 +64,13 @@ final class Env
|
||||
return api_error(r("Invalid key '{key}' was given.", ['key' => $key]), HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
if (false === $this->envfile->has($key)) {
|
||||
if (false === $this->envFile->has($key)) {
|
||||
return api_error(r("Key '{key}' is not set.", ['key' => $key]), HTTP_STATUS::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, [
|
||||
'key' => $key,
|
||||
'value' => $this->envfile->get($key),
|
||||
'value' => $this->envFile->get($key),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -94,7 +88,7 @@ final class Env
|
||||
}
|
||||
|
||||
if ('DELETE' === $request->getMethod()) {
|
||||
$this->envfile->remove($key);
|
||||
$this->envFile->remove($key);
|
||||
} else {
|
||||
$params = DataUtil::fromRequest($request);
|
||||
if (null === ($value = $params->get('value', null))) {
|
||||
@@ -103,14 +97,14 @@ final class Env
|
||||
]), HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$this->envfile->set($key, $value);
|
||||
$this->envFile->set($key, $value);
|
||||
}
|
||||
|
||||
$this->envfile->persist();
|
||||
$this->envFile->persist();
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, [
|
||||
'key' => $key,
|
||||
'value' => env($key, fn() => $this->envfile->get($key)),
|
||||
'value' => $this->envFile->get($key, fn() => env($key)),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,6 @@ final class Supported
|
||||
#[Get(self::URL . '[/]', name: 'system.supported')]
|
||||
public function __invoke(iRequest $request): iResponse
|
||||
{
|
||||
return api_response(HTTP_STATUS::HTTP_OK, [
|
||||
'supported' => array_keys(Config::get('supported')),
|
||||
]);
|
||||
return api_response(HTTP_STATUS::HTTP_OK, ['supported' => array_keys(Config::get('supported'))]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ use App\Commands\System\TasksCommand;
|
||||
use App\Libs\Attributes\Route\Get;
|
||||
use App\Libs\Attributes\Route\Route;
|
||||
use App\Libs\HTTP_STATUS;
|
||||
use Cron\CronExpression;
|
||||
use DateInterval;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
@@ -28,29 +29,15 @@ final class Index
|
||||
#[Get(self::URL . '[/]', name: 'tasks.index')]
|
||||
public function tasksIndex(iRequest $request): iResponse
|
||||
{
|
||||
$apiUrl = $request->getUri()->withHost('')->withPort(0)->withScheme('');
|
||||
$urlPath = rtrim($request->getUri()->getPath(), '/');
|
||||
|
||||
$queuedTasks = $this->cache->get('queued_tasks', []);
|
||||
|
||||
$response = [
|
||||
'tasks' => [],
|
||||
'queued' => $queuedTasks,
|
||||
'links' => [
|
||||
'self' => (string)$apiUrl,
|
||||
],
|
||||
];
|
||||
|
||||
foreach (TasksCommand::getTasks() as $task) {
|
||||
$task = self::formatTask($task);
|
||||
|
||||
$task['links'] = [
|
||||
'self' => (string)$apiUrl->withPath($urlPath . '/' . ag($task, 'name')),
|
||||
'queue' => (string)$apiUrl->withPath($urlPath . '/' . ag($task, 'name') . '/queue'),
|
||||
];
|
||||
|
||||
$task['queued'] = in_array(ag($task, 'name'), $queuedTasks);
|
||||
|
||||
$response['tasks'][] = $task;
|
||||
}
|
||||
|
||||
@@ -87,17 +74,9 @@ final class Index
|
||||
return api_response(HTTP_STATUS::HTTP_OK, ['queue' => $queuedTasks]);
|
||||
}
|
||||
|
||||
$apiUrl = $request->getUri()->withHost('')->withPort(0)->withScheme('')->withUserInfo('');
|
||||
$urlPath = parseConfigValue(Index::URL);
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, [
|
||||
'task' => $id,
|
||||
'is_queued' => in_array($id, $queuedTasks),
|
||||
'links' => [
|
||||
'self' => (string)$apiUrl,
|
||||
'task' => (string)$apiUrl->withPath($urlPath . '/' . $id),
|
||||
'tasks' => (string)$apiUrl->withPath($urlPath),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -108,34 +87,27 @@ final class Index
|
||||
return api_error('No id was given.', HTTP_STATUS::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$apiUrl = $request->getUri()->withHost('')->withPort(0)->withScheme('');
|
||||
|
||||
$task = TasksCommand::getTasks($id);
|
||||
|
||||
if (empty($task)) {
|
||||
return api_error('Task not found.', HTTP_STATUS::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$response = [
|
||||
...Index::formatTask($task),
|
||||
'links' => [
|
||||
'self' => (string)$apiUrl,
|
||||
'list' => (string)$apiUrl->withPath(parseConfigValue(Index::URL)),
|
||||
],
|
||||
];
|
||||
|
||||
return api_response(HTTP_STATUS::HTTP_OK, ['task' => $response]);
|
||||
return api_response(HTTP_STATUS::HTTP_OK, Index::formatTask($task));
|
||||
}
|
||||
|
||||
private function formatTask(array $task): array
|
||||
{
|
||||
$isEnabled = (bool)ag($task, 'enabled', false);
|
||||
|
||||
$timer = ag($task, 'timer');
|
||||
assert($timer instanceof CronExpression);
|
||||
|
||||
$item = [
|
||||
'name' => ag($task, 'name'),
|
||||
'description' => ag($task, 'description'),
|
||||
'enabled' => true === $isEnabled,
|
||||
'timer' => ag($task, 'timer')->getexpression(),
|
||||
'timer' => $timer->getExpression(),
|
||||
'next_run' => null,
|
||||
'prev_run' => null,
|
||||
'command' => ag($task, 'command'),
|
||||
@@ -147,8 +119,13 @@ final class Index
|
||||
}
|
||||
|
||||
if (true === $isEnabled) {
|
||||
$item['next_run'] = makeDate(ag($task, 'timer')->getNextRunDate());
|
||||
$item['prev_run'] = makeDate(ag($task, 'timer')->getPreviousRunDate());
|
||||
try {
|
||||
$item['next_run'] = makeDate($timer->getNextRunDate());
|
||||
$item['prev_run'] = makeDate($timer->getPreviousRunDate());
|
||||
} catch (\Exception) {
|
||||
$item['next_run'] = null;
|
||||
$item['prev_run'] = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $item;
|
||||
|
||||
Reference in New Issue
Block a user