each user get their own ignore.yaml file now.

This commit is contained in:
ArabCoders
2025-02-08 17:02:52 +03:00
parent c2d4e6a65b
commit 00c65e4aab
12 changed files with 219 additions and 150 deletions

4
FAQ.md
View File

@@ -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.

View File

@@ -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
);
}
}

View File

@@ -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.",

View File

@@ -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.",

View File

@@ -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];
}
}

View File

@@ -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

View File

@@ -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]);
}
}

View File

@@ -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),

View File

@@ -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),

View File

@@ -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([

View File

@@ -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

View File

@@ -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')) {