Template/Update (Part 46 - I)

* account management rework: Base
 * create proper account settings page
   - modelviewer preferences
   - show ids in lists
   - announcement purge
   - public description
  * fix broken FKs between aowow_user_ratings and aowow_account
This commit is contained in:
Sarjuuk
2025-08-28 17:33:03 +02:00
parent ab27976132
commit 155bf1e4a3
28 changed files with 1735 additions and 804 deletions

View File

@@ -19,7 +19,7 @@ trait TrRecoveryHelper
// check if already processing
if ($_ = DB::Aowow()->selectCell('SELECT `statusTimer` - UNIX_TIMESTAMP() FROM ?_account WHERE `email` = ? AND `status` > ?d AND `statusTimer` > UNIX_TIMESTAMP()', $email, ACC_STATUS_NEW))
return sprintf(Lang::account('isRecovering'), Util::formatTime($_ * 1000));
return Lang::account('inputbox', 'error', 'isRecovering', [Util::formatTime($_ * 1000)]);
// create new token and write to db
$token = Util::createHash();
@@ -28,7 +28,7 @@ trait TrRecoveryHelper
// send recovery mail
if (!Util::sendMail($email, $mailTemplate, [$token], Cfg::get('ACC_RECOVERY_DECAY')))
return sprintf(Lang::main('intError2'), 'send mail');
return Lang::main('intError2', ['send mail']);
return '';
}

View File

@@ -62,10 +62,14 @@ define('DB_AUTH', 2);
define('DB_CHARACTERS', 3);
// Account Status
define('ACC_STATUS_OK', 0); // nothing special
define('ACC_STATUS_NONE', 0); // nothing special
define('ACC_STATUS_NEW', 1); // just created, awaiting confirmation
define('ACC_STATUS_RECOVER_USER', 2); // currently recovering username
define('ACC_STATUS_RECOVER_PASS', 3); // currently recovering password
define('ACC_STATUS_CHANGE_EMAIL', 4); // currently changing contact email
define('ACC_STATUS_CHANGE_PASS', 5); // currently changing password
define('ACC_STATUS_CHANGE_USERNAME', 6); // currently changing username
define('ACC_STATUS_DELETED', 7); // is deleted - only a stub remains
// Session Status
define('SESSION_ACTIVE', 1);
@@ -84,6 +88,12 @@ define('ACC_BAN_VIDEO', 0x0040); // cannot suggest vi
define('ACC_BAN_GUIDE', 0x0080); // cannot write a guide
define('ACC_BAN_FORUM', 0x0100); // cannot post on forums [not used here]
define('IP_BAN_TYPE_LOGIN_ATTEMPT', 0);
define('IP_BAN_TYPE_REGISTRATION_ATTEMPT', 1);
define('IP_BAN_TYPE_EMAIL_RECOVERY', 2);
define('IP_BAN_TYPE_PASSWORD_RECOVERY', 3);
define('IP_BAN_TYPE_USERNAME_RECOVERY', 4);
// Site Reputation/Privileges
define('SITEREP_ACTION_REGISTER', 1); // Registered account
define('SITEREP_ACTION_DAILYVISIT', 2); // Daily visit

View File

