Merge branch 'main' into feature/2fa

This commit is contained in:
slawkens
2025-09-14 09:53:34 +02:00
19 changed files with 293 additions and 114 deletions

View File

@@ -1,5 +1,21 @@
# Changelog # Changelog
## [1.8.1 - 05.09.2025]
### Added
* New Commands: plugin:enable/disable/uninstall {plugin-name} (https://github.com/slawkens/myaac/commit/7a08f91d3fc0897c1ff76089ef3c649a2c6d2003, https://github.com/slawkens/myaac/commit/fec773ba4b740f35c0a3ef92ca8444a4c7d02082)
* Gifts: Added Transferable Coins to the store dropdown menu in the admin area (by @andreoam, #321) (https://github.com/slawkens/myaac/commit/42671c5c199dd9e91c774d8c9d30da9e12f1b695)
### Changed
* Commands: Allow settings to be changed/reset by plugin name (https://github.com/slawkens/myaac/commit/f8c4332e03e838d285ea0afb4b72b7c23e324d45, https://github.com/slawkens/myaac/commit/4b948e9510f7ba69d00f84d7fdaea8b3bf05b630)
* Templates: Menus should be saved for each template separately (https://github.com/slawkens/myaac/commit/482f4067b2a2e7513d9ba214274a361ffaf123d8)
### Fixed
* Online: Fix skulls display (#320) (https://github.com/slawkens/myaac/commit/98073a110ae13f9592ec9d2c4d1d1aace87587a9)
* Online: Fix if there is no world_id in the server_record table (https://github.com/slawkens/myaac/commit/b6e1620f14c20eecfc9001a7d86dfb67942985c6) (Reported by @gesior in #318)
* tibiacom: some fixes to menus (https://github.com/slawkens/myaac/commit/20f99903ae80c74ad66c1cf5a5ea8d0b0fc2fd70, https://github.com/slawkens/myaac/commit/11dae90fa94fbbf47447017db5e5847c33d6aadf)
* Guilds: Fix for some servers that don't have guild_invites table (https://github.com/slawkens/myaac/commit/9725a3c2bdb7003f5cb48febb77604c31a9b805b)
## [1.8 - 02.08.2025] ## [1.8 - 02.08.2025]
### Added ### Added

View File

@@ -26,7 +26,7 @@
if (version_compare(phpversion(), '8.1', '<')) die('PHP version 8.1 or higher is required.'); if (version_compare(phpversion(), '8.1', '<')) die('PHP version 8.1 or higher is required.');
const MYAAC = true; const MYAAC = true;
const MYAAC_VERSION = '1.8.1-dev'; const MYAAC_VERSION = '1.8.2-dev';
const DATABASE_VERSION = 46; const DATABASE_VERSION = 46;
const TABLE_PREFIX = 'myaac_'; const TABLE_PREFIX = 'myaac_';
define('START_TIME', microtime(true)); define('START_TIME', microtime(true));

View File

@@ -42,45 +42,44 @@ if(!$error) {
$configToSave['cache_prefix'] = 'myaac_' . generateRandomString(8, true, false, true); $configToSave['cache_prefix'] = 'myaac_' . generateRandomString(8, true, false, true);
$configToSave['database_auto_migrate'] = true; $configToSave['database_auto_migrate'] = true;
if(!$error) { $content = '';
$content = ''; $saved = Settings::saveConfig($configToSave, BASE . 'config.local.php', $content);
$saved = Settings::saveConfig($configToSave, BASE . 'config.local.php', $content); if ($saved || file_exists(BASE . 'config.local.php')) {
if ($saved) { success($locale['step_database_config_saved']);
success($locale['step_database_config_saved']); $_SESSION['saved'] = true;
$_SESSION['saved'] = true;
require BASE . 'config.local.php'; require BASE . 'config.local.php';
require BASE . 'install/includes/config.php'; require BASE . 'install/includes/config.php';
if (!$error) { if (!$error) {
require BASE . 'install/includes/database.php'; require BASE . 'install/includes/database.php';
if (isset($database_error)) { // we failed connect to the database if (isset($database_error)) { // we failed connect to the database
error($database_error); error($database_error);
}
else {
if (!$db->hasTable('accounts')) {
$tmp = str_replace('$TABLE$', 'accounts', $locale['step_database_error_table']);
error($tmp);
$error = true;
} }
else {
if (!$db->hasTable('accounts')) {
$tmp = str_replace('$TABLE$', 'accounts', $locale['step_database_error_table']);
error($tmp);
$error = true;
}
if (!$error) { if (!$error) {
$twig->display('install.installer.html.twig', array( $twig->display('install.installer.html.twig', array(
'url' => 'tools/5-database.php', 'url' => 'tools/5-database.php',
'message' => $locale['loading_spinner'] 'message' => $locale['loading_spinner']
)); ));
}
} }
} }
} else {
$_SESSION['config_content'] = $content;
unset($_SESSION['saved']);
$locale['step_database_error_file'] = str_replace('$FILE$', '<b>' . BASE . 'config.php</b>', $locale['step_database_error_file']);
error($locale['step_database_error_file'] . '<br/>
<textarea cols="70" rows="10">' . $content . '</textarea>');
} }
} else {
$error = true;
$_SESSION['config_content'] = $content;
unset($_SESSION['saved']);
$locale['step_database_error_file'] = str_replace('$FILE$', '<b>' . BASE . 'config.local.php</b>', $locale['step_database_error_file']);
error($locale['step_database_error_file'] . '<br/>
<textarea cols="70" rows="10">' . $content . '</textarea>');
} }
} }
?> ?>

View File

@@ -23,6 +23,12 @@ if(!Validator::guildName($guild_name)) {
$errors[] = Validator::getLastError(); $errors[] = Validator::getLastError();
} }
if (!$db->hasTableAndColumns('guild_invites', ['player_id'])) {
$errors[] = "Guild invite is not possible on this website.";
$twig->display('error_box.html.twig', ['errors' => $errors]);
return;
}
if(empty($errors)) { if(empty($errors)) {
$guild = new OTS_Guild(); $guild = new OTS_Guild();
$guild->find($guild_name); $guild->find($guild_name);
@@ -58,7 +64,7 @@ if(empty($errors)) {
} }
} }
if(!$guild_vice) { if(empty($errors) && !$guild_vice) {
$errors[] = 'You are not a leader or vice leader of guild <b>'.$guild_name.'</b>.'.$level_in_guild; $errors[] = 'You are not a leader or vice leader of guild <b>'.$guild_name.'</b>.'.$level_in_guild;
} }
@@ -84,6 +90,7 @@ if(isset($_POST['todo']) && $_POST['todo'] == 'save') {
} }
} }
} }
if(empty($errors)) { if(empty($errors)) {
include(SYSTEM . 'libs/pot/InvitesDriver.php'); include(SYSTEM . 'libs/pot/InvitesDriver.php');
new InvitesDriver($guild); new InvitesDriver($guild);
@@ -104,6 +111,7 @@ if(!empty($errors)) {
else { else {
if(isset($_POST['todo']) && $_POST['todo'] == 'save') { if(isset($_POST['todo']) && $_POST['todo'] == 'save') {
$guild->invite($player); $guild->invite($player);
$twig->display('success.html.twig', array( $twig->display('success.html.twig', array(
'title' => 'Invite player', 'title' => 'Invite player',
'description' => 'Player with name <b>' . $player->getName() . '</b> has been invited to your guild.', 'description' => 'Player with name <b>' . $player->getName() . '</b> has been invited to your guild.',

View File

@@ -121,25 +121,28 @@ foreach($rank_list as $rank)
} }
} }
include(SYSTEM . 'libs/pot/InvitesDriver.php'); $invited_list = [];
new InvitesDriver($guild);
$invited_list = $guild->listInvites();
$show_accept_invite = 0; $show_accept_invite = 0;
if($logged && count($invited_list) > 0)
{ if ($db->hasTableAndColumns('guild_invites', ['player_id'])) {
foreach($invited_list as $invited_player) include(SYSTEM . 'libs/pot/InvitesDriver.php');
{ new InvitesDriver($guild);
if(count($account_players) > 0) $invited_list = $guild->listInvites();
{
foreach($account_players as $player_from_acc) if($logged && count($invited_list) > 0) {
{ foreach($invited_list as $invited_player) {
if($player_from_acc->isLoaded() && $invited_player->isLoaded() && $player_from_acc->getName() == $invited_player->getName()) if(count($account_players) > 0) {
$show_accept_invite++; foreach($account_players as $player_from_acc) {
if($player_from_acc->isLoaded() && $invited_player->isLoaded() && $player_from_acc->getName() == $invited_player->getName()) {
$show_accept_invite++;
}
}
} }
} }
} }
} }
$useGuildNick = $db->hasTable('guild_members') || $db->hasTable('guild_membership') || $db->hasColumn('players', 'guildnick'); $useGuildNick = $db->hasTable('guild_members') || $db->hasTable('guild_membership') || $db->hasColumn('players', 'guildnick');
$twig->display('guilds.view.html.twig', array( $twig->display('guilds.view.html.twig', array(

View File

@@ -94,19 +94,30 @@ $dispatcher = FastRoute\cachedDispatcher(function (FastRoute\RouteCollector $r)
$routesFinal[] = ['*', $page, '__database__/' . $page, 100]; $routesFinal[] = ['*', $page, '__database__/' . $page, 100];
} }
$routes = require SYSTEM . 'routes.php';
Plugins::clearWarnings(); Plugins::clearWarnings();
foreach (Plugins::getRoutes() as $route) {
$routesFinal[] = [$route[0], $route[1], $route[2], $route[3] ?? 1000]; foreach (Plugins::getRoutes() as $pluginRoute) {
$routesFinal[] = [$pluginRoute[0], $pluginRoute[1], $pluginRoute[2], $pluginRoute[3] ?? 1000];
// Possibility to override routes with plugins pages, like characters.php
foreach ($routes as &$route) {
if (str_contains($pluginRoute[2], 'pages/' . $route[2])) {
$route[2] = $pluginRoute[2];
}
}
/* /*
echo '<pre>'; echo '<pre>';
var_dump($route[1], $route[3], $route[2]); var_dump($pluginRoute[1], $pluginRoute[3], $pluginRoute[2]);
echo '/<pre>'; echo '/<pre>';
*/ */
} }
$routes = require SYSTEM . 'routes.php';
foreach ($routes as $route) { foreach ($routes as $route) {
if (!str_contains($route[2], '__redirect__') && !str_contains($route[2], '__database__')) { if (!str_contains($route[2], '__redirect__') && !str_contains($route[2], '__database__')
&& !str_contains($route[2], 'plugins/')
) {
if (!is_file(BASE . 'system/pages/' . $route[2])) { if (!is_file(BASE . 'system/pages/' . $route[2])) {
continue; continue;
} }

View File

@@ -28,6 +28,15 @@ if (!IS_CLI) {
$siteURL = $serverUrl . $baseDir; $siteURL = $serverUrl . $baseDir;
} }
$donateColumnOptions = [
'premium_points' => 'Premium Points',
'coins' => 'Coins',
];
if (defined('HAS_ACCOUNT_COINS_TRANSFERABLE') && (HAS_ACCOUNT_COINS_TRANSFERABLE || HAS_ACCOUNT_TRANSFERABLE_COINS)) {
$donateColumnOptions[ACCOUNT_COINS_TRANSFERABLE_COLUMN] = 'Coins Transferable';
}
return [ return [
'name' => 'MyAAC', 'name' => 'MyAAC',
'settings' => [ 'settings' => [
@@ -1295,7 +1304,7 @@ Sent by MyAAC,<br/>
'name' => 'Data Center', 'name' => 'Data Center',
'type' => 'text', 'type' => 'text',
'desc' => 'Server Location, will be shown on online page', 'desc' => 'Server Location, will be shown on online page',
'default' => 'Frankfurt - Germany', 'default' => 'Poland - Warsaw',
], ],
[ [
'type' => 'section', 'type' => 'section',
@@ -1598,13 +1607,14 @@ Sent by MyAAC,<br/>
'name' => 'Donate Column', 'name' => 'Donate Column',
'type' => 'options', 'type' => 'options',
'desc' => 'What to give to player after donation - what column in accounts table to use.', 'desc' => 'What to give to player after donation - what column in accounts table to use.',
'options' => ['premium_points' => 'Premium Points', 'coins' => 'Coins'], 'options' => $donateColumnOptions,
'default' => 'premium_points', 'default' => 'premium_points',
'callbacks' => [ 'callbacks' => [
'beforeSave' => function($key, $value, &$errorMessage) { 'beforeSave' => function($key, $value, &$errorMessage) {
global $db; global $db;
if ($value == 'coins' && !HAS_ACCOUNT_COINS) {
$errorMessage = "Shop: Donate Column: Cannot set column to coins, because it doesn't exist in database."; if (!$db->hasColumn('accounts', $value)) {
$errorMessage = "Shop: Donate Column: Cannot set column to $value, because it doesn't exist in database.";
return false; return false;
} }
return true; return true;

View File

@@ -45,6 +45,22 @@ class MigrateRunCommand extends Command
$down = $input->getOption('down') ?? false; $down = $input->getOption('down') ?? false;
/**
* Sort according to $down option.
* Do we really want it?
* Or should we use order provided by user,
* even when it's not sorted correctly?
* Leaving it for consideration.
*/
/*
if ($down) {
rsort($ids);
}
else {
sort($ids);
}
*/
foreach ($ids as $id) { foreach ($ids as $id) {
$this->executeMigration($id, $io, !$down); $this->executeMigration($id, $io, !$down);
} }

View File

@@ -0,0 +1,36 @@
<?php
namespace MyAAC\Commands;
use MyAAC\Plugins;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class PluginDisableCommand extends Command
{
protected function configure(): void
{
$this->setName('plugin:disable')
->setDescription('This command disables plugin')
->addArgument('plugin-name', InputArgument::REQUIRED, 'Plugin that you want to disable');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
require SYSTEM . 'init.php';
$io = new SymfonyStyle($input, $output);
$pluginName = $input->getArgument('plugin-name');
if (!Plugins::disable($pluginName)) {
$io->error('Error while disabling plugin ' . $pluginName . ': ' . Plugins::getError());
return 2;
}
$io->success('Successfully disabled plugin ' . $pluginName);
return Command::SUCCESS;
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace MyAAC\Commands;
use MyAAC\Plugins;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class PluginEnableCommand extends Command
{
protected function configure(): void
{
$this->setName('plugin:enable')
->setDescription('This command enables plugin')
->addArgument('plugin-name', InputArgument::REQUIRED, 'Plugin that you want to enable');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
require SYSTEM . 'init.php';
$io = new SymfonyStyle($input, $output);
$pluginName = $input->getArgument('plugin-name');
if (!Plugins::enable($pluginName)) {
$io->error('Error while enabling plugin ' . $pluginName . ': ' . Plugins::getError());
return 2;
}
$io->success('Successfully enabled plugin ' . $pluginName);
return Command::SUCCESS;
}
}

View File

@@ -8,7 +8,7 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Console\Style\SymfonyStyle;
class PluginInstallInstallCommand extends Command class PluginSetupCommand extends Command
{ {
protected function configure(): void protected function configure(): void
{ {

View File

@@ -0,0 +1,40 @@
<?php
namespace MyAAC\Commands;
use MyAAC\Plugins;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class PluginUninstallCommand extends Command
{
protected function configure(): void
{
$this->setName('plugin:uninstall')
->setDescription('This command uninstalls plugin')
->addArgument('plugin-name', InputArgument::REQUIRED, 'Plugin that you want to uninstall');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
require SYSTEM . 'init.php';
$io = new SymfonyStyle($input, $output);
$pluginName = $input->getArgument('plugin-name');
if (!Plugins::uninstall($pluginName)) {
$io->error('Error while uninstalling plugin ' . $pluginName . ': ' . Plugins::getError());
return 2;
}
foreach(Plugins::getWarnings() as $warning) {
$io->warning($warning);
}
$io->success('Successfully uninstalled plugin ' . $pluginName);
return Command::SUCCESS;
}
}

View File

@@ -3,6 +3,7 @@
namespace MyAAC\Commands; namespace MyAAC\Commands;
use MyAAC\Models\Settings as SettingsModel; use MyAAC\Models\Settings as SettingsModel;
use MyAAC\Plugins;
use MyAAC\Settings; use MyAAC\Settings;
use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
@@ -34,7 +35,14 @@ class SettingsResetCommand extends Command
return Command::FAILURE; return Command::FAILURE;
} }
if (!$name) { // find by plugin name
foreach (Plugins::getAllPluginsSettings() as $key => $setting) {
if ($setting['pluginFilename'] === $name) {
$name = $key;
}
}
if (empty($name)) {
SettingsModel::truncate(); SettingsModel::truncate();
} }
else { else {

View File

@@ -3,6 +3,7 @@
namespace MyAAC\Commands; namespace MyAAC\Commands;
use MyAAC\Models\Settings as SettingsModel; use MyAAC\Models\Settings as SettingsModel;
use MyAAC\Plugins;
use MyAAC\Settings; use MyAAC\Settings;
use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
@@ -17,7 +18,7 @@ class SettingsSetCommand extends Command
->setDescription('Updates the setting specified by argument in database') ->setDescription('Updates the setting specified by argument in database')
->addArgument('key', ->addArgument('key',
InputArgument::REQUIRED, InputArgument::REQUIRED,
'Setting name/key' 'Setting key in format name.key'
) )
->addArgument('value', ->addArgument('value',
InputArgument::REQUIRED, InputArgument::REQUIRED,
@@ -34,6 +35,18 @@ class SettingsSetCommand extends Command
$key = $input->getArgument('key'); $key = $input->getArgument('key');
$value = $input->getArgument('value'); $value = $input->getArgument('value');
// format settings_name.key
// example: core.template
$explode = explode('.', $key);
// find by plugin name
foreach (Plugins::getAllPluginsSettings() as $_key => $setting) {
if ($setting['pluginFilename'] === $explode[0]) {
$explode[0] = $_key;
$key = implode('.', $explode);
}
}
$settings = Settings::getInstance(); $settings = Settings::getInstance();
$settings->clearCache(); $settings->clearCache();
$settings->load(); $settings->load();
@@ -44,10 +57,6 @@ class SettingsSetCommand extends Command
return Command::FAILURE; return Command::FAILURE;
} }
// format plugin_name.key
// example: core.template
$explode = explode('.', $key);
$settings->updateInDatabase($explode[0], $explode[1], $value); $settings->updateInDatabase($explode[0], $explode[1], $value);
$settings->clearCache(); $settings->clearCache();

View File

@@ -7,16 +7,13 @@ use MyAAC\Models\Settings as ModelsSettings;
class Settings implements \ArrayAccess class Settings implements \ArrayAccess
{ {
static private $instance; static private ?Settings $instance = null;
private $settingsFile = []; private array $settingsFile = [];
private $settingsDatabase = []; private array $settingsDatabase = [];
private $cache = []; private array $cache = [];
private $valuesAsked = []; private array $valuesAsked = [];
private $errors = []; private array $errors = [];
/**
* @return Settings
*/
public static function getInstance(): Settings public static function getInstance(): Settings
{ {
if (!self::$instance) { if (!self::$instance) {
@@ -26,28 +23,21 @@ class Settings implements \ArrayAccess
return self::$instance; return self::$instance;
} }
public function load() public function load(): void
{ {
$cache = Cache::getInstance(); $this->settingsDatabase = Cache::remember('settings', 10 * 60, function () {
if ($cache->enabled()) { $settingsDatabase = [];
$tmp = '';
if ($cache->fetch('settings', $tmp)) { $settings = ModelsSettings::all();
$this->settingsDatabase = unserialize($tmp); foreach ($settings as $setting) {
return; $settingsDatabase[$setting->name][$setting->key] = $setting->value;
} }
}
$settings = ModelsSettings::all(); return $settingsDatabase;
foreach ($settings as $setting) { });
$this->settingsDatabase[$setting->name][$setting->key] = $setting->value;
}
if ($cache->enabled()) {
$cache->set('settings', serialize($this->settingsDatabase), 600);
}
} }
public function save($pluginName, $values) public function save($pluginName, $values): bool
{ {
$this->loadPlugin($pluginName); $this->loadPlugin($pluginName);
@@ -104,7 +94,7 @@ class Settings implements \ArrayAccess
return true; return true;
} }
public function updateInDatabase($pluginName, $key, $value) public function updateInDatabase($pluginName, $key, $value): void
{ {
if (ModelsSettings::where(['name' => $pluginName, 'key' => $key])->exists()) { if (ModelsSettings::where(['name' => $pluginName, 'key' => $key])->exists()) {
ModelsSettings::where(['name' => $pluginName, 'key' => $key])->update(['value' => $value]); ModelsSettings::where(['name' => $pluginName, 'key' => $key])->update(['value' => $value]);
@@ -117,7 +107,7 @@ class Settings implements \ArrayAccess
$this->clearCache(); $this->clearCache();
} }
public function deleteFromDatabase($pluginName, $key = null) public function deleteFromDatabase($pluginName, $key = null): void
{ {
if (!isset($key)) { if (!isset($key)) {
ModelsSettings::where('name', $pluginName)->delete(); ModelsSettings::where('name', $pluginName)->delete();
@@ -217,7 +207,7 @@ class Settings implements \ArrayAccess
if (isset($setting['hidden']) && $setting['hidden']) { if (isset($setting['hidden']) && $setting['hidden']) {
$value = ''; $value = '';
if ($setting['type'] === 'boolean') { if ($setting['type'] === 'boolean') {
$value = ($setting['default'] ? 'true' : 'false'); $value = (getBoolean($setting['default']) ? 'true' : 'false');
} }
else if (in_array($setting['type'], ['text', 'number', 'float', 'double', 'email', 'password', 'textarea'])) { else if (in_array($setting['type'], ['text', 'number', 'float', 'double', 'email', 'password', 'textarea'])) {
$value = $setting['default']; $value = $setting['default'];
@@ -230,12 +220,7 @@ class Settings implements \ArrayAccess
} }
else if ($setting['type'] === 'boolean') { else if ($setting['type'] === 'boolean') {
if(isset($settingsDb[$key])) { if(isset($settingsDb[$key])) {
if($settingsDb[$key] === 'true') { $value = getBoolean($settingsDb[$key]);
$value = true;
}
else {
$value = false;
}
} }
else { else {
$value = ($setting['default'] ?? false); $value = ($setting['default'] ?? false);
@@ -383,7 +368,7 @@ class Settings implements \ArrayAccess
} }
#[\ReturnTypeWillChange] #[\ReturnTypeWillChange]
public function offsetSet($offset, $value) public function offsetSet($offset, $value): void
{ {
if (is_null($offset)) { if (is_null($offset)) {
throw new \RuntimeException("Settings: You cannot set empty offset with value: $value!"); throw new \RuntimeException("Settings: You cannot set empty offset with value: $value!");
@@ -423,7 +408,7 @@ class Settings implements \ArrayAccess
} }
#[\ReturnTypeWillChange] #[\ReturnTypeWillChange]
public function offsetUnset($offset) public function offsetUnset($offset): void
{ {
$this->loadPlugin($offset); $this->loadPlugin($offset);
@@ -455,7 +440,7 @@ class Settings implements \ArrayAccess
* @return array|mixed * @return array|mixed
*/ */
#[\ReturnTypeWillChange] #[\ReturnTypeWillChange]
public function offsetGet($offset) public function offsetGet($offset): mixed
{ {
// try cache hit // try cache hit
if(isset($this->cache[$offset])) { if(isset($this->cache[$offset])) {
@@ -521,7 +506,7 @@ class Settings implements \ArrayAccess
return $ret; return $ret;
} }
private function updateValuesAsked($offset) private function updateValuesAsked($offset): void
{ {
$pluginKeyName = $offset; $pluginKeyName = $offset;
if (strpos($offset, '.')) { if (strpos($offset, '.')) {
@@ -537,7 +522,7 @@ class Settings implements \ArrayAccess
} }
} }
private function loadPlugin($offset) private function loadPlugin($offset): void
{ {
$this->updateValuesAsked($offset); $this->updateValuesAsked($offset);
@@ -566,7 +551,7 @@ class Settings implements \ArrayAccess
} }
} }
public static function saveConfig($config, $filename, &$content = '') public static function saveConfig($config, $filename, &$content = ''): bool|int
{ {
$content = "<?php" . PHP_EOL; $content = "<?php" . PHP_EOL;

View File

@@ -148,7 +148,7 @@ function get_template_menus(): array
{ {
global $template_name; global $template_name;
$result = Cache::remember('template_menus', 10 * 60, function () use ($template_name) { $result = Cache::remember('template_menus_' . $template_name, 10 * 60, function () use ($template_name) {
$result = Menu::select(['name', 'link', 'blank', 'color', 'category']) $result = Menu::select(['name', 'link', 'blank', 'color', 'category'])
->where('template', $template_name) ->where('template', $template_name)
->orderBy('category') ->orderBy('category')

View File

@@ -235,14 +235,16 @@
{% endif %} {% endif %}
{% if isVice %} {% if isVice %}
<form action="{{ getLink('guilds') }}?action=invite&guild={{ guild_name|url_encode }}" method="post"> {% if db.hasTableAndColumns('guild_invites', ['player_id']) %}
{{ csrf() }} <form action="{{ getLink('guilds') }}?action=invite&guild={{ guild_name|url_encode }}" method="post">
<td> {{ csrf() }}
{% set button_name = 'Invite Character' %} <td>
{% set button_image = '_sbutton_invitecharacter' %} {% set button_name = 'Invite Character' %}
{% include('buttons.base.html.twig') %} {% set button_image = '_sbutton_invitecharacter' %}
</td> {% include('buttons.base.html.twig') %}
</form> </td>
</form>
{% endif %}
<form action="{{ getLink('guilds') }}?action=change_rank&guild={{ guild_name|url_encode }}" method="post"> <form action="{{ getLink('guilds') }}?action=change_rank&guild={{ guild_name|url_encode }}" method="post">
{{ csrf() }} {{ csrf() }}

View File

@@ -161,7 +161,7 @@
{% endif %} {% endif %}
<td style="width:70%; text-align:left"> <td style="width:70%; text-align:left">
{{ player.name|raw }}{{ player.skull }} {{ player.name|raw }}{{ player.skull|raw }}
</td> </td>
<td style="width:10%">{{ player.level }}</td> <td style="width:10%">{{ player.level }}</td>
<td style="width:20%">{{ player.vocation }}</td> <td style="width:20%">{{ player.vocation }}</td>

View File

@@ -391,7 +391,7 @@ foreach($config['menu_categories'] as $id => $cat) {
?> ?>
</div> </div>
<?php <?php
if($id == MENU_CATEGORY_SHOP || (!setting('core.gifts_system') && $i == $countElements)) { if ($i == $countElements) {
?> ?>
<div id='MenuBottom' style='background-image:url(<?php echo $template_path; ?>/images/general/box-bottom.gif);'></div> <div id='MenuBottom' style='background-image:url(<?php echo $template_path; ?>/images/general/box-bottom.gif);'></div>
<?php <?php