From 97f9d3d6f6c28aef6d824973058d7133f56e09c4 Mon Sep 17 00:00:00 2001 From: slawkens Date: Thu, 2 Oct 2025 15:06:57 +0200 Subject: [PATCH 01/40] Add option to use ?subtopic=x for plugins pages --- system/router.php | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/system/router.php b/system/router.php index 9c9ce4ad..0f1845f2 100644 --- a/system/router.php +++ b/system/router.php @@ -88,8 +88,10 @@ if($logged && $account_logged && $account_logged->isLoaded()) { /** * Routes loading */ +$routesFinal = []; $dispatcher = FastRoute\cachedDispatcher(function (FastRoute\RouteCollector $r) { - $routesFinal = []; + global $routesFinal; + foreach(getDatabasePages() as $page) { $routesFinal[] = ['*', $page, '__database__/' . $page, 100]; } @@ -165,7 +167,7 @@ $dispatcher = FastRoute\cachedDispatcher(function (FastRoute\RouteCollector $r) echo ''; die; */ - foreach ($routesFinal as $route) { + foreach ($routesFinal as &$route) { if ($route[0] === '*') { $route[0] = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD']; } @@ -212,7 +214,7 @@ $found = true; // old support for pages like /?subtopic=accountmanagement $page = $_REQUEST['p'] ?? ($_REQUEST['subtopic'] ?? ''); -if(!empty($page) && preg_match('/^[A-z0-9\-]+$/', $page)) { +if(!empty($page) && preg_match('/^[A-z0-9\/\-]+$/', $page)) { if (isset($_REQUEST['p'])) { // some plugins may require this $_REQUEST['subtopic'] = $_REQUEST['p']; } @@ -221,9 +223,20 @@ if(!empty($page) && preg_match('/^[A-z0-9\-]+$/', $page)) { require SYSTEM . 'compat/pages.php'; } - $file = loadPageFromFileSystem($page, $found); - if(!$found) { - $file = false; + $foundRoute = false; + foreach ($routesFinal as $route) { + if ($page === $route[1]) { + $file = $route[2]; + $foundRoute = true; + break; + } + } + + if (!$foundRoute) { + $file = loadPageFromFileSystem($page, $found); + if(!$found) { + $file = false; + } } } else { From 64acf70d3854182d88aaf0b67f77cea2a254f179 Mon Sep 17 00:00:00 2001 From: slawkens Date: Thu, 2 Oct 2025 22:13:15 +0200 Subject: [PATCH 02/40] Cache::remember -1 = infinite --- system/src/Cache/Cache.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/system/src/Cache/Cache.php b/system/src/Cache/Cache.php index 53a84530..1b7d284b 100644 --- a/system/src/Cache/Cache.php +++ b/system/src/Cache/Cache.php @@ -115,6 +115,11 @@ class Cache return unserialize($value); } + // -1 for infinite cache + if ($ttl == -1) { + $ttl = 10 * 365 * 24 * 60 * 60; // 10 years should be enough + } + $value = $callback(); $cache->set($key, serialize($value), $ttl); return $value; From 3bb272ebbbd2eb7769d174b7082061d14a17bd44 Mon Sep 17 00:00:00 2001 From: slawkens Date: Thu, 2 Oct 2025 22:13:33 +0200 Subject: [PATCH 03/40] Allow for img in online_datacenter --- system/templates/online.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/templates/online.html.twig b/system/templates/online.html.twig index bb6c786c..6f798740 100644 --- a/system/templates/online.html.twig +++ b/system/templates/online.html.twig @@ -101,7 +101,7 @@ Location Datacenter: - {{ setting('core.online_datacenter') }} (Server date & time: - {{ "now"|date("d/m/Y H:i:s") }}) + {{ setting('core.online_datacenter')|raw }} (Server date & time: - {{ "now"|date("d/m/Y H:i:s") }}) PvP Type: From d8b73f55a310704ee884f1338dead9ff2c48a2f2 Mon Sep 17 00:00:00 2001 From: slawkens Date: Thu, 2 Oct 2025 22:16:29 +0200 Subject: [PATCH 04/40] Fix routes_final for prod env --- system/router.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/system/router.php b/system/router.php index 0f1845f2..ec79f9b3 100644 --- a/system/router.php +++ b/system/router.php @@ -88,9 +88,9 @@ if($logged && $account_logged && $account_logged->isLoaded()) { /** * Routes loading */ -$routesFinal = []; $dispatcher = FastRoute\cachedDispatcher(function (FastRoute\RouteCollector $r) { - global $routesFinal; + global $cache; + $routesFinal = []; foreach(getDatabasePages() as $page) { $routesFinal[] = ['*', $page, '__database__/' . $page, 100]; @@ -200,6 +200,8 @@ $dispatcher = FastRoute\cachedDispatcher(function (FastRoute\RouteCollector $r) log_append('router.log', $warning); } } + + $cache->set('routes_final', serialize($routesFinal), 10 * 365 * 24 * 60 * 60); // 10 years / infinite }, [ 'cacheFile' => CACHE . 'route.cache', @@ -224,6 +226,13 @@ if(!empty($page) && preg_match('/^[A-z0-9\/\-]+$/', $page)) { } $foundRoute = false; + + $routesFinal = []; + $tmp = null; + if ($cache->fetch('routes_final', $tmp)) { + $routesFinal = unserialize($tmp); + } + foreach ($routesFinal as $route) { if ($page === $route[1]) { $file = $route[2]; From 0cb9d3a20801045d5553e303f1933ef82650923b Mon Sep 17 00:00:00 2001 From: slawkens Date: Thu, 2 Oct 2025 22:31:02 +0200 Subject: [PATCH 05/40] Fix routes_final cache --- system/router.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/system/router.php b/system/router.php index ec79f9b3..f876a9b2 100644 --- a/system/router.php +++ b/system/router.php @@ -88,9 +88,9 @@ if($logged && $account_logged && $account_logged->isLoaded()) { /** * Routes loading */ +$routesFinal = []; $dispatcher = FastRoute\cachedDispatcher(function (FastRoute\RouteCollector $r) { - global $cache; - $routesFinal = []; + global $cache, $routesFinal; foreach(getDatabasePages() as $page) { $routesFinal[] = ['*', $page, '__database__/' . $page, 100]; @@ -201,7 +201,9 @@ $dispatcher = FastRoute\cachedDispatcher(function (FastRoute\RouteCollector $r) } } - $cache->set('routes_final', serialize($routesFinal), 10 * 365 * 24 * 60 * 60); // 10 years / infinite + if ($cache->enabled()) { + $cache->set('routes_final', serialize($routesFinal), 10 * 365 * 24 * 60 * 60); // 10 years / infinite + } }, [ 'cacheFile' => CACHE . 'route.cache', @@ -227,9 +229,8 @@ if(!empty($page) && preg_match('/^[A-z0-9\/\-]+$/', $page)) { $foundRoute = false; - $routesFinal = []; $tmp = null; - if ($cache->fetch('routes_final', $tmp)) { + if ($cache->enabled() && $cache->fetch('routes_final', $tmp)) { $routesFinal = unserialize($tmp); } From 0d8f68a48e0b5ce3071567ad955475263981879c Mon Sep 17 00:00:00 2001 From: slawkens Date: Thu, 2 Oct 2025 22:31:16 +0200 Subject: [PATCH 06/40] Fix menus for ?subtopic= --- templates/tibiacom/index.php | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/templates/tibiacom/index.php b/templates/tibiacom/index.php index 1bfe6164..a6b57841 100644 --- a/templates/tibiacom/index.php +++ b/templates/tibiacom/index.php @@ -27,26 +27,18 @@ if(isset($config['boxes'])) var loginStatus=""; Date: Fri, 3 Oct 2025 00:25:41 +0200 Subject: [PATCH 07/40] Add lookmount into getTopPlayers --- system/functions.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/system/functions.php b/system/functions.php index 8c365391..b5141b2f 100644 --- a/system/functions.php +++ b/system/functions.php @@ -1146,6 +1146,10 @@ function getTopPlayers($limit = 5, $skill = 'level') { $columns[] = 'lookaddons'; } + if ($db->hasColumn('players', 'lookmount')) { + $columns[] = 'lookmount'; + } + return Player::query() ->select($columns) ->withOnlineStatus() From 901df48d134079d648a18f9d82b60182e818ac02 Mon Sep 17 00:00:00 2001 From: slawkens Date: Fri, 3 Oct 2025 00:31:03 +0200 Subject: [PATCH 08/40] Add promotion into getTopPlayers --- system/functions.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/system/functions.php b/system/functions.php index b5141b2f..212a043e 100644 --- a/system/functions.php +++ b/system/functions.php @@ -1142,6 +1142,10 @@ function getTopPlayers($limit = 5, $skill = 'level') { 'looktype', 'lookhead', 'lookbody', 'looklegs', 'lookfeet' ]; + if ($db->hasColumn('players', 'promotion')) { + $columns[] = 'promotion'; + } + if ($db->hasColumn('players', 'lookaddons')) { $columns[] = 'lookaddons'; } From 8272f1373c8592feebf2db5e092b294c4372ea75 Mon Sep 17 00:00:00 2001 From: slawkens Date: Fri, 3 Oct 2025 16:24:02 +0200 Subject: [PATCH 09/40] Fix database column info cache --- system/libs/pot/OTS_DB_MySQL.php | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/system/libs/pot/OTS_DB_MySQL.php b/system/libs/pot/OTS_DB_MySQL.php index 68f34787..8b9626d9 100644 --- a/system/libs/pot/OTS_DB_MySQL.php +++ b/system/libs/pot/OTS_DB_MySQL.php @@ -120,6 +120,11 @@ class OTS_DB_MySQL extends OTS_Base_DB if($cache->fetch('database_columns', $tmp) && $tmp) { $this->has_column_cache = unserialize($tmp); } + + $tmp = null; + if($cache->fetch('database_columns_info', $tmp) && $tmp) { + $this->get_column_info_cache = unserialize($tmp); + } } } @@ -156,11 +161,13 @@ class OTS_DB_MySQL extends OTS_Base_DB if ($this->clearCacheAfter) { $cache->delete('database_tables'); $cache->delete('database_columns'); + $cache->delete('database_columns_info'); $cache->delete('database_checksum'); } else { $cache->set('database_tables', serialize($this->has_table_cache), 3600); $cache->set('database_columns', serialize($this->has_column_cache), 3600); + $cache->set('database_columns_info', serialize($this->get_column_info_cache), 3600); $cache->set('database_checksum', serialize(sha1($config['database_host'] . '.' . $config['database_name'])), 3600); } } @@ -295,7 +302,8 @@ class OTS_DB_MySQL extends OTS_Base_DB return []; } - public function revalidateCache() { + public function revalidateCache(): void + { foreach($this->has_table_cache as $key => $value) { $this->hasTableInternal($key); } @@ -310,6 +318,21 @@ class OTS_DB_MySQL extends OTS_Base_DB $this->hasColumnInternal($explode[0], $explode[1]); } } + + foreach($this->get_column_info_cache as $key => $value) { + $explode = explode('.', $key); + if(!isset($this->has_table_cache[$explode[0]])) { // first check if table exist + $this->hasTableInternal($explode[0]); + } + + if($this->has_table_cache[$explode[0]]) { + $this->hasColumnInternal($explode[0], $explode[1]); + } + + if($this->has_table_cache[$explode[0]]) { + $this->getColumnInfoInternal($explode[0], $explode[1]); + } + } } public function setClearCacheAfter($clearCache) From 2eae44e0755e624a91be68b4d1ec26d01eb4d9a1 Mon Sep 17 00:00:00 2001 From: slawkens Date: Wed, 8 Oct 2025 14:39:23 +0200 Subject: [PATCH 10/40] Add missing compat config: email_lai_sec_interval --- system/compat/config.php | 1 + 1 file changed, 1 insertion(+) diff --git a/system/compat/config.php b/system/compat/config.php index 9d58f4d6..4fc3004a 100644 --- a/system/compat/config.php +++ b/system/compat/config.php @@ -81,6 +81,7 @@ $deprecatedConfig = [ 'account_change_character_name_points' => 'account_change_character_name_price', 'account_change_character_sex', 'account_change_character_sex_points' => 'account_change_character_name_price', + 'email_lai_sec_interval' => 'mail_lost_account_interval', ]; foreach ($deprecatedConfig as $key => $value) { From 8c3cb0e06f9709c1de3398b48221241e7cbdd310 Mon Sep 17 00:00:00 2001 From: slawkens Date: Sat, 11 Oct 2025 18:34:15 +0200 Subject: [PATCH 11/40] New configurable: hooks_debug To view where hooks are located in .twig files --- system/twig.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/system/twig.php b/system/twig.php index ecc7a957..89f25939 100644 --- a/system/twig.php +++ b/system/twig.php @@ -101,7 +101,9 @@ $twig->addFunction($function); $function = new TwigFunction('hook', function ($context, $hook, array $params = []) { global $hooks; - //note($hook); + if (config('hooks_debug')) { + note($hook); + } if(is_string($hook)) { if (defined($hook)) { From 9acad15451071639acf7a7d4e81619b0a9742b12 Mon Sep 17 00:00:00 2001 From: slawkens Date: Sun, 12 Oct 2025 00:15:04 +0200 Subject: [PATCH 12/40] Allow links in error_box --- system/templates/error_box.html.twig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/templates/error_box.html.twig b/system/templates/error_box.html.twig index e6ed4992..ba9a2263 100644 --- a/system/templates/error_box.html.twig +++ b/system/templates/error_box.html.twig @@ -9,7 +9,7 @@
The Following Errors Have Occurred:
{% for error in errors %} -
  • {{ error|striptags('')|raw }}
  • +
  • {{ error|striptags('')|raw }}
  • {% endfor %}
    @@ -17,4 +17,4 @@
    -
    \ No newline at end of file +
    From fe821c58085483e70491dcf76376ad5b96de3fdd Mon Sep 17 00:00:00 2001 From: Slawomir Boczek Date: Sun, 12 Oct 2025 11:19:30 +0200 Subject: [PATCH 13/40] Feature/resend email verify (#333) * feat: Resend Email Verify + rework the whole concept, based on new table for email hashes This make it possible that every email will work, not matter if first or last * Nothing important: change variable name * Change message --- common.php | 2 +- install/includes/schema.sql | 11 ++- install/tools/5-database.php | 9 +- .../migrations/46-account_emails_verify.sql | 8 ++ system/migrations/46.php | 24 +++++ system/pages/account/confirm-email.php | 13 ++- system/pages/account/create.php | 8 +- system/pages/account/login.php | 4 +- system/pages/account/resend-email-verify.php | 94 +++++++++++++++++++ system/src/Models/AccountEmailVerify.php | 15 +++ .../account.resend-email-verify.html.twig | 45 +++++++++ ...mail.account.resend-email-verify.html.twig | 7 ++ 12 files changed, 225 insertions(+), 15 deletions(-) create mode 100644 system/migrations/46-account_emails_verify.sql create mode 100644 system/migrations/46.php create mode 100644 system/pages/account/resend-email-verify.php create mode 100644 system/src/Models/AccountEmailVerify.php create mode 100644 system/templates/account.resend-email-verify.html.twig create mode 100644 system/templates/mail.account.resend-email-verify.html.twig diff --git a/common.php b/common.php index 6bb6be85..e26921c5 100644 --- a/common.php +++ b/common.php @@ -27,7 +27,7 @@ if (version_compare(phpversion(), '8.1', '<')) die('PHP version 8.1 or higher is const MYAAC = true; const MYAAC_VERSION = '1.8.3-dev'; -const DATABASE_VERSION = 45; +const DATABASE_VERSION = 46; const TABLE_PREFIX = 'myaac_'; define('START_TIME', microtime(true)); define('MYAAC_OS', stripos(PHP_OS, 'WIN') === 0 ? 'WINDOWS' : (strtoupper(PHP_OS) === 'DARWIN' ? 'MAC' : 'LINUX')); diff --git a/install/includes/schema.sql b/install/includes/schema.sql index eccaee54..b53ffab2 100644 --- a/install/includes/schema.sql +++ b/install/includes/schema.sql @@ -1,4 +1,4 @@ -SET @myaac_database_version = 45; +SET @myaac_database_version = 46; CREATE TABLE `myaac_account_actions` ( @@ -10,6 +10,15 @@ CREATE TABLE `myaac_account_actions` KEY (`account_id`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; +CREATE TABLE `myaac_account_emails_verify` +( + `id` int NOT NULL AUTO_INCREMENT, + `account_id` int NOT NULL, + `hash` varchar(32) NOT NULL, + `sent_at` int NOT NULL DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; + CREATE TABLE `myaac_admin_menu` ( `id` int NOT NULL AUTO_INCREMENT, diff --git a/install/tools/5-database.php b/install/tools/5-database.php index b9ff587f..f97eca11 100644 --- a/install/tools/5-database.php +++ b/install/tools/5-database.php @@ -102,18 +102,13 @@ if(!$db->hasColumn('accounts', 'web_flags')) { success($locale['step_database_adding_field'] . ' accounts.web_flags...'); } -if(!$db->hasColumn('accounts', 'email_hash')) { - if(query("ALTER TABLE `accounts` ADD `email_hash` VARCHAR(32) NOT NULL DEFAULT '' AFTER `web_flags`;")) - success($locale['step_database_adding_field'] . ' accounts.email_hash...'); -} - if(!$db->hasColumn('accounts', 'email_verified')) { - if(query("ALTER TABLE `accounts` ADD `email_verified` TINYINT(1) NOT NULL DEFAULT 0 AFTER `email_hash`;")) + if(query("ALTER TABLE `accounts` ADD `email_verified` TINYINT(1) NOT NULL DEFAULT 0 AFTER `web_flags`;")) success($locale['step_database_adding_field'] . ' accounts.email_verified...'); } if(!$db->hasColumn('accounts', 'email_new')) { - if(query("ALTER TABLE `accounts` ADD `email_new` VARCHAR(255) NOT NULL DEFAULT '' AFTER `email_hash`;")) + if(query("ALTER TABLE `accounts` ADD `email_new` VARCHAR(255) NOT NULL DEFAULT '' AFTER `email_verified`;")) success($locale['step_database_adding_field'] . ' accounts.email_new...'); } diff --git a/system/migrations/46-account_emails_verify.sql b/system/migrations/46-account_emails_verify.sql new file mode 100644 index 00000000..13d42b16 --- /dev/null +++ b/system/migrations/46-account_emails_verify.sql @@ -0,0 +1,8 @@ +CREATE TABLE `myaac_account_emails_verify` +( + `id` int NOT NULL AUTO_INCREMENT, + `account_id` int NOT NULL, + `hash` varchar(32) NOT NULL, + `sent_at` int NOT NULL DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; diff --git a/system/migrations/46.php b/system/migrations/46.php new file mode 100644 index 00000000..452527e5 --- /dev/null +++ b/system/migrations/46.php @@ -0,0 +1,24 @@ +hasColumn('accounts', 'email_hash')) { + $db->dropColumn('accounts', 'email_hash'); + } + + if (!$db->hasTable(TABLE_PREFIX . 'account_emails_verify')) { + $db->query(file_get_contents(__DIR__ . '/46-account_emails_verify.sql')); + } +}; + +$down = function () use ($db) { + if (!$db->hasColumn('accounts', 'email_hash')) { + $db->addColumn('accounts', 'email_hash', "varchar(32) NOT NULL DEFAULT ''"); + } + + if ($db->hasTable(TABLE_PREFIX . 'account_emails_verify')) { + $db->dropTable(TABLE_PREFIX . 'account_emails_verify'); + } +}; diff --git a/system/pages/account/confirm-email.php b/system/pages/account/confirm-email.php index 615dd942..87183a3c 100644 --- a/system/pages/account/confirm-email.php +++ b/system/pages/account/confirm-email.php @@ -9,6 +9,7 @@ */ use MyAAC\Models\Account; +use MyAAC\Models\AccountEmailVerify; defined('MYAAC') or die('Direct access not allowed!'); @@ -20,16 +21,20 @@ if(empty($hash)) { return; } -if(!Account::where('email_hash', $hash)->exists()) { - note("Your email couldn't be verified. Please contact staff to do it manually."); +// by default link is valid for 30 days +$accountEmailVerify = AccountEmailVerify::where('hash', $hash)->where('sent_at', '>', time() - 30 * 24 * 60 * 60)->first(); +if(!$accountEmailVerify) { + note("Wrong link or link has expired."); } else { - $accountModel = Account::where('email_hash', $hash)->where('email_verified', 0)->first(); + $accountModel = Account::where('id', $accountEmailVerify->account_id)->where('email_verified', 0)->first(); if ($accountModel) { $accountModel->email_verified = 1; $accountModel->save(); + AccountEmailVerify::where('account_id', $accountModel->id)->delete(); + success('You have now verified your e-mail, this will increase the security of your account. Thank you for doing this. You can now
    log in.'); $account = new OTS_Account(); @@ -39,6 +44,6 @@ else } } else { - error('Link has expired.'); + error('Your account is already verified.'); } } diff --git a/system/pages/account/create.php b/system/pages/account/create.php index 7a0d3c56..9ffdf6f7 100644 --- a/system/pages/account/create.php +++ b/system/pages/account/create.php @@ -10,6 +10,7 @@ */ use MyAAC\CreateCharacter; +use MyAAC\Models\AccountEmailVerify; defined('MYAAC') or die('Direct access not allowed!'); $title = 'Create Account'; @@ -244,7 +245,12 @@ if($save) if(setting('core.mail_enabled') && setting('core.account_mail_verify')) { $hash = md5(generateRandomString(16, true, true) . $email); - $new_account->setCustomField('email_hash', $hash); + + AccountEmailVerify::create([ + 'account_id' => $new_account->getId(), + 'hash' => $hash, + 'sent_at' => time(), + ]); $verify_url = getLink('account/confirm-email/' . $hash); $body_html = $twig->render('mail.account.verify.html.twig', array( diff --git a/system/pages/account/login.php b/system/pages/account/login.php index d6771c91..e18dacf4 100644 --- a/system/pages/account/login.php +++ b/system/pages/account/login.php @@ -48,7 +48,9 @@ if(!empty($login_account) && !empty($login_password)) ) { if (setting('core.account_mail_verify') && (int)$account_logged->getCustomField('email_verified') !== 1) { - $errors[] = 'Your account is not verified. Please verify your email address. If the message is not coming check the SPAM folder in your E-Mail client.'; + $link = getLink('account/resend-email-verify'); + $errors[] = 'Your account is not verified. Please verify your email address. If the message is not coming check the SPAM folder in your E-Mail client.
    ' . + 'You can resend the Email here: ' . $link . ''; } else { session_regenerate_id(); setSession('account', $account_logged->getId()); diff --git a/system/pages/account/resend-email-verify.php b/system/pages/account/resend-email-verify.php new file mode 100644 index 00000000..ffccb548 --- /dev/null +++ b/system/pages/account/resend-email-verify.php @@ -0,0 +1,94 @@ +display('error_box.html.twig', ['errors' => $errors]); + $twig->display('account.back_button.html.twig', [ + 'action' => getLink('account/resend-email-verify'), + ]); +}; + +if (!setting('core.mail_enabled') || !setting('core.account_mail_verify')) { + $errorWithBackButton('Resending email is not possible on this server.'); + return; +} + +$showForm = true; + +if (isset($_POST['submit']) && $_POST['submit'] == '1') { + $email = $_REQUEST['email']; + + if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) { + $errorWithBackButton('Please enter valid Email.'); + return; + } + + $account = new OTS_Account(); + $account->findByEMail($email); + if ($account->isLoaded()) { + if ($account->getCustomField('email_verified') == '1') { + $errorWithBackButton('This account is already verified! You can log in on the website.'); + return; + } + + $accountEmailVerify = AccountEmailVerify::where('account_id', $account->getId())->orderBy('sent_at', 'DESC')->first(); + if ($accountEmailVerify && time() - $accountEmailVerify->sent_at < 60) { + $errorWithBackButton('Only one Email per minute is allowed. Please try again later.'); + return; + } + + $tmp_account = $email; + if (!config('account_login_by_email')) { + $tmp_account = (USE_ACCOUNT_NAME ? $account->getName() : $account->getId()); + } + + $hash = md5(generateRandomString(16, true, true) . $email); + + AccountEmailVerify::create([ + 'account_id' => $account->getId(), + 'hash' => $hash, + 'sent_at' => time(), + ]); + + $verify_url = getLink('account/confirm-email/' . $hash); + $body_html = $twig->render('mail.account.resend-email-verify.html.twig', array( + 'account' => $tmp_account, + 'verify_url' => generateLink($verify_url, $verify_url, true) + )); + + if (_mail($account->getEMail(), configLua('serverName') . ' - Verify Account', $body_html)) { + $message = "If account with this email exists - you will become an email with verification link."; + $showForm = false; + } else { + $message = "

    An error occurred while sending email ({$email} )! Try again later. For Admin: More info can be found in system/logs/mailer-error.log

    "; + } + } + else { + $message = "
    If account with this email exists - you will become an email with verification link."; + $showForm = false; + } + + $twig->display('success.html.twig', array( + 'title' => 'Verify Email Sent', + 'description' => $message, + )); +} + +//show errors if not empty +if (!empty($errors)) { + $twig->display('error_box.html.twig', ['errors' => $errors]); + $twig->display('account.back_button.html.twig', [ + 'action' => getLink('account/resend-email-verify'), + ]); +} + +if ($showForm) { + $twig->display('account.resend-email-verify.html.twig'); +} diff --git a/system/src/Models/AccountEmailVerify.php b/system/src/Models/AccountEmailVerify.php new file mode 100644 index 00000000..8773750f --- /dev/null +++ b/system/src/Models/AccountEmailVerify.php @@ -0,0 +1,15 @@ +
    +{% set title = 'Resend Email' %} +{% set background = config('darkborder') %} +{% set content %} + + + + + +
    + + + +
    +{% endset %} +{% include 'tables.headline.html.twig' %} +
    + + + + + +
    + + + + +
    +
    + {{ csrf() }} + + {{ include('buttons.submit.html.twig') }} +
    +
    +
    + + + + +
    +
    + {{ include('buttons.back.html.twig') }} +
    +
    +
    diff --git a/system/templates/mail.account.resend-email-verify.html.twig b/system/templates/mail.account.resend-email-verify.html.twig new file mode 100644 index 00000000..75bdab8b --- /dev/null +++ b/system/templates/mail.account.resend-email-verify.html.twig @@ -0,0 +1,7 @@ +Hello {{ account }}!
    +
    +You requested to resend the verify Email on {{ config.lua.serverName }}!
    +
    + +To verify your email address please click the link below:
    +{{ verify_url|raw }} From c91bb5d4097647dca2196d3dea87bc90c89181d2 Mon Sep 17 00:00:00 2001 From: slawkens Date: Sun, 12 Oct 2025 21:53:01 +0200 Subject: [PATCH 14/40] Fix guild create with freePremium --- system/pages/guilds/create.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/system/pages/guilds/create.php b/system/pages/guilds/create.php index ef0117e8..ba348a36 100644 --- a/system/pages/guilds/create.php +++ b/system/pages/guilds/create.php @@ -21,6 +21,8 @@ if(!$logged) { $errors[] = 'You are not logged in. You can\'t create guild.'; } +$freePremium = getBoolean(configLua('freePremium')); + $array_of_player_nig = array(); if(empty($errors)) { @@ -31,7 +33,7 @@ if(empty($errors)) if(!$player_rank->isLoaded()) { if($player->getLevel() >= setting('core.guild_need_level')) { - if(!setting('core.guild_need_premium') || $account_logged->isPremium()) { + if(!setting('core.guild_need_premium') || $account_logged->isPremium() || $freePremium) { $array_of_player_nig[] = $player->getName(); } } @@ -95,7 +97,7 @@ if($todo == 'save') if($player->getLevel() < setting('core.guild_need_level')) { $errors[] = 'Character '.$name.' has too low level. To create guild you need character with level ' . setting('core.guild_need_level') . '.'; } - if(setting('core.guild_need_premium') && !$account_logged->isPremium()) { + if(setting('core.guild_need_premium') && !$account_logged->isPremium() && !$freePremium) { $errors[] = 'Character '.$name.' is on FREE account. To create guild you need PREMIUM account.'; } } From 90c846379751ab53b127ab7210efafbcd6353487 Mon Sep 17 00:00:00 2001 From: slawkens Date: Mon, 13 Oct 2025 17:52:39 +0200 Subject: [PATCH 15/40] Update create.php --- system/pages/guilds/create.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/system/pages/guilds/create.php b/system/pages/guilds/create.php index ba348a36..6921595f 100644 --- a/system/pages/guilds/create.php +++ b/system/pages/guilds/create.php @@ -21,7 +21,8 @@ if(!$logged) { $errors[] = 'You are not logged in. You can\'t create guild.'; } -$freePremium = getBoolean(configLua('freePremium')); +$configLuaFreePremium = configLua('freePremium'); +$freePremium = (isset($configLuaFreePremium) && getBoolean($configLuaFreePremium)) || $account_logged->getPremDays() == OTS_Account::GRATIS_PREMIUM_DAYS; $array_of_player_nig = array(); if(empty($errors)) From b797908e49fe66518f59d8854d939f9b9f8a2e5e Mon Sep 17 00:00:00 2001 From: slawkens Date: Mon, 13 Oct 2025 17:53:26 +0200 Subject: [PATCH 16/40] Update create.php --- system/pages/guilds/create.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/pages/guilds/create.php b/system/pages/guilds/create.php index 6921595f..08bc8817 100644 --- a/system/pages/guilds/create.php +++ b/system/pages/guilds/create.php @@ -22,7 +22,7 @@ if(!$logged) { } $configLuaFreePremium = configLua('freePremium'); -$freePremium = (isset($configLuaFreePremium) && getBoolean($configLuaFreePremium)) || $account_logged->getPremDays() == OTS_Account::GRATIS_PREMIUM_DAYS; +$freePremium = (isset($configLuaFreePremium) && getBoolean($configLuaFreePremium)) || ($logged && $account_logged->getPremDays() == OTS_Account::GRATIS_PREMIUM_DAYS); $array_of_player_nig = array(); if(empty($errors)) From 82d417b5906c15580bd796fb54099151f3889260 Mon Sep 17 00:00:00 2001 From: slawkens Date: Mon, 13 Oct 2025 18:01:19 +0200 Subject: [PATCH 17/40] Change spaces to tabs --- system/libs/pot/OTS_Account.php | 824 ++++++++++++++++---------------- 1 file changed, 412 insertions(+), 412 deletions(-) diff --git a/system/libs/pot/OTS_Account.php b/system/libs/pot/OTS_Account.php index 20c7fe32..872d1c89 100644 --- a/system/libs/pot/OTS_Account.php +++ b/system/libs/pot/OTS_Account.php @@ -38,7 +38,7 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @var array * @version 0.1.5 */ - private $data = array('email' => '', 'rlname' => '','location' => '', 'country' => '','web_flags' => 0, 'lastday' => 0, 'premdays' => 0, 'created' => 0); + private $data = array('email' => '', 'rlname' => '','location' => '', 'country' => '','web_flags' => 0, 'lastday' => 0, 'premdays' => 0, 'created' => 0); public static $cache = array(); @@ -66,39 +66,39 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @example examples/create.php create.php * @tutorial POT/Accounts.pkg#create */ - public function createNamed($name = null) - { - // if name is not passed then it will be generated randomly - if( !isset($name) ) - { - // reads already existing names - foreach( $this->db->query('SELECT ' . $this->db->fieldName('name') . ' FROM ' . $this->db->tableName('accounts') )->fetchAll() as $account) - { - $exist[] = $account['name']; - } + public function createNamed($name = null) + { + // if name is not passed then it will be generated randomly + if( !isset($name) ) + { + // reads already existing names + foreach( $this->db->query('SELECT ' . $this->db->fieldName('name') . ' FROM ' . $this->db->tableName('accounts') )->fetchAll() as $account) + { + $exist[] = $account['name']; + } - // initial name - $name = uniqid(); + // initial name + $name = uniqid(); - // repeats until name is unique - while( in_array($name, $exist) ) - { - $name .= '_'; - } + // repeats until name is unique + while( in_array($name, $exist) ) + { + $name .= '_'; + } - // resets array for account numbers loop - $exist = array(); - } + // resets array for account numbers loop + $exist = array(); + } - // saves blank account info - $this->db->exec('INSERT INTO ' . $this->db->tableName('accounts') . ' (' . $this->db->fieldName('name') . ', ' . $this->db->fieldName('password') . ', ' . $this->db->fieldName('email') . ') VALUES (' . $this->db->quote($name) . ', \'\', \'\')'); + // saves blank account info + $this->db->exec('INSERT INTO ' . $this->db->tableName('accounts') . ' (' . $this->db->fieldName('name') . ', ' . $this->db->fieldName('password') . ', ' . $this->db->fieldName('email') . ') VALUES (' . $this->db->quote($name) . ', \'\', \'\')'); - // reads created account's ID - $this->data['id'] = $this->db->lastInsertId(); + // reads created account's ID + $this->data['id'] = $this->db->lastInsertId(); - // return name of newly created account - return $name; - } + // return name of newly created account + return $name; + } /** * @param $email @@ -166,8 +166,8 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @throws Exception ON lastInsertId error. * @deprecated 0.1.5 Use createNamed(). */ - public function create($name = NULL, $id = NULL) - { + public function create($name = NULL, $id = NULL) + { if(isset($name)) { $nameOrNumber = 'name'; $nameOrNumberValue = $name; @@ -183,8 +183,8 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable } } - // saves blank account info - $this->db->exec('INSERT INTO `accounts` (' . (isset($id) ? '`id`,' : '') . (isset($nameOrNumber) ? '`' . $nameOrNumber . '`,' : '') . '`password`, `email`, `created`) VALUES (' . (isset($id) ? $id . ',' : '') . (isset($nameOrNumber) ? $this->db->quote($nameOrNumberValue) . ',' : '') . ' \'\', \'\',' . time() . ')'); + // saves blank account info + $this->db->exec('INSERT INTO `accounts` (' . (isset($id) ? '`id`,' : '') . (isset($nameOrNumber) ? '`' . $nameOrNumber . '`,' : '') . '`password`, `email`, `created`) VALUES (' . (isset($id) ? $id . ',' : '') . (isset($nameOrNumber) ? $this->db->quote($nameOrNumberValue) . ',' : '') . ' \'\', \'\',' . time() . ')'); if(isset($name)) { $this->data['name'] = $name; @@ -206,8 +206,8 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable throw new Exception(__CLASS__ . ':' . __METHOD__ . ' unexpected error. Please report to MyAAC Developers.'); } - return $this->data['id']; - } + return $this->data['id']; + } /** * @version 0.0.6 @@ -218,10 +218,10 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @return int Created account number. * @deprecated 0.0.6 There is no more group_id field in database, use create(). */ - public function createEx(OTS_Group $group, $min = 1, $max = 9999999) - { - return $this->create($min, $max); - } + public function createEx(OTS_Group $group, $min = 1, $max = 9999999) + { + return $this->create($min, $max); + } /** * Loads account with given number. @@ -230,8 +230,8 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @param int $id Account number. * @throws PDOException On PDO operation error. */ - public function load($id, $fresh = false) - { + public function load($id, $fresh = false) + { if(!$fresh && isset(self::$cache[$id])) { $this->data = self::$cache[$id]; return; @@ -244,10 +244,10 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable $nameOrNumber = '`number`,'; } - // SELECT query on database + // SELECT query on database $this->data = $this->db->query('SELECT `id`, ' . $nameOrNumber . '`password`, `email`, `rlname`, `location`, `country`, `web_flags`, ' . ($this->db->hasColumn('accounts', 'premdays') ? '`premdays`, ' : '') . ($this->db->hasColumn('accounts', 'lastday') ? '`lastday`, ' : ($this->db->hasColumn('accounts', 'premend') ? '`premend`,' : ($this->db->hasColumn('accounts', 'premium_ends_at') ? '`premium_ends_at`,' : ''))) . '`created` FROM `accounts` WHERE `id` = ' . (int) $id)->fetch(); self::$cache[$id] = $this->data; - } + } /** * Loads account by it's name. @@ -261,22 +261,22 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @param string $name Account's name. * @throws PDOException On PDO operation error. */ - public function find($name) - { + public function find($name) + { $nameOrNumberColumn = 'name'; if (USE_ACCOUNT_NUMBER) { $nameOrNumberColumn = 'number'; } - // finds player's ID - $id = $this->db->query('SELECT `id` FROM `accounts` WHERE `' . $nameOrNumberColumn . '` = ' . $this->db->quote($name) )->fetch(); + // finds player's ID + $id = $this->db->query('SELECT `id` FROM `accounts` WHERE `' . $nameOrNumberColumn . '` = ' . $this->db->quote($name) )->fetch(); - // if anything was found - if( isset($id['id']) ) - { - $this->load($id['id']); - } - } + // if anything was found + if( isset($id['id']) ) + { + $this->load($id['id']); + } + } /** * Loads account by it's e-mail address. @@ -286,27 +286,27 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @param string $email Account's e-mail address. * @throws PDOException On PDO operation error. */ - public function findByEMail($email) - { - // finds player's ID - $id = $this->db->query('SELECT `id` FROM `accounts` WHERE `email` = ' . $this->db->quote($email) )->fetch(); + public function findByEMail($email) + { + // finds player's ID + $id = $this->db->query('SELECT `id` FROM `accounts` WHERE `email` = ' . $this->db->quote($email) )->fetch(); - // if anything was found - if( isset($id['id']) ) - { - $this->load($id['id']); - } - } + // if anything was found + if( isset($id['id']) ) + { + $this->load($id['id']); + } + } /** * Checks if object is loaded. * * @return bool Load state. */ - public function isLoaded() - { - return isset($this->data['id']); - } + public function isLoaded() + { + return isset($this->data['id']); + } /** * Updates account in database. @@ -323,16 +323,16 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @throws E_OTS_NotLoaded If account doesn't have ID assigned. * @throws PDOException On PDO operation error. */ - public function save() - { - if( !isset($this->data['id']) ) - { - throw new E_OTS_NotLoaded(); - } + public function save() + { + if( !isset($this->data['id']) ) + { + throw new E_OTS_NotLoaded(); + } $field = 'lastday'; if($this->db->hasColumn('accounts', 'premend')) { // othire - $field = 'premend'; + $field = 'premend'; if(!isset($this->data['premend'])) { $this->data['premend'] = 0; } @@ -344,9 +344,9 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable } } - // UPDATE query on database - $this->db->exec('UPDATE `accounts` SET ' . ($this->db->hasColumn('accounts', 'name') ? '`name` = ' . $this->db->quote($this->data['name']) . ',' : '') . '`password` = ' . $this->db->quote($this->data['password']) . ', `email` = ' . $this->db->quote($this->data['email']) . ', `rlname` = ' . $this->db->quote($this->data['rlname']) . ', `location` = ' . $this->db->quote($this->data['location']) . ', `country` = ' . $this->db->quote($this->data['country']) . ', `web_flags` = ' . (int) $this->data['web_flags'] . ', ' . ($this->db->hasColumn('accounts', 'premdays') ? '`premdays` = ' . (int) $this->data['premdays'] . ',' : '') . '`' . $field . '` = ' . (int) $this->data[$field] . ' WHERE `id` = ' . $this->data['id']); - } + // UPDATE query on database + $this->db->exec('UPDATE `accounts` SET ' . ($this->db->hasColumn('accounts', 'name') ? '`name` = ' . $this->db->quote($this->data['name']) . ',' : '') . '`password` = ' . $this->db->quote($this->data['password']) . ', `email` = ' . $this->db->quote($this->data['email']) . ', `rlname` = ' . $this->db->quote($this->data['rlname']) . ', `location` = ' . $this->db->quote($this->data['location']) . ', `country` = ' . $this->db->quote($this->data['country']) . ', `web_flags` = ' . (int) $this->data['web_flags'] . ', ' . ($this->db->hasColumn('accounts', 'premdays') ? '`premdays` = ' . (int) $this->data['premdays'] . ',' : '') . '`' . $field . '` = ' . (int) $this->data[$field] . ' WHERE `id` = ' . $this->data['id']); + } /** * Account number. @@ -359,15 +359,15 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @return int Account number. * @throws E_OTS_NotLoaded If account is not loaded. */ - public function getId() - { - if( !isset($this->data['id']) ) - { - throw new E_OTS_NotLoaded(); - } + public function getId() + { + if( !isset($this->data['id']) ) + { + throw new E_OTS_NotLoaded(); + } - return $this->data['id']; - } + return $this->data['id']; + } public function getNumber() { @@ -378,45 +378,45 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable return $this->data['id']; } - public function getRLName() - { - if( !isset($this->data['rlname']) ) - { - throw new E_OTS_NotLoaded(); - } + public function getRLName() + { + if( !isset($this->data['rlname']) ) + { + throw new E_OTS_NotLoaded(); + } - return $this->data['rlname']; - } + return $this->data['rlname']; + } - public function getLocation() - { - if( !isset($this->data['location']) ) - { - throw new E_OTS_NotLoaded(); - } + public function getLocation() + { + if( !isset($this->data['location']) ) + { + throw new E_OTS_NotLoaded(); + } - return $this->data['location']; - } + return $this->data['location']; + } - public function getCountry() - { - if( !isset($this->data['country']) ) - { - throw new E_OTS_NotLoaded(); - } + public function getCountry() + { + if( !isset($this->data['country']) ) + { + throw new E_OTS_NotLoaded(); + } - return $this->data['country']; - } + return $this->data['country']; + } - public function getWebFlags() - { - if( !isset($this->data['web_flags']) ) - { - throw new E_OTS_NotLoaded(); - } + public function getWebFlags() + { + if( !isset($this->data['web_flags']) ) + { + throw new E_OTS_NotLoaded(); + } - return $this->data['web_flags']; - } + return $this->data['web_flags']; + } public function hasFlag($flag) { @@ -462,17 +462,17 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable } public function getLastLogin() - { - if( !isset($this->data['lastday']) ) - { - throw new E_OTS_NotLoaded(); - } + { + if( !isset($this->data['lastday']) ) + { + throw new E_OTS_NotLoaded(); + } - return $this->data['lastday']; - } + return $this->data['lastday']; + } - public function isPremium() - { + public function isPremium() + { if(isset($this->data['premium_ends_at'])) { return $this->data['premium_ends_at'] > time(); } @@ -484,15 +484,15 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable return ($this->data['premdays'] - (date("z", time()) + (365 * (date("Y", time()) - date("Y", $this->data['lastday']))) - date("z", $this->data['lastday'])) > 0); } - public function getCreated() - { - if( !isset($this->data['created']) ) - { - throw new E_OTS_NotLoaded(); - } + public function getCreated() + { + if( !isset($this->data['created']) ) + { + throw new E_OTS_NotLoaded(); + } - return $this->data['created']; - } + return $this->data['created']; + } /** * Name. @@ -501,37 +501,37 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @since 0.7.5 * @throws E_OTS_NotLoaded If account is not loaded. */ - public function setPremDays($premdays) - { + public function setPremDays($premdays) + { $this->data['premdays'] = (int) $premdays; $this->data['premend'] = time() + ($premdays * 24 * 60 * 60); $this->data['premium_ends_at'] = time() + ($premdays * 24 * 60 * 60); - } + } - public function setRLName($name) - { - $this->data['rlname'] = (string) $name; - } + public function setRLName($name) + { + $this->data['rlname'] = (string) $name; + } - public function setLocation($location) - { - $this->data['location'] = (string) $location; - } + public function setLocation($location) + { + $this->data['location'] = (string) $location; + } - public function setCountry($country) - { - $this->data['country'] = (string) $country; - } + public function setCountry($country) + { + $this->data['country'] = (string) $country; + } public function setLastLogin($lastlogin) - { - $this->data['lastday'] = (int) $lastlogin; - } + { + $this->data['lastday'] = (int) $lastlogin; + } - public function setWebFlags($webflags) - { - $this->data['web_flags'] = (int) $webflags; - } + public function setWebFlags($webflags) + { + $this->data['web_flags'] = (int) $webflags; + } /** * Name. @@ -541,15 +541,15 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @return string Name. * @throws E_OTS_NotLoaded If account is not loaded. */ - public function getName() - { - if( !isset($this->data['name']) ) - { - throw new E_OTS_NotLoaded(); - } + public function getName() + { + if( !isset($this->data['name']) ) + { + throw new E_OTS_NotLoaded(); + } - return $this->data['name']; - } + return $this->data['name']; + } /** * Sets account's name. @@ -562,10 +562,10 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @since 0.1.5 * @param string $name Account name. */ - public function setName($name) - { - $this->data['name'] = (string) $name; - } + public function setName($name) + { + $this->data['name'] = (string) $name; + } /** * Account's password. @@ -582,15 +582,15 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @return string Password. * @throws E_OTS_NotLoaded If account is not loaded. */ - public function getPassword() - { - if( !isset($this->data['password']) ) - { - throw new E_OTS_NotLoaded(); - } + public function getPassword() + { + if( !isset($this->data['password']) ) + { + throw new E_OTS_NotLoaded(); + } - return $this->data['password']; - } + return $this->data['password']; + } /** * Sets account's password. @@ -605,10 +605,10 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * * @param string $password Password. */ - public function setPassword($password) - { - $this->data['password'] = (string) $password; - } + public function setPassword($password) + { + $this->data['password'] = (string) $password; + } /** * E-mail address. * @@ -620,15 +620,15 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @return string E-mail. * @throws E_OTS_NotLoaded If account is not loaded. */ - public function getEMail() - { - if( !isset($this->data['email']) ) - { - throw new E_OTS_NotLoaded(); - } + public function getEMail() + { + if( !isset($this->data['email']) ) + { + throw new E_OTS_NotLoaded(); + } - return $this->data['email']; - } + return $this->data['email']; + } /** * Sets account's email. @@ -639,10 +639,10 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * * @param string $email E-mail address. */ - public function setEMail($email) - { - $this->data['email'] = (string) $email; - } + public function setEMail($email) + { + $this->data['email'] = (string) $email; + } /** * Reads custom field. @@ -662,16 +662,16 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @throws E_OTS_NotLoaded If account is not loaded. * @throws PDOException On PDO operation error. */ - public function getCustomField($field) - { - if( !isset($this->data['id']) ) - { - throw new E_OTS_NotLoaded(); - } + public function getCustomField($field) + { + if( !isset($this->data['id']) ) + { + throw new E_OTS_NotLoaded(); + } - $value = $this->db->query('SELECT ' . $this->db->fieldName($field) . ' FROM ' . $this->db->tableName('accounts') . ' WHERE ' . $this->db->fieldName('id') . ' = ' . $this->data['id'])->fetch(); - return $value[$field]; - } + $value = $this->db->query('SELECT ' . $this->db->fieldName($field) . ' FROM ' . $this->db->tableName('accounts') . ' WHERE ' . $this->db->fieldName('id') . ' = ' . $this->data['id'])->fetch(); + return $value[$field]; + } /** * Writes custom field. @@ -695,20 +695,20 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @throws E_OTS_NotLoaded If account is not loaded. * @throws PDOException On PDO operation error. */ - public function setCustomField($field, $value) - { - if( !isset($this->data['id']) ) - { - throw new E_OTS_NotLoaded(); - } + public function setCustomField($field, $value) + { + if( !isset($this->data['id']) ) + { + throw new E_OTS_NotLoaded(); + } - // quotes value for SQL query - if(!( is_int($value) || is_float($value) )) - { - $value = $this->db->quote($value); - } - $this->db->exec('UPDATE ' . $this->db->tableName('accounts') . ' SET ' . $this->db->fieldName($field) . ' = ' . $value . ' WHERE ' . $this->db->fieldName('id') . ' = ' . $this->data['id']); - } + // quotes value for SQL query + if(!( is_int($value) || is_float($value) )) + { + $value = $this->db->quote($value); + } + $this->db->exec('UPDATE ' . $this->db->tableName('accounts') . ' SET ' . $this->db->fieldName($field) . ' = ' . $value . ' WHERE ' . $this->db->fieldName('id') . ' = ' . $this->data['id']); + } /** * @version 0.1.0 @@ -716,25 +716,25 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @throws E_OTS_NotLoaded If account is not loaded. * @deprecated 0.0.5 Use getPlayersList(). */ - public function getPlayers() - { - if( !isset($this->data['id']) ) - { - throw new E_OTS_NotLoaded(); - } + public function getPlayers() + { + if( !isset($this->data['id']) ) + { + throw new E_OTS_NotLoaded(); + } - $players = array(); + $players = array(); - foreach( $this->db->query('SELECT ' . $this->db->fieldName('id') . ' FROM ' . $this->db->tableName('players') . ' WHERE ' . $this->db->fieldName('account_id') . ' = ' . $this->data['id'])->fetchAll() as $player) - { - // creates new object - $object = new OTS_Player(); - $object->load($player['id']); - $players[] = $object; - } + foreach( $this->db->query('SELECT ' . $this->db->fieldName('id') . ' FROM ' . $this->db->tableName('players') . ' WHERE ' . $this->db->fieldName('account_id') . ' = ' . $this->data['id'])->fetchAll() as $player) + { + // creates new object + $object = new OTS_Player(); + $object->load($player['id']); + $players[] = $object; + } - return $players; - } + return $players; + } /** * List of characters on account. @@ -752,16 +752,16 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @return OTS_Players_List List of players from current account. * @throws E_OTS_NotLoaded If account is not loaded. */ - public function getPlayersList($withDeleted = true) - { - if( !isset($this->data['id']) ) - { - throw new E_OTS_NotLoaded(); - } + public function getPlayersList($withDeleted = true) + { + if( !isset($this->data['id']) ) + { + throw new E_OTS_NotLoaded(); + } - // creates filter - $filter = new OTS_SQLFilter(); - $filter->compareField('account_id', (int) $this->data['id']); + // creates filter + $filter = new OTS_SQLFilter(); + $filter->compareField('account_id', (int) $this->data['id']); if(!$withDeleted) { global $db; @@ -772,12 +772,12 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable } } - // creates list object - $list = new OTS_Players_List(); - $list->setFilter($filter); + // creates list object + $list = new OTS_Players_List(); + $list->setFilter($filter); - return $list; - } + return $list; + } /** * @version 0.1.5 @@ -786,22 +786,22 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @throws PDOException On PDO operation error. * @deprecated 0.1.5 Use OTS_AccountBan class. */ - public function ban($time = 0) - { - // can't ban nothing - if( !$this->isLoaded() ) - { - throw new E_OTS_NotLoaded(); - } + public function ban($time = 0) + { + // can't ban nothing + if( !$this->isLoaded() ) + { + throw new E_OTS_NotLoaded(); + } - // creates ban entry - $ban = new OTS_AccountBan(); - $ban->setValue($this->data['id']); - $ban->setExpires($time); - $ban->setAdded( time() ); - $ban->activate(); - $ban->save(); - } + // creates ban entry + $ban = new OTS_AccountBan(); + $ban->setValue($this->data['id']); + $ban->setExpires($time); + $ban->setAdded( time() ); + $ban->activate(); + $ban->save(); + } /** * @version 0.1.5 @@ -809,19 +809,19 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @throws PDOException On PDO operation error. * @deprecated 0.1.5 Use OTS_AccountBan class. */ - public function unban() - { - // can't unban nothing - if( !$this->isLoaded() ) - { - throw new E_OTS_NotLoaded(); - } + public function unban() + { + // can't unban nothing + if( !$this->isLoaded() ) + { + throw new E_OTS_NotLoaded(); + } - // deletes ban entry - $ban = new OTS_AccountBan(); - $ban->find($this->data['id']); - $ban->delete(); - } + // deletes ban entry + $ban = new OTS_AccountBan(); + $ban->find($this->data['id']); + $ban->delete(); + } /** * @version 0.1.5 @@ -830,37 +830,37 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @throws PDOException On PDO operation error. * @deprecated 0.1.5 Use OTS_AccountBan class. */ - public function isBanned() - { - // nothing can't be banned - if( !$this->isLoaded() ) - { - throw new E_OTS_NotLoaded(); - } + public function isBanned() + { + // nothing can't be banned + if( !$this->isLoaded() ) + { + throw new E_OTS_NotLoaded(); + } if( !isset($this->data['banned']) ) $this->loadBan(); - return ($this->data['banned'] === true); - } + return ($this->data['banned'] === true); + } - public function getBanTime() - { - // nothing can't be banned - if( !$this->isLoaded() ) - { - throw new E_OTS_NotLoaded(); - } + public function getBanTime() + { + // nothing can't be banned + if( !$this->isLoaded() ) + { + throw new E_OTS_NotLoaded(); + } if( !isset($this->data['banned_time']) ) $this->loadBan(); - return $this->data['banned_time']; - } + return $this->data['banned_time']; + } - public function loadBan() - { - // nothing can't be banned - if( !$this->isLoaded() ) - { - throw new E_OTS_NotLoaded(); - } + public function loadBan() + { + // nothing can't be banned + if( !$this->isLoaded() ) + { + throw new E_OTS_NotLoaded(); + } if($this->db->hasTable('account_bans')) { $ban = $this->db->query('SELECT `expires_at` FROM `account_bans` WHERE `account_id` = ' . $this->data['id'] . ' AND (`expires_at` > ' . time() .' OR `expires_at` = -1) ORDER BY `expires_at` DESC')->fetch(); @@ -883,7 +883,7 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable $this->data['banned'] = false; $this->data['banned_time'] = 0; } - } + } /** * Deletes account. @@ -897,19 +897,19 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @throws E_OTS_NotLoaded If account is not loaded. * @throws PDOException On PDO operation error. */ - public function delete() - { - if( !isset($this->data['id']) ) - { - throw new E_OTS_NotLoaded(); - } + public function delete() + { + if( !isset($this->data['id']) ) + { + throw new E_OTS_NotLoaded(); + } - // deletes row from database - $this->db->exec('DELETE FROM ' . $this->db->tableName('accounts') . ' WHERE ' . $this->db->fieldName('id') . ' = ' . $this->data['id']); + // deletes row from database + $this->db->exec('DELETE FROM ' . $this->db->tableName('accounts') . ' WHERE ' . $this->db->fieldName('id') . ' = ' . $this->data['id']); - // resets object handle - unset($this->data['id']); - } + // resets object handle + unset($this->data['id']); + } /** * Checks highest access level of account. @@ -917,10 +917,10 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @return int Access level (highest access level of all characters). * @throws PDOException On PDO operation error. */ - public function getAccess() - { + public function getAccess() + { return $this->getGroupId(); - } + } public function getGroupId() { @@ -982,25 +982,25 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @return int Access level (highest access level of all characters). * @throws PDOException On PDO operation error. */ - public function getGuildAccess(OTS_Guild $guild) - { - // by default - $access = 0; + public function getGuildAccess(OTS_Guild $guild) + { + // by default + $access = 0; - // finds ranks of all characters - foreach($this->getPlayersList(false) as $player) - { - $rank = $player->getRank(); + // finds ranks of all characters + foreach($this->getPlayersList(false) as $player) + { + $rank = $player->getRank(); - // checks if rank's access level is higher then previouls found highest - if( isset($rank) && $rank->isLoaded() && $rank->getGuild()->getId() == $guild->getId() && $rank->getLevel() > $access) - { - $access = $rank->getLevel(); - } - } + // checks if rank's access level is higher then previouls found highest + if( isset($rank) && $rank->isLoaded() && $rank->getGuild()->getId() == $guild->getId() && $rank->getLevel() > $access) + { + $access = $rank->getLevel(); + } + } - return $access; - } + return $access; + } public function logAction($action) { @@ -1039,10 +1039,10 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @return Iterator List of players. */ #[\ReturnTypeWillChange] - public function getIterator() - { - return $this->getPlayersList(); - } + public function getIterator() + { + return $this->getPlayersList(); + } /** * Returns number of player within. @@ -1053,10 +1053,10 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @throws PDOException On PDO operation error. * @return int Count of players. */ - public function count(): int - { - return $this->getPlayersList()->count(); - } + public function count(): int + { + return $this->getPlayersList()->count(); + } /** * Magic PHP5 method. @@ -1069,44 +1069,44 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @throws OutOfBoundsException For non-supported properties. * @throws PDOException On PDO operation error. */ - public function __get($name) - { - switch($name) - { - case 'id': - return $this->getId(); + public function __get($name) + { + switch($name) + { + case 'id': + return $this->getId(); - case 'name': - return $this->getName(); + case 'name': + return $this->getName(); - case 'password': - return $this->getPassword(); + case 'password': + return $this->getPassword(); - case 'eMail': - return $this->getEMail(); + case 'eMail': + return $this->getEMail(); - case 'premiumEnd': - return $this->getPremiumEnd(); + case 'premiumEnd': + return $this->getPremiumEnd(); - case 'loaded': - return $this->isLoaded(); + case 'loaded': + return $this->isLoaded(); - case 'playersList': - return $this->getPlayersList(); + case 'playersList': + return $this->getPlayersList(); - case 'deleted': - return $this->isDeleted(); + case 'deleted': + return $this->isDeleted(); - case 'banned': - return $this->isBanned(); + case 'banned': + return $this->isBanned(); - case 'access': - return $this->getAccess(); + case 'access': + return $this->getAccess(); - default: - throw new OutOfBoundsException(); - } - } + default: + throw new OutOfBoundsException(); + } + } /** * Magic PHP5 method. @@ -1119,52 +1119,52 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @throws OutOfBoundsException For non-supported properties. * @throws PDOException On PDO operation error. */ - public function __set($name, $value) - { - switch($name) - { - case 'name': - $this->setName($name); - break; + public function __set($name, $value) + { + switch($name) + { + case 'name': + $this->setName($name); + break; - case 'password': - $this->setPassword($value); - break; + case 'password': + $this->setPassword($value); + break; - case 'eMail': - $this->setEMail($value); - break; + case 'eMail': + $this->setEMail($value); + break; - case 'premiumEnd': - $this->setPremiumEnd($value); - break; + case 'premiumEnd': + $this->setPremiumEnd($value); + break; - case 'deleted': - if($value) - { - $this->setDeleted(); - } - else - { - $this->unsetDeleted(); - } - break; + case 'deleted': + if($value) + { + $this->setDeleted(); + } + else + { + $this->unsetDeleted(); + } + break; - case 'banned': - if($value) - { - $this->ban(); - } - else - { - $this->unban(); - } - break; + case 'banned': + if($value) + { + $this->ban(); + } + else + { + $this->unban(); + } + break; - default: - throw new OutOfBoundsException(); - } - } + default: + throw new OutOfBoundsException(); + } + } /** * Returns string representation of object. @@ -1177,18 +1177,18 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable * @since 0.1.0 * @return string String representation of object. */ - public function __toString() - { - $ots = POT::getInstance(); + public function __toString() + { + $ots = POT::getInstance(); - // checks if display driver is loaded - if( $ots->isDisplayDriverLoaded() ) - { - return $ots->getDisplayDriver()->displayAccount($this); - } + // checks if display driver is loaded + if( $ots->isDisplayDriverLoaded() ) + { + return $ots->getDisplayDriver()->displayAccount($this); + } - return $this->getId(); - } + return $this->getId(); + } } /**#@-*/ From c88b08eb1ec1f560cbfdaaa16b24e3a0f26da7b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Morais?= Date: Wed, 15 Oct 2025 06:46:52 -0300 Subject: [PATCH 18/40] feature: show vip days in account management (#334) * feature: show vip days in account management This feature causes VIP days to be shown in account management when vipSystemEnabled is true in the canary config.lua * Some fixes & adjustments * If freePremium = true and vipEnabled = show gratis VIP * Revert to previous version --------- Co-authored-by: slawkens --- system/pages/account/manage.php | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/system/pages/account/manage.php b/system/pages/account/manage.php index 3776a732..b74f7bd8 100644 --- a/system/pages/account/manage.php +++ b/system/pages/account/manage.php @@ -38,15 +38,24 @@ csrfProtect(); $groups = new OTS_Groups_List(); -$freePremium = isset($config['lua']['freePremium']) && getBoolean($config['lua']['freePremium']) || $account_logged->getPremDays() == OTS_Account::GRATIS_PREMIUM_DAYS; -$dayOrDays = $account_logged->getPremDays() == 1 ? 'day' : 'days'; /** * @var OTS_Account $account_logged */ -if(!$account_logged->isPremium()) +$premDays = $account_logged->getPremDays(); + +$freePremium = isset($config['lua']['freePremium']) && getBoolean($config['lua']['freePremium']) || $premDays == OTS_Account::GRATIS_PREMIUM_DAYS; +$dayOrDays = ($premDays == 1 ? 'day' : 'days'); + +$vipSystemEnabled = isset($config['lua']['vipSystemEnabled']) && getBoolean($config['lua']['vipSystemEnabled']); +$premiumLabel = $vipSystemEnabled ? 'VIP' : 'Premium Account'; + +if ($freePremium && !$vipSystemEnabled) { + $account_status = 'Gratis Premium Account'; +} else if(!$account_logged->isPremium()) { $account_status = 'Free Account'; -else - $account_status = '' . ($freePremium ? 'Gratis Premium Account' : 'Premium Account, ' . $account_logged->getPremDays() . ' '.$dayOrDays.' left') . ''; +} else { + $account_status = '' . $premiumLabel . ', ' . $premDays . ' '.$dayOrDays.' left'; +} $recovery_key = $account_logged->getCustomField('key'); if(empty($recovery_key)) From 3e61692780d4add93b7b0e9f12f7a283bd8f4b7a Mon Sep 17 00:00:00 2001 From: slawkens Date: Wed, 15 Oct 2025 15:49:58 +0200 Subject: [PATCH 19/40] Fix premDays count in canary --- system/functions.php | 6 ++++++ system/libs/pot/OTS_Account.php | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/system/functions.php b/system/functions.php index 212a043e..b3f1189f 100644 --- a/system/functions.php +++ b/system/functions.php @@ -1704,6 +1704,12 @@ function getAccountIdentityColumn(): string return 'id'; } +function isCanary(): bool +{ + $vipSystemEnabled = configLua('vipSystemEnabled'); + return isset($vipSystemEnabled); +} + // validator functions require_once SYSTEM . 'compat/base.php'; diff --git a/system/libs/pot/OTS_Account.php b/system/libs/pot/OTS_Account.php index 872d1c89..5cee25a4 100644 --- a/system/libs/pot/OTS_Account.php +++ b/system/libs/pot/OTS_Account.php @@ -449,6 +449,11 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable return max($ret, 0); } + if (isCanary() && isset($this->data['lastday'])) { + $ret = ceil(($this->data['lastday'] - time()) / 86400); + return $ret > 0 ? $ret : 0; + } + if($this->data['premdays'] == 0) { return 0; } From 38902c30d114fdbce259467f5820f97037b393e9 Mon Sep 17 00:00:00 2001 From: slawkens Date: Wed, 15 Oct 2025 15:50:22 +0200 Subject: [PATCH 20/40] Comment code to update lastday --- login.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/login.php b/login.php index d4d25529..438754e2 100644 --- a/login.php +++ b/login.php @@ -220,6 +220,8 @@ switch ($action) { } } + /* + * not needed anymore? if (fieldExist('premdays', 'accounts') && fieldExist('lastday', 'accounts')) { $save = false; $timeNow = time(); @@ -256,6 +258,7 @@ switch ($action) { $account->save(); } } + */ $worlds = [$world]; $playdata = compact('worlds', 'characters'); From 12e40b2592ee4bb3a80a17158f5e2aa16142baac Mon Sep 17 00:00:00 2001 From: slawkens Date: Wed, 15 Oct 2025 15:50:25 +0200 Subject: [PATCH 21/40] Update functions.php --- system/functions.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/system/functions.php b/system/functions.php index b3f1189f..582f9c30 100644 --- a/system/functions.php +++ b/system/functions.php @@ -1640,13 +1640,14 @@ function camelCaseToUnderscore($input) return ltrim(strtolower(preg_replace('/[A-Z]([A-Z](?![a-z]))*/', '_$0', $input)), '_'); } -function removeIfFirstSlash(&$text) { +function removeIfFirstSlash(&$text): void +{ if(strpos($text, '/') === 0) { $text = str_replace_first('/', '', $text); } }; -function escapeHtml($html) { +function escapeHtml($html): string { return htmlspecialchars($html); } @@ -1660,7 +1661,7 @@ function getGuildNameById($id) return false; } -function getGuildLogoById($id) +function getGuildLogoById($id): string { $logo = 'default.gif'; @@ -1676,7 +1677,8 @@ function getGuildLogoById($id) return BASE_URL . GUILD_IMAGES_DIR . $logo; } -function displayErrorBoxWithBackButton($errors, $action = null) { +function displayErrorBoxWithBackButton($errors, $action = null): void +{ global $twig; $twig->display('error_box.html.twig', ['errors' => $errors]); $twig->display('account.back_button.html.twig', [ From 7f60b3d31d53addb806631dd9edd5ac0e4c79d54 Mon Sep 17 00:00:00 2001 From: slawkens Date: Wed, 15 Oct 2025 15:59:49 +0200 Subject: [PATCH 22/40] Add same code in Models\Account + Optimize code --- system/libs/pot/OTS_Account.php | 11 ++++++----- system/src/Models/Account.php | 9 +++++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/system/libs/pot/OTS_Account.php b/system/libs/pot/OTS_Account.php index 5cee25a4..a5007e3b 100644 --- a/system/libs/pot/OTS_Account.php +++ b/system/libs/pot/OTS_Account.php @@ -443,15 +443,16 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable throw new E_OTS_NotLoaded(); } - if(isset($this->data['premium_ends_at']) || isset($this->data['premend'])) { - $col = isset($this->data['premium_ends_at']) ? 'premium_ends_at' : 'premend'; - $ret = ceil(($this->data[$col] - time()) / (24 * 60 * 60)); - return max($ret, 0); + if(isset($this->data['premium_ends_at']) || isset($this->data['premend']) || + (isCanary() && isset($this->data['lastday']))) { + $col = (isset($this->premium_ends_at) ? 'premium_ends_at' : (isset($this->data['lastday']) ? 'lastday' : 'premend')); + $ret = ceil(($this->data[$col] - time()) / (24 * 60 * 60)); + return max($ret, 0); } if (isCanary() && isset($this->data['lastday'])) { $ret = ceil(($this->data['lastday'] - time()) / 86400); - return $ret > 0 ? $ret : 0; + return max($ret, 0); } if($this->data['premdays'] == 0) { diff --git a/system/src/Models/Account.php b/system/src/Models/Account.php index f0bd435f..fdd7d540 100644 --- a/system/src/Models/Account.php +++ b/system/src/Models/Account.php @@ -33,10 +33,11 @@ class Account extends Model { public function getPremiumDaysAttribute() { - if(isset($this->premium_ends_at) || isset($this->premend)) { - $col = isset($this->premium_ends_at) ? 'premium_ends_at' : 'premend'; - $ret = ceil(($this->{$col}- time()) / (24 * 60 * 60)); - return $ret > 0 ? $ret : 0; + if(isset($this->premium_ends_at) || isset($this->premend) || + (isCanary() && isset($this->data['lastday']))) { + $col = (isset($this->premium_ends_at) ? 'premium_ends_at' : (isset($this->data['lastday']) ? 'lastday' : 'premend')); + $ret = ceil(($this->{$col}- time()) / (24 * 60 * 60)); + return max($ret, 0); } if($this->premdays == 0) { From 470555f2687809a0c12491bbb27597e64b8929c1 Mon Sep 17 00:00:00 2001 From: slawkens Date: Thu, 16 Oct 2025 21:22:49 +0200 Subject: [PATCH 23/40] New hooks for account/change-password HOOK_ACCOUNT_CHANGE_PASSWORD_AFTER_OLD_PASSWORD + HOOK_ACCOUNT_CHANGE_PASSWORD_AFTER_NEW_PASSWORD --- system/src/global.php | 2 ++ system/templates/account.change-password.html.twig | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/system/src/global.php b/system/src/global.php index 8f1885f3..85f9476d 100644 --- a/system/src/global.php +++ b/system/src/global.php @@ -28,6 +28,8 @@ define('HOOK_CHARACTERS_AFTER_CHARACTERS', ++$i); define('HOOK_LOGIN', ++$i); define('HOOK_LOGIN_ATTEMPT', ++$i); define('HOOK_LOGOUT', ++$i); +define('HOOK_ACCOUNT_CHANGE_PASSWORD_AFTER_OLD_PASSWORD', ++$i); +define('HOOK_ACCOUNT_CHANGE_PASSWORD_AFTER_NEW_PASSWORD', ++$i); define('HOOK_ACCOUNT_CHANGE_PASSWORD_POST', ++$i); define('HOOK_ACCOUNT_CREATE_BEFORE_FORM', ++$i); define('HOOK_ACCOUNT_CREATE_BEFORE_BOXES', ++$i); diff --git a/system/templates/account.change-password.html.twig b/system/templates/account.change-password.html.twig index df101323..db2c1f74 100644 --- a/system/templates/account.change-password.html.twig +++ b/system/templates/account.change-password.html.twig @@ -12,6 +12,9 @@ Please enter your current password and a new password. For your security, please + + {{ hook('HOOK_ACCOUNT_CHANGE_PASSWORD_AFTER_OLD_PASSWORD') }} + New Password: @@ -20,6 +23,9 @@ Please enter your current password and a new password. For your security, please + + {{ hook('HOOK_ACCOUNT_CHANGE_PASSWORD_AFTER_NEW_PASSWORD') }} + New Password Again: From 16849e7578321c92bec12674e5bf46ad4d38140f Mon Sep 17 00:00:00 2001 From: slawkens Date: Thu, 16 Oct 2025 21:36:14 +0200 Subject: [PATCH 24/40] account/change-password refactor a bit Add "The old password is same as the new password!" Better post variables names --- system/pages/account/change-password.php | 18 ++++++++++-------- .../account.change-password.html.twig | 6 +++--- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/system/pages/account/change-password.php b/system/pages/account/change-password.php index 35058d3d..157515b7 100644 --- a/system/pages/account/change-password.php +++ b/system/pages/account/change-password.php @@ -19,18 +19,17 @@ if(!$logged) { csrfProtect(); -$new_password = $_POST['newpassword'] ?? NULL; -$new_password_confirm = $_POST['newpassword_confirm'] ?? NULL; -$old_password = $_POST['oldpassword'] ?? NULL; +$new_password = $_POST['new_password'] ?? null; +$new_password_confirm = $_POST['new_password_confirm'] ?? null; +$old_password = $_POST['old_password'] ?? null; if(empty($new_password) && empty($new_password_confirm) && empty($old_password)) { $twig->display('account.change-password.html.twig'); } -else -{ +else { if(empty($new_password) || empty($new_password_confirm) || empty($old_password)){ $errors[] = 'Please fill in form.'; } - $password_strlen = strlen($new_password); + if($new_password != $new_password_confirm) { $errors[] = 'The new passwords do not match!'; } @@ -41,10 +40,13 @@ else } /** @var OTS_Account $account_logged */ - $old_password = encrypt((USE_ACCOUNT_SALT ? $account_logged->getCustomField('salt') : '') . $old_password); - if($old_password != $account_logged->getPassword()) { + $old_password_hashed = encrypt((USE_ACCOUNT_SALT ? $account_logged->getCustomField('salt') : '') . $old_password); + if($old_password_hashed != $account_logged->getPassword()) { $errors[] = 'Current password is incorrect!'; } + else if ($old_password == $new_password) { + $errors[] = 'The old password is same as the new password!'; + } $hooks->trigger(HOOK_ACCOUNT_CHANGE_PASSWORD_POST); } diff --git a/system/templates/account.change-password.html.twig b/system/templates/account.change-password.html.twig index db2c1f74..03f82d9b 100644 --- a/system/templates/account.change-password.html.twig +++ b/system/templates/account.change-password.html.twig @@ -9,7 +9,7 @@ Please enter your current password and a new password. For your security, please Current Password: - + @@ -20,7 +20,7 @@ Please enter your current password and a new password. For your security, please New Password: - + @@ -31,7 +31,7 @@ Please enter your current password and a new password. For your security, please New Password Again: - + From 89fae38caa7e4f645957fcf1a9330a36358ac04f Mon Sep 17 00:00:00 2001 From: slawkens Date: Tue, 21 Oct 2025 12:18:56 +0200 Subject: [PATCH 25/40] Ignore set last visit for AJAX pages - Fixes template change redirect --- admin/tools/phpinfo.php | 3 ++- admin/tools/reload_data.php | 1 + admin/tools/settings_save.php | 1 + admin/tools/status.php | 3 ++- admin/tools/upload_image.php | 3 ++- system/login.php | 10 ++++++---- tools/generate_account_number.php | 2 ++ tools/status.php | 3 +++ tools/validate.php | 2 ++ 9 files changed, 21 insertions(+), 7 deletions(-) diff --git a/admin/tools/phpinfo.php b/admin/tools/phpinfo.php index cd043279..bd09fb5d 100644 --- a/admin/tools/phpinfo.php +++ b/admin/tools/phpinfo.php @@ -1,5 +1,6 @@ addGlobal('account_logged', $account_logged); } -setSession('last_visit', time()); -if(defined('PAGE')) { - setSession('last_page', PAGE); +if (!defined('IGNORE_SET_LAST_VISIT') || !IGNORE_SET_LAST_VISIT) { + setSession('last_visit', time()); + if(defined('PAGE')) { + setSession('last_page', PAGE); + } + setSession('last_uri', $_SERVER['REQUEST_URI']); } -setSession('last_uri', $_SERVER['REQUEST_URI']); diff --git a/tools/generate_account_number.php b/tools/generate_account_number.php index a53ba9a3..643bb2c2 100644 --- a/tools/generate_account_number.php +++ b/tools/generate_account_number.php @@ -9,6 +9,8 @@ * @link https://my-aac.org */ +const IGNORE_SET_LAST_VISIT = true; + // we need some functions require '../common.php'; require SYSTEM . 'functions.php'; diff --git a/tools/status.php b/tools/status.php index ae0ee49d..9e9c8a29 100644 --- a/tools/status.php +++ b/tools/status.php @@ -1,4 +1,7 @@ Date: Tue, 21 Oct 2025 17:18:07 +0200 Subject: [PATCH 26/40] Release v1.8.3 --- CHANGELOG-1.x.md | 25 +++++++++++++++++++++++++ common.php | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-1.x.md b/CHANGELOG-1.x.md index 17e2a06e..8779d2c5 100644 --- a/CHANGELOG-1.x.md +++ b/CHANGELOG-1.x.md @@ -1,5 +1,30 @@ # Changelog +## [1.8.3 - 21.10.2025] + +### Added +* Feature: resend email verify (https://github.com/slawkens/myaac/commit/fe821c58085483e70491dcf76376ad5b96de3fdd) +* New config: hooks_debug (To view where hooks are located in .twig files) (https://github.com/slawkens/myaac/commit/8c3cb0e06f9709c1de3398b48221241e7cbdd310) +* Functions: Add db->getColumnInfo(table, column) (https://github.com/slawkens/myaac/commit/c898fe25efff6793a01d11c26fc153cb23fcb858) +* Plugins: Add option to use ?subtopic=x for plugins pages (https://github.com/slawkens/myaac/commit/97f9d3d6f6c28aef6d824973058d7133f56e09c4) +* getTopPlayers() Function - Add lookmount & promotion (https://github.com/slawkens/myaac/commit/2da0024c68f1cedc38a16ebbc6f52ffa55e65f7a, https://github.com/slawkens/myaac/commit/901df48d134079d648a18f9d82b60182e818ac02) +* New hooks for account/change-password (https://github.com/slawkens/myaac/commit/470555f2687809a0c12491bbb27597e64b8929c1) + +### Changed +* Feature: show vip days in account management (https://github.com/slawkens/myaac/commit/c88b08eb1ec1f560cbfdaaa16b24e3a0f26da7b3, by @andreoam) +* Allow links in error_box.html.twig (https://github.com/slawkens/myaac/commit/9acad15451071639acf7a7d4e81619b0a9742b12) +* Canary - Comment code to update lastday in login.php (https://github.com/slawkens/myaac/commit/38902c30d114fdbce259467f5820f97037b393e9) +* Cache::remember $ttl = -1 = infinite (https://github.com/slawkens/myaac/commit/64acf70d3854182d88aaf0b67f77cea2a254f179) + +### Fixed +* Online - Allow for html code (example - img) in online_datacenter (https://github.com/slawkens/myaac/commit/3bb272ebbbd2eb7769d174b7082061d14a17bd44) +* Guilds - Fix guild create with freePremium enabled (https://github.com/slawkens/myaac/commit/c91bb5d4097647dca2196d3dea87bc90c89181d2) +* Canary - Fix premDays count (https://github.com/slawkens/myaac/commit/3e61692780d4add93b7b0e9f12f7a283bd8f4b7a) +* Template Change: Ignore set last visit for AJAX pages - Fixes template change redirect (https://github.com/slawkens/myaac/commit/89fae38caa7e4f645957fcf1a9330a36358ac04f) +* Admin Panel - Accounts: Fix lastip v6 (TFS master) (https://github.com/slawkens/myaac/commit/f54b1bdd2af4c16c64ddff0e87a6c96bc4cf9eeb) +* Functions - Prevent injection in $db->hasColumn (https://github.com/slawkens/myaac/commit/56bd7ec5ed904666074492f2e4f13e4fce226bee) +* Compat Config: Add missing config: email_lai_sec_interval (https://github.com/slawkens/myaac/commit/2eae44e0755e624a91be68b4d1ec26d01eb4d9a1) + ## [1.8.2 - 26.09.2025] ### Added diff --git a/common.php b/common.php index e26921c5..1cbd0dd8 100644 --- a/common.php +++ b/common.php @@ -26,7 +26,7 @@ if (version_compare(phpversion(), '8.1', '<')) die('PHP version 8.1 or higher is required.'); const MYAAC = true; -const MYAAC_VERSION = '1.8.3-dev'; +const MYAAC_VERSION = '1.8.3'; const DATABASE_VERSION = 46; const TABLE_PREFIX = 'myaac_'; define('START_TIME', microtime(true)); From 13ea68cc0c9349380c8e4051d702a6c2c8256f44 Mon Sep 17 00:00:00 2001 From: slawkens Date: Fri, 24 Oct 2025 21:10:55 +0200 Subject: [PATCH 27/40] Use low level env init on migrate:run + migrate:to --- aac | 4 ++- system/src/Commands/Env.php | 33 +++++++++++++++++++++++ system/src/Commands/MigrateRunCommand.php | 6 +++-- system/src/Commands/MigrateToCommand.php | 29 +++----------------- 4 files changed, 43 insertions(+), 29 deletions(-) create mode 100644 system/src/Commands/Env.php diff --git a/aac b/aac index d4ce7b7d..8f213136 100644 --- a/aac +++ b/aac @@ -25,7 +25,9 @@ foreach ($commandsGlob as $item) { } $commandPre = '\\MyAAC\Commands\\'; - $application->add(new ($commandPre . $name)); + if (!trait_exists($class = $commandPre . $name)) { + $application->add(new $class); + } } $pluginCommands = Plugins::getCommands(); diff --git a/system/src/Commands/Env.php b/system/src/Commands/Env.php new file mode 100644 index 00000000..e3130806 --- /dev/null +++ b/system/src/Commands/Env.php @@ -0,0 +1,33 @@ +setName('migrate:run') @@ -23,12 +25,12 @@ class MigrateRunCommand extends Command protected function execute(InputInterface $input, OutputInterface $output): int { - require SYSTEM . 'init.php'; - $io = new SymfonyStyle($input, $output); $ids = $input->getArgument('id'); + $this->init(); + // pre-check // in case one of the migrations doesn't exist - we won't execute any of them foreach ($ids as $id) { diff --git a/system/src/Commands/MigrateToCommand.php b/system/src/Commands/MigrateToCommand.php index b82012ed..72be5730 100644 --- a/system/src/Commands/MigrateToCommand.php +++ b/system/src/Commands/MigrateToCommand.php @@ -11,6 +11,8 @@ use Symfony\Component\Console\Style\SymfonyStyle; class MigrateToCommand extends Command { + use Env; + protected function configure(): void { $this->setName('migrate:to') @@ -32,7 +34,7 @@ class MigrateToCommand extends Command return Command::FAILURE; } - $this->initEnv(); + $this->init(); $currentVersion = Config::where('name', 'database_version')->first()->value; if ($currentVersion > $versionDest) { @@ -80,29 +82,4 @@ class MigrateToCommand extends Command updateDatabaseConfig('database_version', ($_up ? $id : $id - 1)); } - - private function initEnv() - { - global $config; - if (!isset($config['installed']) || !$config['installed']) { - throw new \RuntimeException('MyAAC has not been installed yet or there was error during installation. Please install again.'); - } - - if(empty($config['server_path'])) { - throw new \RuntimeException('Server Path has been not set. Go to config.php and set it.'); - } - - // take care of trailing slash at the end - if($config['server_path'][strlen($config['server_path']) - 1] !== '/') - $config['server_path'] .= '/'; - - $config['lua'] = load_config_lua($config['server_path'] . 'config.lua'); - - // POT - require_once SYSTEM . 'libs/pot/OTS.php'; - $ots = POT::getInstance(); - $eloquentConnection = null; - - require_once SYSTEM . 'database.php'; - } } From 07fd034fe4cb0ffdb88667b1e400f414d0c6d06f Mon Sep 17 00:00:00 2001 From: slawkens Date: Fri, 24 Oct 2025 21:12:40 +0200 Subject: [PATCH 28/40] Use low level env init on migrate command --- system/src/Commands/MigrateCommand.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/system/src/Commands/MigrateCommand.php b/system/src/Commands/MigrateCommand.php index a8a21016..73868ce3 100644 --- a/system/src/Commands/MigrateCommand.php +++ b/system/src/Commands/MigrateCommand.php @@ -9,6 +9,8 @@ use Symfony\Component\Console\Style\SymfonyStyle; class MigrateCommand extends Command { + use Env; + protected function configure(): void { $this->setName('migrate') @@ -17,7 +19,7 @@ class MigrateCommand extends Command protected function execute(InputInterface $input, OutputInterface $output): int { - require SYSTEM . 'init.php'; + $this->init(); $io = new SymfonyStyle($input, $output); require SYSTEM . 'migrate.php'; From 727f68a57594b7d98682024b6aac778804ad84a1 Mon Sep 17 00:00:00 2001 From: slawkens Date: Fri, 24 Oct 2025 21:14:49 +0200 Subject: [PATCH 29/40] migrate command: show "Already on latest version" --- system/migrate.php | 2 ++ system/src/Commands/MigrateCommand.php | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/system/migrate.php b/system/migrate.php index 2199fd73..2bbb3786 100644 --- a/system/migrate.php +++ b/system/migrate.php @@ -9,6 +9,8 @@ */ defined('MYAAC') or die('Direct access not allowed!'); +global $db; + // database migrations $tmp = ''; if(fetchDatabaseConfig('database_version', $tmp)) { // we got version diff --git a/system/src/Commands/MigrateCommand.php b/system/src/Commands/MigrateCommand.php index 73868ce3..fe110190 100644 --- a/system/src/Commands/MigrateCommand.php +++ b/system/src/Commands/MigrateCommand.php @@ -22,6 +22,16 @@ class MigrateCommand extends Command $this->init(); $io = new SymfonyStyle($input, $output); + + $tmp = ''; + if(fetchDatabaseConfig('database_version', $tmp)) { // we got version + $tmp = (int)$tmp; + if ($tmp >= DATABASE_VERSION) { + $io->success('Already on latest version.'); + return Command::SUCCESS; + } + } + require SYSTEM . 'migrate.php'; $io->success('Migrated to latest version (' . DATABASE_VERSION . ')'); From 44110a9496b4385e42c31b75de301037e711b6c3 Mon Sep 17 00:00:00 2001 From: slawkens Date: Sat, 25 Oct 2025 21:32:49 +0200 Subject: [PATCH 30/40] Show if there is mysql error on import schema Weird fix, don't know why it didn't worked with query() --- install/tools/5-database.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/tools/5-database.php b/install/tools/5-database.php index f97eca11..f377b809 100644 --- a/install/tools/5-database.php +++ b/install/tools/5-database.php @@ -40,7 +40,7 @@ else { $locale['step_database_importing'] = str_replace('$DATABASE_NAME$', config('database_name'), $locale['step_database_importing']); success($locale['step_database_importing']); - $db->query(file_get_contents(BASE . 'install/includes/schema.sql')); + $db->exec(file_get_contents(BASE . 'install/includes/schema.sql')); $locale['step_database_success_schema'] = str_replace('$PREFIX$', TABLE_PREFIX, $locale['step_database_success_schema']); success($locale['step_database_success_schema']); From 9d92a11fb7cb6d7a1619d79c12faaa0b1c01f980 Mon Sep 17 00:00:00 2001 From: slawkens Date: Mon, 27 Oct 2025 14:34:53 +0100 Subject: [PATCH 31/40] Fix the premium checks, introduced in v1.8.3 --- system/libs/pot/OTS_Account.php | 17 +++++++---------- system/src/Models/Account.php | 22 +++++++++++++--------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/system/libs/pot/OTS_Account.php b/system/libs/pot/OTS_Account.php index a5007e3b..f617bbfc 100644 --- a/system/libs/pot/OTS_Account.php +++ b/system/libs/pot/OTS_Account.php @@ -445,16 +445,11 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable if(isset($this->data['premium_ends_at']) || isset($this->data['premend']) || (isCanary() && isset($this->data['lastday']))) { - $col = (isset($this->premium_ends_at) ? 'premium_ends_at' : (isset($this->data['lastday']) ? 'lastday' : 'premend')); + $col = (isset($this->data['premium_ends_at']) ? 'premium_ends_at' : (isset($this->data['lastday']) ? 'lastday' : 'premend')); $ret = ceil(($this->data[$col] - time()) / (24 * 60 * 60)); return max($ret, 0); } - if (isCanary() && isset($this->data['lastday'])) { - $ret = ceil(($this->data['lastday'] - time()) / 86400); - return max($ret, 0); - } - if($this->data['premdays'] == 0) { return 0; } @@ -479,12 +474,14 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable public function isPremium() { - if(isset($this->data['premium_ends_at'])) { - return $this->data['premium_ends_at'] > time(); + if(isset($this->data['premium_ends_at']) || isset($this->data['premend']) || + (isCanary() && isset($this->data['lastday']))) { + $col = (isset($this->data['premium_ends_at']) ? 'premium_ends_at' : (isset($this->data['lastday']) ? 'lastday' : 'premend')); + return $this->data[$col] > time(); } - if(isset($this->data['premend'])) { - return $this->data['premend'] > time(); + if($this->data['premdays'] == self::GRATIS_PREMIUM_DAYS){ + return true; } return ($this->data['premdays'] - (date("z", time()) + (365 * (date("Y", time()) - date("Y", $this->data['lastday']))) - date("z", $this->data['lastday'])) > 0); diff --git a/system/src/Models/Account.php b/system/src/Models/Account.php index fdd7d540..5f2de268 100644 --- a/system/src/Models/Account.php +++ b/system/src/Models/Account.php @@ -10,6 +10,8 @@ use Illuminate\Database\Eloquent\Model; */ class Account extends Model { + const GRATIS_PREMIUM_DAYS = 65535; + protected $table = 'accounts'; public $timestamps = false; @@ -34,9 +36,9 @@ class Account extends Model { public function getPremiumDaysAttribute() { if(isset($this->premium_ends_at) || isset($this->premend) || - (isCanary() && isset($this->data['lastday']))) { - $col = (isset($this->premium_ends_at) ? 'premium_ends_at' : (isset($this->data['lastday']) ? 'lastday' : 'premend')); - $ret = ceil(($this->{$col}- time()) / (24 * 60 * 60)); + (isCanary() && isset($this->lastday))) { + $col = (isset($this->premium_ends_at) ? 'premium_ends_at' : (isset($this->lastday) ? 'lastday' : 'premend')); + $ret = ceil(($this->{$col} - time()) / (24 * 60 * 60)); return max($ret, 0); } @@ -44,8 +46,8 @@ class Account extends Model { return 0; } - if($this->premdays == 65535){ - return 65535; + if($this->premdays == self::GRATIS_PREMIUM_DAYS){ + return self::GRATIS_PREMIUM_DAYS; } $ret = ceil($this->premdays - ((int)date("z", time()) + (365 * (date("Y", time()) - date("Y", $this->lastday))) - date("z", $this->lastday))); @@ -54,12 +56,14 @@ class Account extends Model { public function getIsPremiumAttribute() { - if(isset($this->premium_ends_at)) { - return $this->premium_ends_at > time(); + if(isset($this->premium_ends_at) || isset($this->premend) || + (isCanary() && isset($this->lastday))) { + $col = (isset($this->premium_ends_at) ? 'premium_ends_at' : (isset($this->lastday) ? 'lastday' : 'premend')); + return $this->{$col} > time(); } - if(isset($this->premend)) { - return $this->premend > time(); + if($this->premdays == self::GRATIS_PREMIUM_DAYS){ + return true; } return ($this->premdays - (date("z", time()) + (365 * (date("Y", time()) - date("Y", $this->lastday))) - date("z", $this->lastday)) > 0); From 6cd38ee1ecb519ec48d37d01e5fc5370f3e07b2a Mon Sep 17 00:00:00 2001 From: slawkens Date: Mon, 27 Oct 2025 14:38:52 +0100 Subject: [PATCH 32/40] Fix php stan --- system/src/Models/Account.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/system/src/Models/Account.php b/system/src/Models/Account.php index 5f2de268..26a09f51 100644 --- a/system/src/Models/Account.php +++ b/system/src/Models/Account.php @@ -5,6 +5,8 @@ namespace MyAAC\Models; use Illuminate\Database\Eloquent\Model; /** + * @property integer $premium_ends_at + * @property integer $premend * @property integer $lastday * @property integer $premdays */ From 8f47b36dc88ad4d4c3176e4afda86b520394e8e8 Mon Sep 17 00:00:00 2001 From: slawkens Date: Mon, 27 Oct 2025 15:03:24 +0100 Subject: [PATCH 33/40] Add return type --- system/libs/pot/OTS_Account.php | 2 +- system/src/Models/Account.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/system/libs/pot/OTS_Account.php b/system/libs/pot/OTS_Account.php index f617bbfc..8505128e 100644 --- a/system/libs/pot/OTS_Account.php +++ b/system/libs/pot/OTS_Account.php @@ -472,7 +472,7 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable return $this->data['lastday']; } - public function isPremium() + public function isPremium(): bool { if(isset($this->data['premium_ends_at']) || isset($this->data['premend']) || (isCanary() && isset($this->data['lastday']))) { diff --git a/system/src/Models/Account.php b/system/src/Models/Account.php index 26a09f51..4b44b153 100644 --- a/system/src/Models/Account.php +++ b/system/src/Models/Account.php @@ -56,7 +56,7 @@ class Account extends Model { return max($ret, 0); } - public function getIsPremiumAttribute() + public function getIsPremiumAttribute(): bool { if(isset($this->premium_ends_at) || isset($this->premend) || (isCanary() && isset($this->lastday))) { From 2580edadf84779f09fd395c21f92019b2c762f83 Mon Sep 17 00:00:00 2001 From: Slawomir Boczek Date: Mon, 27 Oct 2025 16:27:22 +0100 Subject: [PATCH 34/40] Database import tables on every install with "IF NOT EXISTS" (#336) * Database import tables on every install with "IF NOT EXISTS" This fixed errors when one table is missing or is duplicated * Add success message on import data * Reorder --- install/includes/import_base_data.php | 69 +++++++++++++++++++++++++++ install/includes/schema.sql | 57 ++++++++-------------- install/tools/5-database.php | 30 +++++------- system/locale/de/install.php | 1 + system/locale/en/install.php | 1 + system/locale/pl/install.php | 3 +- system/src/Models/Changelog.php | 9 ++++ system/src/Models/ForumBoard.php | 16 +++++++ system/src/Models/Gallery.php | 5 ++ system/src/Models/NewsCategory.php | 15 ++++++ 10 files changed, 150 insertions(+), 56 deletions(-) create mode 100644 install/includes/import_base_data.php create mode 100644 system/src/Models/ForumBoard.php create mode 100644 system/src/Models/NewsCategory.php diff --git a/install/includes/import_base_data.php b/install/includes/import_base_data.php new file mode 100644 index 00000000..45c803ed --- /dev/null +++ b/install/includes/import_base_data.php @@ -0,0 +1,69 @@ + 3, + 'where' => 2, + 'date' => time(), + 'body' => 'MyAAC installed. (:', + 'hide' => 0, + ]); +} + +if (Config::where('name', 'database_version')->count() === 0) { + Config::create([ + 'name' => 'database_version', + 'value' => DATABASE_VERSION, + ]); +} + +if (ForumBoard::count() === 0) { + $forumBoards = [ + ['name' => 'News', 'description' => 'News commenting', 'closed' => 1], + ['name' => 'Trade', 'description' => 'Trade offers.', 'closed' => 0], + ['name' => 'Quests', 'description' => 'Quest making.', 'closed' => 0], + ['name' => 'Pictures', 'description' => 'Your pictures.', 'closed' => 0], + ['name' => 'Bug Report', 'description' => 'Report bugs there.', 'closed' => 0], + ]; + + $i = 0; + foreach ($forumBoards as $forumBoard) { + ForumBoard::create([ + 'name' => $forumBoard['name'], + 'description' => $forumBoard['description'], + 'ordering' => $i++, + 'closed' => $forumBoard['closed'], + ]); + } +} + +if (NewsCategory::count() === 0) { + $newsCategoriesIcons = [ + 0, 1, 2, 3, 4 + ]; + + foreach ($newsCategoriesIcons as $iconId) { + NewsCategory::create([ + 'icon_id' => $iconId, + ]); + } +} + +if (Gallery::count() === 0) { + Gallery::create([ + 'comment' => 'Demon', + 'image' => 'images/gallery/demon.jpg', + 'thumb' => 'images/gallery/demon_thumb.gif', + 'author' => 'MyAAC', + 'ordering' => 0, + ]); +} + +success($locale['step_database_success_import_data']); diff --git a/install/includes/schema.sql b/install/includes/schema.sql index b53ffab2..d4bc97d6 100644 --- a/install/includes/schema.sql +++ b/install/includes/schema.sql @@ -1,6 +1,4 @@ -SET @myaac_database_version = 46; - -CREATE TABLE `myaac_account_actions` +CREATE TABLE IF NOT EXISTS `myaac_account_actions` ( `account_id` int NOT NULL, `ip` int unsigned NOT NULL DEFAULT 0, @@ -10,7 +8,7 @@ CREATE TABLE `myaac_account_actions` KEY (`account_id`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE `myaac_account_emails_verify` +CREATE TABLE IF NOT EXISTS `myaac_account_emails_verify` ( `id` int NOT NULL AUTO_INCREMENT, `account_id` int NOT NULL, @@ -19,7 +17,7 @@ CREATE TABLE `myaac_account_emails_verify` PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE `myaac_admin_menu` +CREATE TABLE IF NOT EXISTS `myaac_admin_menu` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL DEFAULT '', @@ -30,7 +28,7 @@ CREATE TABLE `myaac_admin_menu` PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE `myaac_changelog` +CREATE TABLE IF NOT EXISTS `myaac_changelog` ( `id` int NOT NULL AUTO_INCREMENT, `body` varchar(500) NOT NULL DEFAULT '', @@ -42,9 +40,7 @@ CREATE TABLE `myaac_changelog` PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -INSERT INTO `myaac_changelog` (`id`, `type`, `where`, `date`, `body`, `hide`) VALUES (1, 3, 2, UNIX_TIMESTAMP(), 'MyAAC installed. (:', 0); - -CREATE TABLE `myaac_config` +CREATE TABLE IF NOT EXISTS `myaac_config` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(30) NOT NULL, @@ -53,9 +49,7 @@ CREATE TABLE `myaac_config` UNIQUE (`name`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -INSERT INTO `myaac_config` (`name`, `value`) VALUES ('database_version', @myaac_database_version); - -CREATE TABLE `myaac_faq` +CREATE TABLE IF NOT EXISTS `myaac_faq` ( `id` int NOT NULL AUTO_INCREMENT, `question` varchar(255) NOT NULL DEFAULT '', @@ -65,7 +59,7 @@ CREATE TABLE `myaac_faq` PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE `myaac_forum_boards` +CREATE TABLE IF NOT EXISTS `myaac_forum_boards` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(32) NOT NULL, @@ -77,13 +71,8 @@ CREATE TABLE `myaac_forum_boards` `hide` tinyint NOT NULL DEFAULT 0, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -INSERT INTO `myaac_forum_boards` (`id`, `name`, `description`, `ordering`, `closed`) VALUES (NULL, 'News', 'News commenting', 0, 1); -INSERT INTO `myaac_forum_boards` (`id`, `name`, `description`, `ordering`) VALUES (NULL, 'Trade', 'Trade offers.', 1); -INSERT INTO `myaac_forum_boards` (`id`, `name`, `description`, `ordering`) VALUES (NULL, 'Quests', 'Quest making.', 2); -INSERT INTO `myaac_forum_boards` (`id`, `name`, `description`, `ordering`) VALUES (NULL, 'Pictures', 'Your pictures.', 3); -INSERT INTO `myaac_forum_boards` (`id`, `name`, `description`, `ordering`) VALUES (NULL, 'Bug Report', 'Report bugs there.', 4); -CREATE TABLE `myaac_forum` +CREATE TABLE IF NOT EXISTS `myaac_forum` ( `id` int NOT NULL AUTO_INCREMENT, `first_post` int NOT NULL DEFAULT 0, @@ -107,7 +96,7 @@ CREATE TABLE `myaac_forum` KEY `section` (`section`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE `myaac_menu` +CREATE TABLE IF NOT EXISTS `myaac_menu` ( `id` int NOT NULL AUTO_INCREMENT, `template` varchar(255) NOT NULL, @@ -121,7 +110,7 @@ CREATE TABLE `myaac_menu` PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE `myaac_monsters` ( +CREATE TABLE IF NOT EXISTS `myaac_monsters` ( `id` int NOT NULL AUTO_INCREMENT, `hide` tinyint NOT NULL DEFAULT 0, `name` varchar(255) NOT NULL, @@ -154,7 +143,7 @@ CREATE TABLE `myaac_monsters` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE `myaac_news` +CREATE TABLE IF NOT EXISTS `myaac_news` ( `id` int NOT NULL AUTO_INCREMENT, `title` varchar(100) NOT NULL, @@ -172,7 +161,7 @@ CREATE TABLE `myaac_news` PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE `myaac_news_categories` +CREATE TABLE IF NOT EXISTS `myaac_news_categories` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL DEFAULT "", @@ -182,13 +171,7 @@ CREATE TABLE `myaac_news_categories` PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 0); -INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 1); -INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 2); -INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 3); -INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 4); - -CREATE TABLE `myaac_notepad` +CREATE TABLE IF NOT EXISTS `myaac_notepad` ( `id` int NOT NULL AUTO_INCREMENT, `account_id` int NOT NULL, @@ -198,7 +181,7 @@ CREATE TABLE `myaac_notepad` PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE `myaac_pages` +CREATE TABLE IF NOT EXISTS `myaac_pages` ( `id` INT NOT NULL AUTO_INCREMENT, `name` varchar(30) NOT NULL, @@ -214,7 +197,7 @@ CREATE TABLE `myaac_pages` UNIQUE (`name`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE `myaac_gallery` +CREATE TABLE IF NOT EXISTS `myaac_gallery` ( `id` int NOT NULL AUTO_INCREMENT, `comment` varchar(255) NOT NULL DEFAULT '', @@ -226,9 +209,7 @@ CREATE TABLE `myaac_gallery` PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -INSERT INTO `myaac_gallery` (`id`, `ordering`, `comment`, `image`, `thumb`, `author`) VALUES (NULL, 1, 'Demon', 'images/gallery/demon.jpg', 'images/gallery/demon_thumb.gif', 'MyAAC'); - -CREATE TABLE `myaac_settings` +CREATE TABLE IF NOT EXISTS `myaac_settings` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL DEFAULT '', @@ -238,7 +219,7 @@ CREATE TABLE `myaac_settings` KEY `key` (`key`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE `myaac_spells` +CREATE TABLE IF NOT EXISTS `myaac_spells` ( `id` int NOT NULL AUTO_INCREMENT, `spell` varchar(255) NOT NULL DEFAULT '', @@ -261,7 +242,7 @@ CREATE TABLE `myaac_spells` UNIQUE (`name`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE `myaac_visitors` +CREATE TABLE IF NOT EXISTS `myaac_visitors` ( `ip` varchar(45) NOT NULL, `lastvisit` int NOT NULL DEFAULT 0, @@ -270,7 +251,7 @@ CREATE TABLE `myaac_visitors` UNIQUE (`ip`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE `myaac_weapons` +CREATE TABLE IF NOT EXISTS `myaac_weapons` ( `id` int NOT NULL, `level` int NOT NULL DEFAULT 0, diff --git a/install/tools/5-database.php b/install/tools/5-database.php index f377b809..6406ee48 100644 --- a/install/tools/5-database.php +++ b/install/tools/5-database.php @@ -30,26 +30,22 @@ if(!$error) { } } -if($db->hasTable(TABLE_PREFIX . 'account_actions')) { - $locale['step_database_error_table_exist'] = str_replace('$TABLE$', TABLE_PREFIX . 'account_actions', $locale['step_database_error_table_exist']); - warning($locale['step_database_error_table_exist']); -} -else { - // import schema - try { - $locale['step_database_importing'] = str_replace('$DATABASE_NAME$', config('database_name'), $locale['step_database_importing']); - success($locale['step_database_importing']); +// import schema +try { + $locale['step_database_importing'] = str_replace('$DATABASE_NAME$', config('database_name'), $locale['step_database_importing']); + success($locale['step_database_importing']); - $db->exec(file_get_contents(BASE . 'install/includes/schema.sql')); + $db->exec(file_get_contents(BASE . 'install/includes/schema.sql')); - $locale['step_database_success_schema'] = str_replace('$PREFIX$', TABLE_PREFIX, $locale['step_database_success_schema']); - success($locale['step_database_success_schema']); - } - catch(PDOException $error_) { - error($locale['step_database_error_schema'] . ' ' . $error_); - return; - } + $locale['step_database_success_schema'] = str_replace('$PREFIX$', TABLE_PREFIX, $locale['step_database_success_schema']); + success($locale['step_database_success_schema']); } +catch(PDOException $error_) { + error($locale['step_database_error_schema'] . ' ' . $error_); + return; +} + +require BASE . 'install/includes/import_base_data.php'; if(!$db->hasColumn('accounts', 'email')) { if(query("ALTER TABLE `accounts` ADD `email` varchar(255) NOT NULL DEFAULT '';")) diff --git a/system/locale/de/install.php b/system/locale/de/install.php index 927da34b..351f6009 100644 --- a/system/locale/de/install.php +++ b/system/locale/de/install.php @@ -78,6 +78,7 @@ $locale['step_database_error_mysql_connect_3'] = 'MySQL ist nicht richtig konfig $locale['step_database_error_mysql_connect_4'] = 'MySQL-Server läuft nicht.'; $locale['step_database_error_schema'] = 'Fehler beim Importieren des Schemas:'; $locale['step_database_success_schema'] = '$PREFIX$ Tabellen wurden erfolgreich installiert.'; +$locale['step_database_success_import_data'] = 'Import von Daten für Tabellen was erfolgreich.'; $locale['step_database_error_file'] = '$FILE$ konnte nicht geöffnet werden. Bitte kopieren Sie diesen Inhalt und fügen Sie ihn dort ein:'; $locale['step_database_adding_field'] = 'Folgendes Feld wurde hinzugefügt: '; $locale['step_database_modifying_field'] = 'Folgendes Feld wurde geändert: '; diff --git a/system/locale/en/install.php b/system/locale/en/install.php index 376e82c3..c623035c 100644 --- a/system/locale/en/install.php +++ b/system/locale/en/install.php @@ -83,6 +83,7 @@ $locale['step_database_error_mysql_connect_3'] = 'MySQL is not configured proper $locale['step_database_error_mysql_connect_4'] = 'MySQL server is not running.'; $locale['step_database_error_schema'] = 'Error while importing schema:'; $locale['step_database_success_schema'] = 'Successfully installed $PREFIX$ tables.'; +$locale['step_database_success_import_data'] = 'Successfully imported base data for tables.'; $locale['step_database_error_file'] = '$FILE$ couldn\'t be opened. Please copy this content and paste there:'; $locale['step_database_adding_field'] = 'Adding field'; $locale['step_database_modifying_field'] = 'Modifying field'; diff --git a/system/locale/pl/install.php b/system/locale/pl/install.php index 159a7d8f..a8ea0cf6 100644 --- a/system/locale/pl/install.php +++ b/system/locale/pl/install.php @@ -81,7 +81,8 @@ $locale['step_database_error_mysql_connect_2'] = 'Możliwe przyczyny:'; $locale['step_database_error_mysql_connect_3'] = 'MySQL nie jest poprawnie skonfigurowane w config.lua.'; $locale['step_database_error_mysql_connect_4'] = 'Serwer MySQL nie jest uruchomiony.'; $locale['step_database_error_schema'] = 'Błąd podczas importowania struktury bazy danych:'; -$locale['step_database_success_schema'] = 'Pomyślnie zainstalowano tabele $PREFIX$.'; +$locale['step_database_success_schema'] = 'Pomyślnie zaimportowano tabele $PREFIX$.'; +$locale['step_database_success_import_data'] = 'Pomyślnie załadowano bazowe dane dla tabel.'; $locale['step_database_error_file'] = '$FILE$ nie mógł zostać otwarty. Proszę skopiować zawartość pola tekstowego i wkleić do tego pliku:'; $locale['step_database_adding_field'] = 'Dodawanie pola'; $locale['step_database_modifying_field'] = 'Modyfikacja pola'; diff --git a/system/src/Models/Changelog.php b/system/src/Models/Changelog.php index b7356166..45f8cf59 100644 --- a/system/src/Models/Changelog.php +++ b/system/src/Models/Changelog.php @@ -18,7 +18,16 @@ class Changelog extends Model { public $timestamps = false; + protected $fillable = [ + 'body', 'type', 'where', + 'date', 'player_id', 'hide', + ]; + public function scopeIsPublic($query) { $query->where('hide', '!=', 1); } + + public function player() { + return $this->belongsTo(Player::class); + } } diff --git a/system/src/Models/ForumBoard.php b/system/src/Models/ForumBoard.php new file mode 100644 index 00000000..ee03fde9 --- /dev/null +++ b/system/src/Models/ForumBoard.php @@ -0,0 +1,16 @@ + Date: Mon, 27 Oct 2025 16:43:34 +0100 Subject: [PATCH 35/40] Release v1.8.4 --- CHANGELOG-1.x.md | 10 ++++++++++ common.php | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-1.x.md b/CHANGELOG-1.x.md index 8779d2c5..bea711e1 100644 --- a/CHANGELOG-1.x.md +++ b/CHANGELOG-1.x.md @@ -1,5 +1,15 @@ # Changelog +## [1.8.4 - 27.10.2025] + +### Changed +* Reimport myaac_ tables on every install, this fixes errors when one table is missing or is duplicated (https://github.com/slawkens/myaac/commit/2580edadf84779f09fd395c21f92019b2c762f83) +* Use custom env init on migrate, migrate:run and migrate:to (https://github.com/slawkens/myaac/commit/13ea68cc0c9349380c8e4051d702a6c2c8256f44, https://github.com/slawkens/myaac/commit/07fd034fe4cb0ffdb88667b1e400f414d0c6d06f) + +### Fixed +* Show if there is mysql error on import schema (https://github.com/slawkens/myaac/commit/44110a9496b4385e42c31b75de301037e711b6c3) +* Fix the premium checks (mostly TFS 1.6+), introduced in v1.8.3 (https://github.com/slawkens/myaac/commit/9d92a11fb7cb6d7a1619d79c12faaa0b1c01f980) + ## [1.8.3 - 21.10.2025] ### Added diff --git a/common.php b/common.php index 1cbd0dd8..4c9d9155 100644 --- a/common.php +++ b/common.php @@ -26,7 +26,7 @@ if (version_compare(phpversion(), '8.1', '<')) die('PHP version 8.1 or higher is required.'); const MYAAC = true; -const MYAAC_VERSION = '1.8.3'; +const MYAAC_VERSION = '1.8.4'; const DATABASE_VERSION = 46; const TABLE_PREFIX = 'myaac_'; define('START_TIME', microtime(true)); From 4b8c3ffae253bbec5a503667d5aa94a5335f0c85 Mon Sep 17 00:00:00 2001 From: slawkens Date: Mon, 27 Oct 2025 16:55:29 +0100 Subject: [PATCH 36/40] Code smell --- admin/pages/mass_account.php | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/admin/pages/mass_account.php b/admin/pages/mass_account.php index 6b1ccb46..4ee9f63b 100644 --- a/admin/pages/mass_account.php +++ b/admin/pages/mass_account.php @@ -6,6 +6,7 @@ * @package MyAAC * @author Slawkens * @author Lee + * @author gpedro * @copyright 2020 MyAAC * @link https://my-aac.org */ @@ -19,9 +20,9 @@ $title = 'Mass Account Actions'; csrfProtect(); $hasPointsColumn = $db->hasColumn('accounts', 'premium_points'); -$freePremium = $config['lua']['freePremium']; +$freePremium = getBoolean(configLua('freePremium')); -function admin_give_points($points) +function admin_give_points($points): void { global $hasPointsColumn; @@ -37,7 +38,7 @@ function admin_give_points($points) displayMessage($points . ' points added to all accounts.', true); } -function admin_give_coins($coins) +function admin_give_coins($coins): void { if (!HAS_ACCOUNT_COINS) { displayMessage('Coins not supported.'); @@ -52,7 +53,7 @@ function admin_give_coins($coins) displayMessage($coins . ' coins added to all accounts.', true); } -function admin_give_premdays($days) +function admin_give_premdays($days): void { global $db, $freePremium; @@ -63,6 +64,7 @@ function admin_give_premdays($days) $value = $days * 86400; $now = time(); + // othire if ($db->hasColumn('accounts', 'premend')) { // append premend @@ -70,14 +72,11 @@ function admin_give_premdays($days) // set premend if (Account::where('premend', '<=', $now)->update(['premend' => $now + $value])) { displayMessage($days . ' premium days added to all accounts.', true); - return; } else { displayMessage('Failed to execute set query.'); - return; } } else { displayMessage('Failed to execute append query.'); - return; } return; @@ -92,20 +91,14 @@ function admin_give_premdays($days) // set lastday if (Account::where('lastday', '<=', $now)->update(['lastday' => $now + $value])) { displayMessage($days . ' premium days added to all accounts.', true); - return; } else { displayMessage('Failed to execute set query.'); - return; } - - return; } else { displayMessage('Failed to execute append query.'); - return; } } else { displayMessage('Failed to execute set days query.'); - return; } return; @@ -118,14 +111,11 @@ function admin_give_premdays($days) // set premium_ends_at if (Account::where('premium_ends_at', '<=', $now)->update(['premium_ends_at' => $now + $value])) { displayMessage($days . ' premium days added to all accounts.', true); - return; } else { displayMessage('Failed to execute set query.'); - return; } } else { displayMessage('Failed to execute append query.'); - return; } return; @@ -170,7 +160,8 @@ else { )); } -function displayMessage($message, $success = false) { +function displayMessage($message, $success = false): void +{ global $twig, $hasPointsColumn, $freePremium; $success ? success($message): error($message); From a2f8759a5236112d4e360c69bb39c7bd3965e62d Mon Sep 17 00:00:00 2001 From: slawkens Date: Mon, 27 Oct 2025 17:10:16 +0100 Subject: [PATCH 37/40] Update CHANGELOG-1.x.md --- CHANGELOG-1.x.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG-1.x.md b/CHANGELOG-1.x.md index bea711e1..b8c57ce7 100644 --- a/CHANGELOG-1.x.md +++ b/CHANGELOG-1.x.md @@ -8,7 +8,7 @@ ### Fixed * Show if there is mysql error on import schema (https://github.com/slawkens/myaac/commit/44110a9496b4385e42c31b75de301037e711b6c3) -* Fix the premium checks (mostly TFS 1.6+), introduced in v1.8.3 (https://github.com/slawkens/myaac/commit/9d92a11fb7cb6d7a1619d79c12faaa0b1c01f980) +* Fix the premium checks, introduced in v1.8.3 (https://github.com/slawkens/myaac/commit/9d92a11fb7cb6d7a1619d79c12faaa0b1c01f980) ## [1.8.3 - 21.10.2025] From d24bde2c1df2244388b63ce7fbf556b359f8c155 Mon Sep 17 00:00:00 2001 From: slawkens Date: Mon, 27 Oct 2025 21:45:34 +0100 Subject: [PATCH 38/40] Start v1.8.5-dev --- common.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.php b/common.php index 4c9d9155..48945038 100644 --- a/common.php +++ b/common.php @@ -26,7 +26,7 @@ if (version_compare(phpversion(), '8.1', '<')) die('PHP version 8.1 or higher is required.'); const MYAAC = true; -const MYAAC_VERSION = '1.8.4'; +const MYAAC_VERSION = '1.8.5-dev'; const DATABASE_VERSION = 46; const TABLE_PREFIX = 'myaac_'; define('START_TIME', microtime(true)); From bc4107bd16965e3f4b5f5d7e4aa0846e91445f49 Mon Sep 17 00:00:00 2001 From: slawkens Date: Thu, 30 Oct 2025 18:54:11 +0100 Subject: [PATCH 39/40] Ignore only top-most Lua folder --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b198856f..15c069b1 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ Thumbs.db # /.htaccess -lua +/lua # composer composer.phar From 26c5aa2e51c215f9a14db170a7591430ad7787d9 Mon Sep 17 00:00:00 2001 From: slawkens Date: Fri, 31 Oct 2025 06:52:56 +0100 Subject: [PATCH 40/40] Added more code into Items::getDescription Is not ready yet --- system/src/Items.php | 48 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/system/src/Items.php b/system/src/Items.php index 977aa602..0f92b005 100644 --- a/system/src/Items.php +++ b/system/src/Items.php @@ -76,10 +76,11 @@ class Items public static function get($id) { self::load(); - return isset(self::$items[$id]) ? self::$items[$id] : []; + return self::$items[$id] ?? []; } - public static function getDescription($id, $count = 1) { + public static function getDescription($id, $count = 1): string + { $item = self::get($id); $attr = $item['attributes']; @@ -112,15 +113,15 @@ class Items $s .= 'an item of type ' . $item['id']; if(isset($attr['type']) && strtolower($attr['type']) == 'rune') { - $item = Spell::where('item_id', $id)->first(); - if($item) { - if($item->level > 0 && $item->maglevel > 0) { - $s .= '. ' . ($count > 1 ? "They" : "It") . ' can only be used by '; + $spell = Spell::where('item_id', $id)->first(); + if($spell) { + if($spell->level > 0 && $spell->maglevel > 0) { + $s .= '. ' . ($count > 1 ? 'They' : 'It') . ' can only be used by '; } $configVocations = config('vocations'); - if(!empty(trim($item->vocations))) { - $vocations = json_decode($item->vocations); + if(!empty(trim($spell->vocations))) { + $vocations = json_decode($spell->vocations); if(count($vocations) > 0) { foreach($vocations as $voc => $show) { $vocations[$configVocations[$voc]] = $show; @@ -133,8 +134,39 @@ class Items $s .= ' with'; + if ($spell->level > 0) { + $s .= ' level ' . $spell->level; + } + + if ($spell->maglevel > 0) { + if ($spell->level > 0) { + $s .= ' and'; + } + + $s .= ' magic level ' . $spell->maglevel; + } + + $s .= ' or higher'; } } + + if (!empty($item['weaponType'])) { + if ($item['weaponType'] == 'distance' && isset($item['ammoType'])) { + $s .= ' (Range:' . $item['range']; + } + + if (isset($item['attack']) && $item['attack'] != 0) { + $s .= ', Atk ' . ($item['attack'] > 0 ? '+' . $item['attack'] : '-' . $item['attack']); + } + + if (isset($item['hitChance']) && $item['hitChance'] != -1) { + $s .= ', Hit% ' . ($item['hitChance'] > 0 ? '+' . $item['hitChance'] : '-' . $item['hitChance']); + } + elseif ($item['weaponType'] != 'ammo') { + + } + } + return $s; } }