Merge branch 'main' into develop

This commit is contained in:
slawkens 2025-04-18 13:58:42 +02:00
commit c13a540878
11 changed files with 186 additions and 76 deletions

View File

@ -1,5 +1,16 @@
# Changelog # Changelog
## [1.3.3 - 04.04.2025]
### Fixed
* Fix uninstall plugin when plugin is disabled (https://github.com/slawkens/myaac/commit/6c568fd36a271270684fc412ccd556b230273a6d)
### Changed
* Display more useful info when error parsing config.lua (https://github.com/slawkens/myaac/commit/fa6b6aa153ffc131e0d1631a4dcd9012a5850c2e)
### Other
* Small adjustments (https://github.com/slawkens/myaac/commit/35e2483de86e295bdf089cceffa25842eeb2e34c, https://github.com/slawkens/myaac/commit/ae639d65b0bfa491e747e907e2ebc77f83f47981)
## [1.3.2 - 01.04.2025] ## [1.3.2 - 01.04.2025]
### Fixed ### Fixed

View File

@ -1,6 +1,8 @@
<?php <?php
// few things we'll need // few things we'll need
use MyAAC\Plugins;
require '../common.php'; require '../common.php';
const ADMIN_PANEL = true; const ADMIN_PANEL = true;
@ -42,15 +44,21 @@ if(!$logged || !admin()) {
$page = 'login'; $page = 'login';
} }
// include our page $pluginsAdminPages = Plugins::getAdminPages();
$file = __DIR__ . '/pages/' . $page . '.php'; if(isset($pluginsAdminPages[$page]) && file_exists(BASE . $pluginsAdminPages[$page])) {
if(!@file_exists($file)) { $file = BASE . $pluginsAdminPages[$page];
if (str_contains($page, 'plugins/')) { }
$file = BASE . $page; else {
} // include our page
else { $file = __DIR__ . '/pages/' . $page . '.php';
$page = '404'; if(!@file_exists($file)) {
$file = SYSTEM . 'pages/404.php'; if (str_contains($page, 'plugins/')) {
$file = BASE . $page;
}
else {
$page = '404';
$file = SYSTEM . 'pages/404.php';
}
} }
} }

View File

@ -48,6 +48,8 @@
"pages": true, "pages": true,
"pagesSubFolders": false, "pagesSubFolders": false,
"commands": true, "commands": true,
"themes": true "themes": true,
"admin-pages": true,
"admin-pages-sub-folders": true,
} }
} }

View File