@@ -48,7 +48,7 @@ class User
return false;
// check IP bans
if ($ipBan = DB::Aowow()->selectRow('SELECT `count`, IF(`unbanDate` > UNIX_TIMESTAMP(), 1, 0) AS "active" FROM ?_account_bannedips WHERE `ip` = ? AND `type` = 0', self::$ip))
if ($ipBan = DB::Aowow()->selectRow('SELECT `count`, IF(`unbanDate` > UNIX_TIMESTAMP(), 1, 0) AS "active" FROM ?_account_bannedips WHERE `ip` = ? AND `type` = ?d', self::$ip, IP_BAN_TYPE_LOGIN_ATTEMPT))
{
if ($ipBan['count'] > Cfg::get('ACC_FAILED_AUTH_COUNT') && $ipBan['active'])
return false;
@@ -62,7 +62,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`
'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`
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`
@@ -97,10 +97,10 @@ class User
self::$preferedLoc = $loc;
// reset expired account statuses
if ($userData['statusTimer'] < time() && $userData['status'] > ACC_STATUS_NEW)
if ($userData['statusTimer'] && $userData['statusTimer'] < time() && $userData['status'] != ACC_STATUS_NEW)
{
DB::Aowow()->query('UPDATE ?_account SET `status` = ?d, `statusTimer` = 0, `token` = "", `updateValue` = "" WHERE `id` = ?d', ACC_STATUS_OK, User::$id);
$userData['status'] = ACC_STATUS_OK;
DB::Aowow()->query('UPDATE ?_account SET `status` = ?d, `statusTimer` = 0, `token` = "", `updateValue` = "" WHERE `id` = ?d', ACC_STATUS_NONE, User::$id);
$userData['status'] = ACC_STATUS_NONE;
}
@@ -117,7 +117,7 @@ class User
self::$dailyVotes = $userData['dailyVotes'];
self::$excludeGroups = $userData['excludeGroups'];
self::$status = $userData['status'];
// self::$debug = $userData['debug']; // TBD
self::$debug = $userData['debug'];
self::$email = $userData['email'];
if (Cfg::get('PROFILER_ENABLE'))
@@ -251,9 +251,9 @@ class User
return AUTH_INTERNAL_ERR;
// handle login try limitation
$ipBan = DB::Aowow()->selectRow('SELECT `ip`, `count`, IF(`unbanDate` > UNIX_TIMESTAMP(), 1, 0) AS "active" FROM ?_account_bannedips WHERE `type` = 0 AND `ip` = ?', self::$ip);
$ipBan = DB::Aowow()->selectRow('SELECT `ip`, `count`, IF(`unbanDate` > UNIX_TIMESTAMP(), 1, 0) AS "active" FROM ?_account_bannedips WHERE `type` = ?d AND `ip` = ?', IP_BAN_TYPE_LOGIN_ATTEMPT, self::$ip);
if (!$ipBan || !$ipBan['active']) // no entry exists or time expired; set count to 1
DB::Aowow()->query('REPLACE INTO ?_account_bannedips (`ip`, `type`, `count`, `unbanDate`) VALUES (?, 0, 1, UNIX_TIMESTAMP() + ?d)', self::$ip, Cfg::get('ACC_FAILED_AUTH_BLOCK'));
DB::Aowow()->query('REPLACE INTO ?_account_bannedips (`ip`, `type`, `count`, `unbanDate`) VALUES (?, ?d, 1, UNIX_TIMESTAMP() + ?d)', self::$ip, IP_BAN_TYPE_LOGIN_ATTEMPT, Cfg::get('ACC_FAILED_AUTH_BLOCK'));
else // entry already exists; increment count
DB::Aowow()->query('UPDATE ?_account_bannedips SET `count` = `count` + 1, `unbanDate` = UNIX_TIMESTAMP() + ?d WHERE `ip` = ?', Cfg::get('ACC_FAILED_AUTH_BLOCK'), self::$ip);
@@ -279,7 +279,7 @@ class User
return AUTH_WRONGPASS;
// successfull auth; clear bans for this IP
DB::Aowow()->query('DELETE FROM ?_account_bannedips WHERE `type` = 0 AND `ip` = ?', self::$ip);
DB::Aowow()->query('DELETE FROM ?_account_bannedips WHERE `type` = ?d AND `ip` = ?', IP_BAN_TYPE_LOGIN_ATTEMPT, self::$ip);
if ($query['bans'] & (ACC_BAN_PERM | ACC_BAN_TEMP))
return AUTH_BANNED;
@@ -362,7 +362,7 @@ class User
$name,
$_SERVER["REMOTE_ADDR"] ?? '',
self::$preferedLoc->value,
ACC_STATUS_OK,
ACC_STATUS_NONE,
$userGroup >= U_GROUP_NONE ? $userGroup : U_GROUP_NONE
);
@@ -497,7 +497,7 @@ class User
public static function isRecovering() : bool
{
return self::$status == ACC_STATUS_RECOVER_USER || self::$status == ACC_STATUS_RECOVER_PASS;
return self::$status != ACC_STATUS_NONE && self::$status != ACC_STATUS_NEW;
}
@@ -565,21 +565,13 @@ class User
$gUser['characters'] = self::getCharacters();
$gUser['excludegroups'] = self::$excludeGroups;
if (Cfg::get('DEBUG') && User::isInGroup(U_GROUP_DEV | U_GROUP_ADMIN | U_GROUP_TESTER))
if (self::$debug)
$gUser['debug'] = true; // csv id-list output option on listviews
if (self::getPremiumBorder())
$gUser['settings'] = ['premiumborder' => 1];
else
$gUser['settings'] = (new \StdClass); // existence is checked in Profiler.js before g_user.excludegroups is applied
if (self::isPremium())
$gUser['premium'] = 1;
if (self::getPremiumBorder())
$gUser['settings'] = ['premiumborder' => 1];
else
$gUser['settings'] = (new \StdClass); // existence is checked in Profiler.js before g_user.excludegroups is applied
$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;

View File

@@ -1212,12 +1212,15 @@ abstract class Util
$body = Util::defStatic($body);
if ($expiration)
{
$vars += array_fill(0, 9, null); // vsprintf requires all unused indizes to also be set...
$vars[9] = Util::formatTime($expiration * 1000);
}
if ($vars)
$body = vsprintf($body, $vars);
if ($expiration)
$body .= "\n\n".Lang::account('tokenExpires', [Util::formatTime($expiration * 1000)])."\n";
$subject = Cfg::get('NAME_SHORT').Lang::main('colon') . $subject;
$header = 'From: ' . Cfg::get('CONTACT_EMAIL') . "\n" .
'Reply-To: ' . Cfg::get('CONTACT_EMAIL') . "\n" .
@@ -1225,7 +1228,7 @@ abstract class Util
if (Cfg::get('DEBUG') >= LOG_LEVEL_INFO)
{
Util::addNote("Redirected from Util::sendMail:\n\nTo: " . $email . "\n\nSubject: " . $subject . "\n\n" . $body, U_GROUP_DEV | U_GROUP_ADMIN, LOG_LEVEL_INFO);
Util::addNote("Redirected from Util::sendMail:\n\nTo: " . $email . "\n\nSubject: " . $subject . "\n\n" . $body, U_GROUP_NONE, LOG_LEVEL_INFO);
return true;
}