Settings control panel saves to admin-override.toml in the app/config directory, resolves #7
This commit is contained in:
parent
0d30f57e83
commit
3c0fd79195
@ -1,5 +1,11 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## Version 4.1
|
||||||
|
* Removed MAL integration, added Anilist Integration
|
||||||
|
* Now uses WebP cache images when the browser supports it
|
||||||
|
* Replaces JS minifier with pre-minified scripts (Removes the need for one caching folder, too)
|
||||||
|
* Updated console command to sync Kitsu and Anilist data
|
||||||
|
|
||||||
## Version 4
|
## Version 4
|
||||||
* Updated to use Kitsu API after discontinuation of Hummingbird
|
* Updated to use Kitsu API after discontinuation of Hummingbird
|
||||||
* Added streaming links to list entries from the Kitsu API
|
* Added streaming links to list entries from the Kitsu API
|
||||||
|
@ -216,8 +216,8 @@ return [
|
|||||||
'verb' => 'get',
|
'verb' => 'get',
|
||||||
],
|
],
|
||||||
'settings-post' => [
|
'settings-post' => [
|
||||||
'path' => '/settings',
|
'path' => '/settings-save',
|
||||||
'action' => 'settings',
|
'action' => 'settings_post',
|
||||||
'controller' => DEFAULT_CONTROLLER,
|
'controller' => DEFAULT_CONTROLLER,
|
||||||
'verb' => 'post',
|
'verb' => 'post',
|
||||||
],
|
],
|
||||||
|
@ -6,6 +6,7 @@ if ( ! $auth->isAuthenticated())
|
|||||||
}
|
}
|
||||||
|
|
||||||
$sectionMapping = [
|
$sectionMapping = [
|
||||||
|
'anilist' => 'Anilist API Integration',
|
||||||
'config' => 'General Settings',
|
'config' => 'General Settings',
|
||||||
'cache' => 'Caching',
|
'cache' => 'Caching',
|
||||||
'database' => 'Collection Database Settings',
|
'database' => 'Collection Database Settings',
|
||||||
@ -15,9 +16,7 @@ $hiddenFields = [];
|
|||||||
$nestedPrefix = 'config';
|
$nestedPrefix = 'config';
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<pre><?= print_r($_POST, TRUE) ?></pre>
|
<form action="<?= $url->generate('settings-post') ?>" method="POST">
|
||||||
|
|
||||||
<form action="<?= $_SERVER['REQUEST_URI'] ?>" method="POST">
|
|
||||||
<main class='form'>
|
<main class='form'>
|
||||||
<button type="submit">Save Changes</button>
|
<button type="submit">Save Changes</button>
|
||||||
<br />
|
<br />
|
||||||
|
@ -49,7 +49,13 @@ $baseConfig = require $APPCONF_DIR . '/base_config.php';
|
|||||||
$di = require $APP_DIR . '/bootstrap.php';
|
$di = require $APP_DIR . '/bootstrap.php';
|
||||||
|
|
||||||
$config = loadToml($CONF_DIR);
|
$config = loadToml($CONF_DIR);
|
||||||
$configArray = array_merge($baseConfig, $config);
|
|
||||||
|
$overrideFile = $CONF_DIR . '/admin-override.toml';
|
||||||
|
$overrideConfig = file_exists($overrideFile)
|
||||||
|
? loadTomlFile($overrideFile)
|
||||||
|
: [];
|
||||||
|
|
||||||
|
$configArray = array_merge($baseConfig, $config, $overrideConfig);
|
||||||
|
|
||||||
$checkedConfig = (new ConfigType($configArray))->toArray();
|
$checkedConfig = (new ConfigType($configArray))->toArray();
|
||||||
$container = $di($checkedConfig);
|
$container = $di($checkedConfig);
|
||||||
|
@ -33,6 +33,11 @@ function loadToml(string $path): array
|
|||||||
foreach ($files as $file)
|
foreach ($files as $file)
|
||||||
{
|
{
|
||||||
$key = str_replace('.toml', '', basename($file));
|
$key = str_replace('.toml', '', basename($file));
|
||||||
|
if ($key === 'admin-override')
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$config = Toml::parseFile($file);
|
$config = Toml::parseFile($file);
|
||||||
|
|
||||||
if ($key === 'config')
|
if ($key === 'config')
|
||||||
@ -71,6 +76,17 @@ function loadTomlByFile(string $path): array
|
|||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load config from one specific TOML file
|
||||||
|
*
|
||||||
|
* @param string $filename
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function loadTomlFile(string $filename): array
|
||||||
|
{
|
||||||
|
return Toml::parseFile($filename);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is the array sequential, not associative?
|
* Is the array sequential, not associative?
|
||||||
*
|
*
|
||||||
|
@ -39,9 +39,6 @@ final class Index extends BaseController {
|
|||||||
/**
|
/**
|
||||||
* Purges the API cache
|
* Purges the API cache
|
||||||
*
|
*
|
||||||
* @throws \Aviat\Ion\Di\ContainerException
|
|
||||||
* @throws \Aviat\Ion\Di\NotFoundException
|
|
||||||
* @throws \InvalidArgumentException
|
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function clearCache()
|
public function clearCache()
|
||||||
@ -56,9 +53,6 @@ final class Index extends BaseController {
|
|||||||
* Show the login form
|
* Show the login form
|
||||||
*
|
*
|
||||||
* @param string $status
|
* @param string $status
|
||||||
* @throws \Aviat\Ion\Di\ContainerException
|
|
||||||
* @throws \Aviat\Ion\Di\NotFoundException
|
|
||||||
* @throws \InvalidArgumentException
|
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function login(string $status = '')
|
public function login(string $status = '')
|
||||||
@ -109,10 +103,6 @@ final class Index extends BaseController {
|
|||||||
/**
|
/**
|
||||||
* Attempt login authentication
|
* Attempt login authentication
|
||||||
*
|
*
|
||||||
* @throws \Aviat\Ion\Di\ContainerException
|
|
||||||
* @throws \Aviat\Ion\Di\NotFoundException
|
|
||||||
* @throws \Aura\Router\Exception\RouteNotFound
|
|
||||||
* @throws \InvalidArgumentException
|
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function loginAction()
|
public function loginAction()
|
||||||
@ -133,9 +123,6 @@ final class Index extends BaseController {
|
|||||||
/**
|
/**
|
||||||
* Deauthorize the current user
|
* Deauthorize the current user
|
||||||
*
|
*
|
||||||
* @throws \Aviat\Ion\Di\ContainerException
|
|
||||||
* @throws \Aviat\Ion\Di\NotFoundException
|
|
||||||
* @throws \InvalidArgumentException
|
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function logout()
|
public function logout()
|
||||||
@ -149,9 +136,6 @@ final class Index extends BaseController {
|
|||||||
/**
|
/**
|
||||||
* Show the user profile page
|
* Show the user profile page
|
||||||
*
|
*
|
||||||
* @throws \Aviat\Ion\Di\ContainerException
|
|
||||||
* @throws \Aviat\Ion\Di\NotFoundException
|
|
||||||
* @throws \InvalidArgumentException
|
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function me()
|
public function me()
|
||||||
@ -188,14 +172,28 @@ final class Index extends BaseController {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to save the user's settings
|
||||||
|
*
|
||||||
|
* @throws \Aura\Router\Exception\RouteNotFound
|
||||||
|
*/
|
||||||
public function settings_post()
|
public function settings_post()
|
||||||
{
|
{
|
||||||
$auth = $this->container->get('auth');
|
$post = $this->request->getParsedBody();
|
||||||
$this->outputHTML('settings', [
|
|
||||||
'auth' => $auth,
|
// dump($post);
|
||||||
'config' => $this->config,
|
$saved = $this->settingsModel->saveSettingsFile($post);
|
||||||
'title' => $this->config->get('whose_list') . "'s Settings",
|
|
||||||
]);
|
if ($saved)
|
||||||
|
{
|
||||||
|
$this->setFlashMessage('Saved config settings.', 'success');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$this->setFlashMessage('Failed to save config file.', 'error');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->redirect($this->url->generate('settings'), 303);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -250,7 +248,7 @@ final class Index extends BaseController {
|
|||||||
$baseSavePath = $this->config->get('img_cache_path');
|
$baseSavePath = $this->config->get('img_cache_path');
|
||||||
$filePrefix = "{$baseSavePath}/{$type}/{$id}";
|
$filePrefix = "{$baseSavePath}/{$type}/{$id}";
|
||||||
|
|
||||||
[$origWidth, $origHeight] = getimagesizefromstring($data);
|
[$origWidth] = getimagesizefromstring($data);
|
||||||
$gdImg = imagecreatefromstring($data);
|
$gdImg = imagecreatefromstring($data);
|
||||||
$resizedImg = imagescale($gdImg, $width ?? $origWidth);
|
$resizedImg = imagescale($gdImg, $width ?? $origWidth);
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ final class FormGenerator {
|
|||||||
$params['attribs']['label'] = $form['description'];
|
$params['attribs']['label'] = $form['description'];
|
||||||
$params['attribs']['value'] = TRUE;
|
$params['attribs']['value'] = TRUE;
|
||||||
$params['attribs']['value_unchecked'] = '0'; */
|
$params['attribs']['value_unchecked'] = '0'; */
|
||||||
|
|
||||||
$params['type'] = 'radio';
|
$params['type'] = 'radio';
|
||||||
$params['options'] = [
|
$params['options'] = [
|
||||||
'1' => 'Yes',
|
'1' => 'Yes',
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
namespace Aviat\AnimeClient\Model;
|
namespace Aviat\AnimeClient\Model;
|
||||||
|
|
||||||
|
use function Aviat\AnimeClient\arrayToToml;
|
||||||
|
use function Aviat\Ion\_dir;
|
||||||
|
|
||||||
use Aviat\AnimeClient\Types\{Config, UndefinedPropertyException};
|
use Aviat\AnimeClient\Types\{Config, UndefinedPropertyException};
|
||||||
|
|
||||||
use Aviat\Ion\ConfigInterface;
|
use Aviat\Ion\ConfigInterface;
|
||||||
@ -36,7 +39,12 @@ final class Settings {
|
|||||||
*/
|
*/
|
||||||
private const SETTINGS_MAP = [
|
private const SETTINGS_MAP = [
|
||||||
'anilist' => [
|
'anilist' => [
|
||||||
|
'enabled' => [
|
||||||
|
'type' => 'boolean',
|
||||||
|
'title' => 'Enable Anilist Integration',
|
||||||
|
'default' => FALSE,
|
||||||
|
'description' => 'Enable syncing data between Kitsu and Anilist. Requires appropriate API keys to be set in config',
|
||||||
|
],
|
||||||
],
|
],
|
||||||
'config' => [
|
'config' => [
|
||||||
'kitsu_username' => [
|
'kitsu_username' => [
|
||||||
@ -265,22 +273,88 @@ final class Settings {
|
|||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function validateSettings(array $settings): bool
|
public function validateSettings(array $settings)
|
||||||
{
|
{
|
||||||
|
$config = (new Config($settings))->toArray();
|
||||||
|
|
||||||
|
$looseConfig = [];
|
||||||
|
$keyedConfig = [];
|
||||||
|
|
||||||
|
// Convert 'boolean' values to true and false
|
||||||
|
// Also order keys so they can be saved properly
|
||||||
|
foreach ($config as $key => $val)
|
||||||
|
{
|
||||||
|
if (is_scalar($val))
|
||||||
|
{
|
||||||
|
if ($val === '1')
|
||||||
|
{
|
||||||
|
$looseConfig[$key] = TRUE;
|
||||||
|
}
|
||||||
|
elseif ($val === '0')
|
||||||
|
{
|
||||||
|
$looseConfig[$key] = FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$looseConfig[$key] = $val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif (is_array($val))
|
||||||
|
{
|
||||||
|
foreach($val as $k => $v)
|
||||||
|
{
|
||||||
|
if ($v === '1')
|
||||||
|
{
|
||||||
|
$keyedConfig[$key][$k] = TRUE;
|
||||||
|
}
|
||||||
|
elseif($v === '0')
|
||||||
|
{
|
||||||
|
$keyedConfig[$key][$k] = FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$keyedConfig[$key][$k] = $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ksort($looseConfig);
|
||||||
|
ksort($keyedConfig);
|
||||||
|
|
||||||
|
$output = [];
|
||||||
|
|
||||||
|
foreach($looseConfig as $k => $v)
|
||||||
|
{
|
||||||
|
$output[$k] = $v;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($keyedConfig as $k => $v)
|
||||||
|
{
|
||||||
|
$output[$k] = $v;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function saveSettingsFile(array $settings): bool
|
||||||
|
{
|
||||||
|
$settings = $settings['config'];
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
new Config($settings);
|
$settings = $this->validateSettings($settings);
|
||||||
}
|
}
|
||||||
catch (UndefinedPropertyException $e)
|
catch (UndefinedPropertyException $e)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
$savePath = realpath(_dir(__DIR__, '..', '..', 'app', 'config'));
|
||||||
}
|
$saveFile = _dir($savePath, 'admin-override.toml');
|
||||||
|
|
||||||
public function saveSettingsFile()
|
$saved = file_put_contents($saveFile, arrayToToml($settings));
|
||||||
{
|
|
||||||
|
|
||||||
|
return $saved !== FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
6
sw.js
6
sw.js
@ -61,6 +61,12 @@ self.addEventListener('activate', event => {
|
|||||||
|
|
||||||
// Pull css, images, and javascript from cache
|
// Pull css, images, and javascript from cache
|
||||||
self.addEventListener('fetch', event => {
|
self.addEventListener('fetch', event => {
|
||||||
|
// Only cache things with a file extension,
|
||||||
|
// Ignore other requests
|
||||||
|
if ( ! event.request.url.includes('/public/')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
fromCache(event.request).then(cached => {
|
fromCache(event.request).then(cached => {
|
||||||
if (cached !== undefined) {
|
if (cached !== undefined) {
|
||||||
event.respondWith(cached);
|
event.respondWith(cached);
|
||||||
|
Loading…
Reference in New Issue
Block a user