@ -343,16 +343,16 @@ function getDatabasePages($withHidden = false): array
function loadPageFromFileSystem($page, &$found): string function loadPageFromFileSystem($page, &$found): string
{ {
$file = SYSTEM . 'pages/' . $page . '.php'; // feature: load pages from templates/ dir
global $template_path;
$file = $template_path . '/pages/' . $page . '.php';
if (!is_file($file)) { if (!is_file($file)) {
// feature: convert camelCase to snake_case $file = SYSTEM . 'pages/' . $page . '.php';
// so instead of forum/move_thread
// we can write: forum/moveThread
$file = SYSTEM . 'pages/' . camelCaseToUnderscore($page) . '.php';
if (!is_file($file)) { if (!is_file($file)) {
// feature: load pages from templates/ dir // feature: convert camelCase to snake_case
global $template_path; // so instead of forum/move_thread
$file = $template_path . '/pages/' . $page . '.php'; // we can write: forum/moveThread
$file = SYSTEM . 'pages/' . camelCaseToUnderscore($page) . '.php';
if (!is_file($file)) { if (!is_file($file)) {
$found = false; $found = false;
} }

View File

@ -11,6 +11,81 @@ class Plugins {
private static $error = null; private static $error = null;
private static $plugin_json = []; private static $plugin_json = [];
public static function getAdminPages()
{
return Cache::remember('plugins_admin_pages', 10 * 60, function () {
$adminPages = [];
foreach(self::getAllPluginsJson() as $plugin) {
if (!self::getAutoLoadOption($plugin, 'admin-pages', true)) {
continue;
}
$adminPagesDefaultPriority = 1000;
if (isset($plugin['admin-pages-default-priority'])) {
$adminPagesDefaultPriority = $plugin['admin-pages-default-priority'];
}
//
// Get all plugins/*/admin-pages/*.php pages
//
$pluginAdminPages = glob(PLUGINS . $plugin['filename'] . '/admin-pages/*.php');
foreach ($pluginAdminPages as $file) {
$file = str_replace(PLUGINS, 'plugins/', $file);
$name = pathinfo($file, PATHINFO_FILENAME);
$adminPages[] = ['name' => $name, 'file' => $file, 'priority' => $adminPagesDefaultPriority];
}
if (self::getAutoLoadOption($plugin, 'admin-pages-sub-folders', true)) {
//
// Get all plugins/*/admin-pages/subFolder/*.php pages
//
$pluginAdminPagesSubFolders = glob(PLUGINS . $plugin['filename'] . '/admin-pages/*', GLOB_ONLYDIR);
foreach ($pluginAdminPagesSubFolders as $folder) {
$folderName = pathinfo($folder, PATHINFO_FILENAME);
$subFiles = glob(PLUGINS . $plugin['filename'] . '/admin-pages/' . $folderName . '/*.php');
foreach ($subFiles as $file) {
$file = str_replace(PLUGINS, 'plugins/', $file);
$name = $folderName . '/' . pathinfo($file, PATHINFO_FILENAME);
$adminPages[] = ['name' => $name, 'file' => $file, 'priority' => $adminPagesDefaultPriority];
}
$subFolders = glob(PLUGINS . $plugin['filename'] . '/admin-pages/' . $folderName . '/*', GLOB_ONLYDIR);
foreach ($subFolders as $subFolder) {
$subFolderName = pathinfo($subFolder, PATHINFO_FILENAME);
$subSubFiles = glob(PLUGINS . $plugin['filename'] . '/admin-pages/' . $folderName . '/' . $subFolderName . '/*.php');
foreach ($subSubFiles as $subSubFile) {
$subSubFile = str_replace(PLUGINS, 'plugins/', $subSubFile);
$name = $folderName . '/' . $subFolderName . '/' . pathinfo($subSubFile, PATHINFO_FILENAME);
$adminPages[] = ['name' => $name, 'file' => $subSubFile, 'priority' => $adminPagesDefaultPriority];;
}
}
}
}
}
usort($adminPages, function ($a, $b)
{
if ($a['priority'] == $b['priority']) {
return 0;
}
return ($a['priority'] > $b['priority']) ? -1 : 1;
});
$ret = [];
foreach ($adminPages as $value) {
$ret[$value['name']] = $value['file'];
}
return $ret;
});
}
public static function getRoutes() public static function getRoutes()
{ {
$cache = Cache::getInstance(); $cache = Cache::getInstance();
@ -411,20 +486,13 @@ class Plugins {
$continue = true; $continue = true;
if(!isset($plugin_json['name']) || empty(trim($plugin_json['name']))) { if(!isset($plugin_json['name']) || empty(trim($plugin_json['name']))) {
self::$warnings[] = 'Plugin "name" tag is not set.'; self::$error = 'Plugin "name" tag is not set.';
} return false;
if(!isset($plugin_json['description']) || empty(trim($plugin_json['description']))) {
self::$warnings[] = 'Plugin "description" tag is not set.';
} }
if(!isset($plugin_json['version']) || empty(trim($plugin_json['version']))) { if(!isset($plugin_json['version']) || empty(trim($plugin_json['version']))) {
self::$warnings[] = 'Plugin "version" tag is not set.'; self::$warnings[] = 'Plugin "version" tag is not set.';
} }
if(!isset($plugin_json['author']) || empty(trim($plugin_json['author']))) {
self::$warnings[] = 'Plugin "author" tag is not set.';
}
if(!isset($plugin_json['contact']) || empty(trim($plugin_json['contact']))) {
self::$warnings[] = 'Plugin "contact" tag is not set.';
}
if(isset($plugin_json['require'])) { if(isset($plugin_json['require'])) {
$require = $plugin_json['require']; $require = $plugin_json['require'];

View File

@ -1 +1 @@
<input type="submit" name="{{ button_name }}" value="{{ button_name }}" /> <input {% if noSubmit is not defined %}type="submit"{% endif %} name="{{ button_name }}" value="{{ button_name }}" />

View File

@ -4,24 +4,25 @@
<input type="hidden" name="redirect" value="{{ redirect }}" /> <input type="hidden" name="redirect" value="{{ redirect }}" />
{% endif %} {% endif %}
<div class="TableContainer" > <div class="TableContainer" >
<table class="Table4" cellpadding="0" cellspacing="0" > <div class="CaptionContainer" >
<div class="CaptionContainer" > <div class="CaptionInnerContainer" >
<div class="CaptionInnerContainer" > <span class="CaptionEdgeLeftTop" style="background-image:url({{ template_path }}/images/global/content/box-frame-edge.gif);" ></span>
<span class="CaptionEdgeLeftTop" style="background-image:url({{ template_path }}/images/global/content/box-frame-edge.gif);" /></span> <span class="CaptionEdgeRightTop" style="background-image:url({{ template_path }}/images/global/content/box-frame-edge.gif);" ></span>
<span class="CaptionEdgeRightTop" style="background-image:url({{ template_path }}/images/global/content/box-frame-edge.gif);" /></span> <span class="CaptionBorderTop" style="background-image:url({{ template_path }}/images/global/content/table-headline-border.gif);" ></span>
<span class="CaptionBorderTop" style="background-image:url({{ template_path }}/images/global/content/table-headline-border.gif);" ></span> <span class="CaptionVerticalLeft" style="background-image:url({{ template_path }}/images/global/content/box-frame-vertical.gif);" ></span>
<span class="CaptionVerticalLeft" style="background-image:url({{ template_path }}/images/global/content/box-frame-vertical.gif);" /></span> <div class="Text" >Account Login</div>
<div class="Text" >Account Login</div> <span class="CaptionVerticalRight" style="background-image:url({{ template_path }}/images/global/content/box-frame-vertical.gif);" ></span>
<span class="CaptionVerticalRight" style="background-image:url({{ template_path }}/images/global/content/box-frame-vertical.gif);" /></span> <span class="CaptionBorderBottom" style="background-image:url({{ template_path }}/images/global/content/table-headline-border.gif);" ></span>
<span class="CaptionBorderBottom" style="background-image:url({{ template_path }}/images/global/content/table-headline-border.gif);" ></span> <span class="CaptionEdgeLeftBottom" style="background-image:url({{ template_path }}/images/global/content/box-frame-edge.gif);" ></span>
<span class="CaptionEdgeLeftBottom" style="background-image:url({{ template_path }}/images/global/content/box-frame-edge.gif);" /></span> <span class="CaptionEdgeRightBottom" style="background-image:url({{ template_path }}/images/global/content/box-frame-edge.gif);" ></span>
<span class="CaptionEdgeRightBottom" style="background-image:url({{ template_path }}/images/global/content/box-frame-edge.gif);" /></span>
</div>
</div> </div>
</div>
<table class="Table4" cellpadding="0" cellspacing="0" >
<tr> <tr>
<td> <td>
<div class="InnerTableContainer" > <div class="InnerTableContainer" >
<table style="width:100%;" > <table style="width:100%;" >
<tbody>
<tr> <tr>
<td> <td>
<div class="TableShadowContainerRightTop" > <div class="TableShadowContainerRightTop" >
@ -30,20 +31,21 @@
<div class="TableContentAndRightShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-rm.gif);" > <div class="TableContentAndRightShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-rm.gif);" >
<div class="TableContentContainer" > <div class="TableContentContainer" >
<table class="TableContent" width="100%" style="border:1px solid #faf0d7;" > <table class="TableContent" width="100%" style="border:1px solid #faf0d7;" >
<tbody>
<tr> <tr>
<td> <td>
<table style="float: left; width: 370px;" cellpadding="0" cellspacing="0" > <table style="float: left; width: 100%;" cellpadding="0" cellspacing="0" >
{{ hook('HOOK_ACCOUNT_LOGIN_BEFORE_ACCOUNT') }} {{ hook('HOOK_ACCOUNT_LOGIN_BEFORE_ACCOUNT') }}
<tr> <tr>
<td class="LabelV"> <td class="LabelV">
<span{% if error is not null %} class="red"{% endif %}>{{ account_login_by }}:</span> <span{% if error is not null %} class="red"{% endif %}>{{ account_login_by }}:</span>
</td> </td>
<td><input type="text" name="account_login" size="35" maxlength="{{ setting('core.account_login_by_email') ? '255' : '30' }}" autofocus /></td> <td><input style="width: 100%;" type="text" name="account_login" size="35" maxlength="{{ setting('core.account_login_by_email') ? '255' : '30' }}" autofocus /></td>
</tr> </tr>
{{ hook('HOOK_ACCOUNT_LOGIN_AFTER_ACCOUNT') }} {{ hook('HOOK_ACCOUNT_LOGIN_AFTER_ACCOUNT') }}
<tr> <tr>
<td class="LabelV" ><span{% if error is not null %} class="red"{% endif %}>Password:</span></td> <td class="LabelV" ><span{% if error is not null %} class="red"{% endif %}>Password:</span></td>
<td><input type="password" name="password_login" size="35" maxlength="29" /></td> <td><input style="width: 100%;" type="password" name="password_login" size="35" maxlength="29" /></td>
</tr> </tr>
{{ hook('HOOK_ACCOUNT_LOGIN_AFTER_PASSWORD') }} {{ hook('HOOK_ACCOUNT_LOGIN_AFTER_PASSWORD') }}
<tr> <tr>
@ -53,17 +55,19 @@
</tr> </tr>
{{ hook('HOOK_ACCOUNT_LOGIN_AFTER_REMEMBER_ME') }} {{ hook('HOOK_ACCOUNT_LOGIN_AFTER_REMEMBER_ME') }}
</table> </table>
<div style="float: right; font-size: 1px;" > </td>
<input type="hidden" name="page" value="overview" > <td id="LoginFormButtonCell">
<div style="float: right;" >
{{ include('buttons.login.html.twig') }} {{ include('buttons.login.html.twig') }}
</form>
<div style="width: 2px; height: 2px;" ></div> <div style="width: 2px; height: 2px;" ></div>
<form action="{{ getLink('account/lost') }}" method="post" style="padding:0px;margin:0px;" > <a href="{{ getLink('account/lost') }}" style="padding:0;margin:0;" >
{{ include('buttons.account_lost.html.twig') }} {% set noSubmit = true %}
</form> {{ include('buttons.account_lost.html.twig') }}
</div> </a>
</div>
</td> </td>
</tr> </tr>
</tbody>
</table> </table>
</div> </div>
</div> </div>
@ -75,35 +79,40 @@
</div> </div>
</td> </td>
</tr> </tr>
</tbody>
</table> </table>
</div> </div>
</td> </td>
</tr> </tr>
</table> </table>
</div> </div>
</form>
<br/> <br/>
<div style="text-align:center"> <div style="text-align:center">
<h1>New to {{ config.lua.serverName }}?</h1> <h1>New to {{ config.lua.serverName }}?</h1>
</div> </div>
<div class="TableContainer" > <div class="TableContainer" >
<table class="Table4" cellpadding="0" cellspacing="0" > <div class="CaptionContainer" >
<div class="CaptionContainer" > <div class="CaptionInnerContainer" >
<div class="CaptionInnerContainer" > <span class="CaptionEdgeLeftTop" style="background-image:url({{ template_path }}/images/global/content/box-frame-edge.gif);"></span>
<span class="CaptionEdgeLeftTop" style="background-image:url({{ template_path }}/images/global/content/box-frame-edge.gif);" /></span> <span class="CaptionEdgeRightTop" style="background-image:url({{ template_path }}/images/global/content/box-frame-edge.gif);"></span>
<span class="CaptionEdgeRightTop" style="background-image:url({{ template_path }}/images/global/content/box-frame-edge.gif);" /></span> <span class="CaptionBorderTop" style="background-image:url({{ template_path }}/images/global/content/table-headline-border.gif);" ></span>
<span class="CaptionBorderTop" style="background-image:url({{ template_path }}/images/global/content/table-headline-border.gif);" ></span> <span class="CaptionVerticalLeft" style="background-image:url({{ template_path }}/images/global/content/box-frame-vertical.gif);"></span>
<span class="CaptionVerticalLeft" style="background-image:url({{ template_path }}/images/global/content/box-frame-vertical.gif);" /></span> <div class="Text" >New Player</div>
<div class="Text" >New Player</div> <span class="CaptionVerticalRight" style="background-image:url({{ template_path }}/images/global/content/box-frame-vertical.gif);"></span>
<span class="CaptionVerticalRight" style="background-image:url({{ template_path }}/images/global/content/box-frame-vertical.gif);" /></span> <span class="CaptionBorderBottom" style="background-image:url({{ template_path }}/images/global/content/table-headline-border.gif);" ></span>
<span class="CaptionBorderBottom" style="background-image:url({{ template_path }}/images/global/content/table-headline-border.gif);" ></span> <span class="CaptionEdgeLeftBottom" style="background-image:url({{ template_path }}/images/global/content/box-frame-edge.gif);"></span>
<span class="CaptionEdgeLeftBottom" style="background-image:url({{ template_path }}/images/global/content/box-frame-edge.gif);" /></span> <span class="CaptionEdgeRightBottom" style="background-image:url({{ template_path }}/images/global/content/box-frame-edge.gif);"></span>
<span class="CaptionEdgeRightBottom" style="background-image:url({{ template_path }}/images/global/content/box-frame-edge.gif);" /></span>
</div>
</div> </div>
</div>
<table class="Table3" cellpadding="0" cellspacing="0" >
<tbody>
<tr> <tr>
<td> <td>
<div class="InnerTableContainer" > <div class="InnerTableContainer" >
<table style="width:100%;" > <table style="width:100%;" >
<tbody>
<tr> <tr>
<td> <td>
<div class="TableShadowContainerRightTop" > <div class="TableShadowContainerRightTop" >
@ -112,6 +121,7 @@
<div class="TableContentAndRightShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-rm.gif);" > <div class="TableContentAndRightShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-rm.gif);" >
<div class="TableContentContainer" > <div class="TableContentContainer" >
<table class="TableContent" width="100%" style="border:1px solid #faf0d7;" > <table class="TableContent" width="100%" style="border:1px solid #faf0d7;" >
<tbody>
<tr> <tr>
<td > <td >
<div style="float: right; margin-top: 20px;" > <div style="float: right; margin-top: 20px;" >
@ -129,9 +139,12 @@
<div style="margin-left: 10px;" > <div style="margin-left: 10px;" >
<p>... where hardcore gaming meets fantasy.</p> <p>... where hardcore gaming meets fantasy.</p>
<p>... where friendships last a lifetime.</p> <p>... where friendships last a lifetime.</p>
<p>... unites adventurers since 2017!</p> <p>... unites adventurers since 1997!</p>
</div> </div>
</div> </div>
</td>
</tr>
</tbody>
</table> </table>
</div> </div>
</div> </div>
@ -143,10 +156,12 @@
</div> </div>
</td> </td>
</tr> </tr>
</tbody>
</table> </table>
</div> </div>
</td> </td>
</tr> </tr>
</tbody>
</table> </table>
</div> </div>
{{ hook('HOOK_ACCOUNT_LOGIN_AFTER_PAGE') }} {{ hook('HOOK_ACCOUNT_LOGIN_AFTER_PAGE') }}

View File

@ -36,6 +36,12 @@ img {
width: expression(document.body.clientWidth > 1200? "1200px": "100%" ); width: expression(document.body.clientWidth > 1200? "1200px": "100%" );
} }
#LoginFormButtonCell {
width: 145px;
vertical-align: top;
padding-right: 10px;
}
#ContentRow { #ContentRow {
position: relative; position: relative;
top: 155px; top: 155px;

View File

@ -13,7 +13,7 @@
<div class="BigButton" style="background-image:url({{ template_path }}/images/global/buttons/{{ tmp_image }}.gif)"> <div class="BigButton" style="background-image:url({{ template_path }}/images/global/buttons/{{ tmp_image }}.gif)">
<div onMouseOver="MouseOverBigButton(this);" onMouseOut="MouseOutBigButton(this);"> <div onMouseOver="MouseOverBigButton(this);" onMouseOut="MouseOutBigButton(this);">
<div class="BigButtonOver" style="background-image:url({{ template_path }}/images/global/buttons/{{ tmp_image }}_over.gif);" ></div> <div class="BigButtonOver" style="background-image:url({{ template_path }}/images/global/buttons/{{ tmp_image }}_over.gif);" ></div>
<input class="BigButtonText" type="submit" value="{{ button_name }}"> <input class="BigButtonText" {% if noSubmit is not defined %}type="submit"{% endif %} value="{{ button_name }}">
</div> </div>
</div> </div>
{% endapply %} {% endapply %}

View File

@ -1,3 +1,3 @@
{% set button_name = 'Logout' %} {% set button_name = 'Logout' %}
{% set button_image = '_sbutton_logout' %} {% set button_color = 'red' %}
{% include('buttons.base.html.twig') %} {% include('buttons.base.html.twig') %}

View File

@ -1,13 +1,13 @@
<?php <?php
$config['menu_default_links_color'] = '#ffffff'; $config['menu_default_links_color'] = '#ffffff';
$config['menu_categories'] = array( $config['menu_categories'] = [
MENU_CATEGORY_NEWS => array('id' => 'news', 'name' => 'Latest News'), MENU_CATEGORY_NEWS => ['id' => 'news', 'name' => 'Latest News'],
MENU_CATEGORY_ACCOUNT => array('id' => 'account', 'name' => 'Account'), MENU_CATEGORY_ACCOUNT => ['id' => 'account', 'name' => 'Account'],
MENU_CATEGORY_COMMUNITY => array('id' => 'community', 'name' => 'Community'), MENU_CATEGORY_COMMUNITY => ['id' => 'community', 'name' => 'Community'],
MENU_CATEGORY_FORUM => array('id' => 'forum', 'name' => 'Forum'), MENU_CATEGORY_FORUM => ['id' => 'forum', 'name' => 'Forum'],
MENU_CATEGORY_LIBRARY => array('id' => 'library', 'name' => 'Library'), MENU_CATEGORY_LIBRARY => ['id' => 'library', 'name' => 'Library'],
MENU_CATEGORY_SHOP => array('id' => 'shops', 'name' => 'Shop') MENU_CATEGORY_SHOP => ['id' => 'shops', 'name' => 'Shop'],
); ];
$config['menus'] = require __DIR__ . '/menus.php'; $config['menus'] = require __DIR__ . '/menus.php';