mirror of
https://github.com/Sarjuuk/aowow.git
synced 2025-11-29 15:58:16 +08:00
Template/Update (Part 44)
* convert admin - config * test for presence of Memcached on enable * allow self-signed certs on domain self test
This commit is contained in:
113
endpoints/admin/siteconfig.php
Normal file
113
endpoints/admin/siteconfig.php
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Aowow;
|
||||||
|
|
||||||
|
if (!defined('AOWOW_REVISION'))
|
||||||
|
die('illegal access');
|
||||||
|
|
||||||
|
|
||||||
|
class AdminSiteconfigResponse extends TemplateResponse
|
||||||
|
{
|
||||||
|
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_DEV;
|
||||||
|
|
||||||
|
protected string $template = 'admin/siteconfig';
|
||||||
|
protected string $pageName = 'siteconfig';
|
||||||
|
protected ?int $activeTab = parent::TAB_STAFF;
|
||||||
|
protected array $breadcrumb = [4, 2, 18]; // Staff > Development > Site Configuration
|
||||||
|
|
||||||
|
protected function generate() : void
|
||||||
|
{
|
||||||
|
$this->h1 = 'Site Configuration';
|
||||||
|
array_unshift($this->title, $this->h1);
|
||||||
|
|
||||||
|
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"]);
|
||||||
|
|
||||||
|
parent::generate();
|
||||||
|
|
||||||
|
$this->addScript([SC_CSS_STRING, <<<CSS
|
||||||
|
|
||||||
|
.grid input[type='text'], .grid input[type='number'] { width:250px; text-align:left; }
|
||||||
|
.grid input[type='button'] { width:65px; padding:2px; }
|
||||||
|
.grid a.tip { margin:0px 5px; opacity:0.8; }
|
||||||
|
.grid a.tip:hover { opacity:1; }
|
||||||
|
.grid tr { height:30px; }
|
||||||
|
.grid .disabled { opacity:0.4 !important; }
|
||||||
|
.grid .status { position:absolute; right:5px; }
|
||||||
|
|
||||||
|
CSS]);
|
||||||
|
|
||||||
|
$head = '<tr><th><b>Key</b></th><th><b>Value</b></th><th style="width:150px;"><b>Options</b></th></tr>';
|
||||||
|
foreach (Cfg::$categories as $idx => $catName)
|
||||||
|
{
|
||||||
|
$rows = '';
|
||||||
|
foreach (Cfg::forCategory($idx) as $key => [$value, $flags, , $default, $comment])
|
||||||
|
$rows .= $this->buildRow($key, $value, $flags, $default, $comment);
|
||||||
|
|
||||||
|
if ($idx == Cfg::CAT_MISCELLANEOUS)
|
||||||
|
$rows .= '<tr><td colspan="3"><a class="icon-add" onclick="cfg_add(this)">new configuration</a></td></tr>';
|
||||||
|
|
||||||
|
if (!$rows)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$this->lvTabs->addDataTab(Profiler::urlize($catName), $catName, '<table class="grid">' . $head . $rows . '</table>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildRow(string $key, string $value, int $flags, ?string $default, string $comment) : string
|
||||||
|
{
|
||||||
|
$buff = '<tr>';
|
||||||
|
$info = explode(' - ', $comment);
|
||||||
|
$key = $flags & Cfg::FLAG_PHP ? strtolower($key) : strtoupper($key);
|
||||||
|
|
||||||
|
// name
|
||||||
|
if (!empty($info[0]))
|
||||||
|
$buff .= '<td>'.sprintf(Util::$dfnString, $info[0], $key).'</td>';
|
||||||
|
else
|
||||||
|
$buff .= '<td>'.$key.'</td>';
|
||||||
|
|
||||||
|
// value
|
||||||
|
if ($flags & Cfg::FLAG_TYPE_BOOL)
|
||||||
|
$buff .= '<td><div id="'.$key.'"><input id="'.$key.'1" type="radio" name="'.$key.'" value="1" '.($value ? 'checked' : null).' /><label for="'.$key.'1">Enabled</label> <input id="'.$key.'0" type="radio" name="'.$key.'" value="0" '.($value ? null : 'checked').' /><label for="'.$key.'0">Disabled</label></div></td>';
|
||||||
|
else if ($flags & Cfg::FLAG_OPT_LIST && !empty($info[1]))
|
||||||
|
{
|
||||||
|
$buff .= '<td><select id="'.$key.'" name="'.$key.'">';
|
||||||
|
foreach (explode(', ', $info[1]) as $option)
|
||||||
|
{
|
||||||
|
[$idx, $name] = explode(':', $option);
|
||||||
|
$buff .= '<option value="'.$idx.'"'.($value == $idx ? ' selected ' : null).'>'.$name.'</option>';
|
||||||
|
}
|
||||||
|
$buff .= '</select></td>';
|
||||||
|
}
|
||||||
|
else if ($flags & Cfg::FLAG_BITMASK && !empty($info[1]))
|
||||||
|
{
|
||||||
|
$buff .= '<td><div id="'.$key.'">';
|
||||||
|
foreach (explode(', ', $info[1]) as $option)
|
||||||
|
{
|
||||||
|
[$idx, $name] = explode(':', $option);
|
||||||
|
$buff .= '<input id="'.$key.$idx.'" type="checkbox" name="'.$key.'" value="'.$idx.'"'.($value & (1 << $idx) ? ' checked ' : null).'><label for="'.$key.$idx.'">'.$name.'</label>';
|
||||||
|
}
|
||||||
|
$buff .= '</div></td>';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
$buff .= '<td><input id="'.$key.'" type="'.($flags & Cfg::FLAG_TYPE_STRING ? 'text" placeholder="<empty>' : 'number'.($flags & Cfg::FLAG_TYPE_FLOAT ? '" step="any' : '')).'" name="'.$key.'" value="'.$value.'" /></td>';
|
||||||
|
|
||||||
|
// actions
|
||||||
|
$buff .= '<td style="position:relative;">';
|
||||||
|
|
||||||
|
$buff .= '<a class="icon-save tip" onclick="cfg_submit.bind(this, \''.$key.'\')()" onmouseover="$WH.Tooltip.showAtCursor(event, \'Save Changes\', 0, 0, \'q\')" onmousemove="$WH.Tooltip.cursorUpdate(event)" onmouseout="$WH.Tooltip.hide()"></a>';
|
||||||
|
|
||||||
|
if ($default)
|
||||||
|
$buff .= '|<a class="icon-refresh tip" onclick="cfg_default(\''.$key.'\', \''.$default.'\')" onmouseover="$WH.Tooltip.showAtCursor(event, \'Restore Default Value\', 0, 0, \'q\')" onmousemove="$WH.Tooltip.cursorUpdate(event)" onmouseout="$WH.Tooltip.hide()"></a>';
|
||||||
|
else
|
||||||
|
$buff .= '|<a class="icon-refresh tip disabled"></a>';
|
||||||
|
|
||||||
|
if (!($flags & Cfg::FLAG_PERSISTENT))
|
||||||
|
$buff .= '|<a class="icon-delete tip" onclick="cfg_remove.bind(this, \''.$key.'\')()" onmouseover="$WH.Tooltip.showAtCursor(event, \'Remove Setting\', 0, 0, \'q\')" onmousemove="$WH.Tooltip.cursorUpdate(event)" onmouseout="$WH.Tooltip.hide()"></a>';
|
||||||
|
|
||||||
|
$buff .= '<span class="status"></span></td></tr>';
|
||||||
|
|
||||||
|
return $buff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
34
endpoints/admin/siteconfig_add.php
Normal file
34
endpoints/admin/siteconfig_add.php
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Aowow;
|
||||||
|
|
||||||
|
if (!defined('AOWOW_REVISION'))
|
||||||
|
die('illegal access');
|
||||||
|
|
||||||
|
|
||||||
|
class AdminSiteconfigActionAddResponse extends TextResponse
|
||||||
|
{
|
||||||
|
protected int $requiredUserGroup = U_GROUP_DEV | U_GROUP_ADMIN;
|
||||||
|
|
||||||
|
protected array $expectedGET = array(
|
||||||
|
'key' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => Cfg::PATTERN_CONF_KEY_FULL]],
|
||||||
|
'val' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextBlob'] ]
|
||||||
|
);
|
||||||
|
|
||||||
|
protected function generate() : void
|
||||||
|
{
|
||||||
|
if (!$this->assertGET('key', 'val'))
|
||||||
|
{
|
||||||
|
trigger_error('AdminSiteconfigActionAddResponse - malformed request received', E_USER_ERROR);
|
||||||
|
$this->result = Lang::main('intError');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = trim($this->_get['key']);
|
||||||
|
$val = trim(urldecode($this->_get['val']));
|
||||||
|
|
||||||
|
$this->result = Cfg::add($key, $val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
30
endpoints/admin/siteconfig_remove.php
Normal file
30
endpoints/admin/siteconfig_remove.php
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Aowow;
|
||||||
|
|
||||||
|
if (!defined('AOWOW_REVISION'))
|
||||||
|
die('illegal access');
|
||||||
|
|
||||||
|
|
||||||
|
class AdminSiteconfigActionRemoveResponse extends TextResponse
|
||||||
|
{
|
||||||
|
protected int $requiredUserGroup = U_GROUP_DEV | U_GROUP_ADMIN;
|
||||||
|
|
||||||
|
protected array $expectedGET = array(
|
||||||
|
'key' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => Cfg::PATTERN_CONF_KEY_FULL]]
|
||||||
|
);
|
||||||
|
|
||||||
|
protected function generate() : void
|
||||||
|
{
|
||||||
|
if (!$this->assertGET('key'))
|
||||||
|
{
|
||||||
|
trigger_error('AdminSiteconfigActionRemoveResponse - malformed request received', E_USER_ERROR);
|
||||||
|
$this->result = Lang::main('intError');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->result = Cfg::delete($this->_get['key']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
34
endpoints/admin/siteconfig_update.php
Normal file
34
endpoints/admin/siteconfig_update.php
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Aowow;
|
||||||
|
|
||||||
|
if (!defined('AOWOW_REVISION'))
|
||||||
|
die('illegal access');
|
||||||
|
|
||||||
|
|
||||||
|
class AdminSiteconfigActionUpdateResponse extends TextResponse
|
||||||
|
{
|
||||||
|
protected int $requiredUserGroup = U_GROUP_DEV | U_GROUP_ADMIN;
|
||||||
|
|
||||||
|
protected array $expectedGET = array(
|
||||||
|
'key' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => Cfg::PATTERN_CONF_KEY_FULL]],
|
||||||
|
'val' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextBlob'] ]
|
||||||
|
);
|
||||||
|
|
||||||
|
protected function generate() : void
|
||||||
|
{
|
||||||
|
if (!$this->assertGET('key', 'val'))
|
||||||
|
{
|
||||||
|
trigger_error('AdminSiteconfigActionUpdateResponse - malformed request received', E_USER_ERROR);
|
||||||
|
$this->result = Lang::main('intError');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = trim($this->_get['key']);
|
||||||
|
$val = trim(urldecode($this->_get['val']));
|
||||||
|
|
||||||
|
$this->result = Cfg::set($key, $val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
@@ -7,8 +7,8 @@ if (!defined('AOWOW_REVISION'))
|
|||||||
|
|
||||||
class Cfg
|
class Cfg
|
||||||
{
|
{
|
||||||
public const PATTERN_CONF_KEY = '/[a-z0-9_\.\-]/i';
|
public const PATTERN_CONF_KEY_CHAR = '/[a-z0-9_\.\-]/i';
|
||||||
public const PATTERN_INV_CONF_KEY = '/[^a-z0-9_\.\-]/i';
|
public const PATTERN_CONF_KEY_FULL = '/^[a-z0-9_\.\-]+$/i';
|
||||||
public const PATTERN_INVALID_CHARS = '/\p{C}/ui';
|
public const PATTERN_INVALID_CHARS = '/\p{C}/ui';
|
||||||
|
|
||||||
// config flags
|
// config flags
|
||||||
@@ -116,7 +116,7 @@ class Cfg
|
|||||||
|
|
||||||
$key = strtolower($key);
|
$key = strtolower($key);
|
||||||
|
|
||||||
if (preg_match(self::PATTERN_INV_CONF_KEY, $key))
|
if (!preg_match(self::PATTERN_CONF_KEY_FULL, $key))
|
||||||
return 'invalid chars in option name: [a-z 0-9 _ . -] are allowed';
|
return 'invalid chars in option name: [a-z 0-9 _ . -] are allowed';
|
||||||
|
|
||||||
if (isset(self::$store[$key]))
|
if (isset(self::$store[$key]))
|
||||||
@@ -129,7 +129,7 @@ class Cfg
|
|||||||
return 'this configuration option cannot be set';
|
return 'this configuration option cannot be set';
|
||||||
|
|
||||||
$flags = self::FLAG_TYPE_STRING | self::FLAG_PHP;
|
$flags = self::FLAG_TYPE_STRING | self::FLAG_PHP;
|
||||||
if (!DB::Aowow()->query('INSERT IGNORE INTO ?_config (`key`, `value`, `cat`, `flags`) VALUES (?, ?, ?d, ?d)', $key, $value, self::CAT_MISCELLANEOUS, $flags))
|
if (!is_int(DB::Aowow()->query('INSERT IGNORE INTO ?_config (`key`, `value`, `cat`, `flags`) VALUES (?, ?, ?d, ?d)', $key, $value, self::CAT_MISCELLANEOUS, $flags)))
|
||||||
return 'internal error';
|
return 'internal error';
|
||||||
|
|
||||||
self::$store[$key] = [$value, $flags, self::CAT_MISCELLANEOUS, null, null];
|
self::$store[$key] = [$value, $flags, self::CAT_MISCELLANEOUS, null, null];
|
||||||
@@ -349,7 +349,7 @@ class Cfg
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($flags & self::FLAG_TYPE_BOOL)
|
if ($flags & self::FLAG_TYPE_BOOL)
|
||||||
$value = (bool)$value;
|
$value = $value ? 1 : 0;
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
@@ -384,7 +384,17 @@ class Cfg
|
|||||||
trigger_error($msg, E_USER_ERROR);
|
trigger_error($msg, E_USER_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function locales(/*int|string*/ $value, ?string &$msg = '') : bool
|
private static function useSSL() : bool
|
||||||
|
{
|
||||||
|
return (($_SERVER['HTTPS'] ?? 'off') != 'off') || (self::$store['force_ssl'][self::IDX_VALUE] ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***************************/
|
||||||
|
/* onSet/onLoad validators */
|
||||||
|
/***************************/
|
||||||
|
|
||||||
|
private static function locales(int|string $value, ?string &$msg = '') : bool
|
||||||
{
|
{
|
||||||
if (!CLI)
|
if (!CLI)
|
||||||
return true;
|
return true;
|
||||||
@@ -397,7 +407,7 @@ class Cfg
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function acc_auth_mode(/*int|string*/ $value, ?string &$msg = '') : bool
|
private static function acc_auth_mode(int|string $value, ?string &$msg = '') : bool
|
||||||
{
|
{
|
||||||
if ($value == 1 && !extension_loaded('gmp'))
|
if ($value == 1 && !extension_loaded('gmp'))
|
||||||
{
|
{
|
||||||
@@ -408,7 +418,7 @@ class Cfg
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function profiler_enable(/*int|string*/ $value, ?string &$msg = '') : bool
|
private static function profiler_enable(int|string $value, ?string &$msg = '') : bool
|
||||||
{
|
{
|
||||||
if ($value != 1)
|
if ($value != 1)
|
||||||
return true;
|
return true;
|
||||||
@@ -416,7 +426,7 @@ class Cfg
|
|||||||
return Profiler::queueStart($msg);
|
return Profiler::queueStart($msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function static_host(/*int|string*/ $value, ?string &$msg = '') : bool
|
private static function static_host(int|string $value, ?string &$msg = '') : bool
|
||||||
{
|
{
|
||||||
self::$store['static_url'] = array( // points js to images & scripts
|
self::$store['static_url'] = array( // points js to images & scripts
|
||||||
(self::useSSL() ? 'https://' : 'http://').$value,
|
(self::useSSL() ? 'https://' : 'http://').$value,
|
||||||
@@ -429,7 +439,7 @@ class Cfg
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function site_host(/*int|string*/ $value, ?string &$msg = '') : bool
|
private static function site_host(int|string $value, ?string &$msg = '') : bool
|
||||||
{
|
{
|
||||||
self::$store['host_url'] = array( // points js to executable files
|
self::$store['host_url'] = array( // points js to executable files
|
||||||
(self::useSSL() ? 'https://' : 'http://').$value,
|
(self::useSSL() ? 'https://' : 'http://').$value,
|
||||||
@@ -442,9 +452,15 @@ class Cfg
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function useSSL() : bool
|
private static function cache_mode(int|string $value, ?string &$msg = '') : bool
|
||||||
{
|
{
|
||||||
return (($_SERVER['HTTPS'] ?? 'off') != 'off') || (self::$store['force_ssl'][self::IDX_VALUE] ?? 0);
|
if ($value & 0x2 && !class_exists('\Memcached'))
|
||||||
|
{
|
||||||
|
$msg .= 'PHP extension Memcached is not enabled.';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function screenshot_min_size(int|string $value, ?string &$msg = '') : bool
|
private static function screenshot_min_size(int|string $value, ?string &$msg = '') : bool
|
||||||
|
|||||||
@@ -217,6 +217,12 @@ trait TrCache
|
|||||||
|
|
||||||
private function memcached() : ?\Memcached
|
private function memcached() : ?\Memcached
|
||||||
{
|
{
|
||||||
|
if (!class_exists('\Memcached'))
|
||||||
|
{
|
||||||
|
trigger_error('Memcached is enabled by us but not in php!', E_USER_ERROR);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (!$this->memcached && (Cfg::get('CACHE_MODE') & CACHE_MODE_MEMCACHED))
|
if (!$this->memcached && (Cfg::get('CACHE_MODE') & CACHE_MODE_MEMCACHED))
|
||||||
{
|
{
|
||||||
$this->memcached = new \Memcached();
|
$this->memcached = new \Memcached();
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ CLISetup::registerUtility(new class extends UtilityScript
|
|||||||
CLI::write();
|
CLI::write();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CLI::read(['idx' => ['', false, false, Cfg::PATTERN_CONF_KEY]], $uiIndex) && $uiIndex && $uiIndex['idx'] !== '')
|
if (CLI::read(['idx' => ['', false, false, Cfg::PATTERN_CONF_KEY_CHAR]], $uiIndex) && $uiIndex && $uiIndex['idx'] !== '')
|
||||||
{
|
{
|
||||||
$idx = array_search(strtolower($uiIndex['idx']), $cfgList);
|
$idx = array_search(strtolower($uiIndex['idx']), $cfgList);
|
||||||
if ($idx === false)
|
if ($idx === false)
|
||||||
@@ -147,7 +147,7 @@ CLISetup::registerUtility(new class extends UtilityScript
|
|||||||
CLI::write();
|
CLI::write();
|
||||||
|
|
||||||
$setting = array(
|
$setting = array(
|
||||||
'key' => ['option name', false, false, Cfg::PATTERN_CONF_KEY],
|
'key' => ['option name', false, false, Cfg::PATTERN_CONF_KEY_CHAR],
|
||||||
'val' => ['value']
|
'val' => ['value']
|
||||||
);
|
);
|
||||||
if (CLI::read($setting, $uiSetting) && $uiSetting)
|
if (CLI::read($setting, $uiSetting) && $uiSetting)
|
||||||
@@ -443,7 +443,13 @@ CLISetup::registerUtility(new class extends UtilityScript
|
|||||||
|
|
||||||
private function testCase(&$protocol, &$host, $testFile, &$status) : bool
|
private function testCase(&$protocol, &$host, $testFile, &$status) : bool
|
||||||
{
|
{
|
||||||
$res = get_headers($protocol.$host.$testFile, true);
|
// https://stackoverflow.com/questions/14279095/allow-self-signed-certificates-for-https-wrapper
|
||||||
|
$ctx = stream_context_create(array(
|
||||||
|
'ssl' => ['verify_peer' => false,
|
||||||
|
'allow_self_signed' => true]
|
||||||
|
));
|
||||||
|
|
||||||
|
$res = get_headers($protocol.$host.$testFile, true, $ctx);
|
||||||
|
|
||||||
if (!preg_match('/HTTP\/[0-9\.]+\s+([0-9]+)/', $res[0], $m))
|
if (!preg_match('/HTTP\/[0-9\.]+\s+([0-9]+)/', $res[0], $m))
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
2
setup/updates/1758578400_10.sql
Normal file
2
setup/updates/1758578400_10.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
-- set on_set_fn check
|
||||||
|
UPDATE `aowow_config` SET `flags` = `flags` | 1024 WHERE `key` = 'cache_mode';
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
<?php namespace Aowow; ?>
|
<?php
|
||||||
|
namespace Aowow\Template;
|
||||||
|
|
||||||
<?php $this->brick('header'); ?>
|
$this->brick('header');
|
||||||
|
?>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
function createStatusIcon(errTxt)
|
function createStatusIcon(errTxt)
|
||||||
|
|||||||
Reference in New Issue
Block a user