Version 5.1 - All the GraphQL #32
@ -2,16 +2,16 @@
|
||||
/**
|
||||
* Hummingbird Anime List Client
|
||||
*
|
||||
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
||||
* An API client for Kitsu to manage anime and manga watch lists
|
||||
*
|
||||
* PHP version 7
|
||||
* PHP version 8
|
||||
*
|
||||
* @package HummingbirdAnimeClient
|
||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||
* @copyright 2015 - 2017 Timothy J. Warren
|
||||
* @copyright 2015 - 2021 Timothy J. Warren
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @version 4.0
|
||||
* @link https://github.com/timw4mail/HummingBirdAnimeClient
|
||||
* @version 5.2
|
||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||
*/
|
||||
|
||||
use function Aviat\AnimeClient\loadConfig;
|
||||
@ -21,12 +21,13 @@ use function Aviat\AnimeClient\loadConfig;
|
||||
//
|
||||
// You shouldn't generally need to change anything below this line
|
||||
// ----------------------------------------------------------------------------
|
||||
$APP_DIR = realpath(__DIR__ . '/../');
|
||||
$ROOT_DIR = realpath("{$APP_DIR}/../");
|
||||
$APP_DIR = dirname(__DIR__);
|
||||
$ROOT_DIR = dirname($APP_DIR);
|
||||
|
||||
$tomlConfig = loadConfig(__DIR__);
|
||||
|
||||
return array_merge($tomlConfig, [
|
||||
'root' => $ROOT_DIR,
|
||||
'asset_dir' => "{$ROOT_DIR}/public",
|
||||
'base_config_dir' => __DIR__,
|
||||
'config_dir' => "{$APP_DIR}/config",
|
||||
|
@ -2,15 +2,15 @@
|
||||
/**
|
||||
* Hummingbird Anime List Client
|
||||
*
|
||||
* An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
|
||||
* An API client for Kitsu to manage anime and manga watch lists
|
||||
*
|
||||
* PHP version 7
|
||||
* PHP version 8
|
||||
*
|
||||
* @package HummingbirdAnimeClient
|
||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||
* @copyright 2015 - 2018 Timothy J. Warren
|
||||
* @copyright 2015 - 2021 Timothy J. Warren
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @version 4.0
|
||||
* @version 5.2
|
||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||
*/
|
||||
|
||||
|
@ -34,11 +34,11 @@ use Psr\SimpleCache\CacheInterface;
|
||||
|
||||
use function Aviat\Ion\_dir;
|
||||
|
||||
if ( ! defined('APP_DIR'))
|
||||
if ( ! defined('HB_APP_DIR'))
|
||||
{
|
||||
define('APP_DIR', __DIR__);
|
||||
define('ROOT_DIR', dirname(APP_DIR));
|
||||
define('TEMPLATE_DIR', _dir(APP_DIR, 'templates'));
|
||||
define('HB_APP_DIR', __DIR__);
|
||||
define('ROOT_DIR', dirname(HB_APP_DIR));
|
||||
define('TEMPLATE_DIR', _dir(HB_APP_DIR, 'templates'));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -50,7 +50,7 @@ return static function (array $configArray = []): Container {
|
||||
// -------------------------------------------------------------------------
|
||||
// Logging
|
||||
// -------------------------------------------------------------------------
|
||||
$LOG_DIR = _dir(APP_DIR, 'logs');
|
||||
$LOG_DIR = _dir(HB_APP_DIR, 'logs');
|
||||
|
||||
$appLogger = new Logger('animeclient');
|
||||
$appLogger->pushHandler(new RotatingFileHandler(_dir($LOG_DIR, 'app.log'), 2, Logger::WARNING));
|
||||
|
@ -2,6 +2,7 @@
|
||||
declare(strict_types=1);
|
||||
|
||||
$file_patterns = [
|
||||
'app/appConf/*.php',
|
||||
'app/bootstrap.php',
|
||||
'migrations/*.php',
|
||||
'src/**/*.php',
|
||||
@ -16,7 +17,7 @@ if ( ! function_exists('glob_recursive'))
|
||||
{
|
||||
// Does not support flag GLOB_BRACE
|
||||
|
||||
function glob_recursive($pattern, $flags = 0)
|
||||
function glob_recursive(string $pattern, int $flags = 0): array
|
||||
{
|
||||
$files = glob($pattern, $flags);
|
||||
|
||||
@ -57,17 +58,21 @@ function get_text_to_replace(array $tokens): string
|
||||
return $output;
|
||||
}
|
||||
|
||||
function get_tokens($source): array
|
||||
function get_tokens(string $source): array
|
||||
{
|
||||
return token_get_all($source);
|
||||
}
|
||||
|
||||
function replace_files(array $files, $template)
|
||||
function replace_files(array $files, string $template): void
|
||||
{
|
||||
print_r($files);
|
||||
foreach ($files as $file)
|
||||
{
|
||||
$source = file_get_contents($file);
|
||||
if ($source === FALSE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (stripos($source, 'namespace') === FALSE)
|
||||
{
|
||||
|
@ -4,6 +4,7 @@ parameters:
|
||||
inferPrivatePropertyTypeFromConstructor: true
|
||||
level: 8
|
||||
paths:
|
||||
- app/appConf
|
||||
- src
|
||||
- ./console
|
||||
- index.php
|
||||
|
@ -186,7 +186,7 @@ function checkFolderPermissions(ConfigInterface $config): array
|
||||
$errors = [];
|
||||
$publicDir = $config->get('asset_dir');
|
||||
|
||||
$APP_DIR = _dir(dirname(__DIR__, 2), '/app');
|
||||
$APP_DIR = _dir($config->get('root'), 'app');
|
||||
|
||||
$pathMap = [
|
||||
'app/config' => "{$APP_DIR}/config",
|
||||
@ -211,7 +211,9 @@ function checkFolderPermissions(ConfigInterface $config): array
|
||||
|
||||
if ( ! $writable)
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
$errors['writable'][] = $pretty;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
|
||||
@ -292,6 +294,7 @@ function getLocalImg (string $kitsuUrl, $webp = TRUE): string
|
||||
/**
|
||||
* Create a transparent placeholder image
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @param string $path
|
||||
* @param int|null $width
|
||||
* @param int|null $height
|
||||
@ -378,7 +381,6 @@ function colNotEmpty(array $search, string $key): bool
|
||||
*
|
||||
* @param CacheInterface $cache
|
||||
* @return bool
|
||||
* @throws Throwable
|
||||
*/
|
||||
function clearCache(CacheInterface $cache): bool
|
||||
{
|
||||
@ -393,9 +395,7 @@ function clearCache(CacheInterface $cache): bool
|
||||
$userData = array_filter((array)$userData, static fn ($value) => $value !== NULL);
|
||||
$cleared = $cache->clear();
|
||||
|
||||
$saved = ( ! empty($userData))
|
||||
? $cache->setMultiple($userData)
|
||||
: TRUE;
|
||||
$saved = ( ! empty($userData)) ? $cache->setMultiple($userData) : TRUE;
|
||||
|
||||
return $cleared && $saved;
|
||||
}
|
||||
|
@ -236,6 +236,9 @@ abstract class AbstractType implements ArrayAccess, Countable {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
final protected function fromObject(mixed $parent = null): float|null|bool|int|array|string
|
||||
{
|
||||
$object = $parent ?? $this;
|
||||
|
@ -32,6 +32,8 @@ class Config extends AbstractType {
|
||||
// Settings in config.toml
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
public string $root; // Path to app root
|
||||
|
||||
public ?string $asset_path; // Path to public folder for urls
|
||||
|
||||
/**
|
||||
@ -62,8 +64,6 @@ class Config extends AbstractType {
|
||||
/**
|
||||
* Default list view type
|
||||
* 'cover_view' or 'list_view'
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public ?string $default_view_type;
|
||||
|
||||
@ -71,21 +71,13 @@ class Config extends AbstractType {
|
||||
|
||||
public bool $secure_urls = TRUE;
|
||||
|
||||
/**
|
||||
* @var string|bool
|
||||
*/
|
||||
public string|bool $show_anime_collection = FALSE;
|
||||
|
||||
/**
|
||||
* @var string|bool
|
||||
*/
|
||||
public string|bool $show_manga_collection = FALSE;
|
||||
|
||||
/**
|
||||
* CSS theme: light, dark, or auto-switching
|
||||
* 'auto', 'light', or 'dark'
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
public ?string $theme = 'auto';
|
||||
|
||||
|
@ -16,9 +16,11 @@
|
||||
|
||||
namespace Aviat\AnimeClient\Tests;
|
||||
|
||||
use Amp\Http\Client\Response;
|
||||
|
||||
use function Aviat\AnimeClient\arrayToToml;
|
||||
use function Aviat\AnimeClient\checkFolderPermissions;
|
||||
use function Aviat\AnimeClient\clearCache;
|
||||
use function Aviat\AnimeClient\colNotEmpty;
|
||||
use function Aviat\AnimeClient\getLocalImg;
|
||||
use function Aviat\AnimeClient\getResponse;
|
||||
use function Aviat\AnimeClient\isSequentialArray;
|
||||
use function Aviat\AnimeClient\tomlToArray;
|
||||
@ -89,4 +91,46 @@ class AnimeClientTest extends AnimeClientTestCase
|
||||
{
|
||||
$this->assertNotEmpty(getResponse('https://example.com'));
|
||||
}
|
||||
|
||||
public function testCheckFolderPermissions(): void
|
||||
{
|
||||
$config = $this->container->get('config');
|
||||
$actual = checkFolderPermissions($config);
|
||||
$this->assertTrue(is_array($actual));
|
||||
}
|
||||
|
||||
public function testGetLocalImageEmptyUrl(): void
|
||||
{
|
||||
$actual = getLocalImg('');
|
||||
$this->assertEquals('images/placeholder.webp', $actual);
|
||||
}
|
||||
|
||||
public function testGetLocalImageBadUrl(): void
|
||||
{
|
||||
$actual = getLocalImg('//foo.bar');
|
||||
$this->assertEquals('images/placeholder.webp', $actual);
|
||||
}
|
||||
|
||||
public function testColNotEmpty(): void
|
||||
{
|
||||
$hasEmptyCols = [[
|
||||
'foo' => '',
|
||||
], [
|
||||
'foo' => '',
|
||||
]];
|
||||
|
||||
$hasNonEmptyCols = [[
|
||||
'foo' => 'bar',
|
||||
], [
|
||||
'foo' => 'baz',
|
||||
]];
|
||||
|
||||
$this->assertEquals(false, colNotEmpty($hasEmptyCols, 'foo'));
|
||||
$this->assertEquals(true, colNotEmpty($hasNonEmptyCols, 'foo'));
|
||||
}
|
||||
|
||||
public function testClearCache(): void
|
||||
{
|
||||
$this->assertTrue(clearCache($this->container->get('cache')));
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@
|
||||
|
||||
namespace Aviat\AnimeClient\Tests;
|
||||
|
||||
use Aviat\Ion\Di\ContainerInterface;
|
||||
use function Aviat\Ion\_dir;
|
||||
|
||||
use Aviat\Ion\Json;
|
||||
@ -59,6 +60,7 @@ class AnimeClientTestCase extends TestCase {
|
||||
parent::setUp();
|
||||
|
||||
$config_array = [
|
||||
'root' => self::ROOT_DIR,
|
||||
'asset_path' => '/assets',
|
||||
'img_cache_path' => _dir(self::ROOT_DIR, 'public/images'),
|
||||
'data_cache_path' => _dir(self::TEST_DATA_DIR, 'cache'),
|
||||
@ -94,7 +96,7 @@ class AnimeClientTestCase extends TestCase {
|
||||
];
|
||||
|
||||
// Set up DI container
|
||||
$di = require _dir(self::ROOT_DIR, 'app', 'bootstrap.php');
|
||||
$di = require self::ROOT_DIR . '/app/bootstrap.php';
|
||||
$container = $di($config_array);
|
||||
|
||||
// Use mock session handler
|
||||
|
53
tests/AnimeClient/Types/ConfigTest.php
Normal file
53
tests/AnimeClient/Types/ConfigTest.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* Hummingbird Anime List Client
|
||||
*
|
||||
* An API client for Kitsu to manage anime and manga watch lists
|
||||
*
|
||||
* PHP version 8
|
||||
*
|
||||
* @package HummingbirdAnimeClient
|
||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||
* @copyright 2015 - 2021 Timothy J. Warren
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @version 5.2
|
||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||
*/
|
||||
|
||||
namespace Aviat\AnimeClient\Tests\Types;
|
||||
|
||||
use Aviat\AnimeClient\Types\Config;
|
||||
use Aviat\AnimeClient\Types\UndefinedPropertyException;
|
||||
|
||||
class ConfigTest extends ConfigTestCase {
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->testClass = Config::class;
|
||||
}
|
||||
|
||||
public function testSetMethods(): void
|
||||
{
|
||||
$type = $this->testClass::from([
|
||||
'anilist' => [],
|
||||
'cache' => [],
|
||||
'database' => [],
|
||||
]);
|
||||
|
||||
$this->assertEquals(3, $type->count());
|
||||
}
|
||||
|
||||
public function testOffsetUnset(): void
|
||||
{
|
||||
$type = $this->testClass::from([
|
||||
'anilist' => [],
|
||||
]);
|
||||
|
||||
$this->assertTrue($type->offsetExists('anilist'));
|
||||
|
||||
$type->offsetUnset('anilist');
|
||||
|
||||
$this->assertNotTrue($type->offsetExists('anilist'));
|
||||
}
|
||||
}
|
72
tests/AnimeClient/Types/ConfigTestCase.php
Normal file
72
tests/AnimeClient/Types/ConfigTestCase.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* Hummingbird Anime List Client
|
||||
*
|
||||
* An API client for Kitsu to manage anime and manga watch lists
|
||||
*
|
||||
* PHP version 8
|
||||
*
|
||||
* @package HummingbirdAnimeClient
|
||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||
* @copyright 2015 - 2021 Timothy J. Warren
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @version 5.2
|
||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||
*/
|
||||
|
||||
namespace Aviat\AnimeClient\Tests\Types;
|
||||
|
||||
use Aviat\AnimeClient\Tests\AnimeClientTestCase;
|
||||
use Aviat\AnimeClient\Types\UndefinedPropertyException;
|
||||
|
||||
abstract class ConfigTestCase extends AnimeClientTestCase {
|
||||
public string $testClass;
|
||||
|
||||
public function testCheck(): void
|
||||
{
|
||||
$result = $this->testClass::check([]);
|
||||
$this->assertEquals([], $result);
|
||||
}
|
||||
|
||||
public function testSetUndefinedProperty(): void
|
||||
{
|
||||
$this->expectException(UndefinedPropertyException::class);
|
||||
$this->testClass::from([
|
||||
'foobar' => 'baz',
|
||||
]);
|
||||
}
|
||||
|
||||
public function testToString(): void
|
||||
{
|
||||
$actual = $this->testClass::from([])->__toString();
|
||||
$this->assertMatchesSnapshot($actual);
|
||||
}
|
||||
|
||||
public function testOffsetExists(): void
|
||||
{
|
||||
$actual = $this->testClass::from([
|
||||
'anilist' => [],
|
||||
])->offsetExists('anilist');
|
||||
$this->assertTrue($actual);
|
||||
}
|
||||
|
||||
public function testSetState(): void
|
||||
{
|
||||
$normal = $this->testClass::from([]);
|
||||
$setState = $this->testClass::__set_state([]);
|
||||
|
||||
$this->assertEquals($normal, $setState);
|
||||
}
|
||||
|
||||
public function testIsEmpty(): void
|
||||
{
|
||||
$type = $this->testClass::from([]);
|
||||
$this->assertTrue($type->isEmpty());
|
||||
}
|
||||
|
||||
public function testCount(): void
|
||||
{
|
||||
$type = $this->testClass::from([]);
|
||||
$this->assertEquals(0, $type->count());
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
Aviat\AnimeClient\Types\Config Object
|
||||
(
|
||||
)
|
Loading…
Reference in New Issue
Block a user