Template/Update (Part 41)
* split 'profiler' into separate endpoints * implement profile=avatar endpoint (though it doesn't do a whole lot and isn't referenced (see comments))
This commit is contained in:
parent
fef27c58e6
commit
69df20af63
30 changed files with 1703 additions and 1336 deletions
68
endpoints/profile/avatar.php
Normal file
68
endpoints/profile/avatar.php
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* waybackmachine has 50ish /profile=avatar calls archived and they 302 to STATIC_URL/images/armory/medium/default_orc_female.jpg etc.
|
||||
*
|
||||
* at the time the blizzard armory also had rendered portraits of characters
|
||||
* HOST_URL/profile=avatar&size=medium&id=77047584.jpg redirects to
|
||||
* STATIC_URL/images/armory/medium/077/047/584.jpg (yes, the profileId is always split like that)
|
||||
*
|
||||
* this came probably after the tiered default icons that we are currently using
|
||||
* since we can't generate custom avatars, references to g_getProfileIcon have been edited.
|
||||
*/
|
||||
|
||||
class ProfileAvatarResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => '/^\d+\.jpg$/'] ],
|
||||
'size' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine']]
|
||||
);
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
parent::__construct($pageParam);
|
||||
|
||||
if (!Cfg::get('PROFILER_ENABLE'))
|
||||
$this->generate404();
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId>
|
||||
size: <string> [optional]
|
||||
return:
|
||||
<redirect>
|
||||
*/
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('id'))
|
||||
$this->generate404();
|
||||
|
||||
$profileId = substr($this->_get['id'], 0, -4);
|
||||
|
||||
$charData = DB::Aowow()->selectRow('SELECT `race`, `gender` FROM ?_profiler_profiles WHERE id = ?d', $profileId);
|
||||
if (!$charData)
|
||||
$this->generate404();
|
||||
|
||||
$gender = $charData['gender'] ? 'female' : 'male';
|
||||
$race = ChrRace::tryFrom($charData['race'])?->json() ?? 'human';
|
||||
$size = match($this->_get['size'])
|
||||
{
|
||||
'small',
|
||||
'medium',
|
||||
'large' => $this->_get['size'],
|
||||
default => 'medium'
|
||||
};
|
||||
|
||||
$this->redirectTo = sprintf('%s/images/armory/%s/default_%s_%s.jpg', Cfg::get('STATIC_URL'), $size, $race, $gender);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
49
endpoints/profile/delete.php
Normal file
49
endpoints/profile/delete.php
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class ProfileDeleteResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
return
|
||||
null
|
||||
*/
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('id'))
|
||||
{
|
||||
trigger_error('ProfileDeleteResponse - profileId empty', E_USER_WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
// only flag as deleted; only custom profiles
|
||||
DB::Aowow()->query(
|
||||
'UPDATE ?_profiler_profiles SET `cuFlags` = `cuFlags` | ?d WHERE `id` IN (?a) AND `cuFlags` & ?d {AND `user` = ?d}',
|
||||
PROFILER_CU_DELETED,
|
||||
$this->_get['id'],
|
||||
PROFILER_CU_PROFILE,
|
||||
User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU) ? DBSIMPLE_SKIP : User::$id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
50
endpoints/profile/link.php
Normal file
50
endpoints/profile/link.php
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class ProfileLinkResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT]
|
||||
);
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
parent::__construct($pageParam);
|
||||
|
||||
if (!Cfg::get('PROFILER_ENABLE'))
|
||||
$this->generate404();
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
return:
|
||||
null
|
||||
*/
|
||||
protected function generate() : void // links char with account
|
||||
{
|
||||
if (!$this->assertGET('id'))
|
||||
{
|
||||
trigger_error('ProfileLinkResponse - profileId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// only link characters, not custom profiles
|
||||
$newId = DB::Aowow()->query(
|
||||
'REPLACE INTO ?_account_profiles (`accountId`, `profileId`, `extraFlags`)
|
||||
SELECT ?d, p.`id`, 0 FROM ?_profiler_profiles p WHERE p.`id` = ?d AND (`cuFlags` & ?d) = 0',
|
||||
User::$id, $this->_get['id'], PROFILER_CU_PROFILE
|
||||
);
|
||||
|
||||
if (!is_int($newId))
|
||||
trigger_error('ProfileLinkResponse - some of the profileIds were custom or do not exist', E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
302
endpoints/profile/load.php
Normal file
302
endpoints/profile/load.php
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class ProfileLoadResponse extends TextResponse
|
||||
{
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdList'] ],
|
||||
'items' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkItemList']]
|
||||
);
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
parent::__construct($pageParam);
|
||||
|
||||
if (!Cfg::get('PROFILER_ENABLE'))
|
||||
$this->generate404();
|
||||
}
|
||||
|
||||
/* params
|
||||
id: profileId
|
||||
items: string [itemIds.join(':')]
|
||||
unnamed: unixtime [only to force the browser to reload instead of cache]
|
||||
return
|
||||
lots...
|
||||
*/
|
||||
protected function generate() : void
|
||||
{
|
||||
// titles, achievements, characterData, talents, pets
|
||||
// and some onLoad-hook to .. load it registerProfile($data)
|
||||
// everything else goes through data.php .. strangely enough
|
||||
|
||||
if (!$this->assertGET('id'))
|
||||
{
|
||||
trigger_error('ProfileLoadResponse - profileId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$pBase = DB::Aowow()->selectRow('SELECT pg.`name` AS "guildname", p.* FROM ?_profiler_profiles p LEFT JOIN ?_profiler_guild pg ON pg.`id` = p.`guild` WHERE p.`id` = ?d', $this->_get['id'][0]);
|
||||
if (!$pBase)
|
||||
{
|
||||
trigger_error('ProfileLoadResponse - called with invalid profileId #'.$this->_get['id'][0], E_USER_WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
if (($pBase['cuFlags'] & PROFILER_CU_DELETED) && !User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
return;
|
||||
|
||||
|
||||
$rData = [];
|
||||
foreach (Profiler::getRealms() as $rId => $rData)
|
||||
if ($rId == $pBase['realm'])
|
||||
break;
|
||||
|
||||
if (!$rData) // realm doesn't exist or access is restricted
|
||||
return;
|
||||
|
||||
$profile = array(
|
||||
'id' => $pBase['id'],
|
||||
'source' => $pBase['id'],
|
||||
'level' => $pBase['level'],
|
||||
'classs' => $pBase['class'],
|
||||
'race' => $pBase['race'],
|
||||
'faction' => ChrRace::tryFrom($pBase['race'])?->getTeam() ?? TEAM_NEUTRAL,
|
||||
'gender' => $pBase['gender'],
|
||||
'skincolor' => $pBase['skincolor'],
|
||||
'hairstyle' => $pBase['hairstyle'],
|
||||
'haircolor' => $pBase['haircolor'],
|
||||
'facetype' => $pBase['facetype'],
|
||||
'features' => $pBase['features'],
|
||||
'title' => $pBase['title'],
|
||||
'name' => $pBase['name'],
|
||||
'guild' => "$'".$pBase['guildname']."'",
|
||||
'published' => !!($pBase['cuFlags'] & PROFILER_CU_PUBLISHED),
|
||||
'pinned' => !!($pBase['cuFlags'] & PROFILER_CU_PINNED),
|
||||
'nomodel' => $pBase['nomodelMask'],
|
||||
'playedtime' => $pBase['playedtime'],
|
||||
'lastupdated' => $pBase['lastupdated'] * 1000,
|
||||
'talents' => array(
|
||||
'builds' => array( // notice the bullshit to prevent the talent-string from becoming a float! NOTICE IT!!
|
||||
['talents' => '$"'.$pBase['talentbuild1'].'"', 'glyphs' => $pBase['glyphs1']],
|
||||
['talents' => '$"'.$pBase['talentbuild2'].'"', 'glyphs' => $pBase['glyphs2']]
|
||||
),
|
||||
'active' => $pBase['activespec']
|
||||
),
|
||||
// set later
|
||||
'inventory' => [],
|
||||
'bookmarks' => [], // list of userIds who claimed this profile (claiming and owning are two different things)
|
||||
|
||||
// completion lists: [subjectId => amount/timestamp/1]
|
||||
'skills' => [], // skillId => [curVal, maxVal]
|
||||
'reputation' => [], // factionId => curVal
|
||||
'titles' => [], // titleId => 1
|
||||
'spells' => [], // spellId => 1; recipes, vanity pets, mounts
|
||||
'achievements' => [], // achievementId => timestamp
|
||||
'quests' => [], // questId => 1
|
||||
'achievementpoints' => 0, // max you have
|
||||
'statistics' => [], // all raid activity [achievementId => killCount]
|
||||
'activity' => [], // recent raid activity [achievementId => 1] (is a subset of statistics)
|
||||
);
|
||||
|
||||
if ($pBase['cuFlags'] & PROFILER_CU_PROFILE)
|
||||
{
|
||||
// this parameter is _really_ strange .. probably still not doing this right
|
||||
$profile['source'] = $pBase['realm'] ? $pBase['sourceId'] : 0;
|
||||
|
||||
$profile['sourcename'] = $pBase['sourceName'];
|
||||
$profile['description'] = $pBase['description'];
|
||||
$profile['user'] = $pBase['user'];
|
||||
$profile['username'] = DB::Aowow()->selectCell('SELECT `username` FROM ?_account WHERE `id` = ?d', $pBase['user']);
|
||||
}
|
||||
|
||||
// custom profiles inherit this when copied from real char :(
|
||||
if ($pBase['realm'])
|
||||
{
|
||||
$profile['region'] = [$rData['region'], Lang::profiler('regions', $rData['region'])];
|
||||
$profile['battlegroup'] = [Profiler::urlize(Cfg::get('BATTLEGROUP')), Cfg::get('BATTLEGROUP')];
|
||||
$profile['realm'] = [Profiler::urlize($rData['name'], true), $rData['name']];
|
||||
}
|
||||
|
||||
// bookmarks
|
||||
if ($_ = DB::Aowow()->selectCol('SELECT `accountId` FROM ?_account_profiles WHERE `profileId` = ?d', $pBase['id']))
|
||||
$profile['bookmarks'] = $_;
|
||||
|
||||
// arena teams - [size(2|3|5) => name]; name gets urlized to use as link
|
||||
if ($at = DB::Aowow()->selectCol('SELECT `type` AS ARRAY_KEY, `name` FROM ?_profiler_arena_team at JOIN ?_profiler_arena_team_member atm ON atm.`arenaTeamId` = at.`id` WHERE atm.`profileId` = ?d', $pBase['id']))
|
||||
$profile['arenateams'] = $at;
|
||||
|
||||
// pets if hunter fields: [name:name, family:petFamily, npc:npcId, displayId:modelId, talents:talentString]
|
||||
if ($pets = DB::Aowow()->select('SELECT `name`, `family`, `npc`, `displayId`, CONCAT("$\"", `talents`, "\"") AS "talents" FROM ?_profiler_pets WHERE `owner` = ?d', $pBase['id']))
|
||||
$profile['pets'] = $pets;
|
||||
|
||||
// source for custom profiles; profileId => [name, ownerId, iconString(optional)]
|
||||
if ($customs = DB::Aowow()->select('SELECT `id` AS ARRAY_KEY, `name`, `user`, `icon` FROM ?_profiler_profiles WHERE `sourceId` = ?d AND `sourceId` <> `id` {AND (`cuFlags` & ?d) = 0}', $pBase['id'], User::isInGroup(U_GROUP_STAFF) ? DBSIMPLE_SKIP : PROFILER_CU_DELETED))
|
||||
{
|
||||
foreach ($customs as $id => $cu)
|
||||
{
|
||||
if (!$cu['icon'])
|
||||
unset($cu['icon']);
|
||||
|
||||
$profile['customs'][$id] = array_values($cu);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* $profile[]
|
||||
// CUSTOM
|
||||
'auras' => [], // custom list of buffs, debuffs [spellId]
|
||||
|
||||
// UNUSED
|
||||
'glyphs' => [], // provided list of already known glyphs (post cataclysm feature)
|
||||
*/
|
||||
|
||||
|
||||
// questId => [cat1, cat2]
|
||||
$profile['quests'] = [];
|
||||
if ($quests = DB::Aowow()->selectCol('SELECT `questId` FROM ?_profiler_completion_quests WHERE `id` = ?d', $pBase['id']))
|
||||
{
|
||||
$qList = new QuestList(array(['id', $quests], Cfg::get('SQL_LIMIT_NONE')));
|
||||
if (!$qList->error)
|
||||
foreach ($qList->iterate() as $id => $__)
|
||||
$profile['quests'][$id] = [$qList->getField('cat1'), $qList->getField('cat2')];
|
||||
}
|
||||
|
||||
// skillId => [value, max]
|
||||
$profile['skills'] = DB::Aowow()->select('SELECT `skillId` AS ARRAY_KEY, `value` AS "0", `max` AS "1" FROM ?_profiler_completion_skills WHERE `id` = ?d', $pBase['id']);
|
||||
|
||||
// factionId => amount
|
||||
$profile['reputation'] = DB::Aowow()->selectCol('SELECT `factionId` AS ARRAY_KEY, `standing` FROM ?_profiler_completion_reputation WHERE `id` = ?d', $pBase['id']);
|
||||
|
||||
// titleId => 1
|
||||
$profile['titles'] = DB::Aowow()->selectCol('SELECT `titleId` AS ARRAY_KEY, 1 FROM ?_profiler_completion_titles WHERE `id` = ?d', $pBase['id']);
|
||||
|
||||
// achievementId => js date object
|
||||
$profile['achievements'] = DB::Aowow()->selectCol('SELECT `achievementId` AS ARRAY_KEY, CONCAT("$new Date(", `date` * 1000, ")") FROM ?_profiler_completion_achievements WHERE `id` = ?d', $pBase['id']);
|
||||
|
||||
// just points
|
||||
$profile['achievementpoints'] = $profile['achievements'] ? DB::Aowow()->selectCell('SELECT SUM(`points`) FROM ?_achievement WHERE `id` IN (?a)', array_keys($profile['achievements'])) : 0;
|
||||
|
||||
// achievementId => counter
|
||||
$profile['statistics'] = DB::Aowow()->selectCol('SELECT `achievementId` AS ARRAY_KEY, `counter` FROM ?_profiler_completion_statistics WHERE `id` = ?d', $pBase['id']);
|
||||
|
||||
// achievementId => 1
|
||||
$profile['activity'] = DB::Aowow()->selectCol('SELECT `achievementId` AS ARRAY_KEY, 1 FROM ?_profiler_completion_statistics WHERE `id` = ?d AND `date` > ?d', $pBase['id'], time() - MONTH);
|
||||
|
||||
// spellId => 1
|
||||
$profile['spells'] = DB::Aowow()->selectCol('SELECT `spellId` AS ARRAY_KEY, 1 FROM ?_profiler_completion_spells WHERE `id` = ?d', $pBase['id']);
|
||||
|
||||
|
||||
$gItems = [];
|
||||
|
||||
$usedSlots = [];
|
||||
if ($this->_get['items'])
|
||||
{
|
||||
$phItems = new ItemList(array(['id', $this->_get['items']], ['slot', INVTYPE_NON_EQUIP, '!']));
|
||||
if (!$phItems->error)
|
||||
{
|
||||
$data = $phItems->getListviewData(ITEMINFO_JSON | ITEMINFO_SUBITEMS);
|
||||
foreach ($phItems->iterate() as $iId => $__)
|
||||
{
|
||||
$sl = $phItems->getField('slot');
|
||||
foreach (Profiler::$slot2InvType as $slot => $invTypes)
|
||||
{
|
||||
if (in_array($sl, $invTypes) && !in_array($slot, $usedSlots))
|
||||
{
|
||||
// get and apply inventory
|
||||
$gItems[$iId] = array(
|
||||
'name_'.Lang::getLocale()->json() => $phItems->getField('name', true),
|
||||
'quality' => $phItems->getField('quality'),
|
||||
'icon' => $phItems->getField('iconString'),
|
||||
'jsonequip' => $data[$iId]
|
||||
);
|
||||
$profile['inventory'][$slot] = [$iId, 0, 0, 0, 0, 0, 0, 0];
|
||||
|
||||
$usedSlots[] = $slot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($items = DB::Aowow()->select('SELECT * FROM ?_profiler_items WHERE `id` = ?d', $pBase['id']))
|
||||
{
|
||||
$itemz = new ItemList(array(['id', array_column($items, 'item')], Cfg::get('SQL_LIMIT_NONE')));
|
||||
if (!$itemz->error)
|
||||
{
|
||||
$data = $itemz->getListviewData(ITEMINFO_JSON | ITEMINFO_SUBITEMS);
|
||||
|
||||
foreach ($items as $i)
|
||||
{
|
||||
if ($itemz->getEntry($i['item']) && !in_array($i['slot'], $usedSlots))
|
||||
{
|
||||
// get and apply inventory
|
||||
$gItems[$i['item']] = array(
|
||||
'name_'.Lang::getLocale()->json() => $itemz->getField('name', true),
|
||||
'quality' => $itemz->getField('quality'),
|
||||
'icon' => $itemz->getField('iconString'),
|
||||
'jsonequip' => $data[$i['item']]
|
||||
);
|
||||
$profile['inventory'][$i['slot']] = [$i['item'], $i['subItem'], $i['permEnchant'], $i['tempEnchant'], $i['gem1'], $i['gem2'], $i['gem3'], $i['gem4']];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$buff = '';
|
||||
foreach ($gItems as $id => $item)
|
||||
$buff .= 'g_items.add('.$id.', '.Util::toJSON($item, JSON_NUMERIC_CHECK | JSON_UNESCAPED_UNICODE).");\n";
|
||||
|
||||
|
||||
// if ($au = $char->getField('auras'))
|
||||
// {
|
||||
// $auraz = new SpellList(array(['id', $char->getField('auras')], Cfg::get('SQL_LIMIT_NONE')));
|
||||
// $dataz = $auraz->getListviewData();
|
||||
// $modz = $auraz->getProfilerMods();
|
||||
|
||||
// // get and apply aura-mods
|
||||
// foreach ($dataz as $id => $data)
|
||||
// {
|
||||
// $mods = [];
|
||||
// if (!empty($modz[$id]))
|
||||
// {
|
||||
// foreach ($modz[$id] as $k => $v)
|
||||
// {
|
||||
// if (is_array($v))
|
||||
// $mods[] = $v;
|
||||
// else if ($str = @Game::$itemMods[$k])
|
||||
// $mods[$str] = $v;
|
||||
// }
|
||||
// }
|
||||
|
||||
// $buff .= 'g_spells.add('.$id.", {id:".$id.", name:'".Util::jsEscape(mb_substr($data['name'], 1))."', icon:'".$data['icon']."', callback:".Util::toJSON($mods)."});\n";
|
||||
// }
|
||||
// $buff .= "\n";
|
||||
// }
|
||||
|
||||
|
||||
// load available titles
|
||||
Util::loadStaticFile('p-titles-'.$pBase['gender'], $buff, true);
|
||||
|
||||
// add profile to buffer
|
||||
$buff .= "\n\n\$WowheadProfiler.registerProfile(".Util::toJSON($profile).");";
|
||||
|
||||
$this->result = $buff."\n";
|
||||
}
|
||||
|
||||
protected static function checkItemList(string $val) : array
|
||||
{
|
||||
// expecting item-list
|
||||
if (preg_match('/\d+(:\d+)*/', $val))
|
||||
return array_map('intVal', explode(':', $val));
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
58
endpoints/profile/pin.php
Normal file
58
endpoints/profile/pin.php
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class ProfilePinResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdList'] ],
|
||||
'user' => ['filter' => FILTER_CALLBACK, 'options' => [Util::class, 'validateUsername']]
|
||||
);
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
parent::__construct($pageParam);
|
||||
|
||||
if (!Cfg::get('PROFILER_ENABLE'))
|
||||
$this->generate404();
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
user: <string> [optional]
|
||||
return: null
|
||||
*/
|
||||
protected function generate() : void // (un)favorite
|
||||
{
|
||||
if (!$this->assertGET('id'))
|
||||
{
|
||||
trigger_error('ProfilePinResponse - profileId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$uid = 0;
|
||||
if (!$this->_get['user'] || User::$username == $this->_get['user'])
|
||||
$uid = User::$id;
|
||||
else if ($this->_get['user'] && User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
$uid = DB::Aowow()->selectCell('SELECT `id` FROM ?_account WHERE LOWER(`username`) = LOWER(?)', $this->_get['user']);
|
||||
|
||||
if (!$uid)
|
||||
{
|
||||
trigger_error('ProfilePinResponse - user "'.$this->_get['user'].'" does not exist', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// since only one character can be pinned at a time we can reset everything
|
||||
DB::Aowow()->query('UPDATE ?_account_profiles SET `extraFlags` = `extraFlags` & ~?d WHERE `accountId` = ?d', PROFILER_CU_PINNED, $uid);
|
||||
// and set a single char if necessary (Replace, because this entry may not exist yet)
|
||||
DB::Aowow()->query('REPLACE INTO ?_account_profiles (`accountId`, `profileId`, `extraFlags`) VALUES (?d, ?d, ?d)', $uid, $this->_get['id'][0], PROFILER_CU_PINNED);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
64
endpoints/profile/private.php
Normal file
64
endpoints/profile/private.php
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class ProfilePrivateResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdList'] ],
|
||||
'user' => ['filter' => FILTER_CALLBACK, 'options' => [Util::class, 'validateUsername']],
|
||||
// 'bookmarked' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkEmptySet'] ] // something with signatures? (must have bookmarked profile to create signature from)
|
||||
);
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
parent::__construct($pageParam);
|
||||
|
||||
if (!Cfg::get('PROFILER_ENABLE'))
|
||||
$this->generate404();
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
user: <string> [optional] // user page this is may be executed from
|
||||
return:
|
||||
null
|
||||
*/
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('id'))
|
||||
{
|
||||
trigger_error('ProfilePrivateResponse - profileId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->_get['user'] && User::$username != $this->_get['user'] && !User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
{
|
||||
trigger_error('ProfilePrivateResponse - user #'.User::$id.' tried to mark profiles of "'.$this->_get['user'].'" as private.', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$uid = 0;
|
||||
if (!$this->_get['user'] || User::$username == $this->_get['user'])
|
||||
$uid = User::$id;
|
||||
else if ($this->_get['user'] && User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
$uid = DB::Aowow()->selectCell('SELECT `id` FROM ?_account WHERE LOWER(`username`) = LOWER(?)', $this->_get['user']);
|
||||
|
||||
if (!$uid)
|
||||
{
|
||||
trigger_error('ProfilePrivateResponse - user "'.$this->_get['user'].'" does not exist', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_account_profiles SET `extraFlags` = `extraFlags` & ~?d WHERE `profileId` IN (?a) AND `accountId` = ?d', PROFILER_CU_PUBLISHED, $this->_get['id'], $uid);
|
||||
DB::Aowow()->query('UPDATE ?_profiler_profiles SET `cuFlags` = `cuFlags` & ~?d WHERE `id` IN (?a) AND `user` = ?d', PROFILER_CU_PUBLISHED, $this->_get['id'], $uid);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
184
endpoints/profile/profile.php
Normal file
184
endpoints/profile/profile.php
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class ProfileBaseResponse extends TemplateResponse
|
||||
{
|
||||
use TrProfilerDetail;
|
||||
|
||||
protected string $template = 'profile';
|
||||
protected string $pageName = 'profile';
|
||||
protected ?int $activeTab = parent::TAB_TOOLS;
|
||||
protected array $breadcrumb = [1, 5, 1]; // Tools > Profiler > New
|
||||
|
||||
protected array $dataLoader = ['enchants', 'gems', 'glyphs', 'itemsets', 'pets', 'pet-talents', 'quick-excludes', 'realms', 'statistics', 'weight-presets', 'achievements'];
|
||||
protected array $scripts = array(
|
||||
[SC_JS_FILE, 'js/filters.js'],
|
||||
[SC_JS_FILE, 'js/TalentCalc.js'],
|
||||
[SC_JS_FILE, 'js/swfobject.js'],
|
||||
[SC_JS_FILE, 'js/profile_all.js'],
|
||||
[SC_JS_FILE, 'js/profile.js'],
|
||||
[SC_JS_FILE, 'js/Profiler.js'],
|
||||
[SC_CSS_FILE, 'css/talentcalc.css'],
|
||||
[SC_CSS_FILE, 'css/Profiler.css']
|
||||
);
|
||||
protected array $expectedGET = array(
|
||||
'new' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkEmptySet']]
|
||||
);
|
||||
|
||||
public int $type = Type::PROFILE;
|
||||
public bool $gDataKey = true;
|
||||
|
||||
public function __construct(string $idOrProfile)
|
||||
{
|
||||
parent::__construct($idOrProfile);
|
||||
|
||||
if (!Cfg::get('PROFILER_ENABLE'))
|
||||
$this->generateError();
|
||||
|
||||
// neither param nor &new > error
|
||||
if (!$idOrProfile && !$this->_get['new'])
|
||||
$this->generateError();
|
||||
|
||||
// display empty/new profile editor > ok
|
||||
if (!$idOrProfile && $this->_get['new'])
|
||||
return;
|
||||
|
||||
$this->getSubjectFromUrl($idOrProfile);
|
||||
|
||||
// we have an ID > ok
|
||||
if ($this->typeId)
|
||||
return;
|
||||
|
||||
// param was incomplete profile > error
|
||||
if (!$this->subjectName)
|
||||
$this->notFound();
|
||||
|
||||
$rnItr = 0;
|
||||
// pending rename
|
||||
if (preg_match('/^([^\-]+)-(\d+)$/i', $this->subjectName, $m))
|
||||
{
|
||||
$this->subjectName = $m[1];
|
||||
$rnItr = $m[2];
|
||||
}
|
||||
|
||||
// 3 possibilities
|
||||
// 1) already synced to aowow
|
||||
if ($subject = DB::Aowow()->selectRow('SELECT `id`, `realmGUID`, `cuFlags` FROM ?_profiler_profiles WHERE `realm` = ?d AND `realmGUID` IS NOT NULL AND `name` = ? AND `renameItr` = ?d', $this->realmId, Util::ucFirst($this->subjectName), $rnItr))
|
||||
{
|
||||
$this->typeId = $subject['id'];
|
||||
|
||||
if ($subject['cuFlags'] & PROFILER_CU_NEEDS_RESYNC)
|
||||
$this->handleIncompleteData(Type::PROFILE, $subject['realmGUID']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// can not be used to look up char on realm
|
||||
if ($rnItr)
|
||||
$this->notFound();
|
||||
|
||||
// 2) not yet synced but exists on realm (and not a gm character)
|
||||
if ($subject = DB::Characters($this->realmId)->selectRow(
|
||||
'SELECT c.`guid` AS "realmGUID", c.`name`, c.`race`, c.`class`, c.`level`, c.`gender`, c.`at_login`, g.`guildid` AS "guildGUID", IFNULL(g.`name`, "") AS "guildName", IFNULL(gm.`rank`, 0) AS "guildRank"
|
||||
FROM characters c
|
||||
LEFT JOIN guild_member gm ON gm.`guid` = c.`guid`
|
||||
LEFT JOIN guild g ON g.`guildid` = gm.`guildid`
|
||||
WHERE c.`name` = ? AND `level` <= ?d AND (`extra_flags` & ?d) = 0',
|
||||
Util::ucFirst($this->subjectName), MAX_LEVEL, Profiler::CHAR_GMFLAGS
|
||||
))
|
||||
{
|
||||
$subject['realm'] = $this->realmId;
|
||||
$subject['cuFlags'] = PROFILER_CU_NEEDS_RESYNC;
|
||||
|
||||
if ($subject['at_login'] & 0x1)
|
||||
$subject['renameItr'] = DB::Aowow()->selectCell('SELECT MAX(`renameItr`) FROM ?_profiler_profiles WHERE `realm` = ?d AND `realmGUID` IS NOT NULL AND `name` = ?', $this->realmId, $subject['name']);
|
||||
|
||||
if ($subject['guildGUID'])
|
||||
{
|
||||
// create empty guild if nessecary to satisfy foreign keys
|
||||
$subject['guild'] = DB::Aowow()->selectCell('SELECT `id` FROM ?_profiler_guild WHERE `realm` = ?d AND `realmGUID` = ?d', $this->realmId, $subject['guildGUID']);
|
||||
if (!$subject['guild'])
|
||||
$subject['guild'] = DB::Aowow()->query('INSERT INTO ?_profiler_guild (`realm`, `realmGUID`, `cuFlags`, `name`) VALUES (?d, ?d, ?d, ?)', $this->realmId, $subject['guildGUID'], PROFILER_CU_NEEDS_RESYNC, $subject['guildName']);
|
||||
}
|
||||
|
||||
unset($subject['guildGUID'], $subject['guildName'], $subject['at_login']);
|
||||
|
||||
// create entry from realm with enough basic info to disply tooltips
|
||||
DB::Aowow()->query('REPLACE INTO ?_profiler_profiles (?#) VALUES (?a)', array_keys($subject), array_values($subject));
|
||||
$this->typeId = DB::Aowow()->selectCell('SELECT `id` FROM ?_profiler_profiles WHERE `realm` = ?d AND `realmGUID` = ?d', $this->realmId, $subject['realmGUID']);
|
||||
|
||||
$this->handleIncompleteData(Type::PROFILE, $subject['realmGUID']);
|
||||
return;
|
||||
}
|
||||
|
||||
// 3) does not exist at all
|
||||
$this->notFound();
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if ($this->doResync)
|
||||
return;
|
||||
|
||||
if ($this->typeId)
|
||||
{
|
||||
$subject = new LocalProfileList(array(['id', $this->typeId]));
|
||||
if ($subject->error)
|
||||
$this->notFound();
|
||||
|
||||
if (!$subject->isVisibleToUser())
|
||||
$this->notFound();
|
||||
|
||||
// character profile accessed by id
|
||||
if (!$subject->isCustom() && !$this->subjectName)
|
||||
$this->forward($subject->getProfileUrl());
|
||||
}
|
||||
|
||||
parent::generate();
|
||||
|
||||
array_unshift($this->title, Util::ucFirst(Lang::game('profile')));
|
||||
|
||||
|
||||
// as demanded by the raid activity tracker
|
||||
$bossIds = array(
|
||||
// ruby: Halion
|
||||
39863,
|
||||
// icc: Valanar, Lana'thel, Saurfang, Festergut, Deathwisper, Marrowgar, Putricide, Rotface, Sindragosa, Valithria, Lich King
|
||||
37970, 37955, 37813, 36626, 36855, 36612, 36678, 36627, 36853, 36789, 36597,
|
||||
// toc: Jaraxxus, Anub'arak
|
||||
34780, 34564,
|
||||
// ony: Onyxia
|
||||
10184,
|
||||
// uld: Flame Levi, Ignis, Razorscale, XT-002, Kologarn, Auriaya, Freya, Hodir, Mimiron, Thorim, Vezaxx, Yogg, Algalon
|
||||
33113, 33118, 33186, 33293, 32930, 33515, 32906, 32845, 33350, 32864, 33271, 33288, 32871,
|
||||
// nax: Anub, Faerlina, Maexxna, Noth, Heigan, Loatheb, Razuvious, Gothik, Patchwerk, Grobbulus, Gluth, Thaddius, Sapphiron, Kel'Thuzad
|
||||
15956, 15953, 15952, 15954, 15936, 16011, 16061, 16060, 16028, 15931, 15932, 15928, 15989, 15990
|
||||
);
|
||||
$this->extendGlobalIds(Type::NPC, ...$bossIds);
|
||||
|
||||
// dummy title from dungeon encounter
|
||||
foreach (Lang::profiler('encounterNames') as $id => $name)
|
||||
$this->extendGlobalData([Type::NPC => [$id => ['name_'.Lang::getLocale()->json() => $name]]]);
|
||||
}
|
||||
|
||||
private function notFound() : never
|
||||
{
|
||||
if ($this->subjectName && $this->realm)
|
||||
$head = Lang::profiler('firstUseTitle', [Util::ucFirst($this->subjectName), $this->realm]);
|
||||
else
|
||||
$head = Lang::profiler('profiler');
|
||||
|
||||
// unsetting typeId to prevent it from being added to the title string in the input-box is jank galore
|
||||
// but it isn't needed for the not-found case anyway, right...?
|
||||
unset($this->typeId);
|
||||
|
||||
parent::generateNotFound($head, Lang::profiler('notFound', 'profile'));
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
84
endpoints/profile/profile_power.php
Normal file
84
endpoints/profile/profile_power.php
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class ProfilePowerResponse extends TextResponse implements ICache
|
||||
{
|
||||
use TrProfilerDetail, TrCache, TrTooltip;
|
||||
|
||||
private const /* string */ POWER_TEMPLATE = '$WowheadPower.registerProfile(%s, %d, %s);';
|
||||
|
||||
protected int $type = Type::PROFILE;
|
||||
protected int $cacheType = CACHE_TYPE_TOOLTIP;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'domain' => ['filter' => FILTER_CALLBACK, 'options' => [Locale::class, 'tryFromDomain']]
|
||||
);
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
parent::__construct($pageParam);
|
||||
|
||||
if (!Cfg::get('PROFILER_ENABLE'))
|
||||
$this->generate404();
|
||||
|
||||
// temp locale
|
||||
if ($this->_get['domain'])
|
||||
Lang::load($this->_get['domain']);
|
||||
|
||||
$this->getSubjectFromUrl($pageParam);
|
||||
|
||||
if ($this->subjectName) // pageParam is fully defined profiler string
|
||||
{
|
||||
// pending rename
|
||||
if (preg_match('/([^\-]+)-(\d+)/i', $this->subjectName, $m))
|
||||
[, $this->subjectName, $renameItr] = $m;
|
||||
|
||||
if ($x = DB::Aowow()->selectCell('SELECT `id` FROM ?_profiler_profiles WHERE `realm` = ?d AND `realmGUID` IS NOT NULL AND LOWER(`name`) = ? AND `renameItr` = ?d', $this->realmId, $this->subjectName, $renameItr ?? 0))
|
||||
$this->typeId = $x;
|
||||
}
|
||||
|
||||
if (!$this->typeId)
|
||||
$this->generate404();
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$profile = new LocalProfileList(array(['id', $this->typeId]));
|
||||
if ($profile->error || !$profile->isVisibleToUser())
|
||||
$this->cacheType = CACHE_TYPE_NONE;
|
||||
else
|
||||
{
|
||||
$n = $profile->getField('name');
|
||||
$r = $profile->getField('race');
|
||||
$c = $profile->getField('class');
|
||||
$g = $profile->getField('gender');
|
||||
$l = $profile->getField('level');
|
||||
|
||||
if (!$this->subjectName) // implicit isCustom
|
||||
$n .= Lang::profiler('customProfile');
|
||||
else if ($_ = $profile->getField('title'))
|
||||
if ($title = (new TitleList(array(['id', $_])))?->getField($g ? 'female' : 'male', true))
|
||||
$n = sprintf($title, $n);
|
||||
|
||||
$opts = array(
|
||||
'name' => $n,
|
||||
'tooltip' => $profile->renderTooltip(),
|
||||
'icon' => '$$WH.g_getProfileIcon('.$r.', '.$c.', '.$g.', '.$l.', \''.$profile->getIcon().'\')'
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->subjectName)
|
||||
$id = implode('.', [$this->region, Profiler::urlize($this->realm, true), urlencode($this->subjectName)]);
|
||||
else
|
||||
$id = $this->typeId;
|
||||
|
||||
$this->result = new Tooltip(self::POWER_TEMPLATE, $id, $opts ?? []);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
64
endpoints/profile/public.php
Normal file
64
endpoints/profile/public.php
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class ProfilePublicResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdList'] ],
|
||||
'user' => ['filter' => FILTER_CALLBACK, 'options' => [Util::class, 'validateUsername']],
|
||||
// 'bookmarked' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkEmptySet'] ] // something with signatures? (must have bookmarked profile to create signature from)
|
||||
);
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
parent::__construct($pageParam);
|
||||
|
||||
if (!Cfg::get('PROFILER_ENABLE'))
|
||||
$this->generate404();
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
user: <string> [optional] // user page this is may be executed from
|
||||
return:
|
||||
null
|
||||
*/
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('id'))
|
||||
{
|
||||
trigger_error('ProfilePublicResponse - profileId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->_get['user'] && User::$username != $this->_get['user'] && !User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
{
|
||||
trigger_error('ProfilePublicResponse - user #'.User::$id.' tried to mark profiles of "'.$this->_get['user'].'" as public.', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$uid = 0;
|
||||
if (!$this->_get['user'] || User::$username == $this->_get['user'])
|
||||
$uid = User::$id;
|
||||
else if ($this->_get['user'] && User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
$uid = DB::Aowow()->selectCell('SELECT `id` FROM ?_account WHERE LOWER(`username`) = LOWER(?)', $this->_get['user']);
|
||||
|
||||
if (!$uid)
|
||||
{
|
||||
trigger_error('ProfilePublicResponse - user "'.$this->_get['user'].'" does not exist', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_account_profiles SET `extraFlags` = `extraFlags` | ?d WHERE `profileId` IN (?a) AND `accountId` = ?d', PROFILER_CU_PUBLISHED, $this->_get['id'], $uid);
|
||||
DB::Aowow()->query('UPDATE ?_profiler_profiles SET `cuFlags` = `cuFlags` | ?d WHERE `id` IN (?a) AND `user` = ?d', PROFILER_CU_PUBLISHED, $this->_get['id'], $uid);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
22
endpoints/profile/purge.php
Normal file
22
endpoints/profile/purge.php
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class ProfilePurgeResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
/* params
|
||||
id: <prId>
|
||||
data: <mode> [string, tabName]
|
||||
return
|
||||
null
|
||||
*/
|
||||
protected function generate() : void { } // removes completion data (as uploaded by the wowhead client) Just fail silently if someone triggers this manually
|
||||
}
|
||||
|
||||
?>
|
||||
42
endpoints/profile/resync.php
Normal file
42
endpoints/profile/resync.php
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class ProfileResyncResponse 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();
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
return:
|
||||
1
|
||||
*/
|
||||
protected function generate() : void
|
||||
{
|
||||
if ($chars = DB::Aowow()->select('SELECT `realm`, `realmGUID` FROM ?_profiler_profiles WHERE `id` IN (?a)', $this->_get['id']))
|
||||
{
|
||||
foreach ($chars as $c)
|
||||
Profiler::scheduleResync(Type::PROFILE, $c['realm'], $c['realmGUID']);
|
||||
}
|
||||
else
|
||||
trigger_error('ProfileResyncResponse - profiles '.implode(', ', $this->_get['id']).' not found in db', E_USER_ERROR);
|
||||
|
||||
$this->result = 1;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
197
endpoints/profile/save.php
Normal file
197
endpoints/profile/save.php
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class ProfileSaveResponse extends TextResponse
|
||||
{
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdList']],
|
||||
);
|
||||
protected array $expectedPOST = array(
|
||||
'name' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine'] ],
|
||||
'level' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'class' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'race' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'gender' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'nomodel' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'talenttree1' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'talenttree2' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'talenttree3' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'activespec' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'talentbuild1' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTalentString']],
|
||||
'glyphs1' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkGlyphString'] ],
|
||||
'talentbuild2' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTalentString']],
|
||||
'glyphs2' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkGlyphString'] ],
|
||||
'icon' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine'] ],
|
||||
'description' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextBlob'] ],
|
||||
'source' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'copy' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'public' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'gearscore' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'inv' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdListUnsigned'], 'flags' => FILTER_REQUIRE_ARRAY]
|
||||
);
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
parent::__construct($pageParam);
|
||||
|
||||
if (!Cfg::get('PROFILER_ENABLE'))
|
||||
$this->generate404();
|
||||
}
|
||||
|
||||
/* params (get))
|
||||
id: <prId1,0> [0: new profile]
|
||||
params (post)
|
||||
<various char data> [see below]
|
||||
return:
|
||||
proileId [onSuccess]
|
||||
-1 [onError]
|
||||
*/
|
||||
protected function generate() : void
|
||||
{
|
||||
$cuProfile = array(
|
||||
'user' => User::$id,
|
||||
// 'userName' => User::$username,
|
||||
'name' => $this->_post['name'],
|
||||
'level' => $this->_post['level'],
|
||||
'class' => $this->_post['class'],
|
||||
'race' => $this->_post['race'],
|
||||
'gender' => $this->_post['gender'],
|
||||
'nomodelMask' => $this->_post['nomodel'],
|
||||
'talenttree1' => $this->_post['talenttree1'],
|
||||
'talenttree2' => $this->_post['talenttree2'],
|
||||
'talenttree3' => $this->_post['talenttree3'],
|
||||
'talentbuild1' => $this->_post['talentbuild1'],
|
||||
'talentbuild2' => $this->_post['talentbuild2'],
|
||||
'activespec' => $this->_post['activespec'],
|
||||
'glyphs1' => $this->_post['glyphs1'],
|
||||
'glyphs2' => $this->_post['glyphs2'],
|
||||
'gearscore' => $this->_post['gearscore'],
|
||||
'icon' => $this->_post['icon'],
|
||||
'cuFlags' => PROFILER_CU_PROFILE | ($this->_post['public'] ? PROFILER_CU_PUBLISHED : 0)
|
||||
);
|
||||
|
||||
// remnant of a conflict between wotlk generic icons and cata+ auto-generated, char-based icons (see profile=avatar)
|
||||
if (strstr($cuProfile['icon'], 'profile=avatar'))
|
||||
$cuProfile['icon'] = '';
|
||||
|
||||
if ($_ = $this->_post['description'])
|
||||
$cuProfile['description'] = $_;
|
||||
|
||||
if ($_ = $this->_post['source']) // should i also set sourcename?
|
||||
$cuProfile['sourceId'] = $_;
|
||||
|
||||
if ($_ = $this->_post['copy']) // gets set to source profileId when "save as" is clicked. Whats the difference to 'source' though?
|
||||
{
|
||||
// get character origin info if possible
|
||||
if ($r = DB::Aowow()->selectCell('SELECT `realm` FROM ?_profiler_profiles WHERE `id` = ?d AND `realm` IS NOT NULL', $_))
|
||||
$cuProfile['realm'] = $r;
|
||||
|
||||
$cuProfile['sourceId'] = $_;
|
||||
}
|
||||
|
||||
if (!empty($cuProfile['sourceId']))
|
||||
$cuProfile['sourceName'] = DB::Aowow()->selectCell('SELECT `name` FROM ?_profiler_profiles WHERE `id` = ?d', $cuProfile['sourceId']);
|
||||
|
||||
$charId = -1;
|
||||
if ($id = $this->_get['id'][0]) // update
|
||||
{
|
||||
if ($charId = DB::Aowow()->selectCell('SELECT `id` FROM ?_profiler_profiles WHERE `id` = ?d', $id))
|
||||
DB::Aowow()->query('UPDATE ?_profiler_profiles SET ?a WHERE `id` = ?d', $cuProfile, $id);
|
||||
}
|
||||
else // new
|
||||
{
|
||||
$nProfiles = DB::Aowow()->selectCell('SELECT COUNT(*) FROM ?_profiler_profiles WHERE `user` = ?d AND (`cuFlags` & ?d) = 0 AND `realmGUID` IS NULL', User::$id, PROFILER_CU_DELETED);
|
||||
if ($nProfiles < 10 || User::isPremium())
|
||||
if ($newId = DB::Aowow()->query('INSERT INTO ?_profiler_profiles (?#) VALUES (?a)', array_keys($cuProfile), array_values($cuProfile)))
|
||||
$charId = $newId;
|
||||
}
|
||||
|
||||
// update items
|
||||
if ($charId != -1)
|
||||
{
|
||||
// ok, 'funny' thing: whether an item has en extra prismatic socket is determined contextually
|
||||
// either the socket is -1 or it has an itemId on an index where there shouldn't be one
|
||||
$keys = ['id', 'slot', 'item', 'subitem', 'permEnchant', 'tempEnchant', 'gem1', 'gem2', 'gem3', 'gem4'];
|
||||
|
||||
// validate Enchantments
|
||||
$enchIds = array_merge(
|
||||
array_column($this->_post['inv'], 3), // perm enchantments
|
||||
array_column($this->_post['inv'], 4) // temp enchantments (not used..?)
|
||||
);
|
||||
$enchs = new EnchantmentList(array(['id', $enchIds]));
|
||||
|
||||
// validate items
|
||||
$itemIds = array_merge(
|
||||
array_column($this->_post['inv'], 1), // base item
|
||||
array_column($this->_post['inv'], 5), // gem slot 1
|
||||
array_column($this->_post['inv'], 6), // gem slot 2
|
||||
array_column($this->_post['inv'], 7), // gem slot 3
|
||||
array_column($this->_post['inv'], 8) // gem slot 4
|
||||
);
|
||||
|
||||
$items = new ItemList(array(['id', $itemIds]));
|
||||
if (!$items->error)
|
||||
{
|
||||
foreach ($this->_post['inv'] as $slot => $itemData)
|
||||
{
|
||||
if ($slot + 1 == array_sum($itemData)) // only slot definition set => empty slot
|
||||
{
|
||||
DB::Aowow()->query('DELETE FROM ?_profiler_items WHERE `id` = ?d AND `slot` = ?d', $charId, $itemData[0]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// item does not exist
|
||||
if (!$items->getEntry($itemData[1]))
|
||||
continue;
|
||||
|
||||
// sub-item check
|
||||
if (!$items->getRandEnchantForItem($itemData[1]))
|
||||
$itemData[2] = 0;
|
||||
|
||||
// item sockets are fubar
|
||||
$nSockets = $items->json[$itemData[1]]['nsockets'] ?? 0;
|
||||
$nSockets += in_array($slot, [SLOT_WAIST, SLOT_WRISTS, SLOT_HANDS]) ? 1 : 0;
|
||||
for ($i = 5; $i < 9; $i++)
|
||||
if ($itemData[$i] > 0 && (!$items->getEntry($itemData[$i]) || $i >= (5 + $nSockets)))
|
||||
$itemData[$i] = 0;
|
||||
|
||||
// item enchantments are borked
|
||||
if ($itemData[3] && !$enchs->getEntry($itemData[3]))
|
||||
$itemData[3] = 0;
|
||||
|
||||
if ($itemData[4] && !$enchs->getEntry($itemData[4]))
|
||||
$itemData[4] = 0;
|
||||
|
||||
// looks good
|
||||
array_unshift($itemData, $charId);
|
||||
DB::Aowow()->query('REPLACE INTO ?_profiler_items (?#) VALUES (?a)', $keys, $itemData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->result = $charId;
|
||||
}
|
||||
|
||||
protected static function checkTalentString(string $val) : string
|
||||
{
|
||||
if (preg_match('/^\d+$/', $val))
|
||||
return $val;
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
protected static function checkGlyphString(string $val) : string
|
||||
{
|
||||
if (preg_match('/^\d+(:\d+)*$/', $val))
|
||||
return $val;
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
50
endpoints/profile/status.php
Normal file
50
endpoints/profile/status.php
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class ProfileStatusResponse extends TextResponse
|
||||
{
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdList'] ],
|
||||
'guild' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkEmptySet']],
|
||||
'arena-team' => ['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>
|
||||
return
|
||||
<status object>
|
||||
*/
|
||||
protected function generate() : void
|
||||
{
|
||||
// roster resync for this guild was requested -> get char list
|
||||
if ($this->_get['guild'])
|
||||
$ids = DB::Aowow()->selectCol('SELECT `id` FROM ?_profiler_profiles WHERE `guild` IN (?a)', $this->_get['id']);
|
||||
else if ($this->_get['arena-team'])
|
||||
$ids = DB::Aowow()->selectCol('SELECT `profileId` FROM ?_profiler_arena_team_member WHERE `arenaTeamId` IN (?a)', $this->_get['id']);
|
||||
else
|
||||
$ids = $this->_get['id'];
|
||||
|
||||
if (!$ids)
|
||||
{
|
||||
trigger_error('ProfileStatusResponse - no profileIds to resync'.($this->_get['guild'] ? ' for guild #'.$this->_get['guild'] : ($this->_get['arena-team'] ? ' for areana team #'.$this->_get['arena-team'] : '')), E_USER_ERROR);
|
||||
$this->result = Util::toJSON([1, [PR_QUEUE_STATUS_ERROR, 0, 0, PR_QUEUE_ERROR_CHAR]]);
|
||||
}
|
||||
|
||||
$this->result = Profiler::resyncStatus(Type::PROFILE, $ids);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
17
endpoints/profile/summary.php
Normal file
17
endpoints/profile/summary.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// page is generated by jScript .. does this need to be here then..?
|
||||
class ProfileSummaryResponse extends TextResponse
|
||||
{
|
||||
public function __construct() {}
|
||||
|
||||
protected function generate() : void {}
|
||||
}
|
||||
|
||||
?>
|
||||
62
endpoints/profile/unlink.php
Normal file
62
endpoints/profile/unlink.php
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class ProfileUnlinkResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdList'] ],
|
||||
'user' => ['filter' => FILTER_CALLBACK, 'options' => [Util::class, 'validateUsername']]
|
||||
);
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
parent::__construct($pageParam);
|
||||
|
||||
if (!Cfg::get('PROFILER_ENABLE'))
|
||||
$this->generate404();
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
user: <string> [optional] // user page this is may be executed from
|
||||
return:
|
||||
null
|
||||
*/
|
||||
protected function generate() : void // links char with account
|
||||
{
|
||||
if (!$this->assertGET('id'))
|
||||
{
|
||||
trigger_error('ProfileUnlinkResponse - profileId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->_get['user'] && User::$username != $this->_get['user'] && !User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
{
|
||||
trigger_error('ProfileUnlinkResponse - user #'.User::$id.' tried to unlink profiles from "'.$this->_get['user'], E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$uid = 0;
|
||||
if (!$this->_get['user'] || User::$username == $this->_get['user'])
|
||||
$uid = User::$id;
|
||||
else if ($this->_get['user'] && User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
$uid = DB::Aowow()->selectCell('SELECT `id` FROM ?_account WHERE LOWER(`username`) = LOWER(?)', $this->_get['user']);
|
||||
|
||||
if (!$uid)
|
||||
{
|
||||
trigger_error('ProfileUnlinkResponse - user "'.$this->_get['user'].'" does not exist', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
DB::Aowow()->query('DELETE FROM ?_account_profiles WHERE `accountId` = ?d AND `profileId` IN (?a)', $uid, $this->_get['id']);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
55
endpoints/profile/unpin.php
Normal file
55
endpoints/profile/unpin.php
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class ProfileUnpinResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdList'] ],
|
||||
'user' => ['filter' => FILTER_CALLBACK, 'options' => [Util::class, 'validateUsername']]
|
||||
);
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
parent::__construct($pageParam);
|
||||
|
||||
if (!Cfg::get('PROFILER_ENABLE'))
|
||||
$this->generate404();
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
user: <string> [optional]
|
||||
return: null
|
||||
*/
|
||||
protected function generate() : void // (un)favorite
|
||||
{
|
||||
if (!$this->assertGET('id'))
|
||||
{
|
||||
trigger_error('ProfileUnpinResponse - profileId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$uid = 0;
|
||||
if (!$this->_get['user'] || User::$username == $this->_get['user'])
|
||||
$uid = User::$id;
|
||||
else if ($this->_get['user'] && User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
$uid = DB::Aowow()->selectCell('SELECT `id` FROM ?_account WHERE LOWER(`username`) = LOWER(?)', $this->_get['user']);
|
||||
|
||||
if (!$uid)
|
||||
{
|
||||
trigger_error('ProfileUnpinResponse - user "'.$this->_get['user'].'" does not exist', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_account_profiles SET `extraFlags` = `extraFlags` & ~?d WHERE `accountId` = ?d', PROFILER_CU_PINNED, $uid);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
52
endpoints/profiler/profiler.php
Normal file
52
endpoints/profiler/profiler.php
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class ProfilerBaseResponse extends TemplateResponse
|
||||
{
|
||||
protected string $template = 'profiler';
|
||||
protected string $pageName = 'profiler';
|
||||
protected ?int $activeTab = parent::TAB_TOOLS;
|
||||
protected array $breadcrumb = [1, 5];
|
||||
|
||||
protected array $dataLoader = ['realms'];
|
||||
protected array $scripts = array(
|
||||
[SC_JS_FILE, 'js/profile_all.js'],
|
||||
[SC_JS_FILE, 'js/profile.js'],
|
||||
[SC_CSS_FILE, 'css/Profiler.css']
|
||||
);
|
||||
|
||||
public bool $gDataKey = true;
|
||||
public array $regions = [];
|
||||
public string $rg = 'us'; // preselected region in form
|
||||
|
||||
public function __construct(string $params)
|
||||
{
|
||||
parent::__construct($params);
|
||||
|
||||
if (!Cfg::get('PROFILER_ENABLE'))
|
||||
$this->generateError();
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
// just so the form does not break. There won't be any results.
|
||||
$usedRegions = array_column(Profiler::getRealms(), 'region') ?: ['us'];
|
||||
foreach (Util::$regions as $idx => $id)
|
||||
if (in_array($id, $usedRegions))
|
||||
$this->regions[$id] = [Lang::profiler('regions', $id), $idx + 1];
|
||||
|
||||
if (!in_array($this->rg, $usedRegions))
|
||||
$this->rg = key($this->regions);
|
||||
|
||||
array_unshift($this->title, Util::ucFirst(Lang::profiler('profiler')));
|
||||
|
||||
parent::generate();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
220
endpoints/profiles/profiles.php
Normal file
220
endpoints/profiles/profiles.php
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class ProfilesBaseResponse extends TemplateResponse implements IProfilerList
|
||||
{
|
||||
use TrProfilerList, TrListPage;
|
||||
|
||||
protected string $template = 'profiles';
|
||||
protected string $pageName = 'profiles';
|
||||
protected ?int $activeTab = parent::TAB_TOOLS;
|
||||
protected array $breadcrumb = [1, 5, 0]; // Tools > Profiler > Characters
|
||||
|
||||
protected array $dataLoader = ['weight-presets', 'realms'];
|
||||
protected array $scripts = array(
|
||||
[SC_JS_FILE, 'js/filters.js'],
|
||||
[SC_JS_FILE, 'js/profile_all.js'],
|
||||
[SC_JS_FILE, 'js/profile.js'],
|
||||
[SC_CSS_FILE, 'css/Profiler.css']
|
||||
);
|
||||
protected array $expectedGET = array(
|
||||
'filter' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => Filter::PATTERN_PARAM]],
|
||||
// 1 guild; 2,3,4 arenateam (4 => 5-man): puts a resync button on the lv (was probably used before arenateams and guilds had a dedicated page)
|
||||
'roster' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_value' => 1, 'max_value' => 4]]
|
||||
);
|
||||
|
||||
public int $type = Type::PROFILE;
|
||||
public string $roster = '';
|
||||
|
||||
private int $sumSubjects = 0;
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
$this->getSubjectFromUrl($pageParam);
|
||||
|
||||
parent::__construct($pageParam);
|
||||
|
||||
if (!Cfg::get('PROFILER_ENABLE'))
|
||||
$this->generateError();
|
||||
|
||||
$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 characters WHERE `deleteInfos_Name` IS NULL AND `level` <= ?d AND (`extra_flags` & ?) = 0', MAX_LEVEL, Profiler::CHAR_GMFLAGS);
|
||||
$realms[] = $idx;
|
||||
}
|
||||
|
||||
$this->subCat = $pageParam !== '' ? '='.$pageParam : '';
|
||||
$this->filter = new ProfileListFilter($this->_get['filter'] ?? '', ['realms' => $realms]);
|
||||
$this->filterError = $this->filter->error;
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->h1 = Util::ucFirst(Lang::game('profiles'));
|
||||
|
||||
$this->filter->evalCriteria();
|
||||
|
||||
|
||||
/*************/
|
||||
/* 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('profiles'));
|
||||
else if ($this->region)
|
||||
array_unshift($this->title, Lang::profiler('regions', $this->region), Lang::game('profiles'));
|
||||
else
|
||||
array_unshift($this->title, Lang::game('profiles'));
|
||||
|
||||
|
||||
/****************/
|
||||
/* Main Content */
|
||||
/****************/
|
||||
|
||||
$conditions = [];
|
||||
if ($_ = $this->filter->getConditions())
|
||||
$conditions[] = $_;
|
||||
|
||||
$this->filterError = $this->filter->error; // maybe the evalX() caused something
|
||||
|
||||
$fiExtraCols = $this->filter->fiExtraCols;
|
||||
|
||||
$lvData = [];
|
||||
$lvExtraCols = [];
|
||||
$lvVisibleCols = ['race', 'classs', 'level', 'talents', 'achievementpoints', 'gearscore'];
|
||||
$lvHiddenCols = [];
|
||||
$lvNote = '';
|
||||
$lv_truncated = 0;
|
||||
|
||||
$this->getRegions();
|
||||
|
||||
foreach ($fiExtraCols as $skill => $idx)
|
||||
$lvExtraCols[] = "\$Listview.funcBox.createSimpleCol('skill-' + ".$skill.", g_spell_skills[".$skill."], '7%', 'skill-' + ".$skill.")";
|
||||
|
||||
if (!$this->filter->useLocalList)
|
||||
{
|
||||
$conditions[] = ['deleteInfos_Name', null];
|
||||
$conditions[] = ['level', MAX_LEVEL, '<=']; // prevents JS errors
|
||||
$conditions[] = [['extra_flags', Profiler::CHAR_GMFLAGS, '&'], 0];
|
||||
}
|
||||
|
||||
$miscParams = ['calcTotal' => true];
|
||||
if ($this->realm)
|
||||
$miscParams['sv'] = $this->realm;
|
||||
if ($this->region)
|
||||
$miscParams['rg'] = $this->region;
|
||||
if ($_ = $this->filter->extraOpts)
|
||||
$miscParams['extraOpts'] = $_;
|
||||
|
||||
if ($this->filter->useLocalList)
|
||||
$profiles = new LocalProfileList($conditions, $miscParams);
|
||||
else
|
||||
$profiles = new RemoteProfileList($conditions, $miscParams);
|
||||
|
||||
if (!$profiles->error)
|
||||
{
|
||||
// init these chars on our side and get local ids
|
||||
if (!$this->filter->useLocalList)
|
||||
$profiles->initializeLocalEntries();
|
||||
|
||||
// Roster only if single realm selected
|
||||
$roster = $this->realmId ? $this->_get['roster'] : 0;
|
||||
if (!$roster && $this->realmId)
|
||||
if (count($r = $this->filter->getSetCriteria(9, 12, 15, 18)) == 1)
|
||||
$roster = ($r[0] - 6) / 3; // 1, 2, 3, or 4
|
||||
|
||||
$addInfoMask = PROFILEINFO_CHARACTER;
|
||||
|
||||
// team rating filters
|
||||
if ($this->filter->getSetCriteria(13, 16, 19))
|
||||
{
|
||||
$lvVisibleCols[] = 'rating';
|
||||
$addInfoMask |= PROFILEINFO_ARENA;
|
||||
}
|
||||
|
||||
// init roster-listview
|
||||
if ($roster == 1 && !$profiles->hasDiffFields('guild') && $profiles->getField('guild'))
|
||||
{
|
||||
$lvVisibleCols[] = 'guildrank';
|
||||
$lvHiddenCols[] = 'guild';
|
||||
|
||||
$this->roster = Lang::profiler('guildRoster', [$profiles->getField('guildname')]);
|
||||
}
|
||||
else if ($roster && !$profiles->hasDiffFields('arenateam') && $profiles->getField('arenateam'))
|
||||
{
|
||||
$lvVisibleCols[] = 'rating';
|
||||
|
||||
$addInfoMask |= PROFILEINFO_ARENA;
|
||||
$this->roster = Lang::profiler('arenaRoster', [$profiles->getField('arenateam')]);
|
||||
}
|
||||
|
||||
$lvData = $profiles->getListviewData($addInfoMask, $fiExtraCols);
|
||||
|
||||
if ($this->filter->getSetCriteria(10) && !in_array('guildrank', $lvHiddenCols))
|
||||
$lvVisibleCols[] = 'guildrank';
|
||||
|
||||
// create note if search limit was exceeded
|
||||
if ($this->filter->query && $profiles->getMatches() > Cfg::get('SQL_LIMIT_DEFAULT'))
|
||||
{
|
||||
$lvNote = sprintf(Util::$tryFilteringString, 'LANG.lvnote_charactersfound2', $this->sumSubjects, $profiles->getMatches());
|
||||
$lv_truncated = 1;
|
||||
}
|
||||
else if ($profiles->getMatches() > Cfg::get('SQL_LIMIT_DEFAULT'))
|
||||
$lvNote = sprintf(Util::$tryFilteringString, 'LANG.lvnote_charactersfound', $this->sumSubjects, 0);
|
||||
|
||||
if ($this->filter->useLocalList)
|
||||
{
|
||||
if (!empty($lvNote))
|
||||
$lvNote .= ' + "<br /><span class=\'r1 icon-report\'>'.Lang::profiler('complexFilter').'</span>"';
|
||||
else
|
||||
$lvNote = '<span class="r1 icon-report">'.Lang::profiler('complexFilter').'</span>';
|
||||
}
|
||||
}
|
||||
|
||||
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"], 'tabsRelated');
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview(array(
|
||||
'id' => 'characters',
|
||||
'data' => $lvData,
|
||||
'hideCount' => 1,
|
||||
'onBeforeCreate' => '$pr_initRosterListview', // puts a resync button on the lv
|
||||
'extraCols' => $lvExtraCols ?: null,
|
||||
'visibleCols' => $lvVisibleCols,
|
||||
'hiddenCols' => $lvHiddenCols ?: null,
|
||||
'note' => $lvNote ?: null,
|
||||
'_truncated' => $lv_truncated ?: null
|
||||
), ProfileList::$brickFile));
|
||||
|
||||
parent::generate();
|
||||
|
||||
$this->result->registerDisplayHook('filter', [self::class, 'filterFormHook']);
|
||||
}
|
||||
|
||||
public static function filterFormHook(Template\PageTemplate &$pt, ProfileListFilter $filter) : void
|
||||
{
|
||||
// sort for dropdown-menus
|
||||
Lang::sort('game', 'ra');
|
||||
Lang::sort('game', 'cl');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
@ -1,780 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
class AjaxProfile extends AjaxHandler
|
||||
{
|
||||
private $undo = false;
|
||||
|
||||
protected $validParams = ['link', 'unlink', 'pin', 'unpin', 'public', 'private', 'avatar', 'resync', 'status', 'save', 'delete', 'purge', 'summary', 'load'];
|
||||
protected $_get = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkIdList' ],
|
||||
'items' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxProfile::checkItemList'],
|
||||
'size' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkTextLine'],
|
||||
'guild' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkEmptySet'],
|
||||
'arena-team' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkEmptySet'],
|
||||
'user' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxProfile::checkUser' ]
|
||||
);
|
||||
|
||||
protected $_post = array(
|
||||
'name' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkTextLine'],
|
||||
'level' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'class' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'race' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'gender' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'nomodel' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'talenttree1' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'talenttree2' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'talenttree3' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'activespec' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'talentbuild1' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxProfile::checkTalentString'],
|
||||
'glyphs1' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxProfile::checkGlyphString' ],
|
||||
'talentbuild2' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxProfile::checkTalentString'],
|
||||
'glyphs2' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxProfile::checkGlyphString' ],
|
||||
'icon' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkTextLine' ],
|
||||
'description' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkTextBlob' ],
|
||||
'source' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'copy' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'public' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'gearscore' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'inv' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkIdListUnsigned', 'flags' => FILTER_REQUIRE_ARRAY],
|
||||
);
|
||||
|
||||
public function __construct(array $params)
|
||||
{
|
||||
parent::__construct($params);
|
||||
|
||||
if (!$this->params)
|
||||
return;
|
||||
|
||||
if (!Cfg::get('PROFILER_ENABLE'))
|
||||
return;
|
||||
|
||||
switch ($this->params[0])
|
||||
{
|
||||
case 'unlink':
|
||||
$this->undo = true;
|
||||
case 'link':
|
||||
$this->handler = 'handleLink'; // always returns null
|
||||
break;
|
||||
case 'unpin':
|
||||
$this->undo = true;
|
||||
case 'pin':
|
||||
$this->handler = 'handlePin'; // always returns null
|
||||
break;
|
||||
case 'private':
|
||||
$this->undo = true;
|
||||
case 'public':
|
||||
$this->handler = 'handlePrivacy'; // always returns null
|
||||
break;
|
||||
case 'avatar':
|
||||
$this->handler = 'handleAvatar'; // sets an image header
|
||||
break; // so it has to die here or another header will be set
|
||||
case 'resync':
|
||||
$this->handler = 'handleResync'; // always returns "1"
|
||||
break;
|
||||
case 'status':
|
||||
$this->handler = 'handleStatus'; // returns status object
|
||||
break;
|
||||
case 'save':
|
||||
$this->handler = 'handleSave';
|
||||
break;
|
||||
case 'delete':
|
||||
$this->handler = 'handleDelete';
|
||||
break;
|
||||
case 'purge':
|
||||
$this->handler = 'handlePurge';
|
||||
break;
|
||||
case 'summary': // page is generated by jScript
|
||||
die(); // just be empty
|
||||
case 'load':
|
||||
$this->handler = 'handleLoad';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
user: <string> [optional]
|
||||
return: null
|
||||
*/
|
||||
protected function handleLink() : void // links char with account
|
||||
{
|
||||
if (!User::isLoggedIn() || empty($this->_get['id']))
|
||||
{
|
||||
trigger_error('AjaxProfile::handleLink - profileId empty or user not logged in', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$uid = User::$id;
|
||||
if ($this->_get['user'] && User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
{
|
||||
if (!($uid = DB::Aowow()->selectCell('SELECT `id` FROM ?_account WHERE LOWER(`username`) = LOWER(?)', $this->_get['user'])))
|
||||
{
|
||||
trigger_error('AjaxProfile::handleLink - user "'.$this->_get['user'].'" does not exist', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->undo)
|
||||
DB::Aowow()->query('DELETE FROM ?_account_profiles WHERE `accountId` = ?d AND `profileId` IN (?a)', $uid, $this->_get['id']);
|
||||
else
|
||||
{
|
||||
foreach ($this->_get['id'] as $prId) // only link characters, not custom profiles
|
||||
{
|
||||
if ($prId = DB::Aowow()->selectCell('SELECT `id` FROM ?_profiler_profiles WHERE `id` = ?d AND `realm` IS NOT NULL', $prId))
|
||||
DB::Aowow()->query('INSERT IGNORE INTO ?_account_profiles VALUES (?d, ?d, 0)', $uid, $prId);
|
||||
else
|
||||
{
|
||||
trigger_error('AjaxProfile::handleLink - profile #'.$prId.' is custom or does not exist', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
user: <string> [optional]
|
||||
return: null
|
||||
*/
|
||||
protected function handlePin() : void // (un)favorite
|
||||
{
|
||||
if (!User::isLoggedIn() || empty($this->_get['id'][0]))
|
||||
{
|
||||
trigger_error('AjaxProfile::handlePin - profileId empty or user not logged in', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$uid = User::$id;
|
||||
if ($this->_get['user'] && User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
{
|
||||
if (!($uid = DB::Aowow()->selectCell('SELECT `id` FROM ?_account WHERE LOWER(`username`) = LOWER(?)', $this->_get['user'])))
|
||||
{
|
||||
trigger_error('AjaxProfile::handlePin - user "'.$this->_get['user'].'" does not exist', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// since only one character can be pinned at a time we can reset everything
|
||||
DB::Aowow()->query('UPDATE ?_account_profiles SET `extraFlags` = `extraFlags` & ?d WHERE `accountId` = ?d', ~PROFILER_CU_PINNED, $uid);
|
||||
// and set a single char if necessary
|
||||
if (!$this->undo)
|
||||
DB::Aowow()->query('UPDATE ?_account_profiles SET `extraFlags` = `extraFlags` | ?d WHERE `profileId` = ?d AND `accountId` = ?d', PROFILER_CU_PINNED, $this->_get['id'][0], $uid);
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
user: <string> [optional]
|
||||
return: null
|
||||
*/
|
||||
protected function handlePrivacy() : void // public visibility
|
||||
{
|
||||
if (!User::isLoggedIn() || empty($this->_get['id'][0]))
|
||||
{
|
||||
trigger_error('AjaxProfile::handlePrivacy - profileId empty or user not logged in', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$uid = User::$id;
|
||||
if ($this->_get['user'] && User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
{
|
||||
if (!($uid = DB::Aowow()->selectCell('SELECT `id` FROM ?_account WHERE LOWER(`username`) = LOWER(?)', $this->_get['user'])))
|
||||
{
|
||||
trigger_error('AjaxProfile::handlePrivacy - user "'.$this->_get['user'].'" does not exist', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->undo)
|
||||
{
|
||||
DB::Aowow()->query('UPDATE ?_account_profiles SET `extraFlags` = `extraFlags` & ?d WHERE `profileId` IN (?a) AND `accountId` = ?d', ~PROFILER_CU_PUBLISHED, $this->_get['id'], $uid);
|
||||
DB::Aowow()->query('UPDATE ?_profiler_profiles SET `cuFlags` = `cuFlags` & ?d WHERE `id` IN (?a) AND `user` = ?d', ~PROFILER_CU_PUBLISHED, $this->_get['id'], $uid);
|
||||
}
|
||||
else
|
||||
{
|
||||
DB::Aowow()->query('UPDATE ?_account_profiles SET `extraFlags` = `extraFlags` | ?d WHERE `profileId` IN (?a) AND `accountId` = ?d', PROFILER_CU_PUBLISHED, $this->_get['id'], $uid);
|
||||
DB::Aowow()->query('UPDATE ?_profiler_profiles SET `cuFlags` = `cuFlags` | ?d WHERE `id` IN (?a) AND `user` = ?d', PROFILER_CU_PUBLISHED, $this->_get['id'], $uid);
|
||||
}
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId>
|
||||
size: <string> [optional]
|
||||
return: image-header
|
||||
*/
|
||||
protected function handleAvatar() : void // image
|
||||
{
|
||||
// something happened in the last years: those textures do not include tiny icons
|
||||
$sizes = [/* 'tiny' => 15, */'small' => 18, 'medium' => 36, 'large' => 56];
|
||||
$aPath = 'uploads/avatars/%d.jpg';
|
||||
$s = $this->_get['size'] ?: 'medium';
|
||||
|
||||
if (!$this->_get['id'] || !preg_match('/^([0-9]+)\.(jpg|gif)$/', $this->_get['id'][0], $matches) || !in_array($s, array_keys($sizes)))
|
||||
{
|
||||
trigger_error('AjaxProfile::handleAvatar - malformed request received', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->contentType = $matches[2] == 'png' ? MIME_TYPE_PNG : MIME_TYPE_JPEG;
|
||||
|
||||
$id = $matches[1];
|
||||
$dest = imageCreateTruecolor($sizes[$s], $sizes[$s]);
|
||||
|
||||
if (file_exists(sprintf($aPath, $id)))
|
||||
{
|
||||
$offsetX = $offsetY = 0;
|
||||
|
||||
switch ($s)
|
||||
{
|
||||
case 'tiny':
|
||||
$offsetX += $sizes['small'];
|
||||
case 'small':
|
||||
$offsetY += $sizes['medium'];
|
||||
case 'medium':
|
||||
$offsetX += $sizes['large'];
|
||||
}
|
||||
|
||||
$src = imageCreateFromJpeg(printf($aPath, $id));
|
||||
imagecopymerge($dest, $src, 0, 0, $offsetX, $offsetY, $sizes[$s], $sizes[$s], 100);
|
||||
}
|
||||
else
|
||||
trigger_error('AjaxProfile::handleAvatar - avatar file #'.$id.' not found', E_USER_ERROR);
|
||||
|
||||
if ($matches[2] == 'gif')
|
||||
imageGif($dest);
|
||||
else
|
||||
imageJpeg($dest);
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
user: <string> [optional, not used]
|
||||
return: 1
|
||||
*/
|
||||
protected function handleResync() : string
|
||||
{
|
||||
if ($chars = DB::Aowow()->select('SELECT realm, realmGUID FROM ?_profiler_profiles WHERE id IN (?a)', $this->_get['id']))
|
||||
{
|
||||
foreach ($chars as $c)
|
||||
Profiler::scheduleResync(Type::PROFILE, $c['realm'], $c['realmGUID']);
|
||||
}
|
||||
else
|
||||
trigger_error('AjaxProfile::handleResync - profiles '.implode(', ', $this->_get['id']).' not found in db', E_USER_ERROR);
|
||||
|
||||
return '1';
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
return
|
||||
<status object>
|
||||
[
|
||||
nQueueProcesses,
|
||||
[statusCode, timeToRefresh, curQueuePos, errorCode, nResyncTries],
|
||||
[<anotherStatus>]
|
||||
...
|
||||
]
|
||||
|
||||
not all fields are required, if zero they are omitted
|
||||
statusCode:
|
||||
0: end the request
|
||||
1: waiting
|
||||
2: working...
|
||||
3: ready; click to view
|
||||
4: error / retry
|
||||
errorCode:
|
||||
0: unk error
|
||||
1: char does not exist
|
||||
2: armory gone
|
||||
*/
|
||||
protected function handleStatus() : string
|
||||
{
|
||||
// roster resync for this guild was requested -> get char list
|
||||
if ($this->_get['guild'])
|
||||
$ids = DB::Aowow()->selectCol('SELECT id FROM ?_profiler_profiles WHERE guild IN (?a)', $this->_get['id']);
|
||||
else if ($this->_get['arena-team'])
|
||||
$ids = DB::Aowow()->selectCol('SELECT profileId FROM ?_profiler_arena_team_member WHERE arenaTeamId IN (?a)', $this->_get['id']);
|
||||
else
|
||||
$ids = $this->_get['id'];
|
||||
|
||||
if (!$ids)
|
||||
{
|
||||
trigger_error('AjaxProfile::handleStatus - no profileIds to resync'.($this->_get['guild'] ? ' for guild #'.$this->_get['guild'] : ($this->_get['arena-team'] ? ' for areana team #'.$this->_get['arena-team'] : '')), E_USER_ERROR);
|
||||
return Util::toJSON([1, [PR_QUEUE_STATUS_ERROR, 0, 0, PR_QUEUE_ERROR_CHAR]]);
|
||||
}
|
||||
|
||||
return Profiler::resyncStatus(Type::PROFILE, $ids);
|
||||
}
|
||||
|
||||
/* params (get))
|
||||
id: <prId1,0> [0: new profile]
|
||||
params (post)
|
||||
<various char data> [see below]
|
||||
return:
|
||||
proileId [onSuccess]
|
||||
-1 [onError]
|
||||
*/
|
||||
protected function handleSave() : string // unKill a profile
|
||||
{
|
||||
// todo (med): detail check this post-data
|
||||
$cuProfile = array(
|
||||
'user' => User::$id,
|
||||
// 'userName' => User::$username,
|
||||
'name' => $this->_post['name'],
|
||||
'level' => $this->_post['level'],
|
||||
'class' => $this->_post['class'],
|
||||
'race' => $this->_post['race'],
|
||||
'gender' => $this->_post['gender'],
|
||||
'nomodelMask' => $this->_post['nomodel'],
|
||||
'talenttree1' => $this->_post['talenttree1'],
|
||||
'talenttree2' => $this->_post['talenttree2'],
|
||||
'talenttree3' => $this->_post['talenttree3'],
|
||||
'talentbuild1' => $this->_post['talentbuild1'],
|
||||
'talentbuild2' => $this->_post['talentbuild2'],
|
||||
'activespec' => $this->_post['activespec'],
|
||||
'glyphs1' => $this->_post['glyphs1'],
|
||||
'glyphs2' => $this->_post['glyphs2'],
|
||||
'gearscore' => $this->_post['gearscore'],
|
||||
'icon' => $this->_post['icon'],
|
||||
'cuFlags' => PROFILER_CU_PROFILE | ($this->_post['public'] ? PROFILER_CU_PUBLISHED : 0)
|
||||
);
|
||||
|
||||
if (strstr($cuProfile['icon'], 'profile=avatar')) // how the profiler is supposed to handle icons is beyond me
|
||||
$cuProfile['icon'] = '';
|
||||
|
||||
if ($_ = $this->_post['description'])
|
||||
$cuProfile['description'] = $_;
|
||||
|
||||
if ($_ = $this->_post['source']) // should i also set sourcename?
|
||||
$cuProfile['sourceId'] = $_;
|
||||
|
||||
if ($_ = $this->_post['copy']) // gets set to source profileId when "save as" is clicked. Whats the difference to 'source' though?
|
||||
{
|
||||
// get character origin info if possible
|
||||
if ($r = DB::Aowow()->selectCell('SELECT realm FROM ?_profiler_profiles WHERE id = ?d AND realm IS NOT NULL', $_))
|
||||
$cuProfile['realm'] = $r;
|
||||
|
||||
$cuProfile['sourceId'] = $_;
|
||||
}
|
||||
|
||||
if (!empty($cuProfile['sourceId']))
|
||||
$cuProfile['sourceName'] = DB::Aowow()->selectCell('SELECT name FROM ?_profiler_profiles WHERE id = ?d', $cuProfile['sourceId']);
|
||||
|
||||
$charId = -1;
|
||||
if ($id = $this->_get['id'][0]) // update
|
||||
{
|
||||
if ($charId = DB::Aowow()->selectCell('SELECT id FROM ?_profiler_profiles WHERE id = ?d', $id))
|
||||
DB::Aowow()->query('UPDATE ?_profiler_profiles SET ?a WHERE id = ?d', $cuProfile, $id);
|
||||
}
|
||||
else // new
|
||||
{
|
||||
$nProfiles = DB::Aowow()->selectCell('SELECT COUNT(*) FROM ?_profiler_profiles WHERE user = ?d AND (cuFlags & ?d) = 0 AND realmGUID IS NULL', User::$id, PROFILER_CU_DELETED);
|
||||
if ($nProfiles < 10 || User::isPremium())
|
||||
if ($newId = DB::Aowow()->query('INSERT INTO ?_profiler_profiles (?#) VALUES (?a)', array_keys($cuProfile), array_values($cuProfile)))
|
||||
$charId = $newId;
|
||||
}
|
||||
|
||||
// update items
|
||||
if ($charId != -1)
|
||||
{
|
||||
// ok, 'funny' thing: wether an item has en extra prismatic sockel is determined contextual
|
||||
// either the socket is -1 or it has an itemId in a socket where there shouldn't be one
|
||||
$keys = ['id', 'slot', 'item', 'subitem', 'permEnchant', 'tempEnchant', 'gem1', 'gem2', 'gem3', 'gem4'];
|
||||
|
||||
// validate Enchantments
|
||||
$enchIds = array_merge(
|
||||
array_column($this->_post['inv'], 3), // perm enchantments
|
||||
array_column($this->_post['inv'], 4) // temp enchantments (not used..?)
|
||||
);
|
||||
$enchs = new EnchantmentList(array(['id', $enchIds]));
|
||||
|
||||
// validate items
|
||||
$itemIds = array_merge(
|
||||
array_column($this->_post['inv'], 1), // base item
|
||||
array_column($this->_post['inv'], 5), // gem slot 1
|
||||
array_column($this->_post['inv'], 6), // gem slot 2
|
||||
array_column($this->_post['inv'], 7), // gem slot 3
|
||||
array_column($this->_post['inv'], 8) // gem slot 4
|
||||
);
|
||||
|
||||
$items = new ItemList(array(['id', $itemIds]));
|
||||
if (!$items->error)
|
||||
{
|
||||
foreach ($this->_post['inv'] as $slot => $itemData)
|
||||
{
|
||||
if ($slot + 1 == array_sum($itemData)) // only slot definition set => empty slot
|
||||
{
|
||||
DB::Aowow()->query('DELETE FROM ?_profiler_items WHERE id = ?d AND slot = ?d', $charId, $itemData[0]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// item does not exist
|
||||
if (!$items->getEntry($itemData[1]))
|
||||
continue;
|
||||
|
||||
// sub-item check
|
||||
if (!$items->getRandEnchantForItem($itemData[1]))
|
||||
$itemData[2] = 0;
|
||||
|
||||
// item sockets are fubar
|
||||
$nSockets = $items->json[$itemData[1]]['nsockets'] ?? 0;
|
||||
$nSockets += in_array($slot, [SLOT_WAIST, SLOT_WRISTS, SLOT_HANDS]) ? 1 : 0;
|
||||
for ($i = 5; $i < 9; $i++)
|
||||
if ($itemData[$i] > 0 && (!$items->getEntry($itemData[$i]) || $i >= (5 + $nSockets)))
|
||||
$itemData[$i] = 0;
|
||||
|
||||
// item enchantments are borked
|
||||
if ($itemData[3] && !$enchs->getEntry($itemData[3]))
|
||||
$itemData[3] = 0;
|
||||
|
||||
if ($itemData[4] && !$enchs->getEntry($itemData[4]))
|
||||
$itemData[4] = 0;
|
||||
|
||||
// looks good
|
||||
array_unshift($itemData, $charId);
|
||||
DB::Aowow()->query('REPLACE INTO ?_profiler_items (?#) VALUES (?a)', $keys, $itemData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (string)$charId;
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
return
|
||||
null
|
||||
*/
|
||||
protected function handleDelete() : void // kill a profile
|
||||
{
|
||||
if (!User::isLoggedIn() || !$this->_get['id'])
|
||||
{
|
||||
trigger_error('AjaxProfile::handleDelete - profileId empty or user not logged in', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// only flag as deleted; only custom profiles
|
||||
DB::Aowow()->query(
|
||||
'UPDATE ?_profiler_profiles SET cuFlags = cuFlags | ?d WHERE id IN (?a) AND cuFlags & ?d {AND user = ?d}',
|
||||
PROFILER_CU_DELETED,
|
||||
$this->_get['id'],
|
||||
PROFILER_CU_PROFILE,
|
||||
User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU) ? DBSIMPLE_SKIP : User::$id
|
||||
);
|
||||
}
|
||||
|
||||
/* params
|
||||
id: profileId
|
||||
items: string [itemIds.join(':')]
|
||||
unnamed: unixtime [only to force the browser to reload instead of cache]
|
||||
return
|
||||
lots...
|
||||
*/
|
||||
protected function handleLoad() : string
|
||||
{
|
||||
// titles, achievements, characterData, talents, pets
|
||||
// and some onLoad-hook to .. load it registerProfile($data)
|
||||
// everything else goes through data.php .. strangely enough
|
||||
|
||||
if (!$this->_get['id'])
|
||||
{
|
||||
trigger_error('AjaxProfile::handleLoad - profileId empty', E_USER_ERROR);
|
||||
return '';
|
||||
}
|
||||
|
||||
$pBase = DB::Aowow()->selectRow('SELECT pg.name AS guildname, p.* FROM ?_profiler_profiles p LEFT JOIN ?_profiler_guild pg ON pg.id = p.guild WHERE p.id = ?d', $this->_get['id'][0]);
|
||||
if (!$pBase)
|
||||
{
|
||||
trigger_error('Profiler::handleLoad - called with invalid profileId #'.$this->_get['id'][0], E_USER_WARNING);
|
||||
return '';
|
||||
}
|
||||
|
||||
if (($pBase['cuFlags'] & PROFILER_CU_DELETED) && !User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
return '';
|
||||
|
||||
|
||||
$rData = [];
|
||||
foreach (Profiler::getRealms() as $rId => $rData)
|
||||
if ($rId == $pBase['realm'])
|
||||
break;
|
||||
|
||||
if (!$rData) // realm doesn't exist or access is restricted
|
||||
return '';
|
||||
|
||||
$profile = array(
|
||||
'id' => $pBase['id'],
|
||||
'source' => $pBase['id'],
|
||||
'level' => $pBase['level'],
|
||||
'classs' => $pBase['class'],
|
||||
'race' => $pBase['race'],
|
||||
'faction' => ChrRace::tryFrom($pBase['race'])?->getTeam() ?? TEAM_NEUTRAL,
|
||||
'gender' => $pBase['gender'],
|
||||
'skincolor' => $pBase['skincolor'],
|
||||
'hairstyle' => $pBase['hairstyle'],
|
||||
'haircolor' => $pBase['haircolor'],
|
||||
'facetype' => $pBase['facetype'],
|
||||
'features' => $pBase['features'],
|
||||
'title' => $pBase['title'],
|
||||
'name' => $pBase['name'],
|
||||
'guild' => "$'".$pBase['guildname']."'",
|
||||
'published' => !!($pBase['cuFlags'] & PROFILER_CU_PUBLISHED),
|
||||
'pinned' => !!($pBase['cuFlags'] & PROFILER_CU_PINNED),
|
||||
'nomodel' => $pBase['nomodelMask'],
|
||||
'playedtime' => $pBase['playedtime'],
|
||||
'lastupdated' => $pBase['lastupdated'] * 1000,
|
||||
'talents' => array(
|
||||
'builds' => array( // notice the bullshit to prevent the talent-string from becoming a float! NOTICE IT!!
|
||||
['talents' => '$"'.$pBase['talentbuild1'].'"', 'glyphs' => $pBase['glyphs1']],
|
||||
['talents' => '$"'.$pBase['talentbuild2'].'"', 'glyphs' => $pBase['glyphs2']]
|
||||
),
|
||||
'active' => $pBase['activespec']
|
||||
),
|
||||
// set later
|
||||
'inventory' => [],
|
||||
'bookmarks' => [], // list of userIds who claimed this profile (claiming and owning are two different things)
|
||||
|
||||
// completion lists: [subjectId => amount/timestamp/1]
|
||||
'skills' => [], // skillId => [curVal, maxVal]
|
||||
'reputation' => [], // factionId => curVal
|
||||
'titles' => [], // titleId => 1
|
||||
'spells' => [], // spellId => 1; recipes, vanity pets, mounts
|
||||
'achievements' => [], // achievementId => timestamp
|
||||
'quests' => [], // questId => 1
|
||||
'achievementpoints' => 0, // max you have
|
||||
'statistics' => [], // all raid activity [achievementId => killCount]
|
||||
'activity' => [], // recent raid activity [achievementId => 1] (is a subset of statistics)
|
||||
);
|
||||
|
||||
if ($pBase['cuFlags'] & PROFILER_CU_PROFILE)
|
||||
{
|
||||
// this parameter is _really_ strange .. probably still not doing this right
|
||||
$profile['source'] = $pBase['realm'] ? $pBase['sourceId'] : 0;
|
||||
|
||||
$profile['sourcename'] = $pBase['sourceName'];
|
||||
$profile['description'] = $pBase['description'];
|
||||
$profile['user'] = $pBase['user'];
|
||||
$profile['username'] = DB::Aowow()->selectCell('SELECT `username` FROM ?_account WHERE `id` = ?d', $pBase['user']);
|
||||
}
|
||||
|
||||
// custom profiles inherit this when copied from real char :(
|
||||
if ($pBase['realm'])
|
||||
{
|
||||
$profile['region'] = [$rData['region'], Lang::profiler('regions', $rData['region'])];
|
||||
$profile['battlegroup'] = [Profiler::urlize(Cfg::get('BATTLEGROUP')), Cfg::get('BATTLEGROUP')];
|
||||
$profile['realm'] = [Profiler::urlize($rData['name'], true), $rData['name']];
|
||||
}
|
||||
|
||||
// bookmarks
|
||||
if ($_ = DB::Aowow()->selectCol('SELECT accountId FROM ?_account_profiles WHERE profileId = ?d', $pBase['id']))
|
||||
$profile['bookmarks'] = $_;
|
||||
|
||||
// arena teams - [size(2|3|5) => name]; name gets urlized to use as link
|
||||
if ($at = DB::Aowow()->selectCol('SELECT type AS ARRAY_KEY, name FROM ?_profiler_arena_team at JOIN ?_profiler_arena_team_member atm ON atm.arenaTeamId = at.id WHERE atm.profileId = ?d', $pBase['id']))
|
||||
$profile['arenateams'] = $at;
|
||||
|
||||
// pets if hunter fields: [name:name, family:petFamily, npc:npcId, displayId:modelId, talents:talentString]
|
||||
if ($pets = DB::Aowow()->select('SELECT `name`, `family`, `npc`, `displayId`, CONCAT("$\"", `talents`, "\"") AS "talents" FROM ?_profiler_pets WHERE `owner` = ?d', $pBase['id']))
|
||||
$profile['pets'] = $pets;
|
||||
|
||||
// source for custom profiles; profileId => [name, ownerId, iconString(optional)]
|
||||
if ($customs = DB::Aowow()->select('SELECT id AS ARRAY_KEY, name, user, icon FROM ?_profiler_profiles WHERE sourceId = ?d AND sourceId <> id {AND (cuFlags & ?d) = 0}', $pBase['id'], User::isInGroup(U_GROUP_STAFF) ? DBSIMPLE_SKIP : PROFILER_CU_DELETED))
|
||||
{
|
||||
foreach ($customs as $id => $cu)
|
||||
{
|
||||
if (!$cu['icon'])
|
||||
unset($cu['icon']);
|
||||
|
||||
$profile['customs'][$id] = array_values($cu);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* $profile[]
|
||||
// CUSTOM
|
||||
'auras' => [], // custom list of buffs, debuffs [spellId]
|
||||
|
||||
// UNUSED
|
||||
'glyphs' => [], // provided list of already known glyphs (post cataclysm feature)
|
||||
*/
|
||||
|
||||
|
||||
// questId => [cat1, cat2]
|
||||
$profile['quests'] = [];
|
||||
if ($quests = DB::Aowow()->selectCol('SELECT `questId` FROM ?_profiler_completion_quests WHERE `id` = ?d', $pBase['id']))
|
||||
{
|
||||
$qList = new QuestList(array(['id', $quests], Cfg::get('SQL_LIMIT_NONE')));
|
||||
if (!$qList->error)
|
||||
foreach ($qList->iterate() as $id => $__)
|
||||
$profile['quests'][$id] = [$qList->getField('cat1'), $qList->getField('cat2')];
|
||||
}
|
||||
|
||||
// skillId => [value, max]
|
||||
$profile['skills'] = DB::Aowow()->select('SELECT `skillId` AS ARRAY_KEY, `value` AS "0", `max` AS "1" FROM ?_profiler_completion_skills WHERE `id` = ?d', $pBase['id']);
|
||||
|
||||
// factionId => amount
|
||||
$profile['reputation'] = DB::Aowow()->selectCol('SELECT `factionId` AS ARRAY_KEY, `standing` FROM ?_profiler_completion_reputation WHERE `id` = ?d', $pBase['id']);
|
||||
|
||||
// titleId => 1
|
||||
$profile['titles'] = DB::Aowow()->selectCol('SELECT `titleId` AS ARRAY_KEY, 1 FROM ?_profiler_completion_titles WHERE `id` = ?d', $pBase['id']);
|
||||
|
||||
// achievementId => js date object
|
||||
$profile['achievements'] = DB::Aowow()->selectCol('SELECT `achievementId` AS ARRAY_KEY, CONCAT("$new Date(", `date` * 1000, ")") FROM ?_profiler_completion_achievements WHERE `id` = ?d', $pBase['id']);
|
||||
|
||||
// just points
|
||||
$profile['achievementpoints'] = $profile['achievements'] ? DB::Aowow()->selectCell('SELECT SUM(`points`) FROM ?_achievement WHERE `id` IN (?a)', array_keys($profile['achievements'])) : 0;
|
||||
|
||||
// achievementId => counter
|
||||
$profile['statistics'] = DB::Aowow()->selectCol('SELECT `achievementId` AS ARRAY_KEY, `counter` FROM ?_profiler_completion_statistics WHERE `id` = ?d', $pBase['id']);
|
||||
|
||||
// achievementId => 1
|
||||
$profile['activity'] = DB::Aowow()->selectCol('SELECT `achievementId` AS ARRAY_KEY, 1 FROM ?_profiler_completion_statistics WHERE `id` = ?d AND `date` > ?d', $pBase['id'], time() - MONTH);
|
||||
|
||||
// spellId => 1
|
||||
$profile['spells'] = DB::Aowow()->selectCol('SELECT `spellId` AS ARRAY_KEY, 1 FROM ?_profiler_completion_spells WHERE `id` = ?d', $pBase['id']);
|
||||
|
||||
|
||||
$gItems = [];
|
||||
|
||||
$usedSlots = [];
|
||||
if ($this->_get['items'])
|
||||
{
|
||||
$phItems = new ItemList(array(['id', $this->_get['items']], ['slot', INVTYPE_NON_EQUIP, '!']));
|
||||
if (!$phItems->error)
|
||||
{
|
||||
$data = $phItems->getListviewData(ITEMINFO_JSON | ITEMINFO_SUBITEMS);
|
||||
foreach ($phItems->iterate() as $iId => $__)
|
||||
{
|
||||
$sl = $phItems->getField('slot');
|
||||
foreach (Profiler::$slot2InvType as $slot => $invTypes)
|
||||
{
|
||||
if (in_array($sl, $invTypes) && !in_array($slot, $usedSlots))
|
||||
{
|
||||
// get and apply inventory
|
||||
$gItems[$iId] = array(
|
||||
'name_'.Lang::getLocale()->json() => $phItems->getField('name', true),
|
||||
'quality' => $phItems->getField('quality'),
|
||||
'icon' => $phItems->getField('iconString'),
|
||||
'jsonequip' => $data[$iId]
|
||||
);
|
||||
$profile['inventory'][$slot] = [$iId, 0, 0, 0, 0, 0, 0, 0];
|
||||
|
||||
$usedSlots[] = $slot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($items = DB::Aowow()->select('SELECT * FROM ?_profiler_items WHERE id = ?d', $pBase['id']))
|
||||
{
|
||||
$itemz = new ItemList(array(['id', array_column($items, 'item')], Cfg::get('SQL_LIMIT_NONE')));
|
||||
if (!$itemz->error)
|
||||
{
|
||||
$data = $itemz->getListviewData(ITEMINFO_JSON | ITEMINFO_SUBITEMS);
|
||||
|
||||
foreach ($items as $i)
|
||||
{
|
||||
if ($itemz->getEntry($i['item']) && !in_array($i['slot'], $usedSlots))
|
||||
{
|
||||
// get and apply inventory
|
||||
$gItems[$i['item']] = array(
|
||||
'name_'.Lang::getLocale()->json() => $itemz->getField('name', true),
|
||||
'quality' => $itemz->getField('quality'),
|
||||
'icon' => $itemz->getField('iconString'),
|
||||
'jsonequip' => $data[$i['item']]
|
||||
);
|
||||
$profile['inventory'][$i['slot']] = [$i['item'], $i['subItem'], $i['permEnchant'], $i['tempEnchant'], $i['gem1'], $i['gem2'], $i['gem3'], $i['gem4']];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$buff = '';
|
||||
foreach ($gItems as $id => $item)
|
||||
$buff .= 'g_items.add('.$id.', '.Util::toJSON($item, JSON_NUMERIC_CHECK | JSON_UNESCAPED_UNICODE).");\n";
|
||||
|
||||
|
||||
// if ($au = $char->getField('auras'))
|
||||
// {
|
||||
// $auraz = new SpellList(array(['id', $char->getField('auras')], Cfg::get('SQL_LIMIT_NONE')));
|
||||
// $dataz = $auraz->getListviewData();
|
||||
// $modz = $auraz->getProfilerMods();
|
||||
|
||||
// // get and apply aura-mods
|
||||
// foreach ($dataz as $id => $data)
|
||||
// {
|
||||
// $mods = [];
|
||||
// if (!empty($modz[$id]))
|
||||
// {
|
||||
// foreach ($modz[$id] as $k => $v)
|
||||
// {
|
||||
// if (is_array($v))
|
||||
// $mods[] = $v;
|
||||
// else if ($str = @Game::$itemMods[$k])
|
||||
// $mods[$str] = $v;
|
||||
// }
|
||||
// }
|
||||
|
||||
// $buff .= 'g_spells.add('.$id.", {id:".$id.", name:'".Util::jsEscape(mb_substr($data['name'], 1))."', icon:'".$data['icon']."', callback:".Util::toJSON($mods)."});\n";
|
||||
// }
|
||||
// $buff .= "\n";
|
||||
// }
|
||||
|
||||
|
||||
// load available titles
|
||||
Util::loadStaticFile('p-titles-'.$pBase['gender'], $buff, true);
|
||||
|
||||
// add profile to buffer
|
||||
$buff .= "\n\n\$WowheadProfiler.registerProfile(".Util::toJSON($profile).");";
|
||||
|
||||
return $buff."\n";
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId>
|
||||
data: <mode> [string, tabName]
|
||||
return
|
||||
null
|
||||
*/
|
||||
protected function handlePurge() : void { } // removes completion data (as uploaded by the wowhead client) Just fail silently if someone triggers this manually
|
||||
|
||||
protected static function checkItemList($val) : array
|
||||
{
|
||||
// expecting item-list
|
||||
if (preg_match('/\d+(:\d+)*/', $val))
|
||||
return array_map('intVal', explode(':', $val));
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
protected static function checkUser(string $val) : string
|
||||
{
|
||||
if (User::isValidName($val))
|
||||
return $val;
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
protected static function checkTalentString(string $val) : string
|
||||
{
|
||||
if (preg_match('/^\d+$/', $val))
|
||||
return $val;
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
protected static function checkGlyphString(string $val) : string
|
||||
{
|
||||
if (preg_match('/^\d+(:\d+)*$/', $val))
|
||||
return $val;
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
@ -326,7 +326,7 @@ class PageTemplate
|
|||
{
|
||||
$result[] = "pr_setRegionRealm(\$WH.ge('fi').firstChild, '".$this->region."', '".$this->realm."');";
|
||||
|
||||
if ($this->filter->values['ra'])
|
||||
if (!empty($this->filter->values['ra']))
|
||||
$result[] = "pr_onChangeRace();";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -247,6 +247,14 @@ class Profiler
|
|||
return self::$realms;
|
||||
}
|
||||
|
||||
public static function getRegions() : array
|
||||
{
|
||||
self::getRealms();
|
||||
|
||||
// sort depends on encountered order in `logon`.`realmlist`. Is that a problem?
|
||||
return array_unique(array_column(self::$realms, 'region'));
|
||||
}
|
||||
|
||||
private static function queueInsert($realmId, $guid, $type, $localId)
|
||||
{
|
||||
if ($rData = DB::Aowow()->selectRow('SELECT `requestTime` AS "time", `status` FROM ?_profiler_sync WHERE `realm` = ?d AND `realmGUID` = ?d AND `type` = ?d AND `typeId` = ?d AND `status` <> ?d', $realmId, $guid, $type, $localId, PR_QUEUE_STATUS_WORKING))
|
||||
|
|
|
|||
|
|
@ -253,7 +253,8 @@ class ProfileListFilter extends Filter
|
|||
'minle' => [parent::V_RANGE, [1, MAX_LEVEL], false], // min level
|
||||
'maxle' => [parent::V_RANGE, [1, MAX_LEVEL], false], // max level
|
||||
'rg' => [parent::V_CALLBACK, 'cbRegionCheck', false], // region
|
||||
'sv' => [parent::V_CALLBACK, 'cbServerCheck', false], // server
|
||||
'bg' => [parent::V_EQUAL, null, false], // battlegroup - unsued here, but var expected by template
|
||||
'sv' => [parent::V_CALLBACK, 'cbServerCheck', false] // server
|
||||
);
|
||||
|
||||
public bool $useLocalList = false;
|
||||
|
|
|
|||
|
|
@ -1,258 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// menuId 5: Profiler g_initPath()
|
||||
// tabId 1: Tools g_initHeader()
|
||||
class ProfilePage extends GenericPage
|
||||
{
|
||||
use TrProfiler;
|
||||
|
||||
protected $gDataKey = true;
|
||||
protected $mode = CACHE_TYPE_PAGE;
|
||||
|
||||
protected $type = Type::PROFILE;
|
||||
|
||||
protected $tabId = 1;
|
||||
protected $path = [1, 5, 1];
|
||||
protected $tpl = 'profile';
|
||||
protected $scripts = array(
|
||||
[SC_JS_FILE, 'js/filters.js'],
|
||||
[SC_JS_FILE, 'js/TalentCalc.js'],
|
||||
[SC_JS_FILE, 'js/swfobject.js'],
|
||||
[SC_JS_FILE, 'js/profile_all.js'],
|
||||
[SC_JS_FILE, 'js/profile.js'],
|
||||
[SC_JS_FILE, 'js/Profiler.js'],
|
||||
[SC_CSS_FILE, 'css/talentcalc.css'],
|
||||
[SC_CSS_FILE, 'css/Profiler.css']
|
||||
);
|
||||
|
||||
protected $_get = array(
|
||||
'domain' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\Locale::tryFromDomain'],
|
||||
'new' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\GenericPage::checkEmptySet']
|
||||
);
|
||||
|
||||
private $isCustom = false;
|
||||
private $profile = null;
|
||||
private $subject = null;
|
||||
private $rnItr = 0;
|
||||
private $powerTpl = '$WowheadPower.registerProfile(%s, %d, %s);';
|
||||
|
||||
public function __construct($pageCall, $pageParam)
|
||||
{
|
||||
parent::__construct($pageCall, $pageParam);
|
||||
|
||||
if (!Cfg::get('PROFILER_ENABLE'))
|
||||
$this->error();
|
||||
|
||||
$params = array_map('urldecode', explode('.', $pageParam));
|
||||
if ($params[0])
|
||||
$params[0] = Profiler::urlize($params[0]);
|
||||
if (isset($params[1]))
|
||||
$params[1] = Profiler::urlize($params[1], true);
|
||||
|
||||
// temp locale
|
||||
if ($this->mode == CACHE_TYPE_TOOLTIP && $this->_get['domain'])
|
||||
Lang::load($this->_get['domain']);
|
||||
|
||||
if (count($params) == 1 && intval($params[0]))
|
||||
{
|
||||
// redundancy much?
|
||||
$this->subjectGUID = intval($params[0]);
|
||||
$this->profile = intval($params[0]);
|
||||
$this->isCustom = true; // until proven otherwise
|
||||
|
||||
$this->subject = new LocalProfileList(array(['id', intval($params[0])]));
|
||||
if ($this->subject->error)
|
||||
$this->notFound();
|
||||
|
||||
if (!$this->subject->isVisibleToUser())
|
||||
$this->notFound();
|
||||
|
||||
if (!$this->subject->isCustom())
|
||||
header('Location: '.$this->subject->getProfileUrl(), true, 302);
|
||||
}
|
||||
else if (count($params) == 3)
|
||||
{
|
||||
$this->getSubjectFromUrl($pageParam);
|
||||
if (!$this->subjectName)
|
||||
$this->notFound();
|
||||
|
||||
// names MUST be ucFirst. Since we don't expect partial matches, search this way
|
||||
$this->profile = $params;
|
||||
|
||||
// pending rename
|
||||
if (preg_match('/([^\-]+)-(\d+)/i', $this->subjectName, $m))
|
||||
{
|
||||
$this->subjectName = $m[1];
|
||||
$this->rnItr = $m[2];
|
||||
}
|
||||
|
||||
// 3 possibilities
|
||||
// 1) already synced to aowow
|
||||
if ($subject = DB::Aowow()->selectRow('SELECT id, realmGUID, cuFlags FROM ?_profiler_profiles WHERE realm = ?d AND realmGUID IS NOT NULL AND name = ? AND renameItr = ?d', $this->realmId, Util::ucFirst($this->subjectName), $this->rnItr))
|
||||
{
|
||||
$this->subjectGUID = $subject['id'];
|
||||
|
||||
if ($subject['cuFlags'] & PROFILER_CU_NEEDS_RESYNC)
|
||||
{
|
||||
$this->handleIncompleteData($params, $subject['realmGUID']);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->subject = new LocalProfileList(array(['id', $subject['id']]));
|
||||
if ($this->subject->error)
|
||||
$this->notFound();
|
||||
}
|
||||
// 2) not yet synced but exists on realm (and not a gm character)
|
||||
else if (!$this->rnItr && ($char = DB::Characters($this->realmId)->selectRow('SELECT c.guid AS realmGUID, c.name, c.race, c.class, c.level, c.gender, c.at_login, g.guildid AS guildGUID, IFNULL(g.name, "") AS guildName, IFNULL(gm.rank, 0) AS guildRank FROM characters c LEFT JOIN guild_member gm ON gm.guid = c.guid LEFT JOIN guild g ON g.guildid = gm.guildid WHERE c.name = ? AND level <= ?d AND (extra_flags & ?d) = 0', Util::ucFirst($this->subjectName), MAX_LEVEL, Profiler::CHAR_GMFLAGS)))
|
||||
{
|
||||
$char['realm'] = $this->realmId;
|
||||
$char['cuFlags'] = PROFILER_CU_NEEDS_RESYNC;
|
||||
|
||||
if ($char['at_login'] & 0x1)
|
||||
$char['renameItr'] = DB::Aowow()->selectCell('SELECT MAX(renameItr) FROM ?_profiler_profiles WHERE realm = ?d AND realmGUID IS NOT NULL AND name = ?', $this->realmId, $char['name']);
|
||||
|
||||
if ($char['guildGUID'])
|
||||
{
|
||||
// create empty guild if necessary to satisfy foreign keys
|
||||
$char['guild'] = DB::Aowow()->selectCell('SELECT id FROM ?_profiler_guild WHERE realm = ?d AND realmGUID = ?d', $this->realmId, $char['guildGUID']);
|
||||
if (!$char['guild'])
|
||||
$char['guild'] = DB::Aowow()->query('INSERT INTO ?_profiler_guild (realm, realmGUID, cuFlags, name) VALUES (?d, ?d, ?d, ?)', $this->realmId, $char['guildGUID'], PROFILER_CU_NEEDS_RESYNC, $char['guildName']);
|
||||
}
|
||||
|
||||
unset($char['guildGUID']);
|
||||
unset($char['guildName']);
|
||||
unset($char['at_login']);
|
||||
|
||||
// create entry from realm with enough basic info to disply tooltips
|
||||
DB::Aowow()->query('REPLACE INTO ?_profiler_profiles (?#) VALUES (?a)', array_keys($char), array_values($char));
|
||||
$this->subjectGUID = DB::Aowow()->selectCell('SELECT id FROM ?_profiler_profiles WHERE realm = ?d AND realmGUID = ?d', $this->realmId, $char['realmGUID']);
|
||||
|
||||
$this->handleIncompleteData($params, $char['realmGUID']);
|
||||
}
|
||||
// 3) does not exist at all
|
||||
else
|
||||
$this->notFound();
|
||||
}
|
||||
else if (($params && $params[0]) || !$this->_get['new'])
|
||||
$this->notFound();
|
||||
else if ($this->_get['new'])
|
||||
$this->mode = CACHE_TYPE_NONE;
|
||||
}
|
||||
|
||||
protected function generateContent()
|
||||
{
|
||||
if ($this->doResync)
|
||||
return;
|
||||
|
||||
// + .titles ?
|
||||
$this->addScript([SC_JS_FILE, '?data=enchants.gems.glyphs.itemsets.pets.pet-talents.quick-excludes.realms.statistics.weight-presets.achievements']);
|
||||
|
||||
// as demanded by the raid activity tracker
|
||||
$bossIds = array(
|
||||
/* Halion */
|
||||
/* ruby */ 39863,
|
||||
/* Valanar, Lana'thel, Saurfang, Festergut, Deathwisper, Marrowgar, Putricide, Rotface, Sindragosa, Valithria, Lich King */
|
||||
/* icc */ 37970, 37955, 37813, 36626, 36855, 36612, 36678, 36627, 36853, 36789, 36597,
|
||||
/* Jaraxxus, Anub'arak */
|
||||
/* toc */ 34780, 34564,
|
||||
/* Onyxia */
|
||||
/* ony */ 10184,
|
||||
/* Flame Levi, Ignis, Razorscale, XT-002, Kologarn, Auriaya, Freya, Hodir, Mimiron, Thorim, Vezaxx, Yogg, Algalon */
|
||||
/* uld */ 33113, 33118, 33186, 33293, 32930, 33515, 32906, 32845, 33350, 32864, 33271, 33288, 32871,
|
||||
/* Anub, Faerlina, Maexxna, Noth, Heigan, Loatheb, Razuvious, Gothik, Patchwerk, Grobbulus, Gluth, Thaddius, Sapphiron, Kel'Thuzad */
|
||||
/* nax */ 15956, 15953, 15952, 15954, 15936, 16011, 16061, 16060, 16028, 15931, 15932, 15928, 15989, 15990
|
||||
);
|
||||
$this->extendGlobalIds(Type::NPC, ...$bossIds);
|
||||
|
||||
// dummy title from dungeon encounter
|
||||
foreach (Lang::profiler('encounterNames') as $id => $name)
|
||||
$this->extendGlobalData([Type::NPC => [$id => ['name_'.Lang::getLocale()->json() => $name]]]);
|
||||
}
|
||||
|
||||
protected function generatePath()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected function generateTitle()
|
||||
{
|
||||
array_unshift($this->title, Util::ucFirst(Lang::game('profile')));
|
||||
}
|
||||
|
||||
protected function generateTooltip()
|
||||
{
|
||||
$id = $this->profile;
|
||||
if (!$this->isCustom)
|
||||
$id = "'".$this->profile[0].'.'.urlencode($this->profile[1]).'.'.urlencode($this->profile[2])."'";
|
||||
|
||||
$power = new \StdClass();
|
||||
if ($this->subject && !$this->subject->error && $this->subject->isVisibleToUser())
|
||||
{
|
||||
$n = $this->subject->getField('name');
|
||||
$l = $this->subject->getField('level');
|
||||
$r = $this->subject->getField('race');
|
||||
$c = $this->subject->getField('class');
|
||||
$g = $this->subject->getField('gender');
|
||||
|
||||
if ($this->isCustom)
|
||||
$n .= Lang::profiler('customProfile');
|
||||
else if ($_ = $this->subject->getField('title'))
|
||||
if ($title = (new TitleList(array(['id', $_])))->getField($g ? 'female' : 'male', true))
|
||||
$n = sprintf($title, $n);
|
||||
|
||||
$power->{'name_'.Lang::getLocale()->json()} = $n;
|
||||
$power->{'tooltip_'.Lang::getLocale()->json()} = $this->subject->renderTooltip();
|
||||
$power->icon = '$$WH.g_getProfileIcon('.$r.', '.$c.', '.$g.', '.$l.', \''.$this->subject->getIcon().'\')';
|
||||
}
|
||||
|
||||
return sprintf($this->powerTpl, $id, Lang::getLocale()->value, Util::toJSON($power, JSON_AOWOW_POWER));
|
||||
}
|
||||
|
||||
public function display(string $override = ''): never
|
||||
{
|
||||
if ($this->mode != CACHE_TYPE_TOOLTIP)
|
||||
parent::display($override);
|
||||
|
||||
// do not cache profile tooltips
|
||||
header(MIME_TYPE_JSON);
|
||||
die($this->generateTooltip());
|
||||
}
|
||||
|
||||
public function notFound(string $title = '', string $msg = '') : never
|
||||
{
|
||||
parent::notFound($title ?: Util::ucFirst(Lang::profiler('profiler')), $msg ?: Lang::profiler('notFound', 'profile'));
|
||||
}
|
||||
|
||||
private function handleIncompleteData($params, $guid)
|
||||
{
|
||||
if ($this->mode == CACHE_TYPE_TOOLTIP) // enable tooltip display with basic data we just added
|
||||
{
|
||||
$this->subject = new LocalProfileList(array(['id', $this->subjectGUID]), ['sv' => $params[1]]);
|
||||
if ($this->subject->error)
|
||||
$this->notFound();
|
||||
|
||||
$this->profile = $params;
|
||||
}
|
||||
else // display empty page and queue status
|
||||
{
|
||||
$this->mode = CACHE_TYPE_NONE;
|
||||
|
||||
// queue full fetch
|
||||
if ($newId = Profiler::scheduleResync(Type::PROFILE, $this->realmId, $guid))
|
||||
{
|
||||
$this->doResync = ['profile', $newId];
|
||||
$this->initialSync();
|
||||
}
|
||||
else // todo: base info should have been created in __construct .. why are we here..?
|
||||
header('Location: ?profiles='.$params[0].'.'.$params[1].'&filter=na='.Util::ucFirst($this->subjectName).';ex=on');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class ProfilerPage extends GenericPage
|
||||
{
|
||||
protected $path = [1, 5];
|
||||
protected $tabId = 1;
|
||||
protected $tpl = 'profiler';
|
||||
protected $gDataKey = true;
|
||||
protected $scripts = array(
|
||||
[SC_JS_FILE, 'js/profile_all.js'],
|
||||
[SC_JS_FILE, 'js/profile.js'],
|
||||
[SC_CSS_FILE, 'css/Profiler.css']
|
||||
);
|
||||
|
||||
public function __construct($pageCall, $pageParam)
|
||||
{
|
||||
parent::__construct($pageCall, $pageParam);
|
||||
|
||||
if (!Cfg::get('PROFILER_ENABLE'))
|
||||
$this->error();
|
||||
}
|
||||
|
||||
protected function generateContent()
|
||||
{
|
||||
$this->addScript([SC_JS_FILE, '?data=realms']);
|
||||
}
|
||||
|
||||
protected function generatePath() { }
|
||||
|
||||
protected function generateTitle()
|
||||
{
|
||||
array_unshift($this->title, Util::ucFirst(Lang::profiler('profiler')));
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
@ -1,199 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// menuId 5: Profiler g_initPath()
|
||||
// tabId 1: Tools g_initHeader()
|
||||
class ProfilesPage extends GenericPage
|
||||
{
|
||||
use TrProfiler;
|
||||
|
||||
protected $filterObj = null;
|
||||
|
||||
protected $subCat = '';
|
||||
protected $lvTabs = [];
|
||||
protected $roster = 0; // $_GET['roster'] = 1|2|3|4 .. 2,3,4 arenateam-size (4 => 5-man), 1 guild .. it puts a resync button on the lv...
|
||||
|
||||
protected $type = Type::PROFILE;
|
||||
|
||||
protected $tabId = 1;
|
||||
protected $path = [1, 5, 0];
|
||||
protected $tpl = 'profiles';
|
||||
protected $scripts = array(
|
||||
[SC_JS_FILE, 'js/filters.js'],
|
||||
[SC_JS_FILE, 'js/profile_all.js'],
|
||||
[SC_JS_FILE, 'js/profile.js'],
|
||||
[SC_CSS_FILE, 'css/Profiler.css']
|
||||
);
|
||||
|
||||
protected $_get = ['filter' => ['filter' => FILTER_UNSAFE_RAW]];
|
||||
|
||||
public function __construct($pageCall, $pageParam)
|
||||
{
|
||||
$this->getSubjectFromUrl($pageParam);
|
||||
|
||||
parent::__construct($pageCall, $pageParam);
|
||||
|
||||
if (!Cfg::get('PROFILER_ENABLE'))
|
||||
$this->error();
|
||||
|
||||
$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 characters WHERE deleteInfos_Name IS NULL AND level <= ?d AND (extra_flags & ?) = 0', MAX_LEVEL, Profiler::CHAR_GMFLAGS);
|
||||
$realms[] = $idx;
|
||||
}
|
||||
|
||||
$this->filterObj = new ProfileListFilter($this->_get['filter'] ?? '', ['realms' => $realms]);
|
||||
|
||||
$this->name = Util::ucFirst(Lang::game('profiles'));
|
||||
$this->subCat = $pageParam ? '='.$pageParam : '';
|
||||
}
|
||||
|
||||
protected function generateTitle()
|
||||
{
|
||||
if ($this->realm)
|
||||
array_unshift($this->title, $this->realm,/* Cfg::get('BATTLEGROUP'),*/ Lang::profiler('regions', $this->region), Lang::game('profiles'));
|
||||
else if ($this->region)
|
||||
array_unshift($this->title, Lang::profiler('regions', $this->region), Lang::game('profiles'));
|
||||
else
|
||||
array_unshift($this->title, Lang::game('profiles'));
|
||||
}
|
||||
|
||||
protected function generateContent()
|
||||
{
|
||||
$this->addScript([SC_JS_FILE, '?data=weight-presets.realms']);
|
||||
|
||||
$conditions = [];
|
||||
|
||||
$this->filterObj->evalCriteria();
|
||||
|
||||
if ($_ = $this->filterObj->getConditions())
|
||||
$conditions[] = $_;
|
||||
|
||||
if (!$this->filterObj->useLocalList)
|
||||
{
|
||||
$conditions[] = ['deleteInfos_Name', null];
|
||||
$conditions[] = ['level', MAX_LEVEL, '<=']; // prevents JS errors
|
||||
$conditions[] = [['extra_flags', Profiler::CHAR_GMFLAGS, '&'], 0];
|
||||
}
|
||||
|
||||
if ($x = $this->filterObj->fiSetCriteria)
|
||||
{
|
||||
if ($r = array_intersect([9, 12, 15, 18], $x['cr']))
|
||||
if (count($r) == 1)
|
||||
$this->roster = (reset($r) - 6) / 3; // 1, 2, 3, or 4
|
||||
}
|
||||
|
||||
$tabData = array(
|
||||
'id' => 'characters',
|
||||
'hideCount' => 1,
|
||||
'visibleCols' => ['race', 'classs', 'level', 'talents', 'achievementpoints', 'gearscore'],
|
||||
'onBeforeCreate' => '$pr_initRosterListview' // puts a resync button on the lv
|
||||
);
|
||||
|
||||
$extraCols = $this->filterObj->fiExtraCols;
|
||||
if ($extraCols)
|
||||
{
|
||||
$xc = [];
|
||||
foreach ($extraCols as $idx => $col)
|
||||
if ($idx > 0)
|
||||
$xc[] = "\$Listview.funcBox.createSimpleCol('Skill' + ".$idx.", g_spell_skills[".$idx."], '7%', 'skill-' + ".$idx.")";
|
||||
|
||||
$tabData['extraCols'] = $xc;
|
||||
}
|
||||
|
||||
$miscParams = ['calcTotal' => true];
|
||||
if ($this->realm)
|
||||
$miscParams['sv'] = $this->realm;
|
||||
if ($this->region)
|
||||
$miscParams['rg'] = $this->region;
|
||||
if ($_ = $this->filterObj->extraOpts)
|
||||
$miscParams['extraOpts'] = $_;
|
||||
|
||||
if ($this->filterObj->useLocalList)
|
||||
$profiles = new LocalProfileList($conditions, $miscParams);
|
||||
else
|
||||
$profiles = new RemoteProfileList($conditions, $miscParams);
|
||||
|
||||
if (!$profiles->error)
|
||||
{
|
||||
// init these chars on our side and get local ids
|
||||
if (!$this->filterObj->useLocalList)
|
||||
$profiles->initializeLocalEntries();
|
||||
|
||||
$addInfoMask = PROFILEINFO_CHARACTER;
|
||||
|
||||
// init roster-listview
|
||||
// $_GET['roster'] = 1|2|3|4 originally supplemented this somehow .. 2,3,4 arenateam-size (4 => 5-man), 1 guild
|
||||
if ($this->roster == 1 && !$profiles->hasDiffFields('guild') && $profiles->getField('guild'))
|
||||
{
|
||||
$tabData['roster'] = $this->roster;
|
||||
$tabData['visibleCols'][] = 'guildrank';
|
||||
$tabData['hiddenCols'][] = 'guild';
|
||||
|
||||
$this->roster = Lang::profiler('guildRoster', [$profiles->getField('guildname')]);
|
||||
}
|
||||
else if ($this->roster && !$profiles->hasDiffFields('arenateam') && $profiles->getField('arenateam'))
|
||||
{
|
||||
$tabData['roster'] = $this->roster;
|
||||
$tabData['visibleCols'][] = 'rating';
|
||||
|
||||
$addInfoMask |= PROFILEINFO_ARENA;
|
||||
$this->roster = Lang::profiler('arenaRoster', [$profiles->getField('arenateam')]);
|
||||
}
|
||||
else
|
||||
$this->roster = 0;
|
||||
|
||||
$tabData['data'] = array_values($profiles->getListviewData($addInfoMask, array_filter($extraCols, fn($x) => $x > 0, ARRAY_FILTER_USE_KEY)));
|
||||
|
||||
if ($sc = $this->filterObj->fiSetCriteria)
|
||||
if (in_array(10, $sc['cr']) && !in_array('guildrank', $tabData['visibleCols']))
|
||||
$tabData['visibleCols'][] = 'guildrank';
|
||||
|
||||
// create note if search limit was exceeded
|
||||
if ($this->filterObj->query && $profiles->getMatches() > Cfg::get('SQL_LIMIT_DEFAULT'))
|
||||
{
|
||||
$tabData['note'] = sprintf(Util::$tryFilteringString, 'LANG.lvnote_charactersfound2', $this->sumSubjects, $profiles->getMatches());
|
||||
$tabData['_truncated'] = 1;
|
||||
}
|
||||
else if ($profiles->getMatches() > Cfg::get('SQL_LIMIT_DEFAULT'))
|
||||
$tabData['note'] = sprintf(Util::$tryFilteringString, 'LANG.lvnote_charactersfound', $this->sumSubjects, 0);
|
||||
|
||||
if ($this->filterObj->useLocalList)
|
||||
{
|
||||
if (!empty($tabData['note']))
|
||||
$tabData['note'] .= ' + "<br><span class=\'r1 icon-report\'>'.Lang::profiler('complexFilter').'</span>"';
|
||||
else
|
||||
$tabData['note'] = '<span class="r1 icon-report">'.Lang::profiler('complexFilter').'</span>';
|
||||
}
|
||||
|
||||
if ($this->filterObj->error)
|
||||
$tabData['_errors'] = '$1';
|
||||
}
|
||||
else
|
||||
$this->roster = 0;
|
||||
|
||||
|
||||
$this->lvTabs[] = [ProfileList::$brickFile, $tabData];
|
||||
}
|
||||
|
||||
protected function postCache()
|
||||
{
|
||||
// sort for dropdown-menus
|
||||
Lang::sort('game', 'cl');
|
||||
Lang::sort('game', 'ra');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
@ -900,7 +900,7 @@ function Profiler() {
|
|||
|
||||
function _updateDefaultIcon() {
|
||||
var icon = $WH.g_getProfileIcon(_profile.race, _profile.classs, _profile.gender, _profile.level, 0, 'large');
|
||||
// aowow - and another bugged icon request
|
||||
// aowow - see profile=avatar endpoint for explanation
|
||||
// var icon = $WH.g_getProfileIcon(_profile.race, _profile.classs, _profile.gender, _profile.level, _profile.source, 'large');
|
||||
|
||||
if (!_profile.icon) {
|
||||
|
|
|
|||
|
|
@ -593,7 +593,7 @@ var PageTemplate = new function()
|
|||
{
|
||||
className: (character.pinned ? 'icon-star-right ' : '') + 'c' + character.classs,
|
||||
// tinyIcon: $WH.g_getProfileIcon(character.race, character.classs, character.gender, character.level, character.id, 'tiny')
|
||||
// aowow: profileId should not be necessary here
|
||||
// aowow - see profile=avatar endpoint for explanation
|
||||
tinyIcon: $WH.g_getProfileIcon(character.race, character.classs, character.gender, character.level, 0, 'tiny')
|
||||
}];
|
||||
|
||||
|
|
@ -16037,7 +16037,7 @@ Listview.templates = {
|
|||
i.style.borderRight = 'none';
|
||||
|
||||
// $WH.ae(i, Icon.create($WH.g_getProfileIcon(profile.race, profile.classs, profile.gender, profile.level, profile.icon ? profile.icon : profile.id, 'medium'), 1, null, this.getItemLink(profile)));
|
||||
// aowow . i dont know .. i dont know... char icon requests are strange
|
||||
// aowow - see profile=avatar endpoint for explanation
|
||||
var ic = Icon.create($WH.g_getProfileIcon(profile.race, profile.classs, profile.gender, profile.level, profile.icon ? profile.icon : 0, 'medium'), 1, null, this.getItemLink(profile));
|
||||
// aowow - custom
|
||||
if (profile.captain) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
<?php namespace Aowow; ?>
|
||||
|
||||
<?php $this->brick('header'); ?>
|
||||
<?php
|
||||
namespace Aowow\Template;
|
||||
|
||||
$this->brick('header');
|
||||
?>
|
||||
<div class="main" id="main">
|
||||
<div class="main-precontents" id="main-precontents"></div>
|
||||
<div class="main-contents" id="main-contents">
|
||||
|
|
@ -15,7 +16,7 @@
|
|||
<div id="profilah-generic"></div>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
var profilah = new Profiler();
|
||||
profilah.initialize('profilah-generic', { id: <?=$this->subjectGUID; ?> });
|
||||
profilah.initialize('profilah-generic', { id: <?=$this->typeId; ?> });
|
||||
pr_setRegionRealm($WH.gE($WH.ge('topbar'), 'form')[0], '<?=$this->region; ?>', '<?=$this->realm; ?>');
|
||||
//]]></script>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
<?php namespace Aowow; ?>
|
||||
<?php
|
||||
namespace Aowow\Template;
|
||||
|
||||
<?php $this->brick('header'); ?>
|
||||
use \Aowow\Lang;
|
||||
|
||||
$this->brick('header');
|
||||
?>
|
||||
<div class="main" id="main">
|
||||
<div class="main-precontents" id="main-precontents"></div>
|
||||
<div class="main-contents" id="main-contents">
|
||||
|
|
@ -23,17 +26,19 @@
|
|||
|
||||
<div class="profiler-home">
|
||||
<div>
|
||||
<h2><?=Util::ucFirst(Lang::main('name')).Lang::main('colon'); ?></h2>
|
||||
<h2><?=$this->ucFirst(Lang::main('name')).Lang::main('colon'); ?></h2>
|
||||
<input type="text" name="na" value="" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2><?=Lang::profiler('region').Lang::main('colon'); ?></h2>
|
||||
<?php
|
||||
foreach (Util::$regions as $idx => $n):
|
||||
echo ' <input type="radio" name="rg" value="'.$n.'" id="rg-'.($idx+1).'" '.(!$idx ? 'checked="checked" ' : '').'/><label for="rg-'.($idx+1).'" class="profiler-button profiler-option-left'.(!$idx ? ' selected' : '').'"><em><i>'.Lang::profiler('regions', $n).'</i></em></label>';
|
||||
endforeach;
|
||||
?>
|
||||
<?=$this->makeRadiosList('rg', $this->regions, $this->rg, 24, function (&$v, $k, &$attribs) {
|
||||
$attribs = ['class' => 'profiler-button profiler-option-left'];
|
||||
$v = '<em><i>'.$v.'</i></em>';
|
||||
if ($k == $this->rg)
|
||||
$attribs['class'] .= ' selected';
|
||||
return true;
|
||||
}); ?>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
<?php namespace Aowow; ?>
|
||||
|
||||
<?php
|
||||
$this->brick('header');
|
||||
$f = $this->filterObj->values // shorthand
|
||||
?>
|
||||
namespace Aowow\Template;
|
||||
|
||||
use \Aowow\Lang;
|
||||
|
||||
$this->brick('header');
|
||||
$f = $this->filter->values; // shorthand
|
||||
?>
|
||||
<div class="main" id="main">
|
||||
<div class="main-precontents" id="main-precontents"></div>
|
||||
<div class="main-contents" id="main-contents">
|
||||
|
|
@ -12,74 +13,64 @@ $f = $this->filterObj->values // shorthand
|
|||
<?php
|
||||
$this->brick('announcement');
|
||||
|
||||
$this->brick('pageTemplate', ['fiQuery' => $this->filterObj->query, 'fiMenuItem' => [2]]);
|
||||
$this->brick('pageTemplate', ['fiQuery' => $this->filter->query, 'fiMenuItem' => array_slice($this->pageTemplate['breadcrumb'], 0, 3)]);
|
||||
|
||||
# for some arcane reason a newline (\n) means, the first childNode is a text instead of the form for the following div
|
||||
# pr_setRegionRealm($WH.ge('fi').firstChild, realm, region) - never have \n\s before <form>, it will become firstChild (a text node)
|
||||
?>
|
||||
<div id="fi" style="display: <?=($this->filterObj->query ? 'block' : 'none'); ?>;"><form
|
||||
<div id="fi" style="display: <?=($this->filter->query ? 'block' : 'none'); ?>;"><form
|
||||
action="?filter=profiles<?=$this->subCat; ?>" method="post" name="fi" onsubmit="return fi_submit(this)" onreset="return fi_reset(this)">
|
||||
<div class="text">
|
||||
<?php
|
||||
$this->brick('headIcons');
|
||||
|
||||
$this->brick('redButtons');
|
||||
?>
|
||||
<h1><?=$this->h1; ?></h1>
|
||||
</div>
|
||||
<div class="rightpanel">
|
||||
<div style="float: left"><?=Util::ucFirst(Lang::game('class')).Lang::main('colon'); ?></div>
|
||||
<div style="float: left"><?=$this->ucFirst(Lang::game('class')).Lang::main('colon'); ?></div>
|
||||
<small><a href="javascript:;" onclick="document.forms['fi'].elements['cl[]'].selectedIndex = -1; return false" onmousedown="return false"><?=Lang::main('clear'); ?></a></small>
|
||||
<div class="clear"></div>
|
||||
<select name="cl[]" size="7" multiple="multiple" class="rightselect" style="background-color: #181818">
|
||||
<?php
|
||||
foreach (Lang::game('cl') as $k => $str):
|
||||
if ($str):
|
||||
echo ' <option class="c'.$k.'" value="'.$k.'"'.(isset($f['cl']) && in_array($k, (array)$f['cl']) ? ' selected' : null).'>'.$str."</option>\n";
|
||||
endif;
|
||||
endforeach;
|
||||
?>
|
||||
<?=$this->makeOptionsList(Lang::game('cl') , $f['cl'], 28, fn($v, $k, &$e) => $v && ($e = ['class' => 'c'.$k])); ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="rightpanel2">
|
||||
<div style="float: left"><?=Util::ucFirst(Lang::game('race')).Lang::main('colon'); ?></div>
|
||||
<div style="float: left"><?=$this->ucFirst(Lang::game('race')).Lang::main('colon'); ?></div>
|
||||
<small><a href="javascript:;" onclick="document.forms['fi'].elements['ra[]'].selectedIndex = -1; pr_onChangeRace(); return false" onmousedown="return false"><?=Lang::main('clear'); ?></a></small>
|
||||
<div class="clear"></div>
|
||||
<select name="ra[]" size="7" multiple="multiple" class="rightselect" onchange="pr_onChangeRace()">
|
||||
<?php
|
||||
foreach (Lang::game('ra') as $k => $str):
|
||||
if ($str && $k > 0):
|
||||
echo ' <option value="'.$k.'"'.(isset($f['ra']) && in_array($k, (array)$f['ra']) ? ' selected' : null).'>'.$str."</option>\n";
|
||||
endif;
|
||||
endforeach;
|
||||
?>
|
||||
|
||||
<?=$this->makeOptionsList(Lang::game('ra') , $f['ra'], 28, fn($v, $k) => $v && $k > 0); ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><?=Util::ucFirst(Lang::main('name')).Lang::main('colon'); ?></td>
|
||||
<td><?=$this->ucFirst(Lang::main('name')).Lang::main('colon'); ?></td>
|
||||
<td colspan="3">
|
||||
<table><tr>
|
||||
<td> <input type="text" name="na" size="30" <?=(isset($f['na']) ? 'value="'.Util::htmlEscape($f['na']).'" ' : null); ?>/></td>
|
||||
<td> <input type="checkbox" name="ex" value="on" id="profile-ex" <?=(isset($f['ex']) ? 'checked="checked"' : null); ?>/></td>
|
||||
<td> <input type="text" name="na" size="30" <?=($f['na'] ? 'value="'.$this->escHTML($f['na']).'" ' : ''); ?>/></td>
|
||||
<td> <input type="checkbox" name="ex" value="on" id="profile-ex" <?=($f['ex'] ? 'checked="checked"' : ''); ?>/></td>
|
||||
<td><label for="profile-ex"><span class="tip" onmouseover="$WH.Tooltip.showAtCursor(event, LANG.tooltip_exactprofilesearch, 0, 0, 'q')" onmousemove="$WH.Tooltip.cursorUpdate(event)" onmouseout="$WH.Tooltip.hide()"><?=Lang::main('exactMatch'); ?></span></label></td>
|
||||
</tr></table>
|
||||
</td>
|
||||
</tr><tr>
|
||||
<td class="padded"><?=Lang::profiler('region').Lang::main('colon'); ?></td>
|
||||
<td class="padded"> <select name="rg" onchange="pr_onChangeRegion(this.form, null, null)">
|
||||
<option></option>
|
||||
<?php
|
||||
foreach (array_unique(array_column(Profiler::getRealms(), 'region')) as $rg):
|
||||
echo " <option value=\"".$rg."\">".Lang::profiler('regions', $rg)."</option>\n";
|
||||
endforeach;
|
||||
?>
|
||||
<option></option>
|
||||
<?=$this->makeOptionsList($this->regions, $f['rg'], 32); ?>
|
||||
</select> </td>
|
||||
<td style="width:50px;" class="padded"> <?=Lang::profiler('realm').Lang::main('colon'); ?></td>
|
||||
<td class="padded"> <select name="sv"><option></option></select><input type="hidden" name="bg" value="<?=(isset($f['bg']) ? Util::htmlEscape($f['bg']) : null); ?>" /></td>
|
||||
<td class="padded"> <select name="sv"><option></option></select><input type="hidden" name="bg" value="<?=($f['bg'] ? $this->escHTML($f['bg']) : ''); ?>" /></td>
|
||||
</tr><tr>
|
||||
<td class="padded"><?=Lang::main('side').Lang::main('colon'); ?></td>
|
||||
<td class="padded" style="width:80px;"> <select name="si">
|
||||
<option></option>
|
||||
<option value="1"<?=(!empty($f['si']) && $f['si'] == 1 ? ' selected' : null);?>><?=Lang::game('si', 1); ?></option>
|
||||
<option value="2"<?=(!empty($f['si']) && $f['si'] == 2 ? ' selected' : null);?>><?=Lang::game('si', 2); ?></option>
|
||||
<?=$this->makeOptionsList(Lang::game('si'), $f['si'], 32, fn($v, $k) => in_array($k, [SIDE_ALLIANCE, SIDE_HORDE])); ?>
|
||||
</select></td>
|
||||
<td class="padded"> <?=Lang::game('level').Lang::main('colon'); ?></td>
|
||||
<td class="padded"> <input type="text" name="minle" maxlength="3" class="smalltextbox" <?=(isset($f['minle']) ? 'value="'.$f['minle'].'" ' : null); ?>/> - <input type="text" name="maxle" maxlength="3" class="smalltextbox" <?=(isset($f['maxle']) ? 'value="'.$f['maxle'].'" ' : null); ?>/></td>
|
||||
<td class="padded"> <input type="text" name="minle" maxlength="3" class="smalltextbox" <?=($f['minle'] ? 'value="'.$f['minle'].'" ' : ''); ?>/> - <input type="text" name="maxle" maxlength="3" class="smalltextbox" <?=($f['maxle'] ? 'value="'.$f['maxle'].'" ' : ''); ?>/></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
|
@ -87,7 +78,7 @@ endforeach;
|
|||
<div><a href="javascript:;" id="fi_addcriteria" onclick="fi_addCriterion(this); return false"><?=Lang::main('addFilter'); ?></a></div>
|
||||
|
||||
<div class="padded2">
|
||||
<?=Lang::main('match').Lang::main('colon'); ?><input type="radio" name="ma" value="" id="ma-0" <?=(!isset($f['ma']) ? 'checked="checked" ' : null); ?>/><label for="ma-0"><?=Lang::main('allFilter'); ?></label><input type="radio" name="ma" value="1" id="ma-1" <?=(isset($f['ma']) ? 'checked="checked" ' : null); ?>/><label for="ma-1"><?=Lang::main('oneFilter'); ?></label>
|
||||
<?=Lang::main('match'); ?><input type="radio" name="ma" value="" id="ma-0" <?=(!$f['ma'] ? 'checked="checked" ' : ''); ?>/><label for="ma-0"><?=Lang::main('allFilter'); ?></label><input type="radio" name="ma" value="1" id="ma-1" <?=($f['ma'] ? 'checked="checked" ' : ''); ?>/><label for="ma-1"><?=Lang::main('oneFilter'); ?></label>
|
||||
</div>
|
||||
|
||||
<div class="clear"></div>
|
||||
|
|
@ -112,7 +103,7 @@ endforeach;
|
|||
?>
|
||||
</div>
|
||||
|
||||
<?php $this->brick('filter'); ?>
|
||||
<?=$this->renderFilter(12); ?>
|
||||
|
||||
<?php $this->brick('lvTabs'); ?>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue