Config class overhaul.
This commit is contained in:
parent
cecfaf4852
commit
2f7cddde19
30 changed files with 838 additions and 396 deletions
|
@ -36,10 +36,13 @@
|
||||||
.manage-list-setting-type--string {
|
.manage-list-setting-type--string {
|
||||||
--type-colour: #ef8323;
|
--type-colour: #ef8323;
|
||||||
}
|
}
|
||||||
.manage-list-setting-type--integer {
|
.manage-list-setting-type--int {
|
||||||
--type-colour: #8c90bc;
|
--type-colour: #8c90bc;
|
||||||
}
|
}
|
||||||
.manage-list-setting-type--boolean {
|
.manage-list-setting-type--float {
|
||||||
|
--type-colour: #cb09c8;
|
||||||
|
}
|
||||||
|
.manage-list-setting-type--bool {
|
||||||
--type-colour: #77b34c;
|
--type-colour: #77b34c;
|
||||||
}
|
}
|
||||||
.manage-list-setting-type--array {
|
.manage-list-setting-type--array {
|
||||||
|
|
62
misuzu.php
62
misuzu.php
|
@ -5,7 +5,6 @@ use Index\Autoloader;
|
||||||
use Index\Environment;
|
use Index\Environment;
|
||||||
use Index\Data\ConnectionFailedException;
|
use Index\Data\ConnectionFailedException;
|
||||||
use Index\Data\DbTools;
|
use Index\Data\DbTools;
|
||||||
use Misuzu\Config\IConfig;
|
|
||||||
use Misuzu\Config\DbConfig;
|
use Misuzu\Config\DbConfig;
|
||||||
use Misuzu\Users\User;
|
use Misuzu\Users\User;
|
||||||
use Misuzu\Users\UserNotFoundException;
|
use Misuzu\Users\UserNotFoundException;
|
||||||
|
@ -47,7 +46,7 @@ set_exception_handler(function(\Throwable $ex) {
|
||||||
header('Content-Type: text/plain; charset=utf-8');
|
header('Content-Type: text/plain; charset=utf-8');
|
||||||
echo (string)$ex;
|
echo (string)$ex;
|
||||||
} else {
|
} else {
|
||||||
header('Content-Type: text/html; charset-utf-8');
|
header('Content-Type: text/html; charset=utf-8');
|
||||||
echo file_get_contents(MSZ_TEMPLATES . '/500.html');
|
echo file_get_contents(MSZ_TEMPLATES . '/500.html');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,24 +82,8 @@ DB::init(DbTools::parse($dbConfig['dsn']));
|
||||||
DB::exec(MSZ_DB_INIT);
|
DB::exec(MSZ_DB_INIT);
|
||||||
|
|
||||||
$cfg = new DbConfig($db);
|
$cfg = new DbConfig($db);
|
||||||
$cfg->reload();
|
|
||||||
|
|
||||||
Config::init($cfg);
|
Mailer::init($cfg->scopeTo('mail'));
|
||||||
|
|
||||||
Mailer::init($cfg->getValue('mail.method', IConfig::T_STR), [
|
|
||||||
'host' => $cfg->getValue('mail.host', IConfig::T_STR),
|
|
||||||
'port' => $cfg->getValue('mail.port', IConfig::T_INT, 25),
|
|
||||||
'username' => $cfg->getValue('mail.username', IConfig::T_STR),
|
|
||||||
'password' => $cfg->getValue('mail.password', IConfig::T_STR),
|
|
||||||
'encryption' => $cfg->getValue('mail.encryption', IConfig::T_STR),
|
|
||||||
'sender_name' => $cfg->getValue('mail.sender.name', IConfig::T_STR),
|
|
||||||
'sender_addr' => $cfg->getValue('mail.sender.address', IConfig::T_STR),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// replace this with a better storage mechanism
|
|
||||||
define('MSZ_STORAGE', $cfg->getValue('storage.path', IConfig::T_STR, MSZ_ROOT . '/store'));
|
|
||||||
if(!is_dir(MSZ_STORAGE))
|
|
||||||
mkdir(MSZ_STORAGE, 0775, true);
|
|
||||||
|
|
||||||
$msz = new MisuzuContext($db, $cfg);
|
$msz = new MisuzuContext($db, $cfg);
|
||||||
|
|
||||||
|
@ -115,17 +98,12 @@ ob_start();
|
||||||
if(file_exists(MSZ_ROOT . '/.migrating')) {
|
if(file_exists(MSZ_ROOT . '/.migrating')) {
|
||||||
http_response_code(503);
|
http_response_code(503);
|
||||||
if(!isset($_GET['_check'])) {
|
if(!isset($_GET['_check'])) {
|
||||||
header('Content-Type: text/html; charset-utf-8');
|
header('Content-Type: text/html; charset=utf-8');
|
||||||
echo file_get_contents(MSZ_TEMPLATES . '/503.html');
|
echo file_get_contents(MSZ_TEMPLATES . '/503.html');
|
||||||
}
|
}
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!is_readable(MSZ_STORAGE) || !is_writable(MSZ_STORAGE)) {
|
|
||||||
echo 'Cannot access storage directory.';
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!MSZ_DEBUG) {
|
if(!MSZ_DEBUG) {
|
||||||
$twigCacheDirSfx = GitInfo::hash(true);
|
$twigCacheDirSfx = GitInfo::hash(true);
|
||||||
if(empty($twigCacheDirSfx))
|
if(empty($twigCacheDirSfx))
|
||||||
|
@ -136,16 +114,27 @@ if(!MSZ_DEBUG) {
|
||||||
mkdir($twigCache, 0775, true);
|
mkdir($twigCache, 0775, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$globals = $cfg->getValues([
|
||||||
|
['site.name:s', 'Misuzu'],
|
||||||
|
'site.desc:s',
|
||||||
|
'site.url:s',
|
||||||
|
'sockChat.chatPath.normal:s',
|
||||||
|
'eeprom.path:s',
|
||||||
|
'eeprom.app:s',
|
||||||
|
['auth.secret:s', 'meow'],
|
||||||
|
['csrf.secret:s', 'soup'],
|
||||||
|
]);
|
||||||
|
|
||||||
Template::init($msz, $twigCache ?? null, MSZ_DEBUG);
|
Template::init($msz, $twigCache ?? null, MSZ_DEBUG);
|
||||||
|
|
||||||
Template::set('globals', [
|
Template::set('globals', [
|
||||||
'site_name' => $cfg->getValue('site.name', IConfig::T_STR, 'Misuzu'),
|
'site_name' => $globals['site.name'],
|
||||||
'site_description' => $cfg->getValue('site.desc', IConfig::T_STR),
|
'site_description' => $globals['site.desc'],
|
||||||
'site_url' => $cfg->getValue('site.url', IConfig::T_STR),
|
'site_url' => $globals['site.url'],
|
||||||
'site_chat' => $cfg->getValue('sockChat.chatPath.normal', IConfig::T_STR),
|
'site_chat' => $globals['sockChat.chatPath.normal'],
|
||||||
'eeprom' => [
|
'eeprom' => [
|
||||||
'path' => $cfg->getValue('eeprom.path', IConfig::T_STR),
|
'path' => $globals['eeprom.path'],
|
||||||
'app' => $cfg->getValue('eeprom.app', IConfig::T_STR),
|
'app' => $globals['eeprom.app'],
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -156,7 +145,7 @@ unset($mszAssetsInfo);
|
||||||
|
|
||||||
Template::addPath(MSZ_TEMPLATES);
|
Template::addPath(MSZ_TEMPLATES);
|
||||||
|
|
||||||
AuthToken::setSecretKey($cfg->getValue('auth.secret', IConfig::T_STR, 'meow'));
|
AuthToken::setSecretKey($globals['auth.secret']);
|
||||||
|
|
||||||
if(isset($_COOKIE['msz_uid']) && isset($_COOKIE['msz_sid'])) {
|
if(isset($_COOKIE['msz_uid']) && isset($_COOKIE['msz_sid'])) {
|
||||||
$authToken = new AuthToken;
|
$authToken = new AuthToken;
|
||||||
|
@ -220,22 +209,21 @@ if($authToken->isValid()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
CSRF::init(
|
CSRF::init(
|
||||||
$cfg->getValue('csrf.secret', IConfig::T_STR, 'soup'),
|
$globals['csrf.secret'],
|
||||||
(UserSession::hasCurrent() ? UserSession::getCurrent()->getToken() : ($_SERVER['REMOTE_ADDR'] ?? '::1'))
|
(UserSession::hasCurrent() ? UserSession::getCurrent()->getToken() : ($_SERVER['REMOTE_ADDR'] ?? '::1'))
|
||||||
);
|
);
|
||||||
|
|
||||||
function mszLockdown(): void {
|
function mszLockdown(): void {
|
||||||
global $misuzuBypassLockdown, $cfg;
|
global $misuzuBypassLockdown, $cfg;
|
||||||
|
|
||||||
if($cfg->getValue('private.enabled', IConfig::T_BOOL)) {
|
if($cfg->getBoolean('private.enabled')) {
|
||||||
$onLoginPage = $_SERVER['PHP_SELF'] === url('auth-login');
|
$onLoginPage = $_SERVER['PHP_SELF'] === url('auth-login');
|
||||||
$onPasswordPage = parse_url($_SERVER['PHP_SELF'], PHP_URL_PATH) === url('auth-forgot');
|
$onPasswordPage = parse_url($_SERVER['PHP_SELF'], PHP_URL_PATH) === url('auth-forgot');
|
||||||
$misuzuBypassLockdown = !empty($misuzuBypassLockdown) || $onLoginPage;
|
$misuzuBypassLockdown = !empty($misuzuBypassLockdown) || $onLoginPage;
|
||||||
|
|
||||||
if(!$misuzuBypassLockdown) {
|
if(!$misuzuBypassLockdown) {
|
||||||
if(UserSession::hasCurrent()) {
|
if(UserSession::hasCurrent()) {
|
||||||
$privatePermCat = $cfg->getValue('private.perm.cat', IConfig::T_STR);
|
['private.perm.cat' => $privatePermCat, 'private.perm.val' => $privatePermVal] = $cfg->getValues(['private.perm.cat:s', 'private.perm.val:i']);
|
||||||
$privatePermVal = $cfg->getValue('private.perm.val', IConfig::T_INT);
|
|
||||||
|
|
||||||
if(!empty($privatePermCat) && $privatePermVal > 0) {
|
if(!empty($privatePermCat) && $privatePermVal > 0) {
|
||||||
if(!perms_check_user($privatePermCat, User::getCurrent()->getId(), $privatePermVal)) {
|
if(!perms_check_user($privatePermCat, User::getCurrent()->getId(), $privatePermVal)) {
|
||||||
|
@ -244,7 +232,7 @@ function mszLockdown(): void {
|
||||||
User::unsetCurrent();
|
User::unsetCurrent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} elseif(!$onLoginPage && !($onPasswordPage && $cfg->getValue('private.allow_password_reset', IConfig::T_BOOL, true))) {
|
} elseif(!$onLoginPage && !($onPasswordPage && $cfg->getBoolean('private.allow_password_reset', true))) {
|
||||||
url_redirect('auth-login');
|
url_redirect('auth-login');
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
namespace Misuzu;
|
namespace Misuzu;
|
||||||
|
|
||||||
use Misuzu\AuthToken;
|
use Misuzu\AuthToken;
|
||||||
use Misuzu\Config\IConfig;
|
|
||||||
use Misuzu\Users\User;
|
use Misuzu\Users\User;
|
||||||
use Misuzu\Users\UserNotFoundException;
|
use Misuzu\Users\UserNotFoundException;
|
||||||
use Misuzu\Users\UserAuthSession;
|
use Misuzu\Users\UserAuthSession;
|
||||||
|
@ -43,11 +42,28 @@ if(!empty($_GET['resolve'])) {
|
||||||
$notices = [];
|
$notices = [];
|
||||||
$ipAddress = $_SERVER['REMOTE_ADDR'];
|
$ipAddress = $_SERVER['REMOTE_ADDR'];
|
||||||
$countryCode = $_SERVER['COUNTRY_CODE'] ?? 'XX';
|
$countryCode = $_SERVER['COUNTRY_CODE'] ?? 'XX';
|
||||||
$siteIsPrivate = $cfg->getValue('private.enable', IConfig::T_BOOL);
|
|
||||||
$loginPermCat = $siteIsPrivate ? $cfg->getValue('private.perm.cat', IConfig::T_STR) : '';
|
|
||||||
$loginPermVal = $siteIsPrivate ? $cfg->getValue('private.perm.val', IConfig::T_INT) : 0;
|
|
||||||
$remainingAttempts = UserLoginAttempt::remaining($ipAddress);
|
$remainingAttempts = UserLoginAttempt::remaining($ipAddress);
|
||||||
|
|
||||||
|
$siteIsPrivate = $cfg->getBoolean('private.enable');
|
||||||
|
if($siteIsPrivate) {
|
||||||
|
[
|
||||||
|
'private.perm.cat' => $loginPermCat,
|
||||||
|
'private.perm.val' => $loginPermVal,
|
||||||
|
'private.msg' => $sitePrivateMessage,
|
||||||
|
'private.allow_password_reset' => $canResetPassword,
|
||||||
|
] = $cfg->getValues([
|
||||||
|
'private.perm.cat:s',
|
||||||
|
'private.perm.val:i',
|
||||||
|
'private.msg:s',
|
||||||
|
['private.allow_password_reset:b', true],
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$loginPermCat = '';
|
||||||
|
$loginPermVal = 0;
|
||||||
|
$sitePrivateMessage = '';
|
||||||
|
$canResetPassword = true;
|
||||||
|
}
|
||||||
|
|
||||||
while(!empty($_POST['login']) && is_array($_POST['login'])) {
|
while(!empty($_POST['login']) && is_array($_POST['login'])) {
|
||||||
if(!CSRF::validateRequest()) {
|
if(!CSRF::validateRequest()) {
|
||||||
$notices[] = 'Was unable to verify the request, please try again!';
|
$notices[] = 'Was unable to verify the request, please try again!';
|
||||||
|
@ -134,8 +150,6 @@ $loginUsername = !empty($_POST['login']['username']) && is_string($_POST['login'
|
||||||
!empty($_GET['username']) && is_string($_GET['username']) ? $_GET['username'] : ''
|
!empty($_GET['username']) && is_string($_GET['username']) ? $_GET['username'] : ''
|
||||||
);
|
);
|
||||||
$loginRedirect = $welcomeMode ? url('index') : (!empty($_GET['redirect']) && is_string($_GET['redirect']) ? $_GET['redirect'] : null) ?? $_SERVER['HTTP_REFERER'] ?? url('index');
|
$loginRedirect = $welcomeMode ? url('index') : (!empty($_GET['redirect']) && is_string($_GET['redirect']) ? $_GET['redirect'] : null) ?? $_SERVER['HTTP_REFERER'] ?? url('index');
|
||||||
$sitePrivateMessage = $siteIsPrivate ? $cfg->getValue('private.msg', IConfig::T_STR) : '';
|
|
||||||
$canResetPassword = $siteIsPrivate ? $cfg->getValue('private.allow_password_reset', IConfig::T_BOOL, true) : true;
|
|
||||||
$canRegisterAccount = !$siteIsPrivate;
|
$canRegisterAccount = !$siteIsPrivate;
|
||||||
|
|
||||||
Template::render('auth.login', [
|
Template::render('auth.login', [
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu;
|
namespace Misuzu;
|
||||||
|
|
||||||
use Misuzu\Config\IConfig;
|
|
||||||
use Misuzu\Users\User;
|
use Misuzu\Users\User;
|
||||||
use Misuzu\Users\UserNotFoundException;
|
use Misuzu\Users\UserNotFoundException;
|
||||||
use Misuzu\Users\UserLoginAttempt;
|
use Misuzu\Users\UserLoginAttempt;
|
||||||
|
@ -33,8 +32,8 @@ if($userId > 0)
|
||||||
|
|
||||||
$notices = [];
|
$notices = [];
|
||||||
$ipAddress = $_SERVER['REMOTE_ADDR'];
|
$ipAddress = $_SERVER['REMOTE_ADDR'];
|
||||||
$siteIsPrivate = $cfg->getValue('private.enable', IConfig::T_BOOL);
|
$siteIsPrivate = $cfg->getBoolean('private.enable');
|
||||||
$canResetPassword = $siteIsPrivate ? $cfg->getValue('private.allow_password_reset', IConfig::T_BOOL, true) : true;
|
$canResetPassword = $siteIsPrivate ? $cfg->getBoolean('private.allow_password_reset', true) : true;
|
||||||
$remainingAttempts = UserLoginAttempt::remaining($ipAddress);
|
$remainingAttempts = UserLoginAttempt::remaining($ipAddress);
|
||||||
|
|
||||||
while($canResetPassword) {
|
while($canResetPassword) {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu;
|
namespace Misuzu;
|
||||||
|
|
||||||
use Misuzu\Config\IConfig;
|
|
||||||
use Misuzu\Users\User;
|
use Misuzu\Users\User;
|
||||||
|
|
||||||
require_once '../../misuzu.php';
|
require_once '../../misuzu.php';
|
||||||
|
@ -21,8 +20,16 @@ $leaderboardIdLength = strlen($leaderboardId);
|
||||||
$leaderboardYear = $leaderboardIdLength === 4 || $leaderboardIdLength === 6 ? substr($leaderboardId, 0, 4) : null;
|
$leaderboardYear = $leaderboardIdLength === 4 || $leaderboardIdLength === 6 ? substr($leaderboardId, 0, 4) : null;
|
||||||
$leaderboardMonth = $leaderboardIdLength === 6 ? substr($leaderboardId, 4, 2) : null;
|
$leaderboardMonth = $leaderboardIdLength === 6 ? substr($leaderboardId, 4, 2) : null;
|
||||||
|
|
||||||
$unrankedForums = !empty($_GET['allow_unranked']) ? [] : $cfg->getValue('forum_leader.unranked.forum', IConfig::T_ARR);
|
if(empty($_GET['allow_unranked'])) {
|
||||||
$unrankedTopics = !empty($_GET['allow_unranked']) ? [] : $cfg->getValue('forum_leader.unranked.topic', IConfig::T_ARR);
|
[
|
||||||
|
'forum_leader.unranked.forum' => $unrankedForums,
|
||||||
|
'forum_leader.unranked.topic' => $unrankedTopics,
|
||||||
|
] = $cfg->getValues([
|
||||||
|
'forum_leader.unranked.forum:a',
|
||||||
|
'forum_leader.unranked.topic:a',
|
||||||
|
]);
|
||||||
|
} else $unrankedForums = $unrankedTopics = [];
|
||||||
|
|
||||||
$leaderboards = forum_leaderboard_categories();
|
$leaderboards = forum_leaderboard_categories();
|
||||||
$leaderboard = forum_leaderboard_listing($leaderboardYear, $leaderboardMonth, $unrankedForums, $unrankedTopics);
|
$leaderboard = forum_leaderboard_listing($leaderboardYear, $leaderboardMonth, $unrankedForums, $unrankedTopics);
|
||||||
|
|
||||||
|
@ -31,9 +38,8 @@ $leaderboardName = 'All Time';
|
||||||
if($leaderboardYear) {
|
if($leaderboardYear) {
|
||||||
$leaderboardName = "Leaderboard {$leaderboardYear}";
|
$leaderboardName = "Leaderboard {$leaderboardYear}";
|
||||||
|
|
||||||
if($leaderboardMonth) {
|
if($leaderboardMonth)
|
||||||
$leaderboardName .= "-{$leaderboardMonth}";
|
$leaderboardName .= "-{$leaderboardMonth}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if($leaderboardMode === 'markdown') {
|
if($leaderboardMode === 'markdown') {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu;
|
namespace Misuzu;
|
||||||
|
|
||||||
use Misuzu\Config;
|
|
||||||
use Misuzu\Config\CfgTools;
|
use Misuzu\Config\CfgTools;
|
||||||
use Misuzu\Users\User;
|
use Misuzu\Users\User;
|
||||||
|
|
||||||
|
@ -13,25 +12,21 @@ if(!User::hasCurrent()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$sName = (string)filter_input(INPUT_GET, 'name');
|
$valueName = (string)filter_input(INPUT_GET, 'name');
|
||||||
if(!CfgTools::validateName($sName) || !$cfg->hasValue($sName))
|
$valueInfo = $cfg->getValueInfo($valueName);
|
||||||
throw new \Exception("Config value does not exist.");
|
if($valueInfo === null) {
|
||||||
|
echo render_error(404);
|
||||||
if($_SERVER['REQUEST_METHOD'] === 'POST') {
|
return;
|
||||||
if(!CSRF::validateRequest())
|
|
||||||
throw new \Exception("Request verification failed.");
|
|
||||||
|
|
||||||
$msz->createAuditLog('CONFIG_DELETE', [$sName]);
|
|
||||||
$cfg->removeValue($sName);
|
|
||||||
url_redirect('manage-general-settings');
|
|
||||||
} else {
|
|
||||||
$sValue = $cfg->getValue($sName);
|
|
||||||
|
|
||||||
Template::render('manage.general.setting-delete', [
|
|
||||||
'conf_var' => [
|
|
||||||
'name' => $sName,
|
|
||||||
'type' => CfgTools::type($sValue),
|
|
||||||
'value' => $sValue,
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
|
||||||
|
$valueName = $valueInfo->getName();
|
||||||
|
$msz->createAuditLog('CONFIG_DELETE', [$valueName]);
|
||||||
|
$cfg->removeValues($valueName);
|
||||||
|
url_redirect('manage-general-settings');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Template::render('manage.general.setting-delete', [
|
||||||
|
'config_value' => $valueInfo,
|
||||||
|
]);
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu;
|
namespace Misuzu;
|
||||||
|
|
||||||
use Misuzu\Config;
|
use Misuzu\Config\DbConfig;
|
||||||
use Misuzu\Config\CfgTools;
|
|
||||||
use Misuzu\Config\IConfig;
|
|
||||||
use Misuzu\Users\User;
|
use Misuzu\Users\User;
|
||||||
|
|
||||||
require_once '../../../misuzu.php';
|
require_once '../../../misuzu.php';
|
||||||
|
@ -14,105 +12,84 @@ if(!User::hasCurrent()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$sVar = [
|
$isNew = true;
|
||||||
'name' => '',
|
|
||||||
'type' => '',
|
|
||||||
'value' => null,
|
|
||||||
'new' => true,
|
|
||||||
];
|
|
||||||
|
|
||||||
$sName = (string)filter_input(INPUT_GET, 'name');
|
$sName = (string)filter_input(INPUT_GET, 'name');
|
||||||
|
$sType = (string)filter_input(INPUT_GET, 'type');
|
||||||
|
$sValue = null;
|
||||||
|
$loadValueInfo = fn() => $cfg->getValueInfo($sName);
|
||||||
|
|
||||||
if(!empty($sName)) {
|
if(!empty($sName)) {
|
||||||
if(!CfgTools::validateName($sName))
|
$sInfo = $loadValueInfo();
|
||||||
throw new \Exception("Config key name has invalid format.");
|
if($sInfo !== null) {
|
||||||
|
$isNew = false;
|
||||||
$sVar['name'] = $sName;
|
$sName = $sInfo->getName();
|
||||||
|
$sType = $sInfo->getType();
|
||||||
|
$sValue = $sInfo->getValue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$sType = (string)filter_input(INPUT_GET, 'type');
|
while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
|
||||||
if(!empty($sType)) {
|
if($isNew) {
|
||||||
if(!CfgTools::isValidType($sType))
|
$sName = trim((string)filter_input(INPUT_POST, 'conf_name'));
|
||||||
throw new \Exception("Specified type is invalid.");
|
if(!DbConfig::validateName($sName)) {
|
||||||
|
echo 'Name contains invalid characters.';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
$sVar['type'] = $sType;
|
$sType = trim((string)filter_input(INPUT_POST, 'conf_type'));
|
||||||
$sVar['value'] = CfgTools::default($sType);
|
if(!in_array($sType, ['string', 'int', 'float', 'bool', 'array'])) {
|
||||||
}
|
echo 'Invalid type specified.';
|
||||||
|
break;
|
||||||
if($_SERVER['REQUEST_METHOD'] === 'POST') {
|
}
|
||||||
if(!CSRF::validateRequest())
|
|
||||||
throw new \Exception("Request verification failed.");
|
|
||||||
|
|
||||||
if(empty($sName)) {
|
|
||||||
$sName = (string)filter_input(INPUT_POST, 'conf_name');
|
|
||||||
|
|
||||||
if(empty($sName) || !CfgTools::validateName($sName))
|
|
||||||
throw new \Exception("Config key name has invalid format.");
|
|
||||||
|
|
||||||
$sVar['name'] = $sName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$sLogAction = 'CONFIG_CREATE';
|
|
||||||
|
|
||||||
if($cfg->hasValue($sName)) {
|
|
||||||
$sType = CfgTools::type($cfg->getValue($sName));
|
|
||||||
$sVar['new'] = false;
|
|
||||||
$sLogAction = 'CONFIG_UPDATE';
|
|
||||||
} elseif(empty($sType)) {
|
|
||||||
$sType = (string)filter_input(INPUT_POST, 'conf_type');
|
|
||||||
if(empty($sType) || !CfgTools::isValidType($sType))
|
|
||||||
throw new \Exception("Specified type is invalid.");
|
|
||||||
}
|
|
||||||
|
|
||||||
$sVar['type'] = $sType;
|
|
||||||
|
|
||||||
$sValue = CfgTools::default($sType);
|
|
||||||
|
|
||||||
if($sType === 'array') {
|
if($sType === 'array') {
|
||||||
if(!empty($_POST['conf_value']) && is_array($_POST['conf_value'])) {
|
$applyFunc = $cfg->setArray(...);
|
||||||
foreach($_POST['conf_value'] as $fv) {
|
$sValue = [];
|
||||||
$fv = (string)$fv;
|
$sRaw = filter_input(INPUT_POST, 'conf_value', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
|
||||||
|
foreach($sRaw as $rValue) {
|
||||||
if(str_starts_with($fv, 's:')) {
|
if(strpos($rValue, ':') === 1) {
|
||||||
$fv = substr($fv, 2);
|
$rType = $rValue[0];
|
||||||
} elseif(str_starts_with($fv, 'i:')) {
|
$rValue = substr($rValue, 2);
|
||||||
$fv = (int)substr($fv, 2);
|
$sValue[] = match($rType) {
|
||||||
} elseif(str_starts_with($fv, 'b:')) {
|
's' => $rValue,
|
||||||
$fv = strtolower(substr($fv, 2));
|
'i' => (int)$rValue,
|
||||||
$fv = $fv !== 'false' && $fv !== '0' && $fv !== '';
|
'd' => (float)$rValue,
|
||||||
}
|
'f' => (float)$rValue,
|
||||||
|
'b' => $rValue !== 'false' && $rValue !== '0' && $rValue !== '',
|
||||||
$sValue[] = $fv;
|
default => '',
|
||||||
}
|
};
|
||||||
|
} else
|
||||||
|
$sValue[] = $rValue;
|
||||||
}
|
}
|
||||||
} elseif($sType === 'boolean') {
|
} elseif($sType === 'bool') {
|
||||||
$sValue = !empty($_POST['conf_value']);
|
$sValue = !empty($_POST['conf_value']);
|
||||||
|
$applyFunc = $cfg->setBoolean(...);
|
||||||
} else {
|
} else {
|
||||||
$sValue = (string)filter_input(INPUT_POST, 'conf_value');
|
$sValue = filter_input(INPUT_POST, 'conf_value');
|
||||||
if($sType === 'integer')
|
if($sType === 'int') {
|
||||||
|
$applyFunc = $cfg->setInteger(...);
|
||||||
$sValue = (int)$sValue;
|
$sValue = (int)$sValue;
|
||||||
|
} elseif($sType === 'float') {
|
||||||
|
$applyFunc = $cfg->setFloat(...);
|
||||||
|
$sValue = (float)$sValue;
|
||||||
|
} else
|
||||||
|
$applyFunc = $cfg->setString(...);
|
||||||
}
|
}
|
||||||
|
|
||||||
$sVar['value'] = $sValue;
|
$msz->createAuditLog($isNew ? 'CONFIG_CREATE' : 'CONFIG_UPDATE', [$sName]);
|
||||||
|
$applyFunc($sName, $sValue);
|
||||||
$msz->createAuditLog($sLogAction, [$sName]);
|
|
||||||
$cfg->setValue($sName, $sValue);
|
|
||||||
url_redirect('manage-general-settings');
|
url_redirect('manage-general-settings');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($cfg->hasValue($sName)) {
|
if($sType === 'array' && !empty($sValue))
|
||||||
$sVar['new'] = false;
|
foreach($sValue as $key => $value)
|
||||||
$sValue = $cfg->getValue($sName);
|
$sValue[$key] = gettype($value)[0] . ':' . $value;
|
||||||
$sVar['type'] = $sType = CfgTools::type($sValue);
|
|
||||||
|
|
||||||
if($sType === IConfig::T_ARR)
|
|
||||||
foreach($sValue as $fk => $fv)
|
|
||||||
$sValue[$fk] = ['integer' => 'i', 'string' => 's', 'boolean' => 'b'][gettype($fv)] . ':' . $fv;
|
|
||||||
|
|
||||||
$sVar['value'] = $sValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Template::render('manage.general.setting', [
|
Template::render('manage.general.setting', [
|
||||||
'conf_var' => $sVar,
|
'config_new' => $isNew,
|
||||||
|
'config_name' => $sName,
|
||||||
|
'config_type' => $sType,
|
||||||
|
'config_value' => $sValue,
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu;
|
namespace Misuzu;
|
||||||
|
|
||||||
use Misuzu\Config;
|
|
||||||
use Misuzu\Config\CfgTools;
|
|
||||||
use Misuzu\Config\IConfig;
|
|
||||||
use Misuzu\Users\User;
|
use Misuzu\Users\User;
|
||||||
|
|
||||||
require_once '../../../misuzu.php';
|
require_once '../../../misuzu.php';
|
||||||
|
@ -14,18 +11,10 @@ if(!User::hasCurrent()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$hidden = $cfg->getValue('settings.hidden', IConfig::T_ARR, []);
|
$hidden = $cfg->getArray('settings.hidden');
|
||||||
|
$vars = $cfg->getAllValueInfos();
|
||||||
$vars = [];
|
|
||||||
foreach($cfg->getNames() as $key) {
|
|
||||||
$var = $cfg->getValue($key);
|
|
||||||
$vars[] = [
|
|
||||||
'key' => $key,
|
|
||||||
'type' => CfgTools::type($var),
|
|
||||||
'value' => in_array($key, $hidden) ? '*** hidden ***' : json_encode($var),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
Template::render('manage.general.settings', [
|
Template::render('manage.general.settings', [
|
||||||
'conf_vars' => $vars,
|
'config_vars' => $vars,
|
||||||
|
'config_hidden' => $hidden,
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu;
|
namespace Misuzu;
|
||||||
|
|
||||||
use Misuzu\Config;
|
|
||||||
use Misuzu\Config\IConfig;
|
|
||||||
use Misuzu\Users\User;
|
use Misuzu\Users\User;
|
||||||
use Misuzu\Users\UserRole;
|
use Misuzu\Users\UserRole;
|
||||||
use Misuzu\Users\UserRoleNotFoundException;
|
use Misuzu\Users\UserRoleNotFoundException;
|
||||||
|
@ -49,7 +47,7 @@ if(!$isRestricted && $isVerifiedRequest && !empty($_POST['role'])) {
|
||||||
if($isVerifiedRequest && isset($_POST['tfa']['enable']) && $currentUser->hasTOTP() !== (bool)$_POST['tfa']['enable']) {
|
if($isVerifiedRequest && isset($_POST['tfa']['enable']) && $currentUser->hasTOTP() !== (bool)$_POST['tfa']['enable']) {
|
||||||
if((bool)$_POST['tfa']['enable']) {
|
if((bool)$_POST['tfa']['enable']) {
|
||||||
$tfaKey = TOTP::generateKey();
|
$tfaKey = TOTP::generateKey();
|
||||||
$tfaIssuer = $cfg->getValue('site.name', IConfig::T_STR, 'Misuzu');
|
$tfaIssuer = $cfg->getString('site.name', 'Misuzu');
|
||||||
$tfaQrcode = (new QRCode(new QROptions([
|
$tfaQrcode = (new QRCode(new QROptions([
|
||||||
'version' => 5,
|
'version' => 5,
|
||||||
'outputType' => QRCode::OUTPUT_IMAGE_JPG,
|
'outputType' => QRCode::OUTPUT_IMAGE_JPG,
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace Misuzu;
|
|
||||||
|
|
||||||
use Misuzu\Config\IConfig;
|
|
||||||
|
|
||||||
final class Config {
|
|
||||||
private static IConfig $config;
|
|
||||||
|
|
||||||
public static function init(IConfig $config): void {
|
|
||||||
self::$config = $config;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function keys(): array {
|
|
||||||
return self::$config->getNames();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function get(string $key, string $type = IConfig::T_ANY, $default = null): mixed {
|
|
||||||
return self::$config->getValue($key, $type, $default);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function has(string $key): bool {
|
|
||||||
return self::$config->hasValue($key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function set(string $key, $value, bool $soft = false): void {
|
|
||||||
self::$config->setValue($key, $value, !$soft);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function remove(string $key, bool $soft = false): void {
|
|
||||||
self::$config->removeValue($key, !$soft);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace Misuzu\Config;
|
|
||||||
|
|
||||||
final class CfgTools {
|
|
||||||
public static function type($value): string {
|
|
||||||
return gettype($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function isValidType(string $type): bool {
|
|
||||||
return $type === IConfig::T_ARR
|
|
||||||
|| $type === IConfig::T_BOOL
|
|
||||||
|| $type === IConfig::T_INT
|
|
||||||
|| $type === IConfig::T_STR;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function validateName(string $name): bool {
|
|
||||||
// this should better validate the format, this allows for a lot of shittery
|
|
||||||
return preg_match('#^([a-z][a-zA-Z0-9._]+)$#', $name) === 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private const DEFAULTS = [
|
|
||||||
IConfig::T_ANY => null,
|
|
||||||
IConfig::T_STR => '',
|
|
||||||
IConfig::T_INT => 0,
|
|
||||||
IConfig::T_BOOL => false,
|
|
||||||
IConfig::T_ARR => [],
|
|
||||||
];
|
|
||||||
|
|
||||||
public static function default(string $type) {
|
|
||||||
return self::DEFAULTS[$type] ?? null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,78 +1,327 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\Config;
|
namespace Misuzu\Config;
|
||||||
|
|
||||||
|
use RuntimeException;
|
||||||
|
use InvalidArgumentException;
|
||||||
use Index\Data\DataException;
|
use Index\Data\DataException;
|
||||||
use Index\Data\IDbConnection;
|
use Index\Data\IDbConnection;
|
||||||
use Index\Data\IDbStatement;
|
use Index\Data\IDbStatement;
|
||||||
|
use Index\Data\IDbResult;
|
||||||
|
use Misuzu\DbStatementCache;
|
||||||
|
use Misuzu\Pagination;
|
||||||
|
|
||||||
class DbConfig implements IConfig {
|
class DbConfig implements IConfig {
|
||||||
private IDbConnection $dbConn;
|
private IDbConnection $dbConn;
|
||||||
|
private DbStatementCache $cache;
|
||||||
private array $values = [];
|
private array $values = [];
|
||||||
|
|
||||||
private ?IDbStatement $stmtSet = null;
|
|
||||||
private ?IDbStatement $stmtDelete = null;
|
|
||||||
|
|
||||||
public function __construct(IDbConnection $dbConn) {
|
public function __construct(IDbConnection $dbConn) {
|
||||||
$this->dbConn = $dbConn;
|
$this->dbConn = $dbConn;
|
||||||
|
$this->cache = new DbStatementCache($dbConn);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function reload(): void {
|
public static function validateName(string $name): bool {
|
||||||
$this->values = [];
|
// this should better validate the format, this allows for a lot of shittery
|
||||||
|
return preg_match('#^([a-z][a-zA-Z0-9._]+)$#', $name) === 1;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
private static function whereInList(int $count): string {
|
||||||
$result = $this->dbConn->query('SELECT config_name, config_value FROM msz_config;');
|
return implode(', ', array_fill(0, $count, '?'));
|
||||||
while($result->next())
|
}
|
||||||
$this->values[$result->getString(0)] = unserialize($result->getString(1));
|
|
||||||
} catch(DataException $ex) { }
|
public function reset(): void {
|
||||||
|
$this->values = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unload(string|array $names): void {
|
||||||
|
if(empty($names))
|
||||||
|
return;
|
||||||
|
if(is_string($names))
|
||||||
|
$names = [$names];
|
||||||
|
|
||||||
|
foreach($names as $name)
|
||||||
|
unset($this->values[$name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function scopeTo(string $prefix): IConfig {
|
public function scopeTo(string $prefix): IConfig {
|
||||||
return new ScopedConfig($this, $prefix);
|
return new ScopedConfig($this, $prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getNames(): array {
|
public function hasValues(string|array $names): bool {
|
||||||
return array_keys($this->values);
|
if(empty($names))
|
||||||
|
return true;
|
||||||
|
if(is_string($names))
|
||||||
|
$names = [$names];
|
||||||
|
|
||||||
|
$cachedNames = array_keys($this->values);
|
||||||
|
$names = array_diff($names, $cachedNames);
|
||||||
|
|
||||||
|
if(!empty($names)) {
|
||||||
|
// array_diff preserves keys, the for() later would fuck up without it
|
||||||
|
$names = array_values($names);
|
||||||
|
$nameCount = count($names);
|
||||||
|
|
||||||
|
$stmt = $this->cache->get(sprintf(
|
||||||
|
'SELECT COUNT(*) FROM msz_config WHERE config_name IN (%s)',
|
||||||
|
self::whereInList($nameCount)
|
||||||
|
));
|
||||||
|
for($i = 0; $i < $nameCount; ++$i)
|
||||||
|
$stmt->addParameter($i + 1, $names[$i]);
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
$result = $stmt->getResult();
|
||||||
|
if($result->next())
|
||||||
|
return $result->getInteger(0) >= $nameCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getValue(string $name, string $type = IConfig::T_ANY, $default = null): mixed {
|
public function removeValues(string|array $names): void {
|
||||||
$value = $this->values[$name] ?? null;
|
if(empty($names))
|
||||||
|
return;
|
||||||
|
if(is_string($names))
|
||||||
|
$names = [$names];
|
||||||
|
|
||||||
if($type !== IConfig::T_ANY && CfgTools::type($value) !== $type)
|
foreach($names as $name)
|
||||||
$value = null;
|
unset($this->values[$name]);
|
||||||
|
|
||||||
return $value ?? $default ?? CfgTools::default($type);
|
$nameCount = count($names);
|
||||||
|
$stmt = $this->cache->get(sprintf(
|
||||||
|
'DELETE FROM msz_config WHERE config_name IN (%s)',
|
||||||
|
self::whereInList($nameCount)
|
||||||
|
));
|
||||||
|
|
||||||
|
for($i = 0; $i < $nameCount; ++$i)
|
||||||
|
$stmt->addParameter($i + 1, $names[$i]);
|
||||||
|
|
||||||
|
$stmt->execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasValue(string $name): bool {
|
public function getAllValueInfos(?Pagination $pagination = null): array {
|
||||||
return array_key_exists($name, $this->values);
|
$this->reset();
|
||||||
|
$infos = [];
|
||||||
|
|
||||||
|
$hasPagination = $pagination !== null;
|
||||||
|
|
||||||
|
$query = 'SELECT config_name, config_value FROM msz_config';
|
||||||
|
if($hasPagination)
|
||||||
|
$query .= ' LIMIT ? RANGE ?';
|
||||||
|
|
||||||
|
$stmt = $this->cache->get($query);
|
||||||
|
if($hasPagination) {
|
||||||
|
$stmt->addParameter(1, $pagination->getRange());
|
||||||
|
$stmt->addParameter(2, $pagination->getOffset());
|
||||||
|
}
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
$result = $stmt->getResult();
|
||||||
|
|
||||||
|
while($result->next()) {
|
||||||
|
$name = $result->getString(0);
|
||||||
|
$infos[] = $this->values[$name] = new DbConfigValueInfo($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $infos;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setValue(string $name, $value, bool $save = true): void {
|
public function getValueInfos(string|array $names): array {
|
||||||
|
if(empty($names))
|
||||||
|
return [];
|
||||||
|
if(is_string($names))
|
||||||
|
$names = [$names];
|
||||||
|
|
||||||
|
$infos = [];
|
||||||
|
$skip = [];
|
||||||
|
|
||||||
|
foreach($names as $name)
|
||||||
|
if(array_key_exists($name, $this->values)) {
|
||||||
|
$infos[] = $this->values[$name];
|
||||||
|
$skip[] = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
$names = array_diff($names, $skip);
|
||||||
|
|
||||||
|
if(!empty($names)) {
|
||||||
|
// array_diff preserves keys, the for() later would fuck up without it
|
||||||
|
$names = array_values($names);
|
||||||
|
$nameCount = count($names);
|
||||||
|
|
||||||
|
$stmt = $this->cache->get(sprintf(
|
||||||
|
'SELECT config_name, config_value FROM msz_config WHERE config_name IN (%s)',
|
||||||
|
self::whereInList($nameCount)
|
||||||
|
));
|
||||||
|
for($i = 0; $i < $nameCount; ++$i)
|
||||||
|
$stmt->addParameter($i + 1, $names[$i]);
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
$result = $stmt->getResult();
|
||||||
|
while($result->next()) {
|
||||||
|
$name = $result->getString(0);
|
||||||
|
$infos[] = $this->values[$name] = new DbConfigValueInfo($result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $infos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getValueInfo(string $name): ?IConfigValueInfo {
|
||||||
|
$infos = $this->getValueInfos($name);
|
||||||
|
return empty($infos) ? null : $infos[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getValues(array $specs): array {
|
||||||
|
$names = [];
|
||||||
|
|
||||||
|
foreach($specs as $key => $spec) {
|
||||||
|
if(is_string($spec)) {
|
||||||
|
$name = $spec;
|
||||||
|
$default = null;
|
||||||
|
} elseif(is_array($spec) && !empty($spec)) {
|
||||||
|
$name = $spec[0];
|
||||||
|
$default = $spec[1] ?? null;
|
||||||
|
} else
|
||||||
|
throw new InvalidArgumentException('$specs array contains an invalid entry.');
|
||||||
|
|
||||||
|
if(($colon = strpos($name, ':')) !== false) {
|
||||||
|
$type = substr($name, $colon + 1, 1);
|
||||||
|
$name = substr($name, 0, $colon);
|
||||||
|
} else $type = '';
|
||||||
|
|
||||||
|
$names[] = $name;
|
||||||
|
$specs[$key] = [
|
||||||
|
'name' => $name,
|
||||||
|
'type' => $type,
|
||||||
|
'default' => $default,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$infos = $this->getValueInfos($names);
|
||||||
|
$results = [];
|
||||||
|
|
||||||
|
foreach($specs as $spec) {
|
||||||
|
foreach($infos as $infoTest)
|
||||||
|
if($infoTest->getName() === $spec['name']) {
|
||||||
|
$info = $infoTest;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isset($info)) {
|
||||||
|
$defaultValue = $spec['default'] ?? null;
|
||||||
|
if($spec['type'] !== '')
|
||||||
|
settype($defaultValue, match($spec['type']) {
|
||||||
|
's' => 'string',
|
||||||
|
'a' => 'array',
|
||||||
|
'i' => 'int',
|
||||||
|
'b' => 'bool',
|
||||||
|
'f' => 'float',
|
||||||
|
'd' => 'double',
|
||||||
|
default => throw new RuntimeException('Invalid type letter encountered.'),
|
||||||
|
});
|
||||||
|
|
||||||
|
$results[$spec['name']] = $defaultValue;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$results[$spec['name']] = match($spec['type']) {
|
||||||
|
's' => $info->getString(),
|
||||||
|
'a' => $info->getArray(),
|
||||||
|
'i' => $info->getInteger(),
|
||||||
|
'b' => $info->getBoolean(),
|
||||||
|
'f' => $info->getFloat(),
|
||||||
|
'd' => $info->getFloat(),
|
||||||
|
'' => $info->getValue(),
|
||||||
|
default => throw new RuntimeException('Unknown type encountered in $specs.'),
|
||||||
|
};
|
||||||
|
|
||||||
|
unset($info);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getString(string $name, string $default = ''): string {
|
||||||
|
$valueInfo = $this->getValueInfo($name);
|
||||||
|
return $valueInfo?->isString() ? $valueInfo->getString() : $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInteger(string $name, int $default = 0): int {
|
||||||
|
$valueInfo = $this->getValueInfo($name);
|
||||||
|
return $valueInfo?->isInteger() ? $valueInfo->getInteger() : $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFloat(string $name, float $default = 0): float {
|
||||||
|
$valueInfo = $this->getValueInfo($name);
|
||||||
|
return $valueInfo?->isFloat() ? $valueInfo->getFloat() : $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBoolean(string $name, bool $default = false): bool {
|
||||||
|
$valueInfo = $this->getValueInfo($name);
|
||||||
|
return $valueInfo?->isBoolean() ? $valueInfo->getBoolean() : $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getArray(string $name, array $default = []): array {
|
||||||
|
$valueInfo = $this->getValueInfo($name);
|
||||||
|
return $valueInfo?->isArray() ? $valueInfo->getArray() : $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function setValue(string $name, $value): void {
|
||||||
$this->values[$name] = $value;
|
$this->values[$name] = $value;
|
||||||
|
$value = serialize($value);
|
||||||
|
|
||||||
if($save) {
|
$stmt = $this->cache->get('REPLACE INTO msz_config (config_name, config_value) VALUES (?, ?)');
|
||||||
$value = serialize($value);
|
$stmt->addParameter(1, $name);
|
||||||
|
$stmt->addParameter(2, $value);
|
||||||
if($this->stmtSet === null)
|
$stmt->execute();
|
||||||
$this->stmtSet = $this->dbConn->prepare('REPLACE INTO msz_config (config_name, config_value) VALUES (?, ?)');
|
|
||||||
|
|
||||||
$this->stmtSet->reset();
|
|
||||||
$this->stmtSet->addParameter(1, $name);
|
|
||||||
$this->stmtSet->addParameter(2, $value);
|
|
||||||
$this->stmtSet->execute();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function removeValue(string $name, bool $save = true): void {
|
public function setValues(array $values): void {
|
||||||
unset($this->values[$name]);
|
if(empty($values))
|
||||||
|
return;
|
||||||
|
|
||||||
if($save) {
|
$valueCount = count($values);
|
||||||
if($this->stmtDelete === null)
|
|
||||||
$this->stmtDelete = $this->dbConn->prepare('DELETE FROM msz_config WHERE config_name = ?');
|
|
||||||
|
|
||||||
$this->stmtDelete->reset();
|
$stmt = $this->cache->get(sprintf(
|
||||||
$this->stmtDelete->addParameter(1, $name);
|
'REPLACE INTO msz_config (config_name, config_value) VALUES %s',
|
||||||
$this->stmtDelete->execute();
|
implode(', ', array_fill(0, $valueCount, '(?, ?)'))
|
||||||
|
));
|
||||||
|
|
||||||
|
$args = 0;
|
||||||
|
foreach($values as $name => $value) {
|
||||||
|
if(!self::validateName($name))
|
||||||
|
throw new InvalidArgumentException('Invalid name encountered in $values.');
|
||||||
|
|
||||||
|
if(is_array($value)) {
|
||||||
|
foreach($value as $entry)
|
||||||
|
if(!is_scalar($entry))
|
||||||
|
throw new InvalidArgumentException('An array value in $values contains a non-scalar type.');
|
||||||
|
} elseif(!is_scalar($value))
|
||||||
|
throw new InvalidArgumentException('Invalid value type encountered in $values.');
|
||||||
|
|
||||||
|
$stmt->addParameter(++$args, $name);
|
||||||
|
$stmt->addParameter(++$args, serialize($value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$stmt->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setString(string $name, string $value): void {
|
||||||
|
$this->setValues([$name => $value]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setInteger(string $name, int $value): void {
|
||||||
|
$this->setValues([$name => $value]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setFloat(string $name, float $value): void {
|
||||||
|
$this->setValues([$name => $value]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBoolean(string $name, bool $value): void {
|
||||||
|
$this->setValues([$name => $value]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setArray(string $name, array $value): void {
|
||||||
|
$this->setValues([$name => $value]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
92
src/Config/DbConfigValueInfo.php
Normal file
92
src/Config/DbConfigValueInfo.php
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
<?php
|
||||||
|
namespace Misuzu\Config;
|
||||||
|
|
||||||
|
use RuntimeException;
|
||||||
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
|
class DbConfigValueInfo implements IConfigValueInfo {
|
||||||
|
private string $name;
|
||||||
|
private string $value;
|
||||||
|
|
||||||
|
public function __construct(IDbResult $result) {
|
||||||
|
$this->name = $result->getString(0);
|
||||||
|
$this->value = $result->getString(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName(): string {
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getType(): string {
|
||||||
|
return match($this->value[0]) {
|
||||||
|
's' => 'string',
|
||||||
|
'a' => 'array',
|
||||||
|
'i' => 'int',
|
||||||
|
'b' => 'bool',
|
||||||
|
'd' => 'float',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isString(): bool {
|
||||||
|
return $this->value[0] === 's';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isInteger(): bool {
|
||||||
|
return $this->value[0] === 'i';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isFloat(): bool {
|
||||||
|
return $this->value[0] === 'd';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isBoolean(): bool {
|
||||||
|
return $this->value[0] === 'b';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isArray(): bool {
|
||||||
|
return $this->value[0] === 'a';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getValue(): mixed {
|
||||||
|
return unserialize($this->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getString(): string {
|
||||||
|
$value = $this->getValue();
|
||||||
|
if(!is_string($value))
|
||||||
|
throw new RuntimeException('Value is not a string.');
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInteger(): int {
|
||||||
|
$value = $this->getValue();
|
||||||
|
if(!is_int($value))
|
||||||
|
throw new RuntimeException('Value is not an integer.');
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFloat(): float {
|
||||||
|
$value = $this->getValue();
|
||||||
|
if(!is_float($value))
|
||||||
|
throw new RuntimeException('Value is not a floating point number.');
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBoolean(): bool {
|
||||||
|
$value = $this->getValue();
|
||||||
|
if(!is_bool($value))
|
||||||
|
throw new RuntimeException('Value is not a boolean.');
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getArray(): array {
|
||||||
|
$value = $this->getValue();
|
||||||
|
if(!is_array($value))
|
||||||
|
throw new RuntimeException('Value is not an array.');
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString(): string {
|
||||||
|
return $this->isArray() ? implode(', ', $this->getArray()) : (string)$this->getValue();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,23 +1,29 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\Config;
|
namespace Misuzu\Config;
|
||||||
|
|
||||||
// getValue (and hasValue?) should probably be replaced with something that allows grouped loading
|
use Misuzu\Pagination;
|
||||||
// that way the entire config doesn't have to be kept in memory on every request
|
|
||||||
// this probably has to be delayed until the backwards compat static Config object isn't needed anymore
|
|
||||||
// otherwise there'd be increased overhead
|
|
||||||
// bulk operations for setValue and removeValue would also be cool
|
|
||||||
|
|
||||||
interface IConfig {
|
interface IConfig {
|
||||||
public const T_ANY = '';
|
|
||||||
public const T_STR = 'string';
|
|
||||||
public const T_INT = 'integer';
|
|
||||||
public const T_BOOL = 'boolean';
|
|
||||||
public const T_ARR = 'array';
|
|
||||||
|
|
||||||
public function scopeTo(string $prefix): IConfig;
|
public function scopeTo(string $prefix): IConfig;
|
||||||
public function getNames(): array;
|
|
||||||
public function getValue(string $name, string $type = IConfig::T_ANY, $default = null): mixed;
|
public function hasValues(string|array $names): bool;
|
||||||
public function hasValue(string $name): bool;
|
public function removeValues(string|array $names): void;
|
||||||
public function setValue(string $name, $value, bool $save = true): void;
|
|
||||||
public function removeValue(string $name, bool $save = true): void;
|
public function getAllValueInfos(?Pagination $pagination = null): array;
|
||||||
|
public function getValueInfos(string|array $names): array;
|
||||||
|
public function getValueInfo(string $name): ?IConfigValueInfo;
|
||||||
|
|
||||||
|
public function getValues(array $specs): array;
|
||||||
|
public function getString(string $name, string $default = ''): string;
|
||||||
|
public function getInteger(string $name, int $default = 0): int;
|
||||||
|
public function getFloat(string $name, float $default = 0): float;
|
||||||
|
public function getBoolean(string $name, bool $default = false): bool;
|
||||||
|
public function getArray(string $name, array $default = []): array;
|
||||||
|
|
||||||
|
public function setValues(array $values): void;
|
||||||
|
public function setString(string $name, string $value): void;
|
||||||
|
public function setInteger(string $name, int $value): void;
|
||||||
|
public function setFloat(string $name, float $value): void;
|
||||||
|
public function setBoolean(string $name, bool $value): void;
|
||||||
|
public function setArray(string $name, array $value): void;
|
||||||
}
|
}
|
||||||
|
|
22
src/Config/IConfigValueInfo.php
Normal file
22
src/Config/IConfigValueInfo.php
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
namespace Misuzu\Config;
|
||||||
|
|
||||||
|
use Stringable;
|
||||||
|
|
||||||
|
interface IConfigValueInfo extends Stringable {
|
||||||
|
public function getName(): string;
|
||||||
|
|
||||||
|
public function getType(): string;
|
||||||
|
public function isString(): bool;
|
||||||
|
public function isInteger(): bool;
|
||||||
|
public function isFloat(): bool;
|
||||||
|
public function isBoolean(): bool;
|
||||||
|
public function isArray(): bool;
|
||||||
|
|
||||||
|
public function getValue(): mixed;
|
||||||
|
public function getString(): string;
|
||||||
|
public function getInteger(): int;
|
||||||
|
public function getFloat(): float;
|
||||||
|
public function getBoolean(): bool;
|
||||||
|
public function getArray(): array;
|
||||||
|
}
|
|
@ -2,12 +2,13 @@
|
||||||
namespace Misuzu\Config;
|
namespace Misuzu\Config;
|
||||||
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
|
use Misuzu\Pagination;
|
||||||
|
|
||||||
class ScopedConfig implements IConfig {
|
class ScopedConfig implements IConfig {
|
||||||
private IConfig $config;
|
private IConfig $config;
|
||||||
private string $prefix;
|
private string $prefix;
|
||||||
|
private int $prefixLength;
|
||||||
|
|
||||||
// update this to : at some point, would need adjustment of the live site's config
|
|
||||||
private const SCOPE_CHAR = '.';
|
private const SCOPE_CHAR = '.';
|
||||||
|
|
||||||
public function __construct(IConfig $config, string $prefix) {
|
public function __construct(IConfig $config, string $prefix) {
|
||||||
|
@ -18,41 +19,120 @@ class ScopedConfig implements IConfig {
|
||||||
|
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
$this->prefix = $prefix;
|
$this->prefix = $prefix;
|
||||||
|
$this->prefixLength = strlen($prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getName(string $name): string {
|
private function prefixNames(string|array $names): array {
|
||||||
|
if(is_string($names))
|
||||||
|
return [$this->prefix . $name];
|
||||||
|
|
||||||
|
foreach($names as $key => $name)
|
||||||
|
$names[$key] = $this->prefix . $name;
|
||||||
|
|
||||||
|
return $names;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function prefixName(string $name): string {
|
||||||
return $this->prefix . $name;
|
return $this->prefix . $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function scopeTo(string $prefix): IConfig {
|
public function scopeTo(string $prefix): IConfig {
|
||||||
return $this->config->scopeTo($this->getName($prefix));
|
return $this->config->scopeTo($this->prefixName($prefix));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getNames(): array {
|
public function hasValues(string|array $names): bool {
|
||||||
$orig = $this->config->getNames();
|
$this->config->hasValues($this->prefixNames($names));
|
||||||
$pfxLength = strlen($this->prefix);
|
|
||||||
$filter = [];
|
|
||||||
|
|
||||||
foreach($orig as $name)
|
|
||||||
if(str_starts_with($name, $this->prefix))
|
|
||||||
$filter[] = substr($name, $pfxLength);
|
|
||||||
|
|
||||||
return $filter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getValue(string $name, string $type = IConfig::T_ANY, $default = null): mixed {
|
public function removeValues(string|array $names): void {
|
||||||
return $this->config->getValue($this->getName($name), $type, $default);
|
$this->config->removeValues($this->prefixNames($names));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasValue(string $name): bool {
|
public function getAllValueInfos(?Pagination $pagination = null): array {
|
||||||
return $this->config->hasValue($this->getName($name));
|
$infos = $this->config->getAllValueInfos($pagination);
|
||||||
|
foreach($infos as $key => $info)
|
||||||
|
$infos[$key] = new ScopedConfigValueInfo($info, $this->prefixLength);
|
||||||
|
return $infos;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setValue(string $name, $value, bool $save = true): void {
|
public function getValueInfos(string|array $names): array {
|
||||||
$this->config->setValue($this->getName($name), $value, $save);
|
$infos = $this->config->getValueInfos($this->prefixNames($names));
|
||||||
|
foreach($infos as $key => $info)
|
||||||
|
$infos[$key] = new ScopedConfigValueInfo($info, $this->prefixLength);
|
||||||
|
return $infos;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function removeValue(string $name, bool $save = true): void {
|
public function getValueInfo(string $name): ?IConfigValueInfo {
|
||||||
$this->config->removeValue($this->getName($name), $save);
|
$info = $this->config->getValueInfo($this->prefixName($name));
|
||||||
|
if($info !== null)
|
||||||
|
$info = new ScopedConfigValueInfo($info, $this->prefixLength);
|
||||||
|
return $info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getValues(array $specs): array {
|
||||||
|
foreach($specs as $key => $spec) {
|
||||||
|
if(is_string($spec))
|
||||||
|
$specs[$key] = $this->prefixName($spec);
|
||||||
|
elseif(is_array($spec) && !empty($spec))
|
||||||
|
$specs[$key][0] = $this->prefixName($spec[0]);
|
||||||
|
else
|
||||||
|
throw new InvalidArgumentException('$specs array contains an invalid entry.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$results = [];
|
||||||
|
foreach($this->config->getValues($specs) as $name => $result)
|
||||||
|
$results[substr($name, $this->prefixLength)] = $result;
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getString(string $name, string $default = ''): string {
|
||||||
|
return $this->config->getString($this->prefixName($name), $default);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInteger(string $name, int $default = 0): int {
|
||||||
|
return $this->config->getInteger($this->prefixName($name), $default);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFloat(string $name, float $default = 0): float {
|
||||||
|
return $this->config->getFloat($this->prefixName($name), $default);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBoolean(string $name, bool $default = false): bool {
|
||||||
|
return $this->config->getBoolean($this->prefixName($name), $default);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getArray(string $name, array $default = []): array {
|
||||||
|
return $this->config->getArray($this->prefixName($name), $default);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setValues(array $values): void {
|
||||||
|
if(empty($values))
|
||||||
|
return;
|
||||||
|
|
||||||
|
$prefixed = [];
|
||||||
|
foreach($values as $name => $value)
|
||||||
|
$prefixed[$this->prefixName($name)] = $value;
|
||||||
|
$this->config->setValues($values);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setString(string $name, string $value): void {
|
||||||
|
$this->config->setString($this->prefixName($name), $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setInteger(string $name, int $value): void {
|
||||||
|
$this->config->setInteger($this->prefixName($name), $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setFloat(string $name, float $value): void {
|
||||||
|
$this->config->setFloat($this->prefixName($name), $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBoolean(string $name, bool $value): void {
|
||||||
|
$this->config->setBoolean($this->prefixName($name), $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setArray(string $name, array $value): void {
|
||||||
|
$this->config->setArray($this->prefixName($name), $value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
72
src/Config/ScopedConfigValueInfo.php
Normal file
72
src/Config/ScopedConfigValueInfo.php
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<?php
|
||||||
|
namespace Misuzu\Config;
|
||||||
|
|
||||||
|
class ScopedConfigValueInfo implements IConfigValueInfo {
|
||||||
|
private IConfigValueInfo $info;
|
||||||
|
private int $prefixLength;
|
||||||
|
|
||||||
|
public function __construct(IConfigValueInfo $info, int $prefixLength) {
|
||||||
|
$this->info = $info;
|
||||||
|
$this->prefixLength = $prefixLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName(): string {
|
||||||
|
return substr($this->info->getName(), $this->prefixLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRealName(): string {
|
||||||
|
return $this->info->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getType(): string {
|
||||||
|
return $this->info->getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isString(): bool {
|
||||||
|
return $this->info->isString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isInteger(): bool {
|
||||||
|
return $this->info->isInteger();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isFloat(): bool {
|
||||||
|
return $this->info->isFloat();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isBoolean(): bool {
|
||||||
|
return $this->info->isBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isArray(): bool {
|
||||||
|
return $this->info->isArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getValue(): mixed {
|
||||||
|
return $this->info->getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getString(): string {
|
||||||
|
return $this->info->getString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInteger(): int {
|
||||||
|
return $this->info->getInteger();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFloat(): float {
|
||||||
|
return $this->info->getFloat();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBoolean(): bool {
|
||||||
|
return $this->info->getBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getArray(): array {
|
||||||
|
return $this->info->getArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString(): string {
|
||||||
|
return (string)$this->info;
|
||||||
|
}
|
||||||
|
}
|
|
@ -535,7 +535,7 @@ function forum_get_user_most_active_category_info(int $userId): ?object {
|
||||||
|
|
||||||
$getActiveForum = \Misuzu\DB::prepare(sprintf(
|
$getActiveForum = \Misuzu\DB::prepare(sprintf(
|
||||||
'SELECT forum_id, COUNT(*) AS post_count FROM msz_forum_posts WHERE user_id = :user AND post_deleted IS NULL AND forum_id NOT IN (%s) GROUP BY forum_id ORDER BY post_count DESC LIMIT 1',
|
'SELECT forum_id, COUNT(*) AS post_count FROM msz_forum_posts WHERE user_id = :user AND post_deleted IS NULL AND forum_id NOT IN (%s) GROUP BY forum_id ORDER BY post_count DESC LIMIT 1',
|
||||||
implode(',', $cfg->getValue('forum_leader.unranked.forum', \Misuzu\Config\IConfig::T_ARR))
|
implode(',', $cfg->getArray('forum_leader.unranked.forum'))
|
||||||
));
|
));
|
||||||
$getActiveForum->bind('user', $userId);
|
$getActiveForum->bind('user', $userId);
|
||||||
|
|
||||||
|
|
|
@ -711,7 +711,7 @@ function forum_get_user_most_active_topic_info(int $userId): ?object {
|
||||||
|
|
||||||
$getActiveForum = \Misuzu\DB::prepare(sprintf(
|
$getActiveForum = \Misuzu\DB::prepare(sprintf(
|
||||||
'SELECT topic_id, COUNT(*) AS post_count FROM msz_forum_posts WHERE user_id = :user AND post_deleted IS NULL AND forum_id NOT IN (%s) GROUP BY topic_id ORDER BY post_count DESC LIMIT 1',
|
'SELECT topic_id, COUNT(*) AS post_count FROM msz_forum_posts WHERE user_id = :user AND post_deleted IS NULL AND forum_id NOT IN (%s) GROUP BY topic_id ORDER BY post_count DESC LIMIT 1',
|
||||||
implode(',', $cfg->getValue('forum_leader.unranked.forum', \Misuzu\Config\IConfig::T_ARR))
|
implode(',', $cfg->getArray('forum_leader.unranked.forum'))
|
||||||
));
|
));
|
||||||
$getActiveForum->bind('user', $userId);
|
$getActiveForum->bind('user', $userId);
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,6 @@ namespace Misuzu\Http\Handlers;
|
||||||
|
|
||||||
use ErrorException;
|
use ErrorException;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Misuzu\Config;
|
|
||||||
use Misuzu\Config\IConfig;
|
|
||||||
use Misuzu\Pagination;
|
use Misuzu\Pagination;
|
||||||
use Misuzu\Template;
|
use Misuzu\Template;
|
||||||
use Misuzu\Comments\CommentsEx;
|
use Misuzu\Comments\CommentsEx;
|
||||||
|
@ -119,11 +117,12 @@ class ChangelogHandler extends Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createFeed(string $feedMode): Feed {
|
private function createFeed(string $feedMode): Feed {
|
||||||
|
$siteName = $this->context->getConfig()->getString('site.name', 'Misuzu');
|
||||||
$changes = $this->context->getChangelog()->getAllChanges(pagination: new Pagination(10));
|
$changes = $this->context->getChangelog()->getAllChanges(pagination: new Pagination(10));
|
||||||
|
|
||||||
$feed = (new Feed)
|
$feed = (new Feed)
|
||||||
->setTitle(Config::get('site.name', IConfig::T_STR, 'Misuzu') . ' » Changelog')
|
->setTitle($siteName . ' » Changelog')
|
||||||
->setDescription('Live feed of changes to ' . Config::get('site.name', IConfig::T_STR, 'Misuzu') . '.')
|
->setDescription('Live feed of changes to ' . $siteName . '.')
|
||||||
->setContentUrl(url_prefix(false) . url('changelog-index'))
|
->setContentUrl(url_prefix(false) . url('changelog-index'))
|
||||||
->setFeedUrl(url_prefix(false) . url("changelog-feed-{$feedMode}"));
|
->setFeedUrl(url_prefix(false) . url("changelog-feed-{$feedMode}"));
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
namespace Misuzu\Http\Handlers;
|
namespace Misuzu\Http\Handlers;
|
||||||
|
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Misuzu\Config;
|
|
||||||
use Misuzu\Config\IConfig;
|
|
||||||
use Misuzu\DB;
|
use Misuzu\DB;
|
||||||
use Misuzu\Pagination;
|
use Misuzu\Pagination;
|
||||||
use Misuzu\Template;
|
use Misuzu\Template;
|
||||||
|
@ -21,13 +19,22 @@ final class HomeHandler extends Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function landing($response, $request): void {
|
public function landing($response, $request): void {
|
||||||
$linkedData = Config::get('social.embed_linked', IConfig::T_BOOL)
|
$config = $this->context->getConfig();
|
||||||
? [
|
|
||||||
'name' => Config::get('site.name', IConfig::T_STR, 'Misuzu'),
|
if($config->getBoolean('social.embed_linked')) {
|
||||||
'url' => Config::get('site.url', IConfig::T_STR),
|
$ldr = $config->getValues([
|
||||||
'logo' => Config::get('site.ext_logo', IConfig::T_STR),
|
['site.name:s', 'Misuzu'],
|
||||||
'same_as' => Config::get('social.linked', IConfig::T_ARR),
|
'site.url:s',
|
||||||
] : null;
|
'site.ext_logo:s',
|
||||||
|
'social.linked:a'
|
||||||
|
]);
|
||||||
|
$linkedData = [
|
||||||
|
'name' => $ldr['site.name'],
|
||||||
|
'url' => $ldr['site.url'],
|
||||||
|
'logo' => $ldr['site.ext_logo'],
|
||||||
|
'same_as' => $ldr['social.linked'],
|
||||||
|
];
|
||||||
|
} else $linkedData = null;
|
||||||
|
|
||||||
$featuredNews = $this->context->getNews()->getAllPosts(
|
$featuredNews = $this->context->getNews()->getAllPosts(
|
||||||
onlyFeatured: true,
|
onlyFeatured: true,
|
||||||
|
@ -55,7 +62,7 @@ final class HomeHandler extends Handler {
|
||||||
)->fetchAll();
|
)->fetchAll();
|
||||||
|
|
||||||
// TODO: don't hardcode forum ids
|
// TODO: don't hardcode forum ids
|
||||||
$featuredForums = Config::get('landing.forum_categories', IConfig::T_ARR);
|
$featuredForums = $config->getArray('landing.forum_categories');
|
||||||
|
|
||||||
$popularTopics = [];
|
$popularTopics = [];
|
||||||
$activeTopics = [];
|
$activeTopics = [];
|
||||||
|
|
|
@ -2,13 +2,11 @@
|
||||||
namespace Misuzu\Http\Handlers;
|
namespace Misuzu\Http\Handlers;
|
||||||
|
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Misuzu\Config;
|
|
||||||
use Misuzu\DB;
|
use Misuzu\DB;
|
||||||
use Misuzu\Pagination;
|
use Misuzu\Pagination;
|
||||||
use Misuzu\Template;
|
use Misuzu\Template;
|
||||||
use Misuzu\Comments\CommentsCategory;
|
use Misuzu\Comments\CommentsCategory;
|
||||||
use Misuzu\Comments\CommentsEx;
|
use Misuzu\Comments\CommentsEx;
|
||||||
use Misuzu\Config\IConfig;
|
|
||||||
use Misuzu\Feeds\Feed;
|
use Misuzu\Feeds\Feed;
|
||||||
use Misuzu\Feeds\FeedItem;
|
use Misuzu\Feeds\FeedItem;
|
||||||
use Misuzu\Feeds\AtomFeedSerializer;
|
use Misuzu\Feeds\AtomFeedSerializer;
|
||||||
|
@ -154,9 +152,10 @@ final class NewsHandler extends Handler {
|
||||||
|
|
||||||
private function createFeed(string $feedMode, ?NewsCategoryInfo $categoryInfo, array $posts): Feed {
|
private function createFeed(string $feedMode, ?NewsCategoryInfo $categoryInfo, array $posts): Feed {
|
||||||
$hasCategory = $categoryInfo !== null;
|
$hasCategory = $categoryInfo !== null;
|
||||||
|
$siteName = $this->context->getConfig()->getString('site.name', 'Misuzu');
|
||||||
|
|
||||||
$feed = (new Feed)
|
$feed = (new Feed)
|
||||||
->setTitle(Config::get('site.name', IConfig::T_STR, 'Misuzu') . ' » ' . ($hasCategory ? $categoryInfo->getName() : 'Featured News'))
|
->setTitle($siteName . ' » ' . ($hasCategory ? $categoryInfo->getName() : 'Featured News'))
|
||||||
->setDescription($hasCategory ? $categoryInfo->getDescription() : 'A live featured news feed.')
|
->setDescription($hasCategory ? $categoryInfo->getDescription() : 'A live featured news feed.')
|
||||||
->setContentUrl(url_prefix(false) . ($hasCategory ? url('news-category', ['category' => $categoryInfo->getId()]) : url('news-index')))
|
->setContentUrl(url_prefix(false) . ($hasCategory ? url('news-category', ['category' => $categoryInfo->getId()]) : url('news-index')))
|
||||||
->setFeedUrl(url_prefix(false) . ($hasCategory ? url("news-category-feed-{$feedMode}", ['category' => $categoryInfo->getId()]) : url("news-feed-{$feedMode}")));
|
->setFeedUrl(url_prefix(false) . ($hasCategory ? url("news-category-feed-{$feedMode}", ['category' => $categoryInfo->getId()]) : url("news-feed-{$feedMode}")));
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
namespace Misuzu;
|
namespace Misuzu;
|
||||||
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
|
use Misuzu\Config\IConfig;
|
||||||
use Symfony\Component\Mime\Email as SymfonyMessage;
|
use Symfony\Component\Mime\Email as SymfonyMessage;
|
||||||
use Symfony\Component\Mime\Address as SymfonyAddress;
|
use Symfony\Component\Mime\Address as SymfonyAddress;
|
||||||
use Symfony\Component\Mailer\Mailer as SymfonyMailer;
|
use Symfony\Component\Mailer\Mailer as SymfonyMailer;
|
||||||
|
@ -11,25 +12,29 @@ use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
|
||||||
final class Mailer {
|
final class Mailer {
|
||||||
private const TEMPLATE_PATH = MSZ_ROOT . '/config/emails/%s.txt';
|
private const TEMPLATE_PATH = MSZ_ROOT . '/config/emails/%s.txt';
|
||||||
|
|
||||||
private static $dsn = 'null://null';
|
private static IConfig $config;
|
||||||
private static $transport = null;
|
private static $transport = null;
|
||||||
|
|
||||||
private static string $senderName = 'Flashii';
|
private static string $senderName = 'Flashii';
|
||||||
private static string $senderAddr = 'sys@flashii.net';
|
private static string $senderAddr = 'sys@flashii.net';
|
||||||
|
|
||||||
public static function init(string $method, array $config): void {
|
public static function init(IConfig $config): void {
|
||||||
if($method !== 'smtp') {
|
self::$config = $config;
|
||||||
self::$dsn = 'null://null';
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$dsn = $method;
|
private static function createDsn(): string {
|
||||||
|
$config = self::$config->getValues([
|
||||||
|
'method:s',
|
||||||
|
'host:s',
|
||||||
|
['port:i', 25],
|
||||||
|
'username:s',
|
||||||
|
'password:s',
|
||||||
|
]);
|
||||||
|
|
||||||
// guess this is applied automatically based on the port?
|
if($config['method'] !== 'smtp')
|
||||||
//if(!empty($config['encryption']))
|
return 'null://null';
|
||||||
// $dsn .= 't';
|
|
||||||
|
|
||||||
$dsn .= '://';
|
$dsn = $config['method'] . '://';
|
||||||
|
|
||||||
if(!empty($config['username'])) {
|
if(!empty($config['username'])) {
|
||||||
$dsn .= $config['username'];
|
$dsn .= $config['username'];
|
||||||
|
@ -44,18 +49,18 @@ final class Mailer {
|
||||||
$dsn .= ':';
|
$dsn .= ':';
|
||||||
$dsn .= $config['port'] ?? 25;
|
$dsn .= $config['port'] ?? 25;
|
||||||
|
|
||||||
self::$dsn = $dsn;
|
if(!empty($config['sender.name']))
|
||||||
|
self::$senderName = $config['sender.name'];
|
||||||
|
|
||||||
if(!empty($config['sender_name']))
|
if(!empty($config['sender.address']))
|
||||||
self::$senderName = $config['sender_name'];
|
self::$senderAddr = $config['sender.address'];
|
||||||
|
|
||||||
if(!empty($config['sender_addr']))
|
return $dsn;
|
||||||
self::$senderAddr = $config['sender_addr'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getTransport() {
|
public static function getTransport() {
|
||||||
if(self::$transport === null)
|
if(self::$transport === null)
|
||||||
self::$transport = SymfonyTransport::fromDsn(self::$dsn);
|
self::$transport = SymfonyTransport::fromDsn(self::createDsn());
|
||||||
return self::$transport;
|
return self::$transport;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,11 +70,16 @@ final class Mailer {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$config = self::$config->getValues([
|
||||||
|
'sender.name:s',
|
||||||
|
'sender.address:s',
|
||||||
|
]);
|
||||||
|
|
||||||
$message = new SymfonyMessage;
|
$message = new SymfonyMessage;
|
||||||
|
|
||||||
$message->from(new SymfonyAddress(
|
$message->from(new SymfonyAddress(
|
||||||
self::$senderAddr,
|
$config['sender.address'],
|
||||||
self::$senderName
|
$config['sender.name']
|
||||||
));
|
));
|
||||||
|
|
||||||
if($bcc)
|
if($bcc)
|
||||||
|
|
|
@ -24,10 +24,10 @@ final class SharpChatRoutes {
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
$this->emotes = $emotes;
|
$this->emotes = $emotes;
|
||||||
|
|
||||||
$hashKey = $this->config->getValue('hashKey', IConfig::T_STR, '');
|
$hashKey = $this->config->getString('hashKey', '');
|
||||||
|
|
||||||
if(empty($hashKey)) {
|
if(empty($hashKey)) {
|
||||||
$hashKeyPath = $this->config->getValue('hashKeyPath', IConfig::T_STR, '');
|
$hashKeyPath = $this->config->getString('hashKeyPath', '');
|
||||||
if(is_file($hashKeyPath))
|
if(is_file($hashKeyPath))
|
||||||
$this->hashKey = file_get_contents($hashKeyPath);
|
$this->hashKey = file_get_contents($hashKeyPath);
|
||||||
} else {
|
} else {
|
||||||
|
@ -96,7 +96,7 @@ final class SharpChatRoutes {
|
||||||
public function getLogin($response, $request): void {
|
public function getLogin($response, $request): void {
|
||||||
$currentUser = User::getCurrent();
|
$currentUser = User::getCurrent();
|
||||||
$configKey = $request->hasParam('legacy') ? 'chatPath.legacy' : 'chatPath.normal';
|
$configKey = $request->hasParam('legacy') ? 'chatPath.legacy' : 'chatPath.normal';
|
||||||
$chatPath = $this->config->getValue($configKey, IConfig::T_STR, '/');
|
$chatPath = $this->config->getString($configKey, '/');
|
||||||
|
|
||||||
$response->redirect(
|
$response->redirect(
|
||||||
$currentUser === null
|
$currentUser === null
|
||||||
|
@ -111,7 +111,7 @@ final class SharpChatRoutes {
|
||||||
$originHost = strtolower(parse_url($origin, PHP_URL_HOST) ?? '');
|
$originHost = strtolower(parse_url($origin, PHP_URL_HOST) ?? '');
|
||||||
|
|
||||||
if(!empty($originHost) && $originHost !== $host) {
|
if(!empty($originHost) && $originHost !== $host) {
|
||||||
$whitelist = $this->config->getValue('origins', IConfig::T_ARR, []);
|
$whitelist = $this->config->getArray('origins', []);
|
||||||
|
|
||||||
if(!in_array($originHost, $whitelist))
|
if(!in_array($originHost, $whitelist))
|
||||||
return 403;
|
return 403;
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\Users\Assets;
|
namespace Misuzu\Users\Assets;
|
||||||
|
|
||||||
use Misuzu\Config;
|
|
||||||
use Misuzu\Config\IConfig;
|
|
||||||
use Misuzu\Imaging\Image;
|
use Misuzu\Imaging\Image;
|
||||||
use Misuzu\Users\User;
|
use Misuzu\Users\User;
|
||||||
|
|
||||||
|
@ -20,13 +18,15 @@ class UserAvatarAsset extends UserImageAsset implements UserAssetScalableInterfa
|
||||||
private const MAX_BYTES = 1000000;
|
private const MAX_BYTES = 1000000;
|
||||||
|
|
||||||
public function getMaxWidth(): int {
|
public function getMaxWidth(): int {
|
||||||
return Config::get('avatar.max_res', IConfig::T_INT, self::MAX_RES);
|
global $cfg;
|
||||||
|
return $cfg->getInteger('avatar.max_res', self::MAX_RES);
|
||||||
}
|
}
|
||||||
public function getMaxHeight(): int {
|
public function getMaxHeight(): int {
|
||||||
return $this->getMaxWidth();
|
return $this->getMaxWidth();
|
||||||
}
|
}
|
||||||
public function getMaxBytes(): int {
|
public function getMaxBytes(): int {
|
||||||
return Config::get('avatar.max_size', IConfig::T_INT, self::MAX_BYTES);
|
global $cfg;
|
||||||
|
return $cfg->getInteger('avatar.max_size', self::MAX_BYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUrl(): string {
|
public function getUrl(): string {
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
namespace Misuzu\Users\Assets;
|
namespace Misuzu\Users\Assets;
|
||||||
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use Misuzu\Config;
|
|
||||||
use Misuzu\Config\IConfig;
|
|
||||||
use Misuzu\Users\User;
|
use Misuzu\Users\User;
|
||||||
|
|
||||||
// attachment and attributes are to be stored in the same byte
|
// attachment and attributes are to be stored in the same byte
|
||||||
|
@ -49,13 +47,16 @@ class UserBackgroundAsset extends UserImageAsset {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMaxWidth(): int {
|
public function getMaxWidth(): int {
|
||||||
return Config::get('background.max_width', IConfig::T_INT, self::MAX_WIDTH);
|
global $cfg;
|
||||||
|
return $cfg->getInteger('background.max_width', self::MAX_WIDTH);
|
||||||
}
|
}
|
||||||
public function getMaxHeight(): int {
|
public function getMaxHeight(): int {
|
||||||
return Config::get('background.max_height', IConfig::T_INT, self::MAX_HEIGHT);
|
global $cfg;
|
||||||
|
return $cfg->getInteger('background.max_height', self::MAX_HEIGHT);
|
||||||
}
|
}
|
||||||
public function getMaxBytes(): int {
|
public function getMaxBytes(): int {
|
||||||
return Config::get('background.max_size', IConfig::T_INT, self::MAX_BYTES);
|
global $cfg;
|
||||||
|
return $cfg->getInteger('background.max_size', self::MAX_BYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUrl(): string {
|
public function getUrl(): string {
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\Users\Assets;
|
namespace Misuzu\Users\Assets;
|
||||||
|
|
||||||
use Misuzu\Config;
|
|
||||||
use Misuzu\Config\IConfig;
|
|
||||||
use Misuzu\Users\User;
|
use Misuzu\Users\User;
|
||||||
|
|
||||||
class UserImageAssetFileCreationFailedException extends UserAssetException {}
|
class UserImageAssetFileCreationFailedException extends UserAssetException {}
|
||||||
|
@ -83,7 +81,7 @@ abstract class UserImageAsset implements UserImageAssetInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getStoragePath(): string {
|
public function getStoragePath(): string {
|
||||||
return Config::get('storage.path', IConfig::T_STR, MSZ_ROOT . DIRECTORY_SEPARATOR . 'store');
|
return MSZ_ROOT . DIRECTORY_SEPARATOR . 'store';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPath(): string {
|
public function getPath(): string {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
{% from 'macros.twig' import container_title %}
|
{% from 'macros.twig' import container_title %}
|
||||||
{% from '_layout/input.twig' import input_csrf, input_text, input_checkbox, input_file, input_select, input_colour %}
|
{% from '_layout/input.twig' import input_csrf, input_text, input_checkbox, input_file, input_select, input_colour %}
|
||||||
|
|
||||||
{% set title = ('Removing setting ' ~ conf_var.name) %}
|
{% set title = ('Removing setting ' ~ config_value.name) %}
|
||||||
|
|
||||||
{% block manage_content %}
|
{% block manage_content %}
|
||||||
<div class="container manage-settings">
|
<div class="container manage-settings">
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
Are you sure you want to delete this setting? It cannot be recovered.
|
Are you sure you want to delete this setting? It cannot be recovered.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form method="post" action="{{ url('manage-general-setting-delete', {'name': conf_var.name}) }}" class="manage-setting">
|
<form method="post" action="{{ url('manage-general-setting-delete', {'name': config_value.name}) }}" class="manage-setting">
|
||||||
{{ input_csrf() }}
|
{{ input_csrf() }}
|
||||||
|
|
||||||
<div class="manage-settings-list-container">
|
<div class="manage-settings-list-container">
|
||||||
|
@ -20,13 +20,13 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr class="manage-list-setting">
|
<tr class="manage-list-setting">
|
||||||
<td class="manage-list-setting-key">
|
<td class="manage-list-setting-key">
|
||||||
<div class="manage-list-setting-key-text">{{ conf_var.name }}</div>
|
<div class="manage-list-setting-key-text">{{ config_value.name }}</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="manage-list-setting-type manage-list-setting-type--{{ conf_var.type }}">
|
<td class="manage-list-setting-type manage-list-setting-type--{{ config_value.type }}">
|
||||||
<div class="manage-list-setting-type-text">{{ conf_var.type }}</div>
|
<div class="manage-list-setting-type-text">{{ config_value.type }}</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="manage-list-setting-value">
|
<td class="manage-list-setting-value">
|
||||||
<div class="manage-list-setting-value-text">{{ conf_var.value|json_encode }}</div>
|
<div class="manage-list-setting-value-text">{{ config_value }}</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -2,44 +2,44 @@
|
||||||
{% from 'macros.twig' import container_title %}
|
{% from 'macros.twig' import container_title %}
|
||||||
{% from '_layout/input.twig' import input_csrf, input_text, input_checkbox, input_file, input_select, input_colour %}
|
{% from '_layout/input.twig' import input_csrf, input_text, input_checkbox, input_file, input_select, input_colour %}
|
||||||
|
|
||||||
{% set title = conf_var.name is empty ? 'Adding a new setting' : ((conf_var.new ? 'Adding ' : 'Editing ') ~ ' setting ' ~ conf_var.name) %}
|
{% set title = config_new ? 'Adding a new setting' : ((config_new ? 'Adding ' : 'Editing ') ~ ' setting ' ~ config_name) %}
|
||||||
|
|
||||||
{% block manage_content %}
|
{% block manage_content %}
|
||||||
<div class="container manage-settings">
|
<div class="container manage-settings">
|
||||||
{{ container_title('<i class="fas fa-cogs fa-fw"></i> ' ~ title) }}
|
{{ container_title('<i class="fas fa-cogs fa-fw"></i> ' ~ title) }}
|
||||||
|
|
||||||
<form method="post" action="{{ url('manage-general-setting', {'name': conf_var.name}) }}" class="manage-setting" id="-msz-manage-setting-form">
|
<form method="post" action="{{ url('manage-general-setting', {'name': config_name|default()}) }}" class="manage-setting" id="-msz-manage-setting-form">
|
||||||
{{ input_csrf() }}
|
{{ input_csrf() }}
|
||||||
|
|
||||||
{% if conf_var.new %}
|
{% if config_new %}
|
||||||
<label class="manage-setting-field">
|
<label class="manage-setting-field">
|
||||||
<div class="manage-setting-field-name">Name</div>
|
<div class="manage-setting-field-name">Name</div>
|
||||||
{{ input_text('conf_name', 'manage__emote__field__value', conf_var.name, 'text', null, false, {'id': '-msz-manage-setting-name'}) }}
|
{{ input_text('conf_name', 'manage__emote__field__value', config_name|default(), 'text', null, false, {'id': '-msz-manage-setting-name'}) }}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label class="manage-setting-field">
|
<label class="manage-setting-field">
|
||||||
<div class="manage-setting-field-name">Type</div>
|
<div class="manage-setting-field-name">Type</div>
|
||||||
{{ input_select(
|
{{ input_select(
|
||||||
'conf_type',
|
'conf_type',
|
||||||
['', 'string', 'integer', 'boolean', 'array'],
|
['', 'string', 'int', 'bool', 'float', 'array'],
|
||||||
conf_var.type, null, null, true, 'manage__emote__field__value',
|
config_type, null, null, true, 'manage__emote__field__value',
|
||||||
{'onchange': ('location.assign("' ~ url('manage-general-setting', {'name': '-name-', 'type': '-type-'}) ~ '".replace("-name-", document.getElementById("-msz-manage-setting-name").value).replace("-type-", this.value))')}
|
{'onchange': ('location.assign("' ~ url('manage-general-setting', {'name': '-name-', 'type': '-type-'}) ~ '".replace("-name-", document.getElementById("-msz-manage-setting-name").value).replace("-type-", this.value))')}
|
||||||
) }}
|
) }}
|
||||||
</label>
|
</label>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if conf_var.type is not empty %}
|
{% if config_type is not empty %}
|
||||||
<label class="manage-setting-field">
|
<label class="manage-setting-field">
|
||||||
<div class="manage-setting-field-name">Value</div>
|
<div class="manage-setting-field-name">Value</div>
|
||||||
|
|
||||||
{% if conf_var.type == 'array' %}
|
{% if config_type == 'array' %}
|
||||||
<div class="manage-setting-array">
|
<div class="manage-setting-array">
|
||||||
<div class="manage-setting-array-warning">
|
<div class="manage-setting-array-warning">
|
||||||
<noscript><div class="warning"><div class="warning__content">Touching this without Javascript will destroy everything.</div></div></noscript>
|
<noscript><div class="warning"><div class="warning__content">Touching this without Javascript will destroy everything.</div></div></noscript>
|
||||||
</div>
|
</div>
|
||||||
<div class="manage-setting-array-select">
|
<div class="manage-setting-array-select">
|
||||||
<select class="input__select" multiple id="-msz-manage-setting-array" name="conf_value[]">
|
<select class="input__select" multiple id="-msz-manage-setting-array" name="conf_value[]">
|
||||||
{% for entry in conf_var.value %}
|
{% for entry in config_value %}
|
||||||
<option>{{ entry }}</option>
|
<option>{{ entry }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
|
@ -86,12 +86,14 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% elseif conf_var.type == 'string' %}
|
{% elseif config_type == 'string' %}
|
||||||
{{ input_text('conf_value', 'manage-setting-field-value', conf_var.value, 'text') }}
|
{{ input_text('conf_value', 'manage-setting-field-value', config_value, 'text') }}
|
||||||
{% elseif conf_var.type == 'integer' %}
|
{% elseif config_type == 'int' %}
|
||||||
{{ input_text('conf_value', 'manage-setting-field-value', conf_var.value, 'number') }}
|
{{ input_text('conf_value', 'manage-setting-field-value', config_value, 'number') }}
|
||||||
{% elseif conf_var.type == 'boolean' %}
|
{% elseif config_type == 'float' %}
|
||||||
{{ input_checkbox('conf_value', 'Enabled', conf_var.value) }}
|
{{ input_text('conf_value', 'manage-setting-field-value', config_value, 'number', '', false, {'step':'0.01'}) }}
|
||||||
|
{% elseif config_type == 'bool' %}
|
||||||
|
{{ input_checkbox('conf_value', 'Enabled', config_value) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
|
|
@ -24,20 +24,20 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for var in conf_vars %}
|
{% for var in config_vars %}
|
||||||
<tr class="manage-list-setting">
|
<tr class="manage-list-setting">
|
||||||
<td class="manage-list-setting-key">
|
<td class="manage-list-setting-key">
|
||||||
<div class="manage-list-setting-key-text">{{ var.key }}</div>
|
<div class="manage-list-setting-key-text">{{ var.name }}</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="manage-list-setting-type manage-list-setting-type--{{ var.type }}">
|
<td class="manage-list-setting-type manage-list-setting-type--{{ var.type }}">
|
||||||
<div class="manage-list-setting-type-text">{{ var.type }}</div>
|
<div class="manage-list-setting-type-text">{{ var.type }}</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="manage-list-setting-value">
|
<td class="manage-list-setting-value">
|
||||||
<div class="manage-list-setting-value-text">{{ var.value }}</div>
|
<div class="manage-list-setting-value-text">{{ var.name in config_hidden ? '*** hidden ***' : var }}</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="manage-list-setting-options">
|
<td class="manage-list-setting-options">
|
||||||
<a class="input__button input__button--autosize" href="{{ url('manage-general-setting', {'name': var.key}) }}" title="Edit"><i class="fas fa-pen fa-fw"></i></a>
|
<a class="input__button input__button--autosize" href="{{ url('manage-general-setting', {'name': var.name}) }}" title="Edit"><i class="fas fa-pen fa-fw"></i></a>
|
||||||
<a class="input__button input__button--autosize input__button--destroy" href="{{ url('manage-general-setting-delete', {'name': var.key}) }}" title="Delete"><i class="fas fa-times fa-fw"></i></a>
|
<a class="input__button input__button--autosize input__button--destroy" href="{{ url('manage-general-setting-delete', {'name': var.name}) }}" title="Delete"><i class="fas fa-times fa-fw"></i></a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
Loading…
Reference in a new issue