Template/Update (Part 45)

* convert misc admin endpoints
This commit is contained in:
Sarjuuk
2025-08-22 16:09:24 +02:00
parent 3f8a1838c0
commit ab27976132
10 changed files with 438 additions and 631 deletions

View File

@@ -0,0 +1,68 @@
<?php
namespace Aowow;
if (!defined('AOWOW_REVISION'))
die('illegal access');
class AdminAnnouncementsResponse extends TemplateResponse
{
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU;
protected string $template = 'text-page-generic';
protected string $pageName = 'announcements';
protected ?int $activeTab = parent::TAB_STAFF;
protected array $breadcrumb = [4, 1, 3]; // Staff > Content > Announcements
protected array $expectedGET = array(
'id' => ['filter' => FILTER_VALIDATE_INT ],
'edit' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkEmptySet'] ],
'status' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 0, 'max_range' => 2]]
);
protected function generate() : void
{
if ($this->_get['id'] && isset($this->_get['status']))
{
$this->updateStatus();
$this->forward($_SERVER['HTTP_REFERER'] ?? '.');
}
else if ($this->_get['edit'])
$this->displayEditor();
else
$this->displayListing();
parent::generate();
}
private function updateStatus() : void
{
if (!$this->assertGET('status', 'id'))
{
trigger_error('AdminAnnouncementsResponse::updateStatus - error in _GET id/status');
return;
}
if (!DB::Aowow()->selectCell('SELECT 1 FROM ?_announcements WHERE `id` = ?d', $this->_get['id']))
{
trigger_error('AdminAnnouncementsResponse::updateStatus - announcement does not exist');
return;
}
DB::Aowow()->query('UPDATE ?_announcements SET `status` = ?d WHERE `id` = ?d', $this->_get['status'], $this->_get['id']);
}
private function displayEditor() : void
{
// TBD
$this->extraHTML = 'TODO - editor';
}
private function displayListing() : void
{
// TBD
// some form of listview with [NEW] button somewhere near the head i guess
$this->extraHTML = 'TODO - announcements listing';
}
}

View File

@@ -0,0 +1,80 @@
<?php
namespace Aowow;
if (!defined('AOWOW_REVISION'))
die('illegal access');
class AdminPhpinfoResponse extends TemplateResponse
{
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_DEV;
protected string $template = 'list-page-generic';
protected string $pageName = 'phpinfo';
protected ?int $activeTab = parent::TAB_STAFF;
protected array $breadcrumb = [4, 2, 21]; // Staff > Development > PHP Information
protected function generate() : void
{
$this->h1 = 'PHP Information';
array_unshift($this->title, $this->h1);
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"]);
parent::generate();
$this->addScript([SC_CSS_STRING, <<<CSS
pre { margin: 0px; font-family: monospace; }
.d, th { border: 1px solid #000000; vertical-align: baseline; }
.p { text-align: left; }
.e { background-color: #ccccff; font-weight: bold; color: #000000; }
.h { background-color: #9999cc; font-weight: bold; color: #000000; }
.v { background-color: #cccccc; color: #000000; }
.vr { background-color: #cccccc; text-align: right; color: #000000; }
CSS]);
$bits = [INFO_GENERAL, INFO_CONFIGURATION, INFO_ENVIRONMENT, INFO_MODULES];
$names = ['General', '', '', 'Module'];
foreach ($bits as $i => $b)
{
ob_start();
phpinfo($b);
$buff = ob_get_contents();
ob_end_clean();
$buff = explode('<div class="center">', $buff)[1];
$buff = explode('</div>', $buff);
array_pop($buff); // remove last from stack
$buff = implode('</div>', $buff); // sew it together
if (strpos($buff, '<h1>'))
$buff = explode('</h1>', $buff)[1];
if (strpos($buff, '<h2>'))
{
$parts = explode('<h2>', $buff);
foreach ($parts as $p)
{
if (!preg_match('/\w/i', $p))
continue;
$p = explode('</h2>', $p);
$name = $names[$i] ? $names[$i].': ' : '';
if (preg_match('/<a[^>]*>([\w\s\d]+)<\/a>/i', $p[0], $m))
$name .= $m[1];
else
$name .= $p[0];
$this->lvTabs->addDataTab(strtolower(strtr($name, [' ' => ''])), $name, $p[1]);
}
}
else
$this->lvTabs->addDataTab(strtolower($names[$i]), $names[$i], $buff);
}
}
}
?>

View File

@@ -0,0 +1,29 @@
<?php
namespace Aowow;
if (!defined('AOWOW_REVISION'))
die('illegal access');
class AdminReportsResponse extends TemplateResponse
{
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_EDITOR | U_GROUP_MOD | U_GROUP_LOCALIZER | U_GROUP_SCREENSHOT | U_GROUP_VIDEO;
protected string $template = 'admin/reports';
protected string $pageName = 'reports';
protected ?int $activeTab = parent::TAB_STAFF;
protected array $breadcrumb = [4, 5]; // Staff > Reports
protected function generate() : void
{
$this->h1 = 'Reports';
array_unshift($this->title, $this->h1);
$this->extraHTML = 'NYI';
parent::generate();
}
}
?>

View File

@@ -0,0 +1,116 @@
<?php
namespace Aowow;
use Error;
if (!defined('AOWOW_REVISION'))
die('illegal access');
class AdminSpawnoverrideResponse extends TextResponse
{
private const /* int */ ERR_NONE = 0;
private const /* int */ ERR_NO_POINTS = 1;
private const /* int */ ERR_WORLD_POS = 2;
private const /* int */ ERR_WRONG_TYPE = 3;
private const /* int */ ERR_WRITE_DB = 4;
private const /* int */ ERR_MISCELLANEOUS = 999;
protected int $requiredUserGroup = U_GROUP_MODERATOR;
protected array $expectedGET = array(
'type' => ['filter' => FILTER_VALIDATE_INT],
'guid' => ['filter' => FILTER_VALIDATE_INT],
'area' => ['filter' => FILTER_VALIDATE_INT],
'floor' => ['filter' => FILTER_VALIDATE_INT]
);
protected function generate() : void
{
if (!$this->assertGET('type', 'guid', 'area', 'floor'))
{
trigger_error('AdminSpawnoverrideResponse - malformed request received', E_USER_ERROR);
$this->result = self::ERR_MISCELLANEOUS;
return;
}
$guid = $this->_get['guid'];
$type = $this->_get['type'];
$area = $this->_get['area'];
$floor = $this->_get['floor'];
if (!in_array($type, [Type::NPC, Type::OBJECT, Type::SOUND, Type::AREATRIGGER, Type::ZONE]))
{
trigger_error('AdminSpawnoverrideResponse - can\'t move pip of type '.Type::getFileString($type), E_USER_ERROR);
$this->result = self::ERR_WRONG_TYPE;
return;
}
DB::Aowow()->query('REPLACE INTO ?_spawns_override (`type`, `typeGuid`, `areaId`, `floor`, `revision`) VALUES (?d, ?d, ?d, ?d, ?d)', $type, $guid, $area, $floor, AOWOW_REVISION);
$wPos = WorldPosition::getForGUID($type, $guid);
if (!$wPos)
{
$this->result = self::ERR_WORLD_POS;
return;
}
$point = WorldPosition::toZonePos($wPos[$guid]['mapId'], $wPos[$guid]['posX'], $wPos[$guid]['posY'], $area, $floor);
if (!$point)
{
$this->result = self::ERR_NO_POINTS;
return;
}
$updGUIDs = [$guid];
$newPos = array(
'posX' => $point[0]['posX'],
'posY' => $point[0]['posY'],
'areaId' => $point[0]['areaId'],
'floor' => $point[0]['floor']
);
// if creature try for waypoints
if ($type == Type::NPC)
{
$jobs = array(
'SELECT -w.`id` AS "entry", w.`point` AS "pointId", w.`position_x` AS "posX", w.`position_y` AS "posY" FROM creature_addon ca JOIN waypoint_data w ON w.`id` = ca.`path_id` WHERE ca.`guid` = ?d AND ca.`path_id` <> 0',
'SELECT `entry`, `pointId`, `location_x` AS "posX", `location_y` AS "posY" FROM `script_waypoint` WHERE `entry` = ?d',
'SELECT `entry`, `pointId`, `position_x` AS "posX", `position_y` AS "posY" FROM `waypoints` WHERE `entry` = ?d'
);
foreach ($jobs as $idx => $job)
{
if ($swp = DB::World()->select($job, $idx ? $wPos[$guid]['id'] : $guid))
{
foreach ($swp as $w)
{
if ($point = WorldPosition::toZonePos($wPos[$guid]['mapId'], $w['posX'], $w['posY'], $area, $floor))
{
$p = array(
'posX' => $point[0]['posX'],
'posY' => $point[0]['posY'],
'areaId' => $point[0]['areaId'],
'floor' => $point[0]['floor']
);
DB::Aowow()->query('UPDATE ?_creature_waypoints SET ?a WHERE `creatureOrPath` = ?d AND `point` = ?d', $p, $w['entry'], $w['pointId']);
}
}
}
}
// also move linked vehicle accessories (on the very same position)
$updGUIDs = array_merge($updGUIDs, DB::Aowow()->selectCol('SELECT s2.`guid` FROM ?_spawns s1 JOIN ?_spawns s2 ON s1.`posX` = s2.`posX` AND s1.`posY` = s2.`posY` AND
s1.`areaId` = s2.`areaId` AND s1.`floor` = s2.`floor` AND s2.`guid` < 0 WHERE s1.`guid` = ?d', $guid));
}
if (DB::Aowow()->query('UPDATE ?_spawns SET ?a WHERE `type` = ?d AND `guid` IN (?a)', $newPos, $type, $updGUIDs))
$this->result = self::ERR_NONE;
else
$this->result = self::ERR_WRITE_DB;
}
}
?>

View File

@@ -0,0 +1,54 @@
<?php
namespace Aowow;
if (!defined('AOWOW_REVISION'))
die('illegal access');
class AdminWeightpresetsResponse extends TemplateResponse
{
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_DEV | U_GROUP_BUREAU;
protected string $template = 'admin/weight-presets';
protected string $pageName = 'weight-presets';
protected ?int $activeTab = parent::TAB_STAFF;
protected array $breadcrumb = [4, 2, 16]; // Staff > Development > Weight Presets
protected array $scripts = array(
[SC_JS_FILE, 'js/filters.js'],
[SC_CSS_STRING, '.wt-edit {display:inline-block; vertical-align:top; width:350px;}']
);
protected function generate() : void
{
$this->h1 = 'Weight Presets';
array_unshift($this->title, $this->h1);
$head = $body = '';
$scales = DB::Aowow()->select('SELECT `class` AS ARRAY_KEY, `id` AS ARRAY_KEY2, `name`, `icon` FROM ?_account_weightscales WHERE `userId` = 0');
$weights = DB::Aowow()->selectCol('SELECT awd.`id` AS ARRAY_KEY, awd.`field` AS ARRAY_KEY2, awd.`val` FROM ?_account_weightscale_data awd JOIN ?_account_weightscales ad ON awd.`id` = ad.`id` WHERE ad.`userId` = 0');
foreach ($scales as $cl => $data)
{
$ul = '';
foreach ($data as $id => $s)
{
$weights[$id]['__icon'] = $s['icon'];
$ul .= '[url=# onclick="loadScale.bind(this, '.$id.')();"]'.$s['name'].'[/url][br]';
}
$head .= '[td=header][class='.$cl.'][/td]';
$body .= '[td valign=top]'.$ul.'[/td]';
$this->extendGlobalIds(Type::CHR_CLASS, $cl);
}
$this->extraText = new Markup('[table class=grid][tr]'.$head.'[/tr][tr]'.$body.'[/tr][/table]', ['allow' => Markup::CLASS_ADMIN], 'text-generic');
$this->extraHTML = '<script type="text/javascript">var wt_presets = '.Util::toJSON($weights).";</script>\n\n";
parent::generate();
}
}
?>

View File

@@ -0,0 +1,74 @@
<?php
namespace Aowow;
if (!defined('AOWOW_REVISION'))
die('illegal access');
class AdminWeightpresetsActionSaveResponse extends TextResponse
{
private const /* int */ ERR_NONE = 0;
private const /* int */ ERR_WRITE_DB = 1;
private const /* int */ ERR_WRITE_FILE = 2;
private const /* int */ ERR_MISCELLANEOUS = 999;
protected int $requiredUserGroup = U_GROUP_DEV | U_GROUP_ADMIN | U_GROUP_BUREAU;
protected array $expectedPOST = array(
'id' => ['filter' => FILTER_VALIDATE_INT ],
'__icon' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => Cfg::PATTERN_CONF_KEY_FULL]],
'scale' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkScale'] ]
);
protected function generate() : void
{
if (!$this->assertPOST('id', '__icon', 'scale'))
{
trigger_error('AdminWeightpresetsActionSaveResponse - malformed request received', E_USER_ERROR);
$this->result = self::ERR_MISCELLANEOUS;
return;
}
// save to db
DB::Aowow()->query('DELETE FROM ?_account_weightscale_data WHERE `id` = ?d', $this->_post['id']);
DB::Aowow()->query('UPDATE ?_account_weightscales SET `icon`= ? WHERE `id` = ?d', $this->_post['__icon'], $this->_post['id']);
foreach (explode(',', $this->_post['scale']) as $s)
{
[$k, $v] = explode(':', $s);
if (!in_array($k, Util::$weightScales) || $v < 1)
continue;
if (DB::Aowow()->query('INSERT INTO ?_account_weightscale_data VALUES (?d, ?, ?d)', $this->_post['id'], $k, $v) === null)
{
trigger_error('AdminWeightpresetsActionSaveResponse - failed to write to database', E_USER_ERROR);
$this->result = self::ERR_WRITE_DB;
return;
}
}
// write dataset
exec('php aowow --build=weightPresets', $out);
foreach ($out as $o)
if (strstr($o, 'ERR'))
{
trigger_error('AdminWeightpresetsActionSaveResponse - failed to write dataset' . $o, E_USER_ERROR);
$this->result = self::ERR_WRITE_FILE;
return;
}
// all done
$this->result = self::ERR_NONE;
}
protected static function checkScale(string $val) : string
{
if (preg_match('/^((\w+:\d+)(,\w+:\d+)*)$/', $val))
return $val;
return '';
}
}
?>

View File

@@ -1,258 +0,0 @@
<?php
namespace Aowow;
if (!defined('AOWOW_REVISION'))
die('illegal access');
class AjaxAdmin extends AjaxHandler
{
protected $validParams = ['siteconfig', 'weight-presets', 'spawn-override', 'comment'];
protected $_get = array(
'action' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkTextLine' ],
'id' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkIdListUnsigned'],
'key' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxAdmin::checkKey' ],
'all' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkEmptySet' ],
'type' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkInt' ],
'typeid' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkInt' ],
'user' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxAdmin::checkUser' ],
'val' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkTextBlob' ],
'guid' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkInt' ],
'area' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkInt' ],
'floor' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkInt' ]
);
protected $_post = array(
'alt' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkTextBlob'],
'id' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkInt' ],
'scale' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxAdmin::checkScale' ],
'__icon' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxAdmin::checkKey' ],
'status' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkInt' ],
'msg' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkTextBlob']
);
public function __construct(array $params)
{
parent::__construct($params);
if (!$this->params)
return;
if ($this->params[0] == 'siteconfig' && $this->_get['action'])
{
if (!User::isInGroup(U_GROUP_DEV | U_GROUP_ADMIN))
return;
if ($this->_get['action'] == 'add')
$this->handler = 'confAdd';
else if ($this->_get['action'] == 'remove')
$this->handler = 'confRemove';
else if ($this->_get['action'] == 'update')
$this->handler = 'confUpdate';
}
else if ($this->params[0] == 'weight-presets' && $this->_get['action'])
{
if (!User::isInGroup(U_GROUP_DEV | U_GROUP_ADMIN | U_GROUP_BUREAU))
return;
if ($this->_get['action'] == 'save')
$this->handler = 'wtSave';
}
else if ($this->params[0] == 'spawn-override')
{
if (!User::isInGroup(U_GROUP_MODERATOR))
return;
$this->handler = 'spawnPosFix';
}
else if ($this->params[0] == 'comment')
{
if (!User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_MOD))
return;
$this->handler = 'commentOutOfDate';
}
}
protected function confAdd() : string
{
$key = trim($this->_get['key']);
$val = trim(urldecode($this->_get['val']));
return Cfg::add($key, $val);
}
protected function confRemove() : string
{
if (!$this->reqGET('key'))
return 'invalid configuration option given';
return Cfg::delete($this->_get['key']);
}
protected function confUpdate() : string
{
$key = trim($this->_get['key']);
$val = trim(urldecode($this->_get['val']));
return Cfg::set($key, $val);
}
protected function wtSave() : string
{
if (!$this->reqPOST('id', '__icon'))
return '3';
// save to db
DB::Aowow()->query('DELETE FROM ?_account_weightscale_data WHERE id = ?d', $this->_post['id']);
DB::Aowow()->query('UPDATE ?_account_weightscales SET `icon`= ? WHERE `id` = ?d', $this->_post['__icon'], $this->_post['id']);
foreach (explode(',', $this->_post['scale']) as $s)
{
[$k, $v] = explode(':', $s);
if (!in_array($k, Util::$weightScales) || $v < 1)
continue;
if (DB::Aowow()->query('INSERT INTO ?_account_weightscale_data VALUES (?d, ?, ?d)', $this->_post['id'], $k, $v) === null)
return '1';
}
// write dataset
exec('php aowow --build=weightPresets', $out);
foreach ($out as $o)
if (strstr($o, 'ERR'))
return '2';
// all done
return '0';
}
protected function spawnPosFix() : string
{
if (!$this->reqGET('type', 'guid', 'area', 'floor'))
return '-4';
$guid = $this->_get['guid'];
$type = $this->_get['type'];
$area = $this->_get['area'];
$floor = $this->_get['floor'];
if (!in_array($type, [Type::NPC, Type::OBJECT, Type::SOUND, Type::AREATRIGGER, Type::ZONE]))
return '-3';
DB::Aowow()->query('REPLACE INTO ?_spawns_override VALUES (?d, ?d, ?d, ?d, ?d)', $type, $guid, $area, $floor, AOWOW_REVISION);
if ($wPos = WorldPosition::getForGUID($type, $guid))
{
if ($point = WorldPosition::toZonePos($wPos[$guid]['mapId'], $wPos[$guid]['posX'], $wPos[$guid]['posY'], $area, $floor))
{
$updGUIDs = [$guid];
$newPos = array(
'posX' => $point[0]['posX'],
'posY' => $point[0]['posY'],
'areaId' => $point[0]['areaId'],
'floor' => $point[0]['floor']
);
// if creature try for waypoints
if ($type == Type::NPC)
{
$jobs = array(
'SELECT -w.id AS `entry`, w.point AS `pointId`, w.position_x AS `posX`, w.position_y AS `posY` FROM creature_addon ca JOIN waypoint_data w ON w.id = ca.path_id WHERE ca.guid = ?d AND ca.path_id <> 0',
'SELECT `entry`, `pointId`, `location_x` AS `posX`, `location_y` AS `posY` FROM `script_waypoint` WHERE `entry` = ?d',
'SELECT `entry`, `pointId`, `position_x` AS `posX`, `position_y` AS `posY` FROM `waypoints` WHERE `entry` = ?d'
);
foreach ($jobs as $idx => $job)
{
if ($swp = DB::World()->select($job, $idx ? $wPos[$guid]['id'] : $guid))
{
foreach ($swp as $w)
{
if ($point = WorldPosition::toZonePos($wPos[$guid]['mapId'], $w['posX'], $w['posY'], $area, $floor))
{
$p = array(
'posX' => $point[0]['posX'],
'posY' => $point[0]['posY'],
'areaId' => $point[0]['areaId'],
'floor' => $point[0]['floor']
);
DB::Aowow()->query('UPDATE ?_creature_waypoints SET ?a WHERE `creatureOrPath` = ?d AND `point` = ?d', $p, $w['entry'], $w['pointId']);
}
}
}
}
// also move linked vehicle accessories (on the very same position)
$updGUIDs = array_merge($updGUIDs, DB::Aowow()->selectCol('SELECT s2.guid FROM ?_spawns s1 JOIN ?_spawns s2 ON s1.posX = s2.posX AND s1.posY = s2.posY AND
s1.areaId = s2.areaId AND s1.floor = s2.floor AND s2.guid < 0 WHERE s1.guid = ?d', $guid));
}
DB::Aowow()->query('UPDATE ?_spawns SET ?a WHERE `type` = ?d AND `guid` IN (?a)', $newPos, $type, $updGUIDs);
return '1';
}
return '-2';
}
return '-1';
}
protected function commentOutOfDate() : string
{
$ok = false;
switch ($this->_post['status'])
{
case 0: // up to date
if ($ok = DB::Aowow()->query('UPDATE ?_comments SET `flags` = `flags` & ~?d WHERE `id` = ?d', CC_FLAG_OUTDATED, $this->_post['id']))
if ($rep = new Report(Report::MODE_COMMENT, Report::CO_OUT_OF_DATE, $this->_post['id']))
$rep->close(Report::STATUS_CLOSED_WONTFIX);
break;
case 1: // outdated, mark as deleted and clear other flags (sticky + outdated)
if ($ok = DB::Aowow()->query('UPDATE ?_comments SET `flags` = ?d, `deleteUserId` = ?d, `deleteDate` = ?d WHERE `id` = ?d', CC_FLAG_DELETED, User::$id, time(), $this->_post['id']))
if ($rep = new Report(Report::MODE_COMMENT, Report::CO_OUT_OF_DATE, $this->_post['id']))
$rep->close(Report::STATUS_CLOSED_SOLVED);
break;
default:
trigger_error('AjaxHandler::comentOutOfDate - called with invalid status');
}
return $ok ? '1' : '0';
}
/***************************/
/* additional input filter */
/***************************/
protected static function checkKey(string $val) : string
{
// expecting string
if (preg_match(Cfg::PATTERN_INV_CONF_KEY, $val))
return '';
return strtolower($val);
}
protected static function checkUser($val) : string
{
$n = Util::lower(trim(urldecode($val)));
if (User::isValidName($n))
return $n;
return '';
}
protected static function checkScale($val) : string
{
if (preg_match('/^((\w+:\d+)(,\w+:\d+)*)$/', $val))
return $val;
return '';
}
}
?>

View File

@@ -1,322 +0,0 @@
<?php
namespace Aowow;
if (!defined('AOWOW_REVISION'))
die('illegal access');
class AdminPage extends GenericPage
{
protected $getAll = null;
protected $ssPages = [];
protected $ssData = [];
protected $ssNFound = 0;
protected $lvTabs = [];
protected $extraText = '';
protected $extraHTML = '';
protected $tpl = null; // depends on the subject
protected $reqUGroup = U_GROUP_NONE; // actual group dependent on the subPage
protected $reqAuth = true;
protected $path = [4];
protected $tabId = 4;
protected $_get = array(
'all' => ['filter' => FILTER_UNSAFE_RAW],
'type' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\GenericPage::checkInt'],
'typeid' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\GenericPage::checkInt'],
'user' => ['filter' => FILTER_CALLBACK, 'options' => 'urldecode']
);
private $generator = '';
public function __construct($pageCall, $pageParam)
{
switch ($pageParam)
{
case 'phpinfo':
$this->reqUGroup = U_GROUP_ADMIN | U_GROUP_DEV;
$this->generator = 'handlePhpInfo';
$this->tpl = 'list-page-generic';
array_push($this->path, 2, 21);
$this->name = 'PHP Information';
break;
case 'siteconfig':
$this->reqUGroup = U_GROUP_ADMIN | U_GROUP_DEV;
$this->generator = 'handleConfig';
$this->tpl = 'admin/siteconfig';
array_push($this->path, 2, 18);
$this->name = 'Site Configuration';
break;
case 'weight-presets':
$this->reqUGroup = U_GROUP_ADMIN | U_GROUP_DEV | U_GROUP_BUREAU;
$this->generator = 'handleWeightPresets';
$this->tpl = 'admin/weight-presets';
array_push($this->path, 2, 16);
$this->name = 'Weight Presets';
break;
case 'guides':
$this->reqUGroup = U_GROUP_STAFF;
$this->generator = 'handleGuideApprove';
$this->tpl = 'list-page-generic';
array_push($this->path, 1, 25);
$this->name = 'Pending Guides';
break;
case 'out-of-date':
$this->reqUGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_MOD;
$this->generator = 'handleOutOfDate';
$this->tpl = 'list-page-generic';
array_push($this->path, 1, 23);
$this->name = 'Out of Date Comments';
break;
case 'reports':
$this->reqUGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_EDITOR | U_GROUP_MOD | U_GROUP_LOCALIZER | U_GROUP_SCREENSHOT | U_GROUP_VIDEO;
$this->generator = 'handleReports';
$this->tpl = 'admin/reports';
array_push($this->path, 5);
$this->name = 'Reports';
break;
default: // error out through unset template
}
parent::__construct($pageCall, $pageParam);
}
protected function generateContent() : void
{
if (!$this->generator || function_exists($this->generator))
return;
$this->{$this->generator}();
}
private function handleConfig() : void
{
$this->addScript(
[SC_CSS_STRING, '.grid input[type=\'text\'], .grid input[type=\'number\'] { width:250px; text-align:left; }'],
[SC_CSS_STRING, '.grid input[type=\'button\'] { width:65px; padding:2px; }'],
[SC_CSS_STRING, '.grid a.tip { margin:0px 5px; opacity:0.8; }'],
[SC_CSS_STRING, '.grid a.tip:hover { opacity:1; }'],
[SC_CSS_STRING, '.grid tr { height:30px; }'],
[SC_CSS_STRING, '.grid .disabled { opacity:0.4 !important; }'],
[SC_CSS_STRING, '.grid .status { position:absolute; right:5px; }']
);
$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->configAddRow($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[] = [null, array(
'data' => '<table class="grid">' . $head . $rows . '</table>',
'name' => $catName,
'id' => Profiler::urlize($catName)
)];
}
}
private function handlePhpInfo() : void
{
$this->addScript([
SC_CSS_STRING, "\npre {margin: 0px; font-family: monospace;}\n" .
"td, th { border: 1px solid #000000; vertical-align: baseline;}\n" .
".p {text-align: left;}\n" .
".e {background-color: #ccccff; font-weight: bold; color: #000000;}\n" .
".h {background-color: #9999cc; font-weight: bold; color: #000000;}\n" .
".v {background-color: #cccccc; color: #000000;}\n" .
".vr {background-color: #cccccc; text-align: right; color: #000000;}\n"
]);
$bits = [INFO_GENERAL, INFO_CONFIGURATION, INFO_ENVIRONMENT, INFO_MODULES];
$names = ['General', '', '', 'Module'];
foreach ($bits as $i => $b)
{
ob_start();
phpinfo($b);
$buff = ob_get_contents();
ob_end_clean();
$buff = explode('<div class="center">', $buff)[1];
$buff = explode('</div>', $buff);
array_pop($buff); // remove last from stack
$buff = implode('</div>', $buff); // sew it together
if (strpos($buff, '<h1>'))
$buff = explode('</h1>', $buff)[1];
if (strpos($buff, '<h2>'))
{
$parts = explode('<h2>', $buff);
foreach ($parts as $p)
{
if (!preg_match('/\w/i', $p))
continue;
$p = explode('</h2>', $p);
$body = substr($p[1], 0, -7); // remove trailing "<br />\n"
$name = $names[$i] ? $names[$i].': ' : '';
if (preg_match('/<a[^>]*>([\w\s\d]+)<\/a>/i', $p[0], $m))
$name .= $m[1];
else
$name .= $p[0];
$this->lvTabs[] = [null, array(
'data' => $body,
'id' => strtolower(strtr($name, [' ' => ''])),
'name' => $name
)];
}
}
else
{
$this->lvTabs[] = [null, array(
'data' => $buff,
'id' => strtolower($names[$i]),
'name' => $names[$i]
)];
}
}
}
private function handleWeightPresets() : void
{
$this->addScript(
[SC_JS_FILE, 'js/filters.js'],
[SC_CSS_STRING, '.wt-edit {display:inline-block; vertical-align:top; width:350px;}']
);
$head = $body = '';
$scales = DB::Aowow()->select('SELECT `class` AS ARRAY_KEY, `id` AS ARRAY_KEY2, `name`, `icon` FROM ?_account_weightscales WHERE `userId` = 0 ORDER BY `class`, `orderIdx` ASC');
$weights = DB::Aowow()->selectCol('SELECT awd.`id` AS ARRAY_KEY, awd.`field` AS ARRAY_KEY2, awd.`val` FROM ?_account_weightscale_data awd JOIN ?_account_weightscales ad ON awd.`id` = ad.`id` WHERE ad.`userId` = 0');
foreach ($scales as $cl => $data)
{
$ul = '';
foreach ($data as $id => $s)
{
$weights[$id]['__icon'] = $s['icon'];
$ul .= '[url=# onclick="loadScale.bind(this, '.$id.')();"]'.$s['name'].'[/url][br]';
}
$head .= '[td=header]'.Lang::game('cl', $cl).'[/td]';
$body .= '[td valign=top]'.$ul.'[/td]';
}
$this->extraText = '[table class=grid][tr]'.$head.'[/tr][tr]'.$body.'[/tr][/table]';
$this->extraHTML = '<script type="text/javascript">var wt_presets = '.Util::toJSON($weights).";</script>\n\n";
}
private function handleGuideApprove() : void
{
$pending = new GuideList([['status', GuideMgr::STATUS_REVIEW]]);
if ($pending->error)
$data = [];
else
{
$data = $pending->getListviewData();
$latest = DB::Aowow()->selectCol('SELECT `typeId` AS ARRAY_KEY, MAX(`rev`) FROM ?_articles WHERE `type` = ?d AND `typeId` IN (?a) GROUP BY `rev`', Type::GUIDE, $pending->getFoundIDs());
foreach ($latest as $id => $rev)
$data[$id]['rev'] = $rev;
}
$this->lvTabs[] = [GuideList::$brickFile, array(
'data' => array_values($data),
'hiddenCols' => ['patch', 'comments', 'views', 'rating'],
'extraCols' => '$_'
), 'guideAdminCol'];
}
private function handleOutOfDate() : void
{
$data = CommunityContent::getCommentPreviews(['flags' => CC_FLAG_OUTDATED]);
$this->lvTabs[] = ['commentpreview', array(
'data' => $data,
'extraCols' => '$_'
), 'commentAdminCol'];
}
private function handleReports() : void
{
// todo: handle reports listing
//
}
private function configAddRow($key, $value, $flags, $default, $comment)
{
$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 (isset($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;
}
protected function generateTitle() {}
protected function generatePath() {}
}
?>

View File

@@ -1,6 +1,8 @@
<?php namespace Aowow; ?>
<?php
namespace Aowow\Template;
<?php $this->brick('header'); ?>
$this->brick('header');
?>
<script type="text/javascript">
</script>
@@ -15,39 +17,15 @@ $this->brick('announcement');
$this->brick('pageTemplate');
?>
<div class="text">
<h1><?=$this->name;?></h1>
<h1><?=$this->h1;?></h1>
<?php
$this->brick('article');
$this->brick('markup', ['markup' => $this->article]);
if (isset($this->extraText)):
$this->brick('markup', ['markup' => $this->extraText]);
echo $this->extraHTML ?? '';
?>
<div id="text-generic" class="left"></div>
<script type="text/javascript">//<![CDATA[
Markup.printHtml("<?=Util::jsEscape($this->extraText);?>", "text-generic", {
allow: Markup.CLASS_ADMIN,
dbpage: true
});
//]]></script>
<div class="pad2"></div>
<?php
endif;
if (isset($this->extraHTML)):
echo $this->extraHTML;
endif;
?>
<h2>Edit<span id="wt-name"></span><span id="status-ic" style="float:right;"></span></h2>
<div class="wt-edit">
<div style="display:inline-block; vertical-align:top;"><div class="pad2" style="color: white; font-size: 15px; font-weight: bold;">Icon</div><input type="text" id="wt-icon" size="30" /></div>
<div id="ic-container" style="display: inline-block; clear: left;"></div>
</div>
<div class="wt-edit">
<div class="pad2" style="color: white; font-size: 15px; font-weight: bold;">Scale</div>
<div id="su-container"></div>
</div>
<div id="su-controls" class="wt-edit" style="width:auto;"></div>
</div>
</div><!-- main-contents -->
</div><!-- main -->

View File

@@ -1,6 +1,8 @@
<?php namespace Aowow; ?>
<?php
namespace Aowow\Template;
<?php $this->brick('header'); ?>
$this->brick('header');
?>
<script type="text/javascript">
var SummaryAdmin = {
@@ -553,28 +555,14 @@ $this->brick('announcement');
$this->brick('pageTemplate');
?>
<div class="text">
<h1><?=$this->name;?></h1>
<h1><?=$this->h1;?></h1>
<?php
$this->brick('article');
$this->brick('markup', ['markup' => $this->article]);
if (isset($this->extraText)):
?>
<div id="text-generic" class="left"></div>
<script type="text/javascript">//<![CDATA[
Markup.printHtml("<?=Util::jsEscape($this->extraText);?>", "text-generic", {
allow: Markup.CLASS_ADMIN,
dbpage: true
});
//]]></script>
$this->brick('markup', ['markup' => $this->extraText]);
<div class="pad2"></div>
<?php
endif;
if (isset($this->extraHTML)):
echo $this->extraHTML;
endif;
echo $this->extraHTML ?? '';
?>
<h2>Edit<span id="wt-name"></span><span id="status-ic" style="float:right;"></span></h2>
<div class="wt-edit">