each user get their own ignore.yaml file now.
This commit is contained in:
4
FAQ.md
4
FAQ.md
@@ -1089,12 +1089,12 @@ the event log.
|
||||
|
||||
### API/WebUI endpoints that supports sub users.
|
||||
|
||||
These endpoints sub users via `?user=username` query parameter, or via `X-User` header.
|
||||
These endpoints supports sub-users via `?user=username` query parameter, or via `X-User` header.
|
||||
|
||||
* `/v1/api/backend/*`.
|
||||
* `/v1/api/system/parity`.
|
||||
* `/v1/api/system/parity`.
|
||||
* `/v1/api/ignore`.
|
||||
* `/v1/api/ignore/*`.
|
||||
* `/v1/api/history/*`.
|
||||
|
||||
### CLI commands that supports sub users.
|
||||
|
||||
@@ -4,43 +4,50 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\API\Ignore;
|
||||
|
||||
use App\Libs\Attributes\DI\Inject;
|
||||
use App\Libs\Attributes\Route\Delete;
|
||||
use App\Libs\Attributes\Route\Get;
|
||||
use App\Libs\Attributes\Route\Post;
|
||||
use App\Libs\Config;
|
||||
use App\Libs\ConfigFile;
|
||||
use App\Libs\Container;
|
||||
use App\Libs\Database\DBLayer;
|
||||
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\Import\DirectMapper;
|
||||
use App\Libs\Mappers\ImportInterface as iImport;
|
||||
use App\Libs\Traits\APITraits;
|
||||
use App\Libs\UserContext;
|
||||
use PDO;
|
||||
use Psr\Http\Message\ResponseInterface as iResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
use Psr\Http\Message\UriInterface as iUri;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
|
||||
final class Index
|
||||
{
|
||||
use APITraits;
|
||||
|
||||
public const string URL = '%{api.prefix}/ignore';
|
||||
|
||||
private array $cache = [];
|
||||
|
||||
private ConfigFile $config;
|
||||
|
||||
public function __construct(private readonly DBLayer $db)
|
||||
{
|
||||
$this->config = ConfigFile::open(
|
||||
file: Config::get('path') . '/config/ignore.yaml',
|
||||
type: 'yaml',
|
||||
autoCreate: true,
|
||||
autoBackup: false
|
||||
);
|
||||
public function __construct(
|
||||
#[Inject(DirectMapper::class)]
|
||||
private readonly iImport $mapper,
|
||||
private readonly iLogger $logger
|
||||
) {
|
||||
}
|
||||
|
||||
#[Get(self::URL . '[/]', name: 'ignore')]
|
||||
public function __invoke(iRequest $request): iResponse
|
||||
{
|
||||
try {
|
||||
$userContext = $this->getUserContext($request, $this->mapper, $this->logger);
|
||||
} catch (RuntimeException $e) {
|
||||
return api_error($e->getMessage(), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
$params = DataUtil::fromArray($request->getQueryParams());
|
||||
|
||||
$type = $params->get('type');
|
||||
@@ -50,8 +57,8 @@ final class Index
|
||||
|
||||
$response = [];
|
||||
|
||||
foreach ($this->config->getAll() as $guid => $date) {
|
||||
$item = $this->ruleAsArray($guid, $date);
|
||||
foreach ($this->getConfigFile(userContext: $userContext)->getAll() as $guid => $date) {
|
||||
$item = $this->ruleAsArray(userContext: $userContext, guid: $guid, date: $date);
|
||||
|
||||
if (null !== $type && strtolower($type) !== strtolower(ag($item, 'type', ''))) {
|
||||
continue;
|
||||
@@ -78,6 +85,12 @@ final class Index
|
||||
#[Post(self::URL . '[/]', name: 'ignore.add')]
|
||||
public function addNewRule(iRequest $request): iResponse
|
||||
{
|
||||
try {
|
||||
$userContext = $this->getUserContext($request, $this->mapper, $this->logger);
|
||||
} catch (RuntimeException $e) {
|
||||
return api_error($e->getMessage(), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
$params = DataUtil::fromRequest($request);
|
||||
|
||||
if (null === ($id = $params->get('rule'))) {
|
||||
@@ -98,7 +111,7 @@ final class Index
|
||||
}
|
||||
|
||||
try {
|
||||
checkIgnoreRule($id);
|
||||
checkIgnoreRule(guid: $id, userContext: $userContext);
|
||||
} catch (RuntimeException $e) {
|
||||
return api_error($e->getMessage(), Status::BAD_REQUEST);
|
||||
}
|
||||
@@ -106,18 +119,26 @@ final class Index
|
||||
$filtered = (string)makeIgnoreId($id);
|
||||
$date = time();
|
||||
|
||||
if ($this->config->has($id) || $this->config->has($filtered)) {
|
||||
$config = $this->getConfigFile(userContext: $userContext);
|
||||
|
||||
if ($config->has($id) || $config->has($filtered)) {
|
||||
return api_error(r('Rule already exists: {id}', ['id' => $id]), Status::CONFLICT);
|
||||
}
|
||||
|
||||
$this->config->set($filtered, $date)->persist();
|
||||
$config->set($filtered, $date)->persist();
|
||||
|
||||
return api_response(Status::OK, $this->ruleAsArray($filtered, $date));
|
||||
return api_response(Status::OK, $this->ruleAsArray(userContext: $userContext, guid: $filtered, date: $date));
|
||||
}
|
||||
|
||||
#[Delete(self::URL . '[/]', name: 'ignore.delete')]
|
||||
public function deleteRule(iRequest $request): iResponse
|
||||
{
|
||||
try {
|
||||
$userContext = $this->getUserContext($request, $this->mapper, $this->logger);
|
||||
} catch (RuntimeException $e) {
|
||||
return api_error($e->getMessage(), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
$params = DataUtil::fromRequest($request);
|
||||
|
||||
if (null === ($rule = $params->get('rule'))) {
|
||||
@@ -125,22 +146,24 @@ final class Index
|
||||
}
|
||||
|
||||
try {
|
||||
checkIgnoreRule($rule);
|
||||
checkIgnoreRule(guid: $rule, userContext: $userContext);
|
||||
} catch (RuntimeException $e) {
|
||||
return api_error($e->getMessage(), Status::BAD_REQUEST);
|
||||
}
|
||||
|
||||
$filtered = (string)makeIgnoreId($rule);
|
||||
|
||||
if (!$this->config->has($filtered)) {
|
||||
$config = $this->getConfigFile(userContext: $userContext);
|
||||
|
||||
if (!$config->has($filtered)) {
|
||||
return api_error(r('Rule does not exist: {rule}', ['rule' => $rule]), Status::NOT_FOUND);
|
||||
}
|
||||
|
||||
$date = $this->config->get($filtered);
|
||||
$date = $config->get($filtered);
|
||||
|
||||
$this->config->delete($filtered)->persist();
|
||||
$config->delete($filtered)->persist();
|
||||
|
||||
return api_response(Status::OK, $this->ruleAsArray($filtered, $date));
|
||||
return api_response(Status::OK, $this->ruleAsArray(userContext: $userContext, guid: $filtered, date: $date));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,7 +173,7 @@ final class Index
|
||||
*
|
||||
* @return string|null Return the name of the item or null if not found.
|
||||
*/
|
||||
private function getInfo(iUri $uri): string|null
|
||||
private function getInfo(UserContext $userContext, iUri $uri): string|null
|
||||
{
|
||||
if (empty($uri->getQuery())) {
|
||||
return null;
|
||||
@@ -171,7 +194,7 @@ final class Index
|
||||
$uri->getScheme() === iState::TYPE_SHOW ? 'show' : 'id'
|
||||
);
|
||||
|
||||
$stmt = $this->db->prepare($sql);
|
||||
$stmt = $userContext->db->getDBLayer()->prepare($sql);
|
||||
$stmt->execute(['id' => $params['id']]);
|
||||
$item = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
@@ -187,7 +210,7 @@ final class Index
|
||||
return $this->cache[$key];
|
||||
}
|
||||
|
||||
public function ruleAsArray(string $guid, int|null $date = null): array
|
||||
public function ruleAsArray(UserContext $userContext, string $guid, int|null $date = null): array
|
||||
{
|
||||
$urlParts = parse_url($guid);
|
||||
|
||||
@@ -215,7 +238,7 @@ final class Index
|
||||
'type' => ucfirst($type),
|
||||
'backend' => $backend,
|
||||
'db' => $db,
|
||||
'title' => null !== $scope ? ($this->getinfo($rule) ?? 'Unknown') : null,
|
||||
'title' => null !== $scope ? ($this->getinfo(userContext: $userContext, uri: $rule) ?? 'Unknown') : null,
|
||||
'scoped' => null !== $scoped_to,
|
||||
'scoped_to' => $scoped_to,
|
||||
];
|
||||
@@ -226,4 +249,15 @@ final class Index
|
||||
|
||||
return $builder;
|
||||
}
|
||||
|
||||
|
||||
private function getConfigFile(UserContext $userContext): ConfigFile
|
||||
{
|
||||
return ConfigFile::open(
|
||||
file: $userContext->getPath() . '/ignore.yaml',
|
||||
type: 'yaml',
|
||||
autoCreate: true,
|
||||
autoBackup: false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ use App\Backends\Emby\EmbyClient;
|
||||
use App\Libs\Config;
|
||||
use App\Libs\Exceptions\Backends\InvalidArgumentException;
|
||||
use App\Libs\Guid;
|
||||
use App\Libs\Options;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Yaml\Exception\ParseException;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
@@ -236,6 +235,7 @@ class JellyfinGuid implements iGuid
|
||||
$id = ag($context, 'item.id', null);
|
||||
$type = ag($context, 'item.type', '??');
|
||||
$type = JellyfinClient::TYPE_MAPPER[$type] ?? $type;
|
||||
$bName = $this->context->backendName;
|
||||
|
||||
foreach (array_change_key_case($guids, CASE_LOWER) as $key => $value) {
|
||||
if (null === ($this->guidMapper[$key] ?? null) || empty($value)) {
|
||||
@@ -243,11 +243,7 @@ class JellyfinGuid implements iGuid
|
||||
}
|
||||
|
||||
try {
|
||||
if (null === ($bName = ag($this->context->options, Options::ALT_NAME))) {
|
||||
$bName = $this->context->backendName;
|
||||
}
|
||||
|
||||
if (true === isIgnoredId($bName, $type, $key, $value, $id)) {
|
||||
if (true === isIgnoredId($this->context->userContext, $bName, $type, $key, $value, $id)) {
|
||||
if (true === $log) {
|
||||
$this->logger->debug(
|
||||
"{class}: Ignoring '{client}: {backend}' external id '{source}' for {item.type} '{item.id}: {item.title}' as requested.",
|
||||
|
||||
@@ -9,7 +9,6 @@ use App\Backends\Common\GuidInterface as iGuid;
|
||||
use App\Libs\Config;
|
||||
use App\Libs\Exceptions\Backends\InvalidArgumentException;
|
||||
use App\Libs\Guid;
|
||||
use App\Libs\Options;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
use Symfony\Component\Yaml\Exception\ParseException;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
@@ -338,6 +337,7 @@ final class PlexGuid implements iGuid
|
||||
$id = ag($context, 'item.id', null);
|
||||
$type = ag($context, 'item.type', '??');
|
||||
$type = PlexClient::TYPE_MAPPER[$type] ?? $type;
|
||||
$bName = $this->context->backendName;
|
||||
|
||||
foreach (array_column($guids, 'id') as $val) {
|
||||
try {
|
||||
@@ -372,11 +372,7 @@ final class PlexGuid implements iGuid
|
||||
continue;
|
||||
}
|
||||
|
||||
if (null === ($bName = ag($this->context->options, Options::ALT_NAME))) {
|
||||
$bName = $this->context->backendName;
|
||||
}
|
||||
|
||||
if (true === isIgnoredId($bName, $type, $key, $value, $id)) {
|
||||
if (true === isIgnoredId($this->context->userContext, $bName, $type, $key, $value, $id)) {
|
||||
if (true === $log) {
|
||||
$this->logger->debug(
|
||||
"PlexGuid: Ignoring '{client}: {backend}' external id '{source}' for {item.type} '{item.id}: {item.title}' as requested.",
|
||||
|
||||
@@ -4,8 +4,19 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Libs;
|
||||
|
||||
use App\Libs\Database\DBLayer;
|
||||
use App\Libs\Database\PDO\PDOAdapter;
|
||||
use App\Libs\Mappers\Import\MemoryMapper;
|
||||
use App\Libs\Mappers\ImportInterface;
|
||||
use Closure;
|
||||
use Monolog\Handler\NullHandler;
|
||||
use Monolog\Handler\TestHandler;
|
||||
use Monolog\Logger;
|
||||
use PDO;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
||||
use Symfony\Component\Cache\Psr16Cache;
|
||||
use Throwable;
|
||||
|
||||
class TestCase extends \PHPUnit\Framework\TestCase
|
||||
@@ -58,4 +69,39 @@ class TestCase extends \PHPUnit\Framework\TestCase
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function createUserContext(
|
||||
string $name = 'test',
|
||||
ConfigFile|null $configFile = null,
|
||||
LoggerInterface|null $logger = null,
|
||||
CacheInterface|null $cache = null,
|
||||
PDOAdapter|null $db = null,
|
||||
ImportInterface|null $mapper = null,
|
||||
array $data = [],
|
||||
): UserContext {
|
||||
static $instances = null;
|
||||
|
||||
if (null !== ($instances[$name] ?? null)) {
|
||||
return $instances[$name];
|
||||
}
|
||||
|
||||
$logger ??= new Logger('test', [new NullHandler()]);
|
||||
$cache ??= new Psr16Cache(new ArrayAdapter());
|
||||
if (null === $db) {
|
||||
$db = new PDOAdapter($logger, new DBLayer(new PDO('sqlite::memory:')));
|
||||
$db->migrations('up');
|
||||
}
|
||||
|
||||
$filePath = TESTS_PATH . '/Fixtures/test_servers.yaml';
|
||||
$instances[$name] = new UserContext(
|
||||
name: $name,
|
||||
config: $configFile ?? new ConfigFile($filePath, 'yaml', false, false, false),
|
||||
mapper: $mapper ?? new MemoryMapper(logger: $logger, db: $db, cache: $cache),
|
||||
cache: $cache,
|
||||
db: $db,
|
||||
data: $data,
|
||||
);
|
||||
|
||||
return $instances[$name];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,11 +38,11 @@ final class UserContext
|
||||
|
||||
public function getPath(): string
|
||||
{
|
||||
if ($this->has('path')) {
|
||||
return $this->get('path');
|
||||
if (isset($this->data['path'])) {
|
||||
return $this->data['path'];
|
||||
}
|
||||
|
||||
return Config::get('path') . '/' . ('main' === $this->name ? 'config' : "users/{$this->name}");
|
||||
return fixPath(Config::get('path') . '/' . ('main' === $this->name ? 'config' : "users/{$this->name}"));
|
||||
}
|
||||
|
||||
public function getBackendsNames(): string
|
||||
|
||||
@@ -59,6 +59,7 @@ use Symfony\Component\Cache\Adapter\RedisAdapter;
|
||||
use Symfony\Component\Cache\Psr16Cache;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
use Symfony\Component\Process\Process;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\ResponseStreamInterface;
|
||||
|
||||
@@ -955,21 +956,38 @@ if (false === function_exists('isIgnoredId')) {
|
||||
* @throws InvalidArgumentException Throws an exception if an invalid context type is given.
|
||||
*/
|
||||
function isIgnoredId(
|
||||
UserContext $userContext,
|
||||
string $backend,
|
||||
string $type,
|
||||
string $db,
|
||||
string|int $id,
|
||||
string|int|null $backendId = null
|
||||
string|int|null $backendId = null,
|
||||
array $opts = [],
|
||||
): bool {
|
||||
static $ignoreList = [];
|
||||
|
||||
if (false === in_array($type, iState::TYPES_LIST)) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid context type \'%s\' was given.', $type));
|
||||
}
|
||||
|
||||
$list = Config::get('ignore', []);
|
||||
if (!isset($ignoreList[$userContext->name]) || isset($opts['reset'])) {
|
||||
$ignoreList[$userContext->name] = $opts['list'] ?? [];
|
||||
$ignoreFile = $userContext->getPath() . '/ignore.yaml';
|
||||
if (true === file_exists($ignoreFile)) {
|
||||
try {
|
||||
foreach (Yaml::parseFile($ignoreFile) as $key => $val) {
|
||||
$ignoreList[$userContext->name][(string)makeIgnoreId($key)] = $val;
|
||||
}
|
||||
} catch (Throwable) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$list = $opts['list'] ?? $ignoreList[$userContext->name];
|
||||
|
||||
$key = makeIgnoreId(sprintf('%s://%s:%s@%s?id=%s', $type, $db, $id, $backend, $backendId));
|
||||
|
||||
if (null !== ($list[(string)$key->withQuery('')] ?? null)) {
|
||||
if (isset($list[(string)$key->withQuery('')])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -977,7 +995,7 @@ if (false === function_exists('isIgnoredId')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return null !== ($list[(string)$key] ?? null);
|
||||
return isset($list[(string)$key]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,21 +10,14 @@ use App\Backends\Common\Context;
|
||||
use App\Backends\Emby\EmbyClient;
|
||||
use App\Backends\Emby\EmbyGuid;
|
||||
use App\Libs\Config;
|
||||
use App\Libs\ConfigFile;
|
||||
use App\Libs\Database\DBLayer;
|
||||
use App\Libs\Database\PDO\PDOAdapter;
|
||||
use App\Libs\Exceptions\Backends\InvalidArgumentException;
|
||||
use App\Libs\Extends\LogMessageProcessor;
|
||||
use App\Libs\Guid;
|
||||
use App\Libs\Mappers\Import\MemoryMapper;
|
||||
use App\Libs\TestCase;
|
||||
use App\Libs\Uri;
|
||||
use App\Libs\UserContext;
|
||||
use Monolog\Handler\NullHandler;
|
||||
use Monolog\Handler\TestHandler;
|
||||
use Monolog\Level;
|
||||
use Monolog\Logger;
|
||||
use PDO;
|
||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
||||
use Symfony\Component\Cache\Psr16Cache;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
@@ -61,33 +54,13 @@ class EmbyGuidTest extends TestCase
|
||||
private function getClass(): EmbyGuid
|
||||
{
|
||||
$this->handler->clear();
|
||||
$logger = new Logger('test', [new NullHandler()]);
|
||||
$cache = new Cache($this->logger, new Psr16Cache(new ArrayAdapter()));
|
||||
$db = new PDOAdapter($logger, new DBLayer(new PDO('sqlite::memory:')));
|
||||
$db->migrations('up');
|
||||
|
||||
return new EmbyGuid($this->logger)->withContext(
|
||||
new Context(
|
||||
clientName: EmbyClient::CLIENT_NAME,
|
||||
backendName: 'test_emby',
|
||||
backendUrl: new Uri('http://127.0.0.1:8096'),
|
||||
cache: $cache,
|
||||
userContext: new UserContext(
|
||||
name: EmbyClient::CLIENT_NAME,
|
||||
config: new ConfigFile(
|
||||
file: __DIR__ . '/../../Fixtures/test_servers.yaml',
|
||||
autoSave: false,
|
||||
autoCreate: false,
|
||||
autoBackup: false
|
||||
),
|
||||
mapper: new MemoryMapper(
|
||||
logger: $logger,
|
||||
db: $db,
|
||||
cache: $cache->getInterface()
|
||||
),
|
||||
cache: $cache->getInterface(),
|
||||
db: $db
|
||||
),
|
||||
cache: new Cache($this->logger, new Psr16Cache(new ArrayAdapter())),
|
||||
userContext: $this->createUserContext(EmbyClient::CLIENT_NAME),
|
||||
logger: $this->logger,
|
||||
backendId: 's000000000000000000000000000000e',
|
||||
backendToken: 't000000000000000000000000000000e',
|
||||
@@ -413,11 +386,28 @@ class EmbyGuidTest extends TestCase
|
||||
'year' => 2021
|
||||
]
|
||||
];
|
||||
Config::save('ignore', [(string)makeIgnoreId('show://imdb:123@test_emby') => 1]);
|
||||
|
||||
$this->assertEquals([],
|
||||
$this->getClass()->get(['imdb' => '123'], $context),
|
||||
'Assert only the the oldest ID is returned for numeric GUIDs.');
|
||||
// -- as we cache the ignore list for each user now,
|
||||
// -- and no longer rely on config.ignore key, we needed a workaround to update the ignore list
|
||||
isIgnoredId(
|
||||
userContext: $this->createUserContext(EmbyClient::CLIENT_NAME),
|
||||
backend: 'test_emby',
|
||||
type: 'show',
|
||||
db: 'imdb',
|
||||
id: '123',
|
||||
opts: [
|
||||
'reset' => true,
|
||||
'list' => [
|
||||
(string)makeIgnoreId('show://imdb:123@test_emby') => 1
|
||||
]
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
expected: [],
|
||||
actual: $this->getClass()->get(['imdb' => '123'], $context),
|
||||
message: 'Assert only the the oldest ID is returned for numeric GUIDs.'
|
||||
);
|
||||
|
||||
$this->assertTrue(
|
||||
$this->logged(Level::Debug, 'EmbyGuid: Ignoring', true),
|
||||
|
||||
@@ -10,21 +10,14 @@ use App\Backends\Common\Context;
|
||||
use App\Backends\Jellyfin\JellyfinClient;
|
||||
use App\Backends\Jellyfin\JellyfinGuid;
|
||||
use App\Libs\Config;
|
||||
use App\Libs\ConfigFile;
|
||||
use App\Libs\Database\DBLayer;
|
||||
use App\Libs\Database\PDO\PDOAdapter;
|
||||
use App\Libs\Exceptions\Backends\InvalidArgumentException;
|
||||
use App\Libs\Extends\LogMessageProcessor;
|
||||
use App\Libs\Guid;
|
||||
use App\Libs\Mappers\Import\MemoryMapper;
|
||||
use App\Libs\TestCase;
|
||||
use App\Libs\Uri;
|
||||
use App\Libs\UserContext;
|
||||
use Monolog\Handler\NullHandler;
|
||||
use Monolog\Handler\TestHandler;
|
||||
use Monolog\Level;
|
||||
use Monolog\Logger;
|
||||
use PDO;
|
||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
||||
use Symfony\Component\Cache\Psr16Cache;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
@@ -61,33 +54,13 @@ class JellyfinGuidTest extends TestCase
|
||||
private function getClass(): JellyfinGuid
|
||||
{
|
||||
$this->handler->clear();
|
||||
$logger = new Logger('test', [new NullHandler()]);
|
||||
$cache = new Cache($this->logger, new Psr16Cache(new ArrayAdapter()));
|
||||
$db = new PDOAdapter($logger, new DBLayer(new PDO('sqlite::memory:')));
|
||||
$db->migrations('up');
|
||||
|
||||
return new JellyfinGuid($this->logger)->withContext(
|
||||
new Context(
|
||||
clientName: JellyfinClient::CLIENT_NAME,
|
||||
backendName: 'test_jellyfin',
|
||||
backendUrl: new Uri('http://127.0.0.1:8096'),
|
||||
cache: $cache,
|
||||
userContext: new UserContext(
|
||||
name: JellyfinClient::CLIENT_NAME,
|
||||
config: new ConfigFile(
|
||||
file: __DIR__ . '/../../Fixtures/test_servers.yaml',
|
||||
autoSave: false,
|
||||
autoCreate: false,
|
||||
autoBackup: false
|
||||
),
|
||||
mapper: new MemoryMapper(
|
||||
logger: $logger,
|
||||
db: $db,
|
||||
cache: $cache->getInterface()
|
||||
),
|
||||
cache: $cache->getInterface(),
|
||||
db: $db
|
||||
),
|
||||
cache: new Cache($this->logger, new Psr16Cache(new ArrayAdapter())),
|
||||
userContext: $this->createUserContext(JellyfinClient::CLIENT_NAME),
|
||||
logger: $this->logger,
|
||||
backendId: 's000000000000000000000000000000j',
|
||||
backendToken: 't000000000000000000000000000000j',
|
||||
@@ -411,7 +384,22 @@ class JellyfinGuidTest extends TestCase
|
||||
'year' => 2021
|
||||
]
|
||||
];
|
||||
Config::save('ignore', [(string)makeIgnoreId('show://imdb:123@test_jellyfin') => 1]);
|
||||
|
||||
// -- as we cache the ignore list for each user now,
|
||||
// -- and no longer rely on config.ignore key, we needed a workaround to update the ignore list
|
||||
isIgnoredId(
|
||||
userContext: $this->createUserContext(JellyfinClient::CLIENT_NAME),
|
||||
backend: 'test_plex',
|
||||
type: 'show',
|
||||
db: 'imdb',
|
||||
id: '123',
|
||||
opts: [
|
||||
'reset' => true,
|
||||
'list' => [
|
||||
(string)makeIgnoreId('show://imdb:123@test_jellyfin') => 1
|
||||
]
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals([],
|
||||
$this->getClass()->get(['imdb' => '123'], $context),
|
||||
|
||||
@@ -10,21 +10,14 @@ use App\Backends\Common\Context;
|
||||
use App\Backends\Plex\PlexClient;
|
||||
use App\Backends\Plex\PlexGuid;
|
||||
use App\Libs\Config;
|
||||
use App\Libs\ConfigFile;
|
||||
use App\Libs\Database\DBLayer;
|
||||
use App\Libs\Database\PDO\PDOAdapter;
|
||||
use App\Libs\Exceptions\Backends\InvalidArgumentException;
|
||||
use App\Libs\Extends\LogMessageProcessor;
|
||||
use App\Libs\Guid;
|
||||
use App\Libs\Mappers\Import\MemoryMapper;
|
||||
use App\Libs\TestCase;
|
||||
use App\Libs\Uri;
|
||||
use App\Libs\UserContext;
|
||||
use Monolog\Handler\NullHandler;
|
||||
use Monolog\Handler\TestHandler;
|
||||
use Monolog\Level;
|
||||
use Monolog\Logger;
|
||||
use PDO;
|
||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
||||
use Symfony\Component\Cache\Psr16Cache;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
@@ -61,33 +54,13 @@ class PlexGuidTest extends TestCase
|
||||
private function getClass(): PlexGuid
|
||||
{
|
||||
$this->handler->clear();
|
||||
$logger = new Logger('test', [new NullHandler()]);
|
||||
$cache = new Cache($this->logger, new Psr16Cache(new ArrayAdapter()));
|
||||
$db = new PDOAdapter($logger, new DBLayer(new PDO('sqlite::memory:')));
|
||||
$db->migrations('up');
|
||||
|
||||
return new PlexGuid($this->logger)->withContext(
|
||||
new Context(
|
||||
clientName: PlexClient::CLIENT_NAME,
|
||||
backendName: 'test_plex',
|
||||
backendUrl: new Uri('http://127.0.0.1:34000'),
|
||||
cache: $cache,
|
||||
userContext: new UserContext(
|
||||
name: PlexClient::CLIENT_NAME,
|
||||
config: new ConfigFile(
|
||||
file: __DIR__ . '/../../Fixtures/test_servers.yaml',
|
||||
autoSave: false,
|
||||
autoCreate: false,
|
||||
autoBackup: false
|
||||
),
|
||||
mapper: new MemoryMapper(
|
||||
logger: $logger,
|
||||
db: $db,
|
||||
cache: $cache->getInterface()
|
||||
),
|
||||
cache: $cache->getInterface(),
|
||||
db: $db
|
||||
),
|
||||
cache: new Cache($this->logger, new Psr16Cache(new ArrayAdapter())),
|
||||
userContext: $this->createUserContext(PlexClient::CLIENT_NAME),
|
||||
logger: $this->logger,
|
||||
backendId: 's00000000000000000000000000000000000000p',
|
||||
backendToken: 't000000000000000000p',
|
||||
@@ -461,7 +434,21 @@ class PlexGuidTest extends TestCase
|
||||
['id' => 'com.plexapp.agents.imdb://2'],
|
||||
], $context), 'Assert only the the oldest ID is returned for numeric GUIDs.');
|
||||
|
||||
Config::save('ignore', [(string)makeIgnoreId('show://imdb:123@test_plex') => 1]);
|
||||
// -- as we cache the ignore list for each user now,
|
||||
// -- and no longer rely on config.ignore key, we needed a workaround to update the ignore list
|
||||
isIgnoredId(
|
||||
userContext: $this->createUserContext(PlexClient::CLIENT_NAME),
|
||||
backend: 'test_plex',
|
||||
type: 'show',
|
||||
db: 'imdb',
|
||||
id: '123',
|
||||
opts: [
|
||||
'reset' => true,
|
||||
'list' => [
|
||||
(string)makeIgnoreId('show://imdb:123@test_plex') => 1
|
||||
]
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals([],
|
||||
$this->getClass()->get([
|
||||
|
||||
@@ -750,14 +750,14 @@ class HelpersTest extends TestCase
|
||||
{
|
||||
$key = sprintf('%s://%s:%s@%s?id=%s', 'movie', 'guid_tvdb', '1200', 'test_plex', '121');
|
||||
|
||||
Config::init([
|
||||
'ignore' => [
|
||||
(string)makeIgnoreId($key) => makeDate(),
|
||||
]
|
||||
]);
|
||||
$userContext = $this->createUserContext();
|
||||
|
||||
$this->assertTrue(
|
||||
isIgnoredId('test_plex', 'movie', 'guid_tvdb', '1200', '121'),
|
||||
isIgnoredId($userContext, 'test_plex', 'movie', 'guid_tvdb', '1200', '121', opts: [
|
||||
'list' => [
|
||||
(string)makeIgnoreId($key) => makeDate(),
|
||||
],
|
||||
]),
|
||||
'When exact ignore url is passed, and it is found in ignore list, true is returned.'
|
||||
);
|
||||
|
||||
@@ -768,17 +768,29 @@ class HelpersTest extends TestCase
|
||||
]);
|
||||
|
||||
$this->assertTrue(
|
||||
isIgnoredId('test_plex', 'movie', 'guid_tvdb', '1200', '121'),
|
||||
isIgnoredId($userContext, 'test_plex', 'movie', 'guid_tvdb', '1200', '121', opts: [
|
||||
'list' => [
|
||||
(string)makeIgnoreId($key)->withQuery('') => makeDate()
|
||||
]
|
||||
]),
|
||||
'When ignore url is passed with and ignore list has url without query string, true is returned.'
|
||||
);
|
||||
|
||||
$this->assertFalse(
|
||||
isIgnoredId('test_plex', 'movie', 'guid_tvdb', '1201', '121'),
|
||||
isIgnoredId($userContext, 'test_plex', 'movie', 'guid_tvdb', '1201', '121', opts: [
|
||||
'list' => [
|
||||
(string)makeIgnoreId($key)->withQuery('') => makeDate()
|
||||
]
|
||||
]),
|
||||
'When ignore url is passed with and ignore list does not contain the url, false is returned.'
|
||||
);
|
||||
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
isIgnoredId('test_plex', 'not_real_type', 'guid_tvdb', '1200', '121');
|
||||
isIgnoredId($userContext, 'test_plex', 'not_real_type', 'guid_tvdb', '1200', '121', opts: [
|
||||
'list' => [
|
||||
(string)makeIgnoreId($key)->withQuery('') => makeDate()
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_r(): void
|
||||
|
||||
@@ -6,6 +6,8 @@ if (false === defined('IN_TEST_MODE')) {
|
||||
define('IN_TEST_MODE', true);
|
||||
}
|
||||
|
||||
const TESTS_PATH = __DIR__;
|
||||
|
||||
require __DIR__ . '/../pre_init.php';
|
||||
|
||||
if (!file_exists(__DIR__ . '/../vendor/autoload.php')) {
|
||||
|
||||
Reference in New Issue
Block a user