Compare commits

...

21 Commits

Author SHA1 Message Date
slawkens
dda4aca832 Merge branch 'develop' into feature/dashboard-insights 2026-04-11 17:59:31 +02:00
slawkens
f6c2e6e460 Merge branch 'main' into develop 2026-04-11 17:58:02 +02:00
slawkens
4145d9eb3c Fix: Clear hooks on plugin uninstall
Fixes error with gesior-shop-system clear-cache.php being called, despite it's removed
2026-04-11 17:49:22 +02:00
slawkens
a27b8a4fa5 Merge branch 'main' of https://github.com/slawkens/myaac 2026-04-11 17:42:45 +02:00
dependabot[bot]
4570ba3801 Bump lodash from 4.17.23 to 4.18.1 (#358)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.23 to 4.18.1.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.23...4.18.1)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-11 17:23:17 +02:00
slawkens
578c0548ee Start v1.8.10-dev 2026-04-11 15:23:46 +02:00
slawkens
aa63e1c986 Fix client boosted + online count (?) 2026-04-10 23:08:33 +02:00
slawkens
0413de85b5 Release v1.8.9 2026-04-06 12:23:42 +02:00
Slawomir Boczek
dd97a749b4 Better name validation, like in the original game website (#356)
* Better name validation, like in the original game website

* Don't automatically ucfirst and strtolower the cases of the word
    * This allows for names like: Lord of Ring, Man of the Earth etc.
* Don't allow special characters like: -, [], '
* Don't allow one letter words
* Require at least one vowel per word
* Add notice about admin logged in

* Add trim, for future

Currently its stripped anyway in the init.php, but AI don't know it :P

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Implement AI recommended changes

* Update tools/validate.php

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Trim $name

* Update Validator.php

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-06 10:41:29 +02:00
slawkens
050181357a Merge branch 'main' into develop 2026-03-15 13:04:37 +01:00
slawkens
853520cfc4 feat: Dashboard Insights 2026-03-15 13:04:07 +01:00
slawkens
4ae2fdd0df Add page load time to admin panel 2026-03-15 13:02:22 +01:00
slawkens
2bf5f5a1db Update GiveAdminCommand.php 2026-02-26 16:46:13 +01:00
slawkens
ccd70d2ee3 Merge branch 'main' into develop 2026-02-24 21:21:36 +01:00
slawkens
5fcde4708a Install: don't suggest deleting of install folder
It is not needed
Instead just remove ip.txt, this will lock the installation
2026-02-24 21:04:20 +01:00
slawkens
f15b0122c6 Nothing important, code style & grammar 2026-02-24 20:35:20 +01:00
slawkens
1da36c7f68 Merge branch 'main' into develop 2026-02-24 20:14:28 +01:00
slawkens
4eb7f48fd7 Update discord link 2026-02-24 20:13:42 +01:00
dependabot[bot]
c82e537dc7 Bump qs from 6.14.1 to 6.14.2 (#353)
Bumps [qs](https://github.com/ljharb/qs) from 6.14.1 to 6.14.2.
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/qs/compare/v6.14.1...v6.14.2)

---
updated-dependencies:
- dependency-name: qs
  dependency-version: 6.14.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-15 01:23:24 +01:00
slawkens
4c3f877091 Update CHANGELOG-2.x.md 2026-02-12 18:21:19 +01:00
slawkens
8b10f85bc1 Start v1.8.9-dev 2026-02-04 18:37:03 +01:00
22 changed files with 351 additions and 47 deletions

View File

@@ -1,5 +1,18 @@
# Changelog # Changelog
## [1.8.9 - 06.04.2026]
### Added
* Settings: Possibility to add custom HTML for the head and body tags like Google Analytics code etc. (https://github.com/slawkens/myaac/commit/108e83806df5686a06826931ed5e243c19cbe130)
* Add command: give-admin (https://github.com/slawkens/myaac/commit/9fa9ec746c4b344387a21f21886c2251319806fc)
* Usage: php aac give:admin slawkens@gmail.com
Parameter: account email, name or id
* It's admin for the website, not the GM for the game! For that, go into the admin panel and change the group manually
* Add page load time to an Admin Panel footer (https://github.com/slawkens/myaac/commit/4ae2fdd0dfcd56697612395c14aecc2dfd33b1c3)
### Changed
* Better character name validation, like in the original game website (#356)
* Install: don't suggest deleting of install folder - it's not required (https://github.com/slawkens/myaac/commit/5fcde4708a39255cf68edc8c43f2ac6597e2601d)
## [1.8.8 - 31.01.2026] ## [1.8.8 - 31.01.2026]
### Added ### Added
* Change Comment: Add missing hooks - patched from 0.8 (https://github.com/slawkens/myaac/commit/a60a23b84f61d41d1503073b52e01e3120f6d92a) * Change Comment: Add missing hooks - patched from 0.8 (https://github.com/slawkens/myaac/commit/a60a23b84f61d41d1503073b52e01e3120f6d92a)

View File

@@ -3,7 +3,7 @@
### Added ### Added
* Add an "access" option to Menus (#340) * Add an "access" option to Menus (#340)
* Possibility to hide menus for unauthorized users * Possibility to hide menus for unauthorized users
* Add the possibility to fetch skills in the getTopPlayers function (#347) * Add the possibility to fetch skills, balance and frags in the getTopPlayers function (#347)
### Changed ### Changed
* Better handling of vocations: (#345) * Better handling of vocations: (#345)

View File

@@ -7,7 +7,7 @@ Official website: https://my-aac.org
[![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/slawkens/myaac/cypress.yml)](https://github.com/slawkens/myaac/actions) [![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/slawkens/myaac/cypress.yml)](https://github.com/slawkens/myaac/actions)
[![License: GPL-3.0](https://img.shields.io/github/license/slawkens/myaac)](https://opensource.org/licenses/gpl-license) [![License: GPL-3.0](https://img.shields.io/github/license/slawkens/myaac)](https://opensource.org/licenses/gpl-license)
[![Downloads Count](https://img.shields.io/github/downloads/slawkens/myaac/total)](https://github.com/slawkens/myaac/releases) [![Downloads Count](https://img.shields.io/github/downloads/slawkens/myaac/total)](https://github.com/slawkens/myaac/releases)
[![OpenTibia Discord](https://img.shields.io/discord/288399552581468162)](https://discord.gg/2J39Wus) [![MyAAC Discord](https://img.shields.io/discord/1468205461319848049)](https://discord.gg/aVagGPJt3g)
[![Closed Issues](https://img.shields.io/github/issues-closed-raw/slawkens/myaac)](https://github.com/slawkens/myaac/issues?q=is%3Aissue+is%3Aclosed) [![Closed Issues](https://img.shields.io/github/issues-closed-raw/slawkens/myaac)](https://github.com/slawkens/myaac/issues?q=is%3Aissue+is%3Aclosed)
| Version | Status | Branch | Requirements | | Version | Status | Branch | Requirements |

View File

@@ -0,0 +1,22 @@
<?php
use MyAAC\Admin\Insights;
defined('MYAAC') or die('Direct access not allowed!');
$getYear = (int)($_GET['year'] ?? date('Y'));
$getMonth = $_GET['month'] ?? (int)date('M') + 1;
$insights = new Insights($db);
$twig->display('insights.html.twig', [
'lastLoginPlayers' => $insights->getLastLoggedPlayers($getYear, $getMonth),
'lastCreatedAccounts' => $insights->getLastCreatedAccounts($getYear, $getMonth),
'firstYear' => $insights->getFirstYear(),
'getYear' => $getYear,
'getMonth' => $getMonth,
'months' => $insights->getMonths(),
]);

View File

@@ -0,0 +1,99 @@
{% set currentYear = 'now' | date('Y') %}
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<div class="col-sm-3 col-md-6 col-lg-12">
<div class="card card-info card-outline">
<div class="card-header">
<h5 class="m-0">Insights</h5>
</div>
<div class="card-body p-3 row">
<div class="col-md-6 col-sm-3">
<label for="month">Month:</label>
<select class="form-control" id="month" name="month">
{% for id, name in months %}
<option value="{{ id }}" {{ getMonth == id ? 'selected="selected"' : '' }}>{{ name }}</option>
{% endfor %}
</select>
</div>
<div class="col-md-6 col-sm-3">
<label for="year">Year:</label>
<select class="form-control" id="year" name="year">
{% for year in range(firstYear, currentYear) %}
<option value="{{ year }}" {{ getYear == year ? 'selected' : '' }}>{{ year }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="card-body p-3 row">
<div class="col-6 col-md-6">
<div class="chart">
<canvas id="lastLoginsChart" style="min-height: 250px; height: 250px; max-height: 250px; max-width: 100%;"></canvas>
</div>
</div>
<div class="col-6 col-md-6">
<div class="chart">
<canvas id="lastCreatedChart" style="min-height: 250px; height: 250px; max-height: 250px; max-width: 100%;"></canvas>
</div>
</div>
</div>
</div>
</div>
<script>
$(function () {
$('#year').on('change', function() {
window.location.href = "?p=dashboard&year=" + $(this).val() + "&month={{ getMonth }}";
});
$('#month').on('change', function() {
window.location.href = "?p=dashboard&year={{ getYear }}" + "&month=" + $(this).val();
});
});
const config = {
type: 'bar',
data: {
labels: [
{% for player in lastLoginPlayers %}
"{{ player.date }}",
{% endfor %}
],
datasets: [
{
label: "Logged players",
backgroundColor: ["#3e95cd", "#8e5ea2", "#3cba9f", "#e8c3b9", "#c45850"],
data: [
{% for player in lastLoginPlayers %}
{{ player.how_much }},
{% endfor %}
]
}
]
}
}
const myChart = new Chart(document.getElementById('lastLoginsChart'), config);
const config2 = {
type: 'bar',
data: {
labels: [
{% for account in lastCreatedAccounts %}
"{{ account.date }}",
{% endfor %}
],
datasets: [
{
label: "Accounts created",
backgroundColor: ["#3e95cd", "#8e5ea2", "#3cba9f", "#e8c3b9", "#c45850"],
data: [
{% for account in lastCreatedAccounts %}
{{ account.how_much }},
{% endfor %}
]
}
]
}
}
const myChart2 = new Chart(document.getElementById('lastCreatedChart'), config2);
</script>

View File

@@ -172,7 +172,8 @@
<div class="float-sm-right d-none d-sm-inline"> <div class="float-sm-right d-none d-sm-inline">
<span class="p-2 right badge badge-<?php echo((isset($status['online']) and $status['online']) ? 'success' : 'danger'); ?>"><?php echo $config['lua']['serverName'] ?></span> <span class="p-2 right badge badge-<?php echo((isset($status['online']) and $status['online']) ? 'success' : 'danger'); ?>"><?php echo $config['lua']['serverName'] ?></span>
</div> </div>
<?php echo base64_decode('UG93ZXJlZCBieSA8YSBocmVmPSJodHRwOi8vbXktYWFjLm9yZyIgdGFyZ2V0PSJfYmxhbmsiPk15QUFDLjwvYT4='); ?> <?= base64_decode('UG93ZXJlZCBieSA8YSBocmVmPSJodHRwOi8vbXktYWFjLm9yZyIgdGFyZ2V0PSJfYmxhbmsiPk15QUFDLjwvYT4='); ?>
<?= 'Load time: ' . round(microtime(true) - START_TIME, 4) . ' seconds.'; ?>
</footer> </footer>
<div id="sidebar-overlay"></div> <div id="sidebar-overlay"></div>
</div> </div>

View File

@@ -30,7 +30,7 @@ if(file_exists(CACHE . 'install.txt')) {
$install_status = unserialize(file_get_contents(CACHE . 'install.txt')); $install_status = unserialize(file_get_contents(CACHE . 'install.txt'));
if(!isset($_REQUEST['step'])) { if(!isset($_REQUEST['step'])) {
$step = isset($install_status['step']) ? $install_status['step'] : ''; $step = $install_status['step'] ?? '';
} }
} }
@@ -53,7 +53,7 @@ if($step == 'finish' && (!isset($config['installed']) || !$config['installed']))
// step verify // step verify
$steps = array(1 => 'welcome', 2 => 'license', 3 => 'requirements', 4 => 'config', 5 => 'database', 6 => 'admin', 7 => 'finish'); $steps = array(1 => 'welcome', 2 => 'license', 3 => 'requirements', 4 => 'config', 5 => 'database', 6 => 'admin', 7 => 'finish');
if(!in_array($step, $steps)) // check if step is valid if(!in_array($step, $steps)) // check if a step is valid
throw new RuntimeException('ERROR: Unknown step.'); throw new RuntimeException('ERROR: Unknown step.');
$install_status['step'] = $step; $install_status['step'] = $step;
@@ -61,7 +61,7 @@ $errors = array();
if($step == 'database') { if($step == 'database') {
foreach($_SESSION as $key => $value) { foreach($_SESSION as $key => $value) {
if(strpos($key, 'var_') === false) { if(!str_contains($key, 'var_')) {
continue; continue;
} }
@@ -182,7 +182,7 @@ $error = false;
clearstatcache(); clearstatcache();
if(is_writable(CACHE) && (MYAAC_OS != 'WINDOWS' || win_is_writable(CACHE))) { if(is_writable(CACHE) && (MYAAC_OS != 'WINDOWS' || win_is_writable(CACHE))) {
if(!file_exists(BASE . 'install/ip.txt')) { if(!file_exists(BASE . 'install/ip.txt')) {
$content = warning('AAC installation is disabled. To enable it make file <b>ip.txt</b> in install/ directory and put there your IP.<br/> $content = warning('AAC installation is disabled. To enable it make a file <b>ip.txt</b> in install/ directory and put there your IP.<br/>
Your IP is:<br /><b>' . get_browser_real_ip() . '</b>', true); Your IP is:<br /><b>' . get_browser_real_ip() . '</b>', true);
} }
else { else {
@@ -198,7 +198,7 @@ if(is_writable(CACHE) && (MYAAC_OS != 'WINDOWS' || win_is_writable(CACHE))) {
if(!$allow) if(!$allow)
{ {
$content = warning('In file <b>install/ip.txt</b> must be your IP!<br/> $content = warning('In file <b>install/ip.txt</b> must be your IP!<br/>
In file is:<br /><b>' . nl2br($file_content) . '</b><br/> In the file is:<br /><b>' . nl2br($file_content) . '</b><br/>
Your IP is:<br /><b>' . get_browser_real_ip() . '</b>', true); Your IP is:<br /><b>' . get_browser_real_ip() . '</b>', true);
} }
else { else {

View File

@@ -30,6 +30,8 @@ $up();
DataLoader::setLocale($locale); DataLoader::setLocale($locale);
DataLoader::load(); DataLoader::load();
clearCache();
// add menus entries // add menus entries
require_once SYSTEM . 'migrations/17.php'; require_once SYSTEM . 'migrations/17.php';
$up(); $up();
@@ -67,6 +69,10 @@ if(file_exists(CACHE . 'install.txt')) {
unlink(CACHE . 'install.txt'); unlink(CACHE . 'install.txt');
} }
if(file_exists(BASE . 'install/ip.txt')) {
unlink(BASE . 'install/ip.txt');
}
$locale['step_finish_desc'] = str_replace('$ADMIN_PANEL$', generateLink(str_replace('tools/', '',ADMIN_URL), $locale['step_finish_admin_panel'], true), $locale['step_finish_desc']); $locale['step_finish_desc'] = str_replace('$ADMIN_PANEL$', generateLink(str_replace('tools/', '',ADMIN_URL), $locale['step_finish_admin_panel'], true), $locale['step_finish_desc']);
$locale['step_finish_desc'] = str_replace('$HOMEPAGE$', generateLink(str_replace('tools/', '', BASE_URL), $locale['step_finish_homepage'], true), $locale['step_finish_desc']); $locale['step_finish_desc'] = str_replace('$HOMEPAGE$', generateLink(str_replace('tools/', '', BASE_URL), $locale['step_finish_homepage'], true), $locale['step_finish_desc']);
$locale['step_finish_desc'] = str_replace('$LINK$', generateLink('https://my-aac.org', 'https://my-aac.org', true), $locale['step_finish_desc']); $locale['step_finish_desc'] = str_replace('$LINK$', generateLink('https://my-aac.org', 'https://my-aac.org', true), $locale['step_finish_desc']);

View File

@@ -93,9 +93,9 @@ switch ($action) {
$creatureBoost = $db->query("SELECT * FROM " . $db->tableName('boosted_creature'))->fetchAll(); $creatureBoost = $db->query("SELECT * FROM " . $db->tableName('boosted_creature'))->fetchAll();
$bossBoost = $db->query("SELECT * FROM " . $db->tableName('boosted_boss'))->fetchAll(); $bossBoost = $db->query("SELECT * FROM " . $db->tableName('boosted_boss'))->fetchAll();
die(json_encode([ die(json_encode([
'boostedcreature' => true, //'boostedcreature' => true,
'bossraceid' => intval($bossBoost[0]['raceid']),
'creatureraceid' => intval($creatureBoost[0]['raceid']), 'creatureraceid' => intval($creatureBoost[0]['raceid']),
'bossraceid' => intval($bossBoost[0]['raceid'])
])); ]));
} }

12
package-lock.json generated
View File

@@ -1431,9 +1431,9 @@
} }
}, },
"node_modules/lodash": { "node_modules/lodash": {
"version": "4.17.23", "version": "4.18.1",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
"integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
@@ -1743,9 +1743,9 @@
} }
}, },
"node_modules/qs": { "node_modules/qs": {
"version": "6.14.1", "version": "6.14.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz",
"integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==",
"dev": true, "dev": true,
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"dependencies": { "dependencies": {

View File

@@ -20,7 +20,7 @@ $locale['not_loaded'] = 'Nicht geladen';
$locale['loading_spinner'] = 'Bitte warten, installieren...'; $locale['loading_spinner'] = 'Bitte warten, installieren...';
$locale['importing_spinner'] = 'Bitte warte, Daten werden importiert...'; $locale['importing_spinner'] = 'Bitte warte, Daten werden importiert...';
$locale['please_fill_all'] = 'Bitte füllen Sie alle Felder aus!'; $locale['please_fill_all'] = 'Bitte füllen Sie alle Felder aus!';
$locale['already_installed'] = 'MyAAC wurde bereits installiert. Bitte löschen <b>install/</b> Verzeichnis. Wenn Sie MyAAC neu installieren möchten, löschen Sie die Datei <strong>config.local.php</strong> aus dem Hauptverzeichnis und aktualisieren Sie die Seite.'; $locale['already_installed'] = 'MyAAC wurde bereits installiert. Wenn Sie MyAAC neu installieren möchten, löschen Sie die Datei <strong>config.local.php</strong> aus dem Hauptverzeichnis und aktualisieren Sie die Seite.';
// welcome // welcome
$locale['step_welcome'] = 'Willkommen'; $locale['step_welcome'] = 'Willkommen';

View File

@@ -20,7 +20,7 @@ $locale['not_loaded'] = 'Not loaded';
$locale['loading_spinner'] = 'Please wait, installing...'; $locale['loading_spinner'] = 'Please wait, installing...';
$locale['importing_spinner'] = 'Please wait, importing data...'; $locale['importing_spinner'] = 'Please wait, importing data...';
$locale['please_fill_all'] = 'Please fill all inputs!'; $locale['please_fill_all'] = 'Please fill all inputs!';
$locale['already_installed'] = 'MyAAC has been already installed. Please delete <b>install/</b> directory. If you want to reinstall MyAAC - please delete <strong>config.local.php</strong> file from the main directory and refresh the page.'; $locale['already_installed'] = 'MyAAC has been already installed. If you want to reinstall MyAAC - please delete <strong>config.local.php</strong> file from the main directory and refresh the page.';
// welcome // welcome
$locale['step_welcome'] = 'Welcome'; $locale['step_welcome'] = 'Welcome';

View File

@@ -20,7 +20,7 @@ $locale['not_loaded'] = 'Nie załadowane';
$locale['loading_spinner'] = 'Proszę czekać, trwa instalacja...'; $locale['loading_spinner'] = 'Proszę czekać, trwa instalacja...';
$locale['importing_spinner'] = 'Proszę czekać, trwa importowanie danych...'; $locale['importing_spinner'] = 'Proszę czekać, trwa importowanie danych...';
$locale['please_fill_all'] = 'Proszę wypełnić wszystkie pola!'; $locale['please_fill_all'] = 'Proszę wypełnić wszystkie pola!';
$locale['already_installed'] = 'MyAAC został już zainstalowany. Proszę usunąć katalog <b>install/</b>. Jeśli chcesz zainstalować MyAAC od nowa - proszę usuń plik <strong>config.local.php</strong> z katalogu głównego i odśwież stronę.'; $locale['already_installed'] = 'MyAAC został już zainstalowany. Jeśli chcesz zainstalować MyAAC od nowa - proszę usuń plik <strong>config.local.php</strong> z katalogu głównego i odśwież stronę.';
// welcome // welcome
$locale['step_welcome'] = 'Witamy'; $locale['step_welcome'] = 'Witamy';

View File

@@ -20,7 +20,7 @@ $locale['not_loaded'] = 'Não carregado';
$locale['loading_spinner'] = 'Por favor aguarde, instalando...'; $locale['loading_spinner'] = 'Por favor aguarde, instalando...';
$locale['importing_spinner'] = 'Por favor, aguarde, importando dados...'; $locale['importing_spinner'] = 'Por favor, aguarde, importando dados...';
$locale['please_fill_all'] = 'Por favor, preencha todas as entradas!'; $locale['please_fill_all'] = 'Por favor, preencha todas as entradas!';
$locale['already_installed'] = 'MyAAC já foi instalado. Por favor, apague o diretório <b> install/ <b/>. Se você quiser reinstalar o MyAAC - exclua o arquivo <strong> config.local.php </strong> do diretório principal e atualize a página.'; $locale['already_installed'] = 'MyAAC já foi instalado. Se você quiser reinstalar o MyAAC - exclua o arquivo <strong> config.local.php </strong> do diretório principal e atualize a página.';
// welcome // welcome
$locale['step_welcome'] = 'Bem vindo'; $locale['step_welcome'] = 'Bem vindo';

View File

@@ -18,7 +18,7 @@ $locale['loaded'] = 'Laddad';
$locale['not_loaded'] = 'Inte Laddad'; $locale['not_loaded'] = 'Inte Laddad';
$locale['please_fill_all'] = 'Vänligen fyll i allt!'; $locale['please_fill_all'] = 'Vänligen fyll i allt!';
$locale['already_installed'] = 'MyAAC är redan installerat. Vänligen ta bort <b>install/<b/> mappen. Om du vill installera MyAAC igen - ta bort filen <strong>config.local.php</strong> från huvudkatalogen och uppdatera sidan.'; $locale['already_installed'] = 'MyAAC är redan installerat. Om du vill installera MyAAC igen - ta bort filen <strong>config.local.php</strong> från huvudkatalogen och uppdatera sidan.';
// welcome // welcome
$locale['step_welcome'] = 'Välkommen'; $locale['step_welcome'] = 'Välkommen';

View File

@@ -171,7 +171,7 @@ if($save)
} }
if(setting('core.account_create_character_create')) { if(setting('core.account_create_character_create')) {
$character_name = isset($_POST['name']) ? stripslashes(ucwords(strtolower($_POST['name']))) : null; $character_name = isset($_POST['name']) ? trim(stripslashes($_POST['name'])) : null;
$character_sex = isset($_POST['sex']) ? (int)$_POST['sex'] : null; $character_sex = isset($_POST['sex']) ? (int)$_POST['sex'] : null;
$character_vocation = isset($_POST['vocation']) ? (int)$_POST['vocation'] : null; $character_vocation = isset($_POST['vocation']) ? (int)$_POST['vocation'] : null;
$character_town = isset($_POST['town']) ? (int)$_POST['town'] : null; $character_town = isset($_POST['town']) ? (int)$_POST['town'] : null;

View File

@@ -0,0 +1,116 @@
<?php
namespace MyAAC\Admin;
use MyAAC\Cache\Cache;
class Insights
{
private $db;
public function __construct($db){
$this->db = $db;
}
public function getLastLoggedPlayers(int $year, $month): array
{
return Cache::remember("admin_dashboard_insights_players_lastlogin_{$year}_{$month}", 5 * 60, function() use ($year, $month) {
$lastLoggedPlayers = [];
$getFromTo = $this->getFromTo($year, $month);
$whereLastLogin = 'AND lastlogin >= ' . $getFromTo[0] . ' AND lastlogin <= ' . $getFromTo[1];
if ($month === 'all') {
$query = $this->db->query('SELECT count(id) as how_much, DATE_FORMAT(FROM_UNIXTIME(lastlogin), "%m.%Y") as lastdate FROM players WHERE lastlogin > 0 ' . $whereLastLogin . ' GROUP BY lastdate LIMIT 14');
foreach ($query as $item) {
$date = explode('.', $item['lastdate']);
$monthName = date('F', mktime(0, 0, 0, $date[0], 10));;
$lastLoggedPlayers[] = ['date' => $monthName, 'how_much' => $item['how_much']];
}
}
else {
$query = $this->db->query('SELECT count(id) as how_much, DATE_FORMAT(FROM_UNIXTIME(lastlogin), "%d.%m.%Y") as lastdate FROM players WHERE lastlogin > 0 ' . $whereLastLogin . ' GROUP BY lastdate LIMIT 14');
foreach ($query as $item) {
$lastLoggedPlayers[] = ['date' => $item['lastdate'], 'how_much' => $item['how_much']];
}
}
return $lastLoggedPlayers;
});
}
public function getLastCreatedAccounts(int $year, $month): array
{
return Cache::remember("admin_dashboard_insights_accounts_created_{$year}_{$month}", 10 * 60, function() use ($year, $month) {
$lastCreatedAccounts = [];
$getFromTo = $this->getFromTo($year, $month);
$whereCreated = 'AND created >= ' . $getFromTo[0] . ' AND created <= ' . $getFromTo[1];
if ($month == 'all') {
$query = $this->db->query('SELECT count(id) as how_much, DATE_FORMAT(FROM_UNIXTIME(created), "%m.%Y") as createdDate FROM accounts WHERE created > 0 ' . $whereCreated . ' GROUP BY createdDate LIMIT 31');
foreach ($query as $item) {
$date = explode('.', $item['createdDate']);
$monthName = date('F', mktime(0, 0, 0, $date[0], 10));;
$lastCreatedAccounts[] = ['date' => $monthName, 'how_much' => $item['how_much']];
}
}
else {
$query = $this->db->query('SELECT count(id) as how_much, DATE_FORMAT(FROM_UNIXTIME(created), "%d.%m.%Y") as createdDate FROM accounts WHERE created > 0 ' . $whereCreated . ' GROUP BY createdDate LIMIT 31');
foreach ($query as $item) {
$lastCreatedAccounts[] = ['date' => $item['createdDate'], 'how_much' => $item['how_much']];
}
}
return $lastCreatedAccounts;
});
}
public function getFirstYear(): int
{
$query = $this->db->query('SELECT created FROM accounts WHERE created > 0 ORDER BY created LIMIT 1');
if ($query->rowCount()) {
$firstAccountCreated = $query->fetch()['created'];
}
else {
$firstAccountCreated = time();
}
return (int)date('Y', $firstAccountCreated);
}
public function getMonths(): array
{
$months = [];
$months['all'] = 'All';
for ($i = 1; $i <= 12; $i++) {
$months[$i] = date('F', mktime(0, 0, 0, $i, 10));
}
return $months;
}
private function getFromTo(int $year, $month): array
{
if ($month == 'all') {
$firstMonth = 1;
$lastMonth = 12;
}
else {
$firstMonth = $month;
$lastMonth = $month;
}
$from = date('U', mktime(0, 0, 0, $firstMonth, 1, $year));
$to = date('U', mktime(0, 0, 0, $lastMonth, 31, $year));
return [$from, $to];
}
}

View File

@@ -39,7 +39,7 @@ class GiveAdminCommand extends Command
} }
if (!$account->isLoaded()) { if (!$account->isLoaded()) {
$io->error('Cannot find account mit supplied parameter: ' . $accountParam); $io->error('Cannot find account with supplied parameter: ' . $accountParam);
return self::FAILURE; return self::FAILURE;
} }

View File

@@ -14,6 +14,26 @@ class Hooks
self::$_hooks[$hook->type()][] = $hook; self::$_hooks[$hook->type()][] = $hook;
} }
public function unregister($name, $type, $file): void
{
if (is_string($type)) {
$type = constant($type);
}
if(!isset(self::$_hooks[$type])) {
return;
}
foreach(self::$_hooks[$type] as $id => $hook) {
if($name == $hook->name()
&& $type == $hook->type()
&& $file == $hook->file()
) {
unset(self::$_hooks[$type][$id]);
}
}
}
public function trigger($type, $params = []): bool public function trigger($type, $params = []): bool
{ {
$ret = true; $ret = true;

View File

@@ -868,6 +868,11 @@ class Plugins {
} }
} }
global $hooks;
foreach($plugin_info['hooks'] ?? [] as $name => $info) {
$hooks->unregister($name, $info['type'], $info['file']);
}
clearCache(); clearCache();
return true; return true;
} }

View File

@@ -183,7 +183,7 @@ class Validator
return false; return false;
} }
// installer doesn't know config.php yet // installer doesn't know settings yet
// that's why we need to ignore the nulls // that's why we need to ignore the nulls
if(defined('MYAAC_INSTALL')) { if(defined('MYAAC_INSTALL')) {
$minLength = 4; $minLength = 4;
@@ -207,21 +207,15 @@ class Validator
return false; return false;
} }
if(strspn($name, "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM- [ ] '") != $length) if(strspn($name, "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM ") != $length)
{ {
self::$lastError = "Invalid name format. Use only A-Z, spaces and '."; self::$lastError = "This name contains invalid letters. Please use only A-Z, a-z and space!";
return false; return false;
} }
if(preg_match('/ {2,}/', $name)) if(preg_match('/ {2,}/', $name))
{ {
self::$lastError = 'Invalid character name format. Use only A-Z and no double spaces.'; self::$lastError = 'Invalid character name format. Use only A-Z, a-z and no double spaces.';
return false;
}
if(!preg_match("/[A-z ']/", $name))
{
self::$lastError = "Invalid name format. Use only A-Z, spaces and '.";
return false; return false;
} }
@@ -230,17 +224,23 @@ class Validator
/** /**
* Validate new character name. * Validate new character name.
* Name lenght must be 3-25 chars * Name length must be 3-25 chars
* *
* @param string $name Name to check * @param string $name Name to check
* @return bool Is name valid? * @return bool Is name valid?
*/ */
public static function newCharacterName($name) public static function newCharacterName($name)
{ {
global $db, $config; global $db;
$name = trim($name);
$name_lower = strtolower($name); $name_lower = strtolower($name);
if(strlen($name) < 1) {
self::$lastError = 'Please enter a name.';
return false;
}
$first_words_blocked = array_merge(["'", '-'], setting('core.create_character_name_blocked_prefix')); $first_words_blocked = array_merge(["'", '-'], setting('core.create_character_name_blocked_prefix'));
foreach($first_words_blocked as $word) { foreach($first_words_blocked as $word) {
if($word == substr($name_lower, 0, strlen($word))) { if($word == substr($name_lower, 0, strlen($word))) {
@@ -249,11 +249,6 @@ class Validator
} }
} }
if(str_ends_with($name_lower, "'") || str_ends_with($name_lower, "-")) {
self::$lastError = 'Your name contains illegal characters.';
return false;
}
if(substr($name_lower, 1, 1) == ' ') { if(substr($name_lower, 1, 1) == ' ') {
self::$lastError = 'Your name contains illegal space.'; self::$lastError = 'Your name contains illegal space.';
return false; return false;
@@ -265,11 +260,36 @@ class Validator
} }
if(preg_match('/ {2,}/', $name)) { if(preg_match('/ {2,}/', $name)) {
self::$lastError = 'Invalid character name format. Use only A-Z and numbers 0-9 and no double spaces.'; self::$lastError = 'Invalid character name format. Use only A-Z and no double spaces.';
return false; return false;
} }
if(strtolower($config['lua']['serverName']) == $name_lower) { if (substr($name[0], 0, 1) !== strtoupper(substr($name[0], 0, 1))) {
self::$lastError = 'The first letter of a name has to be a capital letter.';
return false;
}
foreach (explode(' ', $name) as $word) {
$wordCut = substr($word, 1, strlen($word));
$hasUpperCase = preg_match('/[A-Z]/', $wordCut);
if ($hasUpperCase) {
self::$lastError = 'In names capital letters are only allowed at the beginning of a word.';
return false;
}
if (strlen($word) == 1) {
self::$lastError = 'This name contains a word with only one letter. Please use more than one letter for each word.';
return false;
}
$hasVowel = preg_match('/[aeiouAEIOU]/', $word);
if (!$hasVowel) {
self::$lastError = 'This name contains a word without vowels. Please choose another name.';
return false;
}
}
if(strtolower(configLua('serverName')) == $name_lower) {
self::$lastError = 'Your name cannot be same as server name.'; self::$lastError = 'Your name cannot be same as server name.';
return false; return false;
} }

View File

@@ -63,10 +63,7 @@ else if(isset($_GET['email']))
} }
else if(isset($_GET['name'])) else if(isset($_GET['name']))
{ {
$name = $_GET['name']; $name = trim(stripslashes($_GET['name']));
if(!admin()) {
$name = strtolower(stripslashes($name));
}
if(!Validator::characterName($name)) { if(!Validator::characterName($name)) {
error_(Validator::getLastError()); error_(Validator::getLastError());
@@ -81,7 +78,12 @@ else if(isset($_GET['name']))
error_($errors['name']); error_($errors['name']);
} }
success_('Good. Your name will be:<br /><b>' . (admin() ? $name : ucwords($name)) . '</b>'); $extraText = '';
if (admin()) {
$extraText = "<br/>Note: You are logged in as admin, so you can create almost any name without rules.";
}
success_("Good. Your name will be:<br /><b>$name</b>$extraText");
} }
else if(isset($_GET['password']) && isset($_GET['password_confirm'])) { else if(isset($_GET['password']) && isset($_GET['password_confirm'])) {
$password = $_GET['password']; $password = $_GET['password'];