Template/Update (Part 46 - V)
* account management rework: Avatar functionality * show avatar at comments (beckported, because no forums)
This commit is contained in:
parent
258ac19f0a
commit
1d5539b362
24 changed files with 839 additions and 58 deletions
|
|
@ -14,12 +14,13 @@ class AccountBaseResponse extends TemplateResponse
|
|||
protected array $scripts = [[SC_JS_FILE, 'js/account.js']];
|
||||
|
||||
// display status of executed step (forwarding back to this page)
|
||||
public ?array $generalMessage = null;
|
||||
public ?array $emailMessage = null;
|
||||
public ?array $usernameMessage = null;
|
||||
public ?array $passwordMessage = null;
|
||||
public ?array $communityMessage = null;
|
||||
public ?array $avatarMessage = null;
|
||||
public ?array $generalMessage = null;
|
||||
public ?array $emailMessage = null;
|
||||
public ?array $usernameMessage = null;
|
||||
public ?array $passwordMessage = null;
|
||||
public ?array $communityMessage = null;
|
||||
public ?array $avatarMessage = null;
|
||||
public ?array $premiumborderMessage = null;
|
||||
|
||||
// form fields
|
||||
public int $modelrace = 0;
|
||||
|
|
@ -36,6 +37,7 @@ class AccountBaseResponse extends TemplateResponse
|
|||
public int $customicon = 0;
|
||||
public array $customicons = [];
|
||||
public bool $premium = false;
|
||||
public int $reputation = 0;
|
||||
public ?Listview $avatarManager = null;
|
||||
|
||||
public ?array $bans;
|
||||
|
|
@ -130,7 +132,7 @@ class AccountBaseResponse extends TemplateResponse
|
|||
$this->avMode = $user['avatar'];
|
||||
|
||||
// status [reviewing, ok, rejected]? (only 2: rejected processed in js)
|
||||
if (User::isPremium() && ($cuAvatars = DB::Aowow()->select('SELECT `id`, `name`, `current`, `size`, `status`, `when` FROM ?_account_avatars WHERE `userId` = ?d AND `status` > 0', User::$id)))
|
||||
if (User::isPremium() && ($cuAvatars = DB::Aowow()->select('SELECT `id`, `name`, `current`, `size`, `status`, `when` FROM ?_account_avatars WHERE `userId` = ?d', User::$id)))
|
||||
{
|
||||
array_walk($cuAvatars, function (&$x) {
|
||||
$x['when'] *= 1000; // uploaded timestamp expected as msec for some reason
|
||||
|
|
@ -139,7 +141,7 @@ class AccountBaseResponse extends TemplateResponse
|
|||
});
|
||||
|
||||
foreach ($cuAvatars as $a)
|
||||
if ($a['status'] != 2)
|
||||
if ($a['status'] != AvatarMgr::STATUS_REJECTED)
|
||||
$this->customicons[$a['id']] = $a['name'];
|
||||
|
||||
// TODO - replace with array_find in PHP 8.4
|
||||
|
|
@ -154,6 +156,8 @@ class AccountBaseResponse extends TemplateResponse
|
|||
if (!$this->premium)
|
||||
return;
|
||||
|
||||
$this->reputation = User::getReputation();
|
||||
|
||||
// Avatar Manager
|
||||
$this->avatarManager = new Listview([
|
||||
'template' => 'avatar',
|
||||
|
|
@ -161,11 +165,12 @@ class AccountBaseResponse extends TemplateResponse
|
|||
'name' => '$LANG.tab_avatars',
|
||||
'parent' => 'avatar-manage',
|
||||
'hideNav' => 1 | 2, // top | bottom
|
||||
'data' => $cuAvatars ?? []
|
||||
'data' => $cuAvatars ?? [],
|
||||
'note' => Lang::account('avatarSlots', [count($this->customicons), Cfg::get('acc_max_avatar_uploads')])
|
||||
]);
|
||||
|
||||
// Premium Border Selector
|
||||
// ???
|
||||
// solved by js
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
47
endpoints/account/delete-icon.php
Normal file
47
endpoints/account/delete-icon.php
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed via form button on user settings page
|
||||
*/
|
||||
|
||||
class AccountDeleteiconResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
protected int $requiredUserGroup = U_GROUP_PREMIUM_PERMISSIONS;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT]
|
||||
);
|
||||
|
||||
/*
|
||||
* response not evaluated
|
||||
*/
|
||||
protected function generate() : void
|
||||
{
|
||||
if (User::isBanned() || !$this->assertPOST('id'))
|
||||
return;
|
||||
|
||||
// non-int > error
|
||||
$selected = DB::Aowow()->selectCell('SELECT `current` FROM ?_account_avatars WHERE `id` = ?d AND `userId` = ?d', $this->_post['id'], User::$id);
|
||||
if ($selected === null || $selected === false)
|
||||
return;
|
||||
|
||||
DB::Aowow()->query('DELETE FROM ?_account_avatars WHERE `id` = ?d AND `userId` = ?d', $this->_post['id'], User::$id);
|
||||
|
||||
// if deleted avatar is also currently selected, unset
|
||||
if ($selected)
|
||||
DB::Aowow()->query('UPDATE ?_account SET `avatar` = 0 WHERE `id` = ?d', User::$id);
|
||||
|
||||
$path = sprintf('static/uploads/avatars/%d.jpg', $this->_post['id']);
|
||||
if (!unlink($path))
|
||||
trigger_error('AccountDeleteiconResponse - failed to delete file: '.$path, E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
108
endpoints/account/forum-avatar.php
Normal file
108
endpoints/account/forum-avatar.php
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed via form submit on user settings page
|
||||
*/
|
||||
|
||||
class AccountForumavatarResponse extends TextResponse
|
||||
{
|
||||
protected ?string $redirectTo = '?account#community';
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
// called via form submit
|
||||
protected array $expectedPOST = array(
|
||||
'avatar' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 0, 'max_range' => 2 ]],
|
||||
'wowicon' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => '/^[[:print:]]+$/' ]], // file name can have \W chars: inv_misc_fork&knife, achievement_dungeon_drak'tharon_heroic
|
||||
'customicon' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 1 ]]
|
||||
);
|
||||
// called via ajax
|
||||
protected array $expectedGET = array(
|
||||
'avatar' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 2, 'max_range' => 2]],
|
||||
'customicon' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 1 ]]
|
||||
);
|
||||
|
||||
private bool $success = false;
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (User::isBanned())
|
||||
return;
|
||||
|
||||
$msg = match ($this->_post['avatar'] ?? $this->_get['avatar'])
|
||||
{
|
||||
0 => $this->unset(), // none
|
||||
1 => $this->fromIcon(), // wow icon
|
||||
2 => $this->fromUpload(!$this->_get['avatar']), // custom icon (premium feature)
|
||||
default => Lang::main('genericError')
|
||||
};
|
||||
|
||||
if ($msg)
|
||||
$_SESSION['msg'] = ['avatar', $this->success, $msg];
|
||||
}
|
||||
|
||||
private function unset() : string
|
||||
{
|
||||
$x = DB::Aowow()->query('UPDATE ?_account SET `avatar` = 0 WHERE `id` = ?d', User::$id);
|
||||
if ($x === null || $x === false)
|
||||
return Lang::main('genericError');
|
||||
|
||||
$this->success = true;
|
||||
|
||||
return Lang::account('updateMessage', $x === 0 ? 'avNoChange' : 'avSuccess');
|
||||
}
|
||||
|
||||
private function fromIcon() : string
|
||||
{
|
||||
if (!$this->assertPOST('wowicon'))
|
||||
return Lang::main('intError');
|
||||
|
||||
$icon = strtolower(trim($this->_post['wowicon']));
|
||||
|
||||
if (!DB::Aowow()->selectCell('SELECT 1 FROM ?_icons WHERE `name` = ?', $icon))
|
||||
return Lang::account('updateMessage', 'avNotFound');
|
||||
|
||||
$x = DB::Aowow()->query('UPDATE ?_account SET `avatar` = 1, `wowicon` = ? WHERE `id` = ?d', strtolower($icon), User::$id);
|
||||
if ($x === null || $x === false)
|
||||
return Lang::main('genericError');
|
||||
|
||||
$this->success = true;
|
||||
|
||||
$msg = Lang::account('updateMessage', $x === 0 ? 'avNoChange' : 'avSuccess');
|
||||
if (($qty = DB::Aowow()->selectCell('SELECT COUNT(1) FROM ?_account WHERE `wowicon` = ?', $icon)) > 1)
|
||||
$msg .= ' '.Lang::account('updateMessage', 'avNthUser', [$qty]);
|
||||
else
|
||||
$msg .= ' '.Lang::account('updateMessage', 'av1stUser');
|
||||
|
||||
return $msg;
|
||||
}
|
||||
|
||||
protected function fromUpload(bool $viaPOST) : string
|
||||
{
|
||||
if (!User::isPremium())
|
||||
return Lang::main('genericError');
|
||||
|
||||
if (($viaPOST && !$this->assertPOST('customicon')) || (!$viaPOST && !$this->assertGET('customicon')))
|
||||
return Lang::main('intError');
|
||||
|
||||
$customIcon = $this->_post['customicon'] ?? $this->_get['customicon'];
|
||||
|
||||
$x = DB::Aowow()->query('UPDATE ?_account_avatars SET `current` = IF(`id` = ?d, 1, 0) WHERE `userId` = ?d AND `status` <> ?d', $customIcon, User::$id, AvatarMgr::STATUS_REJECTED);
|
||||
if (!is_int($x))
|
||||
return Lang::main('genericError');
|
||||
|
||||
if (!is_int(DB::Aowow()->query('UPDATE ?_account SET `avatar` = 2 WHERE `id` = ?d', User::$id)))
|
||||
return Lang::main('intError');
|
||||
|
||||
$this->success = true;
|
||||
|
||||
return Lang::account('updateMessage', $x === 0 ? 'avNoChange' : 'avSuccess');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
41
endpoints/account/premium-border.php
Normal file
41
endpoints/account/premium-border.php
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed via form submit on user settings page
|
||||
*/
|
||||
|
||||
class AccountPremiumborderResponse extends TextResponse
|
||||
{
|
||||
protected ?string $redirectTo = '?account#premium';
|
||||
protected bool $requiresLogin = true;
|
||||
protected int $requiredUserGroup = U_GROUP_PREMIUM_PERMISSIONS;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'avatarborder' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 0, 'max_range' => 4]],
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (User::isBanned())
|
||||
return;
|
||||
|
||||
if (!$this->assertPOST('avatarborder'))
|
||||
return;
|
||||
|
||||
$x = DB::Aowow()->query('UPDATE ?_account SET `avatarborder` = ?d WHERE `id` = ?d', $this->_post['avatarborder'], User::$id);
|
||||
if (!is_int($x))
|
||||
$_SESSION['msg'] = ['premiumborder', false, Lang::main('genericError')];
|
||||
else if (!$x)
|
||||
$_SESSION['msg'] = ['premiumborder', true, Lang::account('updateMessage', 'avNoChange')];
|
||||
else
|
||||
$_SESSION['msg'] = ['premiumborder', true, Lang::account('updateMessage', 'avSuccess')];
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
36
endpoints/account/rename-icon.php
Normal file
36
endpoints/account/rename-icon.php
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
* accessed via form button on user settings page
|
||||
*/
|
||||
|
||||
class AccountRenameiconResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
protected int $requiredUserGroup = U_GROUP_PREMIUM_PERMISSIONS;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'name' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' =>'/^[a-zA-Z][a-zA-Z0-9 ]{0,19}$/']]
|
||||
);
|
||||
|
||||
/*
|
||||
* response not evaluated
|
||||
*/
|
||||
protected function generate() : void
|
||||
{
|
||||
if (User::isBanned() || !$this->assertPOST('id', 'name'))
|
||||
return;
|
||||
|
||||
// regexp same as in account.js
|
||||
DB::Aowow()->query('UPDATE ?_account_avatars SET `name` = ? WHERE `id` = ?d AND `userId` = ?d', trim($this->_post['name']), $this->_post['id'], User::$id);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
88
endpoints/upload/image-complete.php
Normal file
88
endpoints/upload/image-complete.php
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class UploadImagecompleteResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
protected int $requiredUserGroup = U_GROUP_PREMIUM_PERMISSIONS;
|
||||
protected ?string $redirectTo = '?account#community';
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'coords' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkCoords']],
|
||||
);
|
||||
|
||||
public string $imgHash;
|
||||
public int $newId;
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
if (User::isBanned())
|
||||
$this->generate404();
|
||||
|
||||
parent::__construct($pageParam);
|
||||
|
||||
if (!preg_match('/^upload=image-complete&(\d+)\.(\w{16})$/i', $_SERVER['QUERY_STRING'] ?? '', $m, PREG_UNMATCHED_AS_NULL))
|
||||
$this->generate404();
|
||||
|
||||
[, $this->newId, $this->imgHash] = $m;
|
||||
|
||||
if (!$this->imgHash || !$this->newId)
|
||||
$this->generate404();
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->handleComplete())
|
||||
$_SESSION['msg'] = ['avatar', false, AvatarMgr::$error ?: Lang::main('intError')];
|
||||
}
|
||||
|
||||
private function handleComplete() : bool
|
||||
{
|
||||
if (!$this->assertPOST('coords'))
|
||||
return false;
|
||||
|
||||
if (!AvatarMgr::init())
|
||||
return false;
|
||||
|
||||
if (!AvatarMgr::loadFile(AvatarMgr::PATH_TEMP, User::$username.'-avatar-'.$this->newId.'-'.$this->imgHash.'_original'))
|
||||
return false;
|
||||
|
||||
if (!AvatarMgr::cropImg(...$this->_post['coords']))
|
||||
return false;
|
||||
|
||||
if (!AvatarMgr::createAtlas($this->newId))
|
||||
return false;
|
||||
|
||||
$fSize = filesize(sprintf(AvatarMgr::PATH_AVATARS, $this->newId));
|
||||
if (!$fSize)
|
||||
return false;
|
||||
|
||||
$newId = DB::Aowow()->query('INSERT INTO ?_account_avatars (`id`, `userId`, `name`, `when`, `size`) VALUES (?d, ?d, ?, ?d, ?d)', $this->newId, User::$id, 'Avatar '.$this->newId, time(), $fSize);
|
||||
if (!is_int($newId))
|
||||
{
|
||||
trigger_error('UploadImagecompleteResponse - avatar query failed', E_USER_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
// delete temp files
|
||||
unlink(sprintf(AvatarMgr::PATH_TEMP, User::$username.'-avatar-'.$this->newId.'-'.$this->imgHash.'_original'));
|
||||
unlink(sprintf(AvatarMgr::PATH_TEMP, User::$username.'-avatar-'.$this->newId.'-'.$this->imgHash));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static function checkCoords(string $val) : ?array
|
||||
{
|
||||
if (preg_match('/^[01]\.[0-9]{3}(,[01]\.[0-9]{3}){3}$/', $val))
|
||||
return explode(',', $val);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
84
endpoints/upload/image-crop.php
Normal file
84
endpoints/upload/image-crop.php
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class UploadImagecropResponse extends TemplateResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
protected int $requiredUserGroup = U_GROUP_PREMIUM_PERMISSIONS;
|
||||
|
||||
protected string $template = 'image-crop';
|
||||
protected string $pageName = 'image-crop';
|
||||
|
||||
protected array $scripts = array(
|
||||
[SC_JS_FILE, 'js/Cropper.js'],
|
||||
[SC_CSS_FILE, 'css/Cropper.css']
|
||||
);
|
||||
|
||||
public array $cropper = [];
|
||||
public int $nextId = 0;
|
||||
public string $imgHash = '';
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
if (User::isBanned())
|
||||
$this->generateError();
|
||||
|
||||
parent::__construct($pageParam);
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if ($err = $this->handleUpload())
|
||||
{
|
||||
$_SESSION['msg'] = ['avatar', false, $err];
|
||||
$this->forward('?account#community');
|
||||
}
|
||||
|
||||
$this->h1 = Lang::account('avatarSubmit');
|
||||
|
||||
$fileBase = User::$username.'-avatar-'.$this->nextId.'-'.$this->imgHash;
|
||||
$dimensions = AvatarMgr::calcImgDimensions();
|
||||
|
||||
$this->cropper = $dimensions + array(
|
||||
'url' => Cfg::get('STATIC_URL').'/uploads/temp/'.$fileBase.'.jpg',
|
||||
'parent' => 'av-container',
|
||||
'minCrop' => ICON_SIZE_LARGE, // optional; defaults to 150 - min selection size (a square)
|
||||
'type' => Type::NPC, // NPC: 15384 [OLDWorld Trigger (DO NOT DELETE)]
|
||||
'typeId' => 15384, // = arbitrary image upload
|
||||
'constraint' => [1, 1] // [xMult, yMult] - relative size to each other (here: be square)
|
||||
);
|
||||
|
||||
parent::generate();
|
||||
}
|
||||
|
||||
private function handleUpload() : string
|
||||
{
|
||||
if (!AvatarMgr::init())
|
||||
return Lang::main('intError');
|
||||
|
||||
if (!AvatarMgr::validateUpload())
|
||||
return AvatarMgr::$error;
|
||||
|
||||
if (!AvatarMgr::loadUpload())
|
||||
return Lang::main('intError');
|
||||
|
||||
$n = DB::Aowow()->selectCell('SELECT COUNT(1) FROM ?_account_avatars WHERE `userId` = ?d', User::$id);
|
||||
if ($n && $n > Cfg::get('ACC_MAX_AVATAR_UPLOADS'))
|
||||
return Lang::main('intError');
|
||||
|
||||
// why is ++(<IntExpression>); illegal syntax? WHO KNOWS!?
|
||||
$this->nextId = (DB::Aowow()->selectCell('SELECT MAX(`id`) FROM ?_account_avatars') ?: 0) + 1;
|
||||
|
||||
if (!AvatarMgr::tempSaveUpload(['avatar', $this->nextId], $this->imgHash))
|
||||
return Lang::main('intError');
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
@ -38,7 +38,7 @@ class UserBaseResponse extends TemplateResponse
|
|||
if (!$pageParam)
|
||||
$this->forwardToSignIn('user');
|
||||
|
||||
if ($user = DB::Aowow()->selectRow('SELECT a.`id`, a.`username`, a.`consecutiveVisits`, a.`userGroups`, a.`avatar`, a.`wowicon`, a.`title`, a.`description`, a.`joinDate`, a.`prevLogin`, IFNULL(SUM(ar.`amount`), 0) AS "sumRep", a.`prevIP`, a.`email` FROM ?_account a LEFT JOIN ?_account_reputation ar ON a.`id` = ar.`userId` WHERE LOWER(a.`username`) = LOWER(?) GROUP BY a.`id`', $pageParam))
|
||||
if ($user = DB::Aowow()->selectRow('SELECT a.`id`, a.`username`, a.`consecutiveVisits`, a.`userGroups`, a.`avatar`, a.`avatarborder`, a.`wowicon`, a.`title`, a.`description`, a.`joinDate`, a.`prevLogin`, IFNULL(SUM(ar.`amount`), 0) AS "sumRep", a.`prevIP`, a.`email` FROM ?_account a LEFT JOIN ?_account_reputation ar ON a.`id` = ar.`userId` WHERE LOWER(a.`username`) = LOWER(?) GROUP BY a.`id`', $pageParam))
|
||||
$this->user = $user;
|
||||
else
|
||||
$this->generateNotFound(Lang::user('notFound', [$pageParam]));
|
||||
|
|
@ -115,12 +115,15 @@ class UserBaseResponse extends TemplateResponse
|
|||
default => ''
|
||||
};
|
||||
|
||||
if (!($this->user['userGroups'] & U_GROUP_PREMIUM))
|
||||
$this->user['avatarborder'] = 2;
|
||||
|
||||
$this->userIcon = array( // JS: Icon.createUser()
|
||||
$this->user['avatar'], // avatar: 1(iconString), 2(customId)
|
||||
$avatarMore, // avatarMore: iconString or customId
|
||||
IconElement::SIZE_MEDIUM, // size: (always medium)
|
||||
null, // url: (always null)
|
||||
User::isInGroup(U_GROUP_PREMIUM) ? 0 : 2, // premiumLevel: affixes css class ['-premium', '-gold', '', '-premiumred', '-red']
|
||||
$this->user['avatarborder'], // premiumLevel: affixes css class ['-premium', '-gold', '', '-premiumred', '-red']
|
||||
false, // noBorder: always false
|
||||
'$Icon.getPrivilegeBorder('.$this->user['sumRep'].')' // reputationLevel: calculated in js from passed rep points
|
||||
);
|
||||
|
|
|
|||
122
includes/components/avatarmgr.class.php
Normal file
122
includes/components/avatarmgr.class.php
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AvatarMgr extends ImageUpload
|
||||
{
|
||||
private const MIN_SIZE = ICON_SIZE_LARGE;
|
||||
// 4k resolution
|
||||
private const MAX_W = 4096;
|
||||
private const MAX_H = 2160;
|
||||
|
||||
public const STATUS_PENDING = 0; // guessed
|
||||
public const STATUS_APPROVED = 1; // guessed
|
||||
public const STATUS_REJECTED = 2;
|
||||
|
||||
protected static string $uploadFormField = 'iconfile';
|
||||
protected static string $tmpPath = self::PATH_TEMP;
|
||||
|
||||
public const PATH_TEMP = 'static/uploads/temp/%s.jpg';
|
||||
public const PATH_AVATARS = 'static/uploads/avatars/%d.jpg';
|
||||
|
||||
public static function init() : bool
|
||||
{
|
||||
$dirErr = false;
|
||||
foreach (['TEMP', 'AVATARS'] as $p)
|
||||
{
|
||||
$path = constant('self::PATH_' . $p);
|
||||
if (!is_writable(substr($path, 0, strrpos($path, '/'))))
|
||||
{
|
||||
trigger_error('AvatarMgr::init - directory '.substr($path, 0, strrpos($path, '/')).' not writable', E_USER_ERROR);
|
||||
$dirErr = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($dirErr)
|
||||
return false;
|
||||
|
||||
return parent::init();
|
||||
}
|
||||
|
||||
public static function validateUpload() : bool
|
||||
{
|
||||
if (!parent::validateUpload())
|
||||
return false;
|
||||
|
||||
// invalid file
|
||||
if ($is = getimagesize(self::$fileName))
|
||||
{
|
||||
// image size out of bounds
|
||||
if ($is[0] < ICON_SIZE_LARGE || $is[1] < ICON_SIZE_LARGE)
|
||||
self::$error = Lang::account('errTooSmall', [ICON_SIZE_LARGE]);
|
||||
else if ($is[0] > self::MAX_W || $is[1] > self::MAX_H)
|
||||
self::$error = Lang::account('selectAvatar');
|
||||
}
|
||||
else
|
||||
self::$error = Lang::account('selectAvatar');
|
||||
|
||||
if (!self::$error)
|
||||
return true;
|
||||
|
||||
self::$fileName = '';
|
||||
return false;
|
||||
}
|
||||
|
||||
/* create icon texture atlas
|
||||
* ******************************
|
||||
* * LARGE * MEDIUM *
|
||||
* * * *
|
||||
* * * *
|
||||
* * *************
|
||||
* * * SMOL * *
|
||||
* * * * *
|
||||
* * ********* *
|
||||
* ******************************
|
||||
*
|
||||
* as static/uploads/avatars/<avatarIdx>.jpg
|
||||
*/
|
||||
|
||||
public static function createAtlas(string $fileName) : bool
|
||||
{
|
||||
if (!self::$img)
|
||||
return false;
|
||||
|
||||
$sizes = [ICON_SIZE_LARGE, ICON_SIZE_MEDIUM, ICON_SIZE_SMALL];
|
||||
|
||||
$dest = imagecreatetruecolor(ICON_SIZE_LARGE + ICON_SIZE_MEDIUM, ICON_SIZE_LARGE);
|
||||
$srcW = imagesx(self::$img);
|
||||
$srcH = imagesx(self::$img);
|
||||
|
||||
$destX = $destY = 0;
|
||||
foreach ($sizes as $idx => $dim)
|
||||
{
|
||||
imagecopyresampled($dest, self::$img, $destX, $destY, 0, 0, $dim, $dim, $srcW, $srcH);
|
||||
|
||||
if ($idx % 2)
|
||||
$destY += $dim;
|
||||
else
|
||||
$destX += $dim;
|
||||
}
|
||||
|
||||
if (!imagejpeg($dest, sprintf(self::PATH_AVATARS, $fileName), self::JPEG_QUALITY))
|
||||
return false;
|
||||
|
||||
self::$img = null;
|
||||
$dest = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*************/
|
||||
/* Admin Mgr */
|
||||
/*************/
|
||||
|
||||
// unsure yet how that's supposed to work
|
||||
// for now pending uploads can be used right away
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
@ -26,7 +26,7 @@ class UserList extends DBTypeList
|
|||
foreach ($this->iterate() as $userId => $__)
|
||||
{
|
||||
$data[$this->curTpl['username']] = array(
|
||||
'border' => 0, // border around avatar (rarityColors)
|
||||
'border' => $this->getPremiumborder(),
|
||||
'roles' => $this->curTpl['userGroups'],
|
||||
'joined' => date(Util::$dateFormatInternal, $this->curTpl['joinDate']),
|
||||
'posts' => 0, // forum posts
|
||||
|
|
@ -47,22 +47,39 @@ class UserList extends DBTypeList
|
|||
$data[$this->curTpl['username']]['avatarmore'] = $this->curTpl['wowicon'];
|
||||
break;
|
||||
case 2:
|
||||
if ($av = DB::Aowow()->selectCell('SELECT `id` FROM ?_account_avatars WHERE `userId` = ?d AND `current` = 1 AND `status` <> 2', $userId))
|
||||
if ($this->isPremium())
|
||||
{
|
||||
$data[$this->curTpl['username']]['avatar'] = $this->curTpl['avatar'];
|
||||
$data[$this->curTpl['username']]['avatarmore'] = $av;
|
||||
if ($av = DB::Aowow()->selectCell('SELECT `id` FROM ?_account_avatars WHERE `userId` = ?d AND `current` = 1 AND `status` <> ?d', $userId, AvatarMgr::STATUS_REJECTED))
|
||||
{
|
||||
$data[$this->curTpl['username']]['avatar'] = $this->curTpl['avatar'];
|
||||
$data[$this->curTpl['username']]['avatarmore'] = $av;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// more optional data
|
||||
// sig: markdown formated string (only used in forum?)
|
||||
// border: seen as null|1|3 .. changes the border around the avatar (i suspect its meaning changed and got decoupled from premium-status with the introduction of patreon-status)
|
||||
}
|
||||
|
||||
return [Type::USER => $data];
|
||||
}
|
||||
|
||||
// seen as null|1|3 .. changes the border around the avatar (chosen from account > premium tab?)
|
||||
// changed at the end of MoP. No longer a jsBool but index to Icon.premiumBorderClasses
|
||||
private function getPremiumBorder() : int
|
||||
{
|
||||
if (!$this->isPremium() || !$this->curTpl['avatar'])
|
||||
return 2; // 2 is "none"
|
||||
|
||||
return $this->curTpl['avatarborder'];
|
||||
}
|
||||
|
||||
public function isPremium() : bool
|
||||
{
|
||||
return $this->curTpl['userGroups'] & U_GROUP_PREMIUM || $this->curTpl['reputation'] >= Cfg::get('REP_REQ_PREMIUM');
|
||||
}
|
||||
|
||||
public function getListviewData() : array { return []; }
|
||||
public function renderTooltip() : ?string { return null; }
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ class User
|
|||
private static int $reputation = 0;
|
||||
private static string $dataKey = '';
|
||||
private static int $excludeGroups = 1;
|
||||
private static int $avatarborder = 2; // 2 is default / reputation colored
|
||||
private static ?LocalProfileList $profiles = null;
|
||||
|
||||
public static function init()
|
||||
|
|
@ -62,7 +63,7 @@ class User
|
|||
|
||||
$session = DB::Aowow()->selectRow('SELECT `userId`, `expires` FROM ?_account_sessions WHERE `status` = ?d AND `sessionId` = ?', SESSION_ACTIVE, session_id());
|
||||
$userData = DB::Aowow()->selectRow(
|
||||
'SELECT a.`id`, a.`passHash`, a.`username`, a.`locale`, a.`userGroups`, a.`userPerms`, BIT_OR(ab.`typeMask`) AS "bans", IFNULL(SUM(r.`amount`), 0) AS "reputation", a.`dailyVotes`, a.`excludeGroups`, a.`status`, a.`statusTimer`, a.`email`, a.`debug`
|
||||
'SELECT a.`id`, a.`passHash`, a.`username`, a.`locale`, a.`userGroups`, a.`userPerms`, BIT_OR(ab.`typeMask`) AS "bans", IFNULL(SUM(r.`amount`), 0) AS "reputation", a.`dailyVotes`, a.`excludeGroups`, a.`status`, a.`statusTimer`, a.`email`, a.`debug`, a.`avatar`, a.`avatarborder`
|
||||
FROM ?_account a
|
||||
LEFT JOIN ?_account_banned ab ON a.`id` = ab.`userId` AND ab.`end` > UNIX_TIMESTAMP()
|
||||
LEFT JOIN ?_account_reputation r ON a.`id` = r.`userId`
|
||||
|
|
@ -119,6 +120,7 @@ class User
|
|||
self::$status = $userData['status'];
|
||||
self::$debug = $userData['debug'];
|
||||
self::$email = $userData['email'];
|
||||
self::$avatarborder = $userData['avatarborder'];
|
||||
|
||||
if (Cfg::get('PROFILER_ENABLE'))
|
||||
{
|
||||
|
|
@ -129,6 +131,18 @@ class User
|
|||
self::$profiles = (new LocalProfileList($conditions));
|
||||
}
|
||||
|
||||
// reset premium options
|
||||
if (!self::isPremium())
|
||||
{
|
||||
if ($userData['avatar'] == 2)
|
||||
{
|
||||
DB::Aowow()->query('UPDATE ?_account SET `avatar` = 1 WHERE `id` = ?d', self::$id);
|
||||
DB::Aowow()->query('UPDATE ?_account_avatars SET `current` = 0 WHERE `userId` = ?d', self::$id);
|
||||
}
|
||||
|
||||
// avatar borders
|
||||
// do not reset, it's just not sent to the browser
|
||||
}
|
||||
|
||||
// stuff, that updates on a daily basis goes here (if you keep you session alive indefinitly, the signin-handler doesn't do very much)
|
||||
// - consecutive visits
|
||||
|
|
@ -482,7 +496,7 @@ class User
|
|||
|
||||
public static function isPremium() : bool
|
||||
{
|
||||
return self::isInGroup(U_GROUP_PREMIUM) || self::$reputation >= Cfg::get('REP_REQ_PREMIUM');
|
||||
return !self::isBanned() && (self::isInGroup(U_GROUP_PREMIUM) || self::$reputation >= Cfg::get('REP_REQ_PREMIUM'));
|
||||
}
|
||||
|
||||
public static function isLoggedIn() : bool
|
||||
|
|
@ -568,14 +582,14 @@ class User
|
|||
if (self::$debug)
|
||||
$gUser['debug'] = true; // csv id-list output option on listviews
|
||||
|
||||
if (self::getPremiumBorder())
|
||||
$gUser['settings'] = ['premiumborder' => 1];
|
||||
if (self::isPremium())
|
||||
{
|
||||
$gUser['premium'] = 1;
|
||||
$gUser['settings'] = ['premiumborder' => self::$avatarborder];
|
||||
}
|
||||
else
|
||||
$gUser['settings'] = (new \StdClass); // existence is checked in Profiler.js before g_user.excludegroups is applied; should this contain - "defaultModel":{"gender":2,"race":6} ?
|
||||
|
||||
if (self::isPremium())
|
||||
$gUser['premium'] = 1;
|
||||
|
||||
if ($_ = self::getProfilerExclusions())
|
||||
$gUser = array_merge($gUser, $_);
|
||||
|
||||
|
|
@ -717,12 +731,6 @@ class User
|
|||
|
||||
return $data;
|
||||
}
|
||||
|
||||
// not sure what to set .. user selected?
|
||||
public static function getPremiumBorder() : bool
|
||||
{
|
||||
return self::isInGroup(U_GROUP_PREMIUM);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
|
|||
|
|
@ -950,6 +950,19 @@ $lang = array(
|
|||
'newPassDiff' => "Euer neues Kennwort muss sich von eurem alten Kennwort unterscheiden.", // message_newpassdifferent
|
||||
'newMailDiff' => "Eure neue E-Mail-Adresse muss sich von eurer alten E-Mail-Adresse unterscheiden.", // message_newemaildifferent
|
||||
|
||||
// premium avatar manager
|
||||
'uploadAvatar' => "Neuen Avatar hochladen",
|
||||
'goToManager' => "Zur Avatarverwaltung gehen",
|
||||
'manageAvatars' => "Avatare verwalten",
|
||||
'avatarSlots' => '<b>%1$d / %2$d</b> Avatarplätze belegt',
|
||||
'manageBorders' => "Premium Rahmen verwalten",
|
||||
'selectAvatar' => "Wählt einen Avatar zum hochladen.",
|
||||
'errTooSmall' => "Euer Avatar muss wenigstens %dpx groß sein.",
|
||||
'cropAvatar' => "Ihr könnt Euren Avatar zuschneiden.",
|
||||
'avatarSubmit' => "Avatar-Einsendung",
|
||||
'reminder' => "Erinnerung",
|
||||
'avatarCoC' => "Dass Benutzen von Bildern, die gegen die Regeln verstoßen kann zum Verlust Eures Premium-Status führen.",
|
||||
|
||||
// settings
|
||||
'settings' => "Kontoeinstellungen",
|
||||
'settingsNote' => "Du kannst einfach die unten stehenden Formulare ausfüllen, um deine Kontodaten zu aktualisieren.",
|
||||
|
|
|
|||
|
|
@ -950,6 +950,19 @@ $lang = array(
|
|||
'newPassDiff' => "Your new password must be different than your previous one.", // message_newpassdifferent
|
||||
'newMailDiff' => "Your new email address must be different than your previous one.", // message_newemaildifferent
|
||||
|
||||
// premium avatar manager
|
||||
'uploadAvatar' => "Upload new Avatar",
|
||||
'goToManager' => "Go to Avatar Manager",
|
||||
'manageAvatars' => "Manage Avatars",
|
||||
'avatarSlots' => 'Using <b>%1$d / %2$d</b> avatar slots',
|
||||
'manageBorders' => "Manage Premium Borders",
|
||||
'selectAvatar' => "Please select the avatar to upload.",
|
||||
'errTooSmall' => "Your avatar must be at last %dpx in size.",
|
||||
'cropAvatar' => "You may crop your avatar.",
|
||||
'avatarSubmit' => "Avatar Submission",
|
||||
'reminder' => "Reminder",
|
||||
'avatarCoC' => "Using imagery violating out terms of service may result in revocation of your premium privileges.",
|
||||
|
||||
// settings
|
||||
'settings' => "Account Settings",
|
||||
'settingsNote' => "Simply use the forms below to update your account information.",
|
||||
|
|
|
|||
|
|
@ -950,6 +950,19 @@ $lang = array(
|
|||
'newPassDiff' => "Su nueva contraseña tiene que ser diferente a su contraseña anterior.",// message_newpassdifferent
|
||||
'newMailDiff' => "Su nueva dirección de correo electrónico tiene que ser diferente a tu dirección de correo electrónico anterior.", // message_newemaildifferent
|
||||
|
||||
// premium avatar manager
|
||||
'uploadAvatar' => "[Upload new Avatar]",
|
||||
'goToManager' => "[Go to Avatar Manager]",
|
||||
'manageAvatars' => "[Manage Avatars]",
|
||||
'avatarSlots' => '[Using <b>%1$d / %2$d</b> avatar slots]',
|
||||
'manageBorders' => "[Manage Premium Borders]",
|
||||
'selectAvatar' => "[Please select the avatar to upload.]",
|
||||
'errTooSmall' => "[Your avatar must be at last %dpx in size.]",
|
||||
'cropAvatar' => "[You may crop your avatar.]",
|
||||
'avatarSubmit' => "[Avatar Submission]",
|
||||
'reminder' => "[Reminder]",
|
||||
'avatarCoC' => "[Using imagery violating out terms of service may result in revocation of your premium privileges.]",
|
||||
|
||||
// settings
|
||||
'settings' => "Mi cuenta",
|
||||
'settingsNote' => "Simplemente usa el siguiente formulario para actualizar la información de tu cuenta.",
|
||||
|
|
|
|||
|
|
@ -950,6 +950,19 @@ $lang = array(
|
|||
'newPassDiff' => "Votre nouveau mot de passe doit être différent de l'ancien.", // message_newpassdifferent
|
||||
'newMailDiff' => "Votre nouvelle adresse courriel doit être différente de l'ancienne.", // message_newemaildifferent
|
||||
|
||||
// premium avatar manager
|
||||
'uploadAvatar' => "[Upload new Avatar]",
|
||||
'goToManager' => "[Go to Avatar Manager]",
|
||||
'manageAvatars' => "[Manage Avatars]",
|
||||
'avatarSlots' => '[Using <b>%1$d / %2$d</b> avatar slots]',
|
||||
'manageBorders' => "[Manage Premium Borders]",
|
||||
'selectAvatar' => "[Please select the avatar to upload.]",
|
||||
'errTooSmall' => "[Your avatar must be at last %dpx in size.]",
|
||||
'cropAvatar' => "[You may crop your avatar.]",
|
||||
'avatarSubmit' => "[Avatar Submission]",
|
||||
'reminder' => "[Reminder]",
|
||||
'avatarCoC' => "[Using imagery violating out terms of service may result in revocation of your premium privileges.]",
|
||||
|
||||
// settings
|
||||
'settings' => "Mon compte",
|
||||
'settingsNote' => "Veuillez utiliser les formulaires ci-dessous pour apporter des changements.",
|
||||
|
|
|
|||
|
|
@ -950,6 +950,19 @@ $lang = array(
|
|||
'newPassDiff' => "Прежний и новый пароли не должны совпадать.", // message_newpassdifferent
|
||||
'newMailDiff' => "Прежний и новый e-mail адреса не должны совпадать.", // message_newemaildifferent
|
||||
|
||||
// premium avatar manager
|
||||
'uploadAvatar' => "[Upload new Avatar]",
|
||||
'goToManager' => "[Go to Avatar Manager]",
|
||||
'manageAvatars' => "[Manage Avatars]",
|
||||
'avatarSlots' => '[Using <b>%1$d / %2$d</b> avatar slots]',
|
||||
'manageBorders' => "[Manage Premium Borders]",
|
||||
'selectAvatar' => "[Please select the avatar to upload.]",
|
||||
'errTooSmall' => "[Your avatar must be at last %dpx in size.]",
|
||||
'cropAvatar' => "[You may crop your avatar.]",
|
||||
'avatarSubmit' => "[Avatar Submission]",
|
||||
'reminder' => "[Reminder]",
|
||||
'avatarCoC' => "[Using imagery violating out terms of service may result in revocation of your premium privileges.]",
|
||||
|
||||
// settings
|
||||
'settings' => "Параметры учетной записи",
|
||||
'settingsNote' => "Используйте нижеприведённую форму, чтобы обновить информацию о вашей учетной записи.",
|
||||
|
|
|
|||
|
|
@ -950,6 +950,19 @@ $lang = array(
|
|||
'newPassDiff' => "你的新密码必须与以前的密码不同。", // message_newpassdifferent
|
||||
'newMailDiff' => "您的新邮箱地址必须不同于旧地址。", // message_newemaildifferent
|
||||
|
||||
// premium avatar manager
|
||||
'uploadAvatar' => "[Upload new Avatar]",
|
||||
'goToManager' => "[Go to Avatar Manager]",
|
||||
'manageAvatars' => "[Manage Avatars]",
|
||||
'avatarSlots' => '[Using <b>%1$d / %2$d</b> avatar slots]',
|
||||
'manageBorders' => "[Manage Premium Borders]",
|
||||
'selectAvatar' => "[Please select the avatar to upload.]",
|
||||
'errTooSmall' => "[Your avatar must be at last %dpx in size.]",
|
||||
'cropAvatar' => "[You may crop your avatar.]",
|
||||
'avatarSubmit' => "[Avatar Submission]",
|
||||
'reminder' => "[Reminder]",
|
||||
'avatarCoC' => "[Using imagery violating out terms of service may result in revocation of your premium privileges.]",
|
||||
|
||||
// settings
|
||||
'settings' => "账号设置",
|
||||
'settingsNote' => "使用下列表格就能升级您的账号信息。",
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ CLISetup::registerUtility(new class extends UtilityScript
|
|||
'static/uploads/screenshots/thumb/',
|
||||
'static/uploads/temp/',
|
||||
'static/uploads/guide/images/',
|
||||
'static/uploads/avatars/'
|
||||
);
|
||||
|
||||
public function __construct()
|
||||
|
|
|
|||
3
setup/updates/1758578400_15.sql
Normal file
3
setup/updates/1758578400_15.sql
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
DELETE FROM `aowow_config` WHERE `key` = 'acc_max_avatar_uploads';
|
||||
INSERT INTO `aowow_config` (`key`, `value`, `default`, `cat`, `flags`, `comment`) VALUES
|
||||
('acc_max_avatar_uploads', 10, 10, 3, 129, 'premium users may upload this many avatars');
|
||||
2
setup/updates/1758578400_16.sql
Normal file
2
setup/updates/1758578400_16.sql
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE `aowow_account`
|
||||
ADD COLUMN `avatarborder` tinyint unsigned NOT NULL DEFAULT 2 AFTER `avatar`;
|
||||
|
|
@ -1161,7 +1161,8 @@ span.iconblizzard {
|
|||
.iconsmall-premiumred del { background-image:url(../images/Icon/small/border/premiumred.png); }
|
||||
.iconmedium-premiumred del { background-image:url(../images/Icon/medium/border/premiumred.png); }
|
||||
.iconlarge-premiumred del {
|
||||
background-image:url(../images/logos/special/subscribe/patron-icon.png);
|
||||
background-image:url(../images/Icon/large/border/premiumred.png);
|
||||
/* background-image:url(../images/logos/special/subscribe/patron-icon.png); aowow - yeah, no */
|
||||
height:85px;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1124,6 +1124,25 @@ function g_GetStaffColorFromRoles(roles) {
|
|||
return '';
|
||||
}
|
||||
|
||||
// aowow - stand in for WH.User.getCommentRoleLabel
|
||||
function g_GetCommentRoleLabel(roles, title) {
|
||||
if (title) {
|
||||
return title;
|
||||
}
|
||||
|
||||
if (roles & U_GROUP_ADMIN) {
|
||||
return g_user_roles[2]; // LANG.administrator_abbrev
|
||||
}
|
||||
else if (roles & U_GROUP_MOD) {
|
||||
return g_user_roles[4]; // LANG.moderator
|
||||
}
|
||||
else if (roles & U_GROUP_PREMIUMISH) {
|
||||
return LANG.premiumuser;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
function g_formatDate(sp, elapsed, theDate, time, alone) {
|
||||
var today = new Date();
|
||||
var event_day = new Date();
|
||||
|
|
@ -13957,6 +13976,49 @@ Listview.templates = {
|
|||
$(div).show();
|
||||
},
|
||||
|
||||
applyAuthorTitle: function (container, title)
|
||||
{
|
||||
if (!title.label)
|
||||
return;
|
||||
|
||||
let cssClass = ['comment-reply-author-label'].concat(title.classes);
|
||||
|
||||
$WH.ae(container, $WH.ct(' ')); // aowow - LANG.wordspace_punct
|
||||
|
||||
if (title.url)
|
||||
$WH.ae(container, $WH.ce('a', { className: cssClass.join(' '), href: title.url }, $WH.ct(`<${ title.label }>`)));
|
||||
else
|
||||
$WH.ae(container, $WH.ce('span', { className: cssClass.join(' ') }, $WH.ct(`<${ title.label }>`)));
|
||||
},
|
||||
|
||||
getAuthorTitle: function (author)
|
||||
{
|
||||
let title = {
|
||||
classes: [],
|
||||
label: undefined,
|
||||
url: undefined
|
||||
};
|
||||
|
||||
if (g_pageInfo.author === author) {
|
||||
title.label = LANG.guideAuthor;
|
||||
return title;
|
||||
}
|
||||
|
||||
let user = g_users[author];
|
||||
if (user) {
|
||||
// aowow - let roleColor = WH.User.getCommentTitleClass(_.roles, _.tierClass, user);
|
||||
let roleColor = g_GetStaffColorFromRoles(user.roles);
|
||||
if (roleColor) {
|
||||
title.classes.push(roleColor);
|
||||
}
|
||||
// aowow - title.label = WH.User.getCommentRoleLabel(user.roles, user.title, user.tierTitle);
|
||||
title.label = g_GetCommentRoleLabel(user.roles, user.title);
|
||||
title.url = /* user.tierTitle && !user.title ? '/?premium' : */ ''; // aowow - tierTitle being the premium tier ("Rare|Epic|Legendary Premium User")
|
||||
}
|
||||
|
||||
return title;
|
||||
},
|
||||
|
||||
updateReplies: function(comment)
|
||||
{
|
||||
this.updateRepliesCell(comment);
|
||||
|
|
@ -14063,7 +14125,13 @@ Listview.templates = {
|
|||
|
||||
row.attr('data-replyid', reply.id);
|
||||
row.attr('data-idx', i);
|
||||
row.find('.reply-text').addClass(g_GetStaffColorFromRoles(reply.roles));
|
||||
|
||||
// aowow - let cssClass = WH.User.getCommentRoleClass(reply.roles, reply.username);
|
||||
let cssClass = g_GetStaffColorFromRoles(reply.roles);
|
||||
if (!['comment-blue', 'comment-green'].includes(cssClass) && owner) {
|
||||
cssClass = 'comment-green'; // comment-guide-author
|
||||
}
|
||||
row.find('.reply-text').addClass(cssClass);
|
||||
|
||||
var replyWhen = $('<a></a>');
|
||||
replyWhen.text(g_formatDate(null, elapsed, creationDate));
|
||||
|
|
@ -14074,12 +14142,7 @@ Listview.templates = {
|
|||
replyByUserLink.attr('href', '?user=' + reply.username);
|
||||
replyByUserLink.text(reply.username);
|
||||
replyBy.append(replyByUserLink);
|
||||
|
||||
if (owner)
|
||||
{
|
||||
$WH.ae(replyBy[0], $WH.ct(' '));
|
||||
$WH.ae(replyBy[0], $WH.ce('span', { className: 'comment-reply-author-label' }, $WH.ct('<' + LANG.guideAuthor + '>')));
|
||||
}
|
||||
this.applyAuthorTitle(replyBy[0], this.getAuthorTitle(reply.username))
|
||||
|
||||
replyBy.append(' ').append(replyWhen).append(' ').append($WH.sprintf(LANG.lvcomment_patch, g_getPatchVersion(creationDate)));
|
||||
|
||||
|
|
@ -14170,7 +14233,6 @@ Listview.templates = {
|
|||
updateCommentAuthor: function(comment, container)
|
||||
{
|
||||
var user = g_users[comment.user];
|
||||
let owner = g_pageInfo.author === comment.user;
|
||||
var postedOn = new Date(comment.date);
|
||||
var elapsed = (g_serverTime - postedOn) / 1000;
|
||||
|
||||
|
|
@ -14178,12 +14240,18 @@ Listview.templates = {
|
|||
|
||||
container.append(LANG.lvcomment_by);
|
||||
container.append($WH.sprintf('<a href="?user=$1">$2</a>', comment.user, comment.user));
|
||||
if (owner)
|
||||
{
|
||||
$WH.ae(container[0], $WH.ct(' '));
|
||||
$WH.ae(container[0], $WH.ce('span', { className: 'comment-reply-author-label' }, $WH.ct('<' + LANG.guideAuthor + '>')));
|
||||
// aowow - avatar recovered and transplanted from commentsv1 version
|
||||
if (user != null && user.avatar) {
|
||||
var icon = Icon.createUser(user.avatar, user.avatarmore, 0, null, (user.roles & U_GROUP_PREMIUM) ? user.border : Icon.STANDARD_BORDER, 0, Icon.getPrivilegeBorder(user.reputation));
|
||||
icon.style.marginRight = '3px';
|
||||
icon.style.cssFloat = 'left';
|
||||
|
||||
container.css('lineHeight', '25px');
|
||||
container.append(icon);
|
||||
}
|
||||
// aowow - end recover
|
||||
container.append(g_getReputationPlusAchievementText(user.gold, user.silver, user.copper, user.reputation));
|
||||
this.applyAuthorTitle(container[0], this.getAuthorTitle(comment.user));
|
||||
container.append($WH.sprintf(' <a class="q0" id="comments:id=$1" href="#comments:id=$2">$3</a>', comment.id, comment.id, g_formatDate(null, elapsed, postedOn)));
|
||||
container.append(' ');
|
||||
container.append($WH.sprintf(LANG.lvcomment_patch, g_getPatchVersion(postedOn)));
|
||||
|
|
|
|||
|
|
@ -146,9 +146,7 @@ if ($this->bans):
|
|||
<div><?=Lang::account('accDeleteNote');?></div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
<?php endif; ?>
|
||||
<div id="tab-community" style="display: none">
|
||||
<h2 class="first"><?=Lang::account('userPage');?></h2>
|
||||
|
||||
|
|
@ -214,11 +212,11 @@ if ($this->bans):
|
|||
</div>
|
||||
<div class="clear"></div>
|
||||
|
||||
<?php if ($this->user::isInGroup(U_GROUP_PREMIUM) && 0): ?>
|
||||
<?php if ($this->user::isInGroup(U_GROUP_PREMIUM)): ?>
|
||||
<input type="radio" name="avatar" value="2" id="avaOpt2" onclick="faChange(2)"<?=($this->avMode == 2 ? ' checked="checked"' : '');?> /> <label for="avaOpt2"><?=Lang::account('custom');?></label> <span class="premium-feature-icon-small"></span><table id="avaSel2" style="padding: 6px; margin-top: 4px; margin-left: 16px; border-left: 1px solid #404040; height: 85px">
|
||||
<tr><td style="padding: 5px; vertical-align: top; position: relative;">
|
||||
<select name="customicon" id="customicon" style="min-width: 150px; margin-right: 5px;" onchange="spawj()">
|
||||
<option>Upload new Avatar</option>
|
||||
<option><?=Lang::account('uploadAvatar');?></option>
|
||||
<?=$this->makeOptionsList($this->customicons, $this->customicon, 40); ?>
|
||||
</select>
|
||||
<div id="avaPre2" style="position: absolute; right: -68px; top: 0px"></div>
|
||||
|
|
@ -226,7 +224,7 @@ if ($this->bans):
|
|||
<div id="iconbrowse">
|
||||
<input type="file" name="iconfile">
|
||||
<div class="pad"></div>
|
||||
Go to <a href="javascript:;" onclick="_.show(3, true);">Avatar Manager</a>
|
||||
<a href="javascript:;" onclick="_.show(3, true);"><?=Lang::account('goToManager');?></a>
|
||||
</div>
|
||||
</td></tr>
|
||||
</table>
|
||||
|
|
@ -255,18 +253,46 @@ if ($this->bans):
|
|||
<ul><li><div><?=Lang::account('status').Lang::main('colon').'<b class="q10">'.Lang::account('inactive'); ?></b></div></li></ul>
|
||||
<?php else: ?>
|
||||
<ul><li><div><?=Lang::account('status').Lang::main('colon').'<b class="q2">'.Lang::account('active'); ?></b></div></li></ul>
|
||||
<?php endif; /*
|
||||
<h2>Manage Avatars</h2>
|
||||
<h2><?=Lang::account('manageAvatars');?></h2>
|
||||
<div id="avatar-manage" class="listview" style="margin: 0px 10% 0px 25px;"></div>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
<?=$this->avatarManager; ?>
|
||||
//]]></script>
|
||||
|
||||
<h2>Manage Premium Borders</h2>
|
||||
<span>Todo</span>
|
||||
<?php endif; */ ?>
|
||||
</div>
|
||||
<h2><?=Lang::account('manageBorders');?></h2>
|
||||
<?php if ([$type, $msg] = $this->premiumborderMessage): ?>
|
||||
<div class="box"><div class="msg-<?=($type ? 'success' : 'failure');?>"><?=$msg;?></div></div>
|
||||
<?php endif; ?>
|
||||
<form action="?account=premium-border" method="POST">
|
||||
<div style="width:500px; padding-left:25px;" class="pad2">
|
||||
<div style="display:flex; justify-content: space-between;" id="ipb-container"></div>
|
||||
<div style="display:flex; justify-content: space-between;" id="pb-container"></div>
|
||||
</div>
|
||||
<input type="submit" value="<?=Lang::main('submit');?>">
|
||||
<div class="pad2"></div>
|
||||
</form>
|
||||
<script type="text/javascript">
|
||||
[2, 1, 0, 4, 3].forEach((i, k) => {
|
||||
let icon = Icon.createUser(2, <?=$this->customicon;?>, 2, null, i, null, Icon.getPrivilegeBorder(<?=$this->reputation;?>));
|
||||
let div = $WH.ce('div', {id: 'pb-' + i, style: 'display:inline-block'}, icon);
|
||||
let input = $WH.ce('input', {
|
||||
type:'radio',
|
||||
name:'avatarborder',
|
||||
value: i,
|
||||
id: 'ipb-' + i,
|
||||
style: 'width:68px; margin:10px 0px;'
|
||||
});
|
||||
|
||||
$WH.ae($WH.ge('pb-container'), div);
|
||||
$WH.ae($WH.ge('ipb-container'), input);
|
||||
|
||||
icon.onclick = ((x, evt) => { $WH.ge('ipb-' + x).click(); }).bind(this, i);
|
||||
if (g_user?.settings?.premiumborder === i)
|
||||
icon.click();
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -280,9 +306,7 @@ if ($this->bans):
|
|||
_.add('<?=Lang::account('tabPremium');?>', {id: 'premium'});
|
||||
_.flush();
|
||||
</script>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="clear"></div>
|
||||
</div><!-- main-contents -->
|
||||
|
|
|
|||
45
template/pages/image-crop.tpl.php
Normal file
45
template/pages/image-crop.tpl.php
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
namespace Aowow\Template;
|
||||
|
||||
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">
|
||||
|
||||
<?php
|
||||
$this->brick('announcement');
|
||||
|
||||
$this->brick('pageTemplate');
|
||||
?>
|
||||
<div class="text">
|
||||
<h1><?=$this->h1; ?></h1>
|
||||
|
||||
<span><?=Lang::account('cropAvatar');?></span>
|
||||
<div class="pad"></div>
|
||||
<div id="av-container"></div><script type="text/javascript">//<![CDATA[
|
||||
var myCropper = new Cropper(<?=$this->json($this->cropper); ?>);
|
||||
//]]></script>
|
||||
|
||||
<div class="pad"></div>
|
||||
<button style="margin:4px 0 0 5px" onclick="myCropper.selectAll()"><?=Lang::screenshot('selectAll'); ?></button>
|
||||
<div class="clear"></div>
|
||||
|
||||
<div class="pad3"></div>
|
||||
|
||||
<form action="?upload=image-complete&<?=$this->nextId.'.'.$this->imgHash; ?>" method="post" onsubmit="this.elements['coords'].value = myCropper.getCoords()">
|
||||
<div class="pad"></div>
|
||||
|
||||
<h2><img src="<?=$this->gStaticUrl; ?>/images/icons/bubble-big.gif" width="32" height="29" alt="" style="vertical-align:middle;margin-right:8px"><?=Lang::account('reminder');?></h2>
|
||||
<div class="pad3"><?=Lang::account('avatarCoC');?></div>
|
||||
|
||||
<input type="submit" value="<?=Lang::main('submit'); ?>" />
|
||||
<input type="hidden" name="coords" />
|
||||
</form>
|
||||
</div>
|
||||
</div><!-- main-contents -->
|
||||
</div><!-- main -->
|
||||
|
||||
<?php $this->brick('footer'); ?>
|
||||
Loading…
Add table
Add a link
Reference in a new issue