mirror of
https://github.com/Sarjuuk/aowow.git
synced 2025-11-29 15:58:16 +08:00
Compare commits
2 Commits
31f51276b2
...
master-dep
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef981c93e2 | ||
|
|
10c70209e7 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -11,7 +11,8 @@
|
||||
|
||||
# generated files
|
||||
/static/js/profile_all.js
|
||||
/static/js/global.js
|
||||
/static/js/locale.js
|
||||
/static/js/Markup.js
|
||||
/static/widgets/power.js
|
||||
/static/widgets/power/demo.html
|
||||
/static/widgets/searchbox.js
|
||||
@@ -49,4 +50,4 @@
|
||||
/static/uploads/screenshots/*
|
||||
/static/uploads/signatures/*
|
||||
/static/uploads/temp/*
|
||||
/static/uploads/guide/images/*
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ Also, this project is not meant to be used for commercial purposes of any kind!
|
||||
+ [MySQL Improved](https://www.php.net/manual/en/book.mysqli.php)
|
||||
+ [Multibyte String](https://www.php.net/manual/en/book.mbstring.php)
|
||||
+ [File Information](https://www.php.net/manual/en/book.fileinfo.php)
|
||||
+ [Internationalization](https://www.php.net/manual/en/book.intl.php)
|
||||
+ [GNU Multiple Precision](https://www.php.net/manual/en/book.gmp.php) (When using TrinityCore as auth source)
|
||||
+ MySQL ≥ 5.7.0 OR MariaDB ≥ 10.6.4 OR similar
|
||||
+ [TDB 335.21101](https://github.com/TrinityCore/TrinityCore/releases/tag/TDB335.21101) (no other other providers are supported at this time)
|
||||
@@ -51,7 +50,7 @@ audio processing may require [lame](https://sourceforge.net/projects/lame/files/
|
||||
|
||||
#### 2. Prepare the database
|
||||
Ensure that the account you are going to use has **full** access on the database AoWoW is going to occupy and ideally only **read** access on the world database you are going to reference.
|
||||
Import files 01 - 03 from `setup/sql/` in order into the AoWoW database `mysql -p {your-db-here} < setup/sql/01-db_structure.sql`, etc.
|
||||
Import `setup/db_structure.sql` into the AoWoW database `mysql -p {your-db-here} < setup/db_structure.sql`
|
||||
|
||||
#### 3. Server created files
|
||||
See to it, that the web server is able to write the following directories and their children. If they are missing, the setup will create them with appropriate permissions
|
||||
|
||||
@@ -4,7 +4,7 @@ if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
function extAuth(string &$usernameOrEmail, #[\SensitiveParameter] string $password, int &$userId = 0, int &$userGroup = -1) : int
|
||||
function extAuth(string &$usernameOrEmail, string $password, int &$userId = 0, int &$userGroup = -1) : int
|
||||
{
|
||||
/*
|
||||
insert some auth mechanism here
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AboutusBaseResponse extends TemplateResponse
|
||||
{
|
||||
protected string $template = 'text-page-generic';
|
||||
protected string $pageName = 'aboutus';
|
||||
protected ?int $activeTab = parent::TAB_MORE;
|
||||
protected array $breadcrumb = [2, 0];
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
parent::__construct($pageParam);
|
||||
|
||||
if ($pageParam)
|
||||
$this->generateError();
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->h1 = Lang::main('moreTitles', $this->pageName);
|
||||
|
||||
array_unshift($this->title, $this->h1);
|
||||
|
||||
parent::generate();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,177 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AccountBaseResponse extends TemplateResponse
|
||||
{
|
||||
protected string $template = 'account';
|
||||
protected string $pageName = 'account';
|
||||
|
||||
protected array $scripts = [[SC_JS_FILE, 'js/account.js']];
|
||||
|
||||
// display status of executed step (forwarding back to this page)
|
||||
public ?array $generalMessage = null;
|
||||
public ?array $emailMessage = null;
|
||||
public ?array $usernameMessage = null;
|
||||
public ?array $passwordMessage = null;
|
||||
public ?array $communityMessage = null;
|
||||
public ?array $avatarMessage = null;
|
||||
public ?array $premiumborderMessage = null;
|
||||
|
||||
// form fields
|
||||
public int $modelrace = 0;
|
||||
public int $modelgender = 0;
|
||||
public int $idsInLists = 0;
|
||||
public string $curEmail = '';
|
||||
public string $curName = '';
|
||||
public string $renameCD = '';
|
||||
public string $activeCD = '';
|
||||
public array $description = [];
|
||||
public array $signature = [];
|
||||
public int $avMode = 0;
|
||||
public string $wowicon = '';
|
||||
public int $customicon = 0;
|
||||
public array $customicons = [];
|
||||
public bool $premium = false;
|
||||
public int $reputation = 0;
|
||||
public ?Listview $avatarManager = null;
|
||||
|
||||
public ?array $bans;
|
||||
|
||||
public function __construct($pageParam)
|
||||
{
|
||||
if (!User::isLoggedIn())
|
||||
$this->forwardToSignIn('account');
|
||||
|
||||
parent::__construct($pageParam);
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
array_unshift($this->title, Lang::account('settings'));
|
||||
|
||||
$user = DB::Aowow()->selectRow('SELECT `debug`, `email`, `description`, `avatar`, `wowicon`, `renameCooldown` FROM ?_account WHERE `id` = ?d', User::$id);
|
||||
|
||||
Lang::sort('game', 'ra');
|
||||
|
||||
parent::generate();
|
||||
|
||||
|
||||
/*************/
|
||||
/* Ban Popup */
|
||||
/*************/
|
||||
|
||||
$b = DB::Aowow()->select(
|
||||
'SELECT ab.`end` AS "0", ab.`reason` AS "1", a.`username` AS "2"
|
||||
FROM ?_account_banned ab
|
||||
LEFT JOIN ?_account a ON a.`id` = ab.`staffId`
|
||||
WHERE ab.`userId` = ?d AND ab.`typeMask` & ?d AND (ab.`end` = 0 OR ab.`end` > UNIX_TIMESTAMP())',
|
||||
User::$id, ACC_BAN_TEMP | ACC_BAN_PERM
|
||||
);
|
||||
|
||||
$this->bans = $b ?: null;
|
||||
|
||||
|
||||
/*******************/
|
||||
/* Status Messages */
|
||||
/*******************/
|
||||
|
||||
if (isset($_SESSION['msg']))
|
||||
{
|
||||
[$var, $status, $msg] = $_SESSION['msg'];
|
||||
if (property_exists($this, $var.'Message'))
|
||||
$this->{$var.'Message'} = [$status, $msg];
|
||||
else
|
||||
trigger_error('AccountBaseResponse::generate - unknown var in $_SESSION msg: '.$var, E_USER_WARNING);
|
||||
|
||||
unset($_SESSION['msg']);
|
||||
}
|
||||
|
||||
|
||||
/*************/
|
||||
/* Form Data */
|
||||
/*************/
|
||||
|
||||
/* GENERAL */
|
||||
|
||||
// Modelviewer
|
||||
if ($_ = DB::Aowow()->selectCell('SELECT `data` FROM ?_account_cookies WHERE `name` = ? AND `userId` = ?d', 'default_3dmodel', User::$id))
|
||||
[$this->modelrace, $this->modelgender] = explode(',', $_);
|
||||
|
||||
// Lists
|
||||
$this->idsInLists = $user['debug'] ? 1 : 0;
|
||||
|
||||
/* PERSONAL */
|
||||
|
||||
// Email address
|
||||
$this->curEmail = $user['email'] ?? '';
|
||||
|
||||
// Username
|
||||
$this->curName = User::$username;
|
||||
$this->renameCD = Util::formatTime(Cfg::get('ACC_RENAME_DECAY') * 1000);
|
||||
if ($user['renameCooldown'] > time())
|
||||
{
|
||||
$locCode = implode('_', str_split(Lang::getLocale()->json(), 2)); // ._.
|
||||
$this->activeCD = (new \IntlDateFormatter($locCode, pattern: Lang::main('dateFmtIntl')))->format($user['renameCooldown']);
|
||||
}
|
||||
|
||||
/* COMMUNITY */
|
||||
|
||||
// Public Description
|
||||
$this->description = ['body' => $user['description']];
|
||||
|
||||
// Forum Signature
|
||||
// $this->signature = ['body' => $user['signature']];
|
||||
|
||||
// Avatar
|
||||
$this->wowicon = $user['wowicon'];
|
||||
$this->avMode = $user['avatar'];
|
||||
|
||||
// status [reviewing, ok, rejected]? (only 2: rejected processed in js)
|
||||
if (User::isPremium() && ($cuAvatars = DB::Aowow()->select('SELECT `id`, `name`, `current`, `size`, `status`, `when` FROM ?_account_avatars WHERE `userId` = ?d', User::$id)))
|
||||
{
|
||||
array_walk($cuAvatars, function (&$x) {
|
||||
$x['when'] *= 1000; // uploaded timestamp expected as msec for some reason
|
||||
$x['caption'] = $x['name']; // only used for getVisibleText, duplicates name?
|
||||
$x['type'] = 1; // always 1 ?, Dialog-popup doesn't work without it
|
||||
});
|
||||
|
||||
foreach ($cuAvatars as $a)
|
||||
if ($a['status'] != AvatarMgr::STATUS_REJECTED)
|
||||
$this->customicons[$a['id']] = $a['name'];
|
||||
|
||||
// TODO - replace with array_find in PHP 8.4
|
||||
if ($x = array_filter($cuAvatars, fn($x) => $x['current'] > 0 ))
|
||||
$this->customicon = array_pop($x)['id'];
|
||||
}
|
||||
|
||||
/* PREMIUM */
|
||||
|
||||
$this->premium = User::isPremium();
|
||||
|
||||
if (!$this->premium)
|
||||
return;
|
||||
|
||||
$this->reputation = User::getReputation();
|
||||
|
||||
// Avatar Manager
|
||||
$this->avatarManager = new Listview([
|
||||
'template' => 'avatar',
|
||||
'id' => 'avatar',
|
||||
'name' => '$LANG.tab_avatars',
|
||||
'parent' => 'avatar-manage',
|
||||
'hideNav' => 1 | 2, // top | bottom
|
||||
'data' => $cuAvatars ?? [],
|
||||
'note' => Lang::account('avatarSlots', [count($this->customicons), Cfg::get('acc_max_avatar_uploads')])
|
||||
]);
|
||||
|
||||
// Premium Border Selector
|
||||
// solved by js
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,73 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed via activation email link
|
||||
* empty page with status box
|
||||
*/
|
||||
|
||||
class AccountActivateResponse extends TemplateResponse
|
||||
{
|
||||
protected string $template = 'text-page-generic';
|
||||
protected string $pageName = 'activate';
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'key' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => '/^[a-zA-Z0-9]{40}$/']]
|
||||
);
|
||||
|
||||
private bool $success = false;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
if (!Cfg::get('ACC_ALLOW_REGISTER') || Cfg::get('ACC_AUTH_MODE') != AUTH_MODE_SELF)
|
||||
$this->generateError();
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->title[] = Lang::account('title');
|
||||
|
||||
$msg = $this->activate();
|
||||
|
||||
if ($this->success)
|
||||
$this->inputbox = ['inputbox-status', ['head' => Lang::account('inputbox', 'head', 'register', [2]), 'message' => $msg]];
|
||||
else
|
||||
{
|
||||
$_SESSION['error']['activate'] = $msg;
|
||||
$this->forward('?account=resend');
|
||||
}
|
||||
|
||||
parent::generate();
|
||||
}
|
||||
|
||||
private function activate() : string
|
||||
{
|
||||
if (!$this->assertGET('key'))
|
||||
return Lang::main('intError');
|
||||
|
||||
if (DB::Aowow()->selectCell('SELECT `id` FROM ?_account WHERE `status` IN (?a) AND `token` = ?', [ACC_STATUS_NONE, ACC_STATUS_NEW], $this->_get['key']))
|
||||
{
|
||||
// don't remove the token yet. It's needed on signin page.
|
||||
DB::Aowow()->query('UPDATE ?_account SET `status` = ?d, `statusTimer` = 0, `userGroups` = ?d WHERE `token` = ?', ACC_STATUS_NONE, U_GROUP_NONE, $this->_get['key']);
|
||||
|
||||
// fully apply block for further registration attempts from this ip
|
||||
DB::Aowow()->query('REPLACE INTO ?_account_bannedips (`ip`, `type`, `count`, `unbanDate`) VALUES (?, ?d, ?d + 1, UNIX_TIMESTAMP() + ?d)',
|
||||
User::$ip, IP_BAN_TYPE_REGISTRATION_ATTEMPT, Cfg::get('ACC_FAILED_AUTH_COUNT'), Cfg::get('ACC_FAILED_AUTH_BLOCK'));
|
||||
|
||||
$this->success = true;
|
||||
return Lang::account('inputbox', 'message', 'accActivated', [$this->_get['key']]);
|
||||
}
|
||||
|
||||
// grace period expired and other user claimed name
|
||||
return Lang::main('intError');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,128 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// custom handler
|
||||
class AccountConfirmdeleteResponse extends TemplateResponse
|
||||
{
|
||||
protected string $template = 'delete';
|
||||
protected string $pageName = 'confirm-delete';
|
||||
|
||||
protected array $scripts = array(
|
||||
[SC_CSS_FILE, 'css/delete.css'],
|
||||
[SC_CSS_STRING, '[type="submit"] { margin: 0px 10px; }']
|
||||
);
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'key' => [FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => '/^[a-zA-Z0-9]{40}$/']]
|
||||
);
|
||||
protected array $expectedPOST = array(
|
||||
'submit' => [FILTER_UNSAFE_RAW ],
|
||||
'cancel' => [FILTER_UNSAFE_RAW ],
|
||||
'confirm' => [FILTER_CALLBACK, 'options' => [self::class, 'checkEmptySet'] ],
|
||||
'key' => [FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => '/^[a-zA-Z0-9]{40}$/']]
|
||||
);
|
||||
|
||||
public bool $confirm = true; // just to select the correct localized brick
|
||||
public string $username = '';
|
||||
public string $deleteFormTarget = '?account=confirm-delete';
|
||||
public ?array $inputbox = null;
|
||||
public string $key = '';
|
||||
|
||||
private bool $success = false;
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
if (Cfg::get('ACC_AUTH_MODE') != AUTH_MODE_SELF)
|
||||
$this->generateError();
|
||||
|
||||
parent::__construct($pageParam);
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
array_unshift($this->title, Lang::account('accDelete'));
|
||||
|
||||
$this->username = User::$username;
|
||||
|
||||
parent::generate();
|
||||
|
||||
$msg = Lang::account('inputbox', 'error', 'purgeTokenUsed');
|
||||
|
||||
// display default confirm template
|
||||
if ($this->assertGET('key') && DB::Aowow()->selectCell('SELECT 1 FROM ?_account WHERE `status` = ?d AND `statusTimer` > UNIX_TIMESTAMP() AND `token` = ?', ACC_STATUS_PURGING, $this->_get['key']))
|
||||
{
|
||||
$this->key = $this->_get['key'];
|
||||
return;
|
||||
}
|
||||
|
||||
// perform action and display status
|
||||
if ($this->assertPOST('key') && ($userId = DB::Aowow()->selectCell('SELECT `id` FROM ?_account WHERE `status` = ?d AND `statusTimer` > UNIX_TIMESTAMP() AND `token` = ?', ACC_STATUS_PURGING, $this->_post['key'])))
|
||||
{
|
||||
if ($this->_post['cancel'])
|
||||
$msg = $this->cancel($userId);
|
||||
else if ($this->_post['submit'] && $this->_post['confirm'])
|
||||
$msg = $this->purge($userId);
|
||||
}
|
||||
|
||||
// throw error and display in status
|
||||
$this->inputbox = ['inputbox-status', array(
|
||||
'head' => Lang::account('inputbox', 'head', $this->success ? 'success' : 'error'),
|
||||
'message' => $this->success ? $msg : '',
|
||||
'error' => $this->success ? '' : $msg
|
||||
)];
|
||||
}
|
||||
|
||||
private function cancel(int $userId) : string
|
||||
{
|
||||
if (DB::Aowow()->query('UPDATE ?_account SET `status` = ?d, `statusTimer` = 0, `token` = "" WHERE `id` = ?d', ACC_STATUS_NONE, $userId))
|
||||
{
|
||||
$this->success = true;
|
||||
return Lang::account('inputbox', 'message', 'deleteCancel');
|
||||
}
|
||||
|
||||
return Lang::main('intError');
|
||||
}
|
||||
|
||||
private function purge(int $userId) : string
|
||||
{
|
||||
// empty all user settings and cookies
|
||||
DB::Aowow()->query('DELETE FROM ?_account_cookies WHERE `userId` = ?d', $userId);
|
||||
DB::Aowow()->query('DELETE FROM ?_account_avatars WHERE `userId` = ?d', $userId);
|
||||
DB::Aowow()->query('DELETE FROM ?_account_excludes WHERE `userId` = ?d', $userId);
|
||||
DB::Aowow()->query('DELETE FROM ?_account_favorites WHERE `userId` = ?d', $userId);
|
||||
DB::Aowow()->query('DELETE FROM ?_account_reputation WHERE `userId` = ?d', $userId);
|
||||
DB::Aowow()->query('DELETE FROM ?_account_weightscales WHERE `userId` = ?d', $userId); // cascades to aowow_account_weightscale_data
|
||||
|
||||
// delete profiles, unlink chars
|
||||
DB::Aowow()->query('DELETE pp FROM ?_profiler_profiles pp JOIN ?_account_profiles ap ON ap.`profileId` = pp.`id` WHERE ap.`accountId` = ?d', $userId);
|
||||
// DB::Aowow()->query('DELETE FROM ?_account_profiles WHERE `accountId` = ?d', $userId); // already deleted via FK?
|
||||
|
||||
// delete all sessions and bans
|
||||
DB::Aowow()->query('DELETE FROM ?_account_banned WHERE `userId` = ?d', $userId);
|
||||
DB::Aowow()->query('DELETE FROM ?_account_sessions WHERE `userId` = ?d', $userId);
|
||||
|
||||
// delete forum posts (msg: This post was from a user who has deleted their account. (no translations at src); comments/replies are unaffected)
|
||||
// ...
|
||||
|
||||
// replace username with userId and empty fields
|
||||
DB::Aowow()->query(
|
||||
'UPDATE ?_account SET
|
||||
`login` = "", `passHash` = "", `username` = `id`, `email` = NULL, `userGroups` = 0, `userPerms` = 0,
|
||||
`curIp` = "", `prevIp` = "", `curLogin` = 0, `prevLogin` = 0,
|
||||
`locale` = 0, `debug` = 0, `avatar` = 0, `wowicon` = "", `title` = "", `description` = "", `excludeGroups` = 0,
|
||||
`status` = ?d, `statusTimer` = 0, `token` = "", `updateValue` = "", `renameCooldown` = 0
|
||||
WHERE `id` = ?d',
|
||||
ACC_STATUS_DELETED, $userId
|
||||
);
|
||||
|
||||
$this->success = true;
|
||||
return Lang::account('inputbox', 'message', 'deleteOk');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,62 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed via confirmation email link
|
||||
* write status to session and redirect to account settings
|
||||
*/
|
||||
|
||||
// ?auth=email-change
|
||||
class AccountConfirmemailaddressResponse extends TemplateResponse
|
||||
{
|
||||
protected string $template = 'text-page-generic';
|
||||
protected string $pageName = 'confirm-email-address';
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'key' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => '/^[a-zA-Z0-9]{40}$/']]
|
||||
);
|
||||
|
||||
private bool $success = false;
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
parent::generate();
|
||||
|
||||
if (User::isBanned())
|
||||
return;
|
||||
|
||||
$msg = $this->change();
|
||||
|
||||
$this->inputbox = ['inputbox-status', array(
|
||||
'head' => Lang::account('inputbox', 'head', $this->success ? 'success' : 'error'),
|
||||
'message' => $this->success ? $msg : '',
|
||||
'error' => $this->success ? '' : $msg,
|
||||
)];
|
||||
}
|
||||
|
||||
// this should probably leave change info intact for revert
|
||||
// todo - move personal settings changes to separate table
|
||||
private function change() : string
|
||||
{
|
||||
if (!$this->assertGET('key'))
|
||||
return Lang::main('intError');
|
||||
|
||||
$acc = DB::Aowow()->selectRow('SELECT `updateValue`, `status`, `statusTimer` FROM ?_account WHERE `token` = ?', $this->_get['key']);
|
||||
if (!$acc || $acc['status'] != ACC_STATUS_CHANGE_EMAIL || $acc['statusTimer'] < time())
|
||||
return Lang::account('inputbox', 'error', 'mailTokenUsed');
|
||||
|
||||
// 0 changes == error
|
||||
if (!DB::Aowow()->query('UPDATE ?_account SET `email` = `updateValue`, `status` = ?d, `statusTimer` = 0, `token` = "", `updateValue` = "" WHERE `token` = ?', ACC_STATUS_NONE, $this->_get['key']))
|
||||
return Lang::main('intError');
|
||||
|
||||
$this->success = true;
|
||||
return Lang::account('inputbox', 'message', 'mailChangeOk');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,60 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed via confirmation email link
|
||||
* write status to session and redirect to account settings
|
||||
*/
|
||||
|
||||
// 2025 - no longer in use?
|
||||
class AccountConfirmpasswordResponse extends TemplateResponse
|
||||
{
|
||||
protected string $template = 'text-page-generic';
|
||||
protected string $pageName = 'confirm-password';
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'key' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => '/^[a-zA-Z0-9]{40}$/']]
|
||||
);
|
||||
|
||||
private bool $success = false;
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
parent::generate();
|
||||
|
||||
if (User::isBanned())
|
||||
return;
|
||||
|
||||
$msg = $this->confirm();
|
||||
|
||||
$this->inputbox = ['inputbox-status', array(
|
||||
'head' => Lang::account('inputbox', 'head', $this->success ? 'success' : 'error'),
|
||||
'message' => $this->success ? $msg : '',
|
||||
'error' => $this->success ? '' : $msg,
|
||||
)];
|
||||
}
|
||||
|
||||
private function confirm() : string
|
||||
{
|
||||
if (!$this->assertGET('key'))
|
||||
return Lang::main('intError');
|
||||
|
||||
$acc = DB::Aowow()->selectRow('SELECT `updateValue`, `status`, `statusTimer` FROM ?_account WHERE `token` = ?', $this->_get['key']);
|
||||
if (!$acc || $acc['status'] != ACC_STATUS_CHANGE_PASS || $acc['statusTimer'] < time())
|
||||
return Lang::account('inputbox', 'error', 'passTokenUsed');
|
||||
|
||||
// 0 changes == error
|
||||
if (!DB::Aowow()->query('UPDATE ?_account SET `passHash` = `updateValue`, `status` = ?d, `statusTimer` = 0, `token` = "", `updateValue` = "" WHERE `token` = ?', ACC_STATUS_NONE, $this->_get['key']))
|
||||
return Lang::main('intError');
|
||||
|
||||
$this->success = true;
|
||||
return Lang::account('inputbox', 'message', 'passChangeOk');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,47 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed via form button on user settings page
|
||||
*/
|
||||
|
||||
class AccountDeleteiconResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
protected int $requiredUserGroup = U_GROUP_PREMIUM_PERMISSIONS;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT]
|
||||
);
|
||||
|
||||
/*
|
||||
* response not evaluated
|
||||
*/
|
||||
protected function generate() : void
|
||||
{
|
||||
if (User::isBanned() || !$this->assertPOST('id'))
|
||||
return;
|
||||
|
||||
// non-int > error
|
||||
$selected = DB::Aowow()->selectCell('SELECT `current` FROM ?_account_avatars WHERE `id` = ?d AND `userId` = ?d', $this->_post['id'], User::$id);
|
||||
if ($selected === null || $selected === false)
|
||||
return;
|
||||
|
||||
DB::Aowow()->query('DELETE FROM ?_account_avatars WHERE `id` = ?d AND `userId` = ?d', $this->_post['id'], User::$id);
|
||||
|
||||
// if deleted avatar is also currently selected, unset
|
||||
if ($selected)
|
||||
DB::Aowow()->query('UPDATE ?_account SET `avatar` = 0 WHERE `id` = ?d', User::$id);
|
||||
|
||||
$path = sprintf('static/uploads/avatars/%d.jpg', $this->_post['id']);
|
||||
if (!unlink($path))
|
||||
trigger_error('AccountDeleteiconResponse - failed to delete file: '.$path, E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,71 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed via account settings link
|
||||
* empty page with status box
|
||||
*/
|
||||
|
||||
class AccountDeleteResponse extends TemplateResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected string $template = 'delete';
|
||||
protected string $pageName = 'delete';
|
||||
|
||||
protected array $scripts = [[SC_CSS_FILE, 'css/delete.css']];
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'proceed' => ['filter' => FILTER_UNSAFE_RAW]
|
||||
);
|
||||
|
||||
public string $username = '';
|
||||
public string $deleteFormTarget = '?account=delete';
|
||||
public ?array $inputbox = null;
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
if (Cfg::get('ACC_AUTH_MODE') != AUTH_MODE_SELF)
|
||||
$this->generateError();
|
||||
|
||||
parent::__construct($pageParam);
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
array_unshift($this->title, Lang::account('accDelete'));
|
||||
|
||||
parent::generate();
|
||||
|
||||
$this->username = User::$username;
|
||||
|
||||
if ($this->_post['proceed'])
|
||||
{
|
||||
$error = false;
|
||||
if (!DB::Aowow()->selectCell('SELECT 1 FROM ?_account WHERE `status` NOT IN (?a) AND `statusTimer` > UNIX_TIMESTAMP() AND `id` = ?d', [ACC_STATUS_NEW, ACC_STATUS_NONE, ACC_STATUS_PURGING], User::$id))
|
||||
{
|
||||
$token = Util::createHash(40);
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_account SET `status` = ?d, `statusTimer` = UNIX_TIMESTAMP() + ?d, `token` = ? WHERE `id` = ?d',
|
||||
ACC_STATUS_PURGING, Cfg::get('ACC_RECOVERY_DECAY'), $token, User::$id);
|
||||
|
||||
Util::sendMail(User::$email, 'delete-account', [$token, User::$email, User::$username]);
|
||||
}
|
||||
else
|
||||
$error = true;
|
||||
|
||||
$this->inputbox = ['inputbox-status', array(
|
||||
'head' => Lang::account('inputbox', 'head', $error ? 'error' : 'success'),
|
||||
'message' => $error ? '' : Lang::account('inputbox', 'message', 'deleteAccSent', [User::$email]),
|
||||
'error' => $error ? Lang::account('inputbox', 'error', 'isRecovering') : ''
|
||||
)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,76 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed from character profiles, when setting exclusions on collections
|
||||
* always returns emptry string
|
||||
*/
|
||||
|
||||
class AccountExcludeResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'mode' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 1, 'max_range' => 1]],
|
||||
'reset' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 1, 'max_range' => 1]],
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdList'] ],
|
||||
'type' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'groups' => ['filter' => FILTER_VALIDATE_INT ]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (User::isBanned())
|
||||
return;
|
||||
|
||||
if ($this->_post['mode'] == 1) // directly set exludes
|
||||
$this->excludeById();
|
||||
|
||||
else if ($this->_post['reset'] == 1) // defaults to unavailable
|
||||
$this->resetExcludes();
|
||||
|
||||
else if ($this->_post['groups']) // exclude by group mask
|
||||
$this->updateGroups();
|
||||
}
|
||||
|
||||
private function excludeById() : void
|
||||
{
|
||||
if (!$this->assertPOST('type', 'id'))
|
||||
return;
|
||||
|
||||
if ($validIds = Type::validateIds($this->_post['type'], $this->_post['id']))
|
||||
{
|
||||
// ready for some bullshit? here it comes!
|
||||
// we don't get signaled whether an id should be added to or removed from either includes or excludes
|
||||
// so we throw everything into one table and toggle the mode if its already in here
|
||||
|
||||
$includes = DB::Aowow()->selectCol('SELECT `typeId` FROM ?_profiler_excludes WHERE `type` = ?d AND `typeId` IN (?a)', $this->_post['type'], $validIds);
|
||||
|
||||
foreach ($validIds as $typeId)
|
||||
DB::Aowow()->query('INSERT INTO ?_account_excludes (`userId`, `type`, `typeId`, `mode`) VALUES (?a) ON DUPLICATE KEY UPDATE `mode` = (`mode` ^ 0x3)',
|
||||
[User::$id, $this->_post['type'], $typeId, in_array($typeId, $includes) ? 2 : 1]
|
||||
);
|
||||
}
|
||||
else
|
||||
trigger_error('AccountExcludeResponse::excludeById - validation failed [type: '.$this->_post['type'].', typeId: '.implode(',', $this->_post['id']).']', E_USER_NOTICE);
|
||||
}
|
||||
|
||||
private function resetExcludes() : void
|
||||
{
|
||||
DB::Aowow()->query('DELETE FROM ?_account_excludes WHERE `userId` = ?d', User::$id);
|
||||
DB::Aowow()->query('UPDATE ?_account SET `excludeGroups` = ?d WHERE `id` = ?d', PR_EXCLUDE_GROUP_UNAVAILABLE, User::$id);
|
||||
}
|
||||
|
||||
private function updateGroups() : void
|
||||
{
|
||||
if ($this->assertPOST('groups')) // clamp to real groups
|
||||
DB::Aowow()->query('UPDATE ?_account SET `excludeGroups` = ?d WHERE `id` = ?d', $this->_post['groups'] & PR_EXCLUDE_GROUP_ANY, User::$id);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,52 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed from db detail pages, when clicking on the fav star near the h1 element
|
||||
* always returns emptry string
|
||||
*/
|
||||
|
||||
class AccountFavoritesResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'add' => ['filter' => FILTER_VALIDATE_INT],
|
||||
'remove' => ['filter' => FILTER_VALIDATE_INT],
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT],
|
||||
// 'sessionKey' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => '/^[a-zA-Z0-9]{40}$/']] // usage of sessionKey omitted
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (User::isBanned())
|
||||
return;
|
||||
|
||||
if ($this->_post['remove'])
|
||||
$this->removeFavorite();
|
||||
|
||||
else if ($this->_post['add'])
|
||||
$this->addFavorite();
|
||||
}
|
||||
|
||||
private function removeFavorite() : void
|
||||
{
|
||||
if ($this->assertPOST('id', 'remove'))
|
||||
DB::Aowow()->query('DELETE FROM ?_account_favorites WHERE `userId` = ?d AND `type` = ?d AND `typeId` = ?d', User::$id, $this->_post['remove'], $this->_post['id']);
|
||||
}
|
||||
|
||||
private function addFavorite() : void
|
||||
{
|
||||
if ($this->assertPOST('id', 'add') && Type::validateIds($this->_post['add'], $this->_post['id']))
|
||||
DB::Aowow()->query('INSERT INTO ?_account_favorites (`userId`, `type`, `typeId`) VALUES (?d, ?d, ?d)', User::$id, $this->_post['add'], $this->_post['id']);
|
||||
else
|
||||
trigger_error('AccountFavoritesResponse::addFavorite() - failed to add [userId: '.User::$id.', type: '.$this->_post['add'].', typeId: '.$this->_post['id'], E_USER_NOTICE);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,101 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed via links on signin form and from recovery email
|
||||
*
|
||||
* A) redirect to external page
|
||||
* B) 1. click password reset link > display email form
|
||||
* 2. submit email form > send mail with recovery link
|
||||
* 3. click recovery link from mail > display password reset form
|
||||
* 4. submit password reset form > update password
|
||||
*/
|
||||
|
||||
class AccountforgotpasswordResponse extends TemplateResponse
|
||||
{
|
||||
use TrRecoveryHelper, TrGetNext;
|
||||
|
||||
protected string $template = 'text-page-generic';
|
||||
protected string $pageName = 'forgot-password';
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'email' => ['filter' => FILTER_VALIDATE_EMAIL, 'flags' => FILTER_FLAG_STRIP_AOWOW]
|
||||
);
|
||||
|
||||
private bool $success = false;
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
// don't redirect logged in users
|
||||
// you can be forgetful AND logged in
|
||||
|
||||
if (Cfg::get('ACC_EXT_RECOVER_URL'))
|
||||
$this->forward(Cfg::get('ACC_EXT_RECOVER_URL'));
|
||||
|
||||
if (Cfg::get('ACC_AUTH_MODE') != AUTH_MODE_SELF)
|
||||
$this->generateError();
|
||||
|
||||
parent::__construct($pageParam);
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->title[] = Lang::account('title');
|
||||
|
||||
parent::generate();
|
||||
|
||||
$msg = $this->processMailForm();
|
||||
|
||||
if ($this->success)
|
||||
$this->inputbox = ['inputbox-status', ['head' => Lang::account('inputbox', 'head', 'recoverPass', [1.5]), 'message' => $msg]];
|
||||
else
|
||||
$this->inputbox = ['inputbox-form-email', array(
|
||||
'head' => Lang::account('inputbox', 'head', 'recoverPass', [1]),
|
||||
'error' => $msg,
|
||||
'action' => '?account=forgot-password&next='.$this->getNext(),
|
||||
'email' => $this->_post['email'] ?? ''
|
||||
)];
|
||||
}
|
||||
|
||||
private function processMailForm() : string
|
||||
{
|
||||
// no input yet. show clean email form
|
||||
if (is_null($this->_post['email']))
|
||||
return '';
|
||||
|
||||
// truncated due to validation fail
|
||||
if (!$this->_post['email'])
|
||||
return Lang::account('emailInvalid');
|
||||
|
||||
$timeout = DB::Aowow()->selectCell('SELECT `unbanDate` FROM ?_account_bannedips WHERE `ip` = ? AND `type` = ?d AND `count` > ?d AND `unbanDate` > UNIX_TIMESTAMP()', User::$ip, IP_BAN_TYPE_PASSWORD_RECOVERY, Cfg::get('ACC_FAILED_AUTH_COUNT'));
|
||||
|
||||
// on cooldown pretend we dont know the email address
|
||||
if ($timeout && $timeout > time())
|
||||
return Cfg::get('DEBUG') ? 'resend on cooldown: '.Util::formatTimeDiff($timeout).' remaining' : Lang::account('inputbox', 'error', 'emailNotFound');
|
||||
|
||||
// pretend recovery started
|
||||
if (!DB::Aowow()->selectCell('SELECT 1 FROM ?_account WHERE `email` = ?', $this->_post['email']))
|
||||
{
|
||||
// do not confirm or deny existence of email
|
||||
$this->success = !Cfg::get('DEBUG');
|
||||
return Cfg::get('DEBUG') ? Lang::account('inputbox', 'error', 'emailNotFound') : Lang::account('inputbox', 'message', 'recovPassSent', [$this->_post['email']]);
|
||||
}
|
||||
|
||||
// recovery actually started
|
||||
if ($err = $this->startRecovery(ACC_STATUS_RECOVER_PASS, 'reset-password', $this->_post['email']))
|
||||
return $err;
|
||||
|
||||
DB::Aowow()->query('INSERT INTO ?_account_bannedips (`ip`, `type`, `count`, `unbanDate`) VALUES (?, ?d, ?d, UNIX_TIMESTAMP() + ?d) ON DUPLICATE KEY UPDATE `count` = `count` + ?d, `unbanDate` = UNIX_TIMESTAMP() + ?d',
|
||||
User::$ip, IP_BAN_TYPE_PASSWORD_RECOVERY, Cfg::get('ACC_FAILED_AUTH_COUNT') + 1, Cfg::get('ACC_FAILED_AUTH_COUNT'), Cfg::get('ACC_FAILED_AUTH_BLOCK'), Cfg::get('ACC_FAILED_AUTH_BLOCK'));
|
||||
|
||||
$this->success = true;
|
||||
return Lang::account('inputbox', 'message', 'recovPassSent', [$this->_post['email']]);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,100 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed via link on signin form
|
||||
*
|
||||
* A) redirect to external page
|
||||
* B) 1. click password reset link > display email form
|
||||
* 2. submit email form > send mail with recovery link
|
||||
* ( 3. click recovery link from mail to go to signin page (so not on this page) )
|
||||
*/
|
||||
|
||||
class AccountforgotusernameResponse extends TemplateResponse
|
||||
{
|
||||
use TrRecoveryHelper;
|
||||
|
||||
protected string $template = 'text-page-generic';
|
||||
protected string $pageName = 'forgot-username';
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'email' => ['filter' => FILTER_VALIDATE_EMAIL, 'flags' => FILTER_FLAG_STRIP_AOWOW]
|
||||
);
|
||||
|
||||
private bool $success = false;
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
// if the user is looged in goto account dashboard
|
||||
if (User::isLoggedIn())
|
||||
$this->forward('?account');
|
||||
|
||||
if (Cfg::get('ACC_EXT_RECOVER_URL'))
|
||||
$this->forward(Cfg::get('ACC_EXT_RECOVER_URL'));
|
||||
|
||||
if (Cfg::get('ACC_AUTH_MODE') != AUTH_MODE_SELF)
|
||||
$this->generateError();
|
||||
|
||||
parent::__construct($pageParam);
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->title[] = Lang::account('title');
|
||||
|
||||
parent::generate();
|
||||
|
||||
$msg = $this->processMailForm();
|
||||
|
||||
if ($this->success)
|
||||
$this->inputbox = ['inputbox-status', ['head' => Lang::account('inputbox', 'head', 'recoverUser'), 'message' => $msg]];
|
||||
else
|
||||
$this->inputbox = ['inputbox-form-email', array(
|
||||
'head' => Lang::account('inputbox', 'head', 'recoverUser'),
|
||||
'error' => $msg,
|
||||
'action' => '?account=forgot-username'
|
||||
)];
|
||||
}
|
||||
|
||||
private function processMailForm() : string
|
||||
{
|
||||
// no input yet. show empty form
|
||||
if (is_null($this->_post['email']))
|
||||
return '';
|
||||
|
||||
// truncated due to validation fail
|
||||
if (!$this->_post['email'])
|
||||
return Lang::account('emailInvalid');
|
||||
|
||||
$timeout = DB::Aowow()->selectCell('SELECT `unbanDate` FROM ?_account_bannedips WHERE `ip` = ? AND `type` = ?d AND `count` > ?d AND `unbanDate` > UNIX_TIMESTAMP()', User::$ip, IP_BAN_TYPE_USERNAME_RECOVERY, Cfg::get('ACC_FAILED_AUTH_COUNT'));
|
||||
|
||||
// on cooldown pretend we dont know the email address
|
||||
if ($timeout && $timeout > time())
|
||||
return Cfg::get('DEBUG') ? 'resend on cooldown: '.Util::formatTimeDiff($timeout).' remaining' : Lang::account('inputbox', 'error', 'emailNotFound');
|
||||
|
||||
// pretend recovery started
|
||||
if (!DB::Aowow()->selectCell('SELECT 1 FROM ?_account WHERE `email` = ?', $this->_post['email']))
|
||||
{
|
||||
// do not confirm or deny existence of email
|
||||
$this->success = !Cfg::get('DEBUG');
|
||||
return Cfg::get('DEBUG') ? Lang::account('inputbox', 'error', 'emailNotFound') : Lang::account('inputbox', 'message', 'recovUserSent', [$this->_post['email']]);
|
||||
}
|
||||
|
||||
// recovery actually started
|
||||
if ($err = $this->startRecovery(ACC_STATUS_RECOVER_USER, 'recover-user', $this->_post['email']))
|
||||
return $err;
|
||||
|
||||
DB::Aowow()->query('INSERT INTO ?_account_bannedips (`ip`, `type`, `count`, `unbanDate`) VALUES (?, ?d, ?d, UNIX_TIMESTAMP() + ?d) ON DUPLICATE KEY UPDATE `count` = `count` + ?d, `unbanDate` = UNIX_TIMESTAMP() + ?d',
|
||||
User::$ip, IP_BAN_TYPE_USERNAME_RECOVERY, Cfg::get('ACC_FAILED_AUTH_COUNT') + 1, Cfg::get('ACC_FAILED_AUTH_COUNT'), Cfg::get('ACC_FAILED_AUTH_BLOCK'), Cfg::get('ACC_FAILED_AUTH_BLOCK'));
|
||||
|
||||
$this->success = true;
|
||||
return Lang::account('inputbox', 'message', 'recovUserSent', [$this->_post['email']]);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,108 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed via form submit on user settings page
|
||||
*/
|
||||
|
||||
class AccountForumavatarResponse extends TextResponse
|
||||
{
|
||||
protected ?string $redirectTo = '?account#community';
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
// called via form submit
|
||||
protected array $expectedPOST = array(
|
||||
'avatar' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 0, 'max_range' => 2 ]],
|
||||
'wowicon' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => '/^[[:print:]]+$/' ]], // file name can have \W chars: inv_misc_fork&knife, achievement_dungeon_drak'tharon_heroic
|
||||
'customicon' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 1 ]]
|
||||
);
|
||||
// called via ajax
|
||||
protected array $expectedGET = array(
|
||||
'avatar' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 2, 'max_range' => 2]],
|
||||
'customicon' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 1 ]]
|
||||
);
|
||||
|
||||
private bool $success = false;
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (User::isBanned())
|
||||
return;
|
||||
|
||||
$msg = match ($this->_post['avatar'] ?? $this->_get['avatar'])
|
||||
{
|
||||
0 => $this->unset(), // none
|
||||
1 => $this->fromIcon(), // wow icon
|
||||
2 => $this->fromUpload(!$this->_get['avatar']), // custom icon (premium feature)
|
||||
default => Lang::main('genericError')
|
||||
};
|
||||
|
||||
if ($msg)
|
||||
$_SESSION['msg'] = ['avatar', $this->success, $msg];
|
||||
}
|
||||
|
||||
private function unset() : string
|
||||
{
|
||||
$x = DB::Aowow()->query('UPDATE ?_account SET `avatar` = 0 WHERE `id` = ?d', User::$id);
|
||||
if ($x === null || $x === false)
|
||||
return Lang::main('genericError');
|
||||
|
||||
$this->success = true;
|
||||
|
||||
return Lang::account('updateMessage', $x === 0 ? 'avNoChange' : 'avSuccess');
|
||||
}
|
||||
|
||||
private function fromIcon() : string
|
||||
{
|
||||
if (!$this->assertPOST('wowicon'))
|
||||
return Lang::main('intError');
|
||||
|
||||
$icon = strtolower(trim($this->_post['wowicon']));
|
||||
|
||||
if (!DB::Aowow()->selectCell('SELECT 1 FROM ?_icons WHERE `name` = ?', $icon))
|
||||
return Lang::account('updateMessage', 'avNotFound');
|
||||
|
||||
$x = DB::Aowow()->query('UPDATE ?_account SET `avatar` = 1, `wowicon` = ? WHERE `id` = ?d', strtolower($icon), User::$id);
|
||||
if ($x === null || $x === false)
|
||||
return Lang::main('genericError');
|
||||
|
||||
$this->success = true;
|
||||
|
||||
$msg = Lang::account('updateMessage', $x === 0 ? 'avNoChange' : 'avSuccess');
|
||||
if (($qty = DB::Aowow()->selectCell('SELECT COUNT(1) FROM ?_account WHERE `wowicon` = ?', $icon)) > 1)
|
||||
$msg .= ' '.Lang::account('updateMessage', 'avNthUser', [$qty]);
|
||||
else
|
||||
$msg .= ' '.Lang::account('updateMessage', 'av1stUser');
|
||||
|
||||
return $msg;
|
||||
}
|
||||
|
||||
protected function fromUpload(bool $viaPOST) : string
|
||||
{
|
||||
if (!User::isPremium())
|
||||
return Lang::main('genericError');
|
||||
|
||||
if (($viaPOST && !$this->assertPOST('customicon')) || (!$viaPOST && !$this->assertGET('customicon')))
|
||||
return Lang::main('intError');
|
||||
|
||||
$customIcon = $this->_post['customicon'] ?? $this->_get['customicon'];
|
||||
|
||||
$x = DB::Aowow()->query('UPDATE ?_account_avatars SET `current` = IF(`id` = ?d, 1, 0) WHERE `userId` = ?d AND `status` <> ?d', $customIcon, User::$id, AvatarMgr::STATUS_REJECTED);
|
||||
if (!is_int($x))
|
||||
return Lang::main('genericError');
|
||||
|
||||
if (!is_int(DB::Aowow()->query('UPDATE ?_account SET `avatar` = 2 WHERE `id` = ?d', User::$id)))
|
||||
return Lang::main('intError');
|
||||
|
||||
$this->success = true;
|
||||
|
||||
return Lang::account('updateMessage', $x === 0 ? 'avNoChange' : 'avSuccess');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,41 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed via form submit on user settings page
|
||||
*/
|
||||
|
||||
class AccountPremiumborderResponse extends TextResponse
|
||||
{
|
||||
protected ?string $redirectTo = '?account#premium';
|
||||
protected bool $requiresLogin = true;
|
||||
protected int $requiredUserGroup = U_GROUP_PREMIUM_PERMISSIONS;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'avatarborder' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 0, 'max_range' => 4]],
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (User::isBanned())
|
||||
return;
|
||||
|
||||
if (!$this->assertPOST('avatarborder'))
|
||||
return;
|
||||
|
||||
$x = DB::Aowow()->query('UPDATE ?_account SET `avatarborder` = ?d WHERE `id` = ?d', $this->_post['avatarborder'], User::$id);
|
||||
if (!is_int($x))
|
||||
$_SESSION['msg'] = ['premiumborder', false, Lang::main('genericError')];
|
||||
else if (!$x)
|
||||
$_SESSION['msg'] = ['premiumborder', true, Lang::account('updateMessage', 'avNoChange')];
|
||||
else
|
||||
$_SESSION['msg'] = ['premiumborder', true, Lang::account('updateMessage', 'avSuccess')];
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed via form button on user settings page
|
||||
*/
|
||||
|
||||
class AccountRenameiconResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
protected int $requiredUserGroup = U_GROUP_PREMIUM_PERMISSIONS;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'name' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' =>'/^[a-zA-Z][a-zA-Z0-9 ]{0,19}$/']]
|
||||
);
|
||||
|
||||
/*
|
||||
* response not evaluated
|
||||
*/
|
||||
protected function generate() : void
|
||||
{
|
||||
if (User::isBanned() || !$this->assertPOST('id', 'name'))
|
||||
return;
|
||||
|
||||
// regexp same as in account.js
|
||||
DB::Aowow()->query('UPDATE ?_account_avatars SET `name` = ? WHERE `id` = ?d AND `userId` = ?d', trim($this->_post['name']), $this->_post['id'], User::$id);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,52 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed after successful resend request
|
||||
* empty page with status box
|
||||
*/
|
||||
|
||||
class AccountResendsubmitResponse extends TemplateResponse
|
||||
{
|
||||
protected string $template = 'text-page-generic';
|
||||
protected string $pageName = 'resend';
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'email' => ['filter' => FILTER_VALIDATE_EMAIL, 'flags' => FILTER_FLAG_STRIP_AOWOW]
|
||||
);
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
if (!Cfg::get('ACC_ALLOW_REGISTER') || Cfg::get('ACC_AUTH_MODE') != AUTH_MODE_SELF)
|
||||
$this->generateError();
|
||||
|
||||
parent::__construct($pageParam);
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->title[] = Lang::account('title');
|
||||
|
||||
$error = $message = '';
|
||||
|
||||
if ($this->assertPOST('email'))
|
||||
$message = Lang::account('inputbox', 'message', 'createAccSent', [$this->_post['email']]);
|
||||
else
|
||||
$error = Lang::main('intError');
|
||||
|
||||
parent::generate();
|
||||
|
||||
$this->inputbox = ['inputbox-status', array(
|
||||
'head' => Lang::account('inputbox', 'head', 'register', [1.5]),
|
||||
'message' => $message,
|
||||
'error' => $error
|
||||
)];
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,98 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed via link on login page
|
||||
* empty page with status box
|
||||
*/
|
||||
|
||||
class AccountResendResponse extends TemplateResponse
|
||||
{
|
||||
protected string $template = 'text-page-generic';
|
||||
protected string $pageName = 'resend';
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'email' => ['filter' => FILTER_VALIDATE_EMAIL, 'flags' => FILTER_FLAG_STRIP_AOWOW]
|
||||
);
|
||||
|
||||
private bool $success = false;
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
if (Cfg::get('ACC_EXT_RECOVER_URL'))
|
||||
$this->forward(Cfg::get('ACC_EXT_RECOVER_URL'));
|
||||
|
||||
if (!Cfg::get('ACC_ALLOW_REGISTER') || Cfg::get('ACC_AUTH_MODE') != AUTH_MODE_SELF)
|
||||
$this->generateError();
|
||||
|
||||
parent::__construct($pageParam);
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->title[] = Lang::account('title');
|
||||
|
||||
parent::generate();
|
||||
|
||||
// error from account=activate
|
||||
if (isset($_SESSION['error']['activate']))
|
||||
{
|
||||
$msg = $_SESSION['error']['activate'];
|
||||
unset($_SESSION['error']['activate']);
|
||||
}
|
||||
else
|
||||
$msg = $this->resend();
|
||||
|
||||
if ($this->success)
|
||||
$this->inputbox = ['inputbox-status', ['head' => Lang::account('inputbox', 'head', 'resendMail'), 'message' => $msg]];
|
||||
else
|
||||
$this->inputbox = ['inputbox-form-email', array(
|
||||
'head' => Lang::account('inputbox', 'head', 'resendMail'),
|
||||
'message' => Lang::account('inputbox', 'message', 'resendMail'),
|
||||
'error' => $msg,
|
||||
'action' => '?account=resend',
|
||||
)];
|
||||
}
|
||||
|
||||
private function resend() : string
|
||||
{
|
||||
// no input yet. show clean form
|
||||
if (is_null($this->_post['email']))
|
||||
return '';
|
||||
|
||||
// truncated due to validation fail
|
||||
if (!$this->_post['email'])
|
||||
return Lang::account('emailInvalid');
|
||||
|
||||
$timeout = DB::Aowow()->selectCell('SELECT `unbanDate` FROM ?_account_bannedips WHERE `ip` = ? AND `type` = ?d AND `count` > ?d AND `unbanDate` > UNIX_TIMESTAMP()', User::$ip, IP_BAN_TYPE_REGISTRATION_ATTEMPT, Cfg::get('ACC_FAILED_AUTH_COUNT'));
|
||||
|
||||
// on cooldown pretend we dont know the email address
|
||||
if ($timeout && $timeout > time())
|
||||
return Cfg::get('DEBUG') ? 'resend on cooldown: '.Util::formatTimeDiff($timeout).' remaining' : Lang::account('inputbox', 'error', 'emailNotFound');
|
||||
|
||||
// check email and account status
|
||||
if ($token = DB::Aowow()->selectCell('SELECT `token` FROM ?_account WHERE `email` = ? AND `status` = ?d', $this->_post['email'], ACC_STATUS_NEW))
|
||||
{
|
||||
if (!Util::sendMail($this->_post['email'], 'activate-account', [$token]))
|
||||
return Lang::main('intError');
|
||||
|
||||
DB::Aowow()->query('INSERT INTO ?_account_bannedips (`ip`, `type`, `count`, `unbanDate`) VALUES (?, ?d, ?d, UNIX_TIMESTAMP() + ?d) ON DUPLICATE KEY UPDATE `count` = `count` + ?d, `unbanDate` = UNIX_TIMESTAMP() + ?d',
|
||||
User::$ip, IP_BAN_TYPE_REGISTRATION_ATTEMPT, Cfg::get('ACC_FAILED_AUTH_COUNT') + 1, Cfg::get('ACC_FAILED_AUTH_COUNT'), Cfg::get('ACC_FAILED_AUTH_BLOCK'), Cfg::get('ACC_FAILED_AUTH_BLOCK'));
|
||||
|
||||
$this->success = true;
|
||||
return Lang::account('inputbox', 'message', 'createAccSent', [$this->_post['email']]);
|
||||
}
|
||||
|
||||
// pretend recovery started
|
||||
// do not confirm or deny existence of email
|
||||
$this->success = !Cfg::get('DEBUG');
|
||||
return Cfg::get('DEBUG') ? Lang::account('inputbox', 'error', 'emailNotFound') : Lang::account('inputbox', 'message', 'createAccSent', [$this->_post['email']]);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,121 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed via links on signin form and from recovery email
|
||||
*
|
||||
* A) redirect to external page
|
||||
* B) 1. click password reset link > display email form
|
||||
* 2. submit email form > send mail with recovery link
|
||||
* 3. click recovery link from mail > display password reset form
|
||||
* 4. submit password reset form > update password
|
||||
*/
|
||||
|
||||
class AccountresetpasswordResponse extends TemplateResponse
|
||||
{
|
||||
use TrRecoveryHelper, TrGetNext;
|
||||
|
||||
protected string $template = 'text-page-generic';
|
||||
protected string $pageName = 'reset-password';
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'key' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => '/^[a-zA-Z0-9]{40}$/']],
|
||||
'next' => ['filter' => FILTER_SANITIZE_URL, 'flags' => FILTER_FLAG_STRIP_AOWOW ]
|
||||
);
|
||||
protected array $expectedPOST = array(
|
||||
'key' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => '/^[a-zA-Z0-9]{40}$/']],
|
||||
'email' => ['filter' => FILTER_VALIDATE_EMAIL, 'flags' => FILTER_FLAG_STRIP_AOWOW ],
|
||||
'password' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine'] ],
|
||||
'c_password' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine'] ]
|
||||
);
|
||||
|
||||
private bool $success = false;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->title[] = Lang::account('title');
|
||||
|
||||
parent::__construct();
|
||||
|
||||
// don't redirect logged in users
|
||||
// you can be forgetful AND logged in
|
||||
|
||||
if (Cfg::get('ACC_EXT_RECOVER_URL'))
|
||||
$this->forward(Cfg::get('ACC_EXT_RECOVER_URL'));
|
||||
|
||||
if (Cfg::get('ACC_AUTH_MODE') != AUTH_MODE_SELF)
|
||||
$this->generateError();
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
parent::generate();
|
||||
|
||||
$errMsg = '';
|
||||
if (!$this->assertGET('key') && !$this->assertPOST('key'))
|
||||
$errMsg = Lang::account('inputbox', 'error', 'passTokenLost');
|
||||
else if ($this->_get['key'] && !DB::Aowow()->selectCell('SELECT 1 FROM ?_account WHERE `token` = ? AND `status` = ?d AND `statusTimer` > UNIX_TIMESTAMP()', $this->_get['key'], ACC_STATUS_RECOVER_PASS))
|
||||
$errMsg = Lang::account('inputbox', 'error', 'passTokenUsed');
|
||||
|
||||
if ($errMsg)
|
||||
{
|
||||
$this->inputbox = ['inputbox-status', array(
|
||||
'head' => Lang::account('inputbox', 'head', 'error'),
|
||||
'error' => $errMsg
|
||||
)];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// step "2.5"
|
||||
$errMsg = $this->doResetPass();
|
||||
if ($this->success)
|
||||
$this->forward('?account=signin');
|
||||
|
||||
// step 2
|
||||
$this->inputbox = ['inputbox-form-password', array(
|
||||
'head' => Lang::account('inputbox', 'head', 'recoverPass', [2]),
|
||||
'token' => $this->_post['key'] ?? $this->_get['key'],
|
||||
'action' => '?account=reset-password&next=account=signin',
|
||||
'error' => $errMsg,
|
||||
)];
|
||||
}
|
||||
|
||||
private function doResetPass() : string
|
||||
{
|
||||
// no input yet. show clean form
|
||||
if (!$this->assertPOST('key', 'password', 'c_password') && is_null($this->_post['email']))
|
||||
return '';
|
||||
|
||||
// truncated due to validation fail
|
||||
if (!$this->_post['email'])
|
||||
return Lang::account('emailInvalid');
|
||||
|
||||
if ($this->_post['password'] != $this->_post['c_password'])
|
||||
return Lang::account('passCheckFail');
|
||||
|
||||
$userData = DB::Aowow()->selectRow('SELECT `id`, `passHash` FROM ?_account WHERE `token` = ? AND `email` = ? AND `status` = ?d AND `statusTimer` > UNIX_TIMESTAMP()',
|
||||
$this->_post['key'],
|
||||
$this->_post['email'],
|
||||
ACC_STATUS_RECOVER_PASS
|
||||
);
|
||||
if (!$userData)
|
||||
return Lang::account('inputbox', 'error', 'emailNotFound');
|
||||
|
||||
if (!User::verifyCrypt($this->_post['c_password'], $userData['passHash']))
|
||||
return Lang::account('newPassDiff');
|
||||
|
||||
if (!DB::Aowow()->query('UPDATE ?_account SET `passHash` = ?, `status` = ?d WHERE `id` = ?d', User::hashCrypt($this->_post['c_password']), ACC_STATUS_NONE, $userData['id']))
|
||||
return Lang::main('intError');
|
||||
|
||||
$this->success = true;
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,62 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed via revert email link
|
||||
* write status to session and redirect to account settings
|
||||
*/
|
||||
|
||||
// ?auth=email-revert
|
||||
class AccountRevertemailaddressResponse extends TemplateResponse
|
||||
{
|
||||
protected string $template = 'text-page-generic';
|
||||
protected string $pageName = 'revert-email-address';
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'key' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => '/^[a-zA-Z0-9]{40}$/']]
|
||||
);
|
||||
|
||||
private bool $success = false;
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
parent::generate();
|
||||
|
||||
if (User::isBanned())
|
||||
return;
|
||||
|
||||
$msg = $this->revert();
|
||||
|
||||
$this->inputbox = ['inputbox-status', array(
|
||||
'head' => Lang::account('inputbox', 'head', $this->success ? 'success' : 'error'),
|
||||
'message' => $this->success ? $msg : '',
|
||||
'error' => $this->success ? '' : $msg,
|
||||
)];
|
||||
}
|
||||
|
||||
// this should probably take precedence over email-change
|
||||
// todo - move personal settings changes to separate table
|
||||
private function revert() : string
|
||||
{
|
||||
if (!$this->assertGET('key'))
|
||||
return Lang::main('intError');
|
||||
|
||||
$acc = DB::Aowow()->selectRow('SELECT `updateValue`, `status`, `statusTimer` FROM ?_account WHERE `token` = ?', $this->_get['key']);
|
||||
if (!$acc || $acc['status'] != ACC_STATUS_CHANGE_EMAIL || $acc['statusTimer'] < time())
|
||||
return Lang::account('inputbox', 'error', 'mailTokenUsed');
|
||||
|
||||
// 0 changes == error
|
||||
if (!DB::Aowow()->query('UPDATE ?_account SET `status` = ?d, `statusTimer` = 0, `token` = "", `updateValue` = "" WHERE `token` = ?', ACC_STATUS_NONE, $this->_get['key']))
|
||||
return Lang::main('intError');
|
||||
|
||||
$this->success = true;
|
||||
return Lang::account('inputbox', 'message', 'mailRevertOk');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,148 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
2 modes
|
||||
A) show form
|
||||
B) execute login and forward to
|
||||
* self on failure
|
||||
* next on success
|
||||
*/
|
||||
|
||||
class AccountSigninResponse extends TemplateResponse
|
||||
{
|
||||
use TrGetNext;
|
||||
|
||||
protected string $template = 'text-page-generic';
|
||||
protected string $pageName = 'signin';
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'username' => ['filter' => FILTER_CALLBACK, 'options' => [Util::class, 'validateLogin'] ],
|
||||
'password' => ['filter' => FILTER_CALLBACK, 'options' => [Util::class, 'validatePassword']],
|
||||
'remember_me' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkRememberMe'] ]
|
||||
);
|
||||
protected array $expectedGET = array(
|
||||
'key' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => '/^[a-zA-Z0-9]{40}$/']],
|
||||
'next' => ['filter' => FILTER_SANITIZE_URL, 'flags' => FILTER_FLAG_STRIP_AOWOW ]
|
||||
);
|
||||
|
||||
private bool $success = false;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
// if the user is logged in, goto user dashboard
|
||||
if (User::isLoggedIn())
|
||||
$this->forward('?user='.User::$username);
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$username =
|
||||
$error = '';
|
||||
$rememberMe = !!$this->_post['remember_me'];
|
||||
|
||||
$this->title = [Lang::account('title')];
|
||||
|
||||
// coming from user recovery or creation, prefill username
|
||||
if ($this->_get['key'])
|
||||
{
|
||||
if ($userData = DB::Aowow()->selectRow('SELECT a.`login` AS "0", IF(s.`expires`, 0, 1) AS "1" FROM ?_account a LEFT JOIN ?_account_sessions s ON a.`id` = s.`userId` AND a.`token` = s.`sessionId` WHERE a.`status` IN (?a) AND a.`token` = ?',
|
||||
[ACC_STATUS_RECOVER_USER, ACC_STATUS_NONE], $this->_get['key']))
|
||||
[$username, $rememberMe] = $userData;
|
||||
}
|
||||
|
||||
if ($this->doSignIn($error))
|
||||
$this->forward($this->getNext(true));
|
||||
|
||||
if ($error)
|
||||
User::destroy();
|
||||
|
||||
$this->inputbox = ['inputbox-form-signin', array(
|
||||
'head' => Lang::account('inputbox', 'head', 'signin'),
|
||||
'action' => '?account=signin&next='.$this->getNext(),
|
||||
'error' => $error,
|
||||
'username' => $username,
|
||||
'rememberMe' => $rememberMe,
|
||||
'hasRecovery' => Cfg::get('ACC_EXT_RECOVER_URL') || Cfg::get('ACC_AUTH_MODE') == AUTH_MODE_SELF,
|
||||
)];
|
||||
|
||||
parent::generate();
|
||||
}
|
||||
|
||||
private function doSignIn(string &$error) : bool
|
||||
{
|
||||
if (is_null($this->_post['username']) && is_null($this->_post['password']))
|
||||
return false;
|
||||
|
||||
if (!$this->assertPOST('username'))
|
||||
{
|
||||
$error = Lang::account('userNotFound');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->assertPOST('password'))
|
||||
{
|
||||
$error = Lang::account('wrongPass');
|
||||
return false;
|
||||
}
|
||||
|
||||
$error = match (User::authenticate($this->_post['username'], $this->_post['password']))
|
||||
{
|
||||
AUTH_OK, AUTH_BANNED => $this->onAuthSuccess(),
|
||||
// AUTH_BANNED => Lang::account('accBanned'); // ToDo: should this return an error? the actual account functionality should be blocked elsewhere
|
||||
AUTH_WRONGUSER => Lang::account('userNotFound'),
|
||||
AUTH_WRONGPASS => Lang::account('wrongPass'),
|
||||
AUTH_IPBANNED => Lang::account('inputbox', 'error', 'loginExceeded', [Util::formatTime(Cfg::get('ACC_FAILED_AUTH_BLOCK') * 1000)]),
|
||||
AUTH_INTERNAL_ERR => Lang::main('intError'),
|
||||
default => Lang::main('intError')
|
||||
};
|
||||
|
||||
return !$error;
|
||||
}
|
||||
|
||||
private function onAuthSuccess() : string
|
||||
{
|
||||
if (!User::$ip)
|
||||
{
|
||||
trigger_error('AccountSigninResponse::onAuthSuccess() - tried to login user without ip set', E_USER_ERROR);
|
||||
return Lang::main('intError');
|
||||
}
|
||||
|
||||
// reset account status, update expiration
|
||||
$ok = DB::Aowow()->query('UPDATE ?_account SET `prevIP` = IF(`curIp` = ?, `prevIP`, `curIP`), `curIP` = IF(`curIp` = ?, `curIP`, ?), `status` = IF(`status` = ?d, `status`, 0), `statusTimer` = IF(`status` = ?d, `statusTimer`, 0), `token` = IF(`status` = ?d, `token`, "") WHERE `id` = ?d',
|
||||
User::$ip, User::$ip, User::$ip,
|
||||
ACC_STATUS_NEW, ACC_STATUS_NEW, ACC_STATUS_NEW,
|
||||
User::$id // available after successful User:authenticate
|
||||
);
|
||||
|
||||
if (!is_int($ok)) // num updated fields or null on fail
|
||||
{
|
||||
trigger_error('AccountSigninResponse::onAuthSuccess() - failed to update account status', E_USER_ERROR);
|
||||
return Lang::main('intError');
|
||||
}
|
||||
|
||||
// DELETE temp session
|
||||
if ($this->_get['key'])
|
||||
DB::Aowow()->query('DELETE FROM ?_account_sessions WHERE `sessionId` = ?', $this->_get['key']);
|
||||
|
||||
session_regenerate_id(true); // user status changed => regenerate id
|
||||
|
||||
// create new session entry
|
||||
DB::Aowow()->query('INSERT INTO ?_account_sessions (`userId`, `sessionId`, `created`, `expires`, `touched`, `deviceInfo`, `ip`, `status`) VALUES (?d, ?, ?d, ?d, ?d, ?, ?, ?d)',
|
||||
User::$id, session_id(), time(), $this->_post['remember_me'] ? 0 : time() + Cfg::get('SESSION_TIMEOUT_DELAY'), time(), User::$agent, User::$ip, SESSION_ACTIVE);
|
||||
|
||||
if (User::init()) // reinitialize the user
|
||||
User::save();
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,40 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AccountSignoutResponse extends TextResponse
|
||||
{
|
||||
use TrGetNext;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'next' => ['filter' => FILTER_SANITIZE_URL, 'flags' => FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH],
|
||||
'global' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkEmptySet'] ]
|
||||
);
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
// if the user not is logged in goto login page
|
||||
if (!User::isLoggedIn())
|
||||
$this->forwardToSignIn();
|
||||
|
||||
parent::__construct($pageParam);
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if ($this->_get['global'])
|
||||
DB::Aowow()->query('UPDATE ?_account_sessions SET `touched` = ?d, `status` = ?d WHERE `userId` = ?d', time(), SESSION_FORCED_LOGOUT, User::$id);
|
||||
else
|
||||
DB::Aowow()->query('UPDATE ?_account_sessions SET `touched` = ?d, `status` = ?d WHERE `sessionId` = ?', time(), SESSION_LOGOUT, session_id());
|
||||
|
||||
User::destroy();
|
||||
|
||||
$this->redirectTo = $this->getNext(true);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,163 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed via signup link
|
||||
* self referencing
|
||||
*/
|
||||
class AccountSignupResponse extends TemplateResponse
|
||||
{
|
||||
use TrGetNext;
|
||||
|
||||
protected string $template = 'text-page-generic';
|
||||
protected string $pageName = 'signup';
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'username' => ['filter' => FILTER_SANITIZE_SPECIAL_CHARS, 'flags' => FILTER_FLAG_STRIP_AOWOW ],
|
||||
'email' => ['filter' => FILTER_SANITIZE_EMAIL, 'flags' => FILTER_FLAG_STRIP_AOWOW ],
|
||||
'password' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine'] ],
|
||||
'c_password' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine'] ],
|
||||
'remember_me' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkRememberMe']]
|
||||
);
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'next' => ['filter' => FILTER_SANITIZE_URL, 'flags' => FILTER_FLAG_STRIP_AOWOW]
|
||||
);
|
||||
|
||||
private bool $success = false;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
// if the user is logged in goto account dashboard
|
||||
if (User::isLoggedIn())
|
||||
$this->forward('?account');
|
||||
|
||||
// redirect to external registration page, if set
|
||||
if (Cfg::get('ACC_EXT_CREATE_URL'))
|
||||
$this->forward(Cfg::get('ACC_EXT_CREATE_URL'));
|
||||
|
||||
parent::__construct();
|
||||
|
||||
// registration not enabled on self
|
||||
if (!Cfg::get('ACC_ALLOW_REGISTER'))
|
||||
$this->generateError();
|
||||
|
||||
if (Cfg::get('ACC_AUTH_MODE') != AUTH_MODE_SELF)
|
||||
$this->generateError();
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->title[] = Lang::account('title');
|
||||
|
||||
// step 1 - no params > signup form
|
||||
// step 2 - any param > status box
|
||||
// step 3 - on ?account=activate
|
||||
|
||||
$message = $this->doSignUp();
|
||||
|
||||
if ($this->success)
|
||||
{
|
||||
$this->inputbox = ['inputbox-status', array(
|
||||
'head' => Lang::account('inputbox', 'head', 'register', [1.5]),
|
||||
'message' => Lang::account('inputbox', 'message', 'createAccSent', [$this->_post['email']])
|
||||
)];
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->inputbox = ['inputbox-form-signup', array(
|
||||
'head' => Lang::account('inputbox', 'head', 'register', [1]),
|
||||
'error' => $message,
|
||||
'action' => '?account=signup&next='.$this->getNext(),
|
||||
'username' => $this->_post['username'] ?? '',
|
||||
'email' => $this->_post['email'] ?? '',
|
||||
'rememberMe' => !!$this->_post['remember_me'],
|
||||
)];
|
||||
}
|
||||
|
||||
parent::generate();
|
||||
}
|
||||
|
||||
private function doSignUp() : string
|
||||
{
|
||||
// no input yet. show clean form
|
||||
if (!$this->assertPOST('username', 'password', 'c_password') && is_null($this->_post['email']))
|
||||
return '';
|
||||
|
||||
// truncated due to validation fail
|
||||
if (!$this->_post['email'])
|
||||
return Lang::account('emailInvalid');
|
||||
|
||||
// check username
|
||||
if (!Util::validateUsername($this->_post['username'], $e))
|
||||
return Lang::account($e == 1 ? 'errNameLength' : 'errNameChars');
|
||||
|
||||
// check password
|
||||
if (!Util::validatePassword($this->_post['password'], $e))
|
||||
return Lang::account($e == 1 ? 'errPassLength' : 'errPassChars');
|
||||
|
||||
if ($this->_post['password'] !== $this->_post['c_password'])
|
||||
return Lang::account('passMismatch');
|
||||
|
||||
// check ip
|
||||
if (!User::$ip)
|
||||
return Lang::main('intError');
|
||||
|
||||
// limit account creation
|
||||
if (DB::Aowow()->selectRow('SELECT 1 FROM ?_account_bannedips WHERE `type` = ?d AND `ip` = ? AND `count` >= ?d AND `unbanDate` >= UNIX_TIMESTAMP()', IP_BAN_TYPE_REGISTRATION_ATTEMPT, User::$ip, Cfg::get('ACC_FAILED_AUTH_COUNT')))
|
||||
{
|
||||
DB::Aowow()->query('UPDATE ?_account_bannedips SET `count` = `count` + 1, `unbanDate` = UNIX_TIMESTAMP() + ?d WHERE `ip` = ? AND `type` = ?d', Cfg::get('ACC_FAILED_AUTH_BLOCK'), User::$ip, IP_BAN_TYPE_REGISTRATION_ATTEMPT);
|
||||
return Lang::account('inputbox', 'error', 'signupExceeded', [Util::formatTime(Cfg::get('ACC_FAILED_AUTH_BLOCK') * 1000)]);
|
||||
}
|
||||
|
||||
// username / email taken
|
||||
if ($inUseData = DB::Aowow()->SelectRow('SELECT `id`, `username`, `status` = ?d AND `statusTimer` < UNIX_TIMESTAMP() AS "expired" FROM ?_account WHERE (LOWER(`username`) = LOWER(?) OR LOWER(`email`) = LOWER(?))', ACC_STATUS_NEW, $this->_post['username'], $this->_post['email']))
|
||||
{
|
||||
if ($inUseData['expired'])
|
||||
DB::Aowow()->query('DELETE FROM ?_account WHERE `id` = ?d', $inUseData['id']);
|
||||
else
|
||||
return Util::lower($inUseData['username']) == Util::lower($this->_post['username']) ? Lang::account('nameInUse') : Lang::account('mailInUse');
|
||||
}
|
||||
|
||||
// create..
|
||||
$token = Util::createHash();
|
||||
$userId = DB::Aowow()->query('INSERT INTO ?_account (`login`, `passHash`, `username`, `email`, `joindate`, `curIP`, `locale`, `userGroups`, `status`, `statusTimer`, `token`) VALUES (?, ?, ?, ?, UNIX_TIMESTAMP(), ?, ?d, ?d, ?d, UNIX_TIMESTAMP() + ?d, ?)',
|
||||
$this->_post['username'],
|
||||
User::hashCrypt($this->_post['password']),
|
||||
$this->_post['username'],
|
||||
$this->_post['email'],
|
||||
User::$ip,
|
||||
Lang::getLocale()->value,
|
||||
U_GROUP_PENDING,
|
||||
ACC_STATUS_NEW,
|
||||
Cfg::get('ACC_CREATE_SAVE_DECAY'),
|
||||
$token
|
||||
);
|
||||
|
||||
if (!$userId)
|
||||
return Lang::main('intError');
|
||||
|
||||
// create session tied to the token to store remember_me status
|
||||
DB::Aowow()->query('INSERT INTO ?_account_sessions (`userId`, `sessionId`, `created`, `expires`, `touched`, `deviceInfo`, `ip`, `status`) VALUES (?d, ?, ?d, ?d, ?d, ?, ?, ?d)',
|
||||
$userId, $token, time(), $this->_post['remember_me'] ? 0 : time() + Cfg::get('SESSION_TIMEOUT_DELAY'), time(), User::$agent, User::$ip, SESSION_ACTIVE);
|
||||
|
||||
if (!Util::sendMail($this->_post['email'], 'activate-account', [$token], Cfg::get('ACC_CREATE_SAVE_DECAY')))
|
||||
return Lang::main('intError2', ['send mail']);
|
||||
|
||||
// success: update ip-bans
|
||||
DB::Aowow()->query('INSERT INTO ?_account_bannedips (`ip`, `type`, `count`, `unbanDate`) VALUES (?, ?d, 1, UNIX_TIMESTAMP() + ?d) ON DUPLICATE KEY UPDATE `count` = `count` + 1, `unbanDate` = UNIX_TIMESTAMP() + ?d',
|
||||
User::$ip, IP_BAN_TYPE_REGISTRATION_ATTEMPT, Cfg::get('ACC_FAILED_AUTH_BLOCK'), Cfg::get('ACC_FAILED_AUTH_BLOCK'));
|
||||
|
||||
Util::gainSiteReputation($userId, SITEREP_ACTION_REGISTER);
|
||||
|
||||
$this->success = true;
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,48 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed via account settings form submit
|
||||
* write status to session and redirect to account settings
|
||||
*/
|
||||
|
||||
class AccountUpdatecommunitysettingsResponse extends TextResponse
|
||||
{
|
||||
protected ?string $redirectTo = '?account#community';
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'desc' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextBlob']]
|
||||
);
|
||||
|
||||
private bool $success = false;
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (User::isBanned())
|
||||
return;
|
||||
|
||||
if ($message = $this->updateSettings())
|
||||
$_SESSION['msg'] = ['community', $this->success, $message];
|
||||
}
|
||||
|
||||
protected function updateSettings()
|
||||
{
|
||||
if (is_null($this->_post['desc'])) // assertPOST tests for empty string which is valid here
|
||||
return Lang::main('genericError');
|
||||
|
||||
// description - 0 modified rows is still success
|
||||
if (!is_int(DB::Aowow()->query('UPDATE ?_account SET `description` = ? WHERE `id` = ?d', $this->_post['desc'], User::$id)))
|
||||
return Lang::main('genericError');
|
||||
|
||||
$this->success = true;
|
||||
return Lang::account('updateMessage', 'community');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,80 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed via account settings form submit
|
||||
* write status to session and redirect to account settings
|
||||
*/
|
||||
|
||||
class AccountUpdateemailResponse extends TextResponse
|
||||
{
|
||||
protected ?string $redirectTo = '?account#personal';
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'newemail' => ['filter' => FILTER_VALIDATE_EMAIL, 'flags' => FILTER_FLAG_STRIP_AOWOW]
|
||||
);
|
||||
|
||||
private bool $success = false;
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
if (Cfg::get('ACC_AUTH_MODE') != AUTH_MODE_SELF)
|
||||
(new TemplateResponse())->generateError();
|
||||
|
||||
parent::__construct($pageParam);
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (User::isBanned())
|
||||
return;
|
||||
|
||||
if ($msg = $this->updateMail())
|
||||
$_SESSION['msg'] = ['email', $this->success, $msg];
|
||||
}
|
||||
|
||||
private function updateMail() : string
|
||||
{
|
||||
// no input yet
|
||||
if (is_null($this->_post['newemail']))
|
||||
return Lang::main('intError');
|
||||
// truncated due to validation fail
|
||||
if (!$this->_post['newemail'])
|
||||
return Lang::account('emailInvalid');
|
||||
|
||||
if (DB::Aowow()->selectCell('SELECT 1 FROM ?_account WHERE `email` = ? AND `id` <> ?d', $this->_post['newemail'], User::$id))
|
||||
return Lang::account('mailInUse');
|
||||
|
||||
$status = DB::Aowow()->selectCell('SELECT `status` FROM ?_account WHERE `statusTimer` > UNIX_TIMESTAMP() AND `id` = ?d', User::$id);
|
||||
if ($status != ACC_STATUS_NONE && $status != ACC_STATUS_CHANGE_EMAIL)
|
||||
return Lang::account('isRecovering', [Util::formatTime(Cfg::get('ACC_RECOVERY_DECAY') * 1000)]);
|
||||
|
||||
$oldEmail = DB::Aowow()->selectCell('SELECT `email` FROM ?_account WHERE `id` = ?d', User::$id);
|
||||
if ($this->_post['newemail'] == $oldEmail)
|
||||
return Lang::account('newMailDiff');
|
||||
|
||||
$token = Util::createHash();
|
||||
|
||||
// store new mail in updateValue field, exchange when confirmation mail gets confirmed
|
||||
if (!DB::Aowow()->query('UPDATE ?_account SET `updateValue` = ?, `status` = ?d, `statusTimer` = UNIX_TIMESTAMP() + ?d, `token` = ? WHERE `id` = ?d',
|
||||
$this->_post['newemail'], ACC_STATUS_CHANGE_EMAIL, Cfg::get('ACC_RECOVERY_DECAY'), $token, User::$id))
|
||||
return Lang::main('intError');
|
||||
|
||||
if (!Util::sendMail($this->_post['newemail'], 'change-email', [$token, $this->_post['newemail']], Cfg::get('ACC_RECOVERY_DECAY')))
|
||||
return Lang::main('intError2', ['send mail']);
|
||||
|
||||
if (!Util::sendMail($oldEmail, 'revert-email', [$token, $oldEmail], Cfg::get('ACC_RECOVERY_DECAY')))
|
||||
return Lang::main('intError2', ['send mail']);
|
||||
|
||||
$this->success = true;
|
||||
return Lang::account('updateMessage', 'personal', [$this->_post['newemail']]);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,60 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed via account settings form submit
|
||||
* write status to session and redirect to account settings
|
||||
*/
|
||||
|
||||
class AccountUpdategeneralsettingsResponse extends TextResponse
|
||||
{
|
||||
protected ?string $redirectTo = '?account#general';
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'modelrace' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['default' => 0, 'min_range' => 1, 'max_range' => 11]],
|
||||
'modelgender' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['default' => 0, 'min_range' => 1, 'max_range' => 2] ],
|
||||
'idsInLists' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkCheckbox'] ]
|
||||
);
|
||||
|
||||
private bool $success = false;
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (User::isBanned())
|
||||
return;
|
||||
|
||||
if ($message = $this->updateGeneral())
|
||||
$_SESSION['msg'] = ['general', $this->success, $message];
|
||||
}
|
||||
|
||||
private function updateGeneral() : string
|
||||
{
|
||||
if (!$this->assertPOST('modelrace', 'modelgender'))
|
||||
return Lang::main('genericError');
|
||||
|
||||
if ($this->_post['modelrace'] && !ChrRace::tryFrom($this->_post['modelrace']))
|
||||
return Lang::main('genericError');
|
||||
|
||||
// js handles this as cookie, so saved as cookie; Q - also save in ?_account table?
|
||||
if (!DB::Aowow()->query('REPLACE INTO ?_account_cookies (`userId`, `name`, `data`) VALUES (?d, ?, ?)', User::$id, 'default_3dmodel', $this->_post['modelrace']. ',' . $this->_post['modelgender']))
|
||||
return Lang::main('genericError');
|
||||
|
||||
if (!setcookie('default_3dmodel', $this->_post['modelrace']. ',' . $this->_post['modelgender'], 0, '/'))
|
||||
return Lang::main('intError');
|
||||
|
||||
// int > number of edited rows > no changes is still success
|
||||
if (!is_int(DB::Aowow()->query('UPDATE ?_account SET `debug` = ?d WHERE `id` = ?d', $this->_post['idsInLists'] ? 1 : 0, User::$id)))
|
||||
return Lang::main('intError');
|
||||
|
||||
$this->success = true;
|
||||
return Lang::account('updateMessage', 'general');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,86 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed via account settings form submit
|
||||
* write status to session and redirect to account settings
|
||||
*/
|
||||
|
||||
class AccountUpdatepasswordResponse extends TextResponse
|
||||
{
|
||||
protected ?string $redirectTo = '?account#personal';
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'currentPassword' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine']],
|
||||
'newPassword' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine']],
|
||||
'confirmPassword' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine']],
|
||||
'globalLogout' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkCheckbox']]
|
||||
);
|
||||
|
||||
private bool $success = false;
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
if (Cfg::get('ACC_AUTH_MODE') != AUTH_MODE_SELF)
|
||||
(new TemplateResponse())->generateError();
|
||||
|
||||
parent::__construct($pageParam);
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (User::isBanned())
|
||||
return;
|
||||
|
||||
if ($msg = $this->updatePassword())
|
||||
$_SESSION['msg'] = ['password', $this->success, $msg];
|
||||
}
|
||||
|
||||
private function updatePassword() : string
|
||||
{
|
||||
if (!$this->assertPOST('currentPassword', 'newPassword', 'confirmPassword'))
|
||||
return Lang::main('intError');
|
||||
|
||||
if (!Util::validatePassword($this->_post['newPassword'], $e))
|
||||
return Lang::account($e == 1 ? 'errPassLength' : 'errPassChars');
|
||||
|
||||
if ($this->_post['newPassword'] !== $this->_post['confirmPassword'])
|
||||
return Lang::account('passMismatch');
|
||||
|
||||
$userData = DB::Aowow()->selectRow('SELECT `status`, `passHash`, `statusTimer` FROM ?_account WHERE `id` = ?d', User::$id);
|
||||
if ($userData['status'] != ACC_STATUS_NONE && $userData['status'] != ACC_STATUS_CHANGE_PASS && $userData['statusTimer'] > time())
|
||||
return Lang::account('isRecovering', [Util::formatTime(Cfg::get('ACC_RECOVERY_DECAY') * 1000)]);
|
||||
|
||||
if (!User::verifyCrypt($this->_post['currentPassword'], $userData['passHash']))
|
||||
return Lang::account('wrongPass');
|
||||
|
||||
if (User::verifyCrypt($this->_post['newPassword'], $userData['passHash']))
|
||||
return Lang::account('newPassDiff');
|
||||
|
||||
$token = Util::createHash();
|
||||
|
||||
// store new hash in updateValue field, exchange when confirmation mail gets confirmed
|
||||
if (!DB::Aowow()->query('UPDATE ?_account SET `updateValue` = ?, `status` = ?d, `statusTimer` = UNIX_TIMESTAMP() + ?d, `token` = ? WHERE `id` = ?d',
|
||||
User::hashCrypt($this->_post['newPassword']), ACC_STATUS_CHANGE_PASS, Cfg::get('ACC_RECOVERY_DECAY'), $token, User::$id))
|
||||
return Lang::main('intError');
|
||||
|
||||
$email = DB::Aowow()->selectCell('SELECT `email` FROM ?_account WHERE `id` = ?d', User::$id);
|
||||
if (!Util::sendMail($email, 'update-password', [$token, $email], Cfg::get('ACC_RECOVERY_DECAY')))
|
||||
return Lang::main('intError2', ['send mail']);
|
||||
|
||||
// logout all other active sessions
|
||||
if ($this->_post['globalLogout'])
|
||||
DB::Aowow()->query('UPDATE ?_account_sessions SET `status` = ?d, `touched` = ?d WHERE `userId` = ?d AND `sessionId` <> ? AND `status` = ?d', SESSION_FORCED_LOGOUT, time(), User::$id, session_id(), SESSION_ACTIVE);
|
||||
|
||||
$this->success = true;
|
||||
return Lang::account('updateMessage', 'personal', [User::$email]);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,61 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed via account settings form submit
|
||||
* write status to session and redirect to account settings
|
||||
*/
|
||||
|
||||
class AccountUpdateusernameResponse extends TextResponse
|
||||
{
|
||||
protected ?string $redirectTo = '?account#personal';
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'newUsername' => ['filter' => FILTER_CALLBACK, 'options' => [Util::class, 'validateUsername']]
|
||||
);
|
||||
|
||||
private bool $success = false;
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
if (Cfg::get('ACC_AUTH_MODE') != AUTH_MODE_SELF)
|
||||
(new TemplateResponse())->generateError();
|
||||
|
||||
parent::__construct($pageParam);
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (User::isBanned())
|
||||
return;
|
||||
|
||||
if ($msg = $this->updateUsername())
|
||||
$_SESSION['msg'] = ['username', $this->success, $msg];
|
||||
}
|
||||
|
||||
private function updateUsername() : string
|
||||
{
|
||||
if (!$this->assertPOST('newUsername'))
|
||||
return Lang::main('intError');
|
||||
|
||||
if (DB::Aowow()->selectCell('SELECT `renameCooldown` FROM ?_account WHERE `id` = ?d', User::$id) > time())
|
||||
return Lang::main('intError'); // should have grabbed the error response..
|
||||
|
||||
// yes, including your current name. you don't want to change into your current name, right?
|
||||
if (DB::Aowow()->selectCell('SELECT 1 FROM ?_account WHERE LOWER(`username`) = LOWER(?)', $this->_post['newUsername']))
|
||||
return Lang::account('nameInUse');
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_account SET `username` = ?, `renameCooldown` = ?d WHERE `id` = ?d', $this->_post['newUsername'], time() + Cfg::get('acc_rename_decay'), User::$id);
|
||||
|
||||
$this->success = true;
|
||||
return Lang::account('updateMessage', 'username', [User::$username, $this->_post['newUsername']]);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,117 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed via ajax
|
||||
* returns scaleId if successful, 0 if not
|
||||
*/
|
||||
|
||||
class AccountWeightscalesResponse extends TextResponse
|
||||
{
|
||||
private const /* int */ MAX_SCALES = 5; // more or less hard-defined in LANG.message_weightscalesaveerror
|
||||
|
||||
protected bool $requiresLogin = true;
|
||||
protected mixed $result = 0; // default to error
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'save' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 1, 'max_range' => 1]],
|
||||
'delete' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 1, 'max_range' => 1]],
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'name' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkName'] ],
|
||||
'scale' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkScale'] ]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (User::isBanned())
|
||||
return;
|
||||
|
||||
if ($this->_post['save'] && $this->_post['id'])
|
||||
$this->updateWeights();
|
||||
|
||||
else if ($this->_post['save'])
|
||||
$this->createWeights();
|
||||
|
||||
else if ($this->_post['delete'])
|
||||
$this->deleteWeights();
|
||||
}
|
||||
|
||||
private function createWeights() : void
|
||||
{
|
||||
if (!$this->assertPOST('name', 'scale'))
|
||||
return;
|
||||
|
||||
$nScales = DB::Aowow()->selectCell('SELECT COUNT(`id`) FROM ?_account_weightscales WHERE `userId` = ?d', User::$id);
|
||||
if ($nScales >= self::MAX_SCALES)
|
||||
return;
|
||||
|
||||
if ($id = DB::Aowow()->query('INSERT INTO ?_account_weightscales (`userId`, `name`) VALUES (?d, ?)', User::$id, $this->_post['name']))
|
||||
if ($this->storeScaleData($id))
|
||||
$this->result = $id;
|
||||
}
|
||||
|
||||
private function updateWeights() : void
|
||||
{
|
||||
if (!$this->assertPOST('name', 'scale', 'id'))
|
||||
return;
|
||||
|
||||
// not in DB or not owned by user
|
||||
if (!DB::Aowow()->selectCell('SELECT 1 FROM ?_account_weightscales WHERE `userId` = ?d AND `id` = ?d', User::$id, $this->_post['id']))
|
||||
{
|
||||
trigger_error('AccountWeightscalesResponse::updateWeights - scale #'.$this->_post['id'].' not in db or not owned by user #'.User::$id, E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_account_weightscales SET `name` = ? WHERE `id` = ?d', $this->_post['name'], $this->_post['id']);
|
||||
$this->storeScaleData($this->_post['id']);
|
||||
|
||||
// return edited id on success
|
||||
$this->result = $this->_post['id'];
|
||||
}
|
||||
|
||||
private function deleteWeights() : void
|
||||
{
|
||||
if ($this->assertPOST('id'))
|
||||
DB::Aowow()->query('DELETE FROM ?_account_weightscales WHERE `id` = ?d AND `userId` = ?d', $this->_post['id'], User::$id);
|
||||
|
||||
$this->result = '';
|
||||
}
|
||||
|
||||
private function storeScaleData(int $scaleId) : bool
|
||||
{
|
||||
if (!is_int(DB::Aowow()->query('DELETE FROM ?_account_weightscale_data WHERE `id` = ?d', $scaleId)))
|
||||
return false;
|
||||
|
||||
foreach ($this->_post['scale'] as [$k, $v])
|
||||
if (in_array($k, Util::$weightScales)) // $v is known to be a positive int due to regex check
|
||||
if (!is_int(DB::Aowow()->query('INSERT INTO ?_account_weightscale_data VALUES (?d, ?, ?d)', $scaleId, $k, $v)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*************************************/
|
||||
/* additional request data callbacks */
|
||||
/*************************************/
|
||||
|
||||
protected static function checkScale(string $val) : array
|
||||
{
|
||||
if (preg_match('/^((\w+:\d+)(,\w+:\d+)*)$/', $val))
|
||||
return array_map(fn($x) => explode(':', $x), explode(',', $val));
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
protected static function checkName(string $val) : string
|
||||
{
|
||||
return mb_substr(preg_replace('/[^[:print:]]/', '', trim(urldecode($val))), 0, 32);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,511 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/* Notes:
|
||||
* can create achievement progress bars with
|
||||
* g_createProgressBar(c)
|
||||
* var c = {
|
||||
* text: "",
|
||||
* hoverText: "",
|
||||
* color: "", // cssClassName rep[0-7] | ach[0|1]
|
||||
* width: 0, // 0 <=> 100
|
||||
* }
|
||||
*/
|
||||
|
||||
class AchievementBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrDetailPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
|
||||
protected string $template = 'achievement';
|
||||
protected string $pageName = 'achievement';
|
||||
protected ?int $activeTab = parent::TAB_DATABASE;
|
||||
protected array $breadcrumb = [0, 9];
|
||||
|
||||
public int $type = Type::ACHIEVEMENT;
|
||||
public int $typeId = 0;
|
||||
public int $reqCrtQty = 0;
|
||||
public ?array $mail = null;
|
||||
public string $description = '';
|
||||
public array $criteria = [];
|
||||
public ?array $rewards = null;
|
||||
|
||||
private AchievementList $subject;
|
||||
|
||||
public function __construct(string $id)
|
||||
{
|
||||
parent::__construct($id);
|
||||
|
||||
$this->typeId = intVal($id);
|
||||
$this->contribute = Type::getClassAttrib($this->type, 'contribute') ?? CONTRIBUTE_NONE;
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->subject = new AchievementList(array(['id', $this->typeId]));
|
||||
if ($this->subject->error)
|
||||
$this->generateNotFound(Lang::game('achievement'), Lang::achievement('notFound'));
|
||||
|
||||
$this->extendGlobalData($this->subject->getJSGlobals(GLOBALINFO_REWARDS));
|
||||
|
||||
$this->h1 = $this->subject->getField('name', true);
|
||||
|
||||
$this->gPageInfo += array(
|
||||
'type' => $this->type,
|
||||
'typeId' => $this->typeId,
|
||||
'name' => $this->h1
|
||||
);
|
||||
|
||||
|
||||
/*************/
|
||||
/* Menu Path */
|
||||
/*************/
|
||||
|
||||
// create page title and path
|
||||
$curCat = $this->subject->getField('category');
|
||||
$catPath = [];
|
||||
while ($curCat > 0)
|
||||
{
|
||||
$catPath[] = $curCat;
|
||||
$curCat = DB::Aowow()->SelectCell('SELECT `parentCat` FROM ?_achievementcategory WHERE `id` = ?d', $curCat);
|
||||
}
|
||||
|
||||
$this->breadcrumb = array_merge($this->breadcrumb, array_reverse($catPath));
|
||||
|
||||
|
||||
/**************/
|
||||
/* Page Title */
|
||||
/**************/
|
||||
|
||||
array_unshift($this->title, $this->subject->getField('name', true), Util::ucFirst(Lang::game('achievement')));
|
||||
|
||||
|
||||
/***********/
|
||||
/* Infobox */
|
||||
/***********/
|
||||
|
||||
$infobox = Lang::getInfoBoxForFlags($this->subject->getField('cuFlags'));
|
||||
|
||||
// points
|
||||
if ($_ = $this->subject->getField('points'))
|
||||
$infobox[] = Lang::achievement('points').Lang::main('colon').'[achievementpoints='.$_.']';
|
||||
|
||||
// location
|
||||
// todo (low)
|
||||
|
||||
// faction
|
||||
$infobox[] = Lang::main('side') . match ($this->subject->getField('faction'))
|
||||
{
|
||||
SIDE_ALLIANCE => '[span class=icon-alliance]'.Lang::game('si', SIDE_ALLIANCE).'[/span]',
|
||||
SIDE_HORDE => '[span class=icon-horde]'.Lang::game('si', SIDE_HORDE).'[/span]',
|
||||
default => Lang::game('si', SIDE_BOTH) // 0, 3
|
||||
};
|
||||
|
||||
// id
|
||||
$infobox[] = Lang::achievement('id') . $this->typeId;
|
||||
|
||||
// icon
|
||||
if ($_ = $this->subject->getField('iconId'))
|
||||
{
|
||||
$infobox[] = Util::ucFirst(Lang::game('icon')).Lang::main('colon').'[icondb='.$_.' name=true]';
|
||||
$this->extendGlobalIds(Type::ICON, $_);
|
||||
}
|
||||
|
||||
// profiler relateed (note that this is part of the cache. I don't think this is important enough to calc for every view)
|
||||
if (Cfg::get('PROFILER_ENABLE') && !($this->subject->getField('flags') & ACHIEVEMENT_FLAG_COUNTER))
|
||||
{
|
||||
$x = DB::Aowow()->selectCell('SELECT COUNT(1) FROM ?_profiler_completion_achievements WHERE `achievementId` = ?d', $this->typeId);
|
||||
$y = DB::Aowow()->selectCell('SELECT COUNT(1) FROM ?_profiler_profiles WHERE `custom` = 0 AND `stub` = 0');
|
||||
$infobox[] = Lang::profiler('attainedBy', [round(($x ?: 0) * 100 / ($y ?: 1))]);
|
||||
|
||||
// completion row added by InfoboxMarkup
|
||||
}
|
||||
|
||||
// original name
|
||||
if (Lang::getLocale() != Locale::EN)
|
||||
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
|
||||
|
||||
if ($infobox)
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0', !($this->subject->getField('flags') & ACHIEVEMENT_FLAG_COUNTER));
|
||||
|
||||
|
||||
/**********/
|
||||
/* Series */
|
||||
/**********/
|
||||
|
||||
$series = [];
|
||||
if ($c = $this->subject->getField('chainId'))
|
||||
{
|
||||
$chainAcv = new AchievementList(array(['chainId', $c]));
|
||||
|
||||
foreach ($chainAcv->iterate() as $aId => $__)
|
||||
{
|
||||
$pos = $chainAcv->getField('chainPos');
|
||||
if (!isset($series[$pos]))
|
||||
$series[$pos] = [];
|
||||
|
||||
$series[$pos][] = array(
|
||||
'side' => (int)$chainAcv->getField('faction'),
|
||||
'typeStr' => Type::getFileString(Type::ACHIEVEMENT),
|
||||
'typeId' => $aId,
|
||||
'name' => $chainAcv->getField('name', true)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($series)
|
||||
$this->series = [[array_values($series), null]];
|
||||
|
||||
|
||||
/****************/
|
||||
/* Main Content */
|
||||
/****************/
|
||||
|
||||
$this->headIcons = [$this->subject->getField('iconString')];
|
||||
$this->description = $this->subject->getField('description', true);
|
||||
$this->redButtons = array(
|
||||
BUTTON_WOWHEAD => !($this->subject->getField('cuFlags') & CUSTOM_SERVERSIDE),
|
||||
BUTTON_LINKS => array(
|
||||
'linkColor' => 'ffffff00',
|
||||
'linkId' => Type::getFileString(Type::ACHIEVEMENT).':'.$this->typeId.':"..UnitGUID("player")..":0:0:0:0:0:0:0:0',
|
||||
'linkName' => $this->h1,
|
||||
'type' => $this->type,
|
||||
'typeId' => $this->typeId
|
||||
)
|
||||
);
|
||||
$this->reqCrtQty = $this->subject->getField('reqCriteriaCount');
|
||||
|
||||
if ($this->createMail())
|
||||
$this->addScript([SC_CSS_FILE, 'css/Book.css']);
|
||||
|
||||
// create rewards
|
||||
$rewItems = $rewTitles = [];
|
||||
if ($foo = $this->subject->getField('rewards'))
|
||||
{
|
||||
if ($itemRewards = array_filter($foo, fn($x) => $x[0] == Type::ITEM))
|
||||
{
|
||||
$bar = new ItemList(array(['i.id', array_column($itemRewards, 1)]));
|
||||
foreach ($bar->iterate() as $id => $__)
|
||||
$rewItems[] = new IconElement(Type::ITEM, $id, $bar->getField('name', true), quality: $bar->getField('quality'));
|
||||
}
|
||||
|
||||
if ($titleRewards = array_filter($foo, fn($x) => $x[0] == Type::TITLE))
|
||||
{
|
||||
$bar = new TitleList(array(['id', array_column($titleRewards, 1)]));
|
||||
foreach ($bar->iterate() as $id => $__)
|
||||
$rewTitles[] = Lang::achievement('titleReward', [$id, trim(str_replace('%s', '', $bar->getField('male', true)))]);
|
||||
}
|
||||
}
|
||||
|
||||
if (($text = $this->subject->getField('reward', true)) || $rewItems || $rewTitles)
|
||||
$this->rewards = [$rewItems, $rewTitles, $text];
|
||||
|
||||
// factionchange-equivalent
|
||||
if ($pendant = DB::World()->selectCell('SELECT IF(`horde_id` = ?d, `alliance_id`, -`horde_id`) FROM player_factionchange_achievement WHERE `alliance_id` = ?d OR `horde_id` = ?d', $this->typeId, $this->typeId, $this->typeId))
|
||||
{
|
||||
$altAcv = new AchievementList(array(['id', abs($pendant)]));
|
||||
if (!$altAcv->error)
|
||||
{
|
||||
$this->transfer = Lang::achievement('_transfer', array(
|
||||
$altAcv->id,
|
||||
ITEM_QUALITY_NORMAL,
|
||||
$altAcv->getField('iconString'),
|
||||
$altAcv->getField('name', true),
|
||||
$pendant > 0 ? 'alliance' : 'horde',
|
||||
$pendant > 0 ? Lang::game('si', SIDE_ALLIANCE) : Lang::game('si', SIDE_HORDE)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************/
|
||||
/* Criteria List */
|
||||
/*****************/
|
||||
|
||||
// serverside extra-Data (not sure why ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE is set, let a lone a couple hundred times)
|
||||
if ($crtIds = array_column($this->subject->getCriteria(), 'id'))
|
||||
$crtExtraData = DB::World()->select('SELECT `criteria_id` AS ARRAY_KEY, `type` AS ARRAY_KEY2, `value1`, `value2`, `ScriptName` FROM achievement_criteria_data WHERE `type` <> ?d AND `criteria_id` IN (?a)', ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE, $crtIds);
|
||||
else
|
||||
$crtExtraData = [];
|
||||
|
||||
foreach ($this->subject->getCriteria() as $crt)
|
||||
{
|
||||
// hide hidden criteria for regular users (really do..?)
|
||||
// if (($crt['completionFlags'] & ACHIEVEMENT_CRITERIA_FLAG_HIDDEN) && !User::isInGroup(U_GROUP_STAFF))
|
||||
// continue;
|
||||
|
||||
// alternative display option
|
||||
$crtName = Util::localizedString($crt, 'name');
|
||||
$killSuffix = null;
|
||||
|
||||
$obj = (int)$crt['value1'];
|
||||
$qty = (int)$crt['value2'];
|
||||
|
||||
switch ($crt['type'])
|
||||
{
|
||||
// link to npc
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE:
|
||||
$killSuffix = Lang::achievement('slain');
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE:
|
||||
$crtIcon = new IconElement(Type::NPC, $obj, $crtName ?: CreatureList::getName($obj), size: IconElement::SIZE_SMALL, element: 'iconlist-icon', extraText: $crtName ? null : $killSuffix);
|
||||
break;
|
||||
// link to area (by map)
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP:
|
||||
$zoneId = DB::Aowow()->selectCell('SELECT `id` FROM ?_zones WHERE `mapId` = ?', $obj);
|
||||
$crtIcon = new IconElement(Type::ZONE, $zoneId ?: 0, $crtName ?: ZoneList::getName($zoneId), size: IconElement::SIZE_SMALL, element: 'iconlist-icon');
|
||||
break;
|
||||
// link to area
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA:
|
||||
$crtIcon = new IconElement(Type::ZONE, $obj, $crtName ?: ZoneList::getName($obj), size: IconElement::SIZE_SMALL, element: 'iconlist-icon');
|
||||
break;
|
||||
// link to skills
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE:
|
||||
$crtIcon = new IconElement(Type::SKILL, $obj, $crtName ?: SkillList::getName($obj), size: IconElement::SIZE_SMALL, element: 'iconlist-icon');
|
||||
$this->extendGlobalIds(Type::SKILL, $obj);
|
||||
break;
|
||||
// link to class
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS:
|
||||
$crtIcon = new IconElement(Type::CHR_CLASS, $obj, $crtName ?: CharClassList::getName($obj), size: IconElement::SIZE_SMALL, element: 'iconlist-icon');
|
||||
break;
|
||||
// link to race
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE:
|
||||
$crtIcon = new IconElement(Type::CHR_RACE, $obj, $crtName ?: CharRaceList::getName($obj), size: IconElement::SIZE_SMALL, element: 'iconlist-icon');
|
||||
break;
|
||||
// link to achivement
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT:
|
||||
$crtIcon = new IconElement(Type::ACHIEVEMENT, $obj, $crtName ?: AchievementList::getName($obj), size: IconElement::SIZE_SMALL, element: 'iconlist-icon');
|
||||
$this->extendGlobalIds(Type::ACHIEVEMENT, $obj);
|
||||
break;
|
||||
// link to quest
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST:
|
||||
$crtIcon = new IconElement(Type::QUEST, $obj, $crtName ?: QuestList::getName($obj), size: IconElement::SIZE_SMALL, element: 'iconlist-icon');
|
||||
break;
|
||||
// link to spell
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2:
|
||||
$crtIcon = new IconElement(Type::SPELL, $obj, $crtName ?: SpellList::getName($obj), size: IconElement::SIZE_SMALL, element: 'iconlist-icon');
|
||||
$this->extendGlobalIds(Type::SPELL, $obj);
|
||||
break;
|
||||
// link to item
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM:
|
||||
$item = new ItemList([['id', $obj]]);
|
||||
$crtIcon = new IconElement(Type::ITEM, $obj, $crtName ?: $item->getField('name', true), quality: $item->getField('quality'), size: IconElement::SIZE_SMALL, element: 'iconlist-icon');
|
||||
$this->extendGlobalData($item->getJSGlobals());
|
||||
break;
|
||||
// link to faction (/w target reputation)
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION:
|
||||
$crtIcon = new IconElement(Type::FACTION, $obj, $crtName ?: FactionList::getName($obj), size: IconElement::SIZE_SMALL, element: 'iconlist-icon', extraText: '('.Lang::getReputationLevelForPoints($qty).')');
|
||||
break;
|
||||
// link to GObject
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT:
|
||||
$crtIcon = new IconElement(Type::OBJECT, $obj, $crtName ?: GameObjectList::getName($obj), size: IconElement::SIZE_SMALL, element: 'iconlist-icon');
|
||||
break;
|
||||
// link to emote
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE:
|
||||
$crtIcon = new IconElement(Type::EMOTE, $obj, $crtName ?: EmoteList::getName($obj), size: IconElement::SIZE_SMALL, element: 'iconlist-icon');
|
||||
break;
|
||||
default:
|
||||
// Add a gold coin icon if required
|
||||
if ($crt['completionFlags'] & ACHIEVEMENT_CRITERIA_FLAG_MONEY_COUNTER )
|
||||
$crtIcon = new IconElement(0, 0, '', extraText: Util::formatMoney($qty));
|
||||
else
|
||||
$crtIcon = new IconElement(0, 0, $crtName);
|
||||
break;
|
||||
}
|
||||
|
||||
if (User::isInGroup(U_GROUP_STAFF))
|
||||
$crtIcon->extraText .= ' [CriteriaId: '.$crt['id'].']';
|
||||
|
||||
$extraData = [];
|
||||
foreach ($crtExtraData[$crt['id']] ?? [] as $xType => $xData)
|
||||
{
|
||||
switch ($xType)
|
||||
{
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE:
|
||||
$extraData[] = CreatureList::makeLink($xData['value1']);
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE:
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE:
|
||||
if ($xData['value1'])
|
||||
$extraData[] = CharClassList::makeLink($xData['value1']);
|
||||
|
||||
if ($xData['value2'])
|
||||
$extraData[] = CharRaceList::makeLink($xData['value2']);
|
||||
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA:
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA:
|
||||
$extraData[] = SpellList::makeLink($xData['value1']);
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA:
|
||||
$extraData[] = ZoneList::makeLink($xData['value1']);
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT:
|
||||
if ($xData['ScriptName'] && User::isInGroup(U_GROUP_STAFF))
|
||||
$extraData[] = 'Script '.$xData['ScriptName'];
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY:
|
||||
if ($we = new WorldEventList(array(['holidayId', $xData['value1']])))
|
||||
$extraData[] = '<a href="?event='.$we->id.'">'.$we->getField('name', true).'</a>';
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_ID:
|
||||
if ($z = new ZoneList(array(['mapIdBak', $xData['value1']])))
|
||||
$extraData[] = '<a href="?zone='.$z->id.'">'.$z->getField('name', true).'</a>';
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_KNOWN_TITLE:
|
||||
$extraData[] = TitleList::makeLink($xData['value1']);
|
||||
break;
|
||||
default:
|
||||
if (User::isInGroup(U_GROUP_STAFF))
|
||||
$extraData[] = 'has extra criteria data';
|
||||
}
|
||||
}
|
||||
|
||||
if ($extraData)
|
||||
$crtIcon->extraText .= ' <br /><sup style="margin-left:8px;">('.implode(', ', $extraData).')</sup>';
|
||||
|
||||
$this->criteria[] = $crtIcon;
|
||||
}
|
||||
|
||||
|
||||
/**************/
|
||||
/* Extra Tabs */
|
||||
/**************/
|
||||
|
||||
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"], 'tabsRelated', true);
|
||||
|
||||
// tab: see also
|
||||
$conditions = array(
|
||||
['name_loc'.Lang::getLocale()->value, $this->subject->getField('name', true)],
|
||||
['id', $this->typeId, '!']
|
||||
);
|
||||
$saList = new AchievementList($conditions);
|
||||
if (!$saList->error)
|
||||
{
|
||||
$this->extendGlobalData($saList->getJSGlobals());
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview(array(
|
||||
'data' => $saList->getListviewData(),
|
||||
'id' => 'see-also',
|
||||
'name' => '$LANG.tab_seealso',
|
||||
'visibleCols' => ['category']
|
||||
), AchievementList::$brickFile));
|
||||
}
|
||||
|
||||
// tab: criteria of
|
||||
$refs = DB::Aowow()->SelectCol('SELECT `refAchievementId` FROM ?_achievementcriteria WHERE `type` = ?d AND `value1` = ?d',
|
||||
ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT,
|
||||
$this->typeId
|
||||
);
|
||||
|
||||
if (!empty($refs))
|
||||
{
|
||||
$coList = new AchievementList(array(['id', $refs]));
|
||||
if (!$coList->error)
|
||||
{
|
||||
$this->extendGlobalData($coList->getJSGlobals());
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview(array(
|
||||
'data' => $coList->getListviewData(),
|
||||
'id' => 'criteria-of',
|
||||
'name' => '$LANG.tab_criteriaof',
|
||||
'visibleCols' => ['category']
|
||||
), AchievementList::$brickFile));
|
||||
}
|
||||
}
|
||||
|
||||
// tab: condition for
|
||||
$cnd = new Conditions();
|
||||
$cnd->getByCondition(Type::ACHIEVEMENT, $this->typeId)->prepare();
|
||||
if ($tab = $cnd->toListviewTab('condition-for', '$LANG.tab_condition_for'))
|
||||
{
|
||||
$this->extendGlobalData($cnd->getJsGlobals());
|
||||
$this->lvTabs->addDataTab(...$tab);
|
||||
}
|
||||
|
||||
parent::generate();
|
||||
|
||||
if ($this->subject->getField('flags') & ACHIEVEMENT_FLAG_REALM_FIRST)
|
||||
$this->result->registerDisplayHook('infobox', [self::class, 'infoboxHook']);
|
||||
}
|
||||
|
||||
private function createMail() : bool
|
||||
{
|
||||
if ($_ = $this->subject->getField('mailTemplate'))
|
||||
{
|
||||
$letter = DB::Aowow()->selectRow('SELECT * FROM ?_mails WHERE `id` = ?d', $_);
|
||||
if (!$letter)
|
||||
return false;
|
||||
|
||||
$this->mail = array(
|
||||
'attachments' => [],
|
||||
'subject' => Util::parseHtmlText(Util::localizedString($letter, 'subject', true)),
|
||||
'text' => Util::parseHtmlText(Util::localizedString($letter, 'text', true)),
|
||||
'header' => [$_, null, null]
|
||||
);
|
||||
}
|
||||
else if ($_ = Util::parseHtmlText($this->subject->getField('text', true, true)))
|
||||
{
|
||||
$this->mail = array(
|
||||
'attachments' => [],
|
||||
'subject' => Util::parseHtmlText($this->subject->getField('subject', true, true)),
|
||||
'text' => $_,
|
||||
'header' => [-$this->typeId, null, null]
|
||||
);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
if ($senderId = $this->subject->getField('sender'))
|
||||
if ($senderName = CreatureList::getName($senderId))
|
||||
$this->mail['header'][1] = Lang::mail('mailBy', [$senderId, $senderName]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* finalize infobox */
|
||||
public static function infoboxHook(Template\PageTemplate &$pt, ?InfoboxMarkup &$markup) : void
|
||||
{
|
||||
// realm first still available?
|
||||
if (!DB::isConnectable(DB_AUTH))
|
||||
return;
|
||||
|
||||
$avlb = [];
|
||||
foreach (Profiler::getRealms() AS $rId => $rData)
|
||||
if (!DB::Characters($rId)->selectCell('SELECT 1 FROM character_achievement WHERE `achievement` = ?d', $pt->typeId))
|
||||
$avlb[] = Util::ucWords($rData['name']);
|
||||
|
||||
if (!$avlb)
|
||||
return;
|
||||
|
||||
$addRow = Lang::achievement('rfAvailable').implode(', ', $avlb);
|
||||
|
||||
if (!$markup)
|
||||
$markup = new InfoboxMarkup([$addRow], ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
|
||||
else
|
||||
$markup->addItem($addRow);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,50 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AchievementPowerResponse extends TextResponse implements ICache
|
||||
{
|
||||
use TrCache, TrTooltip;
|
||||
|
||||
private const /* string */ POWER_TEMPLATE = '$WowheadPower.registerAchievement(%d, %d, %s);';
|
||||
|
||||
protected int $type = Type::ACHIEVEMENT;
|
||||
protected int $typeId = 0;
|
||||
protected int $cacheType = CACHE_TYPE_TOOLTIP;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'domain' => ['filter' => FILTER_CALLBACK, 'options' => [Locale::class, 'tryFromDomain']]
|
||||
);
|
||||
|
||||
public function __construct($id)
|
||||
{
|
||||
parent::__construct($id);
|
||||
|
||||
// temp locale
|
||||
if ($this->_get['domain'])
|
||||
Lang::load($this->_get['domain']);
|
||||
|
||||
$this->typeId = intVal($id);
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$achievement = new AchievementList(array(['id', $this->typeId]));
|
||||
if ($achievement->error)
|
||||
$this->cacheType = CACHE_TYPE_NONE;
|
||||
else
|
||||
$opts = array(
|
||||
'name' => $achievement->getField('name', true),
|
||||
'tooltip' => $achievement->renderTooltip(),
|
||||
'icon' => $achievement->getField('iconString')
|
||||
);
|
||||
|
||||
$this->result = new Tooltip(self::POWER_TEMPLATE, $this->typeId, $opts ?? []);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,168 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AchievementsBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $type = Type::ACHIEVEMENT;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
|
||||
protected string $template = 'achievements';
|
||||
protected string $pageName = 'achievements';
|
||||
protected ?int $activeTab = parent::TAB_DATABASE;
|
||||
protected array $breadcrumb = [0, 9];
|
||||
|
||||
protected array $scripts = [[SC_JS_FILE, 'js/filters.js']];
|
||||
protected array $expectedGET = array(
|
||||
'filter' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => Filter::PATTERN_PARAM]]
|
||||
);
|
||||
protected array $validCats = array(
|
||||
92 => true,
|
||||
96 => [14861, 14862, 14863],
|
||||
97 => [14777, 14778, 14779, 14780],
|
||||
95 => [165, 14801, 14802, 14803, 14804, 14881, 14901, 15003],
|
||||
168 => [14808, 14805, 14806, 14921, 14922, 14923, 14961, 14962, 15001, 15002, 15041, 15042],
|
||||
169 => [170, 171, 172],
|
||||
201 => [14864, 14865, 14866],
|
||||
155 => [160, 187, 159, 163, 161, 162, 158, 14981, 156, 14941],
|
||||
81 => true,
|
||||
1 => array (
|
||||
130 => [140, 145, 147, 191],
|
||||
141 => true,
|
||||
128 => [135, 136, 137],
|
||||
122 => [123, 124, 125, 126, 127],
|
||||
133 => true,
|
||||
14807 => [14821, 14822, 14823, 14963, 15021, 15062],
|
||||
132 => [178, 173],
|
||||
134 => true,
|
||||
131 => true,
|
||||
21 => [152, 153, 154]
|
||||
)
|
||||
);
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
$this->getCategoryFromUrl($pageParam);
|
||||
|
||||
parent::__construct($pageParam);
|
||||
|
||||
$this->subCat = $pageParam !== '' ? '='.$pageParam : '';
|
||||
$this->filter = new AchievementListFilter($this->_get['filter'] ?? '', ['parentCats' => $this->category]);
|
||||
if ($this->filter->shouldReload)
|
||||
{
|
||||
$_SESSION['error']['fi'] = $this->filter::class;
|
||||
$get = $this->filter->buildGETParam();
|
||||
$this->forward('?' . $this->pageName . $this->subCat . ($get ? '&filter=' . $get : ''));
|
||||
}
|
||||
$this->filterError = $this->filter->error;
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->h1 = Util::ucFirst(Lang::game('achievements'));
|
||||
|
||||
$conditions = [];
|
||||
if (!User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
$conditions[] = [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0];
|
||||
|
||||
// include child categories if current category is empty
|
||||
if ($this->category)
|
||||
$conditions[] = ['category', end($this->category)];
|
||||
|
||||
if ($fiCnd = $this->filter->getConditions())
|
||||
$conditions[] = $fiCnd;
|
||||
|
||||
|
||||
/*************/
|
||||
/* Menu Path */
|
||||
/*************/
|
||||
|
||||
foreach ($this->category as $cat)
|
||||
$this->breadcrumb[] = $cat;
|
||||
|
||||
|
||||
/**************/
|
||||
/* Page Title */
|
||||
/**************/
|
||||
|
||||
array_unshift($this->title, Util::ucFirst(Lang::game('achievements')));
|
||||
if ($this->category)
|
||||
array_unshift($this->title, Lang::achievement('cat', end($this->category)));
|
||||
|
||||
|
||||
/****************/
|
||||
/* Main Content */
|
||||
/****************/
|
||||
|
||||
// fix modern client achievement category structure: top catg [1:char, 2:statistic, 3:guild]
|
||||
if ($this->category && $this->category[0] != 1)
|
||||
$link = '=1.'.implode('.', $this->category);
|
||||
else if ($this->category)
|
||||
$link = '=2'.(count($this->category) > 1 ? '.'.implode('.', array_slice($this->category, 1)) : '');
|
||||
else
|
||||
$link = '';
|
||||
|
||||
$this->redButtons[BUTTON_WOWHEAD] = true;
|
||||
$this->wowheadLink = sprintf(WOWHEAD_LINK, Lang::getLocale()->domain(), $this->pageName, $link);
|
||||
|
||||
if ($fiQuery = $this->filter->buildGETParam())
|
||||
$this->wowheadLink .= '&filter='.$fiQuery;
|
||||
|
||||
$acvList = new AchievementList($conditions, ['calcTotal' => true]);
|
||||
if (!$acvList->getMatches() && $this->category)
|
||||
{
|
||||
// ToDo - we also branch into here if the filter prohibits results. That should be skipped.
|
||||
$conditions = [];
|
||||
if ($fiCnd)
|
||||
$conditions[] = $fiCnd;
|
||||
if ($catList = DB::Aowow()->SelectCol('SELECT `id` FROM ?_achievementcategory WHERE `parentCat` IN (?a) OR `parentCat2` IN (?a) ', $this->category, $this->category))
|
||||
$conditions[] = ['category', $catList];
|
||||
|
||||
$acvList = new AchievementList($conditions, ['calcTotal' => true]);
|
||||
}
|
||||
|
||||
$tabData = [];
|
||||
if (!$acvList->error)
|
||||
{
|
||||
$tabData['data'] = $acvList->getListviewData();
|
||||
|
||||
// fill g_items, g_titles, g_achievements
|
||||
$this->extendGlobalData($acvList->getJSGlobals());
|
||||
|
||||
// if we are have different cats display field
|
||||
if ($acvList->hasDiffFields('category'))
|
||||
$tabData['visibleCols'] = ['category'];
|
||||
|
||||
if ($this->filter->fiExtraCols)
|
||||
$tabData['extraCols'] = '$fi_getExtraCols(fi_extraCols, 0, 0)';
|
||||
|
||||
// create note if search limit was exceeded
|
||||
if ($acvList->getMatches() > Cfg::get('SQL_LIMIT_DEFAULT'))
|
||||
{
|
||||
$tabData['note'] = sprintf(Util::$tryFilteringString, 'LANG.lvnote_achievementsfound', $acvList->getMatches(), Cfg::get('SQL_LIMIT_DEFAULT'));
|
||||
$tabData['_truncated'] = 1;
|
||||
}
|
||||
}
|
||||
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"]);
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview($tabData, AchievementList::$brickFile));
|
||||
|
||||
parent::generate();
|
||||
|
||||
$this->setOnCacheLoaded([self::class, 'onBeforeDisplay']);
|
||||
}
|
||||
|
||||
public static function onBeforeDisplay()
|
||||
{
|
||||
// sort for dropdown-menus in filter
|
||||
Lang::sort('game', 'si');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,68 +0,0 @@
|
||||
<?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';
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminCommentResponse extends TextResponse
|
||||
{
|
||||
private const /* int */ ERR_NONE = 1;
|
||||
private const /* int */ ERR_WRITE_DB = 0;
|
||||
private const /* int */ ERR_MISCELLANEOUS = 999;
|
||||
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_MOD;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'status' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 0, 'max_range' => 1]]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertPOST('id', 'status'))
|
||||
{
|
||||
trigger_error('AdminCommentResponse - malformed request received', E_USER_ERROR);
|
||||
$this->result = self::ERR_MISCELLANEOUS;
|
||||
return;
|
||||
}
|
||||
|
||||
// check if is marked as outdated CC_FLAG_OUTDATED?
|
||||
|
||||
$ok = false;
|
||||
if ($this->_post['status']) // 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);
|
||||
}
|
||||
else // 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);
|
||||
}
|
||||
|
||||
$this->result = $ok ? self::ERR_NONE : self::ERR_WRITE_DB;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,81 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminGuideResponse extends TextResponse
|
||||
{
|
||||
private const /* int */ ERR_NONE = 0;
|
||||
private const /* int */ ERR_GUIDE = 1;
|
||||
private const /* int */ ERR_STATUS = 2;
|
||||
private const /* int */ ERR_WRITE_DB = 3;
|
||||
private const /* int */ ERR_MISCELLANEOUS = 999;
|
||||
|
||||
protected int $requiredUserGroup = U_GROUP_STAFF;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'status' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => GuideMgr::STATUS_APPROVED, 'max_range' => GuideMgr::STATUS_REJECTED]],
|
||||
'msg' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextBlob'] ]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertPOST('id', 'status'))
|
||||
{
|
||||
trigger_error('AdminGuideResponse - malformed request received', E_USER_ERROR);
|
||||
$this->result = self::ERR_MISCELLANEOUS;
|
||||
return;
|
||||
}
|
||||
|
||||
$guide = DB::Aowow()->selectRow('SELECT `userId`, `status` FROM ?_guides WHERE `id` = ?d', $this->_post['id']);
|
||||
if (!$guide)
|
||||
{
|
||||
trigger_error('AdminGuideResponse - guide #'.$this->_post['id'].' not found', E_USER_ERROR);
|
||||
$this->result = self::ERR_GUIDE;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->_post['status'] == $guide['status'])
|
||||
{
|
||||
trigger_error('AdminGuideResponse - guide #'.$this->_post['id'].' already has status #'.$this->_post['status'], E_USER_ERROR);
|
||||
$this->result = self::ERR_STATUS;
|
||||
return;
|
||||
}
|
||||
|
||||
// status can only be APPROVED or REJECTED due to input validation
|
||||
if (!$this->update($this->_post['id'], $this->_post['status'], $this->_post['msg']))
|
||||
{
|
||||
trigger_error('AdminGuideResponse - write to db failed for guide #'.$this->_post['id'], E_USER_ERROR);
|
||||
$this->result = self::ERR_WRITE_DB;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->_post['status'] == GuideMgr::STATUS_APPROVED)
|
||||
Util::gainSiteReputation($guide['userId'], SITEREP_ACTION_ARTICLE, ['id' => $this->_post['id']]);
|
||||
|
||||
$this->result = self::ERR_NONE;
|
||||
}
|
||||
|
||||
private function update(int $id, int $status, ?string $msg = null) : bool
|
||||
{
|
||||
if ($status == GuideMgr::STATUS_APPROVED) // set display rev to latest
|
||||
$ok = DB::Aowow()->query('UPDATE ?_guides SET `status` = ?d, `rev` = (SELECT `rev` FROM ?_articles WHERE `type` = ?d AND `typeId` = ?d ORDER BY `rev` DESC LIMIT 1), `approveUserId` = ?d, `approveDate` = ?d WHERE `id` = ?d', $status, Type::GUIDE, $id, User::$id, time(), $id);
|
||||
else
|
||||
$ok = DB::Aowow()->query('UPDATE ?_guides SET `status` = ?d WHERE `id` = ?d', $status, $id);
|
||||
|
||||
if (!$ok)
|
||||
return false;
|
||||
|
||||
DB::Aowow()->query('INSERT INTO ?_guides_changelog (`id`, `date`, `userId`, `status`) VALUES (?d, ?d, ?d, ?d)', $id, time(), User::$id, $status);
|
||||
if ($msg)
|
||||
DB::Aowow()->query('INSERT INTO ?_guides_changelog (`id`, `date`, `userId`, `msg`) VALUES (?d, ?d, ?d, ?)', $id, time(), User::$id, $msg);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminGuidesResponse extends TemplateResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_STAFF;
|
||||
|
||||
protected string $template = 'list-page-generic';
|
||||
protected string $pageName = 'guides';
|
||||
protected ?int $activeTab = parent::TAB_STAFF;
|
||||
protected array $breadcrumb = [4, 1, 25]; // Staff > Content > Guides Awaiting Approval
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->h1 = 'Pending Guides';
|
||||
array_unshift($this->title, $this->h1);
|
||||
|
||||
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"]);
|
||||
|
||||
parent::generate();
|
||||
|
||||
$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->addListviewTab(new Listview(array(
|
||||
'data' => array_values($data),
|
||||
'hiddenCols' => ['patch', 'comments', 'views', 'rating'],
|
||||
'extraCols' => '$_'
|
||||
), GuideList::$brickFile, 'guideAdminCol'));
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminOutofdateResponse extends TemplateResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_MOD;
|
||||
|
||||
protected string $template = 'list-page-generic';
|
||||
protected string $pageName = 'out-of-date';
|
||||
protected ?int $activeTab = parent::TAB_STAFF;
|
||||
protected array $breadcrumb = [4, 1, 23]; // Staff > Content > Out of Date Comments
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->h1 = 'Out of Date Comments';
|
||||
array_unshift($this->title, $this->h1);
|
||||
|
||||
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"]);
|
||||
|
||||
parent::generate();
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview(array(
|
||||
'data' => CommunityContent::getCommentPreviews(['flags' => CC_FLAG_OUTDATED]),
|
||||
'extraCols' => '$_'
|
||||
), 'commentpreview', 'commentAdminCol'));
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,80 +0,0 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,29 +0,0 @@
|
||||
<?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();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,68 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminScreenshotsResponse extends TemplateResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_SCREENSHOT;
|
||||
|
||||
protected string $template = 'admin/screenshots';
|
||||
protected string $pageName = 'screenshots';
|
||||
protected ?int $activeTab = parent::TAB_STAFF;
|
||||
protected array $breadcrumb = [4, 1, 5]; // Staff > Content > Screenshots
|
||||
|
||||
protected array $scripts = array(
|
||||
[SC_JS_FILE, 'js/screenshot.js'],
|
||||
[SC_CSS_STRING, '.layout {margin: 0px 25px; max-width: inherit; min-width: 1200px; }'],
|
||||
[SC_CSS_STRING, '#highlightedRow { background-color: #322C1C; }']
|
||||
);
|
||||
protected array $expectedGET = array(
|
||||
'action' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine']],
|
||||
'all' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkEmptySet']],
|
||||
'type' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'typeid' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'user' => ['filter' => FILTER_CALLBACK, 'options' => 'urldecode' ]
|
||||
);
|
||||
|
||||
public ?bool $getAll = null;
|
||||
public array $ssPages = [];
|
||||
public array $ssData = [];
|
||||
public int $ssNFound = 0;
|
||||
public array $pageTypes = [];
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->h1 = 'Screenshot Manager';
|
||||
|
||||
// types that can have screenshots
|
||||
foreach (Type::getClassesFor(0, 'contribute', CONTRIBUTE_SS) as $type => $obj)
|
||||
$this->pageTypes[$type] = Util::ucWords(Lang::game(Type::getFileString($type)));
|
||||
|
||||
$ssGetAll = $this->_get['all'];
|
||||
$ssPages = [];
|
||||
$ssData = [];
|
||||
$nMatches = 0;
|
||||
|
||||
if ($this->_get['type'] && $this->_get['typeid'])
|
||||
$ssData = ScreenshotMgr::getScreenshots($this->_get['type'], $this->_get['typeid'], nFound: $nMatches);
|
||||
else if ($this->_get['user'])
|
||||
{
|
||||
if (mb_strlen($this->_get['user']) >= 3)
|
||||
if ($uId = DB::Aowow()->selectCell('SELECT `id` FROM ?_account WHERE LOWER(`username`) = LOWER(?)', $this->_get['user']))
|
||||
$ssData = ScreenshotMgr::getScreenshots(userId: $uId, nFound: $nMatches);
|
||||
}
|
||||
else
|
||||
$ssPages = ScreenshotMgr::getPages($ssGetAll, $nMatches);
|
||||
|
||||
$this->getAll = $ssGetAll;
|
||||
$this->ssPages = $ssPages;
|
||||
$this->ssData = $ssData;
|
||||
$this->ssNFound = $nMatches; // ssm_numPagesFound
|
||||
|
||||
parent::generate();
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
use GdImage;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminScreenshotsActionApproveResponse extends TextResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_SCREENSHOT;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdListUnsigned']]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('id'))
|
||||
{
|
||||
trigger_error('AdminScreenshotsActionApproveResponse - screenshotId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
ScreenshotMgr::init();
|
||||
|
||||
// create resized and thumb version of screenshot
|
||||
$ssEntries = DB::Aowow()->select('SELECT `id` AS ARRAY_KEY, `userIdOwner`, `date`, `type`, `typeId` FROM ?_screenshots WHERE (`status` & ?d) = 0 AND `id` IN (?a)', CC_FLAG_APPROVED, $this->_get['id']);
|
||||
foreach ($ssEntries as $id => $ssData)
|
||||
{
|
||||
if (!ScreenshotMgr::loadFile(ScreenshotMgr::PATH_PENDING, $id))
|
||||
continue;
|
||||
|
||||
if (!ScreenshotMgr::createResized($id))
|
||||
continue;
|
||||
|
||||
if (!ScreenshotMgr::createThumbnail($id))
|
||||
continue;
|
||||
|
||||
// move pending > normal
|
||||
if (!rename(sprintf(ScreenshotMgr::PATH_PENDING, $id), sprintf(ScreenshotMgr::PATH_NORMAL, $id)))
|
||||
continue;
|
||||
|
||||
// set as approved in DB
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET `status` = ?d, `userIdApprove` = ?d WHERE `id` = ?d', CC_FLAG_APPROVED, User::$id, $id);
|
||||
|
||||
// gain siterep
|
||||
Util::gainSiteReputation($ssData['userIdOwner'], SITEREP_ACTION_SUBMIT_SCREENSHOT, ['id' => $id, 'what' => 1, 'date' => $ssData['date']]);
|
||||
|
||||
// flag DB entry as having screenshots
|
||||
if ($tbl = Type::getClassAttrib($ssData['type'], 'dataTable'))
|
||||
DB::Aowow()->query('UPDATE ?# SET `cuFlags` = `cuFlags` | ?d WHERE `id` = ?d', $tbl, CUSTOM_HAS_SCREENSHOT, $ssData['typeId']);
|
||||
|
||||
unset($ssEntries[$id]);
|
||||
}
|
||||
|
||||
if (!$ssEntries)
|
||||
trigger_error('AdminScreenshotsActionApproveResponse - screenshot(s) # '.implode(', ', array_keys($ssEntries)).' not in db or already approved', E_USER_WARNING);
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminScreenshotsActionDeleteResponse extends TextResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_SCREENSHOT;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdListUnsigned']]
|
||||
);
|
||||
|
||||
// 2 steps: 1) remove from sight, 2) remove from disk
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('id'))
|
||||
{
|
||||
trigger_error('AdminScreenshotsActionDeleteResponse - screenshotId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this->_get['id'] as $id)
|
||||
{
|
||||
// irrevocably purge files already flagged as deleted (should only exist as pending)
|
||||
if (User::isInGroup(U_GROUP_ADMIN) && DB::Aowow()->selectCell('SELECT 1 FROM ?_screenshots WHERE `status` & ?d AND `id` = ?d', CC_FLAG_DELETED, $id))
|
||||
{
|
||||
DB::Aowow()->query('DELETE FROM ?_screenshots WHERE `id` = ?d', $id);
|
||||
if (file_exists(sprintf(ScreenshotMgr::PATH_PENDING, $id)))
|
||||
unlink(sprintf(ScreenshotMgr::PATH_PENDING, $id));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// move normal to pending and remove resized and thumb
|
||||
if (file_exists(sprintf(ScreenshotMgr::PATH_NORMAL, $id)))
|
||||
rename(sprintf(ScreenshotMgr::PATH_NORMAL, $id), sprintf(ScreenshotMgr::PATH_PENDING, $id));
|
||||
|
||||
if (file_exists(sprintf(ScreenshotMgr::PATH_THUMB, $id)))
|
||||
unlink(sprintf(ScreenshotMgr::PATH_THUMB, $id));
|
||||
|
||||
if (file_exists(sprintf(ScreenshotMgr::PATH_RESIZED, $id)))
|
||||
unlink(sprintf(ScreenshotMgr::PATH_RESIZED, $id));
|
||||
}
|
||||
|
||||
// flag as deleted if not aready
|
||||
$oldEntries = DB::Aowow()->selectCol('SELECT `type` AS ARRAY_KEY, GROUP_CONCAT(`typeId`) FROM ?_screenshots WHERE `id` IN (?a) GROUP BY `type`', $this->_get['id']);
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET `status` = ?d, `userIdDelete` = ?d WHERE `id` IN (?a)', CC_FLAG_DELETED, User::$id, $this->_get['id']);
|
||||
|
||||
// deflag db entry as having screenshots
|
||||
foreach ($oldEntries as $type => $typeIds)
|
||||
{
|
||||
$typeIds = explode(',', $typeIds);
|
||||
$toUnflag = DB::Aowow()->selectCol('SELECT `typeId` AS ARRAY_KEY, IF(BIT_OR(`status`) & ?d, 1, 0) AS "hasMore" FROM ?_screenshots WHERE `type` = ?d AND `typeId` IN (?a) GROUP BY `typeId` HAVING `hasMore` = 0', CC_FLAG_APPROVED, $type, $typeIds);
|
||||
if ($toUnflag && ($tbl = Type::getClassAttrib($type, 'dataTable')))
|
||||
DB::Aowow()->query('UPDATE ?# SET cuFlags = cuFlags & ~?d WHERE id IN (?a)', $tbl, CUSTOM_HAS_SCREENSHOT, array_keys($toUnflag));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminScreenshotsActionEditaltResponse extends TextResponse
|
||||
{
|
||||
use TrCommunityHelper;
|
||||
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_SCREENSHOT;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT]
|
||||
);
|
||||
protected array $expectedPOST = array(
|
||||
'alt' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine']]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('id'))
|
||||
return;
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET `caption` = ? WHERE `id` = ?d',
|
||||
$this->handleCaption($this->_post['alt']),
|
||||
$this->_get['id']
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminScreenshotsActionListResponse extends TextResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_SCREENSHOT;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'all' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkEmptySet']]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$pages = ScreenshotMgr::getPages($this->_get['all'], $nPages);
|
||||
$this->result = 'ssm_screenshotPages = '.Util::toJSON($pages).";\n";
|
||||
$this->result .= 'ssm_numPagesFound = '.$nPages.';';
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminScreenshotsActionManageResponse extends TextResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_SCREENSHOT;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'type' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'typeid' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'user' => ['filter' => FILTER_CALLBACK, 'options' => 'urldecode']
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$res = [];
|
||||
|
||||
if ($this->_get['type'] && $this->_get['typeid'])
|
||||
$res = ScreenshotMgr::getScreenshots($this->_get['type'], $this->_get['typeid']);
|
||||
else if ($this->_get['user'])
|
||||
if ($uId = DB::Aowow()->selectCell('SELECT `id` FROM ?_account WHERE LOWER(`username`) = LOWER(?)', $this->_get['user']))
|
||||
$res = ScreenshotMgr::getScreenshots(userId: $uId);
|
||||
|
||||
$this->result = 'ssm_screenshotData = '.Util::toJSON($res);
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminScreenshotsActionRelocateResponse extends TextResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_SCREENSHOT;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT],
|
||||
'typeid' => ['filter' => FILTER_VALIDATE_INT]
|
||||
// (but not type..?)
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('id', 'typeid'))
|
||||
{
|
||||
trigger_error('AdminScreenshotsActionRelocateResponse - screenshotId or typeId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
[$type, $oldTypeId] = array_values(DB::Aowow()->selectRow('SELECT `type`, `typeId` FROM ?_screenshots WHERE `id` = ?d', $this->_get['id']));
|
||||
$typeId = $this->_get['typeid'];
|
||||
|
||||
if (Type::validateIds($type, $typeId))
|
||||
{
|
||||
$tbl = Type::getClassAttrib($type, 'dataTable');
|
||||
|
||||
// move screenshot
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET `typeId` = ?d WHERE `id` = ?d', $typeId, $this->_get['id']);
|
||||
|
||||
// flag target as having screenshot
|
||||
DB::Aowow()->query('UPDATE ?# SET `cuFlags` = `cuFlags` | ?d WHERE `id` = ?d', $tbl, CUSTOM_HAS_SCREENSHOT, $typeId);
|
||||
|
||||
// deflag source for having had screenshots (maybe)
|
||||
$ssInfo = DB::Aowow()->selectRow('SELECT IF(BIT_OR(~`status`) & ?d, 1, 0) AS "hasMore" FROM ?_screenshots WHERE `status`& ?d AND `type` = ?d AND `typeId` = ?d', CC_FLAG_DELETED, CC_FLAG_APPROVED, $type, $oldTypeId);
|
||||
if ($ssInfo || !$ssInfo['hasMore'])
|
||||
DB::Aowow()->query('UPDATE ?# SET `cuFlags` = `cuFlags` & ~?d WHERE `id` = ?d', $tbl, CUSTOM_HAS_SCREENSHOT, $oldTypeId);
|
||||
}
|
||||
else
|
||||
trigger_error('AdminScreenshotsActionRelocateResponse - invalid typeId #'.$typeId.' for type #'.$type, E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminScreenshotsActionStickyResponse extends TextResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_SCREENSHOT;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdListUnsigned']]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('id'))
|
||||
{
|
||||
trigger_error('AdminScreenshotsActionStickyResponse - screenshotId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// this one is a bit strange: as far as i've seen, the only thing a 'sticky' screenshot does is show up in the infobox
|
||||
// this also means, that only one screenshot per page should be sticky
|
||||
// so, handle it one by one and the last one affecting one particular type/typId-key gets the cake
|
||||
$ssEntries = DB::Aowow()->select('SELECT `id` AS ARRAY_KEY, `userIdOwner`, `date`, `type`, `typeId`, `status` FROM ?_screenshots WHERE (`status` & ?d) = 0 AND `id` IN (?a)', CC_FLAG_DELETED, $this->_get['id']);
|
||||
foreach ($ssEntries as $id => $ssData)
|
||||
{
|
||||
// approve yet unapproved screenshots
|
||||
if (!($ssData['status'] & CC_FLAG_APPROVED))
|
||||
{
|
||||
ScreenshotMgr::init();
|
||||
|
||||
if (!ScreenshotMgr::loadFile(ScreenshotMgr::PATH_PENDING, $id))
|
||||
continue;
|
||||
|
||||
if (!ScreenshotMgr::createResized($id))
|
||||
continue;
|
||||
|
||||
if (!ScreenshotMgr::createThumbnail($id))
|
||||
continue;
|
||||
|
||||
// move pending > normal
|
||||
if (!rename(sprintf(ScreenshotMgr::PATH_PENDING, $id), sprintf(ScreenshotMgr::PATH_NORMAL, $id)))
|
||||
continue;
|
||||
|
||||
// set as approved in DB
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET `status` = ?d, `userIdApprove` = ?d WHERE `id` = ?d', CC_FLAG_APPROVED, User::$id, $id);
|
||||
|
||||
// gain siterep
|
||||
Util::gainSiteReputation($ssData['userIdOwner'], SITEREP_ACTION_SUBMIT_SCREENSHOT, ['id' => $id, 'what' => 1, 'date' => $ssData['date']]);
|
||||
|
||||
// flag DB entry as having screenshots
|
||||
if ($tbl = Type::getClassAttrib($ssData['type'], 'dataTable'))
|
||||
DB::Aowow()->query('UPDATE ?# SET `cuFlags` = `cuFlags` | ?d WHERE `id` = ?d', $tbl, CUSTOM_HAS_SCREENSHOT, $ssData['typeId']);
|
||||
}
|
||||
|
||||
// reset all others
|
||||
DB::Aowow()->query('UPDATE ?_screenshots a, ?_screenshots b SET a.`status` = a.`status` & ~?d WHERE a.`type` = b.`type` AND a.`typeId` = b.`typeId` AND a.`id` <> b.`id` AND b.`id` = ?d', CC_FLAG_STICKY, $id);
|
||||
|
||||
// toggle sticky status
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET `status` = IF(`status` & ?d, `status` & ~?d, `status` | ?d) WHERE `id` = ?d AND `status` & ?d', CC_FLAG_STICKY, CC_FLAG_STICKY, CC_FLAG_STICKY, $id, CC_FLAG_APPROVED);
|
||||
|
||||
unset($ssEntries[$id]);
|
||||
}
|
||||
|
||||
if ($ssEntries)
|
||||
trigger_error('AdminScreenshotsActionStickyResponse - screenshot(s) # '.implode(', ', array_keys($ssEntries)).' not in db or flagged as deleted', E_USER_WARNING);
|
||||
}
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,34 +0,0 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,30 +0,0 @@
|
||||
<?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']);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,34 +0,0 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,116 +0,0 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,68 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminVideosResponse extends TemplateResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_VIDEO;
|
||||
|
||||
protected string $template = 'admin/videos';
|
||||
protected string $pageName = 'videos';
|
||||
protected ?int $activeTab = parent::TAB_STAFF;
|
||||
protected array $breadcrumb = [4, 1, 17]; // Staff > Content > Videos
|
||||
|
||||
protected array $scripts = array(
|
||||
[SC_JS_FILE, 'js/video.js'],
|
||||
[SC_CSS_STRING, '.layout {margin: 0px 25px; max-width: inherit; min-width: 1200px; }'],
|
||||
[SC_CSS_STRING, '#highlightedRow { background-color: #322C1C; }']
|
||||
);
|
||||
protected array $expectedGET = array(
|
||||
'action' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine']],
|
||||
'all' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkEmptySet']],
|
||||
'type' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'typeid' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'user' => ['filter' => FILTER_CALLBACK, 'options' => 'urldecode' ]
|
||||
);
|
||||
|
||||
public ?bool $getAll = null;
|
||||
public array $viPages = [];
|
||||
public array $viData = [];
|
||||
public int $viNFound = 0;
|
||||
public array $pageTypes = [];
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->h1 = 'Video Manager';
|
||||
|
||||
// types that can have videos
|
||||
foreach (Type::getClassesFor(0, 'contribute', CONTRIBUTE_SS) as $type => $obj)
|
||||
$this->pageTypes[$type] = Util::ucWords(Lang::game(Type::getFileString($type)));
|
||||
|
||||
$viGetAll = $this->_get['all'];
|
||||
$viPages = [];
|
||||
$viData = [];
|
||||
$nMatches = 0;
|
||||
|
||||
if ($this->_get['type'] && $this->_get['typeid'])
|
||||
$viData = VideoMgr::getVideos($this->_get['type'], $this->_get['typeid'], nFound: $nMatches);
|
||||
else if ($this->_get['user'])
|
||||
{
|
||||
if (mb_strlen($this->_get['user']) >= 3)
|
||||
if ($uId = DB::Aowow()->selectCell('SELECT `id` FROM ?_account WHERE LOWER(`username`) = LOWER(?)', $this->_get['user']))
|
||||
$viData = VideoMgr::getVideos(userId: $uId, nFound: $nMatches);
|
||||
}
|
||||
else
|
||||
$viPages = VideoMgr::getPages($viGetAll, $nMatches);
|
||||
|
||||
$this->getAll = $viGetAll;
|
||||
$this->viPages = $viPages;
|
||||
$this->viData = $viData;
|
||||
$this->viNFound = $nMatches; // ssm_numPagesFound
|
||||
|
||||
parent::generate();
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
use GdImage;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminVideosActionApproveResponse extends TextResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_VIDEO;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdListUnsigned']]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('id'))
|
||||
{
|
||||
trigger_error('AdminVideosActionApproveResponse - videoId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$viEntries = DB::Aowow()->select('SELECT `id` AS ARRAY_KEY, `userIdOwner`, `date`, `type`, `typeId` FROM ?_videos WHERE (`status` & ?d) = 0 AND `id` IN (?a)', CC_FLAG_APPROVED, $this->_get['id']);
|
||||
foreach ($viEntries as $id => $viData)
|
||||
{
|
||||
// set as approved in DB
|
||||
DB::Aowow()->query('UPDATE ?_videos SET `status` = ?d, `userIdApprove` = ?d WHERE `id` = ?d', CC_FLAG_APPROVED, User::$id, $id);
|
||||
|
||||
// gain siterep
|
||||
Util::gainSiteReputation($viData['userIdOwner'], SITEREP_ACTION_SUGGEST_VIDEO, ['id' => $id, 'what' => 1, 'date' => $viData['date']]);
|
||||
|
||||
// flag DB entry as having videos
|
||||
if ($tbl = Type::getClassAttrib($viData['type'], 'dataTable'))
|
||||
DB::Aowow()->query('UPDATE ?# SET `cuFlags` = `cuFlags` | ?d WHERE `id` = ?d', $tbl, CUSTOM_HAS_VIDEO, $viData['typeId']);
|
||||
|
||||
unset($viEntries[$id]);
|
||||
}
|
||||
|
||||
if (!$viEntries)
|
||||
trigger_error('AdminVideosActionApproveResponse - video(s) # '.implode(', ', array_keys($viEntries)).' not in db or already approved', E_USER_WARNING);
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminVideosActionDeleteResponse extends TextResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_VIDEO;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'all' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkEmptySet']]
|
||||
);
|
||||
|
||||
// 2 steps: 1) remove from sight, 2) remove from disk
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('id'))
|
||||
{
|
||||
trigger_error('AdminVideosActionDeleteResponse - videoId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// irrevocably purge files already flagged as deleted (should only exist as pending)
|
||||
if (User::isInGroup(U_GROUP_ADMIN))
|
||||
DB::Aowow()->selectCell('SELECT 1 FROM ?_videos WHERE `status` & ?d AND `id` IN (?a)', CC_FLAG_DELETED, $this->_get['id']);
|
||||
|
||||
// flag as deleted if not aready
|
||||
$oldEntries = DB::Aowow()->selectCol('SELECT `type` AS ARRAY_KEY, GROUP_CONCAT(`typeId`) FROM ?_videos WHERE `id` IN (?a) GROUP BY `type`', $this->_get['id']);
|
||||
DB::Aowow()->query('UPDATE ?_videos SET `status` = ?d, `userIdDelete` = ?d WHERE (`status` & ?d) = 0 AND `id` IN (?a)', CC_FLAG_DELETED, User::$id, CC_FLAG_DELETED, $this->_get['id']);
|
||||
|
||||
// deflag db entry as having videos
|
||||
foreach ($oldEntries as $type => $typeIds)
|
||||
{
|
||||
$typeIds = explode(',', $typeIds);
|
||||
$toUnflag = DB::Aowow()->selectCol('SELECT `typeId` AS ARRAY_KEY, IF(BIT_OR(`status`) & ?d, 1, 0) AS "hasMore" FROM ?_videos WHERE `type` = ?d AND `typeId` IN (?a) GROUP BY `typeId` HAVING `hasMore` = 0', CC_FLAG_APPROVED, $type, $typeIds);
|
||||
if ($toUnflag && ($tbl = Type::getClassAttrib($type, 'dataTable')))
|
||||
DB::Aowow()->query('UPDATE ?# SET cuFlags = cuFlags & ~?d WHERE id IN (?a)', $tbl, CUSTOM_HAS_VIDEO, array_keys($toUnflag));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminVideosActionEdittitleResponse extends TextResponse
|
||||
{
|
||||
use TrCommunityHelper;
|
||||
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_VIDEO;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdListUnsigned']]
|
||||
);
|
||||
protected array $expectedPOST = array(
|
||||
'title' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine']]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('id'))
|
||||
return;
|
||||
|
||||
$caption = $this->handleCaption($this->_post['title']);
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_videos SET `caption` = ? WHERE `id` = ?d', $caption, $this->_get['id'][0]);
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminVideosActionListResponse extends TextResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_VIDEO;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'all' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkEmptySet']]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$pages = VideoMgr::getPages($this->_get['all'], $nPages);
|
||||
$this->result = 'vim_videoPages = '.Util::toJSON($pages).";\n";
|
||||
$this->result .= 'vim_numPagesFound = '.$nPages.';';
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminVideosActionManageResponse extends TextResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_VIDEO;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'type' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'typeid' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'user' => ['filter' => FILTER_CALLBACK, 'options' => 'urldecode']
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$res = [];
|
||||
|
||||
if ($this->_get['type'] && $this->_get['typeid'])
|
||||
$res = VideoMgr::getVideos($this->_get['type'], $this->_get['typeid']);
|
||||
else if ($this->_get['user'])
|
||||
if ($uId = DB::Aowow()->selectCell('SELECT `id` FROM ?_account WHERE LOWER(`username`) = LOWER(?)', $this->_get['user']))
|
||||
$res = VideoMgr::getVideos(userId: $uId);
|
||||
|
||||
$this->result = 'vim_videoData = '.Util::toJSON($res);
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminVideosActionOrderResponse extends TextResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_VIDEO;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdListUnsigned'] ],
|
||||
'move' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => -1, 'max_range' => 1]] // -1 = up, 1 = down
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('id', 'move') || $this->_get['move'] === 0)
|
||||
{
|
||||
trigger_error('AdminVideosActionOrderResponse - id or move empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$id = $this->_get['id'][0];
|
||||
|
||||
$videos = DB::Aowow()->selectCol('SELECT a.`id` AS ARRAY_KEY, a.`pos` FROM ?_videos a, ?_videos b WHERE a.`type` = b.`type` AND a.`typeId` = b.`typeId` AND (a.`status` & ?d) = 0 AND b.`id` = ?d ORDER BY a.`pos` ASC', CC_FLAG_DELETED, $id);
|
||||
if (!$videos || count($videos) == 1)
|
||||
{
|
||||
trigger_error('AdminVideosActionOrderResponse - not enough videos to sort', E_USER_WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
$dir = $this->_get['move'];
|
||||
$curPos = $videos[$id];
|
||||
|
||||
if ($dir == -1 && $curPos == 0)
|
||||
{
|
||||
trigger_error('AdminVideosActionOrderResponse - video #'.$id.' already in top position', E_USER_WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($dir == 1 && $curPos + 1 == count($videos))
|
||||
{
|
||||
trigger_error('AdminVideosActionOrderResponse - video #'.$id.' already in bottom position', E_USER_WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
$oldKey = array_search($curPos + $dir, $videos);
|
||||
$videos[$oldKey] -= $dir;
|
||||
$videos[$id] += $dir;
|
||||
|
||||
foreach ($videos as $id => $pos)
|
||||
DB::Aowow()->query('UPDATE ?_videos SET `pos` = ?d WHERE `id` = ?d', $pos, $id);
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminVideosActionRelocateResponse extends TextResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_VIDEO;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdListUnsigned']],
|
||||
'typeid' => ['filter' => FILTER_VALIDATE_INT ]
|
||||
// (but not type..?)
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('id', 'typeid'))
|
||||
{
|
||||
trigger_error('AdminVideosActionRelocateResponse - videoId or typeId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$id = $this->_get['id'][0];
|
||||
[$type, $oldTypeId] = array_values(DB::Aowow()->selectRow('SELECT `type`, `typeId` FROM ?_videos WHERE `id` = ?d', $id));
|
||||
$typeId = $this->_get['typeid'];
|
||||
|
||||
if (Type::validateIds($type, $typeId))
|
||||
{
|
||||
$tbl = Type::getClassAttrib($type, 'dataTable');
|
||||
|
||||
// move video
|
||||
DB::Aowow()->query('UPDATE ?_videos SET `typeId` = ?d WHERE `id` = ?d', $typeId, $id);
|
||||
|
||||
// flag target as having video
|
||||
DB::Aowow()->query('UPDATE ?# SET `cuFlags` = `cuFlags` | ?d WHERE `id` = ?d', $tbl, CUSTOM_HAS_VIDEO, $typeId);
|
||||
|
||||
// deflag source for having had videos (maybe)
|
||||
$viInfo = DB::Aowow()->selectRow('SELECT IF(BIT_OR(~`status`) & ?d, 1, 0) AS "hasMore" FROM ?_videos WHERE `status`& ?d AND `type` = ?d AND `typeId` = ?d', CC_FLAG_DELETED, CC_FLAG_APPROVED, $type, $oldTypeId);
|
||||
if ($viInfo || !$viInfo['hasMore'])
|
||||
DB::Aowow()->query('UPDATE ?# SET `cuFlags` = `cuFlags` & ~?d WHERE `id` = ?d', $tbl, CUSTOM_HAS_VIDEO, $oldTypeId);
|
||||
}
|
||||
else
|
||||
trigger_error('AdminVideosActionRelocateResponse - invalid typeId #'.$typeId.' for type #'.$type, E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminVideosActionStickyResponse extends TextResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_VIDEO;
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdListUnsigned']]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('id'))
|
||||
{
|
||||
trigger_error('AdminVideosActionStickyResponse - videoId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// this one is a bit strange: as far as i've seen, the only thing a 'sticky' video does is show up in the infobox
|
||||
// this also means, that only one video per page should be sticky
|
||||
// so, handle it one by one and the last one affecting one particular type/typId-key gets the cake
|
||||
$viEntries = DB::Aowow()->select('SELECT `id` AS ARRAY_KEY, `userIdOwner`, `date`, `type`, `typeId`, `status` FROM ?_videos WHERE (`status` & ?d) = 0 AND `id` IN (?a)', CC_FLAG_DELETED, $this->_get['id']);
|
||||
foreach ($viEntries as $id => $viData)
|
||||
{
|
||||
// approve yet unapproved videos
|
||||
if (!($viData['status'] & CC_FLAG_APPROVED))
|
||||
{
|
||||
// set as approved in DB
|
||||
DB::Aowow()->query('UPDATE ?_videos SET `status` = ?d, `userIdApprove` = ?d WHERE `id` = ?d', CC_FLAG_APPROVED, User::$id, $id);
|
||||
|
||||
// gain siterep
|
||||
Util::gainSiteReputation($viData['userIdOwner'], SITEREP_ACTION_SUGGEST_VIDEO, ['id' => $id, 'what' => 1, 'date' => $viData['date']]);
|
||||
|
||||
// flag DB entry as having videos
|
||||
if ($tbl = Type::getClassAttrib($viData['type'], 'dataTable'))
|
||||
DB::Aowow()->query('UPDATE ?# SET `cuFlags` = `cuFlags` | ?d WHERE `id` = ?d', $tbl, CUSTOM_HAS_VIDEO, $viData['typeId']);
|
||||
}
|
||||
|
||||
// reset all others
|
||||
DB::Aowow()->query('UPDATE ?_videos a, ?_videos b SET a.`status` = a.`status` & ~?d WHERE a.`type` = b.`type` AND a.`typeId` = b.`typeId` AND a.`id` <> b.`id` AND b.`id` = ?d', CC_FLAG_STICKY, $id);
|
||||
|
||||
// toggle sticky status
|
||||
DB::Aowow()->query('UPDATE ?_videos SET `status` = IF(`status` & ?d, `status` & ~?d, `status` | ?d) WHERE `id` = ?d AND `status` & ?d', CC_FLAG_STICKY, CC_FLAG_STICKY, CC_FLAG_STICKY, $id, CC_FLAG_APPROVED);
|
||||
|
||||
unset($viEntries[$id]);
|
||||
}
|
||||
|
||||
if ($viEntries)
|
||||
trigger_error('AdminVideosActionStickyResponse - video(s) # '.implode(', ', array_keys($viEntries)).' not in db or flagged as deleted', E_USER_WARNING);
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
<?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();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,74 +0,0 @@
|
||||
<?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 '';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,141 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AreatriggerBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrDetailPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
protected int $requiredUserGroup = U_GROUP_STAFF;
|
||||
|
||||
protected string $template = 'detail-page-generic';
|
||||
protected string $pageName = 'areatrigger';
|
||||
protected ?int $activeTab = parent::TAB_DATABASE;
|
||||
protected array $breadcrumb = [0, 102];
|
||||
|
||||
public int $type = Type::AREATRIGGER;
|
||||
public int $typeId = 0;
|
||||
|
||||
private AreaTriggerList $subject;
|
||||
|
||||
public function __construct(string $id)
|
||||
{
|
||||
parent::__construct($id);
|
||||
|
||||
$this->typeId = intVal($id);
|
||||
$this->contribute = Type::getClassAttrib($this->type, 'contribute') ?? CONTRIBUTE_NONE;
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->subject = new AreaTriggerList(array(['id', $this->typeId]));
|
||||
if ($this->subject->error)
|
||||
$this->generateNotFound(Lang::game('areatrigger'), Lang::areatrigger('notFound'));
|
||||
|
||||
$this->h1 = $this->subject->getField('name') ?: 'Areatrigger #'.$this->typeId;
|
||||
|
||||
$this->gPageInfo += array(
|
||||
'type' => $this->type,
|
||||
'typeId' => $this->typeId,
|
||||
'name' => $this->h1
|
||||
);
|
||||
|
||||
|
||||
/*************/
|
||||
/* Menu Path */
|
||||
/*************/
|
||||
|
||||
$this->breadcrumb[] = $this->subject->getField('type');
|
||||
|
||||
|
||||
/**************/
|
||||
/* Page Title */
|
||||
/**************/
|
||||
|
||||
array_unshift($this->title, $this->h1, Util::ucFirst(Lang::game('areatrigger')));
|
||||
|
||||
|
||||
/****************/
|
||||
/* Main Content */
|
||||
/****************/
|
||||
|
||||
$_type = $this->subject->getField('type');
|
||||
|
||||
// get spawns
|
||||
if ($spawns = $this->subject->getSpawns(SPAWNINFO_FULL))
|
||||
{
|
||||
$this->addDataLoader('zones');
|
||||
$this->map = array(
|
||||
['parent' => 'mapper-generic'], // Mapper
|
||||
$spawns, // mapperData
|
||||
null, // ShowOnMap
|
||||
[Lang::areatrigger('foundIn')] // foundIn
|
||||
);
|
||||
foreach ($spawns as $areaId => $_)
|
||||
$this->map[3][$areaId] = ZoneList::getName($areaId);
|
||||
}
|
||||
|
||||
// Smart AI
|
||||
if ($_type == AT_TYPE_SMART)
|
||||
{
|
||||
$sai = new SmartAI(SmartAI::SRC_TYPE_AREATRIGGER, $this->typeId, ['teleportTargetArea' => $this->subject->getField('areaId')]);
|
||||
if ($sai->prepare())
|
||||
{
|
||||
$this->extendGlobalData($sai->getJSGlobals());
|
||||
$this->smartAI = $sai->getMarkup();
|
||||
}
|
||||
}
|
||||
|
||||
$this->redButtons = array(
|
||||
BUTTON_LINKS => false,
|
||||
BUTTON_WOWHEAD => false
|
||||
);
|
||||
|
||||
|
||||
/**************/
|
||||
/* Extra Tabs */
|
||||
/**************/
|
||||
|
||||
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"], 'tabsRelated', true);
|
||||
|
||||
// tab: conditions
|
||||
$cnd = new Conditions();
|
||||
$cnd->getBySourceEntry($this->typeId, Conditions::SRC_AREATRIGGER_CLIENT)->prepare();
|
||||
if ($tab = $cnd->toListviewTab())
|
||||
{
|
||||
$this->extendGlobalData($cnd->getJsGlobals());
|
||||
$this->lvTabs->addDataTab(...$tab);
|
||||
}
|
||||
|
||||
if ($_type == AT_TYPE_OBJECTIVE)
|
||||
{
|
||||
$relQuest = new QuestList(array(['id', $this->subject->getField('quest')]));
|
||||
if (!$relQuest->error)
|
||||
{
|
||||
$this->extendGlobalData($relQuest->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_REWARDS));
|
||||
$this->lvTabs->addListviewTab(new Listview(['data' => $relQuest->getListviewData()], QuestList::$brickFile));
|
||||
}
|
||||
}
|
||||
else if ($_type == AT_TYPE_TELEPORT)
|
||||
{
|
||||
$relZone = new ZoneList(array(['id', $this->subject->getField('areaId')]));
|
||||
if (!$relZone->error)
|
||||
$this->lvTabs->addListviewTab(new Listview(['data' => $relZone->getListviewData()], ZoneList::$brickFile));
|
||||
}
|
||||
else if ($_type == AT_TYPE_SCRIPT)
|
||||
{
|
||||
$relTrigger = new AreaTriggerList(array(['id', $this->typeId, '!'], ['name', $this->subject->getField('name')]));
|
||||
if (!$relTrigger->error)
|
||||
$this->lvTabs->addListviewTab(new Listview(['data' => $relTrigger->getListviewData(), 'name' => Util::ucFirst(Lang::game('areatrigger'))]), AreaTriggerList::$brickFile, 'areatrigger');
|
||||
}
|
||||
|
||||
parent::generate();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,102 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AreatriggersBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $type = Type::AREATRIGGER;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
protected int $requiredUserGroup = U_GROUP_STAFF;
|
||||
|
||||
protected string $template = 'areatriggers';
|
||||
protected string $pageName = 'areatriggers';
|
||||
protected ?int $activeTab = parent::TAB_DATABASE;
|
||||
protected array $breadcrumb = [0, 102];
|
||||
|
||||
protected array $scripts = [[SC_JS_FILE, 'js/filters.js']];
|
||||
protected array $expectedGET = ['filter' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => Filter::PATTERN_PARAM]]];
|
||||
protected array $validCats = [0, 1, 2, 3, 4, 5];
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
$this->getCategoryFromUrl($pageParam);
|
||||
|
||||
if (isset($this->category[0]))
|
||||
$this->forward('?areatriggers&filter=ty='.$this->category[0]);
|
||||
|
||||
parent::__construct($pageParam);
|
||||
|
||||
$this->filter = new AreaTriggerListFilter($this->_get['filter'] ?? '');
|
||||
if ($this->filter->shouldReload)
|
||||
{
|
||||
$_SESSION['error']['fi'] = $this->filter::class;
|
||||
$get = $this->filter->buildGETParam();
|
||||
$this->forward('?' . $this->pageName . ($get ? '&filter=' . $get : ''));
|
||||
}
|
||||
$this->filterError = $this->filter->error;
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->h1 = Util::ucFirst(Lang::game('areatriggers'));
|
||||
|
||||
$fiForm = $this->filter->values;
|
||||
|
||||
|
||||
/**************/
|
||||
/* Page Title */
|
||||
/**************/
|
||||
|
||||
array_unshift($this->title, $this->h1);
|
||||
|
||||
if (count($fiForm['ty']) == 1)
|
||||
array_unshift($this->title, Lang::areatrigger('types', $fiForm['ty'][0]));
|
||||
|
||||
|
||||
/*************/
|
||||
/* Menu Path */
|
||||
/*************/
|
||||
|
||||
if (count($fiForm['ty']) == 1)
|
||||
$this->breadcrumb[] = $fiForm['ty'];
|
||||
|
||||
|
||||
/****************/
|
||||
/* Main Content */
|
||||
/****************/
|
||||
|
||||
$this->redButtons[BUTTON_WOWHEAD] = false;
|
||||
|
||||
$conditions = [];
|
||||
if ($_ = $this->filter->getConditions())
|
||||
$conditions[] = $_;
|
||||
|
||||
$tabData = [];
|
||||
$trigger = new AreaTriggerList($conditions, ['calcTotal' => true]);
|
||||
if (!$trigger->error)
|
||||
{
|
||||
$tabData['data'] = $trigger->getListviewData();
|
||||
|
||||
// create note if search limit was exceeded; overwriting 'note' is intentional
|
||||
if ($trigger->getMatches() > Cfg::get('SQL_LIMIT_DEFAULT'))
|
||||
{
|
||||
$tabData['note'] = sprintf(Util::$tryFilteringEntityString, $trigger->getMatches(), '"'.Lang::game('areatriggers').'"', Cfg::get('SQL_LIMIT_DEFAULT'));
|
||||
$tabData['_truncated'] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"]);
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview($tabData, AreaTriggerList::$brickFile, 'areatrigger'));
|
||||
|
||||
parent::generate();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,149 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class ArenateamBaseResponse extends TemplateResponse
|
||||
{
|
||||
use TrProfilerDetail;
|
||||
|
||||
protected string $template = 'roster';
|
||||
protected string $pageName = 'arena-team';
|
||||
protected ?int $activeTab = parent::TAB_TOOLS;
|
||||
protected array $breadcrumb = [1, 5, 3]; // Tools > Profiler > Arena Team
|
||||
|
||||
protected array $dataLoader = ['realms', 'weight-presets'];
|
||||
protected array $scripts = array(
|
||||
[SC_JS_FILE, 'js/profile_all.js'],
|
||||
[SC_JS_FILE, 'js/profile.js'],
|
||||
[SC_CSS_FILE, 'css/Profiler.css']
|
||||
);
|
||||
|
||||
public int $type = Type::ARENA_TEAM;
|
||||
|
||||
public function __construct(string $idOrProfile)
|
||||
{
|
||||
parent::__construct($idOrProfile);
|
||||
|
||||
if (!Cfg::get('PROFILER_ENABLE'))
|
||||
$this->generateError();
|
||||
|
||||
if (!$idOrProfile)
|
||||
$this->generateError();
|
||||
|
||||
$this->getSubjectFromUrl($idOrProfile);
|
||||
|
||||
// we have an ID > ok
|
||||
if ($this->typeId)
|
||||
return;
|
||||
|
||||
// param was incomplete profile > error
|
||||
if (!$this->subjectName)
|
||||
$this->generateError();
|
||||
|
||||
// 3 possibilities
|
||||
// 1) already synced to aowow
|
||||
if ($subject = DB::Aowow()->selectRow('SELECT `id`, `realmGUID`, `stub` FROM ?_profiler_arena_team WHERE `realm` = ?d AND `nameUrl` = ?', $this->realmId, Profiler::urlize($this->subjectName)))
|
||||
{
|
||||
$this->typeId = $subject['id'];
|
||||
|
||||
if ($subject['stub'])
|
||||
$this->handleIncompleteData(Type::ARENA_TEAM, $subject['realmGUID']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// 2) not yet synced but exists on realm (wont work if we get passed an urlized name, but there is nothing we can do about it)
|
||||
$subjects = DB::Characters($this->realmId)->select('SELECT at.`arenaTeamId` AS "realmGUID", at.`name`, at.`type` FROM arena_team at WHERE at.`name` = ?', $this->subjectName);
|
||||
if ($subject = array_filter($subjects, fn($x) => Util::lower($x['name']) === Util::lower($this->subjectName)))
|
||||
{
|
||||
$subject = array_pop($subject);
|
||||
$subject['realm'] = $this->realmId;
|
||||
$subject['stub'] = 1;
|
||||
$subject['nameUrl'] = Profiler::urlize($subject['name']);
|
||||
|
||||
// create entry from realm with basic info
|
||||
DB::Aowow()->query('INSERT IGNORE INTO ?_profiler_arena_team (?#) VALUES (?a)', array_keys($subject), array_values($subject));
|
||||
|
||||
$this->handleIncompleteData(Type::ARENA_TEAM, $subject['realmGUID']);
|
||||
return;
|
||||
}
|
||||
|
||||
// 3) does not exist at all
|
||||
$this->notFound();
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if ($this->doResync)
|
||||
{
|
||||
parent::generate();
|
||||
return;
|
||||
}
|
||||
|
||||
$subject = new LocalArenaTeamList(array(['at.id', $this->typeId]));
|
||||
if ($subject->error)
|
||||
$this->notFound();
|
||||
|
||||
// arena team accessed by id
|
||||
if (!$this->subjectName)
|
||||
$this->forward($subject->getProfileUrl());
|
||||
|
||||
$this->h1 = Lang::profiler('arenaRoster', [$subject->getField('name')]);
|
||||
|
||||
|
||||
/*************/
|
||||
/* Menu Path */
|
||||
/*************/
|
||||
|
||||
$this->followBreadcrumbPath();
|
||||
|
||||
|
||||
/**************/
|
||||
/* Page Title */
|
||||
/**************/
|
||||
|
||||
array_unshift(
|
||||
$this->title,
|
||||
$subject->getField('name').' ('.$this->realm.' - '.Lang::profiler('regions', $this->region).')',
|
||||
Util::ucFirst(Lang::profiler('profiler'))
|
||||
);
|
||||
|
||||
|
||||
/****************/
|
||||
/* Main Content */
|
||||
/****************/
|
||||
|
||||
parent::generate();
|
||||
|
||||
$this->redButtons[BUTTON_RESYNC] = [$this->typeId, 'arena-team'];
|
||||
|
||||
// statistic calculations here
|
||||
|
||||
|
||||
/**************/
|
||||
/* Extra Tabs */
|
||||
/**************/
|
||||
|
||||
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"], 'tabsRelated');
|
||||
|
||||
// tab: members
|
||||
$member = new LocalProfileList(array(['atm.arenaTeamId', $this->typeId]));
|
||||
$this->lvTabs->addListviewTab(new Listview(array(
|
||||
'data' => $member->getListviewData(PROFILEINFO_CHARACTER | PROFILEINFO_ARENA),
|
||||
'sort' => [-15],
|
||||
'visibleCols' => ['race', 'classs', 'level', 'talents', 'gearscore', 'rating', 'wins', 'losses'],
|
||||
'hiddenCols' => ['guild', 'location']
|
||||
), ProfileList::$brickFile));
|
||||
}
|
||||
|
||||
private function notFound() : never
|
||||
{
|
||||
parent::generateNotFound(Lang::game('arenateam'), Lang::profiler('notFound', 'arenateam'));
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,48 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class ArenaTeamResyncResponse extends TextResponse
|
||||
{
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdList'] ],
|
||||
'profile' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkEmptySet']]
|
||||
);
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
parent::__construct($pageParam);
|
||||
|
||||
if (!Cfg::get('PROFILER_ENABLE'))
|
||||
$this->generate404();
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
user: <string> [optional, not used]
|
||||
profile: <empty> [optional, also get related chars]
|
||||
return: 1
|
||||
*/
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('id'))
|
||||
return;
|
||||
|
||||
if ($teams = DB::Aowow()->select('SELECT `realm`, `realmGUID` FROM ?_profiler_arena_team WHERE `id` IN (?a)', $this->_get['id']))
|
||||
foreach ($teams as $t)
|
||||
Profiler::scheduleResync(Type::ARENA_TEAM, $t['realm'], $t['realmGUID']);
|
||||
|
||||
if ($this->_get['profile'])
|
||||
if ($chars = DB::Aowow()->select('SELECT `realm`, `realmGUID` FROM ?_profiler_profiles p JOIN ?_profiler_arena_team_member atm ON atm.`profileId` = p.`id` WHERE atm.`arenaTeamId` IN (?a)', $this->_get['id']))
|
||||
foreach ($chars as $c)
|
||||
Profiler::scheduleResync(Type::PROFILE, $c['realm'], $c['realmGUID']);
|
||||
|
||||
$this->result = 1; // as string?
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class ArenaTeamStatusResponse extends TextResponse
|
||||
{
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdList']]
|
||||
);
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
parent::__construct($pageParam);
|
||||
|
||||
if (!Cfg::get('PROFILER_ENABLE'))
|
||||
$this->generate404();
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->result = Profiler::resyncStatus(Type::ARENA_TEAM, $this->_get['id']);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,158 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class ArenateamsBaseResponse extends TemplateResponse implements IProfilerList
|
||||
{
|
||||
use TrProfilerList, TrListPage;
|
||||
|
||||
protected string $template = 'arena-teams';
|
||||
protected string $pageName = 'arena-teams';
|
||||
protected ?int $activeTab = parent::TAB_TOOLS;
|
||||
protected array $breadcrumb = [1, 5, 3]; // Tools > Profiler > Arena Teams
|
||||
|
||||
protected array $dataLoader = ['realms'];
|
||||
protected array $scripts = array(
|
||||
[SC_JS_FILE, 'js/filters.js'],
|
||||
[SC_JS_FILE, 'js/profile_all.js'],
|
||||
[SC_JS_FILE, 'js/profile.js']
|
||||
);
|
||||
protected array $expectedGET = array(
|
||||
'filter' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => Filter::PATTERN_PARAM]]
|
||||
);
|
||||
|
||||
public int $type = Type::ARENA_TEAM;
|
||||
|
||||
private int $sumSubjects = 0;
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
if (!Cfg::get('PROFILER_ENABLE'))
|
||||
$this->generateError();
|
||||
|
||||
$this->getSubjectFromUrl($pageParam);
|
||||
|
||||
parent::__construct($pageParam);
|
||||
|
||||
$realms = [];
|
||||
foreach (Profiler::getRealms() as $idx => $r)
|
||||
{
|
||||
if ($this->region && $r['region'] != $this->region)
|
||||
continue;
|
||||
|
||||
if ($this->realm && $r['name'] != $this->realm)
|
||||
continue;
|
||||
|
||||
$this->sumSubjects += DB::Characters($idx)->selectCell('SELECT count(*) FROM arena_team');
|
||||
$realms[] = $idx;
|
||||
}
|
||||
|
||||
$this->subCat = $pageParam !== '' ? '='.$pageParam : '';
|
||||
$this->filter = new ArenaTeamListFilter($this->_get['filter'] ?? '', ['realms' => $realms]);
|
||||
if ($this->filter->shouldReload)
|
||||
{
|
||||
$_SESSION['error']['fi'] = $this->filter::class;
|
||||
$get = $this->filter->buildGETParam();
|
||||
$this->forward('?' . $this->pageName . $this->subCat . ($get ? '&filter=' . $get : ''));
|
||||
}
|
||||
$this->filterError = $this->filter->error;
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->h1 = Lang::game('arenateams');
|
||||
|
||||
|
||||
/*************/
|
||||
/* Menu Path */
|
||||
/*************/
|
||||
|
||||
$this->followBreadcrumbPath();
|
||||
|
||||
|
||||
/**************/
|
||||
/* Page Title */
|
||||
/**************/
|
||||
|
||||
if ($this->realm)
|
||||
array_unshift($this->title, $this->realm,/* Cfg::get('BATTLEGROUP'),*/ Lang::profiler('regions', $this->region), Lang::game('arenateams'));
|
||||
else if ($this->region)
|
||||
array_unshift($this->title, Lang::profiler('regions', $this->region), Lang::game('arenateams'));
|
||||
else
|
||||
array_unshift($this->title, Lang::game('arenateams'));
|
||||
|
||||
|
||||
/****************/
|
||||
/* Main Content */
|
||||
/****************/
|
||||
|
||||
$conditions = [];
|
||||
if (!User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
$conditions[] = ['at.seasonGames', 0, '>'];
|
||||
|
||||
if ($_ = $this->filter->getConditions())
|
||||
$conditions[] = $_;
|
||||
|
||||
$this->getRegions();
|
||||
|
||||
$tabData = array(
|
||||
'id' => 'arena-teams',
|
||||
'data' => [],
|
||||
'hideCount' => 1,
|
||||
'sort' => [-16],
|
||||
'extraCols' => ['$Listview.extraCols.members'],
|
||||
'visibleCols' => ['rank', 'wins', 'losses', 'rating'],
|
||||
'hiddenCols' => ['arenateam', 'guild']
|
||||
);
|
||||
|
||||
if (!$this->filter->values['sz'])
|
||||
$tabData['visibleCols'][] = 'size';
|
||||
|
||||
if ($this->filter->values['si'])
|
||||
$tabData['hiddenCols'][] = 'faction';
|
||||
|
||||
$miscParams = ['calcTotal' => true];
|
||||
if ($this->realm)
|
||||
$miscParams['sv'] = $this->realm;
|
||||
if ($this->region)
|
||||
$miscParams['rg'] = $this->region;
|
||||
|
||||
$teams = new RemoteArenaTeamList($conditions, $miscParams);
|
||||
if (!$teams->error)
|
||||
{
|
||||
$teams->initializeLocalEntries();
|
||||
|
||||
$tabData['data'] = $teams->getListviewData();
|
||||
|
||||
// create note if search limit was exceeded
|
||||
if ($this->filter->query && $teams->getMatches() > Cfg::get('SQL_LIMIT_DEFAULT'))
|
||||
{
|
||||
$tabData['note'] = sprintf(Util::$tryFilteringString, 'LANG.lvnote_arenateamsfound2', $this->sumSubjects, $teams->getMatches());
|
||||
$tabData['_truncated'] = 1;
|
||||
}
|
||||
else if ($teams->getMatches() > Cfg::get('SQL_LIMIT_DEFAULT'))
|
||||
$tabData['note'] = sprintf(Util::$tryFilteringString, 'LANG.lvnote_arenateamsfound', $this->sumSubjects, 0);
|
||||
}
|
||||
|
||||
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"], 'tabsRelated');
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview($tabData, ArenaTeamList::$brickFile, 'membersCol'));
|
||||
|
||||
parent::generate();
|
||||
|
||||
$this->result->registerDisplayHook('filter', [self::class, 'filterFormHook']);
|
||||
}
|
||||
|
||||
public static function filterFormHook(Template\PageTemplate &$pt, ArenaTeamListFilter $filter) : void
|
||||
{
|
||||
// sort for dropdown-menus
|
||||
Lang::sort('game', 'cl');
|
||||
Lang::sort('game', 'ra');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,48 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class ClassesBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $type = Type::CHR_CLASS;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
|
||||
protected string $template = 'list-page-generic';
|
||||
protected string $pageName = 'classes';
|
||||
protected ?int $activeTab = parent::TAB_DATABASE;
|
||||
protected array $breadcrumb = [0, 12];
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
$this->getCategoryFromUrl($pageParam);
|
||||
|
||||
parent::__construct($pageParam);
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->h1 = Util::ucFirst(Lang::game('classes'));
|
||||
|
||||
|
||||
array_unshift($this->title, Util::ucFirst(Lang::game('classes')));
|
||||
|
||||
|
||||
$this->redButtons[BUTTON_WOWHEAD] = true;
|
||||
|
||||
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"]);
|
||||
|
||||
$classes = new CharClassList();
|
||||
if (!$classes->error)
|
||||
$this->lvTabs->addListviewTab(new Listview(['data' => $classes->getListviewData()], CharClassList::$brickFile));
|
||||
|
||||
parent::generate();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,51 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// returns all replies on success
|
||||
// must have non-200 header on error
|
||||
class CommentAddreplyResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'commentId' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'replyId' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'body' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextBlob']]
|
||||
);
|
||||
|
||||
protected function generate(): void
|
||||
{
|
||||
if (!$this->assertPOST('commentId', 'replyId', 'body'))
|
||||
{
|
||||
trigger_error('CommentAddreplyResponse - malformed request received', E_USER_ERROR);
|
||||
$this->generate404(User::isInGroup(U_GROUP_STAFF) ? 'request malformed' : '');
|
||||
}
|
||||
|
||||
if (!User::canReply())
|
||||
$this->generate404(Lang::main('cannotComment'));
|
||||
|
||||
if (!$this->_post['commentId'] || !DB::Aowow()->selectCell('SELECT 1 FROM ?_comments WHERE `id` = ?d', $this->_post['commentId']))
|
||||
{
|
||||
trigger_error('CommentAddreplyResponse - parent comment #'.$this->_post['commentId'].' does not exist', E_USER_ERROR);
|
||||
$this->generate404(Lang::main('intError'));
|
||||
}
|
||||
|
||||
if (mb_strlen($this->_post['body']) < CommunityContent::REPLY_LENGTH_MIN || mb_strlen($this->_post['body']) > CommunityContent::REPLY_LENGTH_MAX)
|
||||
$this->generate404(Lang::main('textLength', [mb_strlen($this->_post['body']), CommunityContent::REPLY_LENGTH_MIN, CommunityContent::REPLY_LENGTH_MAX]));
|
||||
|
||||
if (!DB::Aowow()->query('INSERT INTO ?_comments (`userId`, `roles`, `body`, `date`, `replyTo`) VALUES (?d, ?d, ?, UNIX_TIMESTAMP(), ?d)', User::$id, User::$groups, $this->_post['body'], $this->_post['commentId']))
|
||||
{
|
||||
trigger_error('CommentAddreplyResponse - write to db failed', E_USER_ERROR);
|
||||
$this->generate404(Lang::main('intError'));
|
||||
}
|
||||
|
||||
$this->result = Util::toJSON(CommunityContent::getCommentReplies($this->_post['commentId']));
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,79 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class CommentAddResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'commentbody' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextBlob']]
|
||||
);
|
||||
protected array $expectedGET = array(
|
||||
'type' => ['filter' => FILTER_VALIDATE_INT],
|
||||
'typeid' => ['filter' => FILTER_VALIDATE_INT]
|
||||
);
|
||||
|
||||
// i .. have problems believing, that everything uses nifty ajax while adding comments requires a brutal header(Loacation: <wherever>), yet, thats how it is
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('type', 'typeid') || !$this->assertPOST('commentbody') || !Type::validateIds($this->_get['type'], $this->_get['typeid']))
|
||||
{
|
||||
trigger_error('CommentAddResponse - malforemd request received', E_USER_ERROR);
|
||||
return; // whatever, we cant even send him back
|
||||
}
|
||||
|
||||
// we now have a valid return target
|
||||
$idOrUrl = $this->_get['typeid'];
|
||||
if ($this->_get['type'] == Type::GUIDE)
|
||||
if ($_ = DB::Aowow()->selectCell('SELECT `url` FROM ?_guides WHERE `id` = ?d', $this->_get['typeid']))
|
||||
$idOrUrl = $_;
|
||||
|
||||
$this->redirectTo = '?'.Type::getFileString($this->_get['type']).'='.$idOrUrl.'#comments';
|
||||
|
||||
// this type cannot be commented on
|
||||
if (!Type::checkClassAttrib($this->_get['type'], 'contribute', CONTRIBUTE_CO))
|
||||
{
|
||||
trigger_error('CommentAddResponse - tried to comment on unsupported type: '.Type::getFileString($this->_get['type']), E_USER_ERROR);
|
||||
$_SESSION['error']['co'] = Lang::main('intError');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!User::canComment())
|
||||
{
|
||||
$_SESSION['error']['co'] = Lang::main('cannotComment');
|
||||
return;
|
||||
}
|
||||
|
||||
$len = mb_strlen($this->_post['commentbody']);
|
||||
|
||||
if ((!User::isInGroup(U_GROUP_MODERATOR) && $len < CommunityContent::COMMENT_LENGTH_MIN) || ($len > CommunityContent::COMMENT_LENGTH_MAX * (User::isPremium() ? 3 : 1)))
|
||||
{
|
||||
$_SESSION['error']['co'] = Lang::main('textLength', [$len, CommunityContent::COMMENT_LENGTH_MIN, CommunityContent::COMMENT_LENGTH_MAX * (User::isPremium() ? 3 : 1)]);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($postId = DB::Aowow()->query('INSERT INTO ?_comments (`type`, `typeId`, `userId`, `roles`, `body`, `date`) VALUES (?d, ?d, ?d, ?d, ?, UNIX_TIMESTAMP())', $this->_get['type'], $this->_get['typeid'], User::$id, User::$groups, $this->_post['commentbody']))
|
||||
{
|
||||
Util::gainSiteReputation(User::$id, SITEREP_ACTION_COMMENT, ['id' => $postId]);
|
||||
|
||||
// every comment starts with a rating of +1 and i guess the simplest thing to do is create a db-entry with the system as owner
|
||||
DB::Aowow()->query('INSERT INTO ?_user_ratings (`type`, `entry`, `userId`, `value`) VALUES (?d, ?d, 0, 1)', RATING_COMMENT, $postId);
|
||||
|
||||
// flag target with hasComment
|
||||
if ($tbl = Type::getClassAttrib($this->_get['type'], 'dataTable'))
|
||||
DB::Aowow()->query('UPDATE ?# SET `cuFlags` = `cuFlags` | ?d WHERE `id` = ?d', $tbl, CUSTOM_HAS_COMMENT, $this->_get['typeid']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
trigger_error('CommentAddResponse - write to db failed', E_USER_ERROR);
|
||||
$_SESSION['error']['co'] = Lang::main('intError');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// expects non-200 header on error
|
||||
class CommentDeletereplyResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertPOST('id'))
|
||||
{
|
||||
trigger_error('CommentDeletereplyResponse - malformed request received', E_USER_ERROR);
|
||||
$this->generate404(User::isInGroup(U_GROUP_STAFF) ? 'request malformed' : '');
|
||||
}
|
||||
|
||||
// flag as deleted (unset sticky (can a reply even be sticky?)
|
||||
$ok = DB::Aowow()->query('UPDATE ?_comments SET `flags` = `flags` & ~?d | ?d, `deleteUserId` = ?d, `deleteDate` = UNIX_TIMESTAMP() WHERE `id` = ?d { AND `userId` = ?d }',
|
||||
CC_FLAG_STICKY, CC_FLAG_DELETED,
|
||||
User::$id,
|
||||
$this->_post['id'],
|
||||
User::isInGroup(U_GROUP_MODERATOR) ? DBSIMPLE_SKIP : User::$id
|
||||
);
|
||||
|
||||
if ($ok)
|
||||
DB::Aowow()->query('DELETE FROM ?_user_ratings WHERE `type` = ?d AND `entry` = ?d', RATING_COMMENT, $this->_post['id']);
|
||||
else
|
||||
{
|
||||
trigger_error('CommentDeletereplyResponse - deleting reply #'.$this->_post['id'].' by user #'.User::$id.' from db failed', E_USER_ERROR);
|
||||
$this->generate404(Lang::main('intError'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class CommentDeleteResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdListUnsigned']],
|
||||
// 'username' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine'] ]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertPOST('id'))
|
||||
{
|
||||
trigger_error('CommentDeleteResponse - malformed request received', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// in theory, there is a username passed alongside if executed from userpage... lets just use the current user (see user.js)
|
||||
$ok = DB::Aowow()->query('UPDATE ?_comments SET `flags` = `flags` | ?d, `deleteUserId` = ?d, `deleteDate` = UNIX_TIMESTAMP() WHERE `id` IN (?a) { AND `userId` = ?d }',
|
||||
CC_FLAG_DELETED,
|
||||
User::$id,
|
||||
$this->_post['id'],
|
||||
User::isInGroup(U_GROUP_MODERATOR) ? DBSIMPLE_SKIP : User::$id
|
||||
);
|
||||
|
||||
// unflag subject: hasComment
|
||||
if ($ok)
|
||||
{
|
||||
$coInfo = DB::Aowow()->select(
|
||||
'SELECT IF(BIT_OR(~b.`flags`) & ?d, 1, 0) AS "0", b.`type` AS "1", b.`typeId` AS "2" FROM ?_comments a JOIN ?_comments b ON a.`type` = b.`type` AND a.`typeId` = b.`typeId` WHERE a.`id` IN (?a) GROUP BY b.`type`, b.`typeId`',
|
||||
CC_FLAG_DELETED, $this->_post['id']
|
||||
);
|
||||
|
||||
foreach ($coInfo as [$hasMore, $type, $typeId])
|
||||
if (!$hasMore && ($tbl = Type::getClassAttrib($type, 'dataTable')))
|
||||
DB::Aowow()->query('UPDATE ?# SET `cuFlags` = `cuFlags` & ~?d WHERE `id` = ?d', $tbl, CUSTOM_HAS_COMMENT, $typeId);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
trigger_error('CommentDeleteResponse - user #'.User::$id.' could not flag comment(s) #'.implode(', ', $this->_post['id']).' as deleted', E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// expects non-200 header on error
|
||||
class CommentDetachreplyResponse extends TextResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_MODERATOR;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertPOST('id'))
|
||||
{
|
||||
trigger_error('CommentDetachreplyResponse - malformed request received', E_USER_ERROR);
|
||||
$this->generate404(User::isInGroup(U_GROUP_STAFF) ? 'request malformed' : '');
|
||||
}
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_comments c1, ?_comments c2 SET c1.`replyTo` = 0, c1.`type` = c2.`type`, c1.`typeId` = c2.`typeId` WHERE c1.`replyTo` = c2.`id` AND c1.`id` = ?d', $this->_post['id']);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,61 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// expects non-200 header on error
|
||||
class CommentDownvotereplyResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertPOST('id'))
|
||||
{
|
||||
trigger_error('CommentDownvotereplyResponse - malformed request received', E_USER_ERROR);
|
||||
$this->generate404(User::isInGroup(U_GROUP_STAFF) ? 'request malformed' : '');
|
||||
}
|
||||
|
||||
if (!User::canDownvote())
|
||||
$this->generate404(User::isInGroup(U_GROUP_STAFF) ? 'cannot downvote' : '');
|
||||
|
||||
$comment = DB::Aowow()->selectRow('SELECT `userId`, IF(`flags` & ?d, 1, 0) AS "deleted" FROM ?_comments WHERE `id` = ?d', CC_FLAG_DELETED, $this->_post['id']);
|
||||
if (!$comment)
|
||||
{
|
||||
trigger_error('CommentDownvotereplyResponse - comment #'.$this->_post['id'].' not found in db', E_USER_ERROR);
|
||||
$this->generate404(User::isInGroup(U_GROUP_STAFF) ? 'replyID not found' : '');
|
||||
}
|
||||
|
||||
if (User::$id == $comment['userId']) // not worth logging?
|
||||
$this->generate404('LANG.voteself_tip');
|
||||
|
||||
if ($comment['deleted'])
|
||||
$this->generate404('LANG.votedeleted_tip');
|
||||
|
||||
$ok = DB::Aowow()->query(
|
||||
'INSERT INTO ?_user_ratings (`type`, `entry`, `userId`, `value`) VALUES (?d, ?d, ?d, ?d)',
|
||||
RATING_COMMENT,
|
||||
$this->_post['id'],
|
||||
User::$id,
|
||||
User::canSupervote() ? -2 : -1
|
||||
);
|
||||
|
||||
if (!is_int($ok))
|
||||
{
|
||||
trigger_error('CommentDownvotereplyResponse - write to db failed', E_USER_ERROR);
|
||||
$this->generate404(User::isInGroup(U_GROUP_STAFF) ? 'write to db failed' : '');
|
||||
}
|
||||
|
||||
Util::gainSiteReputation($comment['userId'], SITEREP_ACTION_DOWNVOTED, ['id' => $this->_post['id'], 'voterId' => User::$id]);
|
||||
User::decrementDailyVotes();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,62 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// returns all replies on success
|
||||
// must have non-200 header on error
|
||||
class CommentEditreplyResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'commentId' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'replyId' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'body' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextBlob']]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertPOST('commentId', 'replyId', 'body'))
|
||||
{
|
||||
trigger_error('CommentEditreplyResponse - malformed request received', E_USER_ERROR);
|
||||
$this->generate404(User::isInGroup(U_GROUP_STAFF) ? 'request malformed' : '');
|
||||
}
|
||||
|
||||
$ownerId = DB::Aowow()->selectCell('SELECT `userId` FROM ?_comments WHERE `id` = ?d AND `replyTo` = ?d', $this->_post['replyId'], $this->_post['commentId']);
|
||||
|
||||
if (!User::canReply() || (User::$id != $ownerId && !User::isInGroup(U_GROUP_MODERATOR)))
|
||||
$this->generate404(Lang::main('cannotComment'));
|
||||
|
||||
if (!$ownerId)
|
||||
{
|
||||
trigger_error('CommentEditreplyResponse - comment #'.$this->_post['commentId'].' or reply #'.$this->_post['replyId'].' does not exist', E_USER_ERROR);
|
||||
$this->generate404(Lang::main('intError'));
|
||||
}
|
||||
|
||||
if (mb_strlen($this->_post['body']) < CommunityContent::REPLY_LENGTH_MIN || mb_strlen($this->_post['body']) > CommunityContent::REPLY_LENGTH_MAX)
|
||||
$this->generate404(Lang::main('textLength', [mb_strlen($this->_post['body']), CommunityContent::REPLY_LENGTH_MIN, CommunityContent::REPLY_LENGTH_MAX]));
|
||||
|
||||
$update = array(
|
||||
'body' => $this->_post['body'],
|
||||
'editUserId' => User::$id,
|
||||
'editDate' => time()
|
||||
);
|
||||
if (User::$id == $ownerId)
|
||||
$update['roles'] = User::$groups;
|
||||
|
||||
if (!DB::Aowow()->query('UPDATE ?_comments SET `editCount` = `editCount` + 1, ?a WHERE `id` = ?d AND `replyTo` = ?d { AND `userId` = ?d }',
|
||||
$update, $this->_post['replyId'], $this->_post['commentId'], User::isInGroup(U_GROUP_MODERATOR) ? DBSIMPLE_SKIP : User::$id))
|
||||
{
|
||||
trigger_error('CommentEditreplyResponse - write to db failed', E_USER_ERROR);
|
||||
$this->generate404(Lang::main('intError'));
|
||||
}
|
||||
|
||||
$this->result = Util::toJSON(CommunityContent::getCommentReplies($this->_post['commentId']));
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,63 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class CommentEditResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'body' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextBlob']],
|
||||
'response' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextBlob']]
|
||||
);
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('id') || !$this->assertPOST('body'))
|
||||
{
|
||||
trigger_error('CommentEditResponse - malforemd request received', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$ownerId = DB::Aowow()->selectCell('SELECT `userId` FROM ?_comments WHERE `id` = ?d', $this->_get['id']);
|
||||
|
||||
if (!User::canComment() || (User::$id != $ownerId && !User::isInGroup(U_GROUP_MODERATOR)))
|
||||
{
|
||||
trigger_error('CommentEditResponse - user #'.User::$id.' not allowed to edit comment #'.$this->_get['id'], E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!User::isInGroup(U_GROUP_MODERATOR) && mb_strlen($this->_post['body']) < CommunityContent::COMMENT_LENGTH_MIN)
|
||||
return; // no point in reporting this trifle
|
||||
|
||||
// trim to max length
|
||||
if (!User::isInGroup(U_GROUP_MODERATOR))
|
||||
$this->_post['body'] = mb_substr($this->_post['body'], 0, (CommunityContent::COMMENT_LENGTH_MAX * (User::isPremium() ? 3 : 1)));
|
||||
|
||||
$update = array(
|
||||
'body' => $this->_post['body'],
|
||||
'editUserId' => User::$id,
|
||||
'editDate' => time()
|
||||
);
|
||||
if (User::$id == $ownerId)
|
||||
$update['roles'] = User::$groups;
|
||||
|
||||
if (User::isInGroup(U_GROUP_MODERATOR))
|
||||
{
|
||||
$update['responseBody'] = $this->_post['response'] ?? '';
|
||||
$update['responseUserId'] = User::$id;
|
||||
$update['responseRoles'] = User::$groups;
|
||||
}
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_comments SET `editCount` = `editCount` + 1, ?a WHERE `id` = ?d', $update, $this->_get['id']);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// expects non-200 header on error
|
||||
class CommentFlagreplyResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertPOST('id'))
|
||||
{
|
||||
trigger_error('CommentFlagreplyResponse - malformed request received', E_USER_ERROR);
|
||||
$this->generate404(User::isInGroup(U_GROUP_STAFF) ? 'request malformed' : '');
|
||||
}
|
||||
|
||||
$replyOwner = DB::Aowow()->selectCell('SELECT `userId` FROM ?_commments WHERE `id` = ?d', $this->_post['id']);
|
||||
if (!$replyOwner)
|
||||
{
|
||||
trigger_error('CommentFlagreplyResponse - reply not found', E_USER_ERROR);
|
||||
$this->generate404(Lang::main('intError'));
|
||||
}
|
||||
|
||||
// ui element should not be present
|
||||
if ($replyOwner == User::$id)
|
||||
$this->generate404();
|
||||
|
||||
$report = new Report(Report::MODE_COMMENT, Report::CO_INAPPROPRIATE, $this->_post['id']);
|
||||
if (!$report->create('Report Reply Button Click'))
|
||||
$this->generate404('LANG.ct_resp_error'.$report->getError());
|
||||
else if (count($report->getSimilar()) >= CommunityContent::REPORT_THRESHOLD_AUTO_DELETE)
|
||||
DB::Aowow()->query('UPDATE ?_comments SET `flags` = `flags` | ?d WHERE `id` = ?d', CC_FLAG_DELETED, $this->_post['id']);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,58 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// toggle flag
|
||||
class CommentOutofdateResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'remove' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 1, 'max_range' => 1]],
|
||||
'reason' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextBlob'] ]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertPOST('id'))
|
||||
{
|
||||
trigger_error('CommentOutofdateResponse - malformed request received', E_USER_ERROR);
|
||||
if (User::isInGroup(U_GROUP_STAFF))
|
||||
$this->result = 'malformed request received';
|
||||
}
|
||||
|
||||
$ok = false;
|
||||
if (User::isInGroup(U_GROUP_MODERATOR)) // directly mark as outdated
|
||||
{
|
||||
if (!$this->_post['remove'])
|
||||
$ok = DB::Aowow()->query('UPDATE ?_comments SET `flags` = `flags` | ?d WHERE `id` = ?d', CC_FLAG_OUTDATED, $this->_post['id']);
|
||||
else
|
||||
$ok = DB::Aowow()->query('UPDATE ?_comments SET `flags` = `flags` & ~?d WHERE `id` = ?d', CC_FLAG_OUTDATED, $this->_post['id']);
|
||||
}
|
||||
else // try to report as outdated
|
||||
{
|
||||
$report = new Report(Report::MODE_COMMENT, Report::CO_OUT_OF_DATE, $this->_post['id']);
|
||||
if (!$report->create($this->_post['reason']))
|
||||
$this->result = Lang::main('intError');
|
||||
|
||||
if (count($report->getSimilar()) >= CommunityContent::REPORT_THRESHOLD_AUTO_OUT_OF_DATE)
|
||||
$ok = DB::Aowow()->query('UPDATE ?_comments SET `flags` = `flags` | ?d WHERE `id` = ?d', CC_FLAG_OUTDATED, $this->_post['id']);
|
||||
}
|
||||
|
||||
if (!$ok)
|
||||
{
|
||||
trigger_error('CommentOutofdateResponse - failed to update comment in db', E_USER_ERROR);
|
||||
$this->result = Lang::main('intError');
|
||||
return;
|
||||
}
|
||||
|
||||
$this->result = 'ok'; // the js expects the actual characters 'ok' on success, not some json string like '"ok"'
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// up/down - distribution
|
||||
class CommentRatingResponse extends TextResponse
|
||||
{
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('id'))
|
||||
{
|
||||
$this->result = Util::toJSON(['success' => 0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($votes = DB::Aowow()->selectRow('SELECT 1 AS "success", SUM(IF(`value` > 0, `value`, 0)) AS "up", SUM(IF(`value` < 0, -`value`, 0)) AS "down" FROM ?_user_ratings WHERE `type` = ?d AND `entry` = ?d AND `userId` <> 0 GROUP BY `entry`', RATING_COMMENT, $this->_get['id']))
|
||||
$this->result = Util::toJSON($votes);
|
||||
else
|
||||
$this->result = Util::toJSON(['success' => 1, 'up' => 0, 'down' => 0]);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class CommentShowrepliesResponse extends TextResponse
|
||||
{
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('id'))
|
||||
$this->result = Util::toJSON([]);
|
||||
else
|
||||
$this->result = Util::toJSON(CommunityContent::getCommentReplies($this->_get['id']));
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// toggle flag
|
||||
class CommentStickyResponse extends TextResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_MODERATOR;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'sticky' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 0, 'max_range' => 1]]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertPOST('id', 'sticky'))
|
||||
{
|
||||
trigger_error('CommentStickyResponse - malformed request received', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->_post['sticky'])
|
||||
DB::Aowow()->query('UPDATE ?_comments SET `flags` = `flags` | ?d WHERE `id` = ?d', CC_FLAG_STICKY, $this->_post['id']);
|
||||
else
|
||||
DB::Aowow()->query('UPDATE ?_comments SET `flags` = `flags` & ~?d WHERE `id` = ?d', CC_FLAG_STICKY, $this->_post['id']);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,48 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class CommentUndeleteResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdListUnsigned']],
|
||||
// 'username' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine'] ]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertPOST('id'))
|
||||
{
|
||||
trigger_error('CommentUndeleteResponse - malformed request received', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// in theory, there is a username passed alongside if executed from userpage... lets just use the current user (see user.js)
|
||||
$ok = DB::Aowow()->query('UPDATE ?_comments SET `flags` = `flags` & ~?d WHERE `id` IN (?a) { AND `userId` = `deleteUserId` AND `deleteUserId` = ?d }',
|
||||
CC_FLAG_DELETED,
|
||||
$this->_post['id'],
|
||||
User::isInGroup(U_GROUP_MODERATOR) ? DBSIMPLE_SKIP : User::$id
|
||||
);
|
||||
|
||||
// unflag subject: hasComment
|
||||
if ($ok)
|
||||
{
|
||||
$coInfo = DB::Aowow()->select('SELECT `type` AS "0", `typeId` AS "1" FROM ?_comments WHERE `id` IN (?a) GROUP BY `type`, `typeId`', $this->_post['id']);
|
||||
foreach ($coInfo as [$type, $typeId])
|
||||
if ($tbl = Type::getClassAttrib($type, 'dataTable'))
|
||||
DB::Aowow()->query('UPDATE ?# SET `cuFlags` = `cuFlags` | ?d WHERE `id` = ?d', $tbl, CUSTOM_HAS_COMMENT, $typeId);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
trigger_error('CommentUndeleteResponse - user #'.User::$id.' could not unflag comment(s) #'.implode(', ', $this->_post['id']).' from deleted', E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,61 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// expects non-200 header on error
|
||||
class CommentUpvotereplyResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertPOST('id'))
|
||||
{
|
||||
trigger_error('CommentUpvotereplyResponse - malformed request received', E_USER_ERROR);
|
||||
$this->generate404(User::isInGroup(U_GROUP_STAFF) ? 'request malformed' : '');
|
||||
}
|
||||
|
||||
if (!User::canUpvote())
|
||||
$this->generate404(User::isInGroup(U_GROUP_STAFF) ? 'cannot upvote' : '');
|
||||
|
||||
$comment = DB::Aowow()->selectRow('SELECT `userId`, IF(`flags` & ?d, 1, 0) AS "deleted" FROM ?_comments WHERE `id` = ?d', CC_FLAG_DELETED, $this->_post['id']);
|
||||
if (!$comment)
|
||||
{
|
||||
trigger_error('CommentUpvotereplyResponse - comment #'.$this->_post['id'].' not found in db', E_USER_ERROR);
|
||||
$this->generate404(User::isInGroup(U_GROUP_STAFF) ? 'replyID not found' : '');
|
||||
}
|
||||
|
||||
if (User::$id == $comment['userId']) // not worth logging?
|
||||
$this->generate404('LANG.voteself_tip');
|
||||
|
||||
if ($comment['deleted'])
|
||||
$this->generate404('LANG.votedeleted_tip');
|
||||
|
||||
$ok = DB::Aowow()->query(
|
||||
'INSERT INTO ?_user_ratings (`type`, `entry`, `userId`, `value`) VALUES (?d, ?d, ?d, ?d)',
|
||||
RATING_COMMENT,
|
||||
$this->_post['id'],
|
||||
User::$id,
|
||||
User::canSupervote() ? 2 : 1
|
||||
);
|
||||
|
||||
if (!is_int($ok))
|
||||
{
|
||||
trigger_error('CommentUpvotereplyResponse - write to db failed', E_USER_ERROR);
|
||||
$this->generate404(User::isInGroup(U_GROUP_STAFF) ? 'write to db failed' : '');
|
||||
}
|
||||
|
||||
Util::gainSiteReputation($comment['userId'], SITEREP_ACTION_UPVOTED, ['id' => $this->_post['id'], 'voterId' => User::$id]);
|
||||
User::decrementDailyVotes();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,84 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// up, down and remove
|
||||
class CommentVoteResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'rating' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => -2, 'max_range' => 2]]
|
||||
);
|
||||
|
||||
protected function generate(): void
|
||||
{
|
||||
if (!$this->assertGET('id', 'rating'))
|
||||
{
|
||||
trigger_error('CommentVoteResponse - malformed request received', E_USER_ERROR);
|
||||
$this->result = Util::toJSON(['error' => 1, 'message' => Lang::main('genericError')]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (User::getCurrentDailyVotes() <= 0)
|
||||
{
|
||||
$this->result = Util::toJSON(['error' => 1, 'message' => Lang::main('tooManyVotes')]);
|
||||
return;
|
||||
}
|
||||
|
||||
$target = DB::Aowow()->selectRow(
|
||||
'SELECT c.`userId` AS "owner", ur.`value`, IF(c.`flags` & ?d, 1, 0) AS "deleted" FROM ?_comments c LEFT JOIN ?_user_ratings ur ON ur.`type` = ?d AND ur.`entry` = c.id AND ur.`userId` = ?d WHERE c.id = ?d',
|
||||
CC_FLAG_DELETED, RATING_COMMENT, User::$id, $this->_get['id']
|
||||
);
|
||||
if (!$target)
|
||||
{
|
||||
trigger_error('CommentVoteResponse - target comment #'.$this->_get['id'].' not found', E_USER_ERROR);
|
||||
$this->result = Util::toJSON(['error' => 1, 'message' => Lang::main('genericError')]);
|
||||
return;
|
||||
}
|
||||
|
||||
$val = User::canSupervote() ? 2 : 1;
|
||||
if ($this->_get['rating'] < 0)
|
||||
$val *= -1;
|
||||
|
||||
if (User::$id == $target['owner'] || $val != $this->_get['rating'] || $target['deleted'])
|
||||
{
|
||||
// circumvented the checks in JS
|
||||
$this->result = Util::toJSON(['error' => 1, 'message' => Lang::main('genericError')]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (($val > 0 && !User::canUpvote()) || ($val < 0 && !User::canDownvote()))
|
||||
{
|
||||
$this->result = Util::toJSON(['error' => 1, 'message' => Lang::main('bannedRating')]);
|
||||
return;
|
||||
}
|
||||
|
||||
$ok = false;
|
||||
// old and new have same sign; undo vote (user may have gained/lost access to superVote in the meantime)
|
||||
if ($target['value'] && ($target['value'] < 0) == ($val < 0))
|
||||
$ok = DB::Aowow()->query('DELETE FROM ?_user_ratings WHERE `type` = ?d AND `entry` = ?d AND `userId` = ?d', RATING_COMMENT, $this->_get['id'], User::$id);
|
||||
else // replace, because we may be overwriting an old, opposing vote
|
||||
if ($ok = DB::Aowow()->query('REPLACE INTO ?_user_ratings (`type`, `entry`, `userId`, `value`) VALUES (?d, ?d, ?d, ?d)', RATING_COMMENT, $this->_get['id'], User::$id, $val))
|
||||
User::decrementDailyVotes(); // do not refund retracted votes!
|
||||
|
||||
if ($ok)
|
||||
{
|
||||
if ($val > 0) // gain rep
|
||||
Util::gainSiteReputation($target['owner'], SITEREP_ACTION_UPVOTED, ['id' => $this->_get['id'], 'voterId' => User::$id]);
|
||||
else if ($val < 0)
|
||||
Util::gainSiteReputation($target['owner'], SITEREP_ACTION_DOWNVOTED, ['id' => $this->_get['id'], 'voterId' => User::$id]);
|
||||
|
||||
$this->result = Util::toJSON(['error' => 0]);
|
||||
}
|
||||
else
|
||||
$this->result = Util::toJSON(['error' => 1, 'message' => Lang::main('intError')]);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,116 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// tabId 1: Tools g_initHeader()
|
||||
class CompareBaseResponse extends TemplateResponse
|
||||
{
|
||||
protected string $template = 'compare';
|
||||
protected string $pageName = 'compare';
|
||||
protected ?int $activeTab = parent::TAB_TOOLS;
|
||||
protected array $breadcrumb = [1, 3];
|
||||
|
||||
protected array $dataLoader = ['weight-presets', 'gems', 'enchants', 'itemsets'];
|
||||
protected array $scripts = array(
|
||||
[SC_JS_FILE, 'js/profile.js'],
|
||||
[SC_JS_FILE, 'js/Draggable.js'],
|
||||
[SC_JS_FILE, 'js/filters.js'],
|
||||
[SC_JS_FILE, 'js/Summary.js'],
|
||||
[SC_CSS_FILE, 'css/Summary.css']
|
||||
);
|
||||
protected array $expectedGET = array(
|
||||
'compare' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkCompareString']]
|
||||
);
|
||||
protected array $expectedCOOKIE = array(
|
||||
'compare_groups' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkCompareString']]
|
||||
);
|
||||
|
||||
public Summary $summary;
|
||||
public array $cmpItems = [];
|
||||
|
||||
private string $compareString = '';
|
||||
|
||||
public function __construct($pageParam)
|
||||
{
|
||||
parent::__construct($pageParam);
|
||||
|
||||
// prefer GET over COOKIE
|
||||
if ($this->_get['compare'])
|
||||
$this->compareString = $this->_get['compare'];
|
||||
else if ($this->_cookie['compare_groups'])
|
||||
$this->compareString = $this->_cookie['compare_groups'];
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->h1 = Lang::main('compareTool');
|
||||
|
||||
|
||||
array_unshift($this->title, $this->h1);
|
||||
|
||||
|
||||
$this->summary = new Summary(array(
|
||||
'template' => 'compare',
|
||||
'id' => 'compare',
|
||||
'parent' => 'compare-generic'
|
||||
));
|
||||
|
||||
if ($this->compareString)
|
||||
{
|
||||
$items = [];
|
||||
foreach (explode(';', $this->compareString) as $itemsString)
|
||||
{
|
||||
$suGroup = [];
|
||||
foreach (explode(':', $itemsString) as $itemDef)
|
||||
{
|
||||
// [itemId, subItem, permEnch, tempEnch, gem1, gem2, gem3, gem4]
|
||||
$params = array_pad(array_map('intVal', explode('.', $itemDef)), 8, 0);
|
||||
$items[] = $params[0];
|
||||
$suGroup[] = $params;
|
||||
}
|
||||
|
||||
$this->summary->addGroup($suGroup);
|
||||
}
|
||||
|
||||
$iList = new ItemList(array(['i.id', $items]));
|
||||
$data = $iList->getListviewData(ITEMINFO_SUBITEMS | ITEMINFO_JSON);
|
||||
|
||||
foreach ($iList->iterate() as $itemId => $__)
|
||||
{
|
||||
if (empty($data[$itemId]))
|
||||
continue;
|
||||
|
||||
if (!empty($data[$itemId]['subitems']))
|
||||
foreach ($data[$itemId]['subitems'] as &$si)
|
||||
{
|
||||
$si['enchantment'] = implode(', ', $si['enchantment']);
|
||||
unset($si['chance']);
|
||||
}
|
||||
|
||||
$this->cmpItems[$itemId] = [
|
||||
'name_'.Lang::getLocale()->json() => $iList->getField('name', true),
|
||||
'quality' => $iList->getField('quality'),
|
||||
'icon' => $iList->getField('iconString'),
|
||||
'jsonequip' => $data[$itemId]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
parent::generate();
|
||||
}
|
||||
|
||||
protected static function checkCompareString(string $val) : string
|
||||
{
|
||||
$val = urldecode($val);
|
||||
if (preg_match('/[^-?\d\.:;]/', $val))
|
||||
return '';
|
||||
|
||||
return $val;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,54 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class CookieBaseResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'purge' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkEmptySet']]
|
||||
);
|
||||
|
||||
public function __construct(private string $param)
|
||||
{
|
||||
// note that parent::__construct has to come after this
|
||||
if ($param && preg_match('/^[\w-]+$/i', $param))
|
||||
$this->expectedGET = [$param => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine']]];
|
||||
|
||||
// NOW we know, what to expect and sanitize
|
||||
parent::__construct($param);
|
||||
}
|
||||
|
||||
/* responses
|
||||
0: success
|
||||
$: silent error
|
||||
*/
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->param && $this->_get['purge'])
|
||||
{
|
||||
if (User::$id && DB::Aowow()->query('UPDATE ?_account_cookies SET `data` = "purged" WHERE `userId` = ?d AND `name` LIKE "announcement-%"', User::$id) !== null)
|
||||
$this->result = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->param || !$this->assertGET($this->param))
|
||||
{
|
||||
trigger_error('CookieBaseResponse - malformed request received', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (DB::Aowow()->query('REPLACE INTO ?_account_cookies VALUES (?d, ?, ?)', User::$id, $this->param, $this->_get[$this->param]))
|
||||
$this->result = 0;
|
||||
else
|
||||
trigger_error('CookieBaseResponse - write to db failed', E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,76 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class CurrenciesBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $type = Type::CURRENCY;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
|
||||
protected string $template = 'list-page-generic';
|
||||
protected string $pageName = 'currencies';
|
||||
protected ?int $activeTab = parent::TAB_DATABASE;
|
||||
protected array $breadcrumb = [0, 15];
|
||||
|
||||
protected array $validCats = [1, 2, 3, 22];
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
$this->getCategoryFromUrl($pageParam);
|
||||
|
||||
parent::__construct($pageParam);
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->h1 = Util::ucFirst(Lang::game('currencies'));
|
||||
|
||||
|
||||
/**************/
|
||||
/* Page Title */
|
||||
/**************/
|
||||
|
||||
array_unshift($this->title, $this->h1);
|
||||
if ($this->category)
|
||||
array_unshift($this->title, Lang::currency('cat', $this->category[0]));
|
||||
|
||||
|
||||
/*************/
|
||||
/* Menu Path */
|
||||
/*************/
|
||||
|
||||
if ($this->category)
|
||||
$this->breadcrumb[] = $this->category[0];
|
||||
|
||||
|
||||
/****************/
|
||||
/* Main Content */
|
||||
/****************/
|
||||
|
||||
$this->redButtons[BUTTON_WOWHEAD] = true;
|
||||
|
||||
$conditions = [];
|
||||
|
||||
if (!User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
$conditions[] = [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0];
|
||||
|
||||
if ($this->category)
|
||||
$conditions[] = ['category', $this->category[0]];
|
||||
|
||||
$money = new CurrencyList($conditions);
|
||||
|
||||
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"]);
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview(['data' => $money->getListviewData()], CurrencyList::$brickFile));
|
||||
|
||||
parent::generate();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,50 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class CurrencyPowerResponse extends TextResponse implements ICache
|
||||
{
|
||||
use TrTooltip, TrCache;
|
||||
|
||||
private const /* string */ POWER_TEMPLATE = '$WowheadPower.registerCurrency(%d, %d, %s);';
|
||||
|
||||
protected int $type = Type::CURRENCY;
|
||||
protected int $typeId = 0;
|
||||
protected int $cacheType = CACHE_TYPE_TOOLTIP;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'domain' => ['filter' => FILTER_CALLBACK, 'options' => [Locale::class, 'tryFromDomain']]
|
||||
);
|
||||
|
||||
public function __construct(string $id)
|
||||
{
|
||||
parent::__construct($id);
|
||||
|
||||
// temp locale
|
||||
if ($this->_get['domain'])
|
||||
Lang::load($this->_get['domain']);
|
||||
|
||||
$this->typeId = intVal($id);
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$currency = new CurrencyList(array(['id', $this->typeId]));
|
||||
if ($currency->error)
|
||||
$this->cacheType = CACHE_TYPE_NONE;
|
||||
else
|
||||
$opts = array(
|
||||
'name' => $currency->getField('name', true),
|
||||
'tooltip' => $currency->renderTooltip(),
|
||||
'icon' => $currency->getField('iconString')
|
||||
);
|
||||
|
||||
$this->result = new Tooltip(self::POWER_TEMPLATE, $this->typeId, $opts ?? []);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,149 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class DataBaseResponse extends TextResponse
|
||||
{
|
||||
protected array $expectedGET = array(
|
||||
'locale' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkLocale' ]],
|
||||
't' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine' ]],
|
||||
'catg' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'skill' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkSkill' ]],
|
||||
'class' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 1, 'max_range' => 11]],
|
||||
'callback' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkCallback' ]]
|
||||
);
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
parent::__construct($pageParam);
|
||||
|
||||
if ($this->_get['locale']?->validate())
|
||||
Lang::load($this->_get['locale']);
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
// different data can be strung together
|
||||
foreach ($this->params as $set)
|
||||
{
|
||||
// requires valid token to hinder automated access
|
||||
if ($set != 'item-scaling' && (!$this->_get['t'] || empty($_SESSION['dataKey']) || $this->_get['t'] != $_SESSION['dataKey']))
|
||||
{
|
||||
trigger_error('DataBaseResponse::generate - session data key empty or expired', E_USER_ERROR);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* issue on no initial data:
|
||||
when we loadOnDemand, the jScript tries to generate the catg-tree before it is initialized
|
||||
it cant be initialized, without loading the data as empty catg are omitted
|
||||
loading the data triggers the generation of the catg-tree
|
||||
*/
|
||||
|
||||
$this->result .= match($set)
|
||||
{
|
||||
'factions' => $this->loadProfilerData($set),
|
||||
'mounts' => $this->loadProfilerData($set, SKILL_MOUNTS),
|
||||
'companions' => $this->loadProfilerData($set, SKILL_COMPANIONS),
|
||||
'quests' => $this->loadProfilerQuests($set, $this->_get['catg']),
|
||||
'recipes' => $this->loadProfilerRecipes(),
|
||||
// locale independent
|
||||
'quick-excludes',
|
||||
'weight-presets',
|
||||
'item-scaling',
|
||||
'realms',
|
||||
'statistics' => $this->loadAgnosticFile($set),
|
||||
// localized
|
||||
'talents',
|
||||
'achievements',
|
||||
'pet-talents',
|
||||
'glyphs',
|
||||
'gems',
|
||||
'enchants',
|
||||
'itemsets',
|
||||
'pets',
|
||||
'zones' => $this->loadLocalizedFile($set),
|
||||
default => (function($x) { trigger_error('DataBaseResponse::generate - invalid file "'.$x.'" in request', E_USER_ERROR); })($set),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private function loadProfilerRecipes() : string
|
||||
{
|
||||
if (!$this->_get['callback'] || !$this->_get['skill'])
|
||||
return '';
|
||||
|
||||
$result = '';
|
||||
|
||||
foreach ($this->_get['skill'] as $s)
|
||||
Util::loadStaticFile('p-recipes-'.$s, $result, true);
|
||||
|
||||
Util::loadStaticFile('p-recipes-sec', $result, true);
|
||||
$result .= "\n\$WowheadProfiler.loadOnDemand('recipes', null);\n";
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function loadProfilerQuests(string $file, ?string $catg = null) : string
|
||||
{
|
||||
$result = '';
|
||||
|
||||
if ($catg === null)
|
||||
Util::loadStaticFile('p-'.$file, $result, false);
|
||||
else
|
||||
Util::loadStaticFile('p-'.$file.'-'.$catg, $result, true);
|
||||
|
||||
$result .= "\n\$WowheadProfiler.loadOnDemand('".$file."', ".($catg ?? 'null').");\n";
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function loadProfilerData(string $file, ?string $catg = null) : string
|
||||
{
|
||||
$result = '';
|
||||
|
||||
if ($this->_get['callback'])
|
||||
if (Util::loadStaticFile('p-'.$file, $result, true))
|
||||
$result .= "\n\$WowheadProfiler.loadOnDemand('".$file."', ".($catg ?? 'null').");\n";
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function loadAgnosticFile(string $file) : string
|
||||
{
|
||||
$result = '';
|
||||
|
||||
if (!Util::loadStaticFile($file, $result) && Cfg::get('DEBUG'))
|
||||
$result .= "alert('could not fetch static data: ".$file."');";
|
||||
|
||||
return $result . "\n\n";
|
||||
}
|
||||
|
||||
private function loadLocalizedFile(string $file) : string
|
||||
{
|
||||
$result = '';
|
||||
|
||||
if ($file == 'talents' && ($_ = $this->_get['class']))
|
||||
$file .= "-".$_;
|
||||
|
||||
if (!Util::loadStaticFile($file, $result, true) && Cfg::get('DEBUG'))
|
||||
$result .= "alert('could not fetch static data: ".$file." for locale: ".Lang::getLocale()->json()."');";
|
||||
|
||||
return $result . "\n\n";
|
||||
}
|
||||
|
||||
protected static function checkSkill(string $val) : array
|
||||
{
|
||||
return array_intersect(array_merge(SKILLS_TRADE_PRIMARY, [SKILL_FIRST_AID, SKILL_COOKING, SKILL_FISHING]), explode(',', $val));
|
||||
}
|
||||
|
||||
protected static function checkCallback(string $val) : bool
|
||||
{
|
||||
return substr($val, 0, 29) === '$WowheadProfiler.loadOnDemand';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,48 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class EditImageResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'qqfile' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine'] ],
|
||||
'guide' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 1, 'max_range' => 1]]
|
||||
);
|
||||
|
||||
/*
|
||||
success: bool
|
||||
id: image enumerator
|
||||
type: 3 ? png : jpg
|
||||
name: old filename
|
||||
error: errString
|
||||
*/
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('qqfile', 'guide'))
|
||||
{
|
||||
$this->result = Util::toJSON(['success' => false, 'error' => Lang::main('genericError')]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!User::canWriteGuide())
|
||||
{
|
||||
$this->result = Util::toJSON(['success' => false, 'error' => Lang::main('genericError')]);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->result = GuideMgr::handleUpload();
|
||||
|
||||
if (isset($this->result['success']))
|
||||
$this->result += ['name' => $this->_get['qqfile']];
|
||||
|
||||
$this->result = Util::toJSON($this->result);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,61 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class EmotesBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
protected int $type = Type::EMOTE;
|
||||
|
||||
protected string $template = 'list-page-generic';
|
||||
protected string $pageName = 'emotes';
|
||||
protected ?int $activeTab = parent::TAB_DATABASE;
|
||||
protected array $breadcrumb = [0, 100];
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
$this->getCategoryFromUrl($pageParam);
|
||||
|
||||
parent::__construct($pageParam);
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->h1 = Util::ucFirst(Lang::game('emotes'));
|
||||
|
||||
|
||||
/**************/
|
||||
/* Page Title */
|
||||
/**************/
|
||||
|
||||
array_unshift($this->title, $this->h1);
|
||||
|
||||
|
||||
/****************/
|
||||
/* Main Content */
|
||||
/****************/
|
||||
|
||||
$cnd = [Cfg::get('SQL_LIMIT_NONE')];
|
||||
if (!User::isInGroup(U_GROUP_STAFF))
|
||||
$cnd[] = [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0];
|
||||
|
||||
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"]);
|
||||
|
||||
$tabData = array(
|
||||
'data' => (new EmoteList($cnd))->getListviewData(),
|
||||
'name' => Util::ucFirst(Lang::game('emotes'))
|
||||
);
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview($tabData, EmoteList::$brickFile, 'emote'));
|
||||
|
||||
parent::generate();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,129 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class EnchantmentsBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $type = Type::ENCHANTMENT;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
|
||||
protected string $template = 'enchantments';
|
||||
protected string $pageName = 'enchantments';
|
||||
protected ?int $activeTab = parent::TAB_DATABASE;
|
||||
protected array $breadcrumb = [0, 101];
|
||||
|
||||
protected array $scripts = [[SC_JS_FILE, 'js/filters.js']];
|
||||
protected array $expectedGET = array(
|
||||
'filter' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => Filter::PATTERN_PARAM]]
|
||||
);
|
||||
protected array $validCats = [1, 2, 3, 4, 5, 6, 7, 8];
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
$this->getCategoryFromUrl($pageParam);
|
||||
|
||||
parent::__construct($pageParam);
|
||||
|
||||
if ($this->category)
|
||||
$this->forward('?enchantments&filter=ty='.$this->category[0]);
|
||||
|
||||
$this->subCat = $pageParam !== '' ? '='.$pageParam : '';
|
||||
$this->filter = new EnchantmentListFilter($this->_get['filter'] ?? '', ['parentCats' => $this->category]);
|
||||
if ($this->filter->shouldReload)
|
||||
{
|
||||
$_SESSION['error']['fi'] = $this->filter::class;
|
||||
$get = $this->filter->buildGETParam();
|
||||
$this->forward('?' . $this->pageName . $this->subCat . ($get ? '&filter=' . $get : ''));
|
||||
}
|
||||
$this->filterError = $this->filter->error;
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->h1 = Util::ucFirst(Lang::game('enchantments'));
|
||||
|
||||
$conditions = [];
|
||||
if (!User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
$conditions[] = [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0];
|
||||
|
||||
if ($_ = $this->filter->getConditions())
|
||||
$conditions[] = $_;
|
||||
|
||||
|
||||
/**************/
|
||||
/* Page Title */
|
||||
/**************/
|
||||
|
||||
$fiForm = $this->filter->values;
|
||||
|
||||
array_unshift($this->title, $this->h1);
|
||||
if (isset($fiForm['ty']) && count($fiForm['ty']) == 1 && $fiForm['ty'][0] > ENCHANTMENT_TYPE_NONE && $fiForm['ty'][0] <= ENCHANTMENT_TYPE_PRISMATIC_SOCKET)
|
||||
array_unshift($this->title, Lang::enchantment('types', $fiForm['ty'][0]));
|
||||
|
||||
|
||||
/*************/
|
||||
/* Menu Path */
|
||||
/*************/
|
||||
|
||||
if (isset($fiForm['ty']) && count($fiForm['ty']) == 1)
|
||||
$this->breadcrumb[] = $fiForm['ty'][0];
|
||||
|
||||
|
||||
/****************/
|
||||
/* Main Content */
|
||||
/****************/
|
||||
|
||||
$this->redButtons[BUTTON_WOWHEAD] = false;
|
||||
|
||||
$tabData = array(
|
||||
'data' => [],
|
||||
'name' => Util::ucFirst(Lang::game('enchantments'))
|
||||
);
|
||||
|
||||
$ench = new EnchantmentList($conditions, ['calcTotal' => true]);
|
||||
|
||||
$tabData['data'] = $ench->getListviewData();
|
||||
$this->extendGlobalData($ench->getJSGlobals());
|
||||
|
||||
$xCols = [];
|
||||
foreach (Stat::getFilterCriteriumIdFor() as $idx => $fiId)
|
||||
if (array_filter(array_column($tabData['data'], Stat::getJsonString($idx))))
|
||||
$xCols[] = $fiId;
|
||||
|
||||
// some kind of declaration conflict going on here..., expects colId for WEAPON_DAMAGE_MAX but jsonString is WEAPON_DAMAGE
|
||||
if (array_filter(array_column($tabData['data'], 'dmg')))
|
||||
$xCols[] = Stat::getFilterCriteriumId(Stat::WEAPON_DAMAGE_MAX);
|
||||
|
||||
if ($xCols)
|
||||
$this->filter->fiExtraCols = array_merge($this->filter->fiExtraCols, $xCols);
|
||||
|
||||
if ($this->filter->fiExtraCols)
|
||||
$tabData['extraCols'] = '$fi_getExtraCols(fi_extraCols, 0, 0)';
|
||||
|
||||
if (array_filter(array_column($tabData['data'], 'spells')))
|
||||
$tabData['visibleCols'] = ['trigger'];
|
||||
|
||||
if (!$ench->hasSetFields('skillLine'))
|
||||
$tabData['hiddenCols'] = ['skill'];
|
||||
|
||||
if ($ench->getMatches() > Cfg::get('SQL_LIMIT_DEFAULT'))
|
||||
{
|
||||
$tabData['note'] = sprintf(Util::$tryFilteringString, 'LANG.lvnote_enchantmentsfound', $ench->getMatches(), Cfg::get('SQL_LIMIT_DEFAULT'));
|
||||
$tabData['_truncated'] = 1;
|
||||
}
|
||||
|
||||
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"]);
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview($tabData, EnchantmentList::$brickFile, 'enchantment'));
|
||||
|
||||
parent::generate();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,344 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class EventBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrDetailPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
|
||||
protected string $template = 'detail-page-generic';
|
||||
protected string $pageName = 'event';
|
||||
protected ?int $activeTab = parent::TAB_DATABASE;
|
||||
protected array $breadcrumb = [0, 11];
|
||||
|
||||
public int $type = Type::WORLDEVENT;
|
||||
public int $typeId = 0;
|
||||
public array $dates = [];
|
||||
|
||||
private WorldEventList $subject;
|
||||
|
||||
public function __construct(string $id)
|
||||
{
|
||||
parent::__construct($id);
|
||||
|
||||
$this->typeId = intVal($id);
|
||||
$this->contribute = Type::getClassAttrib($this->type, 'contribute') ?? CONTRIBUTE_NONE;
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->subject = new WorldEventList(array(['id', $this->typeId]));
|
||||
if ($this->subject->error)
|
||||
$this->generateNotFound(Lang::game('event'), Lang::event('notFound'));
|
||||
|
||||
$this->h1 = $this->subject->getField('name', true);
|
||||
$this->dates = array(
|
||||
'firstDate' => $this->subject->getField('startTime'),
|
||||
'lastDate' => $this->subject->getField('endTime'),
|
||||
'length' => $this->subject->getField('length'),
|
||||
'rec' => $this->subject->getField('occurence')
|
||||
);
|
||||
|
||||
$this->gPageInfo += array(
|
||||
'type' => $this->type,
|
||||
'typeId' => $this->typeId,
|
||||
'name' => $this->h1
|
||||
);
|
||||
|
||||
$_holidayId = $this->subject->getField('holidayId');
|
||||
|
||||
|
||||
/*************/
|
||||
/* Menu Path */
|
||||
/*************/
|
||||
|
||||
$this->breadcrumb[] = match ($this->subject->getField('scheduleType'))
|
||||
{
|
||||
-1 => 1,
|
||||
0, 1 => 2,
|
||||
2 => 3,
|
||||
'' => 0,
|
||||
default => 0
|
||||
};
|
||||
|
||||
|
||||
/**************/
|
||||
/* Page Title */
|
||||
/**************/
|
||||
|
||||
array_unshift($this->title, $this->h1, Util::ucWords(Lang::game('event')));
|
||||
|
||||
|
||||
/***********/
|
||||
/* Infobox */
|
||||
/***********/
|
||||
|
||||
$infobox = Lang::getInfoBoxForFlags($this->subject->getField('cuFlags'));
|
||||
|
||||
// boss
|
||||
if ($_ = $this->subject->getField('bossCreature'))
|
||||
{
|
||||
$this->extendGlobalIds(Type::NPC, $_);
|
||||
$infobox[] = Lang::npc('rank', 3).Lang::main('colon').'[npc='.$_.']';
|
||||
}
|
||||
|
||||
// id
|
||||
$infobox[] = Lang::event('id') . $this->typeId;
|
||||
|
||||
// display holiday id to staff
|
||||
if ($_holidayId && User::isInGroup(U_GROUP_STAFF))
|
||||
$infobox[] = 'Holiday ID'.Lang::main('colon').$_holidayId;
|
||||
|
||||
// original name
|
||||
if (Lang::getLocale() != Locale::EN)
|
||||
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
|
||||
|
||||
if ($infobox)
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
|
||||
|
||||
|
||||
/****************/
|
||||
/* Main Content */
|
||||
/****************/
|
||||
|
||||
// no entry in ?_articles? use default HolidayDescription
|
||||
if ($_holidayId && empty($this->article))
|
||||
$this->article = new Markup($this->subject->getField('description', true), ['dbpage' => true]);
|
||||
|
||||
if ($_holidayId)
|
||||
$this->wowheadLink = sprintf(WOWHEAD_LINK, Lang::getLocale()->domain(), 'event=', $_holidayId);
|
||||
|
||||
$this->headIcons = [$this->subject->getField('iconString')];
|
||||
$this->redButtons = array(
|
||||
BUTTON_WOWHEAD => $_holidayId > 0,
|
||||
BUTTON_LINKS => ['type' => $this->type, 'typeId' => $this->typeId]
|
||||
);
|
||||
|
||||
parent::generate();
|
||||
|
||||
|
||||
/**************/
|
||||
/* Extra Tabs */
|
||||
/**************/
|
||||
|
||||
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"], 'tabsRelated', true);
|
||||
|
||||
// tab: npcs
|
||||
if ($npcIds = DB::World()->selectCol('SELECT `id` AS ARRAY_KEY, IF(ec.`eventEntry` > 0, 1, 0) AS "added" FROM creature c, game_event_creature ec WHERE ec.`guid` = c.`guid` AND ABS(ec.`eventEntry`) = ?d', $this->typeId))
|
||||
{
|
||||
$creatures = new CreatureList(array(['id', array_keys($npcIds)]));
|
||||
if (!$creatures->error)
|
||||
{
|
||||
$data = $creatures->getListviewData();
|
||||
foreach ($data as &$d)
|
||||
$d['method'] = $npcIds[$d['id']];
|
||||
|
||||
$tabData = ['data' => $data];
|
||||
|
||||
if ($_holidayId && CreatureListFilter::getCriteriaIndex(38, $_holidayId))
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?npcs&filter=cr=38;crs='.$_holidayId.';crv=0');
|
||||
|
||||
$this->result->addDataLoader('zones'); // req. by secondary tooltip in this tab
|
||||
$this->lvTabs->addListviewTab(new Listview($tabData, CreatureList::$brickFile));
|
||||
}
|
||||
}
|
||||
|
||||
// tab: objects
|
||||
if ($objectIds = DB::World()->selectCol('SELECT `id` AS ARRAY_KEY, IF(eg.`eventEntry` > 0, 1, 0) AS "added" FROM gameobject g, game_event_gameobject eg WHERE eg.`guid` = g.`guid` AND ABS(eg.`eventEntry`) = ?d', $this->typeId))
|
||||
{
|
||||
$objects = new GameObjectList(array(['id', array_keys($objectIds)]));
|
||||
if (!$objects->error)
|
||||
{
|
||||
$data = $objects->getListviewData();
|
||||
foreach ($data as &$d)
|
||||
$d['method'] = $objectIds[$d['id']];
|
||||
|
||||
$tabData = ['data' => $data];
|
||||
|
||||
if ($_holidayId && GameObjectListFilter::getCriteriaIndex(16, $_holidayId))
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?objects&filter=cr=16;crs='.$_holidayId.';crv=0');
|
||||
|
||||
$this->result->addDataLoader('zones'); // req. by secondary tooltip in this tab
|
||||
$this->lvTabs->addListviewTab(new Listview($tabData, GameObjectList::$brickFile));
|
||||
}
|
||||
}
|
||||
|
||||
// tab: achievements
|
||||
if ($_ = $this->subject->getField('achievementCatOrId'))
|
||||
{
|
||||
$condition = $_ > 0 ? [['category', $_]] : [['id', -$_]];
|
||||
$acvs = new AchievementList($condition);
|
||||
if (!$acvs->error)
|
||||
{
|
||||
$this->extendGlobalData($acvs->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED));
|
||||
|
||||
$tabData = array(
|
||||
'data' => $acvs->getListviewData(),
|
||||
'visibleCols' => ['category']
|
||||
);
|
||||
|
||||
if ($_holidayId && AchievementListFilter::getCriteriaIndex(11, $_holidayId))
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?achievements&filter=cr=11;crs='.$_holidayId.';crv=0');
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview($tabData, AchievementList::$brickFile));
|
||||
}
|
||||
}
|
||||
|
||||
$itemCnd = [];
|
||||
if ($_holidayId)
|
||||
{
|
||||
$itemCnd = array(
|
||||
'OR',
|
||||
['eventId', $this->typeId], // direct requirement on item
|
||||
);
|
||||
|
||||
// tab: quests (by table, go & creature)
|
||||
$quests = new QuestList(array(['eventId', $this->typeId]));
|
||||
if (!$quests->error)
|
||||
{
|
||||
$this->extendGlobalData($quests->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_REWARDS));
|
||||
|
||||
$tabData = ['data'=> $quests->getListviewData()];
|
||||
|
||||
if (QuestListFilter::getCriteriaIndex(33, $_holidayId))
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?quests&filter=cr=33;crs='.$_holidayId.';crv=0');
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview($tabData, QuestList::$brickFile));
|
||||
|
||||
$questItems = [];
|
||||
foreach (array_column($quests->rewards, Type::ITEM) as $arr)
|
||||
$questItems = array_merge($questItems, array_keys($arr));
|
||||
|
||||
foreach (array_column($quests->choices, Type::ITEM) as $arr)
|
||||
$questItems = array_merge($questItems, array_keys($arr));
|
||||
|
||||
foreach (array_column($quests->requires, Type::ITEM) as $arr)
|
||||
$questItems = array_merge($questItems, $arr);
|
||||
|
||||
if ($questItems)
|
||||
$itemCnd[] = ['id', $questItems];
|
||||
}
|
||||
}
|
||||
|
||||
// items from creature
|
||||
if ($npcIds && !$creatures->error)
|
||||
{
|
||||
// vendor
|
||||
$cIds = $creatures->getFoundIDs();
|
||||
if ($sells = DB::World()->selectCol(
|
||||
'SELECT `item` FROM npc_vendor nv WHERE `entry` IN (?a) UNION
|
||||
SELECT nv1.`item` FROM npc_vendor nv1 JOIN npc_vendor nv2 ON -nv1.`entry` = nv2.`item` WHERE nv2.`entry` IN (?a) UNION
|
||||
SELECT `item` FROM game_event_npc_vendor genv JOIN creature c ON genv.`guid` = c.`guid` WHERE c.`id` IN (?a)',
|
||||
$cIds, $cIds, $cIds
|
||||
))
|
||||
$itemCnd[] = ['id', $sells];
|
||||
}
|
||||
|
||||
// tab: items
|
||||
// not checking for loot ... cant distinguish between eventLoot and fillerCrapLoot
|
||||
if ($itemCnd)
|
||||
{
|
||||
$eventItems = new ItemList($itemCnd);
|
||||
if (!$eventItems->error)
|
||||
{
|
||||
$this->extendGlobalData($eventItems->getJSGlobals(GLOBALINFO_SELF));
|
||||
|
||||
$tabData = ['data'=> $eventItems->getListviewData()];
|
||||
|
||||
if ($_holidayId && ItemListFilter::getCriteriaIndex(160, $_holidayId))
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?items&filter=cr=160;crs='.$_holidayId.';crv=0');
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview($tabData, ItemList::$brickFile));
|
||||
}
|
||||
}
|
||||
|
||||
// tab: see also (event conditions)
|
||||
if ($rel = DB::World()->selectCol('SELECT IF(`eventEntry` = `prerequisite_event`, NULL, IF(`eventEntry` = ?d, `prerequisite_event`, -`eventEntry`)) FROM game_event_prerequisite WHERE `prerequisite_event` = ?d OR `eventEntry` = ?d', $this->typeId, $this->typeId, $this->typeId))
|
||||
{
|
||||
if (array_filter($rel, fn($x) => $x === null))
|
||||
trigger_error('game_event_prerequisite: this event has itself as prerequisite', E_USER_WARNING);
|
||||
|
||||
if ($seeAlso = array_filter($rel, fn($x) => $x > 0))
|
||||
{
|
||||
$relEvents = new WorldEventList(array(['id', $seeAlso]));
|
||||
$this->extendGlobalData($relEvents->getJSGlobals());
|
||||
$relData = $relEvents->getListviewData();
|
||||
foreach ($relEvents->getFoundIDs() as $id)
|
||||
Conditions::extendListviewRow($relData[$id], Conditions::SRC_NONE, $this->typeId, [-Conditions::ACTIVE_EVENT, $this->typeId]);
|
||||
|
||||
$this->extendGlobalData($this->subject->getJSGlobals());
|
||||
$d = $this->subject->getListviewData();
|
||||
foreach ($rel as $r)
|
||||
if ($r > 0)
|
||||
if (Conditions::extendListviewRow($d[$this->typeId], Conditions::SRC_NONE, $this->typeId, [-Conditions::ACTIVE_EVENT, $r]))
|
||||
$this->extendGlobalIds(Type::WORLDEVENT, $r);
|
||||
|
||||
$tabData = array(
|
||||
'data' => array_merge($relData, $d),
|
||||
'id' => 'see-also',
|
||||
'name' => '$LANG.tab_seealso',
|
||||
'hiddenCols' => ['date'],
|
||||
'extraCols' => ['$Listview.extraCols.condition']
|
||||
);
|
||||
$this->lvTabs->addListviewTab(new Listview($tabData, WorldEventList::$brickFile));
|
||||
}
|
||||
}
|
||||
|
||||
// tab: condition for
|
||||
$cnd = new Conditions();
|
||||
$cnd->getByCondition(Type::WORLDEVENT, $this->typeId)->prepare();
|
||||
if ($tab = $cnd->toListviewTab('condition-for', '$LANG.tab_condition_for'))
|
||||
{
|
||||
$this->extendGlobalData($cnd->getJsGlobals());
|
||||
$this->lvTabs->addDataTab(...$tab);
|
||||
}
|
||||
|
||||
$this->result->registerDisplayHook('lvTabs', [self::class, 'tabsHook']);
|
||||
$this->result->registerDisplayHook('infobox', [self::class, 'infoboxHook']);
|
||||
}
|
||||
|
||||
// update dates to now()
|
||||
public static function tabsHook(Template\PageTemplate &$pt, Tabs &$lvTabs) : void
|
||||
{
|
||||
foreach ($lvTabs->iterate() as &$listview)
|
||||
if (is_object($listview) && $listview?->getTemplate() == 'holiday')
|
||||
WorldEventList::updateListview($listview);
|
||||
}
|
||||
|
||||
/* finalize infobox */
|
||||
public static function infoboxHook(Template\PageTemplate &$pt, ?InfoboxMarkup &$markup) : void
|
||||
{
|
||||
WorldEventList::updateDates($pt->dates, $start, $end, $rec);
|
||||
$infobox = [];
|
||||
|
||||
// start
|
||||
if ($start)
|
||||
$infobox[] = Lang::event('start').date(Lang::main('dateFmtLong'), $start);
|
||||
|
||||
// end
|
||||
if ($end)
|
||||
$infobox[] = Lang::event('end').date(Lang::main('dateFmtLong'), $end);
|
||||
|
||||
// interval
|
||||
if ($rec > 0)
|
||||
$infobox[] = Lang::event('interval').Util::formatTime($rec * 1000);
|
||||
|
||||
// in progress
|
||||
if ($start < time() && $end > time())
|
||||
$infobox[] = '[span class=q2]'.Lang::event('inProgress').'[/span]';
|
||||
|
||||
if ($infobox && !$markup)
|
||||
$markup = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
|
||||
else if ($markup)
|
||||
foreach ($infobox as $ib)
|
||||
$markup->addItem($ib);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,79 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class EventPowerResponse extends TextResponse implements ICache
|
||||
{
|
||||
use TrCache, TrTooltip;
|
||||
|
||||
private const /* string */ POWER_TEMPLATE = '$WowheadPower.registerHoliday(%d, %d, %s);';
|
||||
|
||||
protected int $type = Type::WORLDEVENT;
|
||||
protected int $typeId = 0;
|
||||
protected int $cacheType = CACHE_TYPE_TOOLTIP;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'domain' => ['filter' => FILTER_CALLBACK, 'options' => [Locale::class, 'tryFromDomain']]
|
||||
);
|
||||
|
||||
private array $dates = [];
|
||||
|
||||
public function __construct(string $id)
|
||||
{
|
||||
parent::__construct($id);
|
||||
|
||||
// temp locale
|
||||
if ($this->_get['domain'])
|
||||
Lang::load($this->_get['domain']);
|
||||
|
||||
$this->typeId = intVal($id);
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$worldevent = new WorldEventList(array(['id', $this->typeId]));
|
||||
if ($worldevent->error)
|
||||
$this->cacheType = CACHE_TYPE_NONE;
|
||||
else
|
||||
{
|
||||
$icon = $worldevent->getField('iconString');
|
||||
if ($icon == 'trade_engineering')
|
||||
$icon = null;
|
||||
|
||||
$opts = array(
|
||||
'name' => $worldevent->getField('name', true),
|
||||
'tooltip' => $worldevent->renderTooltip(),
|
||||
'icon' => $icon
|
||||
);
|
||||
|
||||
$this->dates = array(
|
||||
'firstDate' => $worldevent->getField('startTime'),
|
||||
'lastDate' => $worldevent->getField('endTime'),
|
||||
'length' => $worldevent->getField('length'),
|
||||
'rec' => $worldevent->getField('occurence')
|
||||
);
|
||||
|
||||
$this->setOnCacheLoaded([self::class, 'onBeforeDisplay'], $this->dates);
|
||||
}
|
||||
|
||||
$this->result = new Tooltip(self::POWER_TEMPLATE, $this->typeId, $opts ?? []);
|
||||
}
|
||||
|
||||
public static function onBeforeDisplay(string $tooltip, array $dates) : string
|
||||
{
|
||||
// update dates to now()
|
||||
WorldEventList::updateDates($dates, $start, $end);
|
||||
|
||||
return sprintf(
|
||||
$tooltip,
|
||||
$start ? date(Lang::main('dateFmtLong'), $start) : null,
|
||||
$end ? date(Lang::main('dateFmtLong'), $end) : null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,96 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class EventsBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $type = Type::WORLDEVENT;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
|
||||
protected string $template = 'list-page-generic';
|
||||
protected string $pageName = 'events';
|
||||
protected ?int $activeTab = parent::TAB_DATABASE;
|
||||
protected array $breadcrumb = [0, 11];
|
||||
|
||||
protected array $validCats = [0, 1, 2, 3];
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
$this->getCategoryFromUrl($pageParam);
|
||||
|
||||
parent::__construct($pageParam);
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->h1 = Util::ucWords(Lang::game('events'));
|
||||
|
||||
|
||||
/**************/
|
||||
/* Page Title */
|
||||
/**************/
|
||||
|
||||
array_unshift($this->title, $this->h1);
|
||||
if ($this->category)
|
||||
array_unshift($this->title, Lang::event('category')[$this->category[0]]);
|
||||
|
||||
|
||||
/*************/
|
||||
/* Menu Path */
|
||||
/*************/
|
||||
|
||||
if ($this->category)
|
||||
$this->breadcrumb[] = $this->category[0];
|
||||
|
||||
|
||||
/****************/
|
||||
/* Main Content */
|
||||
/****************/
|
||||
|
||||
$this->redButtons[BUTTON_WOWHEAD] = true;
|
||||
|
||||
$condition = [];
|
||||
|
||||
if (!User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
$condition[] = [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0];
|
||||
|
||||
if ($this->category)
|
||||
$condition[] = match ($this->category[0])
|
||||
{
|
||||
1 => ['h.scheduleType', -1],
|
||||
2 => ['h.scheduleType', [0, 1]],
|
||||
3 => ['h.scheduleType', 2],
|
||||
default => ['e.holidayId', 0] // also cat 0
|
||||
};
|
||||
|
||||
$events = new WorldEventList($condition);
|
||||
$this->extendGlobalData($events->getJSGlobals());
|
||||
|
||||
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"]);
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview(['data' => $events->getListviewData()], WorldEventList::$brickFile));
|
||||
|
||||
if ($_ = array_filter($events->getListviewData(), fn($x) => $x['category'] > 0))
|
||||
$this->lvTabs->addListviewTab(new Listview(['data' => $_, 'hideCount' => 1], 'calendar'));
|
||||
|
||||
parent::generate();
|
||||
|
||||
$this->result->registerDisplayHook('lvTabs', [self::class, 'tabsHook']);
|
||||
}
|
||||
|
||||
// recalculate dates with now()
|
||||
public static function tabsHook(Template\PageTemplate &$pt, Tabs &$lvTabs) : void
|
||||
{
|
||||
foreach ($lvTabs->iterate() as &$listview)
|
||||
if (is_object($listview) && ($listview?->getTemplate() == 'holiday' || $listview?->getTemplate() == 'holidaycal'))
|
||||
WorldEventList::updateListview($listview);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,361 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class FactionBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrDetailPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
|
||||
protected string $template = 'detail-page-generic';
|
||||
protected string $pageName = 'faction';
|
||||
protected ?int $activeTab = parent::TAB_DATABASE;
|
||||
protected array $breadcrumb = [0, 7];
|
||||
|
||||
public int $type = Type::FACTION;
|
||||
public int $typeId = 0;
|
||||
|
||||
private FactionList $subject;
|
||||
|
||||
public function __construct(string $id)
|
||||
{
|
||||
parent::__construct($id);
|
||||
|
||||
$this->typeId = intVal($id);
|
||||
$this->contribute = Type::getClassAttrib($this->type, 'contribute') ?? CONTRIBUTE_NONE;
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->subject = new FactionList(array(['id', $this->typeId]));
|
||||
if ($this->subject->error)
|
||||
$this->generateNotFound(Lang::game('faction'), Lang::faction('notFound'));
|
||||
|
||||
$this->h1 = $this->subject->getField('name', true);
|
||||
|
||||
$this->gPageInfo += array(
|
||||
'type' => $this->type,
|
||||
'typeId' => $this->typeId,
|
||||
'name' => $this->h1
|
||||
);
|
||||
|
||||
|
||||
/*************/
|
||||
/* Menu Path */
|
||||
/*************/
|
||||
|
||||
array_unshift($this->title, $this->h1, Util::ucFirst(Lang::game('faction')));
|
||||
|
||||
|
||||
/**************/
|
||||
/* Page Title */
|
||||
/**************/
|
||||
|
||||
if ($foo = $this->subject->getField('cat'))
|
||||
{
|
||||
if ($bar = $this->subject->getField('cat2'))
|
||||
$this->breadcrumb[] = $bar;
|
||||
|
||||
$this->breadcrumb[] = $foo;
|
||||
}
|
||||
|
||||
|
||||
/***********/
|
||||
/* Infobox */
|
||||
/***********/
|
||||
|
||||
$infobox = Lang::getInfoBoxForFlags($this->subject->getField('cuFlags'));
|
||||
|
||||
// Quartermaster if any
|
||||
if ($ids = $this->subject->getField('qmNpcIds'))
|
||||
{
|
||||
$this->extendGlobalIds(Type::NPC, ...$ids);
|
||||
|
||||
$qmStr = Lang::faction('quartermaster');
|
||||
|
||||
if (count($ids) == 1)
|
||||
$qmStr .= '[npc='.$ids[0].']';
|
||||
else if (count($ids) > 1)
|
||||
{
|
||||
$qmStr .= '[ul]';
|
||||
foreach ($ids as $id)
|
||||
$qmStr .= '[li][npc='.$id.'][/li]';
|
||||
|
||||
$qmStr .= '[/ul]';
|
||||
}
|
||||
|
||||
$infobox[] = $qmStr;
|
||||
}
|
||||
|
||||
// side if any
|
||||
if ($_ = $this->subject->getField('side'))
|
||||
$infobox[] = Lang::main('side').'[span class=icon-'.($_ == SIDE_ALLIANCE ? 'alliance' : 'horde').']'.Lang::game('si', $_).'[/span]';
|
||||
|
||||
// id
|
||||
$infobox[] = Lang::faction('id') . $this->typeId;
|
||||
|
||||
// profiler relateed (note that this is part of the cache. I don't think this is important enough to calc for every view)
|
||||
if (Cfg::get('PROFILER_ENABLE') && !($this->subject->getField('cuFlags') & CUSTOM_EXCLUDE_FOR_LISTVIEW))
|
||||
{
|
||||
$x = DB::Aowow()->selectCell('SELECT COUNT(1) FROM ?_profiler_completion_reputation WHERE `exalted` = 1 AND `factionId` = ?d', $this->typeId);
|
||||
$y = DB::Aowow()->selectCell('SELECT COUNT(1) FROM ?_profiler_profiles WHERE `custom` = 0 AND `stub` = 0');
|
||||
$infobox[] = Lang::profiler('attainedBy', [round(($x ?: 0) * 100 / ($y ?: 1))]);
|
||||
|
||||
// completion row added by InfoboxMarkup
|
||||
}
|
||||
|
||||
// original name
|
||||
if (Lang::getLocale() != Locale::EN)
|
||||
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
|
||||
|
||||
if ($infobox) // unsure if this should be tracked (needs data dump in User::getCompletion())
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0', 0);
|
||||
|
||||
|
||||
/****************/
|
||||
/* Main Content */
|
||||
/****************/
|
||||
|
||||
$this->redButtons = array(
|
||||
BUTTON_WOWHEAD => true,
|
||||
BUTTON_LINKS => ['type' => $this->type, 'typeId' => $this->typeId]
|
||||
);
|
||||
|
||||
// Spillover Effects
|
||||
/* todo (low): also check on reputation_spillover_template (but its data is identical to calculation below
|
||||
$rst = DB::World()->selectRow('SELECT
|
||||
CONCAT_WS(" ", faction1, faction2, faction3, faction4) AS faction,
|
||||
CONCAT_WS(" ", rate_1, rate_2, rate_3, rate_4) AS rate,
|
||||
CONCAT_WS(" ", rank_1, rank_2, rank_3, rank_4) AS rank
|
||||
FROM reputation_spillover_template WHERE faction = ?d', $this->typeId);
|
||||
*/
|
||||
|
||||
|
||||
$conditions = array(
|
||||
['id', $this->typeId, '!'], // not self
|
||||
['repIdx', -1, '!'] // only gainable
|
||||
);
|
||||
|
||||
if ($p = $this->subject->getField('parentFactionId')) // linked via parent
|
||||
$conditions[] = ['OR', ['id', $p], ['parentFactionId', $p]];
|
||||
else // self as parent
|
||||
$conditions[] = ['parentFactionId', $this->typeId];
|
||||
|
||||
$spillover = new FactionList($conditions);
|
||||
$this->extendGlobalData($spillover->getJSGlobals());
|
||||
|
||||
$buff = '';
|
||||
foreach ($spillover->iterate() as $spillId => $__)
|
||||
if ($val = ($spillover->getField('spilloverRateIn') * $this->subject->getField('spilloverRateOut') * 100))
|
||||
$buff .= '[tr][td][faction='.$spillId.'][/td][td][span class=q'.($val > 0 ? '2]+' : '10]').$val.'%[/span][/td][td]'.Lang::game('rep', $spillover->getField('spilloverMaxRank')).'[/td][/tr]';
|
||||
|
||||
if ($buff)
|
||||
$this->extraText = new Markup(
|
||||
'[h3 class=clear]'.Lang::faction('spillover').'[/h3][div margin=15px]'.Lang::faction('spilloverDesc').'[/div][table class=grid width=400px][tr][td width=150px][b]'.Util::ucFirst(Lang::game('faction')).'[/b][/td][td width=100px][b]'.Lang::spell('_value').'[/b][/td][td width=150px][b]'.Lang::faction('maxStanding').'[/b][/td][/tr]'.$buff.'[/table]',
|
||||
['dbpage' => true, 'allow' => Markup::CLASS_ADMIN],
|
||||
'text-generic'
|
||||
);
|
||||
|
||||
// reward rates (ultimately this should be calculated into each reward display)
|
||||
if ($rates = DB::World()->selectRow('SELECT `quest_rate`, `quest_daily_rate`, `quest_weekly_rate`, `quest_monthly_rate`, `quest_repeatable_rate`, `creature_rate`, `spell_rate` FROM reputation_reward_rate WHERE `faction` = ?d', $this->typeId))
|
||||
{
|
||||
$buff = '';
|
||||
foreach ($rates as $k => $v)
|
||||
{
|
||||
if ($v == 1)
|
||||
continue;
|
||||
|
||||
$head = match ($k)
|
||||
{
|
||||
'quest_rate' => Lang::game('quests'),
|
||||
'quest_daily_rate' => Lang::game('quests').' ('.Lang::quest('daily').')',
|
||||
'quest_weekly_rate' => Lang::game('quests').' ('.Lang::quest('weekly').')',
|
||||
'quest_monthly_rate' => Lang::game('quests').' ('.Lang::quest('monthly').')',
|
||||
'quest_repeatable_rate' => Lang::game('quests').' ('.Lang::quest('repeatable').')',
|
||||
'creature_rate' => Lang::game('npcs'),
|
||||
'spell_rate' => Lang::game('spells')
|
||||
};
|
||||
|
||||
$buff .= '[tr][td]'.$head.Lang::main('colon').'[/td][td width=35px align=right][span class=q'.($v < 1 ? '10]' : '2]+').intVal(($v - 1) * 100).'%[/span][/td][/tr]';
|
||||
}
|
||||
|
||||
if ($buff && $this->extraText)
|
||||
$this->extraText->append('[h3 class=clear]'.Lang::faction('customRewRate').'[/h3][table class=grid width=250px]'.$buff.'[/table]');
|
||||
else if ($buff)
|
||||
$this->extraText = new Markup('[h3 class=clear]'.Lang::faction('customRewRate').'[/h3][table class=grid width=250px]'.$buff.'[/table]', ['dbpage' => true, 'allow' => Markup::CLASS_ADMIN], 'text-generic');
|
||||
}
|
||||
|
||||
// factionchange-equivalent
|
||||
if ($pendant = DB::World()->selectCell('SELECT IF(`horde_id` = ?d, `alliance_id`, -`horde_id`) FROM player_factionchange_reputations WHERE `alliance_id` = ?d OR `horde_id` = ?d', $this->typeId, $this->typeId, $this->typeId))
|
||||
{
|
||||
$altFac = new FactionList(array(['id', abs($pendant)]));
|
||||
if (!$altFac->error)
|
||||
{
|
||||
$this->transfer = Lang::faction('_transfer', array(
|
||||
$altFac->id,
|
||||
$altFac->getField('name', true),
|
||||
$pendant > 0 ? 'alliance' : 'horde',
|
||||
$pendant > 0 ? Lang::game('si', SIDE_ALLIANCE) : Lang::game('si', SIDE_HORDE)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**************/
|
||||
/* Extra Tabs */
|
||||
/**************/
|
||||
|
||||
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"], 'tabsRelated', true);
|
||||
|
||||
// tab: items
|
||||
$items = new ItemList(array(['requiredFaction', $this->typeId]), ['calcTotal' => true]);
|
||||
if (!$items->error)
|
||||
{
|
||||
$this->extendGlobalData($items->getJSGlobals(GLOBALINFO_SELF));
|
||||
|
||||
$tabData = array(
|
||||
'data' => $items->getListviewData(),
|
||||
'extraCols' => '$_',
|
||||
'sort' => ['standing', 'name']
|
||||
);
|
||||
|
||||
if ($items->getMatches() > Cfg::get('SQL_LIMIT_DEFAULT'))
|
||||
if (!is_null(ItemListFilter::getCriteriaIndex(17, $this->typeId)))
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?items&filter=cr=17;crs='.$this->typeId.';crv=0');
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview($tabData, ItemList::$brickFile, 'itemStandingCol'));
|
||||
}
|
||||
|
||||
// tab: creatures with onKill reputation
|
||||
// only if you can actually gain reputation by kills
|
||||
if ($this->subject->getField('reputationIndex') != -1)
|
||||
{
|
||||
// inherit siblings/children from $spillover
|
||||
$cRep = DB::World()->selectCol('SELECT DISTINCT `creature_id` AS ARRAY_KEY, `qty` FROM (
|
||||
SELECT `creature_id`, `RewOnKillRepValue1` as "qty" FROM creature_onkill_reputation WHERE `RewOnKillRepValue1` > 0 AND (`RewOnKillRepFaction1` = ?d { OR (`RewOnKillRepFaction1` IN (?a) AND `IsTeamAward1` <> 0) } ) UNION
|
||||
SELECT `creature_id`, `RewOnKillRepValue2` as "qty" FROM creature_onkill_reputation WHERE `RewOnKillRepValue2` > 0 AND (`RewOnKillRepFaction2` = ?d { OR (`RewOnKillRepFaction2` IN (?a) AND `IsTeamAward2` <> 0) } )
|
||||
) x',
|
||||
$this->typeId, $spillover->getFoundIDs() ?: DBSIMPLE_SKIP,
|
||||
$this->typeId, $spillover->getFoundIDs() ?: DBSIMPLE_SKIP
|
||||
);
|
||||
|
||||
if ($cRep)
|
||||
{
|
||||
$killCreatures = new CreatureList(array(['id', array_keys($cRep)]), ['calcTotal' => true]);
|
||||
if (!$killCreatures->error)
|
||||
{
|
||||
$data = $killCreatures->getListviewData();
|
||||
foreach ($data as $id => &$d)
|
||||
$d['reputation'] = $cRep[$id];
|
||||
|
||||
$tabData = array(
|
||||
'data' => $data,
|
||||
'extraCols' => '$_',
|
||||
'sort' => ['-reputation', 'name']
|
||||
);
|
||||
|
||||
if ($killCreatures->getMatches() > Cfg::get('SQL_LIMIT_DEFAULT'))
|
||||
if (!is_null(CreatureListFilter::getCriteriaIndex(42, $this->typeId)))
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?npcs&filter=cr=42;crs='.$this->typeId.';crv=0');
|
||||
|
||||
$this->addDataLoader('zones');
|
||||
$this->lvTabs->addListviewTab(new Listview($tabData, CreatureList::$brickFile, 'npcRepCol'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// tab: members
|
||||
if ($_ = $this->subject->getField('templateIds'))
|
||||
{
|
||||
$members = new CreatureList(array(['faction', $_]), ['calcTotal' => true]);
|
||||
if (!$members->error)
|
||||
{
|
||||
$tabData = array(
|
||||
'data' => $members->getListviewData(),
|
||||
'id' => 'member',
|
||||
'name' => '$LANG.tab_members'
|
||||
);
|
||||
|
||||
if ($members->getMatches() > Cfg::get('SQL_LIMIT_DEFAULT'))
|
||||
if (!is_null(CreatureListFilter::getCriteriaIndex(3, $this->typeId)))
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?npcs&filter=cr=3;crs='.$this->typeId.';crv=0');
|
||||
|
||||
$this->addDataLoader('zones');
|
||||
$this->lvTabs->addListviewTab(new Listview($tabData, CreatureList::$brickFile));
|
||||
}
|
||||
}
|
||||
|
||||
// tab: objects
|
||||
if ($_ = $this->subject->getField('templateIds'))
|
||||
{
|
||||
$objects = new GameObjectList(array(['faction', $_]));
|
||||
if (!$objects->error)
|
||||
{
|
||||
$this->addDataLoader('zones');
|
||||
$this->lvTabs->addListviewTab(new Listview(['data' => $objects->getListviewData()], GameObjectList::$brickFile));
|
||||
}
|
||||
}
|
||||
|
||||
// tab: quests
|
||||
$conditions = array(
|
||||
['AND', ['rewardFactionId1', $this->typeId], ['rewardFactionValue1', 0, '>']],
|
||||
['AND', ['rewardFactionId2', $this->typeId], ['rewardFactionValue2', 0, '>']],
|
||||
['AND', ['rewardFactionId3', $this->typeId], ['rewardFactionValue3', 0, '>']],
|
||||
['AND', ['rewardFactionId4', $this->typeId], ['rewardFactionValue4', 0, '>']],
|
||||
['AND', ['rewardFactionId5', $this->typeId], ['rewardFactionValue5', 0, '>']],
|
||||
'OR'
|
||||
);
|
||||
$quests = new QuestList($conditions, ['calcTotal' => true]);
|
||||
if (!$quests->error)
|
||||
{
|
||||
$this->extendGlobalData($quests->getJSGlobals(GLOBALINFO_ANY));
|
||||
|
||||
$tabData = array(
|
||||
'data' => $quests->getListviewData($this->typeId),
|
||||
'extraCols' => '$_'
|
||||
);
|
||||
|
||||
if ($quests->getMatches() > Cfg::get('SQL_LIMIT_DEFAULT'))
|
||||
if (!is_null(QuestListFilter::getCriteriaIndex(1, $this->typeId)))
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?quests&filter=cr=1;crs='.$this->typeId.';crv=0');
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview($tabData, QuestList::$brickFile, 'questRepCol'));
|
||||
}
|
||||
|
||||
// tab: achievements
|
||||
$conditions = array(
|
||||
['ac.type', ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION],
|
||||
['ac.value1', $this->typeId]
|
||||
);
|
||||
$acvs = new AchievementList($conditions);
|
||||
if (!$acvs->error)
|
||||
{
|
||||
$this->extendGlobalData($acvs->getJSGlobals(GLOBALINFO_ANY));
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview(array(
|
||||
'data' => $acvs->getListviewData(),
|
||||
'id' => 'criteria-of',
|
||||
'name' => '$LANG.tab_criteriaof',
|
||||
'visibleCols' => ['category']
|
||||
), AchievementList::$brickFile));
|
||||
}
|
||||
|
||||
// tab: condition-for
|
||||
$cnd = new Conditions();
|
||||
$cnd->getByCondition(Type::FACTION, $this->typeId)->prepare();
|
||||
if ($tab = $cnd->toListviewTab('condition-for', '$LANG.tab_condition_for'))
|
||||
{
|
||||
$this->extendGlobalData($cnd->getJsGlobals());
|
||||
$this->lvTabs->addDataTab(...$tab);
|
||||
}
|
||||
|
||||
parent::generate();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user