Updated most of backend API endpoints to support sub users.
This commit is contained in:
@@ -10,7 +10,8 @@
|
||||
<div class="field is-grouped">
|
||||
<p class="control" v-if="backends && backends.length>0">
|
||||
<button class="button is-purple" v-tooltip.bottom="'Create sub users backends.'"
|
||||
@click="navigateTo(makeConsoleCommand('backend:create -v', true))">
|
||||
@click="navigateTo(makeConsoleCommand('backend:create -v', true))"
|
||||
:disabled="'main' !== api_user">
|
||||
<span class="icon"><i class="fas fa-users"></i></span>
|
||||
</button>
|
||||
</p>
|
||||
@@ -196,6 +197,7 @@ useHead({title: 'Backends'})
|
||||
const backends = ref([])
|
||||
const toggleForm = ref(false)
|
||||
const api_url = useStorage('api_url', '')
|
||||
const api_user = useStorage('api_user', 'main')
|
||||
const show_page_tips = useStorage('show_page_tips', true)
|
||||
const isLoading = ref(false)
|
||||
const selectedCommand = ref('')
|
||||
|
||||
@@ -8,9 +8,11 @@ use App\Libs\Attributes\Route\Post;
|
||||
use App\Libs\DataUtil;
|
||||
use App\Libs\Enums\Http\Status;
|
||||
use App\Libs\Exceptions\InvalidArgumentException;
|
||||
use App\Libs\Mappers\ExtendedImportInterface as iEImport;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface as iHttp;
|
||||
use Throwable;
|
||||
|
||||
@@ -23,13 +25,11 @@ final class AccessToken
|
||||
}
|
||||
|
||||
#[Post(Index::URL . '/{name:backend}/accesstoken[/]', name: 'backend.accesstoken')]
|
||||
public function __invoke(iRequest $request, array $args = []): iResponse
|
||||
public function __invoke(iRequest $request, string $name, iEImport $mapper, iLogger $logger): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', Status::BAD_REQUEST);
|
||||
}
|
||||
$userContext = $this->getUserContext($request, $mapper, $logger);
|
||||
|
||||
if (null === $this->getBackend(name: $name)) {
|
||||
if (null === $this->getBackend(name: $name, userContext: $userContext)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ final class AccessToken
|
||||
}
|
||||
|
||||
try {
|
||||
$client = $this->getClient(name: $name);
|
||||
$client = $this->getClient(name: $name, userContext: $userContext);
|
||||
$token = $client->getUserToken(
|
||||
userId: $id,
|
||||
username: $data->get('username', $client->getContext()->backendName . '_user'),
|
||||
|
||||
@@ -4,29 +4,28 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\API\Backend;
|
||||
|
||||
use App\Libs\Config;
|
||||
use App\Libs\ConfigFile;
|
||||
use App\Libs\Database\DBLayer;
|
||||
use App\Libs\Enums\Http\Status;
|
||||
use App\Libs\Mappers\ExtendedImportInterface as iEImport;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
|
||||
final class Delete
|
||||
{
|
||||
use APITraits;
|
||||
|
||||
#[\App\Libs\Attributes\Route\Delete(Index::URL . '/{name:backend}[/]', name: 'backend.delete')]
|
||||
public function __invoke(DBLayer $db, iRequest $request, array $args = []): iResponse
|
||||
public function __invoke(iRequest $request, string $name, iEImport $mapper, iLogger $logger): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', Status::BAD_REQUEST);
|
||||
}
|
||||
$userContext = $this->getUserContext($request, $mapper, $logger);
|
||||
|
||||
if (null === ($data = $this->getBackend(name: $name))) {
|
||||
if (null === ($data = $this->getBackend(name: $name, userContext: $userContext))) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
$db = $userContext->db->getDBLayer();
|
||||
|
||||
set_time_limit(0);
|
||||
ignore_user_abort(true);
|
||||
|
||||
@@ -53,7 +52,7 @@ final class Delete
|
||||
|
||||
$deletedRecords = $stmt->rowCount();
|
||||
|
||||
ConfigFile::open(Config::get('backends_file'), 'yaml')->delete($name)->persist();
|
||||
$userContext->config->delete($name)->persist();
|
||||
|
||||
return api_response(Status::OK, [
|
||||
'deleted' => [
|
||||
|
||||
@@ -8,10 +8,12 @@ use App\Backends\Plex\PlexClient;
|
||||
use App\Libs\Attributes\Route\Get;
|
||||
use App\Libs\Enums\Http\Status;
|
||||
use App\Libs\Exceptions\InvalidArgumentException;
|
||||
use App\Libs\Mappers\ExtendedImportInterface as iEImport;
|
||||
use App\Libs\Options;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface as iHttp;
|
||||
use Throwable;
|
||||
|
||||
@@ -19,23 +21,17 @@ 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
|
||||
public function __invoke(iRequest $request, string $name, iEImport $mapper, iLogger $logger, iHttp $http): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', Status::BAD_REQUEST);
|
||||
}
|
||||
$userContext = $this->getUserContext($request, $mapper, $logger);
|
||||
|
||||
if (null === $this->getBackend(name: $name)) {
|
||||
if (null === $this->getBackend(name: $name, userContext: $userContext)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
try {
|
||||
$client = $this->getClient(name: $name);
|
||||
$client = $this->getClient(name: $name, userContext: $userContext);
|
||||
|
||||
if (PlexClient::CLIENT_NAME !== $client->getType()) {
|
||||
return api_error('Discover is only available for Plex backends.', Status::BAD_REQUEST);
|
||||
@@ -50,7 +46,7 @@ final class Discover
|
||||
$opts[Options::ADMIN_TOKEN] = $adminToken;
|
||||
}
|
||||
|
||||
$list = $client::discover($this->http, $context->backendToken, $opts);
|
||||
$list = $client::discover($http, $context->backendToken, $opts);
|
||||
return api_response(Status::OK, ag($list, 'list', []));
|
||||
} catch (InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), Status::NOT_FOUND);
|
||||
|
||||
@@ -11,9 +11,11 @@ use App\Libs\Config;
|
||||
use App\Libs\ConfigFile;
|
||||
use App\Libs\DataUtil;
|
||||
use App\Libs\Enums\Http\Status;
|
||||
use App\Libs\Mappers\ExtendedImportInterface as iEImport;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
use Throwable;
|
||||
|
||||
final class Ignore
|
||||
@@ -22,19 +24,17 @@ final class Ignore
|
||||
|
||||
private ConfigFile $file;
|
||||
|
||||
public function __construct()
|
||||
public function __construct(private readonly iEImport $mapper, private readonly iLogger $logger)
|
||||
{
|
||||
$this->file = new ConfigFile(Config::get('path') . '/config/ignore.yaml', type: 'yaml', autoCreate: true);
|
||||
}
|
||||
|
||||
#[Get(Index::URL . '/{name:backend}/ignore[/]', name: 'backend.ignoredIds')]
|
||||
public function ignoredIds(string $name): iResponse
|
||||
public function ignoredIds(iRequest $request, string $name): iResponse
|
||||
{
|
||||
if (empty($name)) {
|
||||
return api_error('Invalid value for name path parameter.', Status::BAD_REQUEST);
|
||||
}
|
||||
$userContext = $this->getUserContext($request, $this->mapper, $this->logger);
|
||||
|
||||
if (null === $this->getBackend(name: $name)) {
|
||||
if (null === $this->getBackend(name: $name, userContext: $userContext)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -70,19 +70,11 @@ final class Ignore
|
||||
}
|
||||
|
||||
#[Delete(Index::URL . '/{name:backend}/ignore[/]', name: 'backend.ignoredIds.delete')]
|
||||
public function deleteRule(iRequest $request, array $args = []): iResponse
|
||||
public function deleteRule(iRequest $request, string $name): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', Status::BAD_REQUEST);
|
||||
}
|
||||
$userContext = $this->getUserContext($request, $this->mapper, $this->logger);
|
||||
|
||||
if (null === $this->getBackend(name: $name)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
$data = $this->getBackends(name: $name);
|
||||
|
||||
if (empty($data)) {
|
||||
if (null === $this->getBackend(name: $name, userContext: $userContext)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -93,7 +85,7 @@ final class Ignore
|
||||
}
|
||||
|
||||
try {
|
||||
checkIgnoreRule($rule);
|
||||
checkIgnoreRule($rule, userContext: $userContext);
|
||||
} catch (Throwable $e) {
|
||||
return api_error($e->getMessage(), Status::BAD_REQUEST);
|
||||
}
|
||||
@@ -108,19 +100,11 @@ final class Ignore
|
||||
}
|
||||
|
||||
#[Post(Index::URL . '/{name:backend}/ignore[/]', name: 'backend.ignoredIds.add')]
|
||||
public function addRule(iRequest $request, array $args = []): iResponse
|
||||
public function addRule(iRequest $request, string $name): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', Status::BAD_REQUEST);
|
||||
}
|
||||
$userContext = $this->getUserContext($request, $this->mapper, $this->logger);
|
||||
|
||||
if (null === $this->getBackend(name: $name)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
$data = $this->getBackends(name: $name);
|
||||
|
||||
if (empty($data)) {
|
||||
if (null === $this->getBackend(name: $name, userContext: $userContext)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -150,7 +134,7 @@ final class Ignore
|
||||
}
|
||||
|
||||
try {
|
||||
checkIgnoreRule($rule);
|
||||
checkIgnoreRule($rule, userContext: $userContext);
|
||||
$id = makeIgnoreId($rule);
|
||||
} catch (Throwable $e) {
|
||||
return api_error($e->getMessage(), Status::BAD_REQUEST);
|
||||
|
||||
@@ -6,9 +6,11 @@ namespace App\API\Backend;
|
||||
|
||||
use App\Libs\Attributes\Route\Get;
|
||||
use App\Libs\Enums\Http\Status;
|
||||
use App\Libs\Mappers\ExtendedImportInterface as iEImport;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
|
||||
final class Index
|
||||
{
|
||||
@@ -17,13 +19,11 @@ final class Index
|
||||
public const string URL = '%{api.prefix}/backend';
|
||||
|
||||
#[Get(self::URL . '/{name:backend}[/]', name: 'backend.view')]
|
||||
public function __invoke(iRequest $request, array $args = []): iResponse
|
||||
public function __invoke(iRequest $request, string $name, iEImport $mapper, iLogger $logger): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', Status::BAD_REQUEST);
|
||||
}
|
||||
$userContext = $this->getUserContext($request, $mapper, $logger);
|
||||
|
||||
if (null === ($data = $this->getBackend(name: $name))) {
|
||||
if (null === ($data = $this->getBackend(name: $name, userContext: $userContext))) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,10 +8,12 @@ use App\Libs\Attributes\Route\Get;
|
||||
use App\Libs\DataUtil;
|
||||
use App\Libs\Enums\Http\Status;
|
||||
use App\Libs\Exceptions\InvalidArgumentException;
|
||||
use App\Libs\Mappers\ExtendedImportInterface as iEImport;
|
||||
use App\Libs\Options;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
use Throwable;
|
||||
|
||||
final class Info
|
||||
@@ -19,18 +21,16 @@ final class Info
|
||||
use APITraits;
|
||||
|
||||
#[Get(Index::URL . '/{name:backend}/info[/]', name: 'backend.info')]
|
||||
public function __invoke(iRequest $request, array $args = []): iResponse
|
||||
public function __invoke(iRequest $request, string $name, iEImport $mapper, iLogger $logger): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', Status::BAD_REQUEST);
|
||||
}
|
||||
$userContext = $this->getUserContext($request, $mapper, $logger);
|
||||
|
||||
if (null === $this->getBackend(name: $name)) {
|
||||
if (null === $this->getBackend(name: $name, userContext: $userContext)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
try {
|
||||
$client = $this->getClient(name: $name);
|
||||
$client = $this->getClient(name: $name, userContext: $userContext);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -7,33 +7,35 @@ 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\Enums\Http\Status;
|
||||
use App\Libs\Exceptions\RuntimeException;
|
||||
use App\Libs\Mappers\ExtendedImportInterface as iEImport;
|
||||
use App\Libs\Options;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
use Throwable;
|
||||
|
||||
final class Library
|
||||
{
|
||||
use APITraits;
|
||||
|
||||
#[Get(BackendsIndex::URL . '/{name:backend}/library[/]', name: 'backend.library')]
|
||||
public function listLibraries(string $name): iResponse
|
||||
public function __construct(private readonly iEImport $mapper, private readonly iLogger $logger)
|
||||
{
|
||||
if (empty($name)) {
|
||||
return api_error('Invalid value for name path parameter.', Status::BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $this->getBackend(name: $name)) {
|
||||
#[Get(BackendsIndex::URL . '/{name:backend}/library[/]', name: 'backend.library')]
|
||||
public function listLibraries(iRequest $request, string $name): iResponse
|
||||
{
|
||||
$userContext = $this->getUserContext($request, $this->mapper, $this->logger);
|
||||
|
||||
if (null === $this->getBackend(name: $name, userContext: $userContext)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
try {
|
||||
$client = $this->getClient(name: $name);
|
||||
$client = $this->getClient(name: $name, userContext: $userContext);
|
||||
return api_response(Status::OK, $client->listLibraries());
|
||||
} catch (RuntimeException $e) {
|
||||
return api_error($e->getMessage(), Status::NOT_FOUND);
|
||||
@@ -43,31 +45,23 @@ final class Library
|
||||
}
|
||||
|
||||
#[Route(['POST', 'DELETE'], BackendsIndex::URL . '/{name:backend}/library/{id}[/]', name: 'backend.library.ignore')]
|
||||
public function ignoreLibrary(iRequest $request, array $args = []): iResponse
|
||||
public function ignoreLibrary(iRequest $request, string $name, string|int $id): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', Status::BAD_REQUEST);
|
||||
}
|
||||
$userContext = $this->getUserContext($request, $this->mapper, $this->logger);
|
||||
|
||||
if (null === $this->getBackend(name: $name)) {
|
||||
if (null === $this->getBackend(name: $name, userContext: $userContext)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
if (null === ($id = ag($args, 'id'))) {
|
||||
return api_error('Invalid value for id path parameter.', Status::BAD_REQUEST);
|
||||
}
|
||||
|
||||
$remove = 'DELETE' === $request->getMethod();
|
||||
|
||||
$config = ConfigFile::open(Config::get('backends_file'), 'yaml');
|
||||
|
||||
if (null === $config->get($name)) {
|
||||
if (null === $userContext->config->get($name)) {
|
||||
return api_error(r("Backend '{backend}' not found.", ['backend' => $name]), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
$ignoreIds = array_map(
|
||||
fn($v) => trim($v),
|
||||
explode(',', (string)$config->get("{$name}.options." . Options::IGNORE, ''))
|
||||
explode(',', (string)$userContext->config->get("{$name}.options." . Options::IGNORE, ''))
|
||||
);
|
||||
|
||||
$mode = !(true === $remove);
|
||||
@@ -80,7 +74,7 @@ final class Library
|
||||
|
||||
$found = false;
|
||||
|
||||
$libraries = $this->getClient(name: $name)->listLibraries();
|
||||
$libraries = $this->getClient(name: $name, userContext: $userContext)->listLibraries();
|
||||
|
||||
foreach ($libraries as &$library) {
|
||||
if ((string)ag($library, 'id') === (string)$id) {
|
||||
@@ -101,7 +95,9 @@ final class Library
|
||||
$ignoreIds = array_diff($ignoreIds, [$id]);
|
||||
}
|
||||
|
||||
$config->set("{$name}.options." . Options::IGNORE, implode(',', array_values($ignoreIds)))->persist();
|
||||
$userContext->config
|
||||
->set("{$name}.options." . Options::IGNORE, implode(',', array_values($ignoreIds)))
|
||||
->persist();
|
||||
|
||||
return api_response(Status::OK, $libraries);
|
||||
}
|
||||
|
||||
@@ -11,10 +11,12 @@ use App\Libs\DataUtil;
|
||||
use App\Libs\Entity\StateInterface as iState;
|
||||
use App\Libs\Enums\Http\Status;
|
||||
use App\Libs\Exceptions\RuntimeException;
|
||||
use App\Libs\Mappers\ExtendedImportInterface as iEImport;
|
||||
use App\Libs\Options;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
use Throwable;
|
||||
|
||||
final class Mismatched
|
||||
@@ -50,14 +52,16 @@ final class Mismatched
|
||||
'*',
|
||||
];
|
||||
|
||||
#[Get(backendIndex::URL . '/{name:backend}/mismatched[/[{id}[/]]]', name: 'backend.mismatched')]
|
||||
public function __invoke(iRequest $request, array $args = []): iResponse
|
||||
public function __construct(private readonly iEImport $mapper, private readonly iLogger $logger)
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', Status::BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $this->getBackend(name: $name)) {
|
||||
#[Get(backendIndex::URL . '/{name:backend}/mismatched[/[{id}[/]]]', name: 'backend.mismatched')]
|
||||
public function __invoke(iRequest $request, string $name, string|int|null $id = null): iResponse
|
||||
{
|
||||
$userContext = $this->getUserContext($request, $this->mapper, $this->logger);
|
||||
|
||||
if (null === $this->getBackend(name: $name, userContext: $userContext)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -88,13 +92,13 @@ final class Mismatched
|
||||
}
|
||||
|
||||
try {
|
||||
$client = $this->getClient(name: $name, config: $backendOpts);
|
||||
$client = $this->getClient(name: $name, config: $backendOpts, userContext: $userContext);
|
||||
} catch (RuntimeException $e) {
|
||||
return api_error($e->getMessage(), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
$ids = [];
|
||||
if (null !== ($id = ag($args, 'id'))) {
|
||||
if (null !== $id) {
|
||||
$ids[] = $id;
|
||||
} else {
|
||||
foreach ($client->listLibraries() as $library) {
|
||||
|
||||
@@ -5,35 +5,35 @@ declare(strict_types=1);
|
||||
namespace App\API\Backend;
|
||||
|
||||
use App\Libs\Attributes\Route\Route;
|
||||
use App\Libs\Config;
|
||||
use App\Libs\ConfigFile;
|
||||
use App\Libs\DataUtil;
|
||||
use App\Libs\Enums\Http\Status;
|
||||
use App\Libs\Exceptions\ValidationException;
|
||||
use App\Libs\Mappers\ExtendedImportInterface as iEImport;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
|
||||
final class Option
|
||||
{
|
||||
use APITraits;
|
||||
|
||||
#[Route(['GET', 'POST', 'PATCH', 'DELETE'], Index::URL . '/{name:backend}/option[/{option}[/]]')]
|
||||
public function __invoke(iRequest $request, array $args = []): iResponse
|
||||
public function __construct(private readonly iEImport $mapper, private readonly iLogger $logger)
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', Status::BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
$list = ConfigFile::open(Config::get('backends_file'), 'yaml', autoCreate: true);
|
||||
#[Route(['GET', 'POST', 'PATCH', 'DELETE'], Index::URL . '/{name:backend}/option[/{option}[/]]')]
|
||||
public function __invoke(iRequest $request, string $name, string|null $option = null): iResponse
|
||||
{
|
||||
$userContext = $this->getUserContext($request, $this->mapper, $this->logger);
|
||||
|
||||
if (false === $list->has($name)) {
|
||||
if (false === $userContext->config->has($name)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
$data = DataUtil::fromRequest($request);
|
||||
|
||||
if (null === ($option = ag($args, 'option', $data->get('key')))) {
|
||||
if (null === ($option = $option ?? $data->get('key'))) {
|
||||
return api_error('No option key was given.', Status::BAD_REQUEST);
|
||||
}
|
||||
|
||||
@@ -52,17 +52,17 @@ final class Option
|
||||
}
|
||||
|
||||
if ('GET' === $request->getMethod()) {
|
||||
if (false === $list->has($name . '.' . $option)) {
|
||||
if (false === $userContext->config->has($name . '.' . $option)) {
|
||||
return api_error(r("Option '{option}' not found in backend '{name}' config.", [
|
||||
'option' => $option,
|
||||
'name' => $name
|
||||
]), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
return $this->viewOption($spec, $list->get("{$name}.{$option}"));
|
||||
return $this->viewOption($spec, $userContext->config->get("{$name}.{$option}"));
|
||||
}
|
||||
|
||||
if ('DELETE' === $request->getMethod() && false === $list->has("{$name}.{$option}")) {
|
||||
if ('DELETE' === $request->getMethod() && false === $userContext->config->has("{$name}.{$option}")) {
|
||||
return api_error(r("Option '{option}' not found in backend '{name}' config.", [
|
||||
'option' => $option,
|
||||
'name' => $name
|
||||
@@ -70,10 +70,10 @@ final class Option
|
||||
}
|
||||
|
||||
if ('DELETE' === $request->getMethod()) {
|
||||
if (null !== ($value = $list->get($name . '.' . $option))) {
|
||||
if (null !== ($value = $userContext->config->get($name . '.' . $option))) {
|
||||
settype($value, ag($spec, 'type', 'string'));
|
||||
}
|
||||
$list->delete("{$name}.{$option}");
|
||||
$userContext->config->delete("{$name}.{$option}");
|
||||
} else {
|
||||
if (null !== ($value = $data->get('value'))) {
|
||||
if (ag($spec, 'type', 'string') === 'bool') {
|
||||
@@ -94,10 +94,10 @@ final class Option
|
||||
}
|
||||
}
|
||||
|
||||
$list->set("{$name}.{$option}", $value);
|
||||
$userContext->config->set("{$name}.{$option}", $value);
|
||||
}
|
||||
|
||||
$list->persist();
|
||||
$userContext->config->persist();
|
||||
|
||||
return api_response(Status::OK, [
|
||||
'key' => $option,
|
||||
|
||||
@@ -8,30 +8,34 @@ use App\Libs\Attributes\Route\Get;
|
||||
use App\Libs\DataUtil;
|
||||
use App\Libs\Enums\Http\Status;
|
||||
use App\Libs\Exceptions\RuntimeException;
|
||||
use App\Libs\Mappers\ExtendedImportInterface as iEImport;
|
||||
use App\Libs\Options;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
use Throwable;
|
||||
|
||||
final class Search
|
||||
{
|
||||
use APITraits;
|
||||
|
||||
#[Get(Index::URL . '/{name:backend}/search[/[{id}[/]]]', name: 'backend.search')]
|
||||
public function __invoke(iRequest $request, array $args = []): iResponse
|
||||
public function __construct(private readonly iEImport $mapper, private readonly iLogger $logger)
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', Status::BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $this->getBackend(name: $name)) {
|
||||
#[Get(Index::URL . '/{name:backend}/search[/[{id}[/]]]', name: 'backend.search')]
|
||||
public function __invoke(iRequest $request, string $name, string|int|null $id = null): iResponse
|
||||
{
|
||||
$userContext = $this->getUserContext($request, $this->mapper, $this->logger);
|
||||
|
||||
if (null === $this->getBackend(name: $name, userContext: $userContext)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
$params = DataUtil::fromRequest($request, true);
|
||||
|
||||
$id = ag($args, 'id', $params->get('id', null));
|
||||
$id = $id ?? $params->get('id') ?? null;
|
||||
$query = $params->get('q', null);
|
||||
|
||||
if (null === $id && null === $query) {
|
||||
@@ -39,7 +43,7 @@ final class Search
|
||||
}
|
||||
|
||||
try {
|
||||
$backend = $this->getClient(name: $name);
|
||||
$backend = $this->getClient(name: $name, userContext: $userContext);
|
||||
} catch (RuntimeException $e) {
|
||||
return api_error($e->getMessage(), Status::NOT_FOUND);
|
||||
}
|
||||
@@ -52,7 +56,7 @@ final class Search
|
||||
if (null !== $id) {
|
||||
$data = $backend->searchId($id, [Options::RAW_RESPONSE => $raw]);
|
||||
if (!empty($data)) {
|
||||
$item = $this->formatEntity($data);
|
||||
$item = $this->formatEntity($data, userContext: $userContext);
|
||||
if (true === $raw) {
|
||||
$item[Options::RAW_RESPONSE] = ag($data, Options::RAW_RESPONSE, []);
|
||||
}
|
||||
@@ -65,7 +69,7 @@ final class Search
|
||||
opts: [Options::RAW_RESPONSE => $raw]
|
||||
);
|
||||
foreach ($data as $entity) {
|
||||
$item = $this->formatEntity($entity);
|
||||
$item = $this->formatEntity($entity, userContext: $userContext);
|
||||
if (true === $raw) {
|
||||
$item[Options::RAW_RESPONSE] = ag($entity, Options::RAW_RESPONSE, []);
|
||||
}
|
||||
|
||||
@@ -8,10 +8,12 @@ use App\Libs\Attributes\Route\Get;
|
||||
use App\Libs\DataUtil;
|
||||
use App\Libs\Enums\Http\Status;
|
||||
use App\Libs\Exceptions\InvalidArgumentException;
|
||||
use App\Libs\Mappers\ExtendedImportInterface as iEImport;
|
||||
use App\Libs\Options;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
use Throwable;
|
||||
|
||||
final class Sessions
|
||||
@@ -19,18 +21,16 @@ final class Sessions
|
||||
use APITraits;
|
||||
|
||||
#[Get(Index::URL . '/{name:backend}/sessions[/]', name: 'backend.sessions')]
|
||||
public function __invoke(iRequest $request, array $args = []): iResponse
|
||||
public function __invoke(iRequest $request, string $name, iEImport $mapper, iLogger $logger): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', Status::BAD_REQUEST);
|
||||
}
|
||||
$userContext = $this->getUserContext($request, $mapper, $logger);
|
||||
|
||||
if (null === $this->getBackend(name: $name)) {
|
||||
if (null === $this->getBackend(name: $name, userContext: $userContext)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
try {
|
||||
$client = $this->getClient(name: $name);
|
||||
$client = $this->getClient(name: $name, userContext: $userContext);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -7,23 +7,24 @@ namespace App\API\Backend;
|
||||
use App\API\Backend\Index as backendIndex;
|
||||
use App\Libs\Attributes\Route\Delete;
|
||||
use App\Libs\Attributes\Route\Get;
|
||||
use App\Libs\Database\DatabaseInterface as iDB;
|
||||
use App\Libs\DataUtil;
|
||||
use App\Libs\Entity\StateInterface as iState;
|
||||
use App\Libs\Enums\Http\Status;
|
||||
use App\Libs\Exceptions\RuntimeException;
|
||||
use App\Libs\Mappers\ExtendedImportInterface as iEImport;
|
||||
use App\Libs\Mappers\Import\DirectMapper;
|
||||
use App\Libs\Mappers\Import\MemoryMapper;
|
||||
use App\Libs\Mappers\Import\ReadOnlyMapper;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use App\Libs\UserContext;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
use Psr\SimpleCache\CacheInterface as iCache;
|
||||
|
||||
final class Stale
|
||||
{
|
||||
use APITraits;
|
||||
|
||||
public function __construct(private readonly ReadOnlyMapper $mapper, private readonly MemoryMapper $local)
|
||||
public function __construct(private readonly iEImport $mapper, private readonly iLogger $logger)
|
||||
{
|
||||
set_time_limit(0);
|
||||
ini_set('memory_limit', '-1');
|
||||
@@ -32,8 +33,10 @@ final class Stale
|
||||
#[Get(backendIndex::URL . '/{name:backend}/stale/{id}[/]', name: 'backend.stale.list')]
|
||||
public function listContent(iRequest $request, string $name, string|int $id): iResponse
|
||||
{
|
||||
if (empty($name)) {
|
||||
return api_error('Invalid value for name path parameter.', Status::BAD_REQUEST);
|
||||
$userContext = $this->getUserContext($request, $this->mapper, $this->logger);
|
||||
|
||||
if (null === $this->getBackend(name: $name, userContext: $userContext)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
if (empty($id)) {
|
||||
@@ -44,6 +47,7 @@ final class Stale
|
||||
|
||||
try {
|
||||
$data = $this->getContent(
|
||||
userContext: $userContext,
|
||||
name: $name,
|
||||
id: $id,
|
||||
ignore: (bool)$params->get('ignore', false),
|
||||
@@ -58,15 +62,12 @@ final class Stale
|
||||
}
|
||||
|
||||
#[Delete(backendIndex::URL . '/{name:backend}/stale/{id}[/]', name: 'backend.stale.delete')]
|
||||
public function deleteContent(
|
||||
iRequest $request,
|
||||
DirectMapper $mapper,
|
||||
iDB $db,
|
||||
string $name,
|
||||
string|int $id
|
||||
): iResponse {
|
||||
if (empty($name)) {
|
||||
return api_error('Invalid value for name path parameter.', Status::BAD_REQUEST);
|
||||
public function deleteContent(iRequest $request, string $name, string|int $id, DirectMapper $mapper): iResponse
|
||||
{
|
||||
$userContext = $this->getUserContext($request, $mapper, $this->logger);
|
||||
|
||||
if (null === $this->getBackend(name: $name, userContext: $userContext)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
if (empty($id)) {
|
||||
@@ -79,14 +80,19 @@ final class Stale
|
||||
return api_error('No items to delete.', Status::BAD_REQUEST);
|
||||
}
|
||||
|
||||
$mapper->loadData();
|
||||
$userContext->mapper->loadData();
|
||||
|
||||
return api_message('Removed stale references.', Status::OK);
|
||||
}
|
||||
|
||||
private function getContent(string $name, string|int $id, bool $ignore = false, int|float $timeout = 0): array
|
||||
{
|
||||
if (null === $this->getBackend(name: $name)) {
|
||||
private function getContent(
|
||||
UserContext $userContext,
|
||||
string $name,
|
||||
string|int $id,
|
||||
bool $ignore = false,
|
||||
int|float $timeout = 0
|
||||
): array {
|
||||
if (null === $this->getBackend(name: $name, userContext: $userContext)) {
|
||||
throw new RuntimeException(r("Backend '{name}' not found.", ['name' => $name]));
|
||||
}
|
||||
|
||||
@@ -96,20 +102,23 @@ final class Stale
|
||||
$backendOpts = ag_set($backendOpts, 'client.timeout', (float)$timeout);
|
||||
}
|
||||
|
||||
$client = $this->getClient(name: $name, config: $backendOpts);
|
||||
$client = $this->getClient(name: $name, config: $backendOpts, userContext: $userContext);
|
||||
|
||||
$remote = cacheableItem(
|
||||
"remote-data-{$id}-{$name}",
|
||||
fn() => array_map(fn($item) => ag($item->getMetadata($item->via), iState::COLUMN_ID),
|
||||
$client->getLibraryContent($id))
|
||||
, ignoreCache: $ignore
|
||||
key: "remote-data-{$id}-{$name}",
|
||||
function: fn() => array_map(
|
||||
callback: fn($item) => ag($item->getMetadata($item->via), iState::COLUMN_ID),
|
||||
array: $client->getLibraryContent($id)
|
||||
),
|
||||
ignoreCache: $ignore,
|
||||
opts: [
|
||||
iCache::class => $userContext->cache
|
||||
]
|
||||
);
|
||||
|
||||
$this->local->loadData();
|
||||
|
||||
$localCount = 0;
|
||||
|
||||
foreach ($this->local->getObjects() as $entity) {
|
||||
foreach ($userContext->mapper->loadData()->getObjects() as $entity) {
|
||||
$backendData = $entity->getMetadata($name);
|
||||
if (empty($backendData)) {
|
||||
continue;
|
||||
|
||||
@@ -10,24 +10,28 @@ use App\Libs\DataUtil;
|
||||
use App\Libs\Entity\StateInterface as iState;
|
||||
use App\Libs\Enums\Http\Status;
|
||||
use App\Libs\Exceptions\RuntimeException;
|
||||
use App\Libs\Mappers\ExtendedImportInterface as iEImport;
|
||||
use App\Libs\Options;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
use Throwable;
|
||||
|
||||
final class Unmatched
|
||||
{
|
||||
use APITraits;
|
||||
|
||||
#[Get(backendIndex::URL . '/{name:backend}/unmatched[/[{id}[/]]]', name: 'backend.unmatched')]
|
||||
public function __invoke(iRequest $request, array $args = []): iResponse
|
||||
public function __construct(private readonly iEImport $mapper, private readonly iLogger $logger)
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', Status::BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $this->getBackend(name: $name)) {
|
||||
#[Get(backendIndex::URL . '/{name:backend}/unmatched[/[{id}[/]]]', name: 'backend.unmatched')]
|
||||
public function __invoke(iRequest $request, string $name, string|int|null $id = null): iResponse
|
||||
{
|
||||
$userContext = $this->getUserContext($request, $this->mapper, $this->logger);
|
||||
|
||||
if (null === $this->getBackend(name: $name, userContext: $userContext)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -44,13 +48,13 @@ final class Unmatched
|
||||
$opts[Options::RAW_RESPONSE] = true;
|
||||
|
||||
try {
|
||||
$client = $this->getClient(name: $name, config: $backendOpts);
|
||||
$client = $this->getClient(name: $name, config: $backendOpts, userContext: $userContext);
|
||||
} catch (RuntimeException $e) {
|
||||
return api_error($e->getMessage(), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
$ids = [];
|
||||
if (null !== ($id = ag($args, 'id'))) {
|
||||
if (null !== $id) {
|
||||
$ids[] = $id;
|
||||
} else {
|
||||
foreach ($client->listLibraries() as $library) {
|
||||
|
||||
@@ -9,19 +9,19 @@ use App\Backends\Common\ClientInterface as iClient;
|
||||
use App\Backends\Common\Context;
|
||||
use App\Libs\Attributes\Route\Patch;
|
||||
use App\Libs\Attributes\Route\Put;
|
||||
use App\Libs\Config;
|
||||
use App\Libs\ConfigFile;
|
||||
use App\Libs\Container;
|
||||
use App\Libs\DataUtil;
|
||||
use App\Libs\Enums\Http\Status;
|
||||
use App\Libs\Exceptions\Backends\InvalidContextException;
|
||||
use App\Libs\Exceptions\ValidationException;
|
||||
use App\Libs\Mappers\ExtendedImportInterface as iEImport;
|
||||
use App\Libs\Options;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use App\Libs\Uri;
|
||||
use JsonException;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
|
||||
final class Update
|
||||
{
|
||||
@@ -37,36 +37,31 @@ final class Update
|
||||
'export',
|
||||
];
|
||||
|
||||
private ConfigFile $backendFile;
|
||||
|
||||
public function __construct()
|
||||
public function __construct(private readonly iEImport $mapper, private readonly iLogger $logger)
|
||||
{
|
||||
$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
|
||||
public function update(iRequest $request, string $name): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', Status::BAD_REQUEST);
|
||||
}
|
||||
$userContext = $this->getUserContext($request, $this->mapper, $this->logger);
|
||||
|
||||
if (false === $this->backendFile->has($name)) {
|
||||
if (false === $userContext->config->has($name)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
try {
|
||||
$client = $this->getClient($name);
|
||||
$client = $this->getClient($name, userContext: $userContext);
|
||||
|
||||
$config = DataUtil::fromArray($this->fromRequest($this->backendFile->get($name), $request, $client));
|
||||
$config = DataUtil::fromArray($this->fromRequest($userContext->config->get($name), $request, $client));
|
||||
|
||||
$context = new Context(
|
||||
clientName: $this->backendFile->get("{$name}.type"),
|
||||
clientName: $userContext->config->get("{$name}.type"),
|
||||
backendName: $name,
|
||||
backendUrl: new Uri($config->get('url')),
|
||||
cache: Container::get(BackendCache::class),
|
||||
cache: Container::get(BackendCache::class)->with(adapter: $userContext->cache),
|
||||
backendId: $config->get('uuid', null),
|
||||
backendToken: $this->backendFile->get("{$name}.token", null),
|
||||
backendToken: $userContext->config->get("{$name}.token", null),
|
||||
backendUser: $config->get('user', null),
|
||||
options: $config->get('options', []),
|
||||
);
|
||||
@@ -75,18 +70,18 @@ final class Update
|
||||
return api_error('Context information validation failed.', Status::BAD_REQUEST);
|
||||
}
|
||||
|
||||
$this->backendFile->set($name, $config->getAll());
|
||||
$userContext->config->set($name, $config->getAll());
|
||||
|
||||
// -- sanity check.
|
||||
if (true === (bool)$this->backendFile->get("{$name}.import.enabled", false)) {
|
||||
if ($this->backendFile->has("{$name}.options." . Options::IMPORT_METADATA_ONLY)) {
|
||||
$this->backendFile->delete("{$name}.options." . Options::IMPORT_METADATA_ONLY);
|
||||
if (true === (bool)$userContext->config->get("{$name}.import.enabled", false)) {
|
||||
if ($userContext->config->has("{$name}.options." . Options::IMPORT_METADATA_ONLY)) {
|
||||
$userContext->config->delete("{$name}.options." . Options::IMPORT_METADATA_ONLY);
|
||||
}
|
||||
}
|
||||
|
||||
$this->backendFile->persist();
|
||||
$userContext->config->persist();
|
||||
|
||||
$backend = $this->getBackends(name: $name);
|
||||
$backend = $this->getBackends(name: $name, userContext: $userContext);
|
||||
|
||||
if (empty($backend)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND);
|
||||
@@ -101,21 +96,18 @@ final class Update
|
||||
}
|
||||
|
||||
#[Patch(Index::URL . '/{name:backend}[/]', name: 'backend.patch')]
|
||||
public function patchUpdate(iRequest $request, array $args = []): iResponse
|
||||
public function patchUpdate(iRequest $request, string $name): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for name path parameter.', Status::BAD_REQUEST);
|
||||
}
|
||||
$userContext = $this->getUserContext($request, $this->mapper, $this->logger);
|
||||
|
||||
if (false === $this->backendFile->has($name)) {
|
||||
if (false === $userContext->config->has($name)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::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()]),
|
||||
Status::BAD_REQUEST);
|
||||
return api_error(r('Invalid JSON data. {error}', ['error' => $e->getMessage()]), Status::BAD_REQUEST);
|
||||
}
|
||||
|
||||
$updates = [];
|
||||
@@ -154,12 +146,12 @@ final class Update
|
||||
}
|
||||
|
||||
foreach ($updates as $key => $value) {
|
||||
$this->backendFile->set($key, $value);
|
||||
$userContext->config->set($key, $value);
|
||||
}
|
||||
|
||||
$this->backendFile->persist();
|
||||
$userContext->config->persist();
|
||||
|
||||
$backend = $this->getBackends(name: $name);
|
||||
$backend = $this->getBackends(name: $name, userContext: $userContext);
|
||||
|
||||
if (empty($backend)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND);
|
||||
|
||||
@@ -8,10 +8,12 @@ use App\Libs\Attributes\Route\Get;
|
||||
use App\Libs\DataUtil;
|
||||
use App\Libs\Enums\Http\Status;
|
||||
use App\Libs\Exceptions\InvalidArgumentException;
|
||||
use App\Libs\Mappers\ExtendedImportInterface as iEImport;
|
||||
use App\Libs\Options;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
use Throwable;
|
||||
|
||||
final class Users
|
||||
@@ -19,13 +21,11 @@ final class Users
|
||||
use APITraits;
|
||||
|
||||
#[Get(Index::URL . '/{name:backend}/users[/]', name: 'backend.users')]
|
||||
public function __invoke(iRequest $request, array $args = []): iResponse
|
||||
public function __invoke(iRequest $request, string $name, iEImport $mapper, iLogger $logger): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for id path parameter.', Status::BAD_REQUEST);
|
||||
}
|
||||
$userContext = $this->getUserContext($request, $mapper, $logger);
|
||||
|
||||
if (null === $this->getBackend(name: $name)) {
|
||||
if (null === $this->getBackend(name: $name, userContext: $userContext)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -41,7 +41,10 @@ final class Users
|
||||
}
|
||||
|
||||
try {
|
||||
return api_response(Status::OK, $this->getClient(name: $name)->getUsersList($opts));
|
||||
return api_response(
|
||||
Status::OK,
|
||||
$this->getClient(name: $name, userContext: $userContext)->getUsersList($opts)
|
||||
);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), Status::NOT_FOUND);
|
||||
} catch (Throwable $e) {
|
||||
|
||||
@@ -7,9 +7,11 @@ namespace App\API\Backend;
|
||||
use App\Libs\Attributes\Route\Get;
|
||||
use App\Libs\Enums\Http\Status;
|
||||
use App\Libs\Exceptions\InvalidArgumentException;
|
||||
use App\Libs\Mappers\ExtendedImportInterface as iEImport;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
use Throwable;
|
||||
|
||||
final class Version
|
||||
@@ -17,18 +19,18 @@ final class Version
|
||||
use APITraits;
|
||||
|
||||
#[Get(Index::URL . '/{name:backend}/version[/]', name: 'backend.version')]
|
||||
public function __invoke(iRequest $request, array $args = []): iResponse
|
||||
public function __invoke(iRequest $request, string $name, iEImport $mapper, iLogger $logger): iResponse
|
||||
{
|
||||
if (null === ($name = ag($args, 'name'))) {
|
||||
return api_error('Invalid value for id path parameter.', Status::BAD_REQUEST);
|
||||
}
|
||||
$userContext = $this->getUserContext($request, $mapper, $logger);
|
||||
|
||||
if (null === $this->getBackend(name: $name)) {
|
||||
if (null === $this->getBackend(name: $name, userContext: $userContext)) {
|
||||
return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
try {
|
||||
return api_response(Status::OK, ['version' => $this->getClient(name: $name)->getVersion()]);
|
||||
return api_response(Status::OK, [
|
||||
'version' => $this->getClient(name: $name, userContext: $userContext)->getVersion()
|
||||
]);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
return api_error($e->getMessage(), Status::NOT_FOUND);
|
||||
} catch (Throwable $e) {
|
||||
|
||||
@@ -1273,11 +1273,12 @@ if (!function_exists('checkIgnoreRule')) {
|
||||
* Check if the given ignore rule is valid.
|
||||
*
|
||||
* @param string $guid The ignore rule to check.
|
||||
* @param UserContext|null $userContext (Optional) The user context.
|
||||
*
|
||||
* @return bool True if the ignore rule is valid, false otherwise.
|
||||
* @throws RuntimeException Throws an exception if the ignore rule is invalid.
|
||||
*/
|
||||
function checkIgnoreRule(string $guid): bool
|
||||
function checkIgnoreRule(string $guid, UserContext|null $userContext = null): bool
|
||||
{
|
||||
$urlParts = parse_url($guid);
|
||||
|
||||
@@ -1319,7 +1320,11 @@ if (!function_exists('checkIgnoreRule')) {
|
||||
throw new RuntimeException('No backend was given.');
|
||||
}
|
||||
|
||||
$backends = array_keys(Config::get('servers', []));
|
||||
if (null !== $userContext) {
|
||||
$backends = array_keys($userContext->config->getAll());
|
||||
} else {
|
||||
$backends = array_keys(Config::get('servers', []));
|
||||
}
|
||||
|
||||
if (false === in_array($backend, $backends)) {
|
||||
throw new RuntimeException(r("Invalid backend name '{backend}' was given. Expected values are '{list}'.", [
|
||||
@@ -1725,11 +1730,13 @@ if (!function_exists('isTaskWorkerRunning')) {
|
||||
}
|
||||
|
||||
switch (PHP_OS) {
|
||||
case 'Linux': {
|
||||
case 'Linux':
|
||||
{
|
||||
$status = file_exists(r('/proc/{pid}/status', ['pid' => $pid]));
|
||||
}
|
||||
break;
|
||||
case 'WINNT': {
|
||||
case 'WINNT':
|
||||
{
|
||||
// -- Windows does not have a /proc directory so we need different way to get the status.
|
||||
@exec("tasklist /FI \"PID eq {$pid}\" 2>NUL", $output);
|
||||
// -- windows doesn't return 0 if the process is not found. we need to parse the output.
|
||||
|
||||
Reference in New Issue
Block a user