Compare commits

..

324 Commits

Author SHA1 Message Date
slawkens
6b89dd133d Fix phpstan 2026-04-19 17:29:25 +02:00
slawkens
6dc16397a1 [WIP] Lua + TOML stages loading
Lua extension required for .lua (canary)
2026-04-19 17:22:32 +02:00
slawkens
5dd97ad8fd Add more configs for ots-info site [skip ci] 2026-04-19 16:29:20 +02:00
slawkens
a6a3c76b8d gameplay & groups are also not needed [skip ci] 2026-04-19 16:17:18 +02:00
slawkens
1eba4cc509 [WIP] Loading of config .toml's
Deprecate load_config_lua, use MyAAC\Server\Lua\Loader::load instead
2026-04-19 16:05:22 +02:00
slawkens
6e603ad558 Merge branch 'develop' into blacktek-toml 2026-04-17 17:31:13 +02:00
slawkens
c16f95f8d2 Merge branch 'main' into develop 2026-04-17 17:30:53 +02:00
slawkens
ec7079dd57 Bye JetBrains, it was not my decision :( 2026-04-14 19:58:12 +02:00
slawkens
9e0e2601d2 Add indexes to myaac_account_actions table 2026-04-12 14:13:13 +02:00
slawkens
e7198aeb23 Update CHANGELOG-2.x.md 2026-04-12 13:42:25 +02:00
slawkens
1fa3630f86 Update CHANGELOG-2.x.md 2026-04-12 13:33:16 +02:00
slawkens
e274b83504 Fix: Reset settings by plugin name, not the settings key name 2026-04-12 13:20:48 +02:00
slawkens
a467a540b1 Add constant DEFAULT_PRIORITY 2026-04-12 13:14:10 +02:00
slawkens
08507e2940 Plugins: type hints 2026-04-12 13:10:44 +02:00
slawkens
f1aa128408 Feat: plugins autoload init-priority option 2026-04-12 13:10:15 +02:00
slawkens
7104c2258f Settings: Add Reset button 2026-04-12 10:43:09 +02:00
slawkens
f51211d47a Merge branch 'main' into develop 2026-04-12 09:56:10 +02:00
slawkens
fa93187f80 Add $fillable to Account model 2026-04-12 09:56:01 +02:00
slawkens
2c62a97160 Make myaac_config table columns bigger 2026-04-12 08:53:02 +02:00
slawkens
7bc8a66cc1 BugTracker has been moved to plugins, remove the model 2026-04-11 18:13:25 +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
4ae2fdd0df Add page load time to admin panel 2026-03-15 13:02:22 +01:00
slawkens
2c18f9c767 Backward support for MyAAC\Items class 2026-03-08 21:08:29 +01:00
slawkens
39614a22c4 Update Items.php 2026-03-07 21:16:17 +01:00
slawkens
02ce6b364b Update Items.php 2026-03-07 21:09:57 +01:00
slawkens
e10ebed2f4 Fix fromid toid parsing 2026-03-07 21:00:14 +01:00
slawkens
a6e658b1a2 60x faster items.xml loading
Using simplexml, which is enabled by default on php
2026-03-07 20:54:47 +01:00
slawkens
2a80bc1b46 Nothing important, var name 2026-03-02 21:05:19 +01:00
slawkens
fbb5034458 [WIP] Refactoring - Uniform error message + TOML exception catch 2026-03-01 21:45:48 +01:00
slawkens
4ca79a1e85 Use static methods instead, looks better 2026-02-27 15:25:06 +01:00
slawkens
f975bd2f2a [WIP] Mounts TOML + XML parsers 2026-02-26 19:48:16 +01:00
slawkens
8a5823a69c [WIP] Outfits TOML + XML
Deprecate old Outfits & Mounts functions
2026-02-26 18:39:08 +01:00
slawkens
2bf5f5a1db Update GiveAdminCommand.php 2026-02-26 16:46:13 +01:00
slawkens
f738448f2e [WIP] Refactoring 2026-02-26 16:45:58 +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
slawkens
058e80cfc6 Update Monsters.php 2026-02-15 02:02:07 +01:00
slawkens
980d5cb5d4 Update Items.php 2026-02-15 02:02:05 +01:00
slawkens
9146a0e53c Parse last item 2026-02-15 02:01:57 +01:00
slawkens
ad1d069b1f Copilot fixes 2026-02-15 01:57:26 +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
4bc3923996 glob is not needed here 2026-02-15 01:20:11 +01:00
slawkens
8809467fc6 Delete debug output 2026-02-15 01:19:58 +01:00
slawkens
97ee430a91 Forgot about composer 2026-02-15 01:08:27 +01:00
slawkens
fc9d6b2b91 [WIP] Initial Blacktek support - groups, vocations, items
items.toml loading through custom parser - no .toml reader that I tested can read it
2026-02-15 00:54:18 +01:00
slawkens
4c3f877091 Update CHANGELOG-2.x.md 2026-02-12 18:21:19 +01:00
slawkens
54265f42e9 New Setting: block create account spam by ip 2026-02-06 20:26:14 +01:00
slawkens
bd87881ad0 Update create.php 2026-02-06 20:20:49 +01:00
slawkens
8b10f85bc1 Start v1.8.9-dev 2026-02-04 18:37:03 +01:00
slawkens
7a113ee72a Settings: Possibility to navigate tabs through link 2026-01-31 19:26:35 +01:00
slawkens
8d78e7090d Better gallery
Replaced complex gallery with simple script
Slideshow loaded from images/gallery folder
Credits: https://www.w3schools.com/howto/howto_js_slideshow.asp
2026-01-31 17:42:59 +01:00
slawkens
fd457b2fe8 Merge branch 'main' into develop 2026-01-31 16:01:46 +01:00
slawkens
108e83806d Settings: Custom HTML for <head> and <body> 2026-01-31 16:01:34 +01:00
slawkens
85e8d4d9af Merge branch 'main' into develop 2026-01-31 15:50:08 +01:00
slawkens
9d6287ecbc Settings: Use current year for the footer, instead of predefined one 2026-01-31 15:49:25 +01:00
slawkens
16f4cdf40a Merge branch 'main' into develop 2026-01-31 15:36:45 +01:00
slawkens
9fa9ec746c Add give:admin Command
Usage: php aac give:admin slawkens@gmail.com
Parameter: account email, name or id
2026-01-31 15:29:48 +01:00
slawkens
3e7ee12676 Update news.html.twig 2026-01-31 15:07:49 +01:00
slawkens
b435a2fba4 Update CHANGELOG-2.x.md 2026-01-31 12:37:50 +01:00
slawkens
d91de1005b Merge branch 'main' into develop 2026-01-31 12:31:02 +01:00
slawkens
88ea9ceee1 Create AccountBan.php 2026-01-31 12:30:07 +01:00
slawkens
a92428287d Migration: 49 - Fix get proper account id for samples 2026-01-31 12:12:32 +01:00
slawkens
c753feeeb0 Update CHANGELOG-1.x.md 2026-01-31 11:55:22 +01:00
slawkens
9c8a78a386 Merge branch 'main' into develop 2026-01-31 11:46:03 +01:00
slawkens
e33e86053d Update CHANGELOG-1.x.md 2026-01-31 11:42:40 +01:00
slawkens
6db738a87c Forum: Fix XSS in board name 2026-01-31 11:40:58 +01:00
slawkens
e52d9e486f Fix XSS in forum board name 2026-01-31 11:34:24 +01:00
slawkens
6859b86f28 Release v1.8.8 2026-01-31 11:23:33 +01:00
dependabot[bot]
c472d5e473 Bump lodash from 4.17.21 to 4.17.23 (#350)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.21 to 4.17.23.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.17.23)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-31 10:21:00 +01:00
slawkens
e8b47429e8 Fix post_edit being an author, didn't worked 2026-01-30 22:23:57 +01:00
slawkens
ff4b15ad1d Merge branch 'main' into develop 2026-01-30 16:43:48 +01:00
slawkens
c2415e9df3 Settings: Fix variable overlapping if same var name as in core
Example: Plugin has setting key named "env". The same key exist in core. It would falsely get value from core, instead of the plugin
2026-01-30 16:41:31 +01:00
slawkens
eaa8d9346e Fix migration 49.php when there is no session 2026-01-29 20:44:28 +01:00
slawkens
3e2d4d6686 Merge branch 'main' into develop 2026-01-28 21:59:46 +01:00
slawkens
5e4806f891 Twig: Extract renderInline(content, context) as method to $twig 2026-01-28 21:59:31 +01:00
slawkens
8dcbb66753 Settings: fix show_if for selects 2026-01-28 21:14:52 +01:00
slawkens
87509ffe16 Refactor OTS_Account save(), fixing premium days on canary 2026-01-21 22:31:13 +01:00
slawkens
8d7c36e3eb Merge branch 'main' into develop 2026-01-21 20:31:48 +01:00
dependabot[bot]
7916cfa85f Bump qs and @cypress/request (#349)
Bumps [qs](https://github.com/ljharb/qs) and [@cypress/request](https://github.com/cypress-io/request). These dependencies needed to be updated together.

Updates `qs` from 6.14.0 to 6.14.1
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/qs/compare/v6.14.0...v6.14.1)

Updates `@cypress/request` from 3.0.8 to 3.0.10
- [Release notes](https://github.com/cypress-io/request/releases)
- [Changelog](https://github.com/cypress-io/request/blob/master/CHANGELOG.md)
- [Commits](https://github.com/cypress-io/request/compare/v3.0.8...v3.0.10)

---
updated-dependencies:
- dependency-name: qs
  dependency-version: 6.14.1
  dependency-type: indirect
- dependency-name: "@cypress/request"
  dependency-version: 3.0.10
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-21 20:30:41 +01:00
slawkens
21e6812cf2 Fix phpstan php version matrix 2026-01-21 20:26:08 +01:00
slawkens
1edb4743fe Fix phpstan php version matrix 2026-01-21 20:20:55 +01:00
slawkens
e3efbdc5a8 Add php 8.5 to phpstan workflow 2026-01-17 19:34:48 +01:00
slawkens
d4cc47e341 Add tfs-0.3 to github workflow cypress 2026-01-17 19:21:50 +01:00
Slawomir Boczek
5040a93031 Feature/refactor account lost (#326)
* [WIP] Account Lost refactor

* [WIP] Refactor account/lost

* Update form.html.twig

* Use myaac-table class for tables

* Set $title to 'Lost Account'

* Remove duplicated code - extract lostAccountCooldown function

* [WIP] Add csrfProtect()

* Refactor code, better $error messages

* Formatting

* Refactor

Add missing password check
Formatting

* [WIP] Refactor

* [WIP] Refactor account lost

* [WIP] Refactor account lost - fixes

* [WIP] Account lost refactor

* Fixes
* Add account lost hooks for password strength plugin
2026-01-17 18:59:01 +01:00
slawkens
173b1ace88 Update CHANGELOG-2.x.md 2026-01-17 00:19:35 +01:00
Slawomir Boczek
276aa600e2 Feature/ots player rewrite (#348)
* [WIP] Rewrite OTS_Player class

* Fix exception on load a non existing player

* Fix for servers that don't have the cap & conditions columns

* Fix created column on player save

* Update OTS_Player.php

* Add Monk Sample + fixes

* Move FAQ creation to import_base_data + cleanup
2026-01-16 23:18:03 +01:00
slawkens
8103f5e70f Merge branch 'main' into develop 2026-01-15 21:47:07 +01:00
slawkens
6661c78dac Remove html tags from email function
Not supported by many clients
2026-01-15 21:46:55 +01:00
slawkens
8632cd3191 Add setting core.vocations for backward compatibility 2026-01-14 19:44:56 +01:00
slawkens
8b6f160a0f Fix php cache get return type 2026-01-12 18:59:51 +01:00
slawkens
a60a23b84f (from 0.8) Patch missing change-comment hooks 2026-01-07 22:33:28 +01:00
slawkens
f640ca636f Fix player link in the forum thread (When outfits enabled) 2026-01-06 21:26:44 +01:00
slawkens
5b841682cd Account Manage: Change last login to correct login time
Instead of just "now"
2026-01-04 19:48:30 +01:00
slawkens
c3036e7d49 Don't show account name for server that don't have it
Admin Panel -> Accounts Editor
2026-01-04 16:22:07 +01:00
slawkens
0c4edf625c Fix for servers with promotion column (mostly tfs 0.3+) 2026-01-04 15:30:23 +01:00
slawkens
c28dc29391 Use develop branch for github workflows 2026-01-04 13:33:44 +01:00
slawkens
2db4f6a57b Update online.html.twig 2026-01-04 13:19:58 +01:00
slawkens
9bfd0242af Make vocation a bit smaller
To fit into the theme
2026-01-04 13:18:09 +01:00
slawkens
3ea2b68561 Update CHANGELOG-2.x.md 2026-01-04 13:17:03 +01:00
Slawomir Boczek
dcdaa5ef43 Feature/get top players skills (#347)
* Add skills to getTopPlayers

* Add example top-5

* Extract getSkillIdByName($name)
2026-01-04 13:13:38 +01:00
slawkens
7289cce826 Update CHANGELOG-2.x.md 2026-01-04 13:13:14 +01:00
slawkens
af9d4c2aeb Update CHANGELOG-2.x.md 2026-01-04 13:04:01 +01:00
Slawomir Boczek
a66edfad31 Restore vocations.xml loading + support for Monk (#345)
* Restore vocations.xml loading

For better handling of vocations
Monk is supported now

* New images for vocations (+ added Monk)

* Fix online.html.twig cause of merge
2026-01-04 13:00:34 +01:00
slawkens
89a35b5335 Merge branch 'main' into develop 2026-01-04 12:41:11 +01:00
slawkens
3d6e4c074a Release v1.8.7 2026-01-04 12:31:59 +01:00
slawkens
55da00520d Admin Panel: save menu collapse state 2026-01-03 22:04:49 +01:00
slawkens
efef16ee86 Extract script.ajax-setup.html.twig 2026-01-03 22:01:58 +01:00
slawkens
2f0b67f840 Merge branch 'main' into develop 2026-01-03 20:40:56 +01:00
slawkens
c65d4e4b62 Settings: better responsiveness on mobile 2026-01-03 20:40:44 +01:00
slawkens
fec3f3d297 Fix wrong header in admin changelogs 2026-01-03 20:39:49 +01:00
slawkens
7e6480b380 Return 404 when signature player not found
In most cases it was a request for a non existing file
2026-01-03 20:25:12 +01:00
slawkens
7c9c8d2990 More small adjustments to online page 2026-01-03 13:43:32 +01:00
slawkens
ca2e3bb576 Merge branch 'main' into develop 2026-01-03 13:21:22 +01:00
slawkens
2d8d35f5c8 Some adjustments to the online page
Use tables.headline
Use .myaac-table
2026-01-03 13:21:13 +01:00
slawkens
aba50ca0f1 Better delete rank button 2026-01-02 20:07:17 +01:00
slawkens
0110bf6ea2 Account character list: Add [ DELETED ] for deleted characters 2026-01-02 20:06:07 +01:00
slawkens
ba1c63921d Update guilds.leave_guild.html.twig 2026-01-02 20:02:57 +01:00
slawkens
5c68fba82a Add labels to some inputs + some small adjustments 2026-01-02 15:51:10 +01:00
slawkens
18c0212f9a Forum better button styling 2026-01-02 14:04:34 +01:00
slawkens
e0e0e46701 Move forum show_board code to Twig 2026-01-02 13:30:35 +01:00
slawkens
61bcdc0c37 Merge branch 'main' into develop 2026-01-01 13:23:12 +01:00
slawkens
6f87d8b322 Add missing deprecated config.team_style 2026-01-01 11:56:22 +01:00
slawkens
cc220bedc1 Remove setting: outfit_images_wrong_looktypes
Is obsolete, the bug doesn't exist in latest outfit images
2026-01-01 11:55:58 +01:00
slawkens
f966dff5a8 Convert switch to match 2025-12-28 15:50:10 +01:00
Slawomir Boczek
402f3bb9b0 [WIP] Add access option to Menus (#340)
* [WIP] Add access option to Menus

Thanks @joelslamospersson for idea

* Add notice about Guest*

* Add access column into schema.sql

* Remove spectrum.js from project

Was used in Menus, replaced by html "color" input

* Block access to page if not required Access by Menus
2025-12-26 12:59:49 +01:00
slawkens
e98de451d8 Merge branch 'main' into develop 2025-12-22 20:04:31 +01:00
slawkens
8ec9bf1068 Fixed [player/guild/house] bb code in forum 2025-12-22 19:59:57 +01:00
slawkens
4fffaf6aff Merge branch 'main' into develop 2025-12-18 14:33:45 +01:00
slawkens
c44c9f9cf4 Add type hints and return types to cache classes 2025-12-18 14:33:07 +01:00
slawkens
ccfd6f1a87 Add PHP to cache engine list in settings 2025-12-18 14:23:25 +01:00
slawkens
96b8e00f49 Refactor PHP cache to store expiration and improve typing
Cache entries now store both the value and expiration timestamp in the file, allowing for more reliable expiration checks. Method signatures have been updated with type hints.
2025-12-18 14:22:42 +01:00
slawkens
11cb1cf97e Save db cache only if it has changed 2025-12-18 11:53:06 +01:00
slawkens
78a3535b6a Start v1.8.7-dev 2025-12-14 13:27:06 +01:00
slawkens
497959fd30 Update CHANGELOG-1.x.md 2025-12-14 13:18:08 +01:00
slawkens
6ba00eea96 Release v1.8.6 2025-12-14 12:38:25 +01:00
slawkens
c5d3d3a25f Merge branch 'main' into develop 2025-12-14 10:21:33 +01:00
slawkens
9ed06782e6 Ini set html_errors = 0, to show html code in exceptions 2025-12-14 10:21:23 +01:00
slawkens
18a1178e4b Fix exception show on first install, when there is no vendor
Before it displayed 500 white page, now it display the exception
2025-12-14 10:20:59 +01:00
slawkens
c86257e6da Highscores: Fix ordering by different skills
Adjust order by desc: skill_tries, manaspent, experience
2025-12-13 21:19:00 +01:00
slawkens
fd74f01291 Fix typo $up -> $down, migration was failing due that 2025-12-09 22:04:21 +01:00
slawkens
3011b969a4 Add php 8.5 to cypress workflow 2025-11-30 17:05:14 +01:00
slawkens
8e6749c599 Hook for adding custom rules to validate new character name 2025-11-24 18:04:09 +01:00
slawkens
e1197515f3 Merge branch 'main' into develop 2025-11-23 10:13:00 +01:00
slawkens
ae5df2b704 Start v1.8.6-dev 2025-11-21 18:08:30 +01:00
slawkens
9c327336d3 Release v1.8.5 2025-11-21 14:51:28 +01:00
slawkens
1d21f4d682 Update create.php 2025-11-18 12:24:22 +01:00
slawkens
603d860b56 Detect "deletion" column in guilds delete 2025-11-18 09:56:07 +01:00
slawkens
6775a061be Detect "deletion" column in guilds show 2025-11-18 00:16:26 +01:00
slawkens
eebfc600cb Detect "deletion" column in guilds show 2025-11-18 00:15:32 +01:00
slawkens
9a99018dce Merge branch 'main' into develop 2025-11-13 20:08:38 +01:00
slawkens
e440c0d6a6 Update .gitignore 2025-11-13 19:14:59 +01:00
slawkens
780d4ccef7 Server Status: Write to status-error.log if there is connection error 2025-11-06 22:06:05 +01:00
slawkens
0a6d44bf21 Fix $status['uptimeReadable'], was totally wrong 2025-11-06 13:47:09 +01:00
slawkens
4d17001a0b Add some popular network images (Facebook, Instagram, WhatsApp) 2025-11-06 12:48:33 +01:00
slawkens
946364f59d New Setting: Account Countries Most Popular 2025-11-06 12:01:33 +01:00
slawkens
5861efdbe9 Settings: escapeHtml in values (support for html code) 2025-11-06 11:48:42 +01:00
slawkens
175e97828b Don't display hidden news for admin - it's confusing 2025-11-05 22:21:42 +01:00
slawkens
9ce55db44c Display error message after failed settings save - just in case 2025-11-05 22:02:11 +01:00
slawkens
88532b0ebb Better message than "Access denied" 2025-11-05 19:32:31 +01:00
slawkens
1c7af30997 Revert "Just testing something, excuse me"
This reverts commit 7ca05e47ff.
2025-11-04 22:17:00 +01:00
slawkens
7ca05e47ff Just testing something, excuse me 2025-11-04 22:01:55 +01:00
slawkens
baec6c9ebf plugin:activate/deactivate alias 2025-11-04 08:17:41 +01:00
slawkens
6367054487 Add plugin:remove + plugin:delete as alias for plugin:uninstall 2025-11-03 21:06:27 +01:00
slawkens
ae7a47464f Update menus.php 2025-11-03 20:37:14 +01:00
slawkens
d201e75b11 Revert "Try to fix "VirtualProtect() failed [87] The parameter is incorrect" in php logs"
This reverts commit 4924696943.
2025-11-02 13:38:15 +01:00
slawkens
4924696943 Try to fix "VirtualProtect() failed [87] The parameter is incorrect" in php logs 2025-11-02 13:23:30 +01:00
slawkens
25a3db68e6 Use $db->hasTableAndColumns + move $skulls to correct place 2025-11-02 13:10:09 +01:00
slawkens
730a0f2912 Ensure some cache folders & index.html exists 2025-11-02 12:21:29 +01:00
slawkens
fd729242ff Fix typo -> satisfied 2025-11-02 12:05:47 +01:00
slawkens
6479546c22 Update CHANGELOG-2.x.md 2025-10-31 16:23:41 +01:00
slawkens
effb23f367 Create CHANGELOG-2.x.md 2025-10-31 15:32:49 +01:00
slawkens
08657c1599 Fix migration 47.php (convert IPs) 2025-10-31 15:25:55 +01:00
slawkens
1379c93439 Create 47.php 2025-10-31 07:00:11 +01:00
slawkens
19b1cfdd34 Merge branch 'main' into develop 2025-10-31 06:56:34 +01:00
slawkens
26c5aa2e51 Added more code into Items::getDescription
Is not ready yet
2025-10-31 06:52:56 +01:00
slawkens
bc4107bd16 Ignore only top-most Lua folder 2025-10-30 18:54:11 +01:00
slawkens
d24bde2c1d Start v1.8.5-dev 2025-10-27 21:45:34 +01:00
slawkens
a2f8759a52 Update CHANGELOG-1.x.md 2025-10-27 17:10:16 +01:00
slawkens
4b8c3ffae2 Code smell 2025-10-27 16:55:29 +01:00
slawkens
97321c9e80 Release v1.8.4 2025-10-27 16:43:34 +01:00
Slawomir Boczek
2580edadf8 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
2025-10-27 16:27:22 +01:00
slawkens
8f47b36dc8 Add return type 2025-10-27 15:03:24 +01:00
slawkens
6cd38ee1ec Fix php stan 2025-10-27 14:38:52 +01:00
slawkens
9d92a11fb7 Fix the premium checks, introduced in v1.8.3 2025-10-27 14:34:53 +01:00
slawkens
44110a9496 Show if there is mysql error on import schema
Weird fix, don't know why it didn't worked with query()
2025-10-25 21:32:49 +02:00
slawkens
727f68a575 migrate command: show "Already on latest version" 2025-10-24 21:14:49 +02:00
slawkens
07fd034fe4 Use low level env init on migrate command 2025-10-24 21:12:40 +02:00
slawkens
13ea68cc0c Use low level env init on migrate:run + migrate:to 2025-10-24 21:10:55 +02:00
slawkens
598cec2fe4 Release v1.8.3 2025-10-21 17:18:07 +02:00
slawkens
89fae38caa Ignore set last visit for AJAX pages - Fixes template change redirect 2025-10-21 12:18:56 +02:00
slawkens
16849e7578 account/change-password refactor a bit
Add "The old password is same as the new password!"
Better post variables names
2025-10-16 21:36:14 +02:00
slawkens
470555f268 New hooks for account/change-password
HOOK_ACCOUNT_CHANGE_PASSWORD_AFTER_OLD_PASSWORD + HOOK_ACCOUNT_CHANGE_PASSWORD_AFTER_NEW_PASSWORD
2025-10-16 21:22:49 +02:00
slawkens
7f60b3d31d Add same code in Models\Account + Optimize code 2025-10-15 15:59:49 +02:00
slawkens
12e40b2592 Update functions.php 2025-10-15 15:50:25 +02:00
slawkens
38902c30d1 Comment code to update lastday 2025-10-15 15:50:22 +02:00
slawkens
3e61692780 Fix premDays count in canary 2025-10-15 15:49:58 +02:00
André Morais
c88b08eb1e 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 <slawkens@gmail.com>
2025-10-15 11:46:52 +02:00
slawkens
82d417b590 Change spaces to tabs 2025-10-13 18:01:19 +02:00
slawkens
b797908e49 Update create.php 2025-10-13 17:53:26 +02:00
slawkens
90c8463797 Update create.php 2025-10-13 17:52:39 +02:00
slawkens
c91bb5d409 Fix guild create with freePremium 2025-10-12 21:53:01 +02:00
Slawomir Boczek
fe821c5808 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
2025-10-12 11:19:30 +02:00
slawkens
9acad15451 Allow links in error_box 2025-10-12 00:15:04 +02:00
slawkens
8c3cb0e06f New configurable: hooks_debug
To view where hooks are located in .twig files
2025-10-11 18:34:15 +02:00
slawkens
2eae44e075 Add missing compat config: email_lai_sec_interval 2025-10-08 14:39:23 +02:00
slawkens
8272f1373c Fix database column info cache 2025-10-03 16:24:02 +02:00
slawkens
901df48d13 Add promotion into getTopPlayers 2025-10-03 00:31:03 +02:00
slawkens
2da0024c68 Add lookmount into getTopPlayers 2025-10-03 00:25:41 +02:00
slawkens
0d8f68a48e Fix menus for ?subtopic= 2025-10-02 22:31:16 +02:00
slawkens
0cb9d3a208 Fix routes_final cache 2025-10-02 22:31:02 +02:00
slawkens
d8b73f55a3 Fix routes_final for prod env 2025-10-02 22:16:29 +02:00
slawkens
3bb272ebbb Allow for img in online_datacenter 2025-10-02 22:13:33 +02:00
slawkens
64acf70d38 Cache::remember -1 = infinite 2025-10-02 22:13:15 +02:00
slawkens
97f9d3d6f6 Add option to use ?subtopic=x for plugins pages 2025-10-02 15:06:57 +02:00
Slawomir Boczek
f54b1bdd2a First attempt (#331) 2025-09-28 19:00:51 +02:00
slawkens
c898fe25ef New function: getColumnInfo($table, $column) 2025-09-28 16:21:31 +02:00
slawkens
73c07d470d Add variable types, don't use $config 2025-09-28 16:10:58 +02:00
slawkens
56bd7ec5ed Prevent injection in $db->hasColumn 2025-09-28 16:09:14 +02:00
slawkens
4c6277c124 Start v1.8.3-dev 2025-09-28 14:16:28 +02:00
slawkens
228780f0ad Just leaving it here, for future use (twig hook display)
Maybe configurable in the future
2025-09-28 14:14:26 +02:00
slawkens
4e9999cc0d Do not use constant on twig hooks
So it can be displayed which hook is used
2025-09-28 14:13:51 +02:00
slawkens
8bc328d6fb Now v1.8.2 real 2025-09-26 10:14:48 +02:00
slawkens
ac41b82579 Update index.php 2025-09-26 10:14:38 +02:00
slawkens
df7b6e29fb Replace firstChild with firstElementChild (Thanks to @un000000) 2025-09-26 08:56:15 +02:00
slawkens
e0cc19ad86 Release v1.8.2 2025-09-26 07:54:40 +02:00
slawkens
85e7005fd3 Fix Menu div wrong tag/closing (#329) 2025-09-24 15:39:47 +02:00
slawkens
3c0cb53e17 Add missing csrf() - fix create account buton 2025-09-23 21:45:49 +02:00
slawkens
d0112d1a67 Fix exception when email cannot be send on create account 2025-09-23 21:45:32 +02:00
slawkens
ed9beaf2b6 Fix account lost routes in tibiacom template 2025-09-14 21:02:01 +02:00
slawkens
5aa9bbf1c8 Ignore child tables of myaac-table class 2025-09-14 20:50:00 +02:00
slawkens
a6032093b2 Better look for myaac-table 2025-09-14 19:35:12 +02:00
slawkens
4eab805d26 Fix when config.local.php cannot be saved 2025-09-09 17:49:05 +02:00
slawkens
3f24f961b1 Possibility to override routes with plugins pages, like characters.php
No need to define routes in plugin.json anymore
2025-09-09 15:17:06 +02:00
slawkens
0b86459940 Start v1.8.2-dev 2025-09-07 09:33:18 +02:00
slawkens
7a9b11434e Release v1.8.1 2025-09-05 13:25:25 +02:00
slawkens
9725a3c2bd Some servers don't have guild_invites table 2025-09-03 23:47:27 +02:00
slawkens
46adeefce3 Update settings.php 2025-08-27 15:30:52 +02:00
slawkens
e4b66f34ac Fix check for donate column 2025-08-27 12:15:52 +02:00
slawkens
2465bb6f9a Update settings.php 2025-08-27 11:40:54 +02:00
André Morais
42671c5c19 Update settings.php (#321)
* Update settings.php

added Transferable Coins to the store dropdown menu in the admin area

* Adjust code a bit

---------

Co-authored-by: slawkens <slawkens@gmail.com>
2025-08-27 11:26:46 +02:00
slawkens
fec773ba4b plugin:enable/disable commands 2025-08-25 11:35:56 +02:00
slawkens
1b9f68c9ec Update PluginUninstallCommand.php 2025-08-25 10:58:54 +02:00
slawkens
7a08f91d3f plugin:unistall command 2025-08-25 09:31:50 +02:00
slawkens
4b948e9510 Option to change/set plugin settings by plugin name 2025-08-22 18:20:37 +02:00
slawkens
17ca93d020 Same with default 2025-08-22 17:51:19 +02:00
slawkens
bcc4b48eb0 Settings: Option to set boolean values as "yes" 2025-08-22 17:39:14 +02:00
slawkens
f8c4332e03 Option to reset plugin settings by plugin name 2025-08-22 17:27:53 +02:00
slawkens
235e0f394d Refactor code to use Cache::remember 2025-08-22 16:04:52 +02:00
slawkens
3451715e96 Settings class: Add type hints 2025-08-22 15:30:19 +02:00
slawkens
d85681880e Rename file name to PluginSetupCommand 2025-08-21 21:12:55 +02:00
slawkens
4701461b1f Add some comment about optional sorting, into migrate:run command 2025-08-21 20:54:58 +02:00
slawkens
482f4067b2 Menus should be saved for each template separately
Trying to fix some weird bug
2025-08-17 18:45:49 +02:00
slawkens
2f26748112 ❤️ 2025-08-17 18:19:07 +02:00
slawkens
98073a110a Fix online skulls display (Fix #320) 2025-08-17 17:50:16 +02:00
slawkens
11dae90fa9 Fix MenuBotton display if some elements are removed
From menu_categories
2025-08-12 17:42:06 +02:00
slawkens
20f99903ae Fix submenu initialization for missing elements
Added a check in InitializeMenu to skip submenu items if their corresponding DOM element does not exist, preventing potential JavaScript errors.
2025-08-12 12:46:39 +02:00
slawkens
b6e1620f14 Fix #318 (online.php throws error in one scenario) 2025-08-07 21:17:25 +02:00
dependabot[bot]
9cb7792623 Bump tmp from 0.2.3 to 0.2.4 (#317)
Bumps [tmp](https://github.com/raszi/node-tmp) from 0.2.3 to 0.2.4.
- [Changelog](https://github.com/raszi/node-tmp/blob/master/CHANGELOG.md)
- [Commits](https://github.com/raszi/node-tmp/compare/v0.2.3...v0.2.4)

---
updated-dependencies:
- dependency-name: tmp
  dependency-version: 0.2.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-07 16:21:22 +02:00
dependabot[bot]
0db908be18 Bump form-data from 4.0.2 to 4.0.4 (#315)
Bumps [form-data](https://github.com/form-data/form-data) from 4.0.2 to 4.0.4.
- [Release notes](https://github.com/form-data/form-data/releases)
- [Changelog](https://github.com/form-data/form-data/blob/master/CHANGELOG.md)
- [Commits](https://github.com/form-data/form-data/compare/v4.0.2...v4.0.4)

---
updated-dependencies:
- dependency-name: form-data
  dependency-version: 4.0.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-02 14:15:13 +02:00
slawkens
785d38312b Start 1.8.1-dev 2025-08-02 12:41:35 +02:00
slawkens
e1c04ed28e Release v1.8 2025-08-02 12:28:13 +02:00
slawkens
c836308601 pages/online: add cache, resulting in 20x performance boost
(for an example server with 2k players)
2025-07-31 13:28:46 +02:00
slawkens
0efe47ce71 Twig: add cache variable 2025-07-31 13:15:06 +02:00
slawkens
3b47e9df2f Cache::remember: $ttl = 0 means no cache 2025-07-31 13:02:55 +02:00
slawkens
43415cf35d Add missing $fillable into PlayerOnline model 2025-07-31 12:32:18 +02:00
slawkens
cf7fd20452 Mailer: send only to verified accounts (option) 2025-07-31 09:19:49 +02:00
slawkens
080cc2781f Fix mailer: send to email link from accounts page 2025-07-31 07:31:15 +02:00
slawkens
20d69a641c Fix exception if setting not found 2025-07-24 23:30:28 +02:00
slawkens
2d4be327b2 Fix if highscores show outfit disabled 2025-07-24 23:07:49 +02:00
slawkens
bb097b69ce Update settings.php 2025-07-22 22:06:32 +02:00
slawkens
6e5a4ff8c7 Fix if setting found in db, but not found in plugins 2025-07-22 21:49:05 +02:00
slawkens
caf326a658 Refactor to use HAS_ACCOUNT_COINS
$db->hasColumn('accounts', 'coins') -> HAS_ACCOUNT_COINS
2025-07-22 21:44:09 +02:00
slawkens
bccf8e056d Rewrite to use constants (account transferable coins) 2025-07-22 21:33:45 +02:00
slawkens
7d27e5a0ba New setting: Default Account Transferable Coins 2025-07-22 21:32:51 +02:00
slawkens
9b6f410459 Update phpstan.neon 2025-07-22 19:11:42 +02:00
slawkens
c06b0017f1 Update phpstan.neon 2025-07-22 19:07:58 +02:00
slawkens
d8132d4d76 Highscores revamp a bit
* Show real rank, if 2 or more players have the same skill, show them with same rank
* New setting: highscores_online_status
* Additional fields passed to twig: updatedAt, totalResults, page, baseLink
2025-07-22 18:18:29 +02:00
slawkens
1566deb84a Add getExperienceForLevel (level) 2025-07-19 15:46:51 +02:00
slawkens
536b29be95 That is duplicated 2025-07-19 15:11:09 +02:00
slawkens
5271633bdb Account -> isPremium -> ignore config.freePremium 2025-07-19 15:00:17 +02:00
slawkens
ce5b1cf2a6 Update CacheClearCommand.php 2025-07-19 11:16:55 +02:00
slawkens
83f84172e0 Add warning about APCu clear in CLI
Adds a warning message if attempting to clear APCu cache from the CLI, as this is not supported. Users are advised to use the Admin Panel for clearing APCu cache outside of development environments.
2025-07-19 11:16:03 +02:00
slawkens
34fead906e Allow for timestamp as integer in the timeago twig function 2025-07-19 10:05:25 +02:00
slawkens
ec11c14024 kathrine: possibility to add custom menu categories 2025-07-19 07:48:01 +02:00
slawkens
2fe9924437 Start 1.7.2-dev 2025-07-08 19:20:45 +02:00
slawkens
f0f2e3785f Fix phpstan 2025-07-08 15:44:45 +02:00
slawkens
36ca755243 New setting: Display Skills Box on highscores
Better space management
2025-07-08 14:28:48 +02:00
slawkens
f17269e44c Move admin bar code into body_start place_holder 2025-07-08 14:22:51 +02:00
slawkens
dcb96f4ce1 Refactor code - early exit 2025-07-08 13:48:33 +02:00
slawkens
a89f9a8484 Set $process_sections to true 2025-07-08 09:22:12 +02:00
slawkens
45d6047031 Add Coins Transferable to accounts editor 2025-07-05 14:22:58 +02:00
slawkens
e719725841 Merge branch 'main' into develop 2025-05-09 13:45:54 +02:00
slawkens
bb3e90110d Merge branch 'main' into develop 2025-05-09 13:14:12 +02:00
slawkens
2f0758e351 Update schema.sql 2025-04-26 06:17:58 +02:00
slawkens
6667c8c364 Merge branch 'main' into develop 2025-04-26 06:17:38 +02:00
slawkens
c13a540878 Merge branch 'main' into develop 2025-04-18 13:58:42 +02:00
slawkens
869ec035d9 Merge branch 'main' into develop 2025-04-04 21:09:12 +02:00
slawkens
9d696d31d8 Merge branch 'main' into develop 2025-04-04 20:08:24 +02:00
slawkens
8cc4caf587 Merge branch 'main' into develop 2025-04-01 07:43:57 +02:00
slawkens
e1d1c7d5db Merge branch 'main' into develop 2025-03-31 22:21:16 +02:00
slawkens
320733c2c1 Merge branch 'main' into develop 2025-03-31 19:51:21 +02:00
slawkens
c1809a98d1 Merge branch 'main' into develop 2025-03-30 07:11:15 +02:00
slawkens
46ed541015 Merge branch 'main' into develop 2025-03-16 20:54:40 +01:00
slawkens
29207361b7 Merge branch 'main' into develop 2025-03-16 12:39:32 +01:00
slawkens
25013ae91b Merge branch 'main' into develop 2025-03-15 23:09:14 +01:00
slawkens
5d630ba9dd Fix the second "Save" button -> addition to previous commit 2025-03-15 22:49:43 +01:00
slawkens
feadf1314d Fix: add possibility to remove all menu items 2025-03-15 22:49:37 +01:00
slawkens
08b8a716d4 Fix the second "Save" button -> addition to previous commit 2025-03-10 13:04:57 +01:00
slawkens
cc26b5c744 Fix: add possibility to remove all menu items 2025-03-10 10:48:19 +01:00
Slawomir Boczek
cb6e9a6a88 Feature/twig hooks filters (#258)
* feat: Hooks filters

* Cleanup
2025-03-09 21:39:37 +01:00
slawkens
4adb0758c5 Set version to 2.0-dev 2025-03-09 21:26:24 +01:00
Slawomir Boczek
7312383f73 Account actions rework on ip (Use single column for IP - VARCHAR(45)) (#289)
* Account actions rework on ip (Use single column for IP - VARCHAR(45))

* No foreach needed here
2025-03-09 21:18:12 +01:00
slawkens
3c1210fefa Nothing important, just better code style 2025-03-03 20:07:54 +01:00
251 changed files with 6640 additions and 6340 deletions

View File

@@ -1,9 +1,9 @@
name: Cypress name: Cypress
on: on:
pull_request: pull_request:
branches: [main] branches: [develop]
push: push:
branches: [main] branches: [develop]
jobs: jobs:
cypress: cypress:
@@ -22,8 +22,8 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
php-versions: [ '8.1', '8.2', '8.3', '8.4' ] php-versions: [ '8.1', '8.2', '8.3', '8.4', '8.5' ]
ots: ['tfs-1.4', 'canary-3.1.2'] # TODO: add 'tfs-master' (actually doesn't work cause AAC doesn't support reading .env configuration) ots: ['tfs-1.4', 'canary-3.1.2', 'tfs-0.3'] # TODO: add 'tfs-master' (actually doesn't work cause AAC doesn't support reading .env configuration)
name: Cypress (PHP ${{ matrix.php-versions }}, ${{ matrix.ots }}) name: Cypress (PHP ${{ matrix.php-versions }}, ${{ matrix.ots }})
steps: steps:
- name: 📌 MySQL Start & init & show db - name: 📌 MySQL Start & init & show db
@@ -58,6 +58,14 @@ jobs:
ref: master ref: master
path: ots path: ots
- name: Checkout TFS 0.3
uses: actions/checkout@v4
if: matrix.ots == 'tfs-0.3'
with:
repository: otland/tfs-old-svn
ref: 0.3
path: ots
- name: Checkout Canary - name: Checkout Canary
uses: actions/checkout@v4 uses: actions/checkout@v4
if: matrix.ots == 'canary-3.1.2' if: matrix.ots == 'canary-3.1.2'
@@ -67,9 +75,15 @@ jobs:
path: ots path: ots
- name: Import OTS Schema - name: Import OTS Schema
if: matrix.ots != 'tfs-0.3'
run: | run: |
mysql -uroot -proot myaac < ots/schema.sql mysql -uroot -proot myaac < ots/schema.sql
- name: Import OTS Schema (TFS 0.3)
if: matrix.ots == 'tfs-0.3'
run: |
mysql -uroot -proot myaac < ots/schemas/mysql.sql
- name: Rename config.lua - name: Rename config.lua
run: mv ots/config.lua.dist ots/config.lua run: mv ots/config.lua.dist ots/config.lua
@@ -109,6 +123,33 @@ jobs:
regex: false regex: false
include: 'ots/config.lua' include: 'ots/config.lua'
- name: Replace mysqlPass (TFS 0.3.6pl1)
uses: jacobtomlinson/gha-find-replace@v3
if: matrix.ots == 'tfs-0.3'
with:
find: 'sqlType = "sqlite"'
replace: 'sqlType = "mysql"'
regex: false
include: 'ots/config.lua'
- name: Replace mysqlPass (TFS 0.3.6pl1)
uses: jacobtomlinson/gha-find-replace@v3
if: matrix.ots == 'tfs-0.3'
with:
find: 'sqlPass = ""'
replace: 'sqlPass = "root"'
regex: false
include: 'ots/config.lua'
- name: Replace mysqlDatabase (Canary)
uses: jacobtomlinson/gha-find-replace@v3
if: matrix.ots == 'tfs-0.3'
with:
find: 'sqlDatabase = "theforgottenserver"'
replace: 'sqlDatabase = "myaac"'
regex: false
include: 'ots/config.lua'
- name: Setup PHP - name: Setup PHP
uses: shivammathur/setup-php@v2 uses: shivammathur/setup-php@v2
with: with:

View File

@@ -1,9 +1,9 @@
name: PHP Linting name: PHP Linting
on: on:
pull_request: pull_request:
branches: [main] branches: [develop]
push: push:
branches: [main] branches: [develop]
jobs: jobs:
phplint: phplint:

View File

@@ -2,9 +2,9 @@ name: "PHPStan"
on: on:
pull_request: pull_request:
branches: [main] branches: [develop]
push: push:
branches: [main] branches: [develop]
jobs: jobs:
tests: tests:
@@ -14,7 +14,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
php-versions: [ '8.1', '8.2', '8.3', '8.4' ] php-versions: [ '8.1', '8.2', '8.3', '8.4', '8.5' ]
steps: steps:
- name: "Checkout" - name: "Checkout"
uses: "actions/checkout@v4" uses: "actions/checkout@v4"
@@ -25,7 +25,7 @@ jobs:
coverage: "none" coverage: "none"
extensions: "intl, zip" extensions: "intl, zip"
ini-values: "memory_limit=-1" ini-values: "memory_limit=-1"
php-version: "${{ matrix.php-version }}" php-version: "${{ matrix.php-versions }}"
- name: Get composer cache directory - name: Get composer cache directory
id: composer-cache id: composer-cache

3
.gitignore vendored
View File

@@ -4,7 +4,7 @@ Thumbs.db
# #
/.htaccess /.htaccess
lua /lua
# composer # composer
composer.phar composer.phar
@@ -24,6 +24,7 @@ releases
tmp tmp
config.local.php config.local.php
config2.local.php
# all custom templates # all custom templates
templates/* templates/*

View File

@@ -1,5 +1,178 @@
# 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]
### Added
* Change Comment: Add missing hooks - patched from 0.8 (https://github.com/slawkens/myaac/commit/a60a23b84f61d41d1503073b52e01e3120f6d92a)
### Changed
* Account Manage: Change the last login to the correct login time Instead of just "now" (https://github.com/slawkens/myaac/commit/5b841682cdc473b38ef1a5edfcfe1a020802e286)
* Twig: Extract renderInline(content, context) as a method to $twig (https://github.com/slawkens/myaac/commit/5e4806f891f8c88c37d45b89bbede23afc2fa37b)
* Mail: Remove HTML tags from the email function (https://github.com/slawkens/myaac/commit/6661c78dac69c6aa498b9c79fe7da4fe0150e5c8)
### Fixed
* Forum: Fix XSS in board name (https://github.com/slawkens/myaac/commit/e52d9e486f5bf1dea867f59287f70aef3d538189, https://github.com/slawkens/myaac/commit/6db738a87c44b8d96919191ba5e661c32ab47457)
* Forum: Fix edit_post, despite being an author, edit didn't work (https://github.com/slawkens/myaac/commit/e8b47429e8c607c2662a78b65415dfa772aa0e48)
* Forum: Fix a player link in the forum thread being not clickable (When outfits are enabled) (https://github.com/slawkens/myaac/commit/f640ca636f34cd2dfc1fa8de6fdbed0674908b30)
* Settings: Fix variable overlapping if the same var name as in core (https://github.com/slawkens/myaac/commit/c2415e9df3a5ffaf768f6f9668bdd38b5efd0771)
* Settings: fix show_if for the selects (https://github.com/slawkens/myaac/commit/8dcbb66753914322706216cfd01436eb1478a5ce)
## [1.8.7 - 04.01.2026]
### Fixed
* Fixed [player/guild/house] bb code in forum (https://github.com/slawkens/myaac/commit/8ec9bf10682c73f1fe40967a106ccda2a5073ed0)
### Changed
* Settings: better responsiveness on mobile (https://github.com/slawkens/myaac/commit/c65d4e4b62ef26fb4e24ecb1d2bcc4556d746adf)
* Signatures: Return 404 when the signature player is not found (https://github.com/slawkens/myaac/commit/7e6480b380799add7a2b1b7ce1d3c1f2b6819ff1)
### Removed
* Remove setting: outfit_images_wrong_looktypes - is obsolete, the bug doesn't exist in the latest outfit images (https://github.com/slawkens/myaac/commit/cc220bedc1f01535eaac23f6961135e2e7a6e310)
## [1.8.6 - 14.12.2025]
### Added
* Added hook for adding custom rules to validate new character name (https://github.com/slawkens/myaac/commit/8e6749c59984631288e8e9803819b2f0ff389761)
### Fixed
* Highscores: Fix ordering by different skills (Adjust order by desc: skill_tries, manaspent, experience) - More exact results (https://github.com/slawkens/myaac/commit/c86257e6dacbad773aa09c0958eeaa106a967f2d)
* Fix exception shown on first install, when there is no vendor - Before it displayed 500 white page, now it display the exception (https://github.com/slawkens/myaac/commit/18a1178e4b93607a350259679e0366cb83fb4126)
* Fix typo $up -> $down, in migration nr 7, was failing due that (https://github.com/slawkens/myaac/commit/fd74f01291d0e9cdb92ee1b95021c9d7b591ad7c)
### Changed
* Ini set html_errors = 0, to show html code in exceptions (https://github.com/slawkens/myaac/commit/9ed06782e67772826d927ad847a077b99df5060d)
## [1.8.5 - 21.11.2025]
### Added
* New Setting: Account Countries Most Popular (https://github.com/slawkens/myaac/commit/946364f59d7cd01472877108ab27ec78fb28307a)
### Changed
* Status: Write to status-error.log if there is connection error (https://github.com/slawkens/myaac/commit/780d4ccef741c1dd45a00bfc121fba9f1a175313)
* Settings: escapeHtml in values (support for html code) (https://github.com/slawkens/myaac/commit/5861efdbe900ccd35309913af0c0a5f3d4cdc1a8)
* News Page: Don't display hidden news for admin - it's confusing (https://github.com/slawkens/myaac/commit/175e97828b9a08ec3080cc8d3fb4eb3f1c08649f)
* Plugins System: Add plugin:remove + plugin:delete as alias for plugin:uninstall + plugin:activate/deactivate (https://github.com/slawkens/myaac/commit/6367054487368c92741bfd1dc7c70c52aea9ee87, https://github.com/slawkens/myaac/commit/baec6c9ebf5c342b3b2f7123427c6ba21dbb93bc)
### Fixed
* Status: Fix $status['uptimeReadable'], was totally wrong (https://github.com/slawkens/myaac/commit/0a6d44bf21417562491aabc93543a2bc3a44b2df)
* Guilds: Detect "deletion" column in guilds show/delete (https://github.com/slawkens/myaac/commit/6775a061bebc9ff449522f0173556d4a7a44fa5e, https://github.com/slawkens/myaac/commit/603d860b56bc7418db09e206f40aa06d0682c00e)
* General: Ensure some cache folders & index.html exists (https://github.com/slawkens/myaac/commit/730a0f29124811f525207c24c06eb0d088fa3434)
## [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, introduced in v1.8.3 (https://github.com/slawkens/myaac/commit/9d92a11fb7cb6d7a1619d79c12faaa0b1c01f980)
## [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
* Routes: Possibility to override routes with plugins pages, like characters.php - No need to define routes in plugin.json anymore (https://github.com/slawkens/myaac/commit/3f24f961b1cdeff5c60387e837ae454448bc5e1b)
### Changed
* Style: Better look for myaac-table (https://github.com/slawkens/myaac/commit/a6032093b21e5bb3f0e75d2704da87d6dea6469d, https://github.com/slawkens/myaac/commit/5aa9bbf1c8e580d973ec82ac012489f8e7bc437e)
### Fixed
* Install: Fix when config.local.php cannot be saved (https://github.com/slawkens/myaac/commit/4eab805d26d8c5562b29ed699769919d77dabced)
* Create Account: Fix an exception when email cannot be sent (https://github.com/slawkens/myaac/commit/d0112d1a67e8b854b65ad131f0375b79305df8d3)
* Login Page: Add missing csrf() - fix create account button (https://github.com/slawkens/myaac/commit/3c0cb53e17dd0b85394cfa0fdc9cf9ad8d4551df)
* tibiacom template: Fix account lost menu (https://github.com/slawkens/myaac/commit/ed9beaf2b6ca069e304e569c52e5b9188b58f05c)
* tibiacom template: Fix Menu div wrong tag/closing (#329) (https://github.com/slawkens/myaac/commit/85e7005fd3f0be51466151a3c122b96085fdfe68)
* tibiacom template: Replace firstChild with firstElementChild (Thanks to @un000000) (https://github.com/slawkens/myaac/commit/df7b6e29fb8875da97f431468c81ee99116271d9)
## [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]
### Added
* Templates - Kathrine: Possibility to add custom menu categories (https://github.com/slawkens/myaac/commit/ec11c1402417c25980582467546d1c1e9bb8267f)
* Admin Panel - Accounts Editor: Add Coins Transferable (https://github.com/slawkens/myaac/commit/45d6047031c9c3a0e7e512dc5d15c75629aec5a2, https://github.com/slawkens/myaac/commit/bb097b69ce106500a49686d6f4fe604348eaa310)
* Highscores:
* Revamped: (https://github.com/slawkens/myaac/commit/d8132d4d76e03d5aa0c042be426320655a601392)
* Show real rank, if 2 or more players have the same skill, show them with same rank
* New setting: highscores_online_status
* Additional fields passed to twig: updatedAt, totalResults, page, baseLink
* Add new Setting: Display Skills Box (https://github.com/slawkens/myaac/commit/36ca755243ef1c83f6ac87465b426d4d8d3b0bb9)
* Functions: Add getExperienceForLevel (level) (https://github.com/slawkens/myaac/commit/1566deb84a082176b8c683fda205d828bc38fbcc)
* Commands - cache:clear : Add warning about APCu clear in CLI (https://github.com/slawkens/myaac/commit/83f84172e02e8ea2ccb6dca29bc033e44c35aebc)
* Models - PlayerOnline: Add missing $fillable into model (https://github.com/slawkens/myaac/commit/43415cf35db1c1307f2684c1728693d65065ffff)
* Twig: add cache variable (https://github.com/slawkens/myaac/commit/0efe47ce71c4b364a9e96bc5a55b1655326ae6da)
### Changed
* pages/online: add cache, resulting in 20x performance boost
* (for an example server with 2k players) (https://github.com/slawkens/myaac/commit/c8363086015cbb6e8786c398c7b9ac3959a26ec4)
* Admin Bar: Move admin bar code into body_start place_holder (https://github.com/slawkens/myaac/commit/f17269e44ce9dd38447bd2e2a8e1bdb065d4161f)
* Cache::remember: $ttl = 0 means no cache (https://github.com/slawkens/myaac/commit/3b47e9df2f4051807c5ff87892f7fa3d348f9c55)
* Templates: Load config.ini with $process_sections set to true (https://github.com/slawkens/myaac/commit/a89f9a84847630eb75b4890fdcc8b7a7bfa6b8ac)
* Twig: Allow for timestamp as integer in the timeago twig function
(https://github.com/slawkens/myaac/commit/34fead906ea13b9f09d7a3c41ed88109d34d386c)
### Fixed
* Settings: Fixed two exceptions (https://github.com/slawkens/myaac/commit/6e5a4ff8c78ff5373aba091baa66cae029557643, https://github.com/slawkens/myaac/commit/20d69a641c0a933d14889a89da6d32f6a4bc6c7d)
* Models\Account + OTS_Account -> isPremium -> ignore config.freePremium (https://github.com/slawkens/myaac/commit/5271633bdbfbbfed0b1d59c403093ce6fc2b7d20)
* Admin Panel - Mailer:
* Fix send to email link redirecting from accounts page (https://github.com/slawkens/myaac/commit/080cc2781f034c844af658229e495e9a47fd2298)
* Option to send only to verified accounts - only if setting('core.account_mail_verify') enabled (https://github.com/slawkens/myaac/commit/cf7fd20452e863980045bb5d6012ec86c6e8e01f)
### Internal
* Rewrite to use constants (account transferable coins) (https://github.com/slawkens/myaac/commit/bccf8e056df985bbe1bab5f7ab5492f714d6b62b)
* Refactor to use HAS_ACCOUNT_COINS (https://github.com/slawkens/myaac/commit/caf326a6584a234775ebc6c8000ea02b3fecd160)
## [1.7.1 - 27.06.2025] ## [1.7.1 - 27.06.2025]
### Changed ### Changed

25
CHANGELOG-2.x.md Normal file
View File

@@ -0,0 +1,25 @@
## [2.0-dev - x.x.2025]
### Added
* Menus: Add an "access" option to Menus (#340)
* Possibility to hide menus for unauthorized users
* Settings: Add Reset button (https://github.com/slawkens/myaac/commit/7104c2258fd724a55239821b46a616dab845b22a, https://github.com/slawkens/myaac/commit/e274b8350451a20c24e652ea05ed1964ebb86b54)
* New Setting: block create account spam by ip (https://github.com/slawkens/myaac/commit/54265f42e987522803288477952d6e5c4daeeb24)
* Functions: Add the possibility to fetch skills, balance and frags in the getTopPlayers function (#347)
* Plugins: autoload init-priority option (https://github.com/slawkens/myaac/commit/f1aa12840875960849fa0c99a2bbe0ad2949bbec)
### Changed
* Better handling of vocations: (#345)
* Load from vocations.xml (No need to manually set)
* Support for Monk vocation
* Better gallery, loads images from images/gallery folder
* Reworked account action logs to use a single IP column as varchar(45) for both ipv4 and ipv6 (#289)
* Make myaac_config table columns bigger (https://github.com/slawkens/myaac/commit/2c62a97160a3ffe9976ee5bd1d770a0abc576742)
* Admin Panel: save menu collapse state (https://github.com/slawkens/myaac/commit/55da00520df7463a1d1ca41931df1598e9f2ffeb)
### Internal
* Refactor account/lost pages (#326)
* Refactor OTS_Player to support more distros (#348)
* Refactor PHP cache to store expiration and improve typing (https://github.com/slawkens/myaac/commit/96b8e00f4999f8b4c4c97b54b97d91c6fd7df298)
* Move forum show_board code to Twig (https://github.com/slawkens/myaac/commit/e0e0e467012a5fb9979cc4387af6bad1d4540279)
* Save db cache only if it has changed (https://github.com/slawkens/myaac/commit/11cb1cf97e74f3bccf59360e1efb800a426b3d43)

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 |
@@ -86,12 +86,6 @@ Look: [Contributing](https://docs.my-aac.org/misc/contributing) in our wiki.
If you have a great idea or want to contribute to the project - visit our website at https://www.my-aac.org If you have a great idea or want to contribute to the project - visit our website at https://www.my-aac.org
## Project supported by JetBrains
Many thanks to Jetbrains for kindly providing a license for me to work on this and other open-source projects.
[![JetBrains](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](https://www.jetbrains.com/?from=https://github.com/slawkens)
### License ### License
This program and all associated files are released under the GNU Public License. This program and all associated files are released under the GNU Public License.

4
aac
View File

@@ -25,7 +25,9 @@ foreach ($commandsGlob as $item) {
} }
$commandPre = '\\MyAAC\Commands\\'; $commandPre = '\\MyAAC\Commands\\';
$application->add(new ($commandPre . $name)); if (!trait_exists($class = $commandPre . $name)) {
$application->add(new $class);
}
} }
$pluginCommands = Plugins::getCommands(); $pluginCommands = Plugins::getCommands();

View File

@@ -9,6 +9,7 @@
*/ */
use MyAAC\Models\Account as AccountModel; use MyAAC\Models\Account as AccountModel;
use MyAAC\Models\AccountAction;
use MyAAC\Models\Player; use MyAAC\Models\Player;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
@@ -26,7 +27,6 @@ if (setting('core.account_country'))
$nameOrNumberColumn = getAccountIdentityColumn(); $nameOrNumberColumn = getAccountIdentityColumn();
$hasSecretColumn = $db->hasColumn('accounts', 'secret'); $hasSecretColumn = $db->hasColumn('accounts', 'secret');
$hasCoinsColumn = $db->hasColumn('accounts', 'coins');
$hasPointsColumn = $db->hasColumn('accounts', 'premium_points'); $hasPointsColumn = $db->hasColumn('accounts', 'premium_points');
$hasTypeColumn = $db->hasColumn('accounts', 'type'); $hasTypeColumn = $db->hasColumn('accounts', 'type');
$hasGroupColumn = $db->hasColumn('accounts', 'group_id'); $hasGroupColumn = $db->hasColumn('accounts', 'group_id');
@@ -136,11 +136,18 @@ else if (isset($_REQUEST['search'])) {
if (!Validator::email($email)) if (!Validator::email($email))
$errors['email'] = Validator::getLastError(); $errors['email'] = Validator::getLastError();
//tibia coins // tibia coins
if ($hasCoinsColumn) { if (HAS_ACCOUNT_COINS) {
$t_coins = $_POST['t_coins']; $t_coins = $_POST['t_coins'];
verify_number($t_coins, 'Tibia coins', 12); verify_number($t_coins, 'Tibia coins', 12);
} }
// transferable tibia coins
if (HAS_ACCOUNT_COINS_TRANSFERABLE || HAS_ACCOUNT_TRANSFERABLE_COINS) {
$t_coins_transferable = $_POST['t_coins_transferable'];
verify_number($t_coins_transferable, 'Transferable Tibia coins', 12);
}
// prem days // prem days
$p_days = (int)$_POST['p_days']; $p_days = (int)$_POST['p_days'];
verify_number($p_days, 'Prem days', 11); verify_number($p_days, 'Prem days', 11);
@@ -176,33 +183,7 @@ else if (isset($_REQUEST['search'])) {
$account->setName($name); $account->setName($name);
} }
if ($hasTypeColumn) {
$account->setCustomField('type', $group);
} elseif ($hasGroupColumn) {
$account->setCustomField('group_id', $group);
}
if ($hasSecretColumn) {
$account->setCustomField('secret', $secret);
}
$account->setCustomField('key', $key);
$account->setEMail($email); $account->setEMail($email);
if ($hasCoinsColumn) {
$account->setCustomField('coins', $t_coins);
}
$lastDay = 0;
if($p_days != 0 && $p_days != OTS_Account::GRATIS_PREMIUM_DAYS) {
$lastDay = time();
} else if ($lastDay != 0) {
$lastDay = 0;
}
$account->setPremDays($p_days);
$account->setLastLogin($lastDay);
if ($hasPointsColumn) {
$account->setCustomField('premium_points', $p_points);
}
$account->setRLName($rl_name); $account->setRLName($rl_name);
$account->setLocation($rl_loca); $account->setLocation($rl_loca);
@@ -210,9 +191,18 @@ else if (isset($_REQUEST['search'])) {
$account->setCountry($rl_country); $account->setCountry($rl_country);
} }
$account->setCustomField('created', $created);
$account->setWebFlags($web_flags); $account->setWebFlags($web_flags);
$account->setCustomField('web_lastlogin', $web_lastlogin);
if (!isCanary()) {
$lastDay = 0;
if($p_days != 0 && $p_days != OTS_Account::GRATIS_PREMIUM_DAYS) {
$lastDay = time();
}
$account->setLastLogin($lastDay);
}
$account->setPremDays($p_days);
if (isset($password)) { if (isset($password)) {
if (USE_ACCOUNT_SALT) { if (USE_ACCOUNT_SALT) {
@@ -223,12 +213,37 @@ else if (isset($_REQUEST['search'])) {
$password = encrypt($password); $password = encrypt($password);
$account->setPassword($password); $account->setPassword($password);
if (USE_ACCOUNT_SALT)
$account->setCustomField('salt', $salt);
} }
$account->save(); $account->save();
if ($hasTypeColumn) {
$account->setCustomField('type', $group);
} elseif ($hasGroupColumn) {
$account->setCustomField('group_id', $group);
}
if ($hasSecretColumn) {
$account->setCustomField('secret', $secret);
}
$account->setCustomField('key', $key);
if (HAS_ACCOUNT_COINS) {
$account->setCustomField('coins', $t_coins);
}
if (HAS_ACCOUNT_COINS_TRANSFERABLE || HAS_ACCOUNT_TRANSFERABLE_COINS) {
$account->setCustomField(ACCOUNT_COINS_TRANSFERABLE_COLUMN, $t_coins_transferable);
}
if ($hasPointsColumn) {
$account->setCustomField('premium_points', $p_points);
}
$account->setCustomField('created', $created);
$account->setCustomField('web_lastlogin', $web_lastlogin);
echo_success('Account saved at: ' . date('G:i')); echo_success('Account saved at: ' . date('G:i'));
} }
} }
@@ -395,12 +410,18 @@ else if (isset($_REQUEST['search'])) {
<label for="email">Email:</label><?php echo (setting('core.mail_enabled') ? ' (<a href="' . ADMIN_URL . '?p=mailer&mail_to=' . $account->getEMail() . '">Send Mail</a>)' : ''); ?> <label for="email">Email:</label><?php echo (setting('core.mail_enabled') ? ' (<a href="' . ADMIN_URL . '?p=mailer&mail_to=' . $account->getEMail() . '">Send Mail</a>)' : ''); ?>
<input type="text" class="form-control" id="email" name="email" autocomplete="off" value="<?php echo $account->getEMail(); ?>"/> <input type="text" class="form-control" id="email" name="email" autocomplete="off" value="<?php echo $account->getEMail(); ?>"/>
</div> </div>
<?php if ($hasCoinsColumn): ?> <?php if (HAS_ACCOUNT_COINS): ?>
<div class="col-12 col-sm-12 col-lg-6"> <div class="col-12 col-sm-12 col-lg-6">
<label for="t_coins">Tibia Coins:</label> <label for="t_coins">Tibia Coins:</label>
<input type="text" class="form-control" id="t_coins" name="t_coins" autocomplete="off" maxlength="11" value="<?php echo $account->getCustomField('coins') ?>"/> <input type="text" class="form-control" id="t_coins" name="t_coins" autocomplete="off" maxlength="11" value="<?php echo $account->getCustomField('coins') ?>"/>
</div> </div>
<?php endif; ?> <?php endif; ?>
<?php if (HAS_ACCOUNT_COINS_TRANSFERABLE || HAS_ACCOUNT_TRANSFERABLE_COINS): ?>
<div class="col-12 col-sm-12 col-lg-6">
<label for="t_coins_transferable">Transferable Tibia Coins:</label>
<input type="text" class="form-control" id="t_coins_transferable" name="t_coins_transferable" autocomplete="off" maxlength="11" value="<?php echo $account->getCustomField(ACCOUNT_COINS_TRANSFERABLE_COLUMN) ?>"/>
</div>
<?php endif; ?>
<div class="col-12 col-sm-12 col-lg-6"> <div class="col-12 col-sm-12 col-lg-6">
<label for="p_days">Premium Days:</label> <label for="p_days">Premium Days:</label>
<input type="text" class="form-control" id="p_days" name="p_days" autocomplete="off" maxlength="11" value="<?php echo $account->getPremDays(); ?>"/> <input type="text" class="form-control" id="p_days" name="p_days" autocomplete="off" maxlength="11" value="<?php echo $account->getPremDays(); ?>"/>
@@ -466,9 +487,8 @@ else if (isset($_REQUEST['search'])) {
</thead> </thead>
<tbody> <tbody>
<?php <?php
$accountActions = \MyAAC\Models\AccountAction::where('account_id', $account->getId())->orderByDesc('date')->get(); $accountActions = AccountAction::where('account_id', $account->getId())->orderByDesc('date')->get();
foreach ($accountActions as $i => $log): foreach ($accountActions as $i => $log):
$log->ip = ($log->ip != 0 ? long2ip($log->ip) : inet_ntop($log->ipv6));
?> ?>
<tr> <tr>
<td><?php echo $i + 1; ?></td> <td><?php echo $i + 1; ?></td>
@@ -616,6 +636,7 @@ else if (isset($_REQUEST['search'])) {
</div> </div>
</form> </form>
</div> </div>
<?php if (USE_ACCOUNT_NAME): ?>
<div class="col-6 col-lg-12"> <div class="col-6 col-lg-12">
<form action="<?php echo $admin_base; ?>" method="post"> <form action="<?php echo $admin_base; ?>" method="post">
<?php csrf(); ?> <?php csrf(); ?>
@@ -626,6 +647,7 @@ else if (isset($_REQUEST['search'])) {
</div> </div>
</form> </form>
</div> </div>
<?php endif; ?>
<div class="col-6 col-lg-12"> <div class="col-6 col-lg-12">
<form action="<?php echo $admin_base; ?>" method="post"> <form action="<?php echo $admin_base; ?>" method="post">
<?php csrf(); ?> <?php csrf(); ?>

View File

@@ -25,9 +25,10 @@ if (!setting('core.mail_enabled')) {
return; return;
} }
$mail_to = isset($_POST['mail_to']) ? stripslashes(trim($_POST['mail_to'])) : null; $mail_to = isset($_REQUEST['mail_to']) ? stripslashes(trim($_REQUEST['mail_to'])) : null;
$mail_subject = isset($_POST['mail_subject']) ? stripslashes($_POST['mail_subject']) : null; $mail_subject = isset($_POST['mail_subject']) ? stripslashes($_POST['mail_subject']) : null;
$mail_content = isset($_POST['mail_content']) ? stripslashes($_POST['mail_content']) : null; $mail_content = isset($_POST['mail_content']) ? stripslashes($_POST['mail_content']) : null;
$mail_verified_only = $_POST['mail_verified_only'] ?? false;
if (isset($_POST['submit'])) { if (isset($_POST['submit'])) {
if (empty($mail_subject)) { if (empty($mail_subject)) {
@@ -58,14 +59,14 @@ if (!empty($mail_content) && !empty($mail_subject) && empty($mail_to)) {
$success = 0; $success = 0;
$failed = 0; $failed = 0;
$add = ''; $query = Account::where('email', '!=', '');
if (setting('core.account_mail_verify')) {
note('Note: Sending only to users with verified E-Mail.'); if ($mail_verified_only) {
$add = ' AND `email_verified` = 1'; info('Note: Sending only to users with verified E-Mail.');
$query->where('email_verified', 1);
} }
$query = Account::where('email', '!=', '')->get(['email']); foreach ($query->get(['email']) as $email) {
foreach ($query as $email) {
if (_mail($email->email, $mail_subject, $mail_content)) { if (_mail($email->email, $mail_subject, $mail_content)) {
$success++; $success++;
} }
@@ -84,5 +85,6 @@ if (!empty($mail_content) && !empty($mail_subject) && empty($mail_to)) {
$twig->display('admin.mailer.html.twig', [ $twig->display('admin.mailer.html.twig', [
'mail_to' => $mail_to, 'mail_to' => $mail_to,
'mail_subject' => $mail_subject, 'mail_subject' => $mail_subject,
'mail_content' => $mail_content 'mail_content' => $mail_content,
'mail_verified_only' => $mail_verified_only,
]); ]);

View File

@@ -6,6 +6,7 @@
* @package MyAAC * @package MyAAC
* @author Slawkens <slawkens@gmail.com> * @author Slawkens <slawkens@gmail.com>
* @author Lee * @author Lee
* @author gpedro
* @copyright 2020 MyAAC * @copyright 2020 MyAAC
* @link https://my-aac.org * @link https://my-aac.org
*/ */
@@ -18,11 +19,10 @@ $title = 'Mass Account Actions';
csrfProtect(); csrfProtect();
$hasCoinsColumn = $db->hasColumn('accounts', 'coins');
$hasPointsColumn = $db->hasColumn('accounts', 'premium_points'); $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; global $hasPointsColumn;
@@ -38,11 +38,9 @@ function admin_give_points($points)
displayMessage($points . ' points added to all accounts.', true); displayMessage($points . ' points added to all accounts.', true);
} }
function admin_give_coins($coins) function admin_give_coins($coins): void
{ {
global $hasCoinsColumn; if (!HAS_ACCOUNT_COINS) {
if (!$hasCoinsColumn) {
displayMessage('Coins not supported.'); displayMessage('Coins not supported.');
return; return;
} }
@@ -55,7 +53,7 @@ function admin_give_coins($coins)
displayMessage($coins . ' coins added to all accounts.', true); displayMessage($coins . ' coins added to all accounts.', true);
} }
function admin_give_premdays($days) function admin_give_premdays($days): void
{ {
global $db, $freePremium; global $db, $freePremium;
@@ -66,6 +64,7 @@ function admin_give_premdays($days)
$value = $days * 86400; $value = $days * 86400;
$now = time(); $now = time();
// othire // othire
if ($db->hasColumn('accounts', 'premend')) { if ($db->hasColumn('accounts', 'premend')) {
// append premend // append premend
@@ -73,14 +72,11 @@ function admin_give_premdays($days)
// set premend // set premend
if (Account::where('premend', '<=', $now)->update(['premend' => $now + $value])) { if (Account::where('premend', '<=', $now)->update(['premend' => $now + $value])) {
displayMessage($days . ' premium days added to all accounts.', true); displayMessage($days . ' premium days added to all accounts.', true);
return;
} else { } else {
displayMessage('Failed to execute set query.'); displayMessage('Failed to execute set query.');
return;
} }
} else { } else {
displayMessage('Failed to execute append query.'); displayMessage('Failed to execute append query.');
return;
} }
return; return;
@@ -95,20 +91,14 @@ function admin_give_premdays($days)
// set lastday // set lastday
if (Account::where('lastday', '<=', $now)->update(['lastday' => $now + $value])) { if (Account::where('lastday', '<=', $now)->update(['lastday' => $now + $value])) {
displayMessage($days . ' premium days added to all accounts.', true); displayMessage($days . ' premium days added to all accounts.', true);
return;
} else { } else {
displayMessage('Failed to execute set query.'); displayMessage('Failed to execute set query.');
return;
} }
return;
} else { } else {
displayMessage('Failed to execute append query.'); displayMessage('Failed to execute append query.');
return;
} }
} else { } else {
displayMessage('Failed to execute set days query.'); displayMessage('Failed to execute set days query.');
return;
} }
return; return;
@@ -121,14 +111,11 @@ function admin_give_premdays($days)
// set premium_ends_at // set premium_ends_at
if (Account::where('premium_ends_at', '<=', $now)->update(['premium_ends_at' => $now + $value])) { if (Account::where('premium_ends_at', '<=', $now)->update(['premium_ends_at' => $now + $value])) {
displayMessage($days . ' premium days added to all accounts.', true); displayMessage($days . ' premium days added to all accounts.', true);
return;
} else { } else {
displayMessage('Failed to execute set query.'); displayMessage('Failed to execute set query.');
return;
} }
} else { } else {
displayMessage('Failed to execute append query.'); displayMessage('Failed to execute append query.');
return;
} }
return; return;
@@ -167,19 +154,20 @@ if (!empty(ACTION) && isRequestMethod('post')) {
} }
else { else {
$twig->display('admin.tools.account.html.twig', array( $twig->display('admin.tools.account.html.twig', array(
'hasCoinsColumn' => $hasCoinsColumn, 'hasCoinsColumn' => HAS_ACCOUNT_COINS,
'hasPointsColumn' => $hasPointsColumn, 'hasPointsColumn' => $hasPointsColumn,
'freePremium' => $freePremium, 'freePremium' => $freePremium,
)); ));
} }
function displayMessage($message, $success = false) { function displayMessage($message, $success = false): void
global $twig, $hasCoinsColumn, $hasPointsColumn, $freePremium; {
global $twig, $hasPointsColumn, $freePremium;
$success ? success($message): error($message); $success ? success($message): error($message);
$twig->display('admin.tools.account.html.twig', array( $twig->display('admin.tools.account.html.twig', array(
'hasCoinsColumn' => $hasCoinsColumn, 'hasCoinsColumn' => HAS_ACCOUNT_COINS,
'hasPointsColumn' => $hasPointsColumn, 'hasPointsColumn' => $hasPointsColumn,
'freePremium' => $freePremium, 'freePremium' => $freePremium,
)); ));

View File

@@ -23,6 +23,7 @@ if (!hasFlag(FLAG_CONTENT_MENUS) && !superAdmin()) {
} }
$pluginThemes = Plugins::getThemes(); $pluginThemes = Plugins::getThemes();
$groups = new OTS_Groups_List();
if (isset($_POST['template'])) { if (isset($_POST['template'])) {
$template = $_POST['template']; $template = $_POST['template'];
@@ -32,6 +33,8 @@ if (isset($_POST['template'])) {
$post_menu_link = $_POST['menu_link'] ?? []; $post_menu_link = $_POST['menu_link'] ?? [];
$post_menu_blank = $_POST['menu_blank'] ?? []; $post_menu_blank = $_POST['menu_blank'] ?? [];
$post_menu_color = $_POST['menu_color'] ?? []; $post_menu_color = $_POST['menu_color'] ?? [];
$post_menu_access = $_POST['menu_access'] ?? [];
if (count($post_menu) != count($post_menu_link)) { if (count($post_menu) != count($post_menu_link)) {
echo 'Menu count is not equal menu links. Something went wrong when sending form.'; echo 'Menu count is not equal menu links. Something went wrong when sending form.';
return; return;
@@ -50,6 +53,7 @@ if (isset($_POST['template'])) {
'link' => $post_menu_link[$category][$i], 'link' => $post_menu_link[$category][$i],
'blank' => $post_menu_blank[$category][$i] == 'on' ? 1 : 0, 'blank' => $post_menu_blank[$category][$i] == 'on' ? 1 : 0,
'color' => str_replace('#', '', $post_menu_color[$category][$i]), 'color' => str_replace('#', '', $post_menu_color[$category][$i]),
'access' => $post_menu_access[$category][$i],
'category' => $category, 'category' => $category,
'ordering' => $i 'ordering' => $i
]); ]);
@@ -122,7 +126,7 @@ if (isset($_POST['template'])) {
?> ?>
<?php <?php
$menus = Menu::query() $menus = Menu::query()
->select('name', 'link', 'blank', 'color', 'category', 'ordering') ->select('name', 'link', 'access', 'blank', 'color', 'category', 'ordering')
->where('enabled', 1) ->where('enabled', 1)
->where('template', $template) ->where('template', $template)
->orderBy('ordering') ->orderBy('ordering')
@@ -151,11 +155,34 @@ if (isset($_POST['template'])) {
foreach ($menus[$id] as $menu): foreach ($menus[$id] as $menu):
$color = (empty($menu['color']) ? ($cat['default_links_color'] ?? ($config['menu_default_links_color'] ?? ($config['menu_default_color'] ?? '#ffffff'))) : '#' . $menu['color']); $color = (empty($menu['color']) ? ($cat['default_links_color'] ?? ($config['menu_default_links_color'] ?? ($config['menu_default_color'] ?? '#ffffff'))) : '#' . $menu['color']);
?> ?>
<li class="ui-state-default" id="list-<?php echo $id ?>-<?php echo $i ?>"><label>Name:</label> <input type="text" name="menu[<?php echo $id ?>][]" value="<?php echo escapeHtml($menu['name']); ?>"/> <li class="ui-state-default" id="list-<?php echo $id ?>-<?php echo $i ?>">
<label>Link:</label> <input type="text" name="menu_link[<?php echo $id ?>][]" value="<?php echo $menu['link'] ?>"/> <label class="label_menu_name">Name: <input type="text" name="menu[<?php echo $id ?>][]" class="form-control menu-name" value="<?php echo escapeHtml($menu['name']); ?>"/>
<input type="hidden" name="menu_blank[<?php echo $id ?>][]" value="0"/> </label>
<label><input class="blank-checkbox" type="checkbox" <?php echo($menu['blank'] == 1 ? 'checked' : '') ?>/><span title="Open in New Window">New Window</span></label>
<input class="color-picker" type="text" name="menu_color[<?php echo $id ?>][]" value="<?php echo $color; ?>"/> <label class="label_menu_link">Link: <input type="text" name="menu_link[<?= $id ?>][]" class="form-control menu-link" value="<?php echo $menu['link'] ?>"/>
</label>
<br/>
<div class="menu-options-row">
<label>Access:
<select name="menu_access[<?= $id ?>][]" class="form-control menu-access">
<option value="0" <?= ($menu['access'] == 0 ? 'selected' : ''); ?>>Guest*</option>
<?php foreach ($groups->getGroups() as $group): ?>
<option value="<?= $group->getId(); ?>" <?= ($menu['access'] == $group->getId() ? 'selected' : ''); ?>><?= ucfirst($group->getName()); ?></option>
<?php endforeach; ?>
</select>
</label>
<label>Color: <input class="menu-color" type="color" name="menu_color[<?php echo $id ?>][]" value="<?php echo $color; ?>"/>
</label>
<input type="hidden" name="menu_blank[<?php echo $id ?>][]" class="menu-blank" value="0"/>
<label><input type="checkbox" class="menu-blank-checkbox" <?php echo($menu['blank'] == 1 ? 'checked' : '') ?>/><span title="Open in New Window">New Window</span></label>
</div>
<a class="remove-button" id="remove-button-<?php echo $id ?>-<?php echo $i ?>"><i class="fas fa-trash"></a></i></li> <a class="remove-button" id="remove-button-<?php echo $id ?>-<?php echo $i ?>"><i class="fas fa-trash"></a></i></li>
<?php $i++; $last_id[$id] = $i; <?php $i++; $last_id[$id] = $i;
endforeach; endforeach;

View File

@@ -6,7 +6,7 @@ defined('MYAAC') or die('Direct access not allowed!');
$coins = 0; $coins = 0;
if ($db->hasColumn('accounts', 'coins')) { if (HAS_ACCOUNT_COINS) {
$whatToGet = ['id', 'coins']; $whatToGet = ['id', 'coins'];
if (USE_ACCOUNT_NAME) { if (USE_ACCOUNT_NAME) {
$whatToGet[] = 'name'; $whatToGet[] = 'name';

View File

@@ -10,6 +10,8 @@
use MyAAC\Forum; use MyAAC\Forum;
use MyAAC\Models\Player; use MyAAC\Models\Player;
use MyAAC\Server\Outfits;
use MyAAC\Server\XML\Vocations;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
@@ -34,6 +36,7 @@ $skills = array(
$hasBlessingsColumn = $db->hasColumn('players', 'blessings'); $hasBlessingsColumn = $db->hasColumn('players', 'blessings');
$hasBlessingColumn = $db->hasColumn('players', 'blessings1'); $hasBlessingColumn = $db->hasColumn('players', 'blessings1');
$hasLookAddons = $db->hasColumn('players', 'lookaddons'); $hasLookAddons = $db->hasColumn('players', 'lookaddons');
$hasCapColumn = $db->hasColumn('players', 'cap');
$skull_type = array("None", "Yellow", "Green", "White", "Red", "Black", "Orange"); $skull_type = array("None", "Yellow", "Green", "White", "Red", "Black", "Orange");
?> ?>
@@ -166,8 +169,11 @@ else if (isset($_REQUEST['search'])) {
$town = $_POST['town']; $town = $_POST['town'];
verify_number($town, 'Town', 11); verify_number($town, 'Town', 11);
if ($hasCapColumn) {
$capacity = $_POST['capacity']; $capacity = $_POST['capacity'];
verify_number($capacity, 'Capacity', 11); verify_number($capacity, 'Capacity', 11);
}
$sex = $_POST['sex']; $sex = $_POST['sex'];
verify_number($sex, 'Sex', 1); verify_number($sex, 'Sex', 1);
@@ -237,7 +243,30 @@ else if (isset($_REQUEST['search'])) {
$player->setGroup($groups->getGroup($group)); $player->setGroup($groups->getGroup($group));
$player->setLevel($level); $player->setLevel($level);
$player->setExperience($experience); $player->setExperience($experience);
if ($db->hasColumn('players', 'promotion')) {
$promotion = 0;
$vocationOriginal = Vocations::getOriginal($vocation);
if ($vocation != $vocationOriginal) {
$tmpId = $vocationOriginal;
while($promoted = Vocations::getPromoted($tmpId)) {
$promotion++;
$tmpId = $promoted;
if ($promoted == $vocation) {
break;
}
}
$vocation = $vocationOriginal;
}
$player->setPromotion($promotion);
}
$player->setVocation($vocation); $player->setVocation($vocation);
$player->setHealth($health); $player->setHealth($health);
$player->setHealthMax($health_max); $player->setHealthMax($health_max);
$player->setMagLevel($magic_level); $player->setMagLevel($magic_level);
@@ -249,16 +278,20 @@ else if (isset($_REQUEST['search'])) {
$player->setLookHead($look_head); $player->setLookHead($look_head);
$player->setLookLegs($look_legs); $player->setLookLegs($look_legs);
$player->setLookType($look_type); $player->setLookType($look_type);
if ($hasLookAddons) if ($hasLookAddons) {
$player->setLookAddons($look_addons); $player->setLookAddons($look_addons);
if ($db->hasColumn('players', 'offlinetraining_time')) }
$player->setCustomField('offlinetraining_time', $offlinetraining);
$player->setPosX($pos_x); $player->setPosX($pos_x);
$player->setPosY($pos_y); $player->setPosY($pos_y);
$player->setPosZ($pos_z); $player->setPosZ($pos_z);
$player->setSoul($soul); $player->setSoul($soul);
$player->setTownId($town); $player->setTownId($town);
if ($hasCapColumn) {
$player->setCap($capacity); $player->setCap($capacity);
}
$player->setSex($sex); $player->setSex($sex);
$player->setLastLogin($lastlogin); $player->setLastLogin($lastlogin);
$player->setLastLogout($lastlogout); $player->setLastLogout($lastlogout);
@@ -275,23 +308,11 @@ else if (isset($_REQUEST['search'])) {
if ($hasBlessingsColumn) if ($hasBlessingsColumn)
$player->setBlessings($blessings); $player->setBlessings($blessings);
if ($hasBlessingColumn) {
for ($i = 1; $i <= $bless_count; $i++) {
$a = 'blessing' . $i;
$player->setCustomField('blessings' . $i, ${'blessing' . $i} ? '1' : '0');
}
}
$player->setBalance($balance); $player->setBalance($balance);
if ($db->hasColumn('players', 'stamina')) if ($db->hasColumn('players', 'stamina'))
$player->setStamina($stamina); $player->setStamina($stamina);
if ($db->hasColumn('players', 'deletion'))
$player->setCustomField('deletion', $deleted ? '1' : '0'); $player->setDeleted($deleted ? '1' : '0');
else
$player->setCustomField('deleted', $deleted ? '1' : '0');
$player->setCustomField('hide', $hide ? '1' : '0');
$player->setCustomField('created', $created);
if (isset($comment))
$player->setCustomField('comment', $comment);
foreach ($_POST['skills'] as $skill => $value) { foreach ($_POST['skills'] as $skill => $value) {
$player->setSkill($skill, $value); $player->setSkill($skill, $value);
@@ -300,6 +321,24 @@ else if (isset($_REQUEST['search'])) {
$player->setSkillTries($skill, $value); $player->setSkillTries($skill, $value);
} }
$player->save(); $player->save();
if ($db->hasColumn('players', 'offlinetraining_time')) {
$player->setCustomField('offlinetraining_time', $offlinetraining);
}
if ($hasBlessingColumn) {
for ($i = 1; $i <= $bless_count; $i++) {
$a = 'blessing' . $i;
$player->setCustomField('blessings' . $i, ${'blessing' . $i} ? '1' : '0');
}
}
$player->setCustomField('hide', $hide ? '1' : '0');
$player->setCustomField('created', $created);
if (isset($comment)) {
$player->setCustomField('comment', $comment);
}
echo_success('Player saved at: ' . date('G:i')); echo_success('Player saved at: ' . date('G:i'));
$player->load($id); $player->load($id);
} }
@@ -531,10 +570,12 @@ else if (isset($_REQUEST['search'])) {
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<?php if($hasCapColumn): ?>
<div class="col-12 col-sm-12 col-lg-6"> <div class="col-12 col-sm-12 col-lg-6">
<label for="capacity" class="control-label">Capacity:</label> <label for="capacity" class="control-label">Capacity:</label>
<input type="text" class="form-control" id="capacity" name="capacity" autocomplete="off" size="3" maxlength="11" value="<?php echo $player->getCap(); ?>"/> <input type="text" class="form-control" id="capacity" name="capacity" autocomplete="off" size="3" maxlength="11" value="<?php echo $player->getCap(); ?>"/>
</div> </div>
<?php endif; ?>
<div class="col-12 col-sm-12 col-lg-6"> <div class="col-12 col-sm-12 col-lg-6">
<label for="soul" class="control-label">Soul:</label> <label for="soul" class="control-label">Soul:</label>
<input type="text" class="form-control" id="soul" name="soul" autocomplete="off" size="3" maxlength="10" value="<?php echo $player->getSoul(); ?>"/> <input type="text" class="form-control" id="soul" name="soul" autocomplete="off" size="3" maxlength="10" value="<?php echo $player->getSoul(); ?>"/>
@@ -619,14 +660,14 @@ else if (isset($_REQUEST['search'])) {
<div class="col-12 col-sm-12 col-lg-6"> <div class="col-12 col-sm-12 col-lg-6">
<label for="look_type" class="control-label">Type:</label> <label for="look_type" class="control-label">Type:</label>
<?php <?php
$outfitlist = null; $outfits = Outfits::get();
$outfitlist = Outfits_loadfromXML(); if ($outfits) { ?>
if ($outfitlist) { ?>
<select name="look_type" id="look_type" class="form-control custom-select"> <select name="look_type" id="look_type" class="form-control custom-select">
<?php <?php
foreach ($outfitlist as $_id => $outfit) { foreach ($outfits as $outfit) {
if ($outfit['enabled'] == 'yes') ; if ($outfit['enabled']) {
echo '<option value=' . $outfit['id'] . ($outfit['id'] == $player->getLookType() ? ' selected' : '') . '>' . $outfit['name'] . ' - ' . ($outfit['type'] == 1 ? 'Male' : 'Female') . '</option>'; echo '<option value=' . $outfit['id'] . ($outfit['id'] == $player->getLookType() ? ' selected' : '') . '>' . $outfit['name'] . ' - ' . ($outfit['sex'] == SEX_MALE ? 'Male' : 'Female') . '</option>';
}
} }
?> ?>
</select> </select>
@@ -669,12 +710,18 @@ else if (isset($_REQUEST['search'])) {
<div class="col-12 col-sm-12 col-lg-6"> <div class="col-12 col-sm-12 col-lg-6">
<label for="lastip" class="control-label">Last IP:</label> <label for="lastip" class="control-label">Last IP:</label>
<input type="text" class="form-control" id="lastip" name="lastip" autocomplete="off" maxlength="10" value="<?php <input type="text" class="form-control" id="lastip" name="lastip" autocomplete="off" maxlength="10" value="<?php
if (strlen($player->getLastIP()) > 11) { $lastIPColumnInfo = $db->getColumnInfo('players', 'lastip');
if ($lastIPColumnInfo && is_array($lastIPColumnInfo)) {
if (str_contains($lastIPColumnInfo['type'], 'varbinary')) {
echo inet_ntop($player->getLastIP()); echo inet_ntop($player->getLastIP());
} }
else { else {
echo longToIp($player->getLastIP()); echo longToIp($player->getLastIP());
} }
}
else {
echo 'Error';
}
?>" readonly/> ?>" readonly/>
</div> </div>
</div> </div>

View File

@@ -46,6 +46,15 @@ if (!is_array($settingsFile)) {
return; return;
} }
if (isset($_POST['reset']) && $_POST['reset'] == '1') {
$settings = Settings::getInstance();
$settings->deleteFromDatabase($settingsFile['key']);
$settings->clearCache();
success('Settings for this plugin has been reset.');
}
$settingsKeyName = ($plugin == 'core' ? $plugin : $settingsFile['key']); $settingsKeyName = ($plugin == 'core' ? $plugin : $settingsFile['key']);
$title = ($plugin == 'core' ? 'Settings' : 'Plugin Settings - ' . $settingsFile['name']); $title = ($plugin == 'core' ? 'Settings' : 'Plugin Settings - ' . $settingsFile['name']);
@@ -57,4 +66,5 @@ $twig->display('admin.settings.html.twig', [
'settings' => $settingsFile['settings'], 'settings' => $settingsFile['settings'],
'script' => $settingsParsed['script'], 'script' => $settingsParsed['script'],
'settingsKeyName' => $settingsKeyName, 'settingsKeyName' => $settingsKeyName,
'pluginName' => $plugin,
]); ]);

View File

@@ -60,7 +60,7 @@ usort($menus, function ($a, $b) {
foreach ($menus as $i => $menu) { foreach ($menus as $i => $menu) {
if (isset($menu['link']) && is_array($menu['link'])) { if (isset($menu['link']) && is_array($menu['link'])) {
usort($menus[$i]['link'], function ($a, $b) { usort($menu['link'], function ($a, $b) {
return $a['order'] - $b['order']; return $a['order'] - $b['order'];
}); });
} }

View File

@@ -19,14 +19,14 @@
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic"> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic">
<?php $hooks->trigger(HOOK_ADMIN_HEAD_END); ?> <?php $hooks->trigger(HOOK_ADMIN_HEAD_END); ?>
</head> </head>
<body class="sidebar-mini "> <body class="sidebar-mini <?= (session('admin.menu-collapse') ? 'sidebar-collapse' : ''); ?>">
<?php $hooks->trigger(HOOK_ADMIN_BODY_START); ?> <?php $hooks->trigger(HOOK_ADMIN_BODY_START); ?>
<?php if ($logged && admin()) { ?> <?php if ($logged && admin()) { ?>
<div class="wrapper"> <div class="wrapper">
<nav class="main-header navbar navbar-expand navbar-white navbar-light"> <nav class="main-header navbar navbar-expand navbar-white navbar-light">
<ul class="navbar-nav"> <ul class="navbar-nav">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" data-widget="pushmenu" href="#"><i class="fas fa-bars"></i></a> <a class="nav-link sidebar-toggle" data-widget="pushmenu" href="#"><i class="fas fa-bars"></i></a>
</li> </li>
<li class="nav-item d-none d-sm-inline-block"> <li class="nav-item d-none d-sm-inline-block">
<a href="<?php echo ADMIN_URL; ?>" class="nav-link">Home</a> <a href="<?php echo ADMIN_URL; ?>" class="nav-link">Home</a>
@@ -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>
@@ -198,6 +199,7 @@ if ($logged && admin()) {
<script src="<?php echo BASE_URL; ?>tools/js/datatables.bs.min.js"></script> <script src="<?php echo BASE_URL; ?>tools/js/datatables.bs.min.js"></script>
<?php } ?> <?php } ?>
<script src="<?php echo BASE_URL; ?>tools/js/adminlte.min.js"></script> <script src="<?php echo BASE_URL; ?>tools/js/adminlte.min.js"></script>
<?php $twig->display('admin.menu-collapse.html.twig'); ?>
<?php $hooks->trigger(HOOK_ADMIN_BODY_END); ?> <?php $hooks->trigger(HOOK_ADMIN_BODY_END); ?>
</body> </body>
</html> </html>

View File

@@ -0,0 +1,23 @@
<?php
const MYAAC_ADMIN = true;
const IGNORE_SET_LAST_VISIT = true;
require '../../common.php';
require SYSTEM . 'functions.php';
require SYSTEM . 'init.php';
require SYSTEM . 'login.php';
if(!admin()) {
http_response_code(500);
die('You are not logged in. Probably session expired. Please login again.');
}
if (!isset($_POST['collapse'])) {
http_response_code(500);
die('Something went wrong.');
}
csrfProtect();
setSession('admin.menu-collapse', $_POST['collapse'] == 'true');

View File

@@ -1,5 +1,6 @@
<?php <?php
define('MYAAC_ADMIN', true); const MYAAC_ADMIN = true;
const IGNORE_SET_LAST_VISIT = true;
require '../../common.php'; require '../../common.php';
require SYSTEM . 'functions.php'; require SYSTEM . 'functions.php';

View File

@@ -26,6 +26,7 @@
use MyAAC\DataLoader; use MyAAC\DataLoader;
const MYAAC_ADMIN = true; const MYAAC_ADMIN = true;
const IGNORE_SET_LAST_VISIT = true;
require '../../common.php'; require '../../common.php';
require SYSTEM . 'functions.php'; require SYSTEM . 'functions.php';

View File

@@ -3,6 +3,7 @@
use MyAAC\Settings; use MyAAC\Settings;
const MYAAC_ADMIN = true; const MYAAC_ADMIN = true;
const IGNORE_SET_LAST_VISIT = true;
require '../../common.php'; require '../../common.php';
require SYSTEM . 'functions.php'; require SYSTEM . 'functions.php';
@@ -11,7 +12,7 @@ require SYSTEM . 'login.php';
if(!admin()) { if(!admin()) {
http_response_code(500); http_response_code(500);
die('Access denied.'); die('You are not logged in. Probably session expired. Please login again.');
} }
csrfProtect(); csrfProtect();
@@ -39,3 +40,6 @@ if (count($errors) > 0) {
if ($success) { if ($success) {
echo 'Saved at ' . date('H:i'); echo 'Saved at ' . date('H:i');
} }
else {
echo 'Something unexpected happened - it was impossible to save the settings, please try again later. If problem persists - contact MyAAC developers.';
}

View File

@@ -1,5 +1,6 @@
<?php <?php
define('MYAAC_ADMIN', true); const MYAAC_ADMIN = true;
const IGNORE_SET_LAST_VISIT = true;
require '../../common.php'; require '../../common.php';
require SYSTEM . 'init.php'; require SYSTEM . 'init.php';

View File

@@ -1,5 +1,6 @@
<?php <?php
define('MYAAC_ADMIN', true); const MYAAC_ADMIN = true;
const IGNORE_SET_LAST_VISIT = true;
require '../../common.php'; require '../../common.php';
require SYSTEM . 'functions.php'; require SYSTEM . 'functions.php';

View File

@@ -26,8 +26,8 @@
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.7.1'; const MYAAC_VERSION = '2.0-dev';
const DATABASE_VERSION = 45; const DATABASE_VERSION = 52;
const TABLE_PREFIX = 'myaac_'; const TABLE_PREFIX = 'myaac_';
define('START_TIME', microtime(true)); define('START_TIME', microtime(true));
define('MYAAC_OS', stripos(PHP_OS, 'WIN') === 0 ? 'WINDOWS' : (strtoupper(PHP_OS) === 'DARWIN' ? 'MAC' : 'LINUX')); define('MYAAC_OS', stripos(PHP_OS, 'WIN') === 0 ? 'WINDOWS' : (strtoupper(PHP_OS) === 'DARWIN' ? 'MAC' : 'LINUX'));
@@ -104,6 +104,8 @@ const OTSERV_FIRST = OTSERV;
const OTSERV_LAST = OTSERV_06; const OTSERV_LAST = OTSERV_06;
const TFS_02 = 3; const TFS_02 = 3;
const TFS_03 = 4; const TFS_03 = 4;
const BLACKTEK_2 = 5;
const BLACKTEK = 6;
const TFS_FIRST = TFS_02; const TFS_FIRST = TFS_02;
const TFS_LAST = TFS_03; const TFS_LAST = TFS_03;
@@ -148,16 +150,17 @@ if(!IS_CLI) {
/** @var array $config */ /** @var array $config */
ini_set('log_errors', 1); ini_set('log_errors', 1);
if(@$config['env'] === 'dev' || defined('MYAAC_INSTALL')) { if(isset($config['env']) && $config['env'] !== 'dev' && !defined('MYAAC_INSTALL')) {
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
}
else {
ini_set('display_errors', 0); ini_set('display_errors', 0);
ini_set('display_startup_errors', 0); ini_set('display_startup_errors', 0);
error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT); error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT);
} }
else {
ini_set('html_errors', 0);
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
}
$autoloadFile = VENDOR . 'autoload.php'; $autoloadFile = VENDOR . 'autoload.php';
if (!is_file($autoloadFile)) { if (!is_file($autoloadFile)) {

View File

@@ -5,6 +5,7 @@
"ext-pdo_mysql": "*", "ext-pdo_mysql": "*",
"ext-json": "*", "ext-json": "*",
"ext-xml": "*", "ext-xml": "*",
"ext-simplexml": "*",
"ext-dom": "*", "ext-dom": "*",
"phpmailer/phpmailer": "^6.1", "phpmailer/phpmailer": "^6.1",
"composer/semver": "^3.2", "composer/semver": "^3.2",
@@ -19,7 +20,8 @@
"symfony/var-dumper": "^6.4", "symfony/var-dumper": "^6.4",
"filp/whoops": "^2.15", "filp/whoops": "^2.15",
"maximebf/debugbar": "1.*", "maximebf/debugbar": "1.*",
"guzzlehttp/guzzle": "7.9.3" "guzzlehttp/guzzle": "7.9.3",
"devium/toml": "^1.0"
}, },
"require-dev": { "require-dev": {
"phpstan/phpstan": "^1.10" "phpstan/phpstan": "^1.10"

127
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "5317e97a5025ebc2a977214bd3fa964c", "content-hash": "de1219601202cf55861809fd69c5feb4",
"packages": [ "packages": [
{ {
"name": "brick/math", "name": "brick/math",
@@ -216,6 +216,75 @@
], ],
"time": "2024-09-19T14:15:21+00:00" "time": "2024-09-19T14:15:21+00:00"
}, },
{
"name": "devium/toml",
"version": "1.0.6",
"source": {
"type": "git",
"url": "https://github.com/vanodevium/toml.git",
"reference": "190882f9d92e88f8031285129ba9df501da899a6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/vanodevium/toml/zipball/190882f9d92e88f8031285129ba9df501da899a6",
"reference": "190882f9d92e88f8031285129ba9df501da899a6",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": ">=8.1",
"php-ds/php-ds": "^1.5",
"symfony/polyfill-mbstring": "^1.30"
},
"require-dev": {
"laravel/pint": "^1.17.3",
"pestphp/pest": "^2.35.1",
"phpstan/phpstan": "^1.12.2",
"rector/rector": "^1.2.4",
"symfony/var-dumper": "^6.4|^7.1.4"
},
"suggest": {
"ext-ds": "For best performance",
"ext-mbstring": "For best performance"
},
"type": "library",
"autoload": {
"files": [
"src/helpers.php"
],
"psr-4": {
"Devium\\Toml\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Vano Devium",
"email": "vano@devium.me"
}
],
"description": "A PHP encoder/decoder for TOML compatible with specification 1.0.0",
"keywords": [
"decode",
"encode",
"parser",
"toml"
],
"support": {
"issues": "https://github.com/vanodevium/toml/issues",
"source": "https://github.com/vanodevium/toml/tree/v1.0.6"
},
"funding": [
{
"url": "https://github.com/vanodevium",
"type": "github"
}
],
"time": "2025-04-22T18:10:54+00:00"
},
{ {
"name": "doctrine/inflector", "name": "doctrine/inflector",
"version": "2.0.10", "version": "2.0.10",
@@ -1615,6 +1684,62 @@
}, },
"time": "2021-04-22T21:32:03+00:00" "time": "2021-04-22T21:32:03+00:00"
}, },
{
"name": "php-ds/php-ds",
"version": "v1.7.0",
"source": {
"type": "git",
"url": "https://github.com/php-ds/polyfill.git",
"reference": "017fb5cdfa52a1f13126c94987b04b884c44f9cd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-ds/polyfill/zipball/017fb5cdfa52a1f13126c94987b04b884c44f9cd",
"reference": "017fb5cdfa52a1f13126c94987b04b884c44f9cd",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": ">=7.4"
},
"provide": {
"ext-ds": "1.5.0"
},
"require-dev": {
"php-ds/tests": "^1.5"
},
"suggest": {
"ext-ds": "to improve performance and reduce memory usage"
},
"type": "library",
"autoload": {
"psr-4": {
"Ds\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Rudi Theunissen",
"email": "rudolf.theunissen@gmail.com"
}
],
"description": "Specialized data structures as alternatives to the PHP array",
"keywords": [
"data structures",
"ds",
"php",
"polyfill"
],
"support": {
"issues": "https://github.com/php-ds/polyfill/issues",
"source": "https://github.com/php-ds/polyfill/tree/v1.7.0"
},
"time": "2025-05-18T04:50:53+00:00"
},
{ {
"name": "phpmailer/phpmailer", "name": "phpmailer/phpmailer",
"version": "v6.9.3", "version": "v6.9.3",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 33 KiB

BIN
images/facebook_16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 718 B

BIN
images/instagram_16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 33 KiB

BIN
images/monk.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1005 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 31 KiB

BIN
images/whatsapp_16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 688 B

View File

@@ -162,15 +162,6 @@ if(setting('core.anonymous_usage_statistics')) {
} }
} }
/**
* @var OTS_Account $account_logged
*/
if ($logged && admin()) {
$content .= $twig->render('admin-bar.html.twig', [
'username' => USE_ACCOUNT_NAME ? $account_logged->getName() : $account_logged->getId()
]);
}
$title_full = (isset($title) ? $title . ' - ' : '') . $config['lua']['serverName']; $title_full = (isset($title) ? $title . ' - ' : '') . $config['lua']['serverName'];
require $template_path . '/' . $template_index; require $template_path . '/' . $template_index;

View File

@@ -1,4 +1,7 @@
<?php <?php
use MyAAC\Server\Lua\Loader;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
if(!isset($_SESSION['var_server_path'])) { if(!isset($_SESSION['var_server_path'])) {
@@ -11,24 +14,36 @@ $config['server_path'] = $_SESSION['var_server_path'];
if($config['server_path'][strlen($config['server_path']) - 1] != '/') if($config['server_path'][strlen($config['server_path']) - 1] != '/')
$config['server_path'] .= '/'; $config['server_path'] .= '/';
if((!isset($error) || !$error) && !file_exists($config['server_path'] . 'config.lua')) { $configLuaExists = file_exists($config['server_path'] . 'config.lua');
$configTomlExists = file_exists($config['server_path'] . 'config/server.toml');
if((!isset($error) || !$error)
&& !$configLuaExists
&& !$configTomlExists) {
error($locale['step_database_error_config']); error($locale['step_database_error_config']);
$error = true; $error = true;
} }
if(!isset($error) || !$error) { if (!isset($error) || !$error) {
$config['lua'] = load_config_lua($config['server_path'] . 'config.lua'); if($configLuaExists) {
if(isset($config['lua']['sqlType'])) // tfs 0.3 $config['lua'] = Loader::load($config['server_path'] . 'config.lua');
if (isset($config['lua']['sqlType'])) // tfs 0.3
$config['database_type'] = $config['lua']['sqlType']; $config['database_type'] = $config['lua']['sqlType'];
else if(isset($config['lua']['mysqlHost'])) // tfs 0.2/1.0 elseif (isset($config['lua']['mysqlHost'])) // tfs 0.2/1.0
$config['database_type'] = 'mysql'; $config['database_type'] = 'mysql';
else if(isset($config['lua']['database_type'])) // otserv elseif (isset($config['lua']['database_type'])) // otserv
$config['database_type'] = $config['lua']['database_type']; $config['database_type'] = $config['lua']['database_type'];
else if(isset($config['lua']['sql_type'])) // otserv elseif (isset($config['lua']['sql_type'])) // otserv
$config['database_type'] = $config['lua']['sql_type']; $config['database_type'] = $config['lua']['sql_type'];
else { else {
$config['database_type'] = ''; $config['database_type'] = '';
} }
}
elseif ($configTomlExists) {
$tomlConfig = new MyAAC\Server\TOML\Config();
$tomlConfig->load();
$config['server'] = $tomlConfig->get();
$config['database_type'] = (isset($config['server']['database']['mysql']) ? 'mysql' : '');
}
$config['database_type'] = strtolower($config['database_type']); $config['database_type'] = strtolower($config['database_type']);
if(empty($config['database_type'])) { if(empty($config['database_type'])) {

View File

@@ -0,0 +1,67 @@
<?php
defined('MYAAC') or die('Direct access not allowed!');
use MyAAC\Models\Changelog;
use MyAAC\Models\Config;
use MyAAC\Models\FAQ;
use MyAAC\Models\ForumBoard;
use MyAAC\Models\Gallery;
use MyAAC\Models\NewsCategory;
if (Changelog::count() === 0) {
Changelog::create([
'type' => 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(FAQ::count() == 0) {
FAQ::create([
'question' => 'What is this?',
'answer' => 'This is website for OTS powered by MyAAC.',
]);
}
success($locale['step_database_success_import_data']);

View File

@@ -1,16 +1,25 @@
SET @myaac_database_version = 45; CREATE TABLE IF NOT EXISTS `myaac_account_actions`
CREATE TABLE `myaac_account_actions`
( (
`id` int NOT NULL AUTO_INCREMENT,
`account_id` int NOT NULL, `account_id` int NOT NULL,
`ip` int unsigned NOT NULL DEFAULT 0, `ip` varchar(45) NOT NULL DEFAULT '',
`ipv6` binary(16) NOT NULL DEFAULT 0,
`date` int NOT NULL DEFAULT 0, `date` int NOT NULL DEFAULT 0,
`action` varchar(255) NOT NULL DEFAULT '', `action` varchar(255) NOT NULL DEFAULT '',
KEY (`account_id`) PRIMARY KEY (`id`),
INDEX `myaac_account_actions_account_id` (`account_id`),
INDEX `myaac_account_actions_ip` (`ip`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE `myaac_admin_menu` CREATE TABLE IF NOT EXISTS `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 IF NOT EXISTS `myaac_admin_menu`
( (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '', `name` varchar(255) NOT NULL DEFAULT '',
@@ -21,7 +30,7 @@ CREATE TABLE `myaac_admin_menu`
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE `myaac_changelog` CREATE TABLE IF NOT EXISTS `myaac_changelog`
( (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`body` varchar(500) NOT NULL DEFAULT '', `body` varchar(500) NOT NULL DEFAULT '',
@@ -33,20 +42,16 @@ CREATE TABLE `myaac_changelog`
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) 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 IF NOT EXISTS `myaac_config`
CREATE TABLE `myaac_config`
( (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`name` varchar(30) NOT NULL, `name` varchar(255) NOT NULL,
`value` varchar(1000) NOT NULL, `value` varchar(10000) NOT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE (`name`) UNIQUE (`name`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
INSERT INTO `myaac_config` (`name`, `value`) VALUES ('database_version', @myaac_database_version); CREATE TABLE IF NOT EXISTS `myaac_faq`
CREATE TABLE `myaac_faq`
( (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`question` varchar(255) NOT NULL DEFAULT '', `question` varchar(255) NOT NULL DEFAULT '',
@@ -56,7 +61,7 @@ CREATE TABLE `myaac_faq`
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) 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, `id` int NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL, `name` varchar(32) NOT NULL,
@@ -68,13 +73,8 @@ CREATE TABLE `myaac_forum_boards`
`hide` tinyint NOT NULL DEFAULT 0, `hide` tinyint NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) 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, `id` int NOT NULL AUTO_INCREMENT,
`first_post` int NOT NULL DEFAULT 0, `first_post` int NOT NULL DEFAULT 0,
@@ -98,12 +98,13 @@ CREATE TABLE `myaac_forum`
KEY `section` (`section`) KEY `section` (`section`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE `myaac_menu` CREATE TABLE IF NOT EXISTS `myaac_menu`
( (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`template` varchar(255) NOT NULL, `template` varchar(255) NOT NULL,
`name` varchar(255) NOT NULL, `name` varchar(255) NOT NULL,
`link` varchar(255) NOT NULL, `link` varchar(255) NOT NULL,
`access` tinyint NOT NULL DEFAULT 0,
`blank` tinyint NOT NULL DEFAULT 0, `blank` tinyint NOT NULL DEFAULT 0,
`color` varchar(6) NOT NULL DEFAULT '', `color` varchar(6) NOT NULL DEFAULT '',
`category` int NOT NULL DEFAULT 1, `category` int NOT NULL DEFAULT 1,
@@ -112,7 +113,7 @@ CREATE TABLE `myaac_menu`
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE `myaac_monsters` ( CREATE TABLE IF NOT EXISTS `myaac_monsters` (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`hide` tinyint NOT NULL DEFAULT 0, `hide` tinyint NOT NULL DEFAULT 0,
`name` varchar(255) NOT NULL, `name` varchar(255) NOT NULL,
@@ -145,7 +146,7 @@ CREATE TABLE `myaac_monsters` (
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE `myaac_news` CREATE TABLE IF NOT EXISTS `myaac_news`
( (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`title` varchar(100) NOT NULL, `title` varchar(100) NOT NULL,
@@ -163,7 +164,7 @@ CREATE TABLE `myaac_news`
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) 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, `id` int NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL DEFAULT "", `name` varchar(50) NOT NULL DEFAULT "",
@@ -173,13 +174,7 @@ CREATE TABLE `myaac_news_categories`
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 0); CREATE TABLE IF NOT EXISTS `myaac_notepad`
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`
( (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`account_id` int NOT NULL, `account_id` int NOT NULL,
@@ -189,7 +184,7 @@ CREATE TABLE `myaac_notepad`
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE `myaac_pages` CREATE TABLE IF NOT EXISTS `myaac_pages`
( (
`id` INT NOT NULL AUTO_INCREMENT, `id` INT NOT NULL AUTO_INCREMENT,
`name` varchar(30) NOT NULL, `name` varchar(30) NOT NULL,
@@ -205,21 +200,7 @@ CREATE TABLE `myaac_pages`
UNIQUE (`name`) UNIQUE (`name`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE `myaac_gallery` CREATE TABLE IF NOT EXISTS `myaac_settings`
(
`id` int NOT NULL AUTO_INCREMENT,
`comment` varchar(255) NOT NULL DEFAULT '',
`image` varchar(255) NOT NULL,
`thumb` varchar(255) NOT NULL,
`author` varchar(50) NOT NULL DEFAULT '',
`ordering` int NOT NULL DEFAULT 0,
`hide` tinyint NOT NULL DEFAULT 0,
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`
( (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '', `name` varchar(255) NOT NULL DEFAULT '',
@@ -229,7 +210,7 @@ CREATE TABLE `myaac_settings`
KEY `key` (`key`) KEY `key` (`key`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE `myaac_spells` CREATE TABLE IF NOT EXISTS `myaac_spells`
( (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`spell` varchar(255) NOT NULL DEFAULT '', `spell` varchar(255) NOT NULL DEFAULT '',
@@ -252,7 +233,7 @@ CREATE TABLE `myaac_spells`
UNIQUE (`name`) UNIQUE (`name`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE `myaac_visitors` CREATE TABLE IF NOT EXISTS `myaac_visitors`
( (
`ip` varchar(45) NOT NULL, `ip` varchar(45) NOT NULL,
`lastvisit` int NOT NULL DEFAULT 0, `lastvisit` int NOT NULL DEFAULT 0,
@@ -261,7 +242,7 @@ CREATE TABLE `myaac_visitors`
UNIQUE (`ip`) UNIQUE (`ip`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE `myaac_weapons` CREATE TABLE IF NOT EXISTS `myaac_weapons`
( (
`id` int NOT NULL, `id` int NOT NULL,
`level` int NOT NULL DEFAULT 0, `level` int NOT NULL DEFAULT 0,

View File

@@ -1,5 +1,6 @@
<?php <?php
use MyAAC\Server\Config;
use Twig\Environment as Twig_Environment; use Twig\Environment as Twig_Environment;
use Twig\Loader\FilesystemLoader as Twig_FilesystemLoader; use Twig\Loader\FilesystemLoader as Twig_FilesystemLoader;
@@ -30,7 +31,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 +54,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 +62,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;
} }
@@ -83,7 +84,7 @@ if($step == 'database') {
$config['server_path'] .= '/'; $config['server_path'] .= '/';
} }
if(!file_exists($config['server_path'] . 'config.lua')) { if(!Config::exists()) {
$errors[] = $locale['step_database_error_config']; $errors[] = $locale['step_database_error_config'];
break; break;
} }
@@ -182,7 +183,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 +199,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

@@ -42,10 +42,9 @@ 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) { if ($saved || file_exists(BASE . 'config.local.php')) {
success($locale['step_database_config_saved']); success($locale['step_database_config_saved']);
$_SESSION['saved'] = true; $_SESSION['saved'] = true;
@@ -74,14 +73,14 @@ if(!$error) {
} }
} }
} else { } else {
$error = true;
$_SESSION['config_content'] = $content; $_SESSION['config_content'] = $content;
unset($_SESSION['saved']); unset($_SESSION['saved']);
$locale['step_database_error_file'] = str_replace('$FILE$', '<b>' . BASE . 'config.php</b>', $locale['step_database_error_file']); $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/> error($locale['step_database_error_file'] . '<br/>
<textarea cols="70" rows="10">' . $content . '</textarea>'); <textarea cols="70" rows="10">' . $content . '</textarea>');
} }
}
} }
?> ?>

View File

@@ -30,27 +30,23 @@ if(!$error) {
} }
} }
if($db->hasTable(TABLE_PREFIX . 'account_actions')) { // import schema
$locale['step_database_error_table_exist'] = str_replace('$TABLE$', TABLE_PREFIX . 'account_actions', $locale['step_database_error_table_exist']); try {
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']); $locale['step_database_importing'] = str_replace('$DATABASE_NAME$', config('database_name'), $locale['step_database_importing']);
success($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']); $locale['step_database_success_schema'] = str_replace('$PREFIX$', TABLE_PREFIX, $locale['step_database_success_schema']);
success($locale['step_database_success_schema']); success($locale['step_database_success_schema']);
} }
catch(PDOException $error_) { catch(PDOException $error_) {
error($locale['step_database_error_schema'] . ' ' . $error_); error($locale['step_database_error_schema'] . ' ' . $error_);
return; return;
}
} }
require BASE . 'install/includes/import_base_data.php';
if(!$db->hasColumn('accounts', 'email')) { if(!$db->hasColumn('accounts', 'email')) {
if(query("ALTER TABLE `accounts` ADD `email` varchar(255) NOT NULL DEFAULT '';")) if(query("ALTER TABLE `accounts` ADD `email` varchar(255) NOT NULL DEFAULT '';"))
success($locale['step_database_adding_field'] . ' accounts.email...'); success($locale['step_database_adding_field'] . ' accounts.email...');
@@ -102,18 +98,13 @@ if(!$db->hasColumn('accounts', 'web_flags')) {
success($locale['step_database_adding_field'] . ' 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(!$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...'); success($locale['step_database_adding_field'] . ' accounts.email_verified...');
} }
if(!$db->hasColumn('accounts', 'email_new')) { 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...'); success($locale['step_database_adding_field'] . ' accounts.email_new...');
} }

View File

@@ -2,8 +2,6 @@
define('MYAAC_INSTALL', true); define('MYAAC_INSTALL', true);
use MyAAC\DataLoader; use MyAAC\DataLoader;
use MyAAC\Models\FAQ as ModelsFAQ;
use MyAAC\Plugins;
require_once '../../common.php'; require_once '../../common.php';
@@ -25,46 +23,19 @@ if(isset($config['installed']) && $config['installed'] && !isset($_SESSION['save
require SYSTEM . 'init.php'; require SYSTEM . 'init.php';
if ($db->hasTable('players')) { // add player samples
$deleted = 'deleted'; require_once SYSTEM . 'migrations/49.php';
if ($db->hasColumn('players', 'deletion')) $up();
$deleted = 'deletion';
$time = time();
function insert_sample_if_not_exist($p)
{
global $db, $success, $deleted, $time;
$query = $db->query('SELECT `id` FROM `players` WHERE `name` = ' . $db->quote($p['name']));
if ($query->rowCount() == 0) {
if (!query("INSERT INTO `players` (`id`, `name`, `group_id`, `account_id`, `level`, `vocation`, `health`, `healthmax`, `experience`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `maglevel`, `mana`, `manamax`, `manaspent`, `soul`, `town_id`, `posx`, `posy`, `posz`, `conditions`, `cap`, `sex`, `lastlogin`, `lastip`, `save`, `lastlogout`, `balance`, `$deleted`, `created`, `hide`, `comment`) VALUES (null, " . $db->quote($p['name']) . ", 1, " . getSession('account') . ", " . $p['level'] . ", " . $p['vocation_id'] . ", " . $p['health'] . ", " . $p['healthmax'] . ", " . $p['experience'] . ", 118, 114, 38, 57, " . $p['looktype'] . ", 0, " . $p['mana'] . ", " . $p['manamax'] . ", 0, " . $p['soul'] . ", 1, 1000, 1000, 7, '', " . $p['cap'] . ", 1, " . $time . ", 2130706433, 1, " . $time . ", 0, 0, " . $time . ", 1, '');"))
$success = false;
}
}
$success = true;
insert_sample_if_not_exist(array('name' => 'Rook Sample', 'level' => 1, 'vocation_id' => 0, 'health' => 150, 'healthmax' => 150, 'experience' => 0, 'looktype' => 130, 'mana' => 0, 'manamax' => 0, 'soul' => 100, 'cap' => 400));
insert_sample_if_not_exist(array('name' => 'Sorcerer Sample', 'level' => 8, 'vocation_id' => 1, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 130, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470));
insert_sample_if_not_exist(array('name' => 'Druid Sample', 'level' => 8, 'vocation_id' => 2, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 130, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470));
insert_sample_if_not_exist(array('name' => 'Paladin Sample', 'level' => 8, 'vocation_id' => 3, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 129, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470));
insert_sample_if_not_exist(array('name' => 'Knight Sample', 'level' => 8, 'vocation_id' => 4, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 131, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470));
if ($success) {
success($locale['step_database_imported_players']);
}
}
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();
// update config.highscores_ids_hidden
require_once SYSTEM . 'migrations/20.php';
$up();
// add z_polls tables // add z_polls tables
require_once SYSTEM . 'migrations/22.php'; require_once SYSTEM . 'migrations/22.php';
$up(); $up();
@@ -83,13 +54,6 @@ $up();
require_once SYSTEM . 'migrations/45.php'; require_once SYSTEM . 'migrations/45.php';
$up(); $up();
if(ModelsFAQ::count() == 0) {
ModelsFAQ::create([
'question' => 'What is this?',
'answer' => 'This is website for OTS powered by MyAAC.',
]);
}
$hooks->trigger(HOOK_INSTALL_FINISH); $hooks->trigger(HOOK_INSTALL_FINISH);
$db->setClearCacheAfter(true); $db->setClearCacheAfter(true);
@@ -105,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'])
])); ]));
} }
@@ -220,6 +220,8 @@ switch ($action) {
} }
} }
/*
* not needed anymore?
if (fieldExist('premdays', 'accounts') && fieldExist('lastday', 'accounts')) { if (fieldExist('premdays', 'accounts') && fieldExist('lastday', 'accounts')) {
$save = false; $save = false;
$timeNow = time(); $timeNow = time();
@@ -256,6 +258,7 @@ switch ($action) {
$account->save(); $account->save();
} }
} }
*/
$worlds = [$world]; $worlds = [$world];
$playdata = compact('worlds', 'characters'); $playdata = compact('worlds', 'characters');

35
package-lock.json generated
View File

@@ -18,9 +18,9 @@
} }
}, },
"node_modules/@cypress/request": { "node_modules/@cypress/request": {
"version": "3.0.8", "version": "3.0.10",
"resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.8.tgz", "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.10.tgz",
"integrity": "sha512-h0NFgh1mJmm1nr4jCwkGHwKneVYKghUyWe6TMNrk0B9zsjAJxpg8C4/+BAcmLgCPa1vj1V8rNUaILl+zYRUWBQ==", "integrity": "sha512-hauBrOdvu08vOsagkZ/Aju5XuiZx6ldsLfByg1htFeldhex+PeMrYauANzFsMJeAA0+dyPLbDoX2OYuvVoLDkQ==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
@@ -30,14 +30,14 @@
"combined-stream": "~1.0.6", "combined-stream": "~1.0.6",
"extend": "~3.0.2", "extend": "~3.0.2",
"forever-agent": "~0.6.1", "forever-agent": "~0.6.1",
"form-data": "~4.0.0", "form-data": "~4.0.4",
"http-signature": "~1.4.0", "http-signature": "~1.4.0",
"is-typedarray": "~1.0.0", "is-typedarray": "~1.0.0",
"isstream": "~0.1.2", "isstream": "~0.1.2",
"json-stringify-safe": "~5.0.1", "json-stringify-safe": "~5.0.1",
"mime-types": "~2.1.19", "mime-types": "~2.1.19",
"performance-now": "^2.1.0", "performance-now": "^2.1.0",
"qs": "6.14.0", "qs": "~6.14.1",
"safe-buffer": "^5.1.2", "safe-buffer": "^5.1.2",
"tough-cookie": "^5.0.0", "tough-cookie": "^5.0.0",
"tunnel-agent": "^0.6.0", "tunnel-agent": "^0.6.0",
@@ -976,15 +976,16 @@
} }
}, },
"node_modules/form-data": { "node_modules/form-data": {
"version": "4.0.2", "version": "4.0.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"asynckit": "^0.4.0", "asynckit": "^0.4.0",
"combined-stream": "^1.0.8", "combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0", "es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.2",
"mime-types": "^2.1.12" "mime-types": "^2.1.12"
}, },
"engines": { "engines": {
@@ -1430,9 +1431,9 @@
} }
}, },
"node_modules/lodash": { "node_modules/lodash": {
"version": "4.17.21", "version": "4.18.1",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
@@ -1742,9 +1743,9 @@
} }
}, },
"node_modules/qs": { "node_modules/qs": {
"version": "6.14.0", "version": "6.14.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz",
"integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==",
"dev": true, "dev": true,
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"dependencies": { "dependencies": {
@@ -2084,9 +2085,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/tmp": { "node_modules/tmp": {
"version": "0.2.3", "version": "0.2.4",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.4.tgz",
"integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", "integrity": "sha512-UdiSoX6ypifLmrfQ/XfiawN6hkjSBpCjhKxxZcWlUUmoXLaCKQU0bx4HF/tdDK2uzRuchf1txGvrWBzYREssoQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {

View File

@@ -28,10 +28,9 @@ parameters:
- '#Variable \$guild might not be defined#' - '#Variable \$guild might not be defined#'
- '#Variable \$[a-zA-Z0-9\\_]+ might not be defined#' - '#Variable \$[a-zA-Z0-9\\_]+ might not be defined#'
# Eloquent models # Eloquent models
- '#Call to an undefined method [a-zA-Z0-9\\_]+::[a-zA-Z0-9\\_]+\(\)#'
- '#Call to an undefined static method [a-zA-Z0-9\\_]+::[a-zA-Z0-9\\_]+\(\)#' - '#Call to an undefined static method [a-zA-Z0-9\\_]+::[a-zA-Z0-9\\_]+\(\)#'
- '#Call to an undefined method object::toArray\(\)#'
# system/pages/highscores.php # system/pages/highscores.php
- '#Call to an undefined method Illuminate\\Database\\Query\\Builder::withOnlineStatus\(\)#'
- '#Access to an undefined property Illuminate\\Database\\Eloquent\\Model::\$online_status#' - '#Access to an undefined property Illuminate\\Database\\Eloquent\\Model::\$online_status#'
- '#Access to an undefined property Illuminate\\Database\\Eloquent\\Model::\$vocation_name#' - '#Access to an undefined property Illuminate\\Database\\Eloquent\\Model::\$vocation_name#'
- -

View File

@@ -9,6 +9,8 @@
*/ */
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
use MyAAC\Server\Lua\Loader;
class Validator extends \MyAAC\Validator {} class Validator extends \MyAAC\Validator {}
function check_name($name, &$errors = '') { function check_name($name, &$errors = '') {
@@ -74,3 +76,77 @@ function fieldExist($field, $table)
global $db; global $db;
return $db->hasColumn($table, $field); return $db->hasColumn($table, $field);
} }
function Outfits_loadfromXML(): ?array
{
global $config;
$file_path = $config['data_path'] . 'XML/outfits.xml';
if (!file_exists($file_path)) { return null; }
$xml = new DOMDocument;
$xml->load($file_path);
$outfits = null;
foreach ($xml->getElementsByTagName('outfit') as $outfit) {
$outfits[] = Outfit_parseNode($outfit);
}
return $outfits;
}
function Outfit_parseNode($node): array
{
$looktype = (int)$node->getAttribute('looktype');
$type = (int)$node->getAttribute('type');
$lookname = $node->getAttribute('name');
$premium = $node->getAttribute('premium');
$unlocked = $node->getAttribute('unlocked');
$enabled = $node->getAttribute('enabled');
return array('id' => $looktype, 'type' => $type, 'name' => $lookname, 'premium' => $premium, 'unlocked' => $unlocked, 'enabled' => $enabled);
}
function Mounts_loadfromXML(): ?array
{
global $config;
$file_path = $config['data_path'] . 'XML/mounts.xml';
if (!file_exists($file_path)) { return null; }
$xml = new DOMDocument;
$xml->load($file_path);
$mounts = null;
foreach ($xml->getElementsByTagName('mount') as $mount) {
$mounts[] = Mount_parseNode($mount);
}
return $mounts;
}
function Mount_parseNode($node): array
{
$id = (int)$node->getAttribute('id');
$clientid = (int)$node->getAttribute('clientid');
$name = $node->getAttribute('name');
$speed = (int)$node->getAttribute('speed');
$premium = $node->getAttribute('premium');
$type = $node->getAttribute('type');
return array('id' => $id, 'clientid' => $clientid, 'name' => $name, 'speed' => $speed, 'premium' => $premium, 'type' => $type);
}
function load_config_lua(string $file): array
{
$result = Loader::load($file);
if ($result === false) {
log_append('error.log', '[load_config_file] Fatal error: Cannot load config.lua (' . $file . ').');
throw new \RuntimeException('ERROR: Cannot find ' . $file . ' file.');
}
return $result;
}
function configLua($key) {
global $config;
if (is_array($key)) {
return $config['lua'][$key[0]] = $key[1];
}
return @$config['lua'][$key];
}

View File

@@ -5,8 +5,6 @@ $deprecatedConfig = [
'genders', 'genders',
'template', 'template',
'template_allow_change', 'template_allow_change',
'vocations_amount',
'vocations',
'client', 'client',
'session_prefix', 'session_prefix',
'friendly_urls', 'friendly_urls',
@@ -21,7 +19,6 @@ $deprecatedConfig = [
'visitors_counter_ttl', 'visitors_counter_ttl',
'views_counter', 'views_counter',
'outfit_images_url', 'outfit_images_url',
'outfit_images_wrong_looktypes',
'item_images_url', 'item_images_url',
'account_country', 'account_country',
'towns', 'towns',
@@ -52,6 +49,7 @@ $deprecatedConfig = [
'online_skulls', 'online_skulls',
'online_outfit', 'online_outfit',
'online_afk', 'online_afk',
'team_style',
'team_display_outfit' => 'team_outfit', 'team_display_outfit' => 'team_outfit',
'team_display_status' => 'team_status', 'team_display_status' => 'team_status',
'team_display_world' => 'team_world', 'team_display_world' => 'team_world',
@@ -81,6 +79,7 @@ $deprecatedConfig = [
'account_change_character_name_points' => 'account_change_character_name_price', 'account_change_character_name_points' => 'account_change_character_name_price',
'account_change_character_sex', 'account_change_character_sex',
'account_change_character_sex_points' => 'account_change_character_name_price', 'account_change_character_sex_points' => 'account_change_character_name_price',
'email_lai_sec_interval' => 'mail_lost_account_interval',
]; ];
foreach ($deprecatedConfig as $key => $value) { foreach ($deprecatedConfig as $key => $value) {

View File

@@ -18,6 +18,19 @@ if (!isset($config['database_overwrite'])) {
if(!$config['database_overwrite'] && !isset($config['database_user'][0], $config['database_password'][0], $config['database_name'][0])) if(!$config['database_overwrite'] && !isset($config['database_user'][0], $config['database_password'][0], $config['database_name'][0]))
{ {
if (isset($config['server']['database']['mysql'])) { // BlackTek
$config['otserv_version'] = BLACKTEK;
$config['database_type'] = 'mysql';
$config['database_host'] = $config['server']['database']['mysql']['host'];
$config['database_port'] = $config['server']['database']['mysql']['port'];
$config['database_user'] = $config['server']['database']['mysql']['user'];
$config['database_password'] = $config['server']['database']['mysql']['pass'];
$config['database_name'] = $config['server']['database']['mysql']['database'];
if(!isset($config['database_socket'][0]) && !empty(trim($config['server']['database']['mysql']['socket']))) {
$config['database_socket'] = trim($config['server']['database']['mysql']['socket']);
}
$config['database_encryption'] = 'sha1';
}
if(isset($config['lua']['sqlType'])) {// tfs 0.3 if(isset($config['lua']['sqlType'])) {// tfs 0.3
if(isset($config['lua']['mysqlHost'])) {// tfs 0.2 if(isset($config['lua']['mysqlHost'])) {// tfs 0.2
$config['otserv_version'] = TFS_02; $config['otserv_version'] = TFS_02;
@@ -94,7 +107,6 @@ if(!isset($config['database_socket'])) {
$config['database_socket'] = ''; $config['database_socket'] = '';
} }
try { try {
$ots->connect(array( $ots->connect(array(
'host' => $config['database_host'], 'host' => $config['database_host'],

View File

@@ -11,17 +11,18 @@ defined('MYAAC') or die('Direct access not allowed!');
use MyAAC\Cache\Cache; use MyAAC\Cache\Cache;
use MyAAC\CsrfToken; use MyAAC\CsrfToken;
use MyAAC\Items;
use MyAAC\Models\Config; use MyAAC\Models\Config;
use MyAAC\Models\Guild; use MyAAC\Models\Guild;
use MyAAC\Models\House; use MyAAC\Models\House;
use MyAAC\Models\Pages; use MyAAC\Models\Pages;
use MyAAC\Models\Player; use MyAAC\Models\Player;
use MyAAC\Models\PlayerDeath;
use MyAAC\Models\PlayerKillers;
use MyAAC\News; use MyAAC\News;
use MyAAC\Plugins; use MyAAC\Plugins;
use MyAAC\Server\Items;
use MyAAC\Settings; use MyAAC\Settings;
use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\PHPMailer;
use Twig\Loader\ArrayLoader as Twig_ArrayLoader;
function message($message, $type, $return) function message($message, $type, $return)
{ {
@@ -433,16 +434,22 @@ function delete_guild($id)
$rank_list->orderBy('level'); $rank_list->orderBy('level');
global $db; global $db;
$deletedColumn = 'deleted';
if ($db->hasColumn('players', 'deletion')) {
$deletedColumn = 'deletion';
}
/** /**
* @var OTS_GuildRank $rank_in_guild * @var OTS_GuildRank $rank_in_guild
*/ */
foreach($rank_list as $rank_in_guild) { foreach($rank_list as $rank_in_guild) {
if($db->hasTable('guild_members')) if($db->hasTable('guild_members'))
$players_with_rank = $db->query('SELECT `players`.`id` as `id`, `guild_members`.`rank_id` as `rank_id` FROM `players`, `guild_members` WHERE `guild_members`.`rank_id` = ' . $rank_in_guild->getId() . ' AND `players`.`id` = `guild_members`.`player_id` ORDER BY `name`;'); $players_with_rank = $db->query('SELECT `players`.`id` as `id`, `guild_members`.`rank_id` as `rank_id` FROM `players`, `guild_members` WHERE `guild_members`.`rank_id` = ' . $rank_in_guild->getId() . ' AND `players`.`id` = `guild_members`.`player_id` AND `' . $deletedColumn . '` = 0 ORDER BY `name`;');
else if($db->hasTable('guild_membership')) else if($db->hasTable('guild_membership'))
$players_with_rank = $db->query('SELECT `players`.`id` as `id`, `guild_membership`.`rank_id` as `rank_id` FROM `players`, `guild_membership` WHERE `guild_membership`.`rank_id` = ' . $rank_in_guild->getId() . ' AND `players`.`id` = `guild_membership`.`player_id` ORDER BY `name`;'); $players_with_rank = $db->query('SELECT `players`.`id` as `id`, `guild_membership`.`rank_id` as `rank_id` FROM `players`, `guild_membership` WHERE `guild_membership`.`rank_id` = ' . $rank_in_guild->getId() . ' AND `players`.`id` = `guild_membership`.`player_id` AND `' . $deletedColumn . '` = 0 ORDER BY `name`;');
else else
$players_with_rank = $db->query('SELECT `id`, `rank_id` FROM `players` WHERE `rank_id` = ' . $rank_in_guild->getId() . ' AND `deleted` = 0;'); $players_with_rank = $db->query('SELECT `id`, `rank_id` FROM `players` WHERE `rank_id` = ' . $rank_in_guild->getId() . ' AND `' . $deletedColumn . '` = 0;');
$players_with_rank_number = $players_with_rank->rowCount(); $players_with_rank_number = $players_with_rank->rowCount();
if($players_with_rank_number > 0) { if($players_with_rank_number > 0) {
@@ -510,10 +517,24 @@ function template_place_holder($type): string
$ret .= $debugBarRenderer->renderHead(); $ret .= $debugBarRenderer->renderHead();
} }
} }
elseif ($type === 'head_end') {
$ret .= setting('core.html_head');
}
elseif ($type === 'body_start') { elseif ($type === 'body_start') {
$ret .= setting('core.html_body');
$ret .= $twig->render('browsehappy.html.twig'); $ret .= $twig->render('browsehappy.html.twig');
if (admin()) {
global $account_logged;
$ret .= $twig->render('admin-bar.html.twig', [
'username' => USE_ACCOUNT_NAME ? $account_logged->getName() : $account_logged->getId()
]);
}
} }
elseif($type === 'body_end') { elseif($type === 'body_end') {
$ret .= setting('core.html_footer');
$ret .= template_ga_code(); $ret .= template_ga_code();
if (isset($debugBar)) { if (isset($debugBar)) {
$ret .= $debugBarRenderer->render(); $ret .= $debugBarRenderer->render();
@@ -767,6 +788,10 @@ function formatExperience($exp, $color = true)
return $ret; return $ret;
} }
function getExperienceForLevel($level): float|int {
return ( 50 / 3 ) * pow( $level, 3 ) - ( 100 * pow( $level, 2 ) ) + ( ( 850 / 3 ) * $level ) - 200;
}
function get_locales() function get_locales()
{ {
$ret = array(); $ret = array();
@@ -861,11 +886,12 @@ function getWorldName($id)
* *
* @param string $to Recipient email address. * @param string $to Recipient email address.
* @param string $subject Subject of the message. * @param string $subject Subject of the message.
* @param string $body Message body in html format. * @param string $body Message body in HTML format.
* @param string $altBody Alternative message body, plain text. * @param string $altBody Alternative message body, plain text.
* @return bool PHPMailer status returned (success/failure). * @return bool PHPMailer status returned (success/failure).
* @throws \PHPMailer\PHPMailer\Exception
*/ */
function _mail($to, $subject, $body, $altBody = '', $add_html_tags = true) function _mail(string $to, string $subject, string $body, string $altBody = ''): bool
{ {
global $mailer, $config; global $mailer, $config;
@@ -883,12 +909,6 @@ function _mail($to, $subject, $body, $altBody = '', $add_html_tags = true)
$mailer->clearAllRecipients(); $mailer->clearAllRecipients();
} }
$signature_html = setting('core.mail_signature_html');
if($add_html_tags && isset($body[0]))
$tmp_body = '<html><head></head><body>' . $body . '<br/><br/>' . $signature_html . '</body></html>';
else
$tmp_body = $body . '<br/><br/>' . $signature_html;
$mailOption = setting('core.mail_option'); $mailOption = setting('core.mail_option');
if($mailOption == MAIL_SMTP) if($mailOption == MAIL_SMTP)
{ {
@@ -915,6 +935,9 @@ function _mail($to, $subject, $body, $altBody = '', $add_html_tags = true)
$mailer->isMail(); $mailer->isMail();
} }
$signature_html = setting('core.mail_signature_html');
$tmp_body = $body . '<br/><br/>' . $signature_html;
$mailer->isHTML(isset($body[0]) > 0); $mailer->isHTML(isset($body[0]) > 0);
$mailer->From = setting('core.mail_address'); $mailer->From = setting('core.mail_address');
$mailer->Sender = setting('core.mail_address'); $mailer->Sender = setting('core.mail_address');
@@ -964,85 +987,6 @@ function log_append($file, $str, array $params = [])
fclose($f); fclose($f);
} }
function load_config_lua($filename)
{
global $config;
$config_file = $filename;
if(!@file_exists($config_file))
{
log_append('error.log', '[load_config_file] Fatal error: Cannot load config.lua (' . $filename . ').');
throw new RuntimeException('ERROR: Cannot find ' . $filename . ' file.');
}
$result = array();
$config_string = str_replace(array("\r\n", "\r"), "\n", file_get_contents($filename));
$lines = explode("\n", $config_string);
if(count($lines) > 0) {
foreach($lines as $ln => $line)
{
$line = trim($line);
if(isset($line[0]) && ($line[0] === '{' || $line[0] === '}')) {
// arrays are not supported yet
// just ignore the error
continue;
}
$tmp_exp = explode('=', $line, 2);
if(str_contains($line, 'dofile')) {
$delimiter = '"';
if(!str_contains($line, $delimiter)) {
$delimiter = "'";
}
$tmp = explode($delimiter, $line);
$result = array_merge($result, load_config_lua($config['server_path'] . $tmp[1]));
}
else if(count($tmp_exp) >= 2) {
$key = trim($tmp_exp[0]);
if(!str_starts_with($key, '--')) {
$value = trim($tmp_exp[1]);
if(str_contains($value, '--')) {// found some deep comment
$value = preg_replace('/--.*$/i', '', $value);
}
if(is_numeric($value))
$result[$key] = (float) $value;
elseif(in_array(@$value[0], array("'", '"')) && in_array(@$value[strlen($value) - 1], array("'", '"')))
$result[$key] = substr(substr($value, 1), 0, -1);
elseif(in_array($value, array('true', 'false')))
$result[$key] = $value === 'true';
elseif(@$value[0] === '{') {
// arrays are not supported yet
// just ignore the error
continue;
}
else
{
foreach($result as $tmp_key => $tmp_value) { // load values defined by other keys, like: dailyFragsToBlackSkull = dailyFragsToRedSkull
$value = str_replace($tmp_key, $tmp_value, $value);
}
try {
$ret = eval("return $value;");
}
catch (Throwable $e) {
throw new RuntimeException('ERROR: Loading config.lua file. Line: ' . ($ln + 1) . ' - Unable to parse value "' . $value . '" - ' . $e->getMessage());
}
if((string) $ret == '' && trim($value) !== '""') {
throw new RuntimeException('ERROR: Loading config.lua file. Line ' . ($ln + 1) . ' is not valid [key: ' . $key . ']');
}
$result[$key] = $ret;
}
}
}
}
}
return array_merge($result, $config['lua'] ?? []);
}
function str_replace_first($search,$replace, $subject) { function str_replace_first($search,$replace, $subject) {
$pos = strpos($subject, $search); $pos = strpos($subject, $search);
if ($pos !== false) { if ($pos !== false) {
@@ -1118,11 +1062,44 @@ function csrfProtect(): void
} }
} }
function getTopPlayers($limit = 5, $skill = 'level') { function getSkillIdByName(string $name): int|null
{
$skills = [
'level' => POT::SKILL_LEVEL,
'experience' => POT::SKILL_LEVEL,
'magic' => POT::SKILL_MAGIC,
'maglevel' => POT::SKILL_MAGIC,
'balance' => SKILL_BALANCE,
'frags' => SKILL_FRAGS,
'club' => POT::SKILL_CLUB,
'sword' => POT::SKILL_SWORD,
'axe' => POT::SKILL_AXE,
'dist' => POT::SKILL_DIST,
'distance' => POT::SKILL_DIST,
'shield' => POT::SKILL_SHIELD,
'shielding' => POT::SKILL_SHIELD,
'fish' => POT::SKILL_FISH,
'fishing' => POT::SKILL_FISH,
];
return $skills[$name] ?? null;
}
function getTopPlayers($limit = 5, $skill = POT::SKILL_LEVEL)
{
global $db; global $db;
if ($skill === 'level') { $skillOriginal = $skill;
$skill = 'experience';
if (is_string($skill)) {
$skill = getSkillIdByName($skill);
}
if (!is_numeric($skill)) {
throw new RuntimeException("getTopPlayers: Invalid skill: $skillOriginal");
} }
return Cache::remember("top_{$limit}_{$skill}", 2 * 60, function () use ($db, $limit, $skill) { return Cache::remember("top_{$limit}_{$skill}", 2 * 60, function () use ($db, $limit, $skill) {
@@ -1131,19 +1108,76 @@ function getTopPlayers($limit = 5, $skill = 'level') {
'looktype', 'lookhead', 'lookbody', 'looklegs', 'lookfeet' 'looktype', 'lookhead', 'lookbody', 'looklegs', 'lookfeet'
]; ];
if ($db->hasColumn('players', 'promotion')) {
$columns[] = 'promotion';
}
if ($db->hasColumn('players', 'lookaddons')) { if ($db->hasColumn('players', 'lookaddons')) {
$columns[] = 'lookaddons'; $columns[] = 'lookaddons';
} }
return Player::query() if ($db->hasColumn('players', 'lookmount')) {
$columns[] = 'lookmount';
}
$query = Player::query()
->select($columns) ->select($columns)
->withOnlineStatus() ->withOnlineStatus()
->notDeleted() ->notDeleted()
->where('group_id', '<', setting('core.highscores_groups_hidden')) ->where('group_id', '<', setting('core.highscores_groups_hidden'))
->whereNotIn('id', setting('core.highscores_ids_hidden')) ->whereNotIn('id', setting('core.highscores_ids_hidden'))
->where('account_id', '!=', 1) ->where('account_id', '!=', 1)
->orderByDesc($skill) ->orderByDesc('value');
->limit($limit)
if ($limit > 0) {
$query->limit($limit);
}
if ($skill >= POT::SKILL_FIRST && $skill <= POT::SKILL_LAST) { // skills
if ($db->hasColumn('players', 'skill_fist')) {// tfs 1.0
$skill_ids = array(
POT::SKILL_FIST => 'skill_fist',
POT::SKILL_CLUB => 'skill_club',
POT::SKILL_SWORD => 'skill_sword',
POT::SKILL_AXE => 'skill_axe',
POT::SKILL_DIST => 'skill_dist',
POT::SKILL_SHIELD => 'skill_shielding',
POT::SKILL_FISH => 'skill_fishing',
);
$query
->addSelect($skill_ids[$skill] . ' as value')
->orderByDesc($skill_ids[$skill] . '_tries');
} else {
$query
->join('player_skills', 'player_skills.player_id', '=', 'players.id')
->where('skillid', $skill)
->addSelect('player_skills.value as value');
}
} else if ($skill == SKILL_FRAGS) // frags
{
if ($db->hasTable('player_killers')) {
$query->addSelect(['value' => PlayerKillers::whereColumn('player_killers.player_id', 'players.id')->selectRaw('COUNT(*)')]);
} else {
$query->addSelect(['value' => PlayerDeath::unjustified()->whereColumn('player_deaths.killed_by', 'players.name')->selectRaw('COUNT(*)')]);
}
} else if ($skill == SKILL_BALANCE) // balance
{
$query
->addSelect('players.balance as value');
} else {
if ($skill == POT::SKILL_MAGIC) {
$query
->addSelect('players.maglevel as value', 'players.maglevel')
->orderByDesc('manaspent');
} else { // level
$query
->addSelect('players.level as value', 'players.experience')
->orderByDesc('experience');
}
}
return $query
->get() ->get()
->map(function ($e, $i) { ->map(function ($e, $i) {
$row = $e->toArray(); $row = $e->toArray();
@@ -1158,7 +1192,8 @@ function getTopPlayers($limit = 5, $skill = 'level') {
}); });
} }
function deleteDirectory($dir, $ignore = array(), $contentOnly = false) { function deleteDirectory($dir, $ignore = array(), $contentOnly = false): bool
{
if(!file_exists($dir)) { if(!file_exists($dir)) {
return true; return true;
} }
@@ -1184,6 +1219,21 @@ function deleteDirectory($dir, $ignore = array(), $contentOnly = false) {
return rmdir($dir); return rmdir($dir);
} }
function ensureFolderExists($dir): void
{
if (!file_exists($dir)) {
mkdir($dir, 0777, true);
}
}
function ensureIndexExists($dir): void
{
$dir = rtrim($dir, '/');
if (!file_exists($file = $dir . '/index.html')) {
touch($file);
}
}
function config($key) { function config($key) {
global $config; global $config;
if (is_array($key)) { if (is_array($key)) {
@@ -1196,15 +1246,6 @@ function config($key) {
return @$config[$key]; return @$config[$key];
} }
function configLua($key) {
global $config;
if (is_array($key)) {
return $config['lua'][$key[0]] = $key[1];
}
return @$config['lua'][$key];
}
function setting($key) function setting($key)
{ {
$settings = Settings::getInstance(); $settings = Settings::getInstance();
@@ -1217,7 +1258,8 @@ function setting($key)
return $settings[$key[0]] = $key[1]; return $settings[$key[0]] = $key[1];
} }
return $settings[$key]['value']; $ret = $settings[$key];
return isset($ret) ? $ret['value'] : null;
} }
function clearCache() function clearCache()
@@ -1339,17 +1381,7 @@ function getCustomPage($name, &$success): string
ob_end_clean(); ob_end_clean();
} }
else { else {
$oldLoader = $twig->getLoader(); $content .= $twig->renderInline($page['body']);
$twig_loader_array = new Twig_ArrayLoader(array(
'content.html' => $page['body']
));
$twig->setLoader($twig_loader_array);
$content .= $twig->render('content.html');
$twig->setLoader($oldLoader);
} }
} }
@@ -1520,58 +1552,6 @@ function verify_number($number, $name, $max_length)
echo_error($name . ' cannot be longer than ' . $max_length . ' digits.'); echo_error($name . ' cannot be longer than ' . $max_length . ' digits.');
} }
function Outfits_loadfromXML()
{
global $config;
$file_path = $config['data_path'] . 'XML/outfits.xml';
if (!file_exists($file_path)) { return null; }
$xml = new DOMDocument;
$xml->load($file_path);
$outfits = null;
foreach ($xml->getElementsByTagName('outfit') as $outfit) {
$outfits[] = Outfit_parseNode($outfit);
}
return $outfits;
}
function Outfit_parseNode($node) {
$looktype = (int)$node->getAttribute('looktype');
$type = (int)$node->getAttribute('type');
$lookname = $node->getAttribute('name');
$premium = $node->getAttribute('premium');
$unlocked = $node->getAttribute('unlocked');
$enabled = $node->getAttribute('enabled');
return array('id' => $looktype, 'type' => $type, 'name' => $lookname, 'premium' => $premium, 'unlocked' => $unlocked, 'enabled' => $enabled);
}
function Mounts_loadfromXML()
{
global $config;
$file_path = $config['data_path'] . 'XML/mounts.xml';
if (!file_exists($file_path)) { return null; }
$xml = new DOMDocument;
$xml->load($file_path);
$mounts = null;
foreach ($xml->getElementsByTagName('mount') as $mount) {
$mounts[] = Mount_parseNode($mount);
}
return $mounts;
}
function Mount_parseNode($node) {
$id = (int)$node->getAttribute('id');
$clientid = (int)$node->getAttribute('clientid');
$name = $node->getAttribute('name');
$speed = (int)$node->getAttribute('speed');
$premium = $node->getAttribute('premium');
$type = $node->getAttribute('type');
return array('id' => $id, 'clientid' => $clientid, 'name' => $name, 'speed' => $speed, 'premium' => $premium, 'type' => $type);
}
function left($str, $length) { function left($str, $length) {
return substr($str, 0, $length); return substr($str, 0, $length);
} }
@@ -1620,13 +1600,14 @@ function camelCaseToUnderscore($input)
return ltrim(strtolower(preg_replace('/[A-Z]([A-Z](?![a-z]))*/', '_$0', $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) { if(strpos($text, '/') === 0) {
$text = str_replace_first('/', '', $text); $text = str_replace_first('/', '', $text);
} }
}; };
function escapeHtml($html) { function escapeHtml($html): string {
return htmlspecialchars($html); return htmlspecialchars($html);
} }
@@ -1640,7 +1621,7 @@ function getGuildNameById($id)
return false; return false;
} }
function getGuildLogoById($id) function getGuildLogoById($id): string
{ {
$logo = 'default.gif'; $logo = 'default.gif';
@@ -1656,7 +1637,8 @@ function getGuildLogoById($id)
return BASE_URL . GUILD_IMAGES_DIR . $logo; return BASE_URL . GUILD_IMAGES_DIR . $logo;
} }
function displayErrorBoxWithBackButton($errors, $action = null) { function displayErrorBoxWithBackButton($errors, $action = null): void
{
global $twig; global $twig;
$twig->display('error_box.html.twig', ['errors' => $errors]); $twig->display('error_box.html.twig', ['errors' => $errors]);
$twig->display('account.back_button.html.twig', [ $twig->display('account.back_button.html.twig', [
@@ -1684,6 +1666,49 @@ function getAccountIdentityColumn(): string
return 'id'; return 'id';
} }
function isCanary(): bool
{
$dataPackDirectory = configLua('dataPackDirectory');
return isset($dataPackDirectory);
}
function getStatusUptimeReadable(int $uptime): string
{
$fullMinute = 60;
$fullHour = (60 * $fullMinute);
$fullDay = (24 * $fullHour);
$fullMonth = (30 * $fullDay);
$fullYear = (365 * $fullDay);
// years
$years = floor($uptime / $fullYear);
$y = ($years > 1 ? "$years years, " : ($years == 1 ? 'year, ' : ''));
$uptime -= $years * $fullYear;
// months
$months = floor($uptime / $fullMonth);
$m = ($months > 1 ? "$months months, " : ($months == 1 ? 'month, ' : ''));
$uptime -= $months * $fullMonth;
// days
$days = floor($uptime / $fullDay);
$d = ($days > 1 ? "$days days, " : ($days == 1 ? 'day, ' : ''));
$uptime -= $days * $fullDay;
// hours
$hours = floor($uptime / $fullHour);
$uptime -= $hours * $fullHour;
// minutes
$min = floor($uptime / $fullMinute);
return "{$y}{$m}{$d}{$hours}h {$min}m";
}
// validator functions // validator functions
require_once SYSTEM . 'compat/base.php'; require_once SYSTEM . 'compat/base.php';

View File

@@ -14,10 +14,15 @@ use MyAAC\CsrfToken;
use MyAAC\Hooks; use MyAAC\Hooks;
use MyAAC\Plugins; use MyAAC\Plugins;
use MyAAC\Models\Town; use MyAAC\Models\Town;
use MyAAC\Server\Config;
use MyAAC\Server\Vocations;
use MyAAC\Settings; use MyAAC\Settings;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
ensureIndexExists(CACHE);
ensureIndexExists(CACHE . 'twig/');
global $config; global $config;
if(!isset($config['installed']) || !$config['installed']) { if(!isset($config['installed']) || !$config['installed']) {
throw new RuntimeException('MyAAC has not been installed yet or there was error during installation. Please install again.'); throw new RuntimeException('MyAAC has not been installed yet or there was error during installation. Please install again.');
@@ -86,28 +91,20 @@ foreach($_REQUEST as $var => $value) {
} }
// load otserv config file // load otserv config file
$config_lua_reload = true;
if($cache->enabled()) { if($cache->enabled()) {
$tmp = null; $tmp = null;
if($cache->fetch('server_path', $tmp) && $tmp == $config['server_path']) { if(!$cache->fetch('server_path', $tmp) || $tmp != config('server_path')) {
$tmp = null; $cache->delete('config_server');
if($cache->fetch('config_lua', $tmp) && $tmp) {
$config['lua'] = unserialize($tmp);
$config_lua_reload = false;
}
} }
} }
if($config_lua_reload) { if (empty($config['server'])) {
$config['lua'] = load_config_lua($config['server_path'] . 'config.lua'); $config['server'] = $config['lua'] = Config::get();
// cache config
if($cache->enabled()) { if($cache->enabled()) {
$cache->set('config_lua', serialize($config['lua']), 2 * 60); $cache->set('server_path', config('server_path'), 10 * 60);
$cache->set('server_path', $config['server_path'], 10 * 60);
} }
} }
unset($tmp);
if(isset($config['lua']['servername'])) if(isset($config['lua']['servername']))
$config['lua']['serverName'] = $config['lua']['servername']; $config['lua']['serverName'] = $config['lua']['servername'];
@@ -144,6 +141,15 @@ $ots = POT::getInstance();
$eloquentConnection = null; $eloquentConnection = null;
require_once SYSTEM . 'database.php'; require_once SYSTEM . 'database.php';
define('USE_ACCOUNT_NAME', $db->hasColumn('accounts', 'name'));
define('USE_ACCOUNT_NUMBER', $db->hasColumn('accounts', 'number'));
define('USE_ACCOUNT_SALT', $db->hasColumn('accounts', 'salt'));
define('HAS_ACCOUNT_COINS', $db->hasColumn('accounts', 'coins'));
define('HAS_ACCOUNT_COINS_TRANSFERABLE', $db->hasColumn('accounts', 'coins_transferable'));
define('HAS_ACCOUNT_TRANSFERABLE_COINS', $db->hasColumn('accounts', 'transferable_coins'));
const ACCOUNT_COINS_TRANSFERABLE_COLUMN = (HAS_ACCOUNT_COINS_TRANSFERABLE ? 'coins_transferable' : 'transferable_coins');
$twig->addGlobal('logged', false); $twig->addGlobal('logged', false);
$twig->addGlobal('account_logged', new \OTS_Account()); $twig->addGlobal('account_logged', new \OTS_Account());
@@ -188,10 +194,6 @@ if($settingsItemImagesURL[strlen($settingsItemImagesURL) - 1] !== '/') {
setting(['core.item_images_url', $settingsItemImagesURL . '/']); setting(['core.item_images_url', $settingsItemImagesURL . '/']);
} }
define('USE_ACCOUNT_NAME', $db->hasColumn('accounts', 'name'));
define('USE_ACCOUNT_NUMBER', $db->hasColumn('accounts', 'number'));
define('USE_ACCOUNT_SALT', $db->hasColumn('accounts', 'salt'));
$towns = Cache::remember('towns', 10 * 60, function () use ($db) { $towns = Cache::remember('towns', 10 * 60, function () use ($db) {
if ($db->hasTable('towns') && Town::count() > 0) { if ($db->hasTable('towns') && Town::count() > 0) {
return Town::orderBy('id', 'ASC')->pluck('name', 'id')->toArray(); return Town::orderBy('id', 'ASC')->pluck('name', 'id')->toArray();
@@ -206,3 +208,5 @@ if (count($towns) <= 0) {
config(['towns', $towns]); config(['towns', $towns]);
unset($towns); unset($towns);
new Vocations();

View File

@@ -12,6 +12,9 @@
* @license http://www.gnu.org/licenses/lgpl-3.0.txt GNU Lesser General Public License, Version 3 * @license http://www.gnu.org/licenses/lgpl-3.0.txt GNU Lesser General Public License, Version 3
*/ */
use MyAAC\Models\Account as AccountModel;
use MyAAC\Models\AccountAction;
/** /**
* OTServ account abstraction. * OTServ account abstraction.
* *
@@ -40,7 +43,11 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable
*/ */
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(); private array $columns = ['password', 'email', 'rlname', 'location', 'country', 'web_flags', 'created'];
private array $optionalColumns = ['name', 'number', 'lastday', 'premdays', 'premium_ends_at', 'premend'];
public static array $cache = [];
const GRATIS_PREMIUM_DAYS = 65535; const GRATIS_PREMIUM_DAYS = 65535;
/** /**
@@ -325,27 +332,50 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable
*/ */
public function save() public function save()
{ {
if( !isset($this->data['id']) ) if (!isset($this->data['id'])) {
{
throw new E_OTS_NotLoaded(); throw new E_OTS_NotLoaded();
} }
$field = 'lastday'; $defaultValues = [
if($this->db->hasColumn('accounts', 'premend')) { // othire 'premium_ends_at' => 0,
$field = 'premend'; 'lastday' => 0,
if(!isset($this->data['premend'])) { 'premend' => 0,
$this->data['premend'] = 0; 'premdays' => 0,
} ];
}
else if($this->db->hasColumn('accounts', 'premium_ends_at')) { foreach ($defaultValues as $key => $value) {
$field = 'premium_ends_at'; if (!isset($this->data[$key])) {
if(!isset($this->data['premium_ends_at'])) { $this->data[$key] = $value;
$this->data['premium_ends_at'] = 0;
} }
} }
// UPDATE query on database $columns = $this->columns;
$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']); foreach ($this->optionalColumns as $column) {
if ($this->db->hasColumn('accounts', $column)) {
$columns[] = $column;
}
}
$values = [];
foreach ($columns as $column) {
$value = $this->data[$column];
$values[$column] = $value;
}
// updates existing player
if( isset($this->data['id']) ) {
AccountModel::where('id', $this->data['id'])->update($values);
}
// creates new player
else {
$values['created'] = time();
$account = AccountModel::create($values);
// ID of new player
$this->data['id'] = $account->id;
}
} }
/** /**
@@ -443,8 +473,9 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable
throw new E_OTS_NotLoaded(); throw new E_OTS_NotLoaded();
} }
if(isset($this->data['premium_ends_at']) || isset($this->data['premend'])) { if(isset($this->data['premium_ends_at']) || isset($this->data['premend']) ||
$col = isset($this->data['premium_ends_at']) ? 'premium_ends_at' : 'premend'; (isCanary() && isset($this->data['lastday']))) {
$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)); $ret = ceil(($this->data[$col] - time()) / (24 * 60 * 60));
return max($ret, 0); return max($ret, 0);
} }
@@ -471,17 +502,16 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable
return $this->data['lastday']; return $this->data['lastday'];
} }
public function isPremium() public function isPremium(): bool
{ {
global $config; if(isset($this->data['premium_ends_at']) || isset($this->data['premend']) ||
if(isset($config['lua']['freePremium']) && getBoolean($config['lua']['freePremium'])) return true; (isCanary() && isset($this->data['lastday']))) {
$col = (isset($this->data['premium_ends_at']) ? 'premium_ends_at' : (isset($this->data['lastday']) ? 'lastday' : 'premend'));
if(isset($this->data['premium_ends_at'])) { return $this->data[$col] > time();
return $this->data['premium_ends_at'] > time();
} }
if(isset($this->data['premend'])) { if($this->data['premdays'] == self::GRATIS_PREMIUM_DAYS){
return $this->data['premend'] > time(); return true;
} }
return ($this->data['premdays'] - (date("z", time()) + (365 * (date("Y", time()) - date("Y", $this->data['lastday']))) - date("z", $this->data['lastday'])) > 0); return ($this->data['premdays'] - (date("z", time()) + (365 * (date("Y", time()) - date("Y", $this->data['lastday']))) - date("z", $this->data['lastday'])) > 0);
@@ -504,11 +534,17 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable
* @since 0.7.5 * @since 0.7.5
* @throws E_OTS_NotLoaded If account is not loaded. * @throws E_OTS_NotLoaded If account is not loaded.
*/ */
public function setPremDays($premdays) public function setPremDays($premdays): void
{ {
$this->data['premdays'] = (int) $premdays; $this->data['premdays'] = (int) $premdays;
$this->data['premend'] = time() + ($premdays * 24 * 60 * 60);
$this->data['premium_ends_at'] = time() + ($premdays * 24 * 60 * 60); $premiumTimeInSeconds = time() + ($premdays * 24 * 60 * 60);
$this->data['premend'] = $premiumTimeInSeconds;
$this->data['premium_ends_at'] = $premiumTimeInSeconds;
if (isCanary()) {
$this->data['lastday'] = $premiumTimeInSeconds;
}
} }
public function setRLName($name) public function setRLName($name)
@@ -1007,26 +1043,16 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable
public function logAction($action) public function logAction($action)
{ {
$ip = get_browser_real_ip(); AccountAction::create([
if(!str_contains($ip, ":")) { 'account_id' => $this->getId(),
$ipv6 = '0'; 'ip' => get_browser_real_ip(),
} 'date' => time(),
else { 'action' => $action,
$ipv6 = $ip; ]);
$ip = '';
} }
return $this->db->exec('INSERT INTO `' . TABLE_PREFIX . 'account_actions` (`account_id`, `ip`, `ipv6`, `date`, `action`) VALUES (' . $this->db->quote($this->getId()).', ' . ($ip == '' ? '0' : $this->db->quote(ip2long($ip))) . ', (' . ($ipv6 == '0' ? $this->db->quote('') : $this->db->quote(inet_pton($ipv6))) . '), UNIX_TIMESTAMP(NOW()), ' . $this->db->quote($action).')'); public function getActionsLog($limit) {
} return AccountAction::where('account_id', $this->data['id'])->orderByDesc('date')->limit($limit)->get()->toArray();
public function getActionsLog($limit1, $limit2)
{
$actions = array();
foreach($this->db->query('SELECT `ip`, `ipv6`, `date`, `action` FROM `' . TABLE_PREFIX . 'account_actions` WHERE `account_id` = ' . $this->data['id'] . ' ORDER by `date` DESC LIMIT ' . $limit1 . ', ' . $limit2 . '')->fetchAll() as $a)
$actions[] = array('ip' => $a['ip'], 'ipv6' => $a['ipv6'], 'date' => $a['date'], 'action' => $a['action']);
return $actions;
} }
/** /**
* Returns players iterator. * Returns players iterator.

View File

@@ -26,10 +26,12 @@ use MyAAC\Cache\Cache;
*/ */
class OTS_DB_MySQL extends OTS_Base_DB class OTS_DB_MySQL extends OTS_Base_DB
{ {
private $has_table_cache = array(); private bool $hasCacheChanged = false;
private $has_column_cache = array(); private array $has_table_cache = [];
private array $has_column_cache = [];
private array $get_column_info_cache = [];
private $clearCacheAfter = false; private bool $clearCacheAfter = false;
/** /**
* Creates database connection. * Creates database connection.
* *
@@ -119,6 +121,11 @@ class OTS_DB_MySQL extends OTS_Base_DB
if($cache->fetch('database_columns', $tmp) && $tmp) { if($cache->fetch('database_columns', $tmp) && $tmp) {
$this->has_column_cache = unserialize($tmp); $this->has_column_cache = unserialize($tmp);
} }
$tmp = null;
if($cache->fetch('database_columns_info', $tmp) && $tmp) {
$this->get_column_info_cache = unserialize($tmp);
}
} }
} }
@@ -155,11 +162,13 @@ class OTS_DB_MySQL extends OTS_Base_DB
if ($this->clearCacheAfter) { if ($this->clearCacheAfter) {
$cache->delete('database_tables'); $cache->delete('database_tables');
$cache->delete('database_columns'); $cache->delete('database_columns');
$cache->delete('database_columns_info');
$cache->delete('database_checksum'); $cache->delete('database_checksum');
} }
else { else if ($this->hasCacheChanged) {
$cache->set('database_tables', serialize($this->has_table_cache), 3600); $cache->set('database_tables', serialize($this->has_table_cache), 3600);
$cache->set('database_columns', serialize($this->has_column_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); $cache->set('database_checksum', serialize(sha1($config['database_host'] . '.' . $config['database_name'])), 3600);
} }
} }
@@ -209,7 +218,8 @@ class OTS_DB_MySQL extends OTS_Base_DB
return $sql; return $sql;
} }
public function hasTable($name) { public function hasTable($name): bool
{
if(isset($this->has_table_cache[$name])) { if(isset($this->has_table_cache[$name])) {
return $this->has_table_cache[$name]; return $this->has_table_cache[$name];
} }
@@ -217,12 +227,15 @@ class OTS_DB_MySQL extends OTS_Base_DB
return $this->hasTableInternal($name); return $this->hasTableInternal($name);
} }
private function hasTableInternal($name) { private function hasTableInternal($name): bool
global $config; {
return ($this->has_table_cache[$name] = $this->query('SELECT `TABLE_NAME` FROM `information_schema`.`tables` WHERE `TABLE_SCHEMA` = ' . $this->quote($config['database_name']) . ' AND `TABLE_NAME` = ' . $this->quote($name) . ' LIMIT 1;')->rowCount() > 0); $this->hasCacheChanged = true;
return ($this->has_table_cache[$name] = $this->query('SELECT `TABLE_NAME` FROM `information_schema`.`tables` WHERE `TABLE_SCHEMA` = ' . $this->quote(config('database_name')) . ' AND `TABLE_NAME` = ' . $this->quote($name) . ' LIMIT 1;')->rowCount() > 0);
} }
public function hasColumn($table, $column) { public function hasColumn($table, $column): bool
{
if(isset($this->has_column_cache[$table . '.' . $column])) { if(isset($this->has_column_cache[$table . '.' . $column])) {
return $this->has_column_cache[$table . '.' . $column]; return $this->has_column_cache[$table . '.' . $column];
} }
@@ -230,8 +243,10 @@ class OTS_DB_MySQL extends OTS_Base_DB
return $this->hasColumnInternal($table, $column); return $this->hasColumnInternal($table, $column);
} }
private function hasColumnInternal($table, $column) { private function hasColumnInternal($table, $column): bool {
return $this->hasTable($table) && ($this->has_column_cache[$table . '.' . $column] = count($this->query('SHOW COLUMNS FROM `' . $table . "` LIKE '" . $column . "'")->fetchAll()) > 0); $this->hasCacheChanged = true;
return $this->hasTable($table) && ($this->has_column_cache[$table . '.' . $column] = count($this->query('SHOW COLUMNS FROM `' . $table . "` LIKE " . $this->quote($column))->fetchAll()) > 0);
} }
public function hasTableAndColumns(string $table, array $columns = []): bool public function hasTableAndColumns(string $table, array $columns = []): bool
@@ -247,7 +262,56 @@ class OTS_DB_MySQL extends OTS_Base_DB
return true; return true;
} }
public function revalidateCache() { public function getColumnInfo(string $table, string $column): bool|array
{
if(isset($this->get_column_info_cache[$table . '.' . $column])) {
return $this->get_column_info_cache[$table . '.' . $column];
}
return $this->getColumnInfoInternal($table, $column);
}
private function getColumnInfoInternal(string $table, string $column): bool|array
{
if (!$this->hasTable($table) || !$this->hasColumn($table, $column)) {
return false;
}
$this->hasCacheChanged = true;
$formatResult = function ($result) {
return [
'field' => $result['Field'],
'type' => $result['Type'],
'null' => strtolower($result['Null']),
'key' => strtolower($result['Key'] ?? ''),
'default' => $result['Default'],
'extra' => $result['Extra'],
];
};
$query = $this->query('SHOW COLUMNS FROM `' . $table . "` LIKE " . $this->quote($column));
$rowCount = $query->rowCount();
if ($rowCount > 1) {
$tmp = [];
$results = $query->fetchAll(PDO::FETCH_ASSOC);
foreach ($results as $result) {
$tmp[] = $formatResult($result);
}
return ($this->get_column_info_cache[$table . '.' . $column] = $tmp);
}
else if ($rowCount == 1) {
$result = $query->fetch(PDO::FETCH_ASSOC);
return ($this->get_column_info_cache[$table . '.' . $column] = $formatResult($result));
}
return [];
}
public function revalidateCache(): void
{
foreach($this->has_table_cache as $key => $value) { foreach($this->has_table_cache as $key => $value) {
$this->hasTableInternal($key); $this->hasTableInternal($key);
} }
@@ -262,6 +326,21 @@ class OTS_DB_MySQL extends OTS_Base_DB
$this->hasColumnInternal($explode[0], $explode[1]); $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) public function setClearCacheAfter($clearCache)

View File

@@ -8,7 +8,7 @@
* @license http://www.gnu.org/licenses/lgpl-3.0.txt GNU Lesser General Public License, Version 3 * @license http://www.gnu.org/licenses/lgpl-3.0.txt GNU Lesser General Public License, Version 3
*/ */
use MyAAC\Cache\Cache; use MyAAC\Server\Groups;
/** /**
* List of groups. * List of groups.
@@ -47,73 +47,8 @@ class OTS_Groups_List implements IteratorAggregate, Countable
return; return;
} }
if(!isset($file[0])) foreach(Groups::get() as $id => $info) {
{ $this->groups[$id] = new OTS_Group($info);
global $config;
$file = $config['data_path'] . 'XML/groups.xml';
}
if(!@file_exists($file)) {
error('Error: Cannot load groups.xml. More info in system/logs/error.log file.');
log_append('error.log', '[OTS_Groups_List.php] Fatal error: Cannot load groups.xml (' . $file . '). It doesnt exist.');
return;
}
$cache = Cache::getInstance();
$data = array();
if($cache->enabled())
{
$tmp = '';
if($cache->fetch('groups', $tmp))
$data = unserialize($tmp);
else
{
$groups = new DOMDocument();
if(!@$groups->load($file)) {
error('Error: Cannot load groups.xml. More info in system/logs/error.log file.');
log_append('error.log', '[OTS_Groups_List.php] Fatal error: Cannot load groups.xml (' . $file . '). Error: ' . print_r(error_get_last(), true));
return;
}
// loads groups
foreach( $groups->getElementsByTagName('group') as $group)
{
$data[$group->getAttribute('id')] = array(
'id' => $group->getAttribute('id'),
'name' => $group->getAttribute('name'),
'access' => $group->getAttribute('access')
);
}
$cache->set('groups', serialize($data), 120);
}
foreach($data as $id => $info)
$this->groups[ $id ] = new OTS_Group($info);
}
else
{
// loads DOM document
$groups = new DOMDocument();
if(!@$groups->load($file)) {
error('Error: Cannot load groups.xml. More info in system/logs/error.log file.');
log_append('error.log', '[OTS_Groups_List.php] Fatal error: Cannot load groups.xml (' . $file . '). Error: ' . print_r(error_get_last(), true));
return;
}
// loads groups
foreach($groups->getElementsByTagName('group') as $group)
{
$data[$group->getAttribute('id')] = array(
'id' => $group->getAttribute('id'),
'name' => $group->getAttribute('name'),
'access' => $group->getAttribute('access')
);
$this->groups[ $group->getAttribute('id') ] = new OTS_Group($data[$group->getAttribute('id')]);
//echo $this->getGroup(1)->getName();
}
} }
} }

View File

@@ -1,20 +1,6 @@
<?php <?php
$__load = array();
/* use MyAAC\Models\Player as PlayerModel;
'loss_experience' => NULL,
'loss_items' => NULL,
'guild_info' => NULL,
'skull_type' => NULL,
'skull_time' => NULL,
'blessings' => NULL,
'direction' => NULL,
'stamina' => NULL,
'world_id' => NULL,
'online' => NULL,
'deletion' => NULL,
'promotion' => NULL,
'marriage' => NULL
);*/
/**#@+ /**#@+
* @version 0.0.1 * @version 0.0.1
@@ -109,6 +95,10 @@ class OTS_Player extends OTS_Row_DAO
POT::SKILL_FISH => array('value' => 0, 'tries' => 0) POT::SKILL_FISH => array('value' => 0, 'tries' => 0)
); );
private array $columns = ['name', 'account_id', 'group_id', 'sex', 'vocation', 'experience', 'level', 'maglevel', 'health', 'healthmax', 'mana', 'manamax', 'manaspent', 'soul', 'lookbody', 'lookfeet', 'lookhead', 'looklegs', 'looktype', 'posx', 'posy', 'posz', 'lastlogin', 'lastlogout', 'lastip', 'town_id', 'balance', 'created', 'comment', 'hide'];
private array $optionalColumns = ['cap', 'skull', 'skull_type', 'skull_time', 'loss_experience', 'loss_mana', 'loss_skills', 'loss_items', 'loss_containers', 'guildnick', 'rank_id', 'promotion', 'direction', 'blessings', 'stamina', 'lookaddons', 'save', 'conditions', 'world_id', 'online', 'deletion', 'deleted', 'marriage'];
private static array $playersOnline; private static array $playersOnline;
/** /**
* Magic PHP5 method. * Magic PHP5 method.
@@ -133,90 +123,14 @@ class OTS_Player extends OTS_Row_DAO
*/ */
public function load($id, $fields = null, $load_skills = true) public function load($id, $fields = null, $load_skills = true)
{ {
global $__load; $columns = $this->columns;
foreach ($this->optionalColumns as $column) {
if(!isset($__load['loss_experience'])) if ($this->db->hasColumn('players', $column)) {
{ $columns[] = $column;
$loss = '';
if($this->db->hasColumn('players', 'loss_experience')) {
$loss = ', `loss_experience`, `loss_mana`, `loss_skills`';
} }
$__load['loss_experience'] = $loss;
}
if(!isset($__load['loss_items']))
{
$loss_items = '';
if($this->db->hasColumn('players', 'loss_items')) {
$loss_items = ', `loss_items`, `loss_containers`';
}
$__load['loss_items'] = $loss_items;
}
if(!isset($__load['guild_info']))
{
$guild_info = '';
if(!$this->db->hasTable('guild_members') && $this->db->hasColumn('players', 'guildnick')) {
$guild_info = ', `guildnick`, `rank_id`';
}
$__load['guild_info'] = $guild_info;
}
if(!isset($__load['skull_type']))
{
$skull_type = 'skull';
if($this->db->hasColumn('players', 'skull_type')) {
$skull_type = 'skull_type';
}
$__load['skull_type'] = $skull_type;
}
if(!isset($__load['skull_time']))
{
$skull_time = 'skulltime';
if($this->db->hasColumn('players', 'skull_time')) {
$skull_time = 'skull_time';
}
$__load['skull_time'] = $skull_time;
}
if(!isset($__load['blessings'])) {
$__load['blessings'] = $this->db->hasColumn('players', 'blessings');
}
if(!isset($__load['direction'])) {
$__load['direction'] = $this->db->hasColumn('players', 'direction');
}
if(!isset($__load['stamina'])) {
$__load['stamina'] = $this->db->hasColumn('players', 'stamina');
}
if(!isset($__load['world_id'])) {
$__load['world_id'] = $this->db->hasColumn('players', 'world_id');
}
if(!isset($__load['online'])) {
$__load['online'] = $this->db->hasColumn('players', 'online');
}
if(!isset($__load['deletion'])) {
$__load['deletion'] = $this->db->hasColumn('players', 'deletion');
}
if(!isset($__load['promotion'])) {
$__load['promotion'] = $this->db->hasColumn('players', 'promotion');
}
if(!isset($__load['marriage'])) {
$__load['marriage'] = $this->db->hasColumn('players', 'marriage');
} }
if(isset($fields)) { // load only what we wish if(isset($fields)) { // load only what we wish
if(in_array('promotion', $fields)) {
if(!$this->db->hasColumn('players', 'promotion')) {
unset($fields[array_search('promotion', $fields)]);
}
}
if(in_array('deleted', $fields)) { if(in_array('deleted', $fields)) {
if($this->db->hasColumn('players', 'deletion')) { if($this->db->hasColumn('players', 'deletion')) {
unset($fields[array_search('deleted', $fields)]); unset($fields[array_search('deleted', $fields)]);
@@ -224,21 +138,21 @@ class OTS_Player extends OTS_Row_DAO
} }
} }
if(in_array('online', $fields)) { $columns = [];
if(!$this->db->hasColumn('players', 'online')) { foreach ($fields as $field) {
unset($fields[array_search('online', $fields)]); if ($this->db->hasColumn('players', $field)) {
$columns[] = $field;
} }
} }
$this->data = $this->db->query('SELECT ' . implode(', ', $fields) . ' FROM `players` WHERE `id` = ' . (int)$id)->fetch();
}
else {
// SELECT query on database
$this->data = $this->db->query('SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`' . ($this->db->hasColumn('players', 'lookaddons') ? ', `lookaddons`' : '') . ', `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `save`, `conditions`, `' . $__load['skull_time'] . '` as `skulltime`, `' . $__load['skull_type'] . '` as `skull`' . $__load['guild_info'] . ', `town_id`' . $__load['loss_experience'] . $__load['loss_items'] . ', `balance`' . ($__load['blessings'] ? ', `blessings`' : '') . ($__load['direction'] ? ', `direction`' : '') . ($__load['stamina'] ? ', `stamina`' : '') . ($__load['world_id'] ? ', `world_id`' : '') . ($__load['online'] ? ', `online`' : '') . ', `' . ($__load['deletion'] ? 'deletion' : 'deleted') . '`' . ($__load['promotion'] ? ', `promotion`' : '') . ($__load['marriage'] ? ', `marriage`' : '') . ', `comment`, `created`, `hide` FROM `players` WHERE `id` = ' . (int)$id)->fetch();
} }
array_unshift($columns, 'id');
$query = PlayerModel::where('id', $id)->first($columns);
$this->data = $query ? $query->toArray() : [];
// loads skills // loads skills
if( $this->isLoaded() && $load_skills) if( $this->isLoaded() && $load_skills) {
{
if($this->db->hasColumn('players', 'skill_fist')) { if($this->db->hasColumn('players', 'skill_fist')) {
$skill_ids = array( $skill_ids = array(
@@ -318,153 +232,65 @@ class OTS_Player extends OTS_Row_DAO
*/ */
public function save() public function save()
{ {
$skull_type = 'skull'; $defaultValues = [
if($this->db->hasColumn('players', 'skull_type')) { 'cap' => 0,
$skull_type = 'skull_type'; 'skull' => 0,
'skull_type' => 0,
'skull_time' => 0,
'loss_experience' => 100,
'loss_mana' => 100,
'loss_skills' => 100,
'loss_items' => 100,
'loss_containers' => 100,
'guildnick' => '',
'rank_id' => 0,
'promotion' => 0,
'direction' => 0,
'blessings' => 0,
'stamina' => 0,
'lookaddons' => 0,
'save' => 1,
'conditions' => '',
'town_id' => 1,
'world_id' => 1,
'online' => 0,
'deletion' => 0,
'deleted' => 0,
'marriage' => 0,
];
foreach ($defaultValues as $key => $value) {
if (!isset($this->data[$key])) {
$this->data[$key] = $value;
}
} }
$skull_time = 'skulltime'; $columns = $this->columns;
if($this->db->hasColumn('players', 'skull_time')) { foreach ($this->optionalColumns as $column) {
$skull_time = 'skull_time'; if ($this->db->hasColumn('players', $column)) {
$columns[] = $column;
}
} }
if(!isset($this->data['loss_experience'])) $values = [];
$this->data['loss_experience'] = 100; foreach ($columns as $column) {
$value = $this->data[$column];
if(!isset($this->data['loss_mana'])) $values[$column] = $value;
$this->data['loss_mana'] = 100; }
if(!isset($this->data['loss_skills']))
$this->data['loss_skills'] = 100;
if(!isset($this->data['loss_items']))
$this->data['loss_items'] = 10;
if(!isset($this->data['loss_containers']))
$this->data['loss_containers'] = 100;
if(!isset($this->data['guildnick']))
$this->data['guildnick'] = '';
if(!isset($this->data['rank_id']))
$this->data['rank_id'] = 0;
if(!isset($this->data['promotion']))
$this->data['promotion'] = 0;
if(!isset($this->data['direction']))
$this->data['direction'] = 0;
if(!isset($this->data['conditions']))
$this->data['conditions'] = '';
if(!isset($this->data['town_id']))
$this->data['town_id'] = 1;
// updates existing player // updates existing player
if( isset($this->data['id']) ) if( isset($this->data['id']) ) {
{ PlayerModel::where('id', $this->data['id'])->update($values);
$loss = '';
if($this->db->hasColumn('players', 'loss_experience')) {
$loss = ', `loss_experience` = ' . $this->data['loss_experience'] . ', `loss_mana` = ' . $this->data['loss_mana'] . ', `loss_skills` = ' . $this->data['loss_skills'];
}
$loss_items = '';
if($this->db->hasColumn('players', 'loss_items')) {
$loss_items = ', `loss_items` = ' . $this->data['loss_items'] . ', `loss_containers` = ' . $this->data['loss_containers'];
}
$guild_info = '';
if(!$this->db->hasTable('guild_members') && $this->db->hasColumn('players', 'guildnick')) {
$guild_info = ', `guildnick` = ' . $this->db->quote($this->data['guildnick']) . ', ' . $this->db->fieldName('rank_id') . ' = ' . $this->data['rank_id'];
}
$direction = '';
if($this->db->hasColumn('players', 'direction')) {
$direction = ', `direction` = ' . $this->db->quote($this->data['direction']);
}
$blessings = '';
if($this->db->hasColumn('players', 'blessings')) {
$blessings = ', `blessings` = ' . $this->db->quote($this->data['blessings']);
}
$stamina = '';
if($this->db->hasColumn('players', 'stamina')) {
$stamina = ', `stamina` = ' . $this->db->quote($this->data['stamina']);
}
$lookaddons = '';
if($this->db->hasColumn('players', 'lookaddons')) {
$lookaddons = ', `lookaddons` = ' . $this->db->quote($this->data['lookaddons']);
}
// UPDATE query on database
$this->db->query('UPDATE ' . $this->db->tableName('players') . ' SET ' . $this->db->fieldName('name') . ' = ' . $this->db->quote($this->data['name']) . ', ' . $this->db->fieldName('account_id') . ' = ' . $this->data['account_id'] . ', ' . $this->db->fieldName('group_id') . ' = ' . $this->data['group_id'] . ', ' . $this->db->fieldName('sex') . ' = ' . $this->data['sex'] . ', ' . $this->db->fieldName('vocation') . ' = ' . $this->data['vocation'] . ', ' . $this->db->fieldName('experience') . ' = ' . $this->data['experience'] . ', ' . $this->db->fieldName('level') . ' = ' . $this->data['level'] . ', ' . $this->db->fieldName('maglevel') . ' = ' . $this->data['maglevel'] . ', ' . $this->db->fieldName('health') . ' = ' . $this->data['health'] . ', ' . $this->db->fieldName('healthmax') . ' = ' . $this->data['healthmax'] . ', ' . $this->db->fieldName('mana') . ' = ' . $this->data['mana'] . ', ' . $this->db->fieldName('manamax') . ' = ' . $this->data['manamax'] . ', ' . $this->db->fieldName('manaspent') . ' = ' . $this->data['manaspent'] . ', ' . $this->db->fieldName('soul') . ' = ' . $this->data['soul'] . ', ' . $this->db->fieldName('lookbody') . ' = ' . $this->data['lookbody'] . ', ' . $this->db->fieldName('lookfeet') . ' = ' . $this->data['lookfeet'] . ', ' . $this->db->fieldName('lookhead') . ' = ' . $this->data['lookhead'] . ', ' . $this->db->fieldName('looklegs') . ' = ' . $this->data['looklegs'] . ', ' . $this->db->fieldName('looktype') . ' = ' . $this->data['looktype'] . $lookaddons . ', ' . $this->db->fieldName('posx') . ' = ' . $this->data['posx'] . ', ' . $this->db->fieldName('posy') . ' = ' . $this->data['posy'] . ', ' . $this->db->fieldName('posz') . ' = ' . $this->data['posz'] . ', ' . $this->db->fieldName('cap') . ' = ' . $this->data['cap'] . ', ' . $this->db->fieldName('lastlogin') . ' = ' . $this->data['lastlogin'] . ', ' . $this->db->fieldName('lastlogout') . ' = ' . $this->data['lastlogout'] . ', ' . $this->db->fieldName('lastip') . ' = ' . $this->db->quote($this->data['lastip']) . ', ' . $this->db->fieldName('save') . ' = ' . (int) $this->data['save'] . ', ' . $this->db->fieldName('conditions') . ' = ' . $this->db->quote($this->data['conditions']) . ', `' . $skull_time . '` = ' . $this->data['skulltime'] . ', `' . $skull_type . '` = ' . (int) $this->data['skull'] . $guild_info . ', ' . $this->db->fieldName('town_id') . ' = ' . $this->data['town_id'] . $loss . $loss_items . ', ' . $this->db->fieldName('balance') . ' = ' . $this->data['balance'] . $blessings . $stamina . $direction . ' WHERE ' . $this->db->fieldName('id') . ' = ' . $this->data['id']);
} }
// creates new player // creates new player
else else {
{ $values['created'] = time();
$loss = '';
$loss_data = '';
if($this->db->hasColumn('players', 'loss_experience')) {
$loss = ', `loss_experience`, `loss_mana`, `loss_skills`';
$loss_data = ', ' . $this->data['loss_experience'] . ', ' . $this->data['loss_mana'] . ', ' . $this->data['loss_skills'];
}
$loss_items = ''; $player = PlayerModel::create($values);
$loss_items_data = '';
if($this->db->hasColumn('players', 'loss_items')) {
$loss_items = ', `loss_items`, `loss_containers`';
$loss_items_data = ', ' . $this->data['loss_items'] . ', ' . $this->data['loss_containers'];
}
$guild_info = ''; // ID of new player
$guild_info_data = ''; $this->data['id'] = $player->id;
if(!$this->db->hasTable('guild_members') && $this->db->hasColumn('players', 'guildnick')) {
$guild_info = ', `guildnick`, `rank_id`';
$guild_info_data = ', ' . $this->db->quote($this->data['guildnick']) . ', ' . $this->data['rank_id'];
}
$promotion = '';
$promotion_data = '';
if($this->db->hasColumn('players', 'promotion')) {
$promotion = ', `promotion`';
$promotion_data = ', ' . $this->data['promotion'];
}
$direction = '';
$direction_data = '';
if($this->db->hasColumn('players', 'direction')) {
$direction = ', `direction`';
$direction_data = ', ' . $this->data['direction'];
}
$blessings = '';
$blessings_data = '';
if($this->db->hasColumn('players', 'blessings')) {
$blessings = ', `blessings`';
$blessings_data = ', ' . $this->data['blessings'];
}
$stamina = '';
$stamina_data = '';
if($this->db->hasColumn('players', 'stamina')) {
$stamina = ', `stamina`';
$stamina_data = ', ' . $this->data['stamina'];
}
$lookaddons = '';
$lookaddons_data = '';
if($this->db->hasColumn('players', 'lookaddons')) {
$lookaddons = ', `lookaddons`';
$lookaddons_data = ', ' . $this->data['lookaddons'];
}
// INSERT query on database
$this->db->query('INSERT INTO `players` (`name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`' . $lookaddons . ', `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `save`, `conditions`, `' . $skull_time . '`, `' . $skull_type . '`' . $guild_info . ', `town_id`' . $loss . $loss_items . ', `balance`' . $blessings . $stamina . $direction . ', `created`' . $promotion . ', `comment`) VALUES (' . $this->db->quote($this->data['name']) . ', ' . $this->data['account_id'] . ', ' . $this->data['group_id'] . ', ' . $this->data['sex'] . ', ' . $this->data['vocation'] . ', ' . $this->data['experience'] . ', ' . $this->data['level'] . ', ' . $this->data['maglevel'] . ', ' . $this->data['health'] . ', ' . $this->data['healthmax'] . ', ' . $this->data['mana'] . ', ' . $this->data['manamax'] . ', ' . $this->data['manaspent'] . ', ' . $this->data['soul'] . ', ' . $this->data['lookbody'] . ', ' . $this->data['lookfeet'] . ', ' . $this->data['lookhead'] . ', ' . $this->data['looklegs'] . ', ' . $this->data['looktype'] . $lookaddons_data . ', ' . $this->data['posx'] . ', ' . $this->data['posy'] . ', ' . $this->data['posz'] . ', ' . $this->data['cap'] . ', ' . $this->data['lastlogin'] . ', ' . $this->data['lastlogout'] . ', ' . $this->data['lastip'] . ', ' . (int) $this->data['save'] . ', ' . $this->db->quote($this->data['conditions']) . ', ' . $this->data['skulltime'] . ', ' . (int) $this->data['skull'] . $guild_info_data . ', ' . $this->data['town_id'] . $loss_data . $loss_items_data . ', ' . $this->data['balance'] . $blessings_data . $stamina_data . $direction_data . ', ' . time() . $promotion_data . ', "")');
// ID of new group
$this->data['id'] = $this->db->lastInsertId();
} }
// updates skills - doesn't matter if we have just created character - trigger inserts new skills // updates skills - doesn't matter if we have just created character - trigger inserts new skills
@@ -490,7 +316,7 @@ class OTS_Player extends OTS_Row_DAO
$set .= ','; $set .= ',';
} }
$skills = $this->db->query('UPDATE `players` SET ' . $set . ' WHERE `id` = ' . $this->data['id']); $this->db->query('UPDATE `players` SET ' . $set . ' WHERE `id` = ' . $this->data['id']);
} }
else if($this->db->hasTable('player_skills')) { else if($this->db->hasTable('player_skills')) {
foreach($this->skills as $id => $skill) foreach($this->skills as $id => $skill)
@@ -748,21 +574,25 @@ class OTS_Player extends OTS_Row_DAO
public function isDeleted() public function isDeleted()
{ {
$field = 'deleted'; $column = 'deleted';
if($this->db->hasColumn('players', 'deletion')) if($this->db->hasColumn('players', 'deletion'))
$field = 'deletion'; $column = 'deletion';
if( !isset($this->data[$field]) ) if( !isset($this->data[$column]) )
{ {
throw new E_OTS_NotLoaded(); throw new E_OTS_NotLoaded();
} }
return $this->data[$field] > 0; return $this->data[$column] > 0;
} }
public function setDeleted($deleted) public function setDeleted($deleted)
{ {
$this->data['deleted'] = (int) $deleted; $column = 'deleted';
if($this->db->hasColumn('players', 'deletion'))
$column = 'deletion';
$this->data[$column] = (int) $deleted;
} }
public function isOnline() public function isOnline()
@@ -852,13 +682,7 @@ class OTS_Player extends OTS_Row_DAO
throw new E_OTS_NotLoaded(); throw new E_OTS_NotLoaded();
} }
if(isset($this->data['promotion'])) { return \OTS_Toolbox::getVocationFromPromotion($this->data['vocation'], $this->data['promotion'] ?? 0);
global $config;
if((int)$this->data['promotion'] > 0)
return ($this->data['vocation'] + ($this->data['promotion'] * $config['vocations_amount']));
}
return $this->data['vocation'];
} }
@@ -1574,12 +1398,7 @@ class OTS_Player extends OTS_Row_DAO
*/ */
public function getCap() public function getCap()
{ {
if( !isset($this->data['cap']) ) return $this->data['cap'] ?? 0;
{
throw new E_OTS_NotLoaded();
}
return $this->data['cap'];
} }
/** /**
@@ -1792,12 +1611,12 @@ class OTS_Player extends OTS_Row_DAO
*/ */
public function getSkullTime() public function getSkullTime()
{ {
if( !isset($this->data['skulltime']) ) $column = 'skulltime';
{ if($this->db->hasColumn('players', 'skull_time')) {
throw new E_OTS_NotLoaded(); $column = 'skull_time';
} }
return $this->data['skulltime']; return $this->data[$column] ?? 0;
} }
/** /**
@@ -1811,7 +1630,12 @@ class OTS_Player extends OTS_Row_DAO
*/ */
public function setSkullTime($skulltime) public function setSkullTime($skulltime)
{ {
$this->data['skulltime'] = (int) $skulltime; $column = 'skulltime';
if($this->db->hasColumn('players', 'skull_time')) {
$column = 'skull_time';
}
$this->data[$column] = (int) $skulltime;
} }
/** /**
@@ -3250,6 +3074,10 @@ class OTS_Player extends OTS_Row_DAO
return 0; return 0;
} }
public function setData(array $data): void{
$this->data = $data;
}
/** /**
* Magic PHP5 method. * Magic PHP5 method.
* *

View File

@@ -97,6 +97,8 @@ class OTS_ServerInfo
return new OTS_Buffer($data); return new OTS_Buffer($data);
} }
log_append('status-error.log', "Cannot connect to {$this->server}:{$this->port} - Error code: $error, message: $message");
return false; return false;
} }

View File

@@ -13,6 +13,8 @@
* @license http://www.gnu.org/licenses/lgpl-3.0.txt GNU Lesser General Public License, Version 3 * @license http://www.gnu.org/licenses/lgpl-3.0.txt GNU Lesser General Public License, Version 3
*/ */
use MyAAC\Server\XML\Vocations;
/** /**
* Toolbox for common operations. * Toolbox for common operations.
* *
@@ -110,14 +112,21 @@ class OTS_Toolbox
$list->setFilter($filter); $list->setFilter($filter);
return $list; return $list;
} }
public static function getVocationFromPromotion($id, $promotion = 0): int
public static function getVocationName($id, $promotion = 0): string
{ {
if($promotion > 0) { if($promotion > 0) {
$id = ($id + ($promotion * config('vocations_amount'))); for ($i = 0; $i < $promotion; $i++) {
if ($_id = Vocations::getPromoted($id)) {
$id = $_id;
}
}
} }
return config('vocations')[$id] ?? 'Unknown'; return $id;
}
public static function getVocationName($id, $promotion = 0): string {
return config('vocations')[self::getVocationFromPromotion($id, $promotion)] ?? 'Unknown';
} }
} }

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';
@@ -67,7 +67,7 @@ $locale['step_database'] = 'Schema importieren';
$locale['step_database_title'] = 'MySQL schema importieren'; $locale['step_database_title'] = 'MySQL schema importieren';
$locale['step_database_importing'] = 'Ihre Datenbank ist MySQL. Datenbankname ist: "$DATABASE_NAME$". Schema wird jetzt importiert...'; $locale['step_database_importing'] = 'Ihre Datenbank ist MySQL. Datenbankname ist: "$DATABASE_NAME$". Schema wird jetzt importiert...';
$locale['step_database_error_path'] = 'Bitte geben Sie den Serverpfad an.'; $locale['step_database_error_path'] = 'Bitte geben Sie den Serverpfad an.';
$locale['step_database_error_config'] = 'Datei config.lua kann nicht gefunden werden. Ist der Serverpfad korrekt? Gehen Sie zurück und überprüfen Sie noch einmal.'; $locale['step_database_error_config'] = 'Datei config.lua oder config/server.toml kann nicht gefunden werden. Ist der Serverpfad korrekt? Gehen Sie zurück und überprüfen Sie noch einmal.';
$locale['step_database_error_database_empty'] = 'Der Datenbanktyp kann nicht aus config.lua ermittelt werden. Ihr OTS wird von diesem AAC nicht unterstützt.'; $locale['step_database_error_database_empty'] = 'Der Datenbanktyp kann nicht aus config.lua ermittelt werden. Ihr OTS wird von diesem AAC nicht unterstützt.';
$locale['step_database_error_only_mysql'] = 'Dieser AAC unterstützt nur MySQL. Aus Ihrer Konfigurationsdatei scheint Ihr OTS die Datenbank $DATABASE_TYPE$ zu verwenden. Bitte ändern Sie Ihre Datenbank in MySQL und folgen Sie dann der Installation erneut.'; $locale['step_database_error_only_mysql'] = 'Dieser AAC unterstützt nur MySQL. Aus Ihrer Konfigurationsdatei scheint Ihr OTS die Datenbank $DATABASE_TYPE$ zu verwenden. Bitte ändern Sie Ihre Datenbank in MySQL und folgen Sie dann der Installation erneut.';
$locale['step_database_error_table'] = 'Die Tabelle $TABLE$ existiert nicht. Bitte importieren Sie zuerst Ihr OTS-Datenbankschema.'; $locale['step_database_error_table'] = 'Die Tabelle $TABLE$ existiert nicht. Bitte importieren Sie zuerst Ihr OTS-Datenbankschema.';
@@ -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_mysql_connect_4'] = 'MySQL-Server läuft nicht.';
$locale['step_database_error_schema'] = 'Fehler beim Importieren des Schemas:'; $locale['step_database_error_schema'] = 'Fehler beim Importieren des Schemas:';
$locale['step_database_success_schema'] = '$PREFIX$ Tabellen wurden erfolgreich installiert.'; $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_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_adding_field'] = 'Folgendes Feld wurde hinzugefügt: ';
$locale['step_database_modifying_field'] = 'Folgendes Feld wurde geändert: '; $locale['step_database_modifying_field'] = 'Folgendes Feld wurde geändert: ';

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';
@@ -72,7 +72,7 @@ $locale['step_database_title'] = 'Import MySQL schema';
$locale['step_database_importing'] = 'Your database is MySQL. Database name is: "$DATABASE_NAME$". Importing schema now...'; $locale['step_database_importing'] = 'Your database is MySQL. Database name is: "$DATABASE_NAME$". Importing schema now...';
$locale['step_database_config_saved'] = 'Local configuration has been saved into file: config.local.php'; $locale['step_database_config_saved'] = 'Local configuration has been saved into file: config.local.php';
$locale['step_database_error_path'] = 'Please specify server path.'; $locale['step_database_error_path'] = 'Please specify server path.';
$locale['step_database_error_config'] = 'Cannot find config.lua file. Is your server path correct? Go back and check again.'; $locale['step_database_error_config'] = 'Cannot find config.lua or config/server.toml file. Is your server path correct? Go back and check again.';
$locale['step_database_error_database_empty'] = 'Cannot determine database type from config.lua. Your OTS is unsupported by this AAC.'; $locale['step_database_error_database_empty'] = 'Cannot determine database type from config.lua. Your OTS is unsupported by this AAC.';
$locale['step_database_error_only_mysql'] = 'This AAC supports only MySQL. From your config file it seems that your OTS is using: $DATABASE_TYPE$ database. Please change your database to MySQL and then follow the installation again.'; $locale['step_database_error_only_mysql'] = 'This AAC supports only MySQL. From your config file it seems that your OTS is using: $DATABASE_TYPE$ database. Please change your database to MySQL and then follow the installation again.';
$locale['step_database_error_table'] = 'Table $TABLE$ doesn\'t exist. Please import your OTS database schema first.'; $locale['step_database_error_table'] = 'Table $TABLE$ doesn\'t exist. Please import your OTS database schema first.';
@@ -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_mysql_connect_4'] = 'MySQL server is not running.';
$locale['step_database_error_schema'] = 'Error while importing schema:'; $locale['step_database_error_schema'] = 'Error while importing schema:';
$locale['step_database_success_schema'] = 'Successfully installed $PREFIX$ tables.'; $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_error_file'] = '$FILE$ couldn\'t be opened. Please copy this content and paste there:';
$locale['step_database_adding_field'] = 'Adding field'; $locale['step_database_adding_field'] = 'Adding field';
$locale['step_database_modifying_field'] = 'Modifying field'; $locale['step_database_modifying_field'] = 'Modifying field';

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';
@@ -71,7 +71,7 @@ $locale['step_database_title'] = 'Baza MySQL';
$locale['step_database_importing'] = 'Twoja baza to MySQL. Nazwa bazy danych to: "$DATABASE_NAME$". Importowanie schematu...'; $locale['step_database_importing'] = 'Twoja baza to MySQL. Nazwa bazy danych to: "$DATABASE_NAME$". Importowanie schematu...';
$locale['step_database_config_saved'] = 'Lokalna konfiguracja została zapisana do pliku: config.local.php'; $locale['step_database_config_saved'] = 'Lokalna konfiguracja została zapisana do pliku: config.local.php';
$locale['step_database_error_path'] = 'Proszę podać ścieżkę do serwera.'; $locale['step_database_error_path'] = 'Proszę podać ścieżkę do serwera.';
$locale['step_database_error_config'] = 'Nie można znaleźć pliku config.lua. Czy ścieżka do katalogu serwera jest poprawna? Wróć się i sprawdź ponownie.'; $locale['step_database_error_config'] = 'Nie można znaleźć pliku config.lua lub config/server.toml. Czy ścieżka do katalogu serwera jest poprawna? Wróć się i sprawdź ponownie.';
$locale['step_database_error_database_empty'] = 'Nie można wykryć typu bazy danych z pliku config.lua. Prawdopodobnie Twój OTS nie jest wspierany przez ten AAC.'; $locale['step_database_error_database_empty'] = 'Nie można wykryć typu bazy danych z pliku config.lua. Prawdopodobnie Twój OTS nie jest wspierany przez ten AAC.';
$locale['step_database_error_only_mysql'] = 'Ten AAC wspiera tylko bazy danych MySQL. Z Twojego pliku config wynika, że Twój serwera używa bazy: $DATABASE_TYPE$. Proszę zmienić typ bazy na MySQL i ponownie przystąpić do instalacji.'; $locale['step_database_error_only_mysql'] = 'Ten AAC wspiera tylko bazy danych MySQL. Z Twojego pliku config wynika, że Twój serwera używa bazy: $DATABASE_TYPE$. Proszę zmienić typ bazy na MySQL i ponownie przystąpić do instalacji.';
$locale['step_database_error_table'] = 'Tabela $TABLE$ nie istnieje. Proszę najpierw zaimportować schemat bazy danych serwera OTS.'; $locale['step_database_error_table'] = 'Tabela $TABLE$ nie istnieje. Proszę najpierw zaimportować schemat bazy danych serwera OTS.';
@@ -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 <i>config.lua</i>.'; $locale['step_database_error_mysql_connect_3'] = 'MySQL nie jest poprawnie skonfigurowane w <i>config.lua</i>.';
$locale['step_database_error_mysql_connect_4'] = 'Serwer MySQL nie jest uruchomiony.'; $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_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_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_adding_field'] = 'Dodawanie pola';
$locale['step_database_modifying_field'] = 'Modyfikacja pola'; $locale['step_database_modifying_field'] = 'Modyfikacja pola';

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';
@@ -61,7 +61,7 @@ $locale['step_database'] = 'Importar schema';
$locale['step_database_title'] = 'Importar MySQL schema'; $locale['step_database_title'] = 'Importar MySQL schema';
$locale['step_database_importing'] = 'Seu banco de dados é o MySQL. O nome do banco de dados é: "$DATABASE_NAME$". Importando schema agora...'; $locale['step_database_importing'] = 'Seu banco de dados é o MySQL. O nome do banco de dados é: "$DATABASE_NAME$". Importando schema agora...';
$locale['step_database_error_path'] = 'Por favor, especifique o caminho da pasta do servidor.'; $locale['step_database_error_path'] = 'Por favor, especifique o caminho da pasta do servidor.';
$locale['step_database_error_config'] = 'Não é possível encontrar o arquivo config.lua. O caminho da pasta do seu servidor está correto? Volte e verifique novamente.'; $locale['step_database_error_config'] = 'Não é possível encontrar o arquivo config.lua ou config/server.toml. O caminho da pasta do seu servidor está correto? Volte e verifique novamente.';
$locale['step_database_error_database_empty'] = 'Não é possível determinar o tipo de banco de dados a partir do config.lua. Seu OTS não é suportado por este AAC.'; $locale['step_database_error_database_empty'] = 'Não é possível determinar o tipo de banco de dados a partir do config.lua. Seu OTS não é suportado por este AAC.';
$locale['step_database_error_only_mysql'] = 'Este AAC suporta apenas o MySQL. A partir do seu arquivo de configuração, parece que o seu OTS está usando: $DATABASE_TYPE$ database. Por favor, mude seu banco de dados para o MySQL e siga a instalação novamente.'; $locale['step_database_error_only_mysql'] = 'Este AAC suporta apenas o MySQL. A partir do seu arquivo de configuração, parece que o seu OTS está usando: $DATABASE_TYPE$ database. Por favor, mude seu banco de dados para o MySQL e siga a instalação novamente.';
$locale['step_database_error_table'] = 'A tabela $TABLE$ não existe. Por favor, importe seu schema de banco de dados OTS primeiro.'; $locale['step_database_error_table'] = 'A tabela $TABLE$ não existe. Por favor, importe seu schema de banco de dados OTS primeiro.';

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

@@ -34,8 +34,10 @@ if($logged) {
$twig->addGlobal('account_logged', $account_logged); $twig->addGlobal('account_logged', $account_logged);
} }
setSession('last_visit', time()); if (!defined('IGNORE_SET_LAST_VISIT') || !IGNORE_SET_LAST_VISIT) {
if(defined('PAGE')) { setSession('last_visit', time());
if(defined('PAGE')) {
setSession('last_page', PAGE); setSession('last_page', PAGE);
}
setSession('last_uri', $_SERVER['REQUEST_URI']);
} }
setSession('last_uri', $_SERVER['REQUEST_URI']);

View File

@@ -9,6 +9,8 @@
*/ */
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
global $db;
// database migrations // database migrations
$tmp = ''; $tmp = '';
if(fetchDatabaseConfig('database_version', $tmp)) { // we got version if(fetchDatabaseConfig('database_version', $tmp)) { // we got version

View File

@@ -1,5 +1,6 @@
<?php <?php
use MyAAC\Models\Player as PlayerModel;
use MyAAC\Settings; use MyAAC\Settings;
function updateHighscoresIdsHidden(): void function updateHighscoresIdsHidden(): void
@@ -10,12 +11,22 @@ function updateHighscoresIdsHidden(): void
return; return;
} }
$query = $db->query("SELECT `id` FROM `players` WHERE (`name` = " . $db->quote("Rook Sample") . " OR `name` = " . $db->quote("Sorcerer Sample") . " OR `name` = " . $db->quote("Druid Sample") . " OR `name` = " . $db->quote("Paladin Sample") . " OR `name` = " . $db->quote("Knight Sample") . " OR `name` = " . $db->quote("Account Manager") . ") ORDER BY `id`;"); $players = PlayerModel::where('name', 'Rook Sample')
->orWhere('name', 'Sorcerer Sample')
->orWhere('name', 'Druid Sample')
->orWhere('name', 'Paladin Sample')
->orWhere('name', 'Knight Sample')
->orWhere('name', 'Monk Sample')
->orWhere('name', 'Account Manager')
->orderBy('id')
->select('id')
->get();
$highscores_ignored_ids = array(); $highscores_ignored_ids = [];
if ($query->rowCount() > 0) { if (count($players) > 0) {
foreach ($query->fetchAll() as $result) foreach ($players as $result) {
$highscores_ignored_ids[] = $result['id']; $highscores_ignored_ids[] = $result->id;
}
} else { } else {
$highscores_ignored_ids[] = 0; $highscores_ignored_ids[] = 0;
} }

View File

@@ -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;

24
system/migrations/46.php Normal file
View File

@@ -0,0 +1,24 @@
<?php
/**
* @var OTS_DB_MySQL $db
*/
$up = function () use ($db) {
if ($db->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');
}
};

42
system/migrations/47.php Normal file
View File

@@ -0,0 +1,42 @@
<?php
/**
* @var OTS_DB_MySQL $db
*/
// 2025-02-27
// remove ipv6, change to ip (for both ipv4 + ipv6) as VARCHAR(45)
$up = function () use ($db) {
$accountActionsInfo = $db->getColumnInfo(TABLE_PREFIX . 'account_actions', 'account_id');
if ($accountActionsInfo && is_array($accountActionsInfo) && $accountActionsInfo['key'] == 'pri') {
$db->query("ALTER TABLE `myaac_account_actions` DROP KEY `account_id`;");
}
if (!$db->hasColumn(TABLE_PREFIX . 'account_actions', 'id')) {
$db->addColumn(TABLE_PREFIX . 'account_actions', 'id', 'INT NOT NULL AUTO_INCREMENT FIRST, ADD PRIMARY KEY (`id`)');
}
$db->modifyColumn(TABLE_PREFIX . 'account_actions', 'ip', "VARCHAR(45) NOT NULL DEFAULT ''");
$db->query("UPDATE `" . TABLE_PREFIX . "account_actions` SET `ip` = INET_NTOA(`ip`) WHERE `ip` != '0';");
$db->query("UPDATE `" . TABLE_PREFIX . "account_actions` SET `ip` = INET6_NTOA(`ipv6`) WHERE `ip` = '0';");
if ($db->hasColumn(TABLE_PREFIX . 'account_actions', 'ipv6')) {
$db->dropColumn(TABLE_PREFIX . 'account_actions', 'ipv6');
}
};
$down = function () use ($db) {
if ($db->hasColumn(TABLE_PREFIX . 'account_actions', 'id')) {
$db->query("ALTER TABLE `" . TABLE_PREFIX . "account_actions` DROP `id`;");
}
$db->query("ALTER TABLE `" . TABLE_PREFIX . "account_actions` ADD KEY (`account_id`);");
if (!$db->hasColumn(TABLE_PREFIX . 'account_actions', 'ipv6')) {
$db->addColumn(TABLE_PREFIX . 'account_actions', 'ipv6', "BINARY(16) NOT NULL DEFAULT 0x00000000000000000000000000000000 AFTER ip");
}
$db->query("UPDATE `" . TABLE_PREFIX . "account_actions` SET `ipv6` = INET6_ATON(ip) WHERE NOT IS_IPV4(`ip`);");
$db->query("UPDATE `" . TABLE_PREFIX . "account_actions` SET `ip` = INET_ATON(`ip`) WHERE IS_IPV4(`ip`);");
$db->query("UPDATE `" . TABLE_PREFIX . "account_actions` SET `ip` = 0 WHERE `ipv6` != 0x00000000000000000000000000000000;");
$db->modifyColumn(TABLE_PREFIX . 'account_actions', 'ip', "INT(11) UNSIGNED NOT NULL DEFAULT 0;");
};

16
system/migrations/48.php Normal file
View File

@@ -0,0 +1,16 @@
<?php
/**
* @var OTS_DB_MySQL $db
*/
$up = function () use ($db) {
if (!$db->hasColumn(TABLE_PREFIX . 'menu', 'access')) {
$db->addColumn(TABLE_PREFIX . 'menu', 'access', 'TINYINT NOT NULL DEFAULT 0 AFTER `link`');
}
};
$down = function () use ($db) {
if ($db->hasColumn(TABLE_PREFIX . 'menu', 'access')) {
$db->dropColumn(TABLE_PREFIX . 'menu', 'access');
}
};

91
system/migrations/49.php Normal file
View File

@@ -0,0 +1,91 @@
<?php
/**
* @var OTS_DB_MySQL $db
*/
use MyAAC\Models\Account as AccountModel;
$time = time();
$accountId = getSession('account') ?? 1;
if (!defined('MYAAC_INSTALL')) {
$accountModel = AccountModel::where('web_flags', 3)->first();
if ($accountModel) {
$accountId = $accountModel->id;
}
}
function insert_sample_if_not_exist($p): void
{
global $time, $accountId;
$player = new OTS_Player();
$player->find($p['name']);
if (!$player->isLoaded()) {
$player->setData([
'name' => $p['name'],
'group_id' => 1,
'account_id' => $accountId,
'level' => $p['level'],
'vocation' => $p['vocation_id'],
'health' => $p['health'],
'healthmax' => $p['healthmax'],
'experience' => $p['experience'],
'lookbody' => 118,
'lookfeet' => 114,
'lookhead' => 38,
'looklegs' => 57,
'looktype' => $p['looktype'],
'maglevel' => 0,
'mana' => $p['mana'],
'manamax' => $p['manamax'],
'manaspent' => 0,
'soul' => $p['soul'],
'town_id' => 1,
'posx' => 1000,
'posy' => 1000,
'posz' => 7,
'conditions' => '',
'cap' => $p['cap'],
'sex' => 1,
'lastlogin' => $time,
'lastip' => 2130706433,
'save' => 1,
'lastlogout' => $time,
'balance' => 0,
'created' => $time,
'hide' => 1,
'comment' => '',
]);
$player->save();
}
}
$up = function () use ($db) {
if (!$db->hasTable('players')) {
return;
}
insert_sample_if_not_exist(['name' => 'Rook Sample', 'level' => 1, 'vocation_id' => 0, 'health' => 150, 'healthmax' => 150, 'experience' => 0, 'looktype' => 130, 'mana' => 0, 'manamax' => 0, 'soul' => 100, 'cap' => 400]);
insert_sample_if_not_exist(['name' => 'Sorcerer Sample', 'level' => 8, 'vocation_id' => 1, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 130, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470]);
insert_sample_if_not_exist(['name' => 'Druid Sample', 'level' => 8, 'vocation_id' => 2, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 130, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470]);
insert_sample_if_not_exist(['name' => 'Paladin Sample', 'level' => 8, 'vocation_id' => 3, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 129, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470]);
insert_sample_if_not_exist(['name' => 'Knight Sample', 'level' => 8, 'vocation_id' => 4, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 131, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470]);
insert_sample_if_not_exist(['name' => 'Monk Sample', 'level' => 8, 'vocation_id' => 9, 'health' => 185, 'healthmax' => 185, 'experience' => 4200, 'looktype' => 128, 'mana' => 90, 'manamax' => 90, 'soul' => 100, 'cap' => 470]);
if (defined('MYAAC_INSTALL')) {
global $locale;
success($locale['step_database_imported_players']);
}
require_once __DIR__ . '/20.php';
updateHighscoresIdsHidden();
};
$down = function () {
// nothing
};

View File

@@ -0,0 +1,11 @@
CREATE TABLE IF NOT EXISTS `myaac_gallery`
(
`id` int NOT NULL AUTO_INCREMENT,
`comment` varchar(255) NOT NULL DEFAULT '',
`image` varchar(255) NOT NULL,
`thumb` varchar(255) NOT NULL,
`author` varchar(50) NOT NULL DEFAULT '',
`ordering` int NOT NULL DEFAULT 0,
`hide` tinyint NOT NULL DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;

16
system/migrations/50.php Normal file
View File

@@ -0,0 +1,16 @@
<?php
/**
* @var OTS_DB_MySQL $db
*/
$up = function () use ($db) {
if ($db->hasTable(TABLE_PREFIX . 'gallery')) {
$db->dropTable(TABLE_PREFIX . 'gallery');
}
};
$down = function () use ($db) {
if (!$db->hasTable(TABLE_PREFIX . 'gallery')) {
$db->query(file_get_contents(__DIR__ . '/50-gallery.sql'));
}
};

10
system/migrations/51.php Normal file
View File

@@ -0,0 +1,10 @@
<?php
$up = function () use ($db) {
$db->modifyColumn(TABLE_PREFIX . 'config', 'name', "varchar(255) NOT NULL");
$db->modifyColumn(TABLE_PREFIX . 'config', 'value', "varchar(10000) NOT NULL");
};
$down = function () {
// nothing to do, to not lose data
};

13
system/migrations/52.php Normal file
View File

@@ -0,0 +1,13 @@
<?php
/**
* 2026-04-12
* Add indexes to myaac_account_actions table
*/
$up = function () use ($db) {
$db->query("CREATE INDEX `myaac_account_actions_account_id` ON `myaac_account_actions` (`account_id`);");
$db->query("CREATE INDEX `myaac_account_actions_ip` ON `myaac_account_actions` (`ip`);");
};
$down = function () {
// nothing to do, to not lose data
};

View File

@@ -9,7 +9,7 @@ $up = function () use ($db) {
} }
}; };
$up = function () use ($db) { $down = function () use ($db) {
if (!$db->hasColumn(TABLE_PREFIX . 'screenshots', 'name')) { if (!$db->hasColumn(TABLE_PREFIX . 'screenshots', 'name')) {
$db->addColumn(TABLE_PREFIX . 'screenshots', 'name', 'VARCHAR(30) NOT NULL'); $db->addColumn(TABLE_PREFIX . 'screenshots', 'name', 'VARCHAR(30) NOT NULL');
} }

View File

@@ -0,0 +1,29 @@
<?php
/**
* Example of using getTopPlayers() function
* to display the best players for each skill
*/
defined('MYAAC') or die('Direct access not allowed!');
$skills = [
'magic', 'level',
'balance', 'frags',
POT::SKILL_FIST, POT::SKILL_CLUB,
POT::SKILL_SWORD, POT::SKILL_AXE,
POT::SKILL_DISTANCE, POT::SKILL_SHIELD,
POT::SKILL_FISH
];
foreach ($skills as $skill) {?>
<ul>
<?php
echo '<strong>' . ucwords(is_string($skill) ? $skill : getSkillName($skill)) . '</strong>';
foreach (getTopPlayers(5, $skill) as $player) {?>
<li><?= $player['rank'] . '. ' . $player['name'] . ' - ' . $player['value']; ?></li>
<?php
}
?>
</ul>
<?php
}

View File

@@ -19,18 +19,17 @@ if(!$logged) {
csrfProtect(); csrfProtect();
$new_password = $_POST['newpassword'] ?? NULL; $new_password = $_POST['new_password'] ?? null;
$new_password_confirm = $_POST['newpassword_confirm'] ?? NULL; $new_password_confirm = $_POST['new_password_confirm'] ?? null;
$old_password = $_POST['oldpassword'] ?? NULL; $old_password = $_POST['old_password'] ?? null;
if(empty($new_password) && empty($new_password_confirm) && empty($old_password)) { if(is_null($new_password) && is_null($new_password_confirm) && is_null($old_password)) {
$twig->display('account.change-password.html.twig'); $twig->display('account.change-password.html.twig');
} }
else else {
{
if(empty($new_password) || empty($new_password_confirm) || empty($old_password)){ if(empty($new_password) || empty($new_password_confirm) || empty($old_password)){
$errors[] = 'Please fill in form.'; $errors[] = 'Please fill in form.';
} }
$password_strlen = strlen($new_password);
if($new_password != $new_password_confirm) { if($new_password != $new_password_confirm) {
$errors[] = 'The new passwords do not match!'; $errors[] = 'The new passwords do not match!';
} }
@@ -41,10 +40,13 @@ else
} }
/** @var OTS_Account $account_logged */ /** @var OTS_Account $account_logged */
$old_password = encrypt((USE_ACCOUNT_SALT ? $account_logged->getCustomField('salt') : '') . $old_password); $old_password_hashed = encrypt((USE_ACCOUNT_SALT ? $account_logged->getCustomField('salt') : '') . $old_password);
if($old_password != $account_logged->getPassword()) { if($old_password_hashed != $account_logged->getPassword()) {
$errors[] = 'Current password is incorrect!'; $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); $hooks->trigger(HOOK_ACCOUNT_CHANGE_PASSWORD_POST);
} }

View File

@@ -51,6 +51,8 @@ if($player_name != null) {
'description' => 'The character information has been changed.' 'description' => 'The character information has been changed.'
)); ));
$show_form = false; $show_form = false;
$hooks->trigger(HOOK_ACCOUNT_CHARACTERS_CHANGE_COMMENT_AFTER_SUCCESS, ['player' => $player]);
} }
} }
} else { } else {
@@ -70,9 +72,11 @@ if($show_form) {
} }
if(isset($player) && $player) { if(isset($player) && $player) {
$twig->display('account.characters.change-comment.html.twig', array( $_player = $player->toArray();
'player' => $player->toArray() $_player['id'] = $player->id; // Hack, as it's somehow missing in the toArray() function
));
$twig->display('account.characters.change-comment.html.twig', [
'player' => $_player,
]);
} }
} }
?>

View File

@@ -9,6 +9,7 @@
*/ */
use MyAAC\Models\Account; use MyAAC\Models\Account;
use MyAAC\Models\AccountEmailVerify;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
@@ -20,16 +21,20 @@ if(empty($hash)) {
return; return;
} }
if(!Account::where('email_hash', $hash)->exists()) { // by default link is valid for 30 days
note("Your email couldn't be verified. Please contact staff to do it manually."); $accountEmailVerify = AccountEmailVerify::where('hash', $hash)->where('sent_at', '>', time() - 30 * 24 * 60 * 60)->first();
if(!$accountEmailVerify) {
note("Wrong link or link has expired.");
} }
else 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) { if ($accountModel) {
$accountModel->email_verified = 1; $accountModel->email_verified = 1;
$accountModel->save(); $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 <a href=' . getLink('account/manage') . '>log in</a>.'); success('You have now verified your e-mail, this will increase the security of your account. Thank you for doing this. You can now <a href=' . getLink('account/manage') . '>log in</a>.');
$account = new OTS_Account(); $account = new OTS_Account();
@@ -39,6 +44,6 @@ else
} }
} }
else { else {
error('Link has expired.'); error('Your account is already verified.');
} }
} }

View File

@@ -10,6 +10,8 @@
*/ */
use MyAAC\CreateCharacter; use MyAAC\CreateCharacter;
use MyAAC\Models\AccountAction;
use MyAAC\Models\AccountEmailVerify;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
$title = 'Create Account'; $title = 'Create Account';
@@ -43,6 +45,16 @@ $errors = array();
$save = isset($_POST['save']) && $_POST['save'] == 1; $save = isset($_POST['save']) && $_POST['save'] == 1;
if($save) if($save)
{ {
$cooldown = setting('core.account_create_ip_block_cooldown');;
if ($cooldown > 0) {
$accountAction = AccountAction::where('ip', get_browser_real_ip())->where('action', 'Account created.')->where('date', '>=', time() - ($cooldown * 60))->first();
if ($accountAction) {
$minute = ($cooldown > 1 ? 'minutes' : 'minute');
$errors['account'] = "You have to wait $cooldown $minute before creating another account.";
}
}
if(!config('account_login_by_email')) { if(!config('account_login_by_email')) {
if(USE_ACCOUNT_NAME) { if(USE_ACCOUNT_NAME) {
$account_name = $_POST['account']; $account_name = $_POST['account'];
@@ -139,7 +151,7 @@ if($save)
'country' => $country, 'country' => $country,
'password' => $password, 'password' => $password,
'password_confirm' => $password_confirm, 'password_confirm' => $password_confirm,
'accept_rules' => isset($_POST['accept_rules']) ? $_POST['accept_rules'] === 'true' : false, 'accept_rules' => isset($_POST['accept_rules']) && $_POST['accept_rules'] === 'true',
); );
if (!config('account_login_by_email')) { if (!config('account_login_by_email')) {
@@ -159,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;
@@ -191,6 +203,21 @@ if($save)
$new_account->setPassword(encrypt($password)); $new_account->setPassword(encrypt($password));
$new_account->setEMail($email); $new_account->setEMail($email);
$settingAccountPremiumDays = setting('core.account_premium_days');
if($settingAccountPremiumDays && $settingAccountPremiumDays > 0) {
$new_account->setPremDays($settingAccountPremiumDays);
if (!isCanary()) {
$lastDay = 0;
if($settingAccountPremiumDays != 0 && $settingAccountPremiumDays != OTS_Account::GRATIS_PREMIUM_DAYS) {
$lastDay = time();
}
$new_account->setLastLogin($lastDay);
}
}
$new_account->save(); $new_account->save();
$hooks->trigger(HOOK_ACCOUNT_CREATE_AFTER_SAVED, ['account' => $new_account]); $hooks->trigger(HOOK_ACCOUNT_CREATE_AFTER_SAVED, ['account' => $new_account]);
@@ -205,32 +232,21 @@ if($save)
$new_account->setCustomField('country', $country); $new_account->setCustomField('country', $country);
} }
$settingAccountPremiumDays = setting('core.account_premium_days');
if($settingAccountPremiumDays && $settingAccountPremiumDays > 0) {
if($db->hasColumn('accounts', 'premend')) { // othire
$new_account->setCustomField('premend', time() + $settingAccountPremiumDays * 86400);
}
else { // rest
if ($db->hasColumn('accounts', 'premium_ends_at')) { // TFS 1.4+
$new_account->setCustomField('premium_ends_at', time() + $settingAccountPremiumDays * (60 * 60 * 24));
}
else {
$new_account->setCustomField('premdays', $settingAccountPremiumDays);
$new_account->setCustomField('lastday', time());
}
}
}
$accountDefaultPremiumPoints = setting('core.account_premium_points'); $accountDefaultPremiumPoints = setting('core.account_premium_points');
if($accountDefaultPremiumPoints > 0) { if($accountDefaultPremiumPoints > 0) {
$new_account->setCustomField('premium_points', $accountDefaultPremiumPoints); $new_account->setCustomField('premium_points', $accountDefaultPremiumPoints);
} }
$accountDefaultCoins = setting('core.account_coins'); $accountDefaultCoins = setting('core.account_coins');
if($db->hasColumn('accounts', 'coins') && $accountDefaultCoins > 0) { if(HAS_ACCOUNT_COINS && $accountDefaultCoins > 0) {
$new_account->setCustomField('coins', $accountDefaultCoins); $new_account->setCustomField('coins', $accountDefaultCoins);
} }
$accountDefaultCoinsTransferable = setting('core.account_coins_transferable');
if((HAS_ACCOUNT_COINS_TRANSFERABLE || HAS_ACCOUNT_TRANSFERABLE_COINS) && $accountDefaultCoinsTransferable > 0) {
$new_account->setCustomField(ACCOUNT_COINS_TRANSFERABLE_COLUMN, $accountDefaultCoinsTransferable);
}
$tmp_account = $email; $tmp_account = $email;
if (!config('account_login_by_email')) { if (!config('account_login_by_email')) {
$tmp_account = (USE_ACCOUNT_NAME ? $account_name : $account_id); $tmp_account = (USE_ACCOUNT_NAME ? $account_name : $account_id);
@@ -239,7 +255,12 @@ if($save)
if(setting('core.mail_enabled') && setting('core.account_mail_verify')) if(setting('core.mail_enabled') && setting('core.account_mail_verify'))
{ {
$hash = md5(generateRandomString(16, true, true) . $email); $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); $verify_url = getLink('account/confirm-email/' . $hash);
$body_html = $twig->render('mail.account.verify.html.twig', array( $body_html = $twig->render('mail.account.verify.html.twig', array(
@@ -263,8 +284,10 @@ if($save)
} }
else else
{ {
error('An error occorred while sending email! Account not created. Try again. For Admin: More info can be found in system/logs/mailer-error.log'); error('An error occurred while sending email! Account not created. Try again. For Admin: More info can be found in system/logs/mailer-error.log');
$new_account->delete(); $new_account->delete();
return;
} }
} }
else else
@@ -354,7 +377,7 @@ if(!empty($errors))
if (setting('core.account_country')) { if (setting('core.account_country')) {
$countries = array(); $countries = array();
foreach (array('pl', 'se', 'br', 'us', 'gb') as $c) foreach (setting('core.account_countries_most_popular') ?? [] as $c)
$countries[$c] = $config['countries'][$c]; $countries[$c] = $config['countries'][$c];
$countries['--'] = '----------'; $countries['--'] = '----------';

View File

@@ -48,7 +48,9 @@ if(!empty($login_account) && !empty($login_password))
) )
{ {
if (setting('core.account_mail_verify') && (int)$account_logged->getCustomField('email_verified') !== 1) { 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.<br/>' .
'You can resend the Email here: <a href="' . $link . '">' . $link . '</a>';
} else { } else {
session_regenerate_id(); session_regenerate_id();
setSession('account', $account_logged->getId()); setSession('account', $account_logged->getId());

View File

@@ -9,540 +9,11 @@
* @link https://my-aac.org * @link https://my-aac.org
*/ */
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
$title = 'Lost Account Interface'; $title = 'Lost Account';
if(!setting('core.mail_enabled')) if(!setting('core.mail_enabled')) {
{ echo "<b>Account maker is not configured to send e-mails, you can't use Lost Account Interface. Contact with admin to get help.</b>";
echo '<b>Account maker is not configured to send e-mails, you can\'t use Lost Account Interface. Contact with admin to get help.</b>';
return; return;
} }
$action_type = isset($_REQUEST['action_type']) ? $_REQUEST['action_type'] : ''; $twig->display('account/lost/form.html.twig');
if($action == '')
{
$twig->display('account.lost.form.html.twig');
}
else if($action == 'step1' && $action_type == '') {
$twig->display('account.lost.noaction.html.twig');
}
elseif($action == 'step1' && $action_type == 'email')
{
$nick = stripslashes($_REQUEST['nick']);
if(Validator::characterName($nick))
{
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($nick);
if($player->isLoaded())
$account = $player->getAccount();
if($account->isLoaded())
{
if($account->getCustomField('email_next') < time())
echo 'Please enter e-mail to account with this character.<BR>
<form action="' . getLink('account/lost') . '?action=sendcode" method=post>
<input type=hidden name="character">
<table cellspacing=1 cellpadding=4 border=0 width=100%>
<TR><TD BGCOLOR="'.$config['vdarkborder'].'" class="white"><B>Please enter e-mail to account</B></TD></TR>
<TR><TD BGCOLOR="'.$config['darkborder'].'">
Character: <INPUT TYPE=text NAME="nick" VALUE="'.$nick.'" SIZE="40" readonly="readonly"><BR>
E-mail to account:<INPUT TYPE=text NAME="email" VALUE="" SIZE="40"><BR>
</TD></TR>
</TABLE>
<BR>
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
' . $twig->render('buttons.submit.html.twig') . '</div>
</TD></TR></FORM></TABLE></TABLE>';
else
{
$insec = (int)$account->getCustomField('email_next') - time();
$minutesleft = floor($insec / 60);
$secondsleft = $insec - ($minutesleft * 60);
$timeleft = $minutesleft.' minutes '.$secondsleft.' seconds';
echo 'Account of selected character (<b>'.$nick.'</b>) received e-mail in last '.ceil(setting('core.mail_lost_account_interval') / 60).' minutes. You must wait '.$timeleft.' before you can use Lost Account Interface again.';
}
}
else
echo 'Player or account of player <b>' . $nick . '</b> doesn\'t exist.';
}
else
echo 'Invalid player name format. If you have other characters on account try with other name.';
echo '<BR /><TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
<a href="' . getLink('account/lost') . '" border="0"><IMG SRC="'.$template_path.'/images/global/buttons/sbutton_back.gif" NAME="Back" ALT="Back" BORDER=0 WIDTH=120 HEIGHT=18></a></div>
</TD></TR></FORM></TABLE></TABLE>';
}
elseif($action == 'sendcode')
{
$email = $_REQUEST['email'];
$nick = stripslashes($_REQUEST['nick']);
if(Validator::characterName($nick))
{
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($nick);
if($player->isLoaded())
$account = $player->getAccount();
if($account->isLoaded())
{
if($account->getCustomField('email_next') < time())
{
if($account->getEMail() == $email)
{
$newcode = generateRandomString(30, true, false, true);
$mailBody = '
You asked to reset your ' . $config['lua']['serverName'] . ' password.<br/>
<p>Account name: '.$account->getName().'</p>
<br />
To do so, please click this link:
<p><a href="' . getLink('account/lost') . '?action=checkcode&code='.$newcode.'&character='.urlencode($nick).'">' . getLink('account/lost') . '?action=checkcode&code='.$newcode.'&character='.urlencode($nick).'</a></p>
<p>or open page: <i>' . getLink('account/lost') . '?action=checkcode</i> and in field "code" write <b>'.$newcode.'</b></p>
<br/>
<p>If you did not request a password change, you may ignore this message and your password will remain unchanged.';
$account_mail = $account->getCustomField('email');
if(_mail($account_mail, $config['lua']['serverName'].' - Recover your account', $mailBody))
{
$account->setCustomField('email_code', $newcode);
$account->setCustomField('email_next', (time() + setting('core.mail_lost_account_interval')));
echo '<br />Details about steps required to recover your account has been sent to <b>' . $account_mail . '</b>. You should receive this email within 15 minutes. Please check your inbox/spam directory.';
}
else
{
$account->setCustomField('email_next', (time() + 60));
echo '<br /><p class="error">An error occurred while sending email! Try again later or contact with admin. For Admin: More info can be found in system/logs/mailer-error.log</p>';
}
}
else
echo 'Invalid e-mail to account of character <b>'.$nick.'</b>. Try again.';
}
else
{
$insec = (int)$account->getCustomField('email_next') - time();
$minutesleft = floor($insec / 60);
$secondsleft = $insec - ($minutesleft * 60);
$timeleft = $minutesleft.' minutes '.$secondsleft.' seconds';
echo 'Account of selected character (<b>'.$nick.'</b>) received e-mail in last '.ceil(setting('core.mail_lost_account_interval') / 60).' minutes. You must wait '.$timeleft.' before you can use Lost Account Interface again.';
}
}
else
echo 'Player or account of player <b>'.$nick.'</b> doesn\'t exist.';
}
else
echo 'Invalid player name format. If you have other characters on account try with other name.';
echo '<BR /><TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
<a href="' . getLink('account/lost') . '?action=step1&action_type=email&nick='.urlencode($nick).'" border="0"><IMG SRC="'.$template_path.'/images/global/buttons/sbutton_back.gif" NAME="Back" ALT="Back" BORDER=0 WIDTH=120 HEIGHT=18></a></div>
</TD></TR></FORM></TABLE></TABLE>';
}
elseif($action == 'step1' && $action_type == 'reckey')
{
$nick = stripslashes($_REQUEST['nick']);
if(Validator::characterName($nick))
{
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($nick);
if($player->isLoaded())
$account = $player->getAccount();
if($account->isLoaded())
{
$account_key = $account->getCustomField('key');
if(!empty($account_key))
{
echo 'If you enter right recovery key you will see form to set new e-mail and password to account. To this e-mail will be send your new password and account name.<BR>
<FORM ACTION="' . getLink('account/lost') . '?action=step2" METHOD=post>
<TABLE CELLSPACING=1 CELLPADDING=4 BORDER=0 WIDTH=100%>
<TR><TD BGCOLOR="'.$config['vdarkborder'].'" class="white"><B>Please enter your recovery key</B></TD></TR>
<TR><TD BGCOLOR="'.$config['darkborder'].'">
Character name:&nbsp;<INPUT TYPE=text NAME="nick" VALUE="'.$nick.'" SIZE="40" readonly="readonly"><BR />
Recovery key:&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE=text NAME="key" VALUE="" SIZE="40"><BR>
</TD></TR>
</TABLE>
<BR>
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
' . $twig->render('buttons.submit.html.twig') . '</div>
</TD></TR></FORM></TABLE></TABLE>';
}
else
echo 'Account of this character has no recovery key!';
}
else
echo 'Player or account of player <b>'.$nick.'</b> doesn\'t exist.';
}
else
echo 'Invalid player name format. If you have other characters on account try with other name.';
echo '<BR /><TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
<a href="' . getLink('account/lost') . '" border="0"><IMG SRC="'.$template_path.'/images/global/buttons/sbutton_back.gif" NAME="Back" ALT="Back" BORDER=0 WIDTH=120 HEIGHT=18></a></div>
</TD></TR></FORM></TABLE></TABLE>';
}
elseif($action == 'step2')
{
$rec_key = trim($_REQUEST['key']);
$nick = stripslashes($_REQUEST['nick']);
if(Validator::characterName($nick))
{
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($nick);
if($player->isLoaded())
$account = $player->getAccount();
if($account->isLoaded())
{
$account_key = $account->getCustomField('key');
if(!empty($account_key))
{
if($account_key == $rec_key)
{
echo '<script type="text/javascript">
function validate_required(field,alerttxt)
{
with (field)
{
if (value==null||value==""||value==" ")
{alert(alerttxt);return false;}
else {return true}
}
}
function validate_email(field,alerttxt)
{
with (field)
{
apos=value.indexOf("@");
dotpos=value.lastIndexOf(".");
if (apos<1||dotpos-apos<2)
{alert(alerttxt);return false;}
else {return true;}
}
}
function validate_form(thisform)
{
with (thisform)
{
if (validate_required(email,"Please enter your e-mail!")==false)
{email.focus();return false;}
if (validate_email(email,"Invalid e-mail format!")==false)
{email.focus();return false;}
if (validate_required(passor,"Please enter password!")==false)
{passor.focus();return false;}
if (validate_required(passor2,"Please repeat password!")==false)
{passor2.focus();return false;}
if (passor2.value!=passor.value)
{alert(\'Repeated password is not equal to password!\');return false;}
}
}
</script>';
echo 'Set new password and e-mail to your account.<BR>
<FORM ACTION="' . getLink('account/lost') . '?action=step3" onsubmit="return validate_form(this)" METHOD=post>
<INPUT TYPE=hidden NAME="character" VALUE="">
<TABLE CELLSPACING=1 CELLPADDING=4 BORDER=0 WIDTH=100%>
<TR><TD BGCOLOR="'.$config['vdarkborder'].'" class="white"><B>Please enter new password and e-mail</B></TD></TR>
<TR><TD BGCOLOR="'.$config['darkborder'].'">
Account of character:&nbsp;&nbsp;<INPUT TYPE=text NAME="nick" VALUE="'.$nick.'" SIZE="40" readonly="readonly"><BR />
New password:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT id="passor" TYPE=password NAME="passor" VALUE="" SIZE="40"><BR>
Repeat new password:&nbsp;&nbsp;<INPUT id="passor2" TYPE=password NAME="passor" VALUE="" SIZE="40"><BR>
New e-mail address:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT id="email" TYPE=text NAME="email" VALUE="" SIZE="40"><BR>
<INPUT TYPE=hidden NAME="key" VALUE="'.$rec_key.'">
</TD></TR>
</TABLE>
<BR>
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
' . $twig->render('buttons.submit.html.twig') . '</div>
</TD></TR></FORM></TABLE></TABLE>';
}
else
echo 'Wrong recovery key!';
}
else
echo 'Account of this character has no recovery key!';
}
else
echo 'Player or account of player <b>'.$nick.'</b> doesn\'t exist.';
}
else
echo 'Invalid player name format. If you have other characters on account try with other name.';
echo '<BR /><TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
<a href="' . getLink('account/lost') . '?action=step1&action_type=reckey&nick='.urlencode($nick).'" border="0"><IMG SRC="'.$template_path.'/images/global/buttons/sbutton_back.gif" NAME="Back" ALT="Back" BORDER=0 WIDTH=120 HEIGHT=18></a></div>
</TD></TR></FORM></TABLE></TABLE>';
}
elseif($action == 'step3')
{
$rec_key = trim($_REQUEST['key']);
$nick = stripslashes($_REQUEST['nick']);
$new_pass = trim($_REQUEST['passor']);
$new_email = trim($_REQUEST['email']);
if(Validator::characterName($nick))
{
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($nick);
if($player->isLoaded())
$account = $player->getAccount();
if($account->isLoaded())
{
$account_key = $account->getCustomField('key');
if(!empty($account_key))
{
if($account_key == $rec_key)
{
if(Validator::password($new_pass))
{
if(Validator::email($new_email))
{
$account->setEMail($new_email);
$tmp_new_pass = $new_pass;
if(USE_ACCOUNT_SALT)
{
$salt = generateRandomString(10, false, true, true);
$tmp_new_pass = $salt . $new_pass;
}
$account->setPassword(encrypt($tmp_new_pass));
$account->save();
if(USE_ACCOUNT_SALT)
$account->setCustomField('salt', $salt);
echo 'Your account name, new password and new e-mail.<BR>
<FORM ACTION="' . getLink('account/manage') . '" onsubmit="return validate_form(this)" METHOD=post>
<INPUT TYPE=hidden NAME="character" VALUE="">
<TABLE CELLSPACING=1 CELLPADDING=4 BORDER=0 WIDTH=100%>
<TR><TD BGCOLOR="'.$config['vdarkborder'].'" class="white"><B>Your account name, new password and new e-mail</B></TD></TR>
<TR><TD BGCOLOR="'.$config['darkborder'].'">
Account name:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>'.$account->getName().'</b><BR>
New password:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>'.$new_pass.'</b><BR>
New e-mail address:&nbsp;<b>'.$new_email.'</b><BR>';
if($account->getCustomField('email_next') < time())
{
$mailBody = '
<h3>Your account name and new password!</h3>
<p>Changed password and e-mail to your account in Lost Account Interface on server <a href="'.BASE_URL.'"><b>'.$config['lua']['serverName'].'</b></a></p>
<p>Account name: <b>'.$account->getName().'</b></p>
<p>New password: <b>'.$new_pass.'</b></p>
<p>E-mail: <b>'.$new_email.'</b> (this e-mail)</p>
<br />
<p><u>It\'s automatic e-mail from OTS Lost Account System. Do not reply!</u></p>';
if(_mail($account->getCustomField('email'), $config['lua']['serverName']." - New password to your account", $mailBody))
{
echo '<br /><small>Sent e-mail with your account name and password to new e-mail. You should receive this e-mail in 15 minutes. You can login now with new password!</small>';
}
else
{
echo '<br /><p class="error">An error occurred while sending email! You will not receive e-mail with this informations. For Admin: More info can be found in system/logs/mailer-error.log</p>';
}
}
else
{
echo '<br /><small>You will not receive e-mail with this informations.</small>';
}
echo '<INPUT TYPE=hidden NAME="account_login" VALUE="'.$account->getId().'">
<INPUT TYPE=hidden NAME="password_login" VALUE="'.$new_pass.'">
</TD></TR></TABLE><BR>
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
<INPUT TYPE=image NAME="Login" ALT="Login" SRC="'.$template_path.'/images/global/buttons/sbutton_login.gif" BORDER=0 WIDTH=120 HEIGHT=18></div>
</TD></TR></FORM></TABLE></TABLE>';
}
else
echo Validator::getLastError();
}
else
echo Validator::getLastError();
}
else
echo 'Wrong recovery key!';
}
else
echo 'Account of this character has no recovery key!';
}
else
echo 'Player or account of player <b>'.$nick.'</b> doesn\'t exist.';
}
else
echo 'Invalid player name format. If you have other characters on account try with other name.';
echo '<BR /><TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
<a href="' . getLink('account/lost') . '?action=step1&action_type=reckey&nick='.urlencode($nick).'" border="0"><IMG SRC="'.$template_path.'/images/global/buttons/sbutton_back.gif" NAME="Back" ALT="Back" BORDER=0 WIDTH=120 HEIGHT=18></a></div>
</TD></TR></FORM></TABLE></TABLE>';
}
elseif($action == 'checkcode')
{
$code = trim($_REQUEST['code']);
$character = stripslashes(trim($_REQUEST['character']));
if(empty($code) || empty($character))
echo 'Please enter code from e-mail and name of one character from account. Then press Submit.<BR>
<FORM ACTION="' . getLink('account/lost') . '?action=checkcode" METHOD=post>
<TABLE CELLSPACING=1 CELLPADDING=4 BORDER=0 WIDTH=100%>
<TR><TD BGCOLOR="'.$config['vdarkborder'].'" class="white"><B>Code & character name</B></TD></TR>
<TR><TD BGCOLOR="'.$config['darkborder'].'">
Your code:&nbsp;<INPUT TYPE=text NAME="code" VALUE="" SIZE="40")><BR />
Character:&nbsp;<INPUT TYPE=text NAME="character" VALUE="" SIZE="40")><BR />
</TD></TR>
</TABLE>
<BR>
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
' . $twig->render('buttons.submit.html.twig') . '</div>
</TD></TR></FORM></TABLE></TABLE>';
else
{
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($character);
if($player->isLoaded())
$account = $player->getAccount();
if($account->isLoaded())
{
if($account->getCustomField('email_code') == $code)
{
echo '<script type="text/javascript">
function validate_required(field,alerttxt)
{
with (field)
{
if (value==null||value==""||value==" ")
{alert(alerttxt);return false;}
else {return true}
}
}
function validate_form(thisform)
{
with (thisform)
{
if (validate_required(passor,"Please enter password!")==false)
{passor.focus();return false;}
if (validate_required(passor2,"Please repeat password!")==false)
{passor2.focus();return false;}
if (passor2.value!=passor.value)
{alert(\'Repeated password is not equal to password!\');return false;}
}
}
</script>
Please enter new password to your account and repeat to make sure you remember password.<BR>
<FORM ACTION="' . getLink('account/lost') . '?action=setnewpassword" onsubmit="return validate_form(this)" METHOD=post>
<INPUT TYPE=hidden NAME="character" VALUE="'.$character.'">
<INPUT TYPE=hidden NAME="code" VALUE="'.$code.'">
<TABLE CELLSPACING=1 CELLPADDING=4 BORDER=0 WIDTH=100%>
<TR><TD BGCOLOR="'.$config['vdarkborder'].'" class="white"><B>Code & account name</B></TD></TR>
<TR><TD BGCOLOR="'.$config['darkborder'].'">
New password:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<INPUT TYPE=password ID="passor" NAME="passor" VALUE="" SIZE="40")><BR />
Repeat new password:&nbsp;<INPUT TYPE=password ID="passor2" NAME="passor2" VALUE="" SIZE="40")><BR />
</TD></TR>
</TABLE>
<BR>
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
' . $twig->render('buttons.submit.html.twig') . '</div>
</TD></TR></FORM></TABLE></TABLE>';
}
else
$error= 'Wrong code to change password.';
}
else
$error = 'Account of this character or this character doesn\'t exist.';
}
if(!empty($error))
echo '<span style="color: red"><b>'.$error.'</b></span><br />Please enter code from e-mail and name of one character from account. Then press Submit.<BR>
<FORM ACTION="' . getLink('account/lost') . '?action=checkcode" METHOD=post>
<TABLE CELLSPACING=1 CELLPADDING=4 BORDER=0 WIDTH=100%>
<TR><TD BGCOLOR="'.$config['vdarkborder'].'" class="white"><B>Code & character name</B></TD></TR>
<TR><TD BGCOLOR="'.$config['darkborder'].'">
Your code:&nbsp;<INPUT TYPE=text NAME="code" VALUE="" SIZE="40")><BR />
Character:&nbsp;<INPUT TYPE=text NAME="character" VALUE="" SIZE="40")><BR />
</TD></TR>
</TABLE>
<BR>
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
' . $twig->render('buttons.submit.html.twig') . '</div>
</TD></TR></FORM></TABLE></TABLE>';
}
elseif($action == 'setnewpassword')
{
$newpassword = $_REQUEST['passor'];
$code = $_REQUEST['code'];
$character = stripslashes($_REQUEST['character']);
echo '';
if(empty($code) || empty($character) || empty($newpassword))
echo '<span style="color: red"><b>Error. Try again.</b></span><br />Please enter code from e-mail and name of one character from account. Then press Submit.<BR>
<BR><FORM ACTION="' . getLink('account/lost') . '?action=checkcode" METHOD=post>
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
<INPUT TYPE=image NAME="Back" ALT="Back" SRC="'.$template_path.'/images/global/buttons/sbutton_back.gif" BORDER=0 WIDTH=120 HEIGHT=18></div>
</TD></TR></FORM></TABLE></TABLE>';
else
{
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($character);
if($player->isLoaded())
$account = $player->getAccount();
if($account->isLoaded())
{
if($account->getCustomField('email_code') == $code)
{
if(Validator::password($newpassword))
{
$tmp_new_pass = $newpassword;
if(USE_ACCOUNT_SALT)
{
$salt = generateRandomString(10, false, true, true);
$tmp_new_pass = $salt . $newpassword;
$account->setCustomField('salt', $salt);
}
$account->setPassword(encrypt($tmp_new_pass ));
$account->save();
$account->setCustomField('email_code', '');
echo 'New password to your account is below. Now you can login.<BR>
<INPUT TYPE=hidden NAME="character" VALUE="'.$character.'">
<TABLE CELLSPACING=1 CELLPADDING=4 BORDER=0 WIDTH=100%>
<TR><TD BGCOLOR="'.$config['vdarkborder'].'" class="white"><B>Changed password</B></TD></TR>
<TR><TD BGCOLOR="'.$config['darkborder'].'">
New password:&nbsp;<b>'.$newpassword.'</b><BR />
Account name:&nbsp;&nbsp;&nbsp;<i>(Already on your e-mail)</i><BR />';
$mailBody = '
<h3>Your account name and password!</h3>
<p>Changed password to your account in Lost Account Interface on server <a href="'.BASE_URL.'"><b>'.$config['lua']['serverName'].'</b></a></p>
<p>Account name: <b>'.$account->getName().'</b></p>
<p>New password: <b>'.$newpassword.'</b></p>
<br />
<p><u>It\'s automatic e-mail from OTS Lost Account System. Do not reply!</u></p>';
if(_mail($account->getCustomField('email'), $config['lua']['serverName']." - Your new password", $mailBody))
{
echo '<br /><small>New password work! Sent e-mail with your password and account name. You should receive this e-mail in 15 minutes. You can login now with new password!';
}
else
{
echo '<br /><p class="error">New password work! An error occurred while sending email! You will not receive e-mail with new password. For Admin: More info can be found in system/logs/mailer-error.log';
}
echo '</TD></TR>
</TABLE>
<BR>
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
<FORM ACTION="' . getLink('account/manage') . '" METHOD=post>
<INPUT TYPE=image NAME="Login" ALT="Login" SRC="'.$template_path.'/images/global/buttons/sbutton_login.gif" BORDER=0 WIDTH=120 HEIGHT=18></div>
</TD></TR></FORM></TABLE></TABLE>';
}
else
$error= Validator::getLastError();
}
else
$error= 'Wrong code to change password.';
}
else
$error = 'Account of this character or this character doesn\'t exist.';
}
if(!empty($error))
echo '<span style="color: red"><b>'.$error.'</b></span><br />Please enter code from e-mail and name of one character from account. Then press Submit.<BR>
<FORM ACTION="' . getLink('account/lost') . '?action=checkcode" METHOD=post>
<TABLE CELLSPACING=1 CELLPADDING=4 BORDER=0 WIDTH=100%>
<TR><TD BGCOLOR="'.$config['vdarkborder'].'" class="white"><B>Code & character name</B></TD></TR>
<TR><TD BGCOLOR="'.$config['darkborder'].'">
Your code:&nbsp;<INPUT TYPE=text NAME="code" VALUE="" SIZE="40")><BR />
Character:&nbsp;<INPUT TYPE=text NAME="character" VALUE="" SIZE="40")><BR />
</TD></TR>
</TABLE>
<BR>
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%><TR><TD><div style="text-align:center">
' . $twig->render('buttons.submit.html.twig') . '</div>
</TD></TR></FORM></TABLE></TABLE>';
}

View File

@@ -0,0 +1,18 @@
<?php
defined('MYAAC') or die('Direct access not allowed!');
function lostAccountWriteCooldown(string $nick, int $time): void
{
global $twig;
$inSec = $time - time();
$minutesLeft = floor($inSec / 60);
$secondsLeft = $inSec - ($minutesLeft * 60);
$timeLeft = "$minutesLeft minutes $secondsLeft seconds";
$timeRounded = ceil(setting('core.mail_lost_account_interval') / 60);
$twig->display('error_box.html.twig', [
'errors' => ["Account of selected character (<b>" . escapeHtml($nick) . "</b>) received e-mail in last $timeRounded minutes. You must wait $timeLeft before you can use Lost Account Interface again."]
]);
}

View File

@@ -0,0 +1,51 @@
<?php
defined('MYAAC') or die('Direct access not allowed!');
csrfProtect();
$title = 'Lost Account';
$code = $_REQUEST['code'] ?? '';
$character = $_REQUEST['character'] ?? '';
if(empty($code) || empty($character)) {
$twig->display('account/lost/check-code.html.twig', [
'code' => $code,
'characters' => $character,
]);
}
else {
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($character);
if($player->isLoaded()) {
$account = $player->getAccount();
}
if($account->isLoaded()) {
if($account->getCustomField('email_code') == $code) {
$twig->display('account/lost/check-code.finish.html.twig', [
'character' => $character,
'code' => $code,
]);
}
else {
$error = 'Wrong code to change password.';
}
}
else {
$error = "Account of this character or this character doesn't exist.";
}
}
if(!empty($error)) {
$twig->display('error_box.html.twig', [
'errors' => [$error],
]);
echo '<br/>';
$twig->display('account/lost/check-code.html.twig', [
]);
}

View File

@@ -0,0 +1,75 @@
<?php
defined('MYAAC') or die('Direct access not allowed!');
csrfProtect();
require __DIR__ . '/../base.php';
$title = 'Lost Account';
$email = $_POST['email'] ?? '';
$nick = $_POST['nick'] ?? '';
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($nick);
if($player->isLoaded()) {
$account = $player->getAccount();
}
if($account->isLoaded()) {
if($account->getCustomField('email_next') < time()) {
if($account->getEMail() == $email) {
$newCode = generateRandomString(30, true, false, true);
$mailBody = $twig->render('mail.account.lost.code.html.twig', [
'newCode' => $newCode,
'account' => $account,
'nick' => $nick,
]);
$accountEMail = $account->getCustomField('email');
if(_mail($accountEMail, configLua('serverName') . ' - Recover your account', $mailBody)) {
$account->setCustomField('email_code', $newCode);
$account->setCustomField('email_next', (time() + setting('core.mail_lost_account_interval')));
$twig->display('success.html.twig', [
'title' => 'Email has been sent',
'description' => 'Details about steps required to recover your account has been sent to <b>' . $accountEMail . '</b>. You should receive this email within 15 minutes. Please check your inbox/spam directory.',
'custom_buttons' => '',
]);
$twig->display('account.back_button.html.twig', [
'new_line' => true,
'center' => true,
'action' => getLink('news'),
]);
return;
}
$account->setCustomField('email_next', (time() + 60));
error('An error occurred while sending email! Try again later or contact with admin. For Admin: More info can be found in system/logs/mailer-error.log</p>');
}
else {
$errors[] = 'Invalid e-mail to account of character <b>' . escapeHtml($nick) . '</b>. Try again.';
}
}
else {
lostAccountWriteCooldown($nick, (int)$account->getCustomField('email_next'));
}
}
else {
$errors[] = "Player or account of player <b>" . escapeHtml($nick) . "</b> doesn't exist.";
}
if (!empty($errors)) {
$twig->display('error_box.html.twig', [
'errors' => $errors,
]);
}
$twig->display('account.back_button.html.twig', [
'new_line' => true,
'center' => true,
'action' => getLink('account/lost/step-1') . '?action=email&nick=' . urlencode($nick),
]);

View File

@@ -0,0 +1,128 @@
<?php
defined('MYAAC') or die('Direct access not allowed!');
csrfProtect();
$title = 'Lost Account';
$newPassword = $_POST['password'] ?? '';
$passwordRepeat = $_POST['password_repeat'] ?? '';
$code = $_POST['code'] ?? '';
$character = $_POST['character'] ?? '';
if(empty($code) || empty($character)) {
$errors[] = 'Please enter code from e-mail and name of one character from account.';
$twig->display('error_box.html.twig', [
'errors' => $errors,
]);
$twig->display('account/lost/check-code.html.twig', [
'code' => $code,
'character' => $character,
]);
$twig->display('account.back_button.html.twig', [
'new_line' => true,
'center' => true,
'action' => getLink('account/lost/check-code')
]);
return;
}
if (empty($newPassword) || empty($passwordRepeat)) {
$errors[] = 'Please enter both passwords.';
$twig->display('error_box.html.twig', [
'errors' => $errors,
]);
$twig->display('account/lost/check-code.finish.html.twig', [
'character' => $character,
'code' => $code,
]);
return;
}
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($character);
if($player->isLoaded()) {
$account = $player->getAccount();
}
$passwordFailed = false;
if($account->isLoaded()) {
if($account->getCustomField('email_code') == $code) {
if ($newPassword == $passwordRepeat) {
if (Validator::password($newPassword)) {
$hooks->trigger(HOOK_ACCOUNT_LOST_EMAIL_SET_NEW_PASSWORD_POST);
if (empty($errors)) {
$tmp_new_pass = $newPassword;
if (USE_ACCOUNT_SALT) {
$salt = generateRandomString(10, false, true, true);
$tmp_new_pass = $salt . $newPassword;
$account->setCustomField('salt', $salt);
}
$account->setPassword(encrypt($tmp_new_pass));
$account->save();
$account->setCustomField('email_code', '');
$mailBody = $twig->render('mail.account.lost.new-password.html.twig', [
'account' => $account,
'newPassword' => $newPassword,
]);
$statusMsg = '';
if (_mail($account->getCustomField('email'), configLua('serverName') . ' - Your new password', $mailBody)) {
$statusMsg = '<br /><small>New password work! Sent e-mail with your password and account name. You should receive this e-mail in 15 minutes. You can login now with new password!';
} else {
$statusMsg = '<br /><p class="error">New password work! An error occurred while sending email! You will not receive e-mail with new password. For Admin: More info can be found in system/logs/mailer-error.log';
}
$twig->display('account/lost/finish.new-password.html.twig', [
'statusMsg' => $statusMsg,
'newPassword' => $newPassword,
]);
}
} else {
$passwordFailed = true;
$errors[] = Validator::getLastError();
}
}
else {
$passwordFailed = true;
$errors[] = 'Passwords are not the same!';
}
}
else {
$errors[] = 'Wrong code to change password.';
}
}
else {
$errors[] = "Account of this character or this character doesn't exist.";
}
if(!empty($errors)) {
$twig->display('error_box.html.twig', [
'errors' => $errors,
]);
echo '<br/>';
$template = 'account/lost/check-code.html.twig';
if($passwordFailed) {
$template = 'account/lost/check-code.finish.html.twig';
}
$twig->display($template, [
'code' => $code,
'character' => $character,
]);
}

View File

@@ -0,0 +1,36 @@
<?php
defined('MYAAC') or die('Direct access not allowed!');
require __DIR__ . '/../base.php';
csrfProtect();
$title = 'Lost Account';
$nick = $_REQUEST['nick'] ?? '';
if($account->isLoaded()) {
if($account->getCustomField('email_next') < time()) {
$twig->display('account/lost/email.html.twig', [
'nick' => $nick,
]);
}
else {
lostAccountWriteCooldown($nick, (int)$account->getCustomField('email_next'));
}
}
else {
$errors[] = "Player or account of player <b>" . escapeHtml($nick) . "</b> doesn't exist.";
}
if (!empty($errors)) {
$twig->display('error_box.html.twig', [
'errors' => $errors,
]);
}
$twig->display('account.back_button.html.twig', [
'new_line' => true,
'center' => true,
'action' => getLink('account/lost'),
]);

View File

@@ -0,0 +1,38 @@
<?php
defined('MYAAC') or die('Direct access not allowed!');
csrfProtect();
$title = 'Lost Account';
$nick = $_REQUEST['nick'] ?? '';
$key = $_REQUEST['key'] ?? '';
if($account->isLoaded()) {
$account_key = $account->getCustomField('key');
if(!empty($account_key)) {
$twig->display('account/lost/recovery-key.step-1.html.twig', [
'nick' => $nick,
'key' => $key,
]);
}
else {
$errors[] = 'Account of this character has no recovery key!';
}
}
else {
$errors[] = "Player or account of player <b>" . escapeHtml($nick) . "</b> doesn't exist.";
}
if (!empty($errors)) {
$twig->display('error_box.html.twig', [
'errors' => $errors,
]);
}
$twig->display('account.back_button.html.twig', [
'new_line' => true,
'center' => true,
'action' => getLink('account/lost'),
]);

View File

@@ -0,0 +1,49 @@
<?php
defined('MYAAC') or die('Direct access not allowed!');
csrfProtect();
$title = 'Lost Account';
$key = $_REQUEST['key'] ?? '';
$nick = $_REQUEST['nick'] ?? '';
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($nick);
if($player->isLoaded()) {
$account = $player->getAccount();
}
if($account->isLoaded()) {
$accountKey = $account->getCustomField('key');
if(!empty($accountKey)) {
if($accountKey == $key) {
$twig->display('account/lost/recovery-key.step-2.html.twig', [
'nick' => $nick,
'key' => $key,
]);
}
else {
$errors[] = 'Wrong recovery key!';
}
}
else {
$errors[] = 'Account of this character has no recovery key!';
}
}
else {
$errors[] = "Player or account of player <b>" . escapeHtml($nick) . "</b> doesn't exist.";
}
if (!empty($errors)) {
$twig->display('error_box.html.twig', [
'errors' => $errors,
]);
}
$twig->display('account.back_button.html.twig', [
'new_line' => true,
'center' => true,
'action' => getLink('account/lost/step-1') . '?action=recovery-key&nick=' . urlencode($nick) . '&key=' . urlencode($key),
]);

View File

@@ -0,0 +1,117 @@
<?php
use MyAAC\Models\Account as AccountModel;
defined('MYAAC') or die('Direct access not allowed!');
csrfProtect();
$title = 'Lost Account';
$key = $_POST['key'];
$nick = $_POST['nick'] ?? '';
$newPassword = $_POST['password'] ?? '';
$passwordRepeat = $_POST['password_repeat'] ?? '';
$newEmail = $_POST['email'] ?? '';
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($nick);
if($player->isLoaded()) {
$account = $player->getAccount();
}
if($account->isLoaded()) {
$accountKey = $account->getCustomField('key');
if(!empty($accountKey)) {
if($accountKey == $key) {
if(Validator::password($newPassword)) {
if ($newPassword == $passwordRepeat) {
if (Validator::email($newEmail)) {
$emailExists = AccountModel::where('email', $newEmail)->count() > 0;
if (!$emailExists) {
$hooks->trigger(HOOK_ACCOUNT_LOST_RECOVERY_KEY_STEP_3_POST);
if (empty($errors)) {
$account->setEMail($newEmail);
$tmp_new_pass = $newPassword;
if (USE_ACCOUNT_SALT) {
$salt = generateRandomString(10, false, true, true);
$tmp_new_pass = $salt . $newPassword;
}
$account->setPassword(encrypt($tmp_new_pass));
$account->save();
if (USE_ACCOUNT_SALT) {
$account->setCustomField('salt', $salt);
}
$statusMsg = '';
if ($account->getCustomField('email_next') < time()) {
$mailBody = $twig->render('mail.account.lost.new-email.html.twig', [
'account' => $account,
'newPassword' => $newPassword,
'newEmail' => $newEmail,
]);
if (_mail($account->getCustomField('email'), configLua('serverName') . ' - New password to your account', $mailBody)) {
$statusMsg = '<br /><small>Sent e-mail with your account name and password to new e-mail. You should receive this e-mail in 15 minutes. You can login now with new password!</small>';
} else {
$statusMsg = '<br /><p class="error">An error occurred while sending email! You will not receive e-mail with this informations. For Admin: More info can be found in system/logs/mailer-error.log</p>';
}
} else {
$statusMsg = '<br /><small>You will not receive e-mail with this informations.</small>';
}
$twig->display('account/lost/finish.new-email.html.twig', [
'statusMsg' => $statusMsg,
'account' => $account,
'newPassword' => $newPassword,
'newEmail' => $newEmail,
]);
return;
}
}
else {
$errors[] = 'This email is already registered!';
}
} else {
$errors[] = Validator::getLastError();
}
}
else {
$errors[] = 'Passwords are not the same!';
}
}
else {
$errors[] = Validator::getLastError();
}
}
else {
$errors[] = 'Wrong recovery key!';
}
}
else {
$errors[] = 'Account of this character has no recovery key!';
}
}
else {
$errors[] = "Player or account of player <b>" . escapeHtml($nick) . "</b> doesn't exist.";
}
if (!empty($errors)) {
$twig->display('error_box.html.twig', [
'errors' => $errors,
]);
}
$twig->display('account.back_button.html.twig', [
'new_line' => true,
'center' => true,
'action' => getLink('account/lost/recovery-key/step-2') . '?nick=' . urlencode($nick) . '&key=' . urlencode($key),
]);

View File

@@ -0,0 +1,26 @@
<?php
defined('MYAAC') or die('Direct access not allowed!');
csrfProtect();
$title = 'Lost Account';
$nick = $_REQUEST['nick'] ?? '';
$player = new OTS_Player();
$account = new OTS_Account();
$player->find($nick);
if($player->isLoaded()) {
$account = $player->getAccount();
}
if (ACTION == 'email') {
require __DIR__ . '/email/step-1.php';
}
else if (ACTION == 'recovery-key') {
require __DIR__ . '/recovery-key/step-1.php';
}
else {
$twig->display('account/lost/no-action.html.twig');
}

View File

@@ -38,15 +38,24 @@ csrfProtect();
$groups = new OTS_Groups_List(); $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 * @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 = '<b><span style="color: green">Gratis Premium Account</span></b>';
} else if(!$account_logged->isPremium()) {
$account_status = '<b><span style="color: red">Free Account</span></b>'; $account_status = '<b><span style="color: red">Free Account</span></b>';
else } else {
$account_status = '<b><span style="color: green">' . ($freePremium ? 'Gratis Premium Account' : 'Premium Account, ' . $account_logged->getPremDays() . ' '.$dayOrDays.' left') . '</span></b>'; $account_status = '<b><span style="color: green">' . $premiumLabel . ', ' . $premDays . ' '.$dayOrDays.' left</span></b>';
}
$recovery_key = $account_logged->getCustomField('key'); $recovery_key = $account_logged->getCustomField('key');
if(empty($recovery_key)) if(empty($recovery_key))
@@ -87,12 +96,8 @@ if($email_new_time > 1)
} }
} }
$actions = array(); $actions = $account_logged->getActionsLog(1000);
foreach($account_logged->getActionsLog(0, 1000) as $action) {
$actions[] = array('action' => $action['action'], 'date' => $action['date'], 'ip' => $action['ip'] != 0 ? long2ip($action['ip']) : inet_ntop($action['ipv6']));
}
$players = array();
/** @var OTS_Players_List $account_players */ /** @var OTS_Players_List $account_players */
$account_players = $account_logged->getPlayersList(); $account_players = $account_logged->getPlayersList();
$account_players->orderBy('id'); $account_players->orderBy('id');

View File

@@ -48,7 +48,7 @@ else
$account_logged->setCustomField('key', $new_rec_key); $account_logged->setCustomField('key', $new_rec_key);
$account_logged->setCustomField(setting('core.donate_column'), $account_logged->getCustomField(setting('core.donate_column')) - setting('core.account_generate_new_reckey_price')); $account_logged->setCustomField(setting('core.donate_column'), $account_logged->getCustomField(setting('core.donate_column')) - setting('core.account_generate_new_reckey_price'));
$account_logged->logAction('Generated new recovery key for ' . setting('core.account_generate_new_reckey_price') . ' premium points.'); $account_logged->logAction('Generated new recovery key for ' . setting('core.account_generate_new_reckey_price') . ' premium points.');
$message = '<br />Your recovery key were send on email address <b>'.$account_logged->getEMail().'</b> for '.setting('core.account_generate_new_reckey_price').' premium points.'; $message = '<br />Your recovery key was sent on email address <b>'.$account_logged->getEMail().'</b> for '.setting('core.account_generate_new_reckey_price').' premium points.';
} }
else else
$message = '<br /><p class="error">An error occurred while sending email ( <b>'.$account_logged->getEMail().'</b> ) with recovery key! Recovery key not changed. Try again later. For Admin: More info can be found in system/logs/mailer-error.log</p>'; $message = '<br /><p class="error">An error occurred while sending email ( <b>'.$account_logged->getEMail().'</b> ) with recovery key! Recovery key not changed. Try again later. For Admin: More info can be found in system/logs/mailer-error.log</p>';

View File

@@ -0,0 +1,94 @@
<?php
use MyAAC\Models\AccountEmailVerify;
defined('MYAAC') or die('Direct access not allowed!');
$title = 'Resend Email';
$errorWithBackButton = function ($msg) use ($twig) {
$errors = [$msg];
$twig->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 <a href=' . getLink('account/manage') . '>log in</a> 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 = "<p class='error'>An error occurred while sending email (<b>{$email}</b> )! Try again later. For Admin: More info can be found in system/logs/mailer-error.log</p>";
}
}
else {
$message = "<br />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');
}

View File

@@ -202,35 +202,37 @@ if($player->isLoaded() && !$player->isDeleted())
unset($storage); unset($storage);
} }
if($db->hasTable('player_items') && $db->hasColumn('player_items', 'pid') && $db->hasColumn('player_items', 'sid') && $db->hasColumn('player_items', 'itemtype')) { if ($db->hasTableAndColumns('player_items', ['pid', 'sid', 'itemtype'])) {
$eq_sql = $db->query('SELECT `pid`, `itemtype` FROM player_items WHERE player_id = '.$player->getId().' AND (`pid` >= 1 and `pid` <= 10)'); $eq_sql = $db->query('SELECT `pid`, `itemtype` FROM player_items WHERE player_id = '.$player->getId().' AND (`pid` >= 1 and `pid` <= 10)');
$equipment = array(); $equipment = [];
foreach($eq_sql as $eq) foreach($eq_sql as $eq) {
$equipment[$eq['pid']] = $eq['itemtype']; $equipment[$eq['pid']] = $eq['itemtype'];
}
$empty_slots = array("", "no_helmet", "no_necklace", "no_backpack", "no_armor", "no_handleft", "no_handright", "no_legs", "no_boots", "no_ring", "no_ammo"); $empty_slots = ["", "no_helmet", "no_necklace", "no_backpack", "no_armor", "no_handleft", "no_handright", "no_legs", "no_boots", "no_ring", "no_ammo"];
for($i = 0; $i <= 10; $i++)
{ for($i = 0; $i <= 10; $i++) {
if(!isset($equipment[$i]) || $equipment[$i] == 0) if(!isset($equipment[$i]) || $equipment[$i] == 0)
$equipment[$i] = $empty_slots[$i]; $equipment[$i] = $empty_slots[$i];
} }
for($i = 1; $i < 11; $i++) for($i = 1; $i < 11; $i++) {
{ if(Validator::number($equipment[$i])) {
if(Validator::number($equipment[$i]))
$equipment[$i] = getItemImage($equipment[$i]); $equipment[$i] = getItemImage($equipment[$i]);
else }
else {
$equipment[$i] = '<img src="images/items/' . $equipment[$i] . '.gif" width="32" height="32" border="0" alt=" ' . $equipment[$i] . '" />'; $equipment[$i] = '<img src="images/items/' . $equipment[$i] . '.gif" width="32" height="32" border="0" alt=" ' . $equipment[$i] . '" />';
} }
}
}
$skulls = array( $skulls = [
1 => 'yellow_skull', 1 => 'yellow_skull',
2 => 'green_skull', 2 => 'green_skull',
3 => 'white_skull', 3 => 'white_skull',
4 => 'red_skull', 4 => 'red_skull',
5 => 'black_skull' 5 => 'black_skull',
); ];
}
$dead_add_content = ''; $dead_add_content = '';
$deaths = array(); $deaths = array();
@@ -450,10 +452,8 @@ WHERE killers.death_id = '".$death['id']."' ORDER BY killers.final_hit DESC, kil
if($query->rowCount() > 0) { if($query->rowCount() > 0) {
echo 'Did you mean:<ul>'; echo 'Did you mean:<ul>';
foreach($query as $player) { foreach($query as $player) {
if(isset($player['promotion'])) { $player['vocation'] = OTS_Toolbox::getVocationFromPromotion($player['vocation'], $player['promotion'] ?? 0);
if((int)$player['promotion'] > 0)
$player['vocation'] += ($player['promotion'] * $config['vocations_amount']);
}
echo '<li>' . getPlayerLink($player['name']) . ' (<small><strong>level ' . $player['level'] . ', ' . $config['vocations'][$player['vocation']] . '</strong></small>)</li>'; echo '<li>' . getPlayerLink($player['name']) . ' (<small><strong>level ' . $player['level'] . ', ' . $config['vocations'][$player['vocation']] . '</strong></small>)</li>';
} }
echo '</ul>'; echo '</ul>';

View File

@@ -11,22 +11,22 @@
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
$title = 'Experience Stages'; $title = 'Experience Stages';
if(file_exists($config['data_path'] . 'XML/stages.xml')) { if((!isset($config['lua']['experienceStages']) || !getBoolean($config['lua']['experienceStages']))
$stages = new DOMDocument(); && (!isset($config['lua']['rateUseStages']) || !getBoolean($config['lua']['rateUseStages']))
$stages->load($config['data_path'] . 'XML/stages.xml'); ) {
}
if(!isset($config['lua']['experienceStages']) || !getBoolean($config['lua']['experienceStages']))
{
$enabled = false; $enabled = false;
if(isset($stages)) { if(file_exists($config['data_path'] . 'XML/stages.xml')) {
$stages = new DOMDocument();
$stages->load($config['data_path'] . 'XML/stages.xml');
foreach($stages->getElementsByTagName('config') as $node) { foreach($stages->getElementsByTagName('config') as $node) {
/** @var DOMElement $node */ /** @var DOMElement $node */
if($node->getAttribute('enabled')) if($node->getAttribute('enabled')) {
$enabled = true; $enabled = true;
} }
} }
}
if(!$enabled) { if(!$enabled) {
$rate_exp = 'not set'; $rate_exp = 'not set';
@@ -42,21 +42,12 @@ if(!isset($config['lua']['experienceStages']) || !getBoolean($config['lua']['exp
} }
} }
if(!$stages) $stages = new MyAAC\Server\ExpStages();
{ $stagesArray = $stages->get();
echo 'Error: cannot load <b>stages.xml</b>!';
if (empty($stagesArray)) {
echo 'Error when loading experience stages.';
return; return;
} }
$stagesArray = [];
foreach($stages->getElementsByTagName('stage') as $stage)
{
/** @var DOMElement $stage */
$maxLevel = $stage->getAttribute('maxlevel');
$stagesArray[] = [
'levels' => $stage->getAttribute('minlevel') . (isset($maxLevel[0]) ? '-' . $maxLevel : '+'),
'multiplier' => $stage->getAttribute('multiplier')
];
}
$twig->display('experience_stages.html.twig', ['stages' => $stagesArray]); $twig->display('experience_stages.html.twig', ['stages' => $stagesArray]);

View File

@@ -36,9 +36,9 @@ if(Forum::canPost($account_logged)) {
$thread = $db->query("SELECT `author_guid`, `author_aid`, `first_post`, `post_topic`, `post_date`, `post_text`, `post_smile`, `post_html`, `id`, `section` FROM `" . FORUM_TABLE_PREFIX . "forum` WHERE `id` = ".$post_id." LIMIT 1")->fetch(); $thread = $db->query("SELECT `author_guid`, `author_aid`, `first_post`, `post_topic`, `post_date`, `post_text`, `post_smile`, `post_html`, `id`, `section` FROM `" . FORUM_TABLE_PREFIX . "forum` WHERE `id` = ".$post_id." LIMIT 1")->fetch();
if(isset($thread['id'])) { if(isset($thread['id'])) {
$first_post = $db->query("SELECT `" . FORUM_TABLE_PREFIX . "forum`.`author_guid`, `" . FORUM_TABLE_PREFIX . "forum`.`author_aid`, `" . FORUM_TABLE_PREFIX . "forum`.`first_post`, `" . FORUM_TABLE_PREFIX . "forum`.`post_topic`, `" . FORUM_TABLE_PREFIX . "forum`.`post_text`, `" . FORUM_TABLE_PREFIX . "forum`.`post_smile`, `" . FORUM_TABLE_PREFIX . "forum`.`id`, `" . FORUM_TABLE_PREFIX . "forum`.`section` FROM `" . FORUM_TABLE_PREFIX . "forum` WHERE `" . FORUM_TABLE_PREFIX . "forum`.`id` = ".(int) $thread['first_post']." LIMIT 1")->fetch(); $first_post = $db->query("SELECT `" . FORUM_TABLE_PREFIX . "forum`.`author_guid`, `" . FORUM_TABLE_PREFIX . "forum`.`author_aid`, `" . FORUM_TABLE_PREFIX . "forum`.`first_post`, `" . FORUM_TABLE_PREFIX . "forum`.`post_topic`, `" . FORUM_TABLE_PREFIX . "forum`.`post_text`, `" . FORUM_TABLE_PREFIX . "forum`.`post_smile`, `" . FORUM_TABLE_PREFIX . "forum`.`id`, `" . FORUM_TABLE_PREFIX . "forum`.`section` FROM `" . FORUM_TABLE_PREFIX . "forum` WHERE `" . FORUM_TABLE_PREFIX . "forum`.`id` = ".(int) $thread['first_post']." LIMIT 1")->fetch();
echo '<a href="' . getLink('forum') . '">Boards</a> >> <a href="' . getForumBoardLink($thread['section']) . '">'.$sections[$thread['section']]['name'].'</a> >> <a href="' . getForumThreadLink($thread['first_post']) . '">'.htmlspecialchars($first_post['post_topic']).'</a> >> <b>Edit post</b>'; echo '<a href="' . getLink('forum') . '">Boards</a> >> <a href="' . getForumBoardLink($thread['section']) . '">'.escapeHtml($sections[$thread['section']]['name']).'</a> >> <a href="' . getForumThreadLink($thread['first_post']) . '">'.htmlspecialchars($first_post['post_topic']).'</a> >> <b>Edit post</b>';
if(Forum::hasAccess($thread['section'] && ($account_logged->getId() == $thread['author_aid'] || Forum::isModerator()))) { if(Forum::hasAccess($thread['section']) && ($account_logged->getId() == $thread['author_aid'] || Forum::isModerator())) {
$char_id = $post_topic = $text = $smile = $html = null; $char_id = $post_topic = $text = $smile = $html = null;
$players_from_account = $db->query("SELECT `players`.`name`, `players`.`id` FROM `players` WHERE `players`.`account_id` = ".(int) $account_logged->getId())->fetchAll(); $players_from_account = $db->query("SELECT `players`.`name`, `players`.`id` FROM `players` WHERE `players`.`account_id` = ".(int) $account_logged->getId())->fetchAll();
$saved = false; $saved = false;

View File

@@ -42,7 +42,7 @@ if(Forum::canPost($account_logged)) {
$thread = $db->query("SELECT `" . FORUM_TABLE_PREFIX . "forum`.`post_topic`, `" . FORUM_TABLE_PREFIX . "forum`.`id`, `" . FORUM_TABLE_PREFIX . "forum`.`section` FROM `" . FORUM_TABLE_PREFIX . "forum` WHERE `" . FORUM_TABLE_PREFIX . "forum`.`id` = ".(int) $thread_id." AND `" . FORUM_TABLE_PREFIX . "forum`.`first_post` = ".$thread_id." LIMIT 1")->fetch(); $thread = $db->query("SELECT `" . FORUM_TABLE_PREFIX . "forum`.`post_topic`, `" . FORUM_TABLE_PREFIX . "forum`.`id`, `" . FORUM_TABLE_PREFIX . "forum`.`section` FROM `" . FORUM_TABLE_PREFIX . "forum` WHERE `" . FORUM_TABLE_PREFIX . "forum`.`id` = ".(int) $thread_id." AND `" . FORUM_TABLE_PREFIX . "forum`.`first_post` = ".$thread_id." LIMIT 1")->fetch();
if(isset($thread['id']) && Forum::hasAccess($thread['section'])) { if(isset($thread['id']) && Forum::hasAccess($thread['section'])) {
echo '<a href="' . getLink('forum') . '">Boards</a> >> <a href="' . getForumBoardLink($thread['section']) . '">'.$sections[$thread['section']]['name'].'</a> >> <a href="' . getForumThreadLink($thread_id) . '">'.htmlspecialchars($thread['post_topic']).'</a> >> <b>Post new reply</b><br /><h3>'.htmlspecialchars($thread['post_topic']).'</h3>'; echo '<a href="' . getLink('forum') . '">Boards</a> >> <a href="' . getForumBoardLink($thread['section']) . '">'.escapeHtml($sections[$thread['section']]['name']).'</a> >> <a href="' . getForumThreadLink($thread_id) . '">'.htmlspecialchars($thread['post_topic']).'</a> >> <b>Post new reply</b><br /><h3>'.htmlspecialchars($thread['post_topic']).'</h3>';
$quote = isset($_REQUEST['quote']) ? (int) $_REQUEST['quote'] : NULL; $quote = isset($_REQUEST['quote']) ? (int) $_REQUEST['quote'] : NULL;
$text = isset($_POST['text']) ? stripslashes(trim($_POST['text'])) : NULL; $text = isset($_POST['text']) ? stripslashes(trim($_POST['text'])) : NULL;

View File

@@ -34,7 +34,7 @@ if(Forum::canPost($account_logged)) {
$players_from_account = $db->query('SELECT `players`.`name`, `players`.`id` FROM `players` WHERE `players`.`account_id` = '.(int) $account_logged->getId())->fetchAll(); $players_from_account = $db->query('SELECT `players`.`name`, `players`.`id` FROM `players` WHERE `players`.`account_id` = '.(int) $account_logged->getId())->fetchAll();
$section_id = $_REQUEST['section_id'] ?? null; $section_id = $_REQUEST['section_id'] ?? null;
if($section_id !== null) { if($section_id !== null) {
echo '<a href="' . getLink('forum') . '">Boards</a> >> <a href="' . getForumBoardLink($section_id) . '">' . $sections[$section_id]['name'] . '</a> >> <b>Post new thread</b><br />'; echo '<a href="' . getLink('forum') . '">Boards</a> >> <a href="' . getForumBoardLink($section_id) . '">' . escapeHtml($sections[$section_id]['name']) . '</a> >> <b>Post new thread</b><br />';
if(isset($sections[$section_id]['name']) && Forum::hasAccess($section_id)) { if(isset($sections[$section_id]['name']) && Forum::hasAccess($section_id)) {
if ($sections[$section_id]['closed'] && !Forum::isModerator()) if ($sections[$section_id]['closed'] && !Forum::isModerator())

View File

@@ -42,35 +42,12 @@ for($i = 0; $i < $threads_count['threads_count'] / setting('core.forum_threads_p
$links_to_pages .= '<b>'.($i + 1).' </b>'; $links_to_pages .= '<b>'.($i + 1).' </b>';
} }
echo '<a href="' . getLink('forum') . '">Boards</a> >> <b>'.$sections[$section_id]['name'].'</b>';
if($logged && (!$sections[$section_id]['closed'] || Forum::isModerator())) {
echo '<br /><br />
<a href="' . getLink('forum') . '?action=new_thread&section_id='.$section_id.'"><img src="images/forum/topic.gif" border="0" /></a>';
}
echo '<br /><br />Page: '.$links_to_pages.'<br />';
$last_threads = $db->query("SELECT `players`.`id` as `player_id`, `players`.`name`, `" . FORUM_TABLE_PREFIX . "forum`.`first_post`, `" . FORUM_TABLE_PREFIX . "forum`.`post_text`, `" . FORUM_TABLE_PREFIX . "forum`.`post_topic`, `" . FORUM_TABLE_PREFIX . "forum`.`id`, `" . FORUM_TABLE_PREFIX . "forum`.`last_post`, `" . FORUM_TABLE_PREFIX . "forum`.`replies`, `" . FORUM_TABLE_PREFIX . "forum`.`views`, `" . FORUM_TABLE_PREFIX . "forum`.`post_date` FROM `players`, `" . FORUM_TABLE_PREFIX . "forum` WHERE `players`.`id` = `" . FORUM_TABLE_PREFIX . "forum`.`author_guid` AND `" . FORUM_TABLE_PREFIX . "forum`.`section` = ".$section_id." AND `" . FORUM_TABLE_PREFIX . "forum`.`first_post` = `" . FORUM_TABLE_PREFIX . "forum`.`id` ORDER BY `" . FORUM_TABLE_PREFIX . "forum`.`last_post` DESC LIMIT ".setting('core.forum_threads_per_page')." OFFSET ".($_page * setting('core.forum_threads_per_page')))->fetchAll(PDO::FETCH_ASSOC); $last_threads = $db->query("SELECT `players`.`id` as `player_id`, `players`.`name`, `" . FORUM_TABLE_PREFIX . "forum`.`first_post`, `" . FORUM_TABLE_PREFIX . "forum`.`post_text`, `" . FORUM_TABLE_PREFIX . "forum`.`post_topic`, `" . FORUM_TABLE_PREFIX . "forum`.`id`, `" . FORUM_TABLE_PREFIX . "forum`.`last_post`, `" . FORUM_TABLE_PREFIX . "forum`.`replies`, `" . FORUM_TABLE_PREFIX . "forum`.`views`, `" . FORUM_TABLE_PREFIX . "forum`.`post_date` FROM `players`, `" . FORUM_TABLE_PREFIX . "forum` WHERE `players`.`id` = `" . FORUM_TABLE_PREFIX . "forum`.`author_guid` AND `" . FORUM_TABLE_PREFIX . "forum`.`section` = ".$section_id." AND `" . FORUM_TABLE_PREFIX . "forum`.`first_post` = `" . FORUM_TABLE_PREFIX . "forum`.`id` ORDER BY `" . FORUM_TABLE_PREFIX . "forum`.`last_post` DESC LIMIT ".setting('core.forum_threads_per_page')." OFFSET ".($_page * setting('core.forum_threads_per_page')))->fetchAll(PDO::FETCH_ASSOC);
if(isset($last_threads[0])) { $threads = [];
echo '<table width="100%"> if(count($last_threads) > 0) {
<tr bgcolor="'.$config['vdarkborder'].'" align="center">
<td class="white">
<span style="font-size: 10px"><b>Thread</b></span></td>
<td><span style="font-size: 10px"><b>Thread Starter</b></span></td>
<td><span style="font-size: 10px"><b>Replies</b></span></td>
<td><span style="font-size: 10px"><b>Views</b></span></td>
<td><span style="font-size: 10px"><b>Last Post</b></span></td>
</tr>';
$player = new OTS_Player(); $player = new OTS_Player();
foreach($last_threads as $thread) { foreach($last_threads as $thread) {
echo '<tr bgcolor="' . getStyle($number_of_rows++) . '"><td>';
if(Forum::isModerator()) {
echo '<a href="' . getLink('forum') . '?action=move_thread&id=' . $thread['id'] . '" title="Move Thread"><img src="images/icons/arrow_right.gif"/></a>';
$twig->display('forum.remove_post.html.twig', ['post' => $thread]);
}
$player->load($thread['player_id']); $player->load($thread['player_id']);
if(!$player->isLoaded()) { if(!$player->isLoaded()) {
throw new RuntimeException('Forum error: Player not loaded.'); throw new RuntimeException('Forum error: Player not loaded.');
@@ -79,28 +56,29 @@ if(isset($last_threads[0])) {
$player_account = $player->getAccount(); $player_account = $player->getAccount();
$canEditForum = $player_account->hasFlag(FLAG_CONTENT_FORUM) || $player_account->isAdmin(); $canEditForum = $player_account->hasFlag(FLAG_CONTENT_FORUM) || $player_account->isAdmin();
echo '<a href="' . getForumThreadLink($thread['id']) . '">'.htmlspecialchars($thread['post_topic']). '</a><br /><small>'.($canEditForum ? substr(strip_tags($thread['post_text']), 0, 50) : htmlspecialchars(substr($thread['post_text'], 0, 50))).'...</small></td><td>' . getPlayerLink($thread['name']) . '</td><td>'.(int) $thread['replies'].'</td><td>'.(int) $thread['views'].'</td><td>'; $thread['link'] = getForumThreadLink($thread['id']);
$thread['post_shortened'] = ($canEditForum ? substr(strip_tags($thread['post_text']), 0, 50) : htmlspecialchars(substr($thread['post_text'], 0, 50)));
$thread['player'] = $player;
$thread['player_link'] = getPlayerLink($thread['name']);
if($thread['last_post'] > 0) { if($thread['last_post'] > 0) {
$last_post = $db->query("SELECT `players`.`name`, `" . FORUM_TABLE_PREFIX . "forum`.`post_date` FROM `players`, `" . FORUM_TABLE_PREFIX . "forum` WHERE `" . FORUM_TABLE_PREFIX . "forum`.`first_post` = ".(int) $thread['id']." AND `players`.`id` = `" . FORUM_TABLE_PREFIX . "forum`.`author_guid` ORDER BY `post_date` DESC LIMIT 1")->fetch(); $last_post = $db->query("SELECT `players`.`name`, `" . FORUM_TABLE_PREFIX . "forum`.`post_date` FROM `players`, `" . FORUM_TABLE_PREFIX . "forum` WHERE `" . FORUM_TABLE_PREFIX . "forum`.`first_post` = ".(int) $thread['id']." AND `players`.`id` = `" . FORUM_TABLE_PREFIX . "forum`.`author_guid` ORDER BY `post_date` DESC LIMIT 1")->fetch();
if(isset($last_post['name'])) { $last_post['player_link'] = getPlayerLink($last_post['name']);
echo date('d.m.y H:i:s', $last_post['post_date']) . '<br />by ' . getPlayerLink($last_post['name']); $thread['latest_post'] = $last_post;
}
else {
echo 'No posts.';
}
}
else {
echo date('d.m.y H:i:s', $thread['post_date']) . '<br />by ' . getPlayerLink($thread['name']);
}
echo '</td></tr>';
} }
echo '</table>'; $threads[] = $thread;
if($logged && (!$sections[$section_id]['closed'] || Forum::isModerator())) {
echo '<br /><a href="' . getLink('forum') . '?action=new_thread&section_id=' . $section_id . '"><img src="images/forum/topic.gif" border="0" /></a>';
} }
} }
else {
echo '<h3>No threads in this board.</h3>'; $twig->display('forum.show_board.html.twig', [
} 'threads' => $threads,
'section_id' => $section_id,
'section_name' => $sections[$section_id]['name'],
'links_to_pages' => $links_to_pages,
'is_moderator' => Forum::isModerator(),
'closed' => $sections[$section_id]['closed'],
]);

Some files were not shown because too many files have changed in this diff Show More