From 136731068a11027fee324d912fe7493c74a29a48 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Sat, 19 Oct 2024 11:12:32 -0700 Subject: [PATCH 01/24] wip --- composer.json | 3 ++- core/init.php | 13 ++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 465a7f960a..f8587f2662 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,8 @@ "joypixels/emoji-toolkit": "^7.0", "geoip2/geoip2": "^2.13", "jenssegers/agent": "^2.6", - "php-di/php-di": "^6.4" + "php-di/php-di": "^6.4", + "aberdeener/nameless-composer-module": "^1.0" }, "require-dev": { "phpstan/phpstan": "1.6.9", diff --git a/core/init.php b/core/init.php index 2e367c500b..07c2bfadfb 100644 --- a/core/init.php +++ b/core/init.php @@ -469,13 +469,24 @@ } } - // Load modules + // Load classic modules foreach ($enabled_modules as $module) { if (file_exists(ROOT_PATH . '/modules/' . $module['name'] . '/init.php')) { require_once ROOT_PATH . '/modules/' . $module['name'] . '/init.php'; } } + // Load new modules + $composer_json = ROOT_PATH . '/composer.lock'; + if (file_exists($composer_json)) { + $packages = json_decode(file_get_contents($composer_json), true)['packages']; + foreach ($packages as $package) { + if ($package['type'] === 'nameless-module') { + require_once ROOT_PATH . '/vendor/' . $package['name'] . '/init.php'; + } + } + } + // Maintenance mode? if (Settings::get('maintenance') === '1') { // Enabled From a5db17d56dd7106f97ba9d74cf555bb73ff3a5d3 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Sat, 19 Oct 2024 11:14:15 -0700 Subject: [PATCH 02/24] wip --- core/init.php | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/core/init.php b/core/init.php index 07c2bfadfb..c964aec7dd 100644 --- a/core/init.php +++ b/core/init.php @@ -477,13 +477,10 @@ } // Load new modules - $composer_json = ROOT_PATH . '/composer.lock'; - if (file_exists($composer_json)) { - $packages = json_decode(file_get_contents($composer_json), true)['packages']; - foreach ($packages as $package) { - if ($package['type'] === 'nameless-module') { - require_once ROOT_PATH . '/vendor/' . $package['name'] . '/init.php'; - } + $packages = json_decode(file_get_contents(ROOT_PATH . '/composer.lock'), true)['packages']; + foreach ($packages as $package) { + if ($package['type'] === 'nameless-module') { + require_once ROOT_PATH . '/vendor/' . $package['name'] . '/init.php'; } } From 564cd2fa0d4d31cc3572e3f8a28da822c4f025a4 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Sun, 20 Oct 2024 14:17:52 -0700 Subject: [PATCH 03/24] wip --- composer.json | 6 +- core/classes/Core/Cache.php | 12 + core/classes/Core/Module.php | 2 + core/classes/Core/Pages.php | 4 +- core/classes/Events/EventHandler.php | 13 +- core/classes/Events/Listener.php | 9 + core/classes/Extend/BaseExtender.php | 20 ++ core/classes/Extend/Container.php | 22 ++ core/classes/Extend/DebugInfo.php | 18 ++ core/classes/Extend/Events.php | 28 +++ core/classes/Extend/FrontendPages.php | 60 +++++ core/classes/Extend/Language.php | 21 ++ core/classes/Extend/PanelPages.php | 45 ++++ core/classes/Extend/Permissions.php | 29 +++ core/classes/Extend/Queries.php | 41 ++++ core/classes/Misc/ErrorHandler.php | 6 + core/classes/Pages/FrontendPage.php | 7 + core/classes/Pages/Page.php | 13 + core/classes/Pages/PanelPage.php | 7 + core/classes/Queries/Query.php | 17 ++ core/init.php | 21 +- ...220921014904_create_member_lists_table.php | 22 -- core/templates/frontend_init.php | 4 +- .../Default/members/member_lists.tpl | 104 -------- .../Default/members/members_settings.tpl | 112 --------- custom/panel_templates/Default/template.php | 11 - .../DefaultRevamp/DefaultRevamp_Template.php | 150 ++++++++++++ .../DefaultRevamp/members/members.tpl | 228 ------------------ index.php | 42 +++- .../Misc/RegisteredMembersListProvider.php | 1 + .../classes/Misc/StaffMembersListProvider.php | 2 + modules/Core/module.php | 11 +- ...tForumReactionScoresMemberListProvider.php | 1 + .../classes/MostPostsMemberListProvider.php | 1 + modules/Forum/module.php | 15 +- .../classes/GroupMemberListProvider.php | 17 -- modules/Members/classes/MemberListManager.php | 110 --------- .../Members/classes/MemberListProvider.php | 182 -------------- modules/Members/init.php | 7 - modules/Members/language/cs_CZ.json | 19 -- modules/Members/language/da_DK.json | 1 - modules/Members/language/de_DE.json | 19 -- modules/Members/language/el_GR.json | 1 - modules/Members/language/en_UK.json | 19 -- modules/Members/language/en_US.json | 19 -- modules/Members/language/es_419.json | 19 -- modules/Members/language/es_ES.json | 19 -- modules/Members/language/fa_IR.json | 19 -- modules/Members/language/fi_FI.json | 1 - modules/Members/language/fr_FR.json | 19 -- modules/Members/language/hr_HR.json | 1 - modules/Members/language/hu_HU.json | 19 -- modules/Members/language/id_ID.json | 1 - modules/Members/language/it_IT.json | 18 -- modules/Members/language/ja_JP.json | 1 - modules/Members/language/ko_KR.json | 1 - modules/Members/language/lt_LT.json | 1 - modules/Members/language/lv_LV.json | 1 - modules/Members/language/nl_NL.json | 19 -- modules/Members/language/no_NO.json | 1 - modules/Members/language/pl_PL.json | 19 -- modules/Members/language/pt_BR.json | 1 - modules/Members/language/ro_RO.json | 1 - modules/Members/language/ru_RU.json | 19 -- modules/Members/language/sk_SK.json | 19 -- modules/Members/language/sl_SI.json | 1 - modules/Members/language/sq_AL.json | 1 - modules/Members/language/sr_RS.json | 1 - modules/Members/language/sv_SE.json | 1 - modules/Members/language/th_TH.json | 1 - modules/Members/language/tr_TR.json | 19 -- modules/Members/language/uk_UA.json | 1 - modules/Members/language/vi_VN.json | 1 - modules/Members/language/zh_CN.json | 19 -- modules/Members/language/zh_TW.json | 1 - modules/Members/module.php | 133 ---------- modules/Members/pages/members.php | 133 ---------- modules/Members/pages/panel/member_lists.php | 71 ------ modules/Members/pages/panel/settings.php | 104 -------- modules/Members/queries/member_list.php | 29 --- 80 files changed, 596 insertions(+), 1618 deletions(-) create mode 100644 core/classes/Events/Listener.php create mode 100644 core/classes/Extend/BaseExtender.php create mode 100644 core/classes/Extend/Container.php create mode 100644 core/classes/Extend/DebugInfo.php create mode 100644 core/classes/Extend/Events.php create mode 100644 core/classes/Extend/FrontendPages.php create mode 100644 core/classes/Extend/Language.php create mode 100644 core/classes/Extend/PanelPages.php create mode 100644 core/classes/Extend/Permissions.php create mode 100644 core/classes/Extend/Queries.php create mode 100644 core/classes/Pages/FrontendPage.php create mode 100644 core/classes/Pages/Page.php create mode 100644 core/classes/Pages/PanelPage.php create mode 100644 core/classes/Queries/Query.php delete mode 100644 core/migrations/20220921014904_create_member_lists_table.php delete mode 100644 custom/panel_templates/Default/members/member_lists.tpl delete mode 100644 custom/panel_templates/Default/members/members_settings.tpl create mode 100644 custom/templates/DefaultRevamp/DefaultRevamp_Template.php delete mode 100644 custom/templates/DefaultRevamp/members/members.tpl delete mode 100644 modules/Members/classes/GroupMemberListProvider.php delete mode 100644 modules/Members/classes/MemberListManager.php delete mode 100644 modules/Members/classes/MemberListProvider.php delete mode 100644 modules/Members/init.php delete mode 100644 modules/Members/language/cs_CZ.json delete mode 100644 modules/Members/language/da_DK.json delete mode 100644 modules/Members/language/de_DE.json delete mode 100644 modules/Members/language/el_GR.json delete mode 100644 modules/Members/language/en_UK.json delete mode 100644 modules/Members/language/en_US.json delete mode 100644 modules/Members/language/es_419.json delete mode 100644 modules/Members/language/es_ES.json delete mode 100644 modules/Members/language/fa_IR.json delete mode 100644 modules/Members/language/fi_FI.json delete mode 100644 modules/Members/language/fr_FR.json delete mode 100644 modules/Members/language/hr_HR.json delete mode 100644 modules/Members/language/hu_HU.json delete mode 100644 modules/Members/language/id_ID.json delete mode 100644 modules/Members/language/it_IT.json delete mode 100644 modules/Members/language/ja_JP.json delete mode 100644 modules/Members/language/ko_KR.json delete mode 100644 modules/Members/language/lt_LT.json delete mode 100644 modules/Members/language/lv_LV.json delete mode 100644 modules/Members/language/nl_NL.json delete mode 100644 modules/Members/language/no_NO.json delete mode 100644 modules/Members/language/pl_PL.json delete mode 100644 modules/Members/language/pt_BR.json delete mode 100644 modules/Members/language/ro_RO.json delete mode 100644 modules/Members/language/ru_RU.json delete mode 100644 modules/Members/language/sk_SK.json delete mode 100644 modules/Members/language/sl_SI.json delete mode 100644 modules/Members/language/sq_AL.json delete mode 100644 modules/Members/language/sr_RS.json delete mode 100644 modules/Members/language/sv_SE.json delete mode 100644 modules/Members/language/th_TH.json delete mode 100644 modules/Members/language/tr_TR.json delete mode 100644 modules/Members/language/uk_UA.json delete mode 100644 modules/Members/language/vi_VN.json delete mode 100644 modules/Members/language/zh_CN.json delete mode 100644 modules/Members/language/zh_TW.json delete mode 100644 modules/Members/module.php delete mode 100644 modules/Members/pages/members.php delete mode 100644 modules/Members/pages/panel/member_lists.php delete mode 100644 modules/Members/pages/panel/settings.php delete mode 100644 modules/Members/queries/member_list.php diff --git a/composer.json b/composer.json index f8587f2662..40895f3afa 100644 --- a/composer.json +++ b/composer.json @@ -8,6 +8,7 @@ "php": "7.4" } }, + "minimum-stability": "dev", "require": { "php": ">=7.4", "jdorn/sql-formatter": "^1.2.17", @@ -33,7 +34,7 @@ "geoip2/geoip2": "^2.13", "jenssegers/agent": "^2.6", "php-di/php-di": "^6.4", - "aberdeener/nameless-composer-module": "^1.0" + "aberdeener/nameless-composer-module": "dev-main" }, "require-dev": { "phpstan/phpstan": "1.6.9", @@ -54,8 +55,7 @@ "modules/Discord Integration/widgets", "modules/Forum/classes", "modules/Forum/hooks", - "modules/Forum/widgets", - "modules/Members/classes" + "modules/Forum/widgets" ] } } diff --git a/core/classes/Core/Cache.php b/core/classes/Core/Cache.php index f55c2db5f1..4743e7d3cd 100644 --- a/core/classes/Core/Cache.php +++ b/core/classes/Core/Cache.php @@ -295,6 +295,18 @@ public function retrieveAll(bool $meta = false): array return $results; } + public function fetch(string $key, callable $callback, int $expiration = 0) + { + if ($this->isCached($key)) { + return $this->retrieve($key); + } + + $data = $callback(); + $this->store($key, $data, $expiration); + + return $data; + } + /** * Erase cached entry by its key. * diff --git a/core/classes/Core/Module.php b/core/classes/Core/Module.php index e53da64187..ba0d6a7dff 100644 --- a/core/classes/Core/Module.php +++ b/core/classes/Core/Module.php @@ -21,6 +21,8 @@ abstract class Module private array $_load_before; private array $_load_after; + public static \DI\Container $container; + public function __construct( Module $module, string $name, diff --git a/core/classes/Core/Pages.php b/core/classes/Core/Pages.php index 88e0309ac6..cbef511d4b 100644 --- a/core/classes/Core/Pages.php +++ b/core/classes/Core/Pages.php @@ -42,14 +42,16 @@ class Pages * @param string $file Path (from module folder) to page file. * @param string $name Name of page. * @param bool $widgets Can widgets be used on the page? Default false. + * @param bool $controllerBased Is the page controller based? Default false. */ - public function add(string $module, string $url, string $file, string $name = '', bool $widgets = false): void + public function add(string $module, string $url, string $file, string $name = '', bool $widgets = false, bool $controllerBased = false): void { $this->_pages[$url] = [ 'module' => $module, 'file' => $file, 'name' => $name, 'widgets' => $widgets, + 'controllerBased' => $controllerBased, 'id' => $this->_id++, ]; } diff --git a/core/classes/Events/EventHandler.php b/core/classes/Events/EventHandler.php index 4281926182..edafcc58b6 100644 --- a/core/classes/Events/EventHandler.php +++ b/core/classes/Events/EventHandler.php @@ -86,7 +86,7 @@ public static function registerEvent( * @param callable|class-string $callback Listener callback to execute when event is executed. If class name is provided, we will assume there is a static "execute" method on the class. * @param int $priority Execution priority - higher gets executed first */ - public static function registerListener(string $event, $callback, int $priority = 10): void + public static function registerListener(string $event, $callback, int $priority = 10, \DI\Container $container = null): void { $name = class_exists($event) && is_subclass_of($event, AbstractEvent::class) ? $event::name() @@ -97,8 +97,17 @@ public static function registerListener(string $event, $callback, int $priority self::registerEvent($event, $event); } + // TODO cleanup if (is_string($callback) && class_exists($callback)) { - $callback = [$callback, 'execute']; + if (!is_subclass_of($callback, \NamelessMC\Framework\Events\Listener::class)) { + $callback = [$callback, 'execute']; + } else { + // TODO could this initialization be moved closer to when it's actually called? + // when it's here, modules can't do things in their constructor such as setting + // the cache location since it could get overwritten by any code that sets cache between + // this and when the listener is actually called + $callback = [$container->make($callback), 'handle']; + } } self::$_events[$name]['listeners'][] = [ diff --git a/core/classes/Events/Listener.php b/core/classes/Events/Listener.php new file mode 100644 index 0000000000..3a2fb05de3 --- /dev/null +++ b/core/classes/Events/Listener.php @@ -0,0 +1,9 @@ +moduleName = $moduleName; + $this->moduleDisplayName = $moduleDisplayName; + + return $this; + } + + abstract public function extend(Container $container): void; + +} \ No newline at end of file diff --git a/core/classes/Extend/Container.php b/core/classes/Extend/Container.php new file mode 100644 index 0000000000..7a8f6dae46 --- /dev/null +++ b/core/classes/Extend/Container.php @@ -0,0 +1,22 @@ +singletons as $class) { + $container->set($class, $container->get($class)); + } + } + + public function singleton(string $class): Container { + $this->singletons[] = $class; + + return $this; + } +} \ No newline at end of file diff --git a/core/classes/Extend/DebugInfo.php b/core/classes/Extend/DebugInfo.php new file mode 100644 index 0000000000..df6608b5de --- /dev/null +++ b/core/classes/Extend/DebugInfo.php @@ -0,0 +1,18 @@ +listeners as $event => $listeners) { + foreach ($listeners as $listener) { + \EventHandler::registerListener($event, $listener, 10, $container); + } + } + } + + public function listen(string $event, string $listener): Events { + if (!isset($this->listeners[$event])) { + $this->listeners[$event] = []; + } + + $this->listeners[$event][] = $listener; + + return $this; + } +} \ No newline at end of file diff --git a/core/classes/Extend/FrontendPages.php b/core/classes/Extend/FrontendPages.php new file mode 100644 index 0000000000..881b71e1ca --- /dev/null +++ b/core/classes/Extend/FrontendPages.php @@ -0,0 +1,60 @@ +get("{$this->moduleName}Language"); + + /** @var \Pages */ + $pages = $container->get(\Pages::class); + + foreach ($this->pages as $page) { + // Remove loading / from path - allows devs to ->register('/') + $path = ltrim($page['path'], '/'); + $path = "/{$this->moduleName}/{$path}"; + // Remove ending / if it exists + $path = rtrim($path, '/'); + + $pages->add( + $this->moduleName, + $path, + $page['handler'], + $moduleLanguage->get($page['name']), + $page['allowWidgets'], + true, + ); + } + + /** @var \Smarty */ + $smarty = $container->get(\Smarty::class); + + foreach ($this->templateDirectories as $directory) { + $smarty->addTemplateDir($directory); + } + } + + public function register(string $path, string $name, string $handler, bool $allowWidgets): FrontendPages { + $this->pages[] = [ + 'path' => $path, + 'name' => $name, + 'handler' => $handler, + 'allowWidgets' => $allowWidgets + ]; + + return $this; + } + + public function templateDirectory(string $path): FrontendPages { + $this->templateDirectories[] = $path; + + return $this; + } +} \ No newline at end of file diff --git a/core/classes/Extend/Language.php b/core/classes/Extend/Language.php new file mode 100644 index 0000000000..b07d47bf78 --- /dev/null +++ b/core/classes/Extend/Language.php @@ -0,0 +1,21 @@ +path = $path; + } + + public function extend(Container $container): void { + $containerKey = "{$this->moduleName}Language"; + + $container->set($containerKey, function() { + return new \Language($this->path); + }); + } +} \ No newline at end of file diff --git a/core/classes/Extend/PanelPages.php b/core/classes/Extend/PanelPages.php new file mode 100644 index 0000000000..450d48e36d --- /dev/null +++ b/core/classes/Extend/PanelPages.php @@ -0,0 +1,45 @@ +get("{$this->moduleName}Language"); + + /** @var \Pages */ + $pages = $container->get(\Pages::class); + + foreach ($this->pages as $page) { + // Remove loading / from path - allows devs to ->register('/') + $path = ltrim($page['path'], '/'); + $path = "/panel/{$this->moduleName}/{$path}"; + // Remove ending / if it exists + $path = rtrim($path, '/'); + + $pages->add( + $this->moduleName, + $path, + $page['handler'], + $moduleLanguage->get($page['name']), + false, + true, + ); + } + } + + public function register(string $path, string $name, string $handler): PanelPages { + $this->pages[] = [ + 'path' => $path, + 'name' => $name, + 'handler' => $handler, + ]; + + return $this; + } +} \ No newline at end of file diff --git a/core/classes/Extend/Permissions.php b/core/classes/Extend/Permissions.php new file mode 100644 index 0000000000..b189a7b1dd --- /dev/null +++ b/core/classes/Extend/Permissions.php @@ -0,0 +1,29 @@ +get(\Language::class); + $moduleLanguage = $container->get("{$this->moduleName}Language"); + + if (isset($this->permissions['staffcp'])) { + foreach ($this->permissions['staffcp'] as $permission => $name) { + \PermissionHandler::registerPermissions($coreLanguage->get('moderator', 'staff_cp'), [ + $permission => $this->moduleDisplayName . ' » ' . $moduleLanguage->get($name) + ]); + } + } + } + + public function register(array $permissions): Permissions { + $this->permissions = $permissions; + + return $this; + } +} \ No newline at end of file diff --git a/core/classes/Extend/Queries.php b/core/classes/Extend/Queries.php new file mode 100644 index 0000000000..721e4f59ae --- /dev/null +++ b/core/classes/Extend/Queries.php @@ -0,0 +1,41 @@ +get(\Pages::class); + + foreach ($this->pages as $page) { + // Remove leading / from path - allows devs to ->register('/') + $path = ltrim($page['path'], '/'); + $path = "/queries/{$this->moduleName}/{$path}"; + // Remove ending / if it exists + $path = rtrim($path, '/'); + + $pages->add( + $this->moduleName, + $path, + $page['handler'], + '', + false, + true, + ); + } + } + + public function register(string $path, string $handler): Queries { + $this->pages[] = [ + 'path' => $path, + 'handler' => $handler, + ]; + + return $this; + } +} \ No newline at end of file diff --git a/core/classes/Misc/ErrorHandler.php b/core/classes/Misc/ErrorHandler.php index bf3178c0b4..4946735941 100644 --- a/core/classes/Misc/ErrorHandler.php +++ b/core/classes/Misc/ErrorHandler.php @@ -107,6 +107,12 @@ public static function catchException(?Throwable $exception, ?string $error_stri continue; } + // Skip frame if it is a function call (Composer autoload, etc) + if (!isset($frame['file'])) { + $skip_frames++; + continue; + } + $frames[] = self::parseFrame($exception, $frame['file'], $frame['line'], $i); $i--; } diff --git a/core/classes/Pages/FrontendPage.php b/core/classes/Pages/FrontendPage.php new file mode 100644 index 0000000000..6c79cdb426 --- /dev/null +++ b/core/classes/Pages/FrontendPage.php @@ -0,0 +1,7 @@ +set(Cache::class, function () { return new Cache([ 'name' => 'nameless', @@ -118,7 +119,7 @@ } // Ensure database is up-to-date - PhinxAdapter::ensureUpToDate('Core'); + // PhinxAdapter::ensureUpToDate('Core'); // Error reporting if (!defined('DEBUGGING')) { @@ -234,9 +235,9 @@ define('LANGUAGE', $language[0]->short_code); } } - $container->set(Language::class, function () { - return new Language('core', LANGUAGE); - }); + $coreLanguage = fn() => new Language('core', LANGUAGE); + $container->set(Language::class, $coreLanguage); + $container->set('coreLanguage', $coreLanguage); $language = $container->get(Language::class); @@ -477,10 +478,18 @@ } // Load new modules - $packages = json_decode(file_get_contents(ROOT_PATH . '/composer.lock'), true)['packages']; + $packages = json_decode(file_get_contents(ROOT_PATH . '/vendor/composer/installed.json'), true)['packages']; foreach ($packages as $package) { if ($package['type'] === 'nameless-module') { - require_once ROOT_PATH . '/vendor/' . $package['name'] . '/init.php'; + $extra = $package['extra']; + /** @var NamelessMC\Framework\Extend\BaseExtender[] $extenders */ + $extenders = require_once ROOT_PATH . '/vendor/' . $package['name'] . '/module.php'; + foreach ($extenders as $extender) { + $extender->setModuleName( + $package['extra']['nameless_module']['name'], + $package['extra']['nameless_module']['display_name'] + )->extend($container); + } } } diff --git a/core/migrations/20220921014904_create_member_lists_table.php b/core/migrations/20220921014904_create_member_lists_table.php deleted file mode 100644 index de9869993d..0000000000 --- a/core/migrations/20220921014904_create_member_lists_table.php +++ /dev/null @@ -1,22 +0,0 @@ -table('nl2_member_lists', ['id' => false, 'primary_key' => 'name']); - - $table->addColumn('name', 'string', ['limit' => 64]) - ->addColumn('friendly_name', 'string', ['limit' => 64]) - ->addColumn('module', 'string', ['limit' => 64]) - ->addColumn('enabled', 'boolean', ['default' => true]); - - $table->addIndex(['name', 'friendly_name'], ['unique' => true]); - - $table->create(); - } -} diff --git a/core/templates/frontend_init.php b/core/templates/frontend_init.php index 1ae8f24c9c..9b79958a87 100644 --- a/core/templates/frontend_init.php +++ b/core/templates/frontend_init.php @@ -53,11 +53,11 @@ $smarty->setCompileDir(ROOT_PATH . '/cache/templates_c'); if (file_exists(ROOT_PATH . '/custom/templates/' . TEMPLATE . '/template.php')) { - $smarty->setTemplateDir(ROOT_PATH . '/custom/templates/' . TEMPLATE); + $smarty->addTemplateDir(ROOT_PATH . '/custom/templates/' . TEMPLATE); require(ROOT_PATH . '/custom/templates/' . TEMPLATE . '/template.php'); } else { - $smarty->setTemplateDir(ROOT_PATH . '/custom/templates/DefaultRevamp'); + $smarty->addTemplateDir(ROOT_PATH . '/custom/templates/DefaultRevamp'); require(ROOT_PATH . '/custom/templates/DefaultRevamp/template.php'); } diff --git a/custom/panel_templates/Default/members/member_lists.tpl b/custom/panel_templates/Default/members/member_lists.tpl deleted file mode 100644 index e0667f3196..0000000000 --- a/custom/panel_templates/Default/members/member_lists.tpl +++ /dev/null @@ -1,104 +0,0 @@ -{include file='header.tpl'} - - - - -
- - - {include file='sidebar.tpl'} - - -
- - -
- - - {include file='navbar.tpl'} - - -
- - -
-

{$MEMBER_LISTS}

- -
- - - {include file='includes/update.tpl'} - -
-
- - {include file='includes/alerts.tpl'} - -
- - - - - - - - - - - {foreach $MEMBER_LISTS_VALUES as $member_list} - - - - - - - {/foreach} - -
{$NAME}{$MODULE}{$ENABLED}
- {$member_list->getFriendlyName()} - - {$member_list->getModule()} - {if $member_list->isEnabled() eq 1}{else}{/if} -
- - - {if $member_list->isEnabled() eq 1} - - {else} - - {/if} -
-
-
- -
-
- - -
- - -
- - -
- - {include file='footer.tpl'} - - -
- - -
- -{include file='scripts.tpl'} - - - - diff --git a/custom/panel_templates/Default/members/members_settings.tpl b/custom/panel_templates/Default/members/members_settings.tpl deleted file mode 100644 index 01375c6d2f..0000000000 --- a/custom/panel_templates/Default/members/members_settings.tpl +++ /dev/null @@ -1,112 +0,0 @@ -{include file='header.tpl'} - - - - -
- - - {include file='sidebar.tpl'} - - -
- - -
- - - {include file='navbar.tpl'} - - -
- - -
-

{$SETTINGS}

- -
- - - {include file='includes/update.tpl'} - -
-
- - - {include file='includes/alerts.tpl'} - -
-
- - -
- -
- - - -
- -
- - -
- -
- - -
-
-
-
- - -
- - -
- - -
- - {include file='footer.tpl'} - - -
- - -
- - {include file='scripts.tpl'} - - - - - diff --git a/custom/panel_templates/Default/template.php b/custom/panel_templates/Default/template.php index 1aff0469f8..1944babcd7 100644 --- a/custom/panel_templates/Default/template.php +++ b/custom/panel_templates/Default/template.php @@ -518,17 +518,6 @@ public function onPageLoad() $this->addJSScript(Input::createTinyEditor($this->_language, 'InputPlaceholder', null, false, true)); } break; - - case 'member_lists': - $this->addJSScript(' - if ($(\'.js-check-change\').length) { - var changeCheckbox = document.querySelector(\'.js-check-change\'); - - changeCheckbox.onchange = function () { - $(\'#toggleHideBannedUsers\').submit(); - }; - } - '); } } } diff --git a/custom/templates/DefaultRevamp/DefaultRevamp_Template.php b/custom/templates/DefaultRevamp/DefaultRevamp_Template.php new file mode 100644 index 0000000000..a42b46dbe5 --- /dev/null +++ b/custom/templates/DefaultRevamp/DefaultRevamp_Template.php @@ -0,0 +1,150 @@ + 'DefaultRevamp', + 'version' => '2.1.2', + 'nl_version' => '2.1.2', + 'author' => 'Xemah', + ]; + + $template['path'] = (defined('CONFIG_PATH') ? CONFIG_PATH : '') . '/custom/templates/' . $template['name'] . '/'; + + parent::__construct($template['name'], $template['version'], $template['nl_version'], $template['author']); + + $this->_settings = ROOT_PATH . '/custom/templates/DefaultRevamp/template_settings/settings.php'; + + $this->assets()->include([ + AssetTree::FONT_AWESOME, + AssetTree::JQUERY, + AssetTree::JQUERY_COOKIE, + AssetTree::FOMANTIC_UI, + ]); + + $smarty->assign('TEMPLATE', $template); + + // Other variables + $smarty->assign('FORUM_SPAM_WARNING_TITLE', $language->get('general', 'warning')); + + $cache->setCache('template_settings'); + $smartyDarkMode = false; + $smartyNavbarColour = ''; + + if (defined('DARK_MODE') && DARK_MODE == '1') { + $smartyDarkMode = true; + } + + if ($cache->isCached('navbarColour')) { + $navbarColour = $cache->retrieve('navbarColour'); + + if ($navbarColour != 'white') { + $smartyNavbarColour = $navbarColour . ' inverted'; + } + } + + $smarty->assign([ + 'DEFAULT_REVAMP_DARK_MODE' => $smartyDarkMode, + 'DEFAULT_REVAMP_NAVBAR_EXTRA_CLASSES' => $smartyNavbarColour, + ]); + + $this->_template = $template; + $this->_language = $language; + $this->_user = $user; + $this->_pages = $pages; + } + + public function onPageLoad() + { + $page_load = microtime(true) - PAGE_START_TIME; + define('PAGE_LOAD_TIME', $this->_language->get('general', 'page_loaded_in', ['time' => round($page_load, 3)])); + + $this->addCSSFiles([ + $this->_template['path'] . 'css/custom.css?v=211' => [], + ]); + + $route = (isset($_GET['route']) ? rtrim($_GET['route'], '/') : '/'); + + $JSVariables = [ + 'siteName' => Output::getClean(SITE_NAME), + 'siteURL' => URL::build('/'), + 'fullSiteURL' => URL::getSelfURL() . ltrim(URL::build('/'), '/'), + 'page' => PAGE, + 'avatarSource' => AvatarSource::getUrlToFormat(), + 'copied' => $this->_language->get('general', 'copied'), + 'cookieNotice' => $this->_language->get('general', 'cookie_notice'), + 'noMessages' => $this->_language->get('user', 'no_messages'), + 'newMessage1' => $this->_language->get('user', '1_new_message'), + 'newMessagesX' => $this->_language->get('user', 'x_new_messages'), + 'noAlerts' => $this->_language->get('user', 'no_alerts'), + 'newAlert1' => $this->_language->get('user', '1_new_alert'), + 'newAlertsX' => $this->_language->get('user', 'x_new_alerts'), + 'bungeeInstance' => $this->_language->get('general', 'bungee_instance'), + 'andMoreX' => $this->_language->get('general', 'and_x_more'), + 'onePlayerOnline' => $this->_language->get('general', 'currently_1_player_online'), + 'xPlayersOnline' => $this->_language->get('general', 'currently_x_players_online'), + 'noPlayersOnline' => $this->_language->get('general', 'no_players_online'), + 'offline' => $this->_language->get('general', 'offline'), + 'confirmDelete' => $this->_language->get('general', 'confirm_deletion'), + 'debugging' => (defined('DEBUGGING') && DEBUGGING == 1) ? '1' : '0', + 'loggedIn' => $this->_user->isLoggedIn() ? '1' : '0', + 'cookie' => defined('COOKIE_NOTICE') ? '1' : '0', + 'loadingTime' => Settings::get('page_loading') === '1' ? PAGE_LOAD_TIME : '', + 'route' => $route, + 'csrfToken' => Token::get(), + ]; + + // Logo + $cache = new Cache(['name' => 'nameless', 'extension' => '.cache', 'path' => ROOT_PATH . '/cache/']); + $cache->setCache('backgroundcache'); + $logo_image = $cache->retrieve('logo_image'); + $JSVariables['logoImage'] = !empty($logo_image) ? $logo_image : null; + + if (str_contains($route, '/forum/topic/') || PAGE === 'profile') { + $this->assets()->include([ + AssetTree::JQUERY_UI, + ]); + } + + $JSVars = ''; + $i = 0; + foreach ($JSVariables as $var => $value) { + $JSVars .= ($i == 0 ? 'const ' : ', ') . $var . ' = ' . json_encode($value); + $i++; + } + + $this->addJSScript($JSVars); + + $this->addJSFiles([ + $this->_template['path'] . 'js/core/core.js?v=203' => [], + $this->_template['path'] . 'js/core/user.js' => [], + $this->_template['path'] . 'js/core/pages.js?v=203' => [], + ]); + + foreach ($this->_pages->getAjaxScripts() as $script) { + $this->addJSScript('$.getJSON(\'' . $script . '\', function(data) {});'); + } + } +} diff --git a/custom/templates/DefaultRevamp/members/members.tpl b/custom/templates/DefaultRevamp/members/members.tpl deleted file mode 100644 index f52dcd28cc..0000000000 --- a/custom/templates/DefaultRevamp/members/members.tpl +++ /dev/null @@ -1,228 +0,0 @@ -{include file='header.tpl'} -{include file='navbar.tpl'} - -

- {$MEMBERS} -

- -
- -{if isset($ERROR)} -
- -
-
{$ERROR_TITLE}
- {$ERROR} -
-
-{/if} - -
-
-
- -
-
-

{$FIND_MEMBER}

-
- -
-
-
- {if $GROUPS|count} -
-
-

{$VIEW_GROUP}

-
- -
-
-
- {/if} -
-
-

{$NEW_MEMBERS}

-
-
- {foreach from=$NEW_MEMBERS_VALUE item=member} -
- - {$member->getDisplayname()} - -
- {/foreach} -
-
-
-
-
-
- {if $VIEWING_LIST == "group" || $MEMBER_LISTS_VIEWING|count} -
- {if $VIEWING_LIST == "group"} -
-

{$VIEWING_GROUP.name}

-
-
    -
- {$PAGINATION} -
-
- {else} - {foreach from=$MEMBER_LISTS_VIEWING item=list} -
-

{$list->getFriendlyName()}

-
-
    -
- {if $VIEWING_LIST == "overview"} - {$VIEW_ALL} - {else} - {$PAGINATION} - {/if} -
-
- {/foreach} - {/if} -
- {else} -
{$NO_OVERVIEW_LISTS_ENABLED}
- {/if} -
-
-
- - - -{include file='footer.tpl'} diff --git a/index.php b/index.php index 2237b70994..5e1ec8ac82 100644 --- a/index.php +++ b/index.php @@ -106,17 +106,47 @@ $all_pages = $pages->returnPages(); if (array_key_exists($route, $all_pages)) { - $pages->setActivePage($all_pages[$route]); - if (isset($all_pages[$route]['custom'])) { + $active_page = $all_pages[$route]; + $pages->setActivePage($active_page); + if (isset($active_page['custom'])) { require(implode(DIRECTORY_SEPARATOR, [ROOT_PATH, 'modules', 'Core', 'pages', 'custom.php'])); die; } - $path = implode(DIRECTORY_SEPARATOR, [ROOT_PATH, 'modules', $all_pages[$route]['module'], $all_pages[$route]['file']]); + if ($active_page['controllerBased']) { + if (str_contains($route, 'queries')) { + /** @var \NamelessMC\Framework\Queries\Query */ + $controller = $container->make($active_page['file']); + $controller->handle(); + } else { + require_once(ROOT_PATH . '/core/templates/frontend_init.php'); + // todo: may have to change shit for panel pages or queries + $languageKey = "{$active_page['module']}Language"; + + /** @var \NamelessMC\Framework\Pages\Page */ + $controller = $container->make($active_page['file'], [ + 'templatePagination' => $template_pagination, + // TODO: php-di does not use parameter names to resolve entries (it uses the typed class names), + // so if this is not provided it will use the root \Language class definition, + // which is the Core language. we can possibly make modules use #[Inject] + $languageKey => $container->get($languageKey), + ]); + $controller->render(); + Module::loadPage($user, $pages, $cache, $smarty, [$navigation, $cc_nav, $staffcp_nav], $widgets, $template); + define('PAGE', $controller->pageName()); + $smarty->assign('TITLE', $active_page['name']); + $template->onPageLoad(); + require(ROOT_PATH . '/core/templates/navbar.php'); + require(ROOT_PATH . '/core/templates/footer.php'); + return $template->displayTemplate($controller->viewFile(), $smarty); + } + } else { + $path = implode(DIRECTORY_SEPARATOR, [ROOT_PATH, 'modules', $active_page['module'], $active_page['file']]); - if (file_exists($path)) { - require($path); - die; + if (file_exists($path)) { + require($path); + die; + } } } else { // Use recursion to check - might have URL parameters in path diff --git a/modules/Core/classes/Misc/RegisteredMembersListProvider.php b/modules/Core/classes/Misc/RegisteredMembersListProvider.php index 8f194caa1a..7e068195a7 100644 --- a/modules/Core/classes/Misc/RegisteredMembersListProvider.php +++ b/modules/Core/classes/Misc/RegisteredMembersListProvider.php @@ -1,4 +1,5 @@ $viewing_language->get('emails', $email . '_message')); Email::addPlaceholder('[Thanks]', static fn(Language $viewing_language) => $viewing_language->get('emails', 'thanks')); - if (Util::isModuleEnabled('Members')) { - MemberListManager::getInstance()->registerListProvider(new RegisteredMembersListProvider($language)); - MemberListManager::getInstance()->registerListProvider(new StaffMembersListProvider($language)); + // if (Util::isModuleEnabled('Members')) { + $memberListManager = self::$container->get('NamelessMC\Members\MemberListManager'); + $memberListManager->registerListProvider(new RegisteredMembersListProvider($language)); + $memberListManager->registerListProvider(new StaffMembersListProvider($language)); - MemberListManager::getInstance()->registerMemberMetadataProvider(function (User $member) use ($language) { + $memberListManager->registerMemberMetadataProvider(function (User $member) use ($language) { return [ $language->get('general', 'joined') => date(DATE_FORMAT, $member->data()->joined), ]; }); - } + // } ReactionContextsManager::getInstance()->provideContext(new ProfilePostReactionContext()); diff --git a/modules/Forum/classes/HighestForumReactionScoresMemberListProvider.php b/modules/Forum/classes/HighestForumReactionScoresMemberListProvider.php index d4856e5fba..8c94d0c6e3 100644 --- a/modules/Forum/classes/HighestForumReactionScoresMemberListProvider.php +++ b/modules/Forum/classes/HighestForumReactionScoresMemberListProvider.php @@ -1,4 +1,5 @@ registerListProvider(new MostPostsMemberListProvider($forum_language)); - MemberListManager::getInstance()->registerListProvider(new HighestForumReactionScoresMemberListProvider($forum_language)); + // if (Util::isModuleEnabled('Members')) { + $memberListManager = self::$container->get('NamelessMC\Members\MemberListManager'); + $memberListManager->registerListProvider(new MostPostsMemberListProvider($forum_language)); + $memberListManager->registerListProvider(new HighestForumReactionScoresMemberListProvider($forum_language)); - MemberListManager::getInstance()->registerMemberMetadataProvider(function (User $member) use ($forum_language) { + $memberListManager->registerMemberMetadataProvider(function (User $member) use ($forum_language) { return [ $forum_language->get('forum', 'posts_title') => DB::getInstance()->query( @@ -157,7 +158,7 @@ public function __construct(Language $language, Language $forum_language, Pages ]; }); - MemberListManager::getInstance()->registerMemberMetadataProvider(function (User $member) use ($forum_language) { + $memberListManager->registerMemberMetadataProvider(function (User $member) use ($forum_language) { return [ $forum_language->get('forum', 'reaction_score') => DB::getInstance()->query( @@ -167,8 +168,8 @@ public function __construct(Language $language, Language $forum_language, Pages ]; }); - ReactionContextsManager::getInstance()->provideContext(new ForumPostReactionContext($forum_language)); - } + ReactionContextsManager::getInstance()->provideContext(new ForumPostReactionContext($forum_language)); + // } } public function onInstall() { diff --git a/modules/Members/classes/GroupMemberListProvider.php b/modules/Members/classes/GroupMemberListProvider.php deleted file mode 100644 index eea0a6d584..0000000000 --- a/modules/Members/classes/GroupMemberListProvider.php +++ /dev/null @@ -1,17 +0,0 @@ -_group_id = $group_id; - } - - protected function generator(): array { - return [ - "SELECT nl2_users.id AS id, nl2_users.username FROM nl2_users LEFT JOIN nl2_users_groups ON nl2_users.id = nl2_users_groups.user_id WHERE nl2_users_groups.group_id = {$this->_group_id} ORDER BY nl2_users.username", - 'id', - ]; - } -} diff --git a/modules/Members/classes/MemberListManager.php b/modules/Members/classes/MemberListManager.php deleted file mode 100644 index 8c8fa72147..0000000000 --- a/modules/Members/classes/MemberListManager.php +++ /dev/null @@ -1,110 +0,0 @@ -_lists[$provider->getName()] = $provider; - } - - /** - * Register a member metadata provider. - * Member metadata providers are used to add additional information to member lists under each member's name. - * - * @param Closure $provider The member metadata provider to register - */ - public function registerMemberMetadataProvider(Closure $provider): void { - $this->_metadata_providers[] = $provider; - } - - /** - * Return all lists, including disabled ones. - * - * @return MemberListProvider[] All lists - */ - public function allLists(): array { - return $this->_lists; - } - - /** - * Return all enabled lists. - * - * @return MemberListProvider[] All enabled lists - */ - public function allEnabledLists(): array { - $lists = []; - foreach ($this->allLists() as $list) { - if ($list->isEnabled()) { - $lists[] = $list; - } - } - - return $lists; - } - - /** - * Determine whether a list with the given name exists. - * - * @param string $name The name of the list - * @return bool Whether a list with the given name exists - */ - public function listExists(string $name): bool { - return isset($this->_lists[$name]); - } - - /** - * Get a member list provider with the given name, or create an instance of GroupMemberListProvider if the name is a group ID. - * - * @see GroupMemberListProvider - * @param string $name The name of the list, or the group ID if $for_group is true - * @param bool $for_group Whether the name is a group ID - * @return MemberListProvider The member list provider with the given name - */ - public function getList(string $name, bool $for_group = false): MemberListProvider { - if (!$this->listExists($name)) { - if (!$for_group) { - throw new RuntimeException("Member list '$name' does not exist"); - } - - $group_id = (int) $name; - return new GroupMemberListProvider($group_id); - } - - return $this->_lists[$name]; - } - - /** - * Get the metadata for a given user. Pipes the user through all registered metadata providers. - * - * @param User $user The user to get the metadata for - * @return array The metadata for the given user - */ - public function getMemberMetadata(User $user): array { - $metadata = []; - foreach ($this->_metadata_providers as $provider) { - $metadata += $provider($user); - } - - return $metadata; - } -} diff --git a/modules/Members/classes/MemberListProvider.php b/modules/Members/classes/MemberListProvider.php deleted file mode 100644 index f8527fd9af..0000000000 --- a/modules/Members/classes/MemberListProvider.php +++ /dev/null @@ -1,182 +0,0 @@ -_name; - } - - /** - * @return string The friendly name of the member list provider, displayed in navigation and user-facing pages - */ - public function getFriendlyName(): string { - return $this->_friendly_name; - } - - /** - * @return string The name of the module that the member list provider belongs to - */ - public function getModule(): string { - return $this->_module; - } - - /** - * @return string|null The icon to display next to the member list provider's name in the members page navigation sidebar - */ - public function getIcon(): ?string { - return $this->_icon; - } - - /** - * @return bool Whether the member list provider should be displayed on the member list overview page - */ - public function displayOnOverview(): bool { - return $this->_display_on_overview; - } - - /** - * @return string A URL to this specific member list page - */ - public function url(): string { - return URL::build('/members', 'list=' . $this->getName()); - } - - /** - * Determine whether the member list provider is enabled or not. Will automatically enable the member list if it is not already enabled. - * @return bool Whether the member list provider is enabled - */ - public function isEnabled(): bool { - if (isset($this->_enabled)) { - return $this->_enabled; - } - - $enabled = DB::getInstance()->get('member_lists', ['name', $this->getName()])->first()->enabled; - if ($enabled === null) { - DB::getInstance()->insert('member_lists', [ - 'name' => $this->getName(), - 'friendly_name' => $this->getFriendlyName(), - 'module' => $this->getModule(), - 'enabled' => true, - ]); - - return true; - } - - return $this->_enabled = $enabled; - } - - /** - * Get the information needed to generate the member list. - * - * @return array An array containing the SQL query to run, the column name of the user ID, and optionally the - * column name of the "count" value for this list. Count values are used to display the number of posts, likes, etc. - */ - abstract protected function generator(): array; - - /** - * Get an array of members to display on the member list page. - * - * @param bool $overview Whether the member list is being displayed on the overview page. If true, only 5 members will be returned, otherwise 20. - * @param int $page The page number to display, starting at 1 - pages are 20 members long - * @return array An array of members to display on the member list page - */ - public function getMembers(bool $overview, int $page): array { - [$sql, $id_column, $count_column] = $this->generator(); - - $rows = DB::getInstance()->query($sql)->results(); - if (Settings::get('member_list_hide_banned', false, 'Members')) { - $rows = $this->filterBanned($rows, $id_column); - } - - $rows = array_slice($rows, ($page - 1) * 20); - - $list_members = []; - $limit = $overview ? 5 : 20; - - - foreach ($rows as $row) { - if (count($list_members) === $limit) { - break; - } - - $user_id = $row->{$id_column}; - $member = new User($user_id); - - $list_members[] = array_merge( - [ - 'username' => Output::getClean($member->data()->username), - 'avatar_url' => $member->getAvatar(), - 'group_style' => $member->getGroupStyle(), - 'profile_url' => $member->getProfileURL(), - 'count' => $count_column ? $row->{$count_column} : null, - ], - $overview - ? [] - : [ - 'group_html' => $member->getAllGroupHtml(), - 'metadata' => MemberListManager::getInstance()->getMemberMetadata($member), - ], - ); - } - - return $list_members; - } - - /** - * Determine the total number of members in this list. - * @return int The total number of members in this list - */ - public function getMemberCount(): int { - [$sql, $id_column] = $this->generator(); - $rows = DB::getInstance()->query($sql)->results(); - - if (Settings::get('member_list_hide_banned', false, 'Members')) { - $rows = $this->filterBanned($rows, $id_column); - } - - return count($rows); - } - - /** - * Filter out banned users from a list of members. - * - * @param array $rows Rows returned from the member list query - * @param string $id_column The name of the column in each row containing the user ID - * @return array The rows with banned users filtered out - */ - private function filterBanned(array $rows, string $id_column): array { - $ids = implode(',', array_map(static fn ($row) => $row->{$id_column}, $rows)); - if (empty($ids)) { - return []; - } - - $banned_users = DB::getInstance()->query("SELECT id, isbanned FROM nl2_users WHERE id IN ($ids) AND isbanned = 1")->results(); - return array_filter($rows, static function ($row) use ($banned_users, $id_column) { - foreach ($banned_users as $banned_user) { - if ($banned_user->id == $row->{$id_column}) { - return false; - } - } - - return true; - }); - } -} diff --git a/modules/Members/init.php b/modules/Members/init.php deleted file mode 100644 index 305eac9c17..0000000000 --- a/modules/Members/init.php +++ /dev/null @@ -1,7 +0,0 @@ -_language = $language; - $this->_members_language = $members_language; - - $name = 'Members'; - $author = 'Aberdeener'; - $module_version = '2.1.2'; - $nameless_version = '2.1.2'; - - parent::__construct($this, $name, $author, $module_version, $nameless_version); - - // Define URLs which belong to this module - $pages->add('Members', '/members', 'pages/members.php'); - $pages->add('Members', '/queries/member_list', 'queries/member_list.php'); - $pages->add('Members', '/panel/members/member_lists', 'pages/panel/member_lists.php'); - $pages->add('Members', '/panel/members/settings', 'pages/panel/settings.php'); - } - - public function onInstall() { - // Not necessary for CookieConsent - } - - public function onUninstall() { - // Not necessary for CookieConsent - } - - public function onEnable() { - // Not necessary for CookieConsent - } - - public function onDisable() { - // Not necessary for CookieConsent - } - - public function onPageLoad(User $user, Pages $pages, Cache $cache, Smarty $smarty, $navs, Widgets $widgets, ?TemplateBase $template) { - $language = $this->_language; - - // AdminCP - PermissionHandler::registerPermissions($language->get('moderator', 'staff_cp'), [ - 'admincp.members' => $this->_members_language->get('members', 'member_lists') - ]); - - $cache->setCache('navbar_order'); - if (!$cache->isCached('members_order')) { - $members_order = 5; - $cache->store('members_order', 5); - } else { - $members_order = $cache->retrieve('members_order'); - } - - $cache->setCache('navbar_icons'); - if (!$cache->isCached('members_icon')) { - $members_icon = ''; - } else { - $members_icon = $cache->retrieve('members_icon'); - } - - $cache->setCache('nav_location'); - if (!$cache->isCached('members_location')) { - $link_location = 1; - $cache->store('members_location', 1); - } else { - $link_location = $cache->retrieve('members_location'); - } - - switch ($link_location) { - case 1: - // Navbar - $navs[0]->add('members', $this->_members_language->get('members', 'members'), URL::build('/members'), 'top', null, $members_order, $members_icon); - break; - case 2: - // "More" dropdown - $navs[0]->addItemToDropdown('more_dropdown', 'members', $this->_members_language->get('members', 'members'), URL::build('/members'), 'top', null, $members_icon, $members_order); - break; - case 3: - // Footer - $navs[0]->add('members', $this->_members_language->get('members', 'members'), URL::build('/members'), 'footer', null, $members_order, $members_icon); - break; - } - - if (defined('BACK_END')) { - $cache->setCache('panel_sidebar'); - - // StaffCP link - if ($user->hasPermission('admincp.members')) { - if (!$cache->isCached('members_order')) { - $order = 13; - $cache->store('members_order', 13); - } else { - $order = $cache->retrieve('members_order'); - } - - if (!$cache->isCached('members_settings_icon')) { - $members_settings_icon = ''; - $cache->store('members_settings_icon', $members_settings_icon); - } else { - $members_settings_icon = $cache->retrieve('members_settings_icon'); - } - - if (!$cache->isCached('member_lists_icon')) { - $member_lists_icon = ''; - $cache->store('member_lists_icon', $member_lists_icon); - } else { - $member_lists_icon = $cache->retrieve('member_lists_icon'); - } - - $navs[2]->add('members_divider', mb_strtoupper($this->_members_language->get('members', 'members'), 'UTF-8'), 'divider', 'top', null, $order); - $navs[2]->add('members_settings', $this->_language->get('admin', 'settings'), URL::build('/panel/members/settings'), 'top', null, $order + 0.1, $members_settings_icon); - $navs[2]->add('member_lists_settings', $this->_members_language->get('members', 'member_lists'), URL::build('/panel/members/member_lists'), 'top', null, $order + 0.2, $member_lists_icon); - } - } - } - - public function getDebugInfo(): array { - return []; - } -} diff --git a/modules/Members/pages/members.php b/modules/Members/pages/members.php deleted file mode 100644 index 91a6142a48..0000000000 --- a/modules/Members/pages/members.php +++ /dev/null @@ -1,133 +0,0 @@ -get('members', 'members'); -require_once(ROOT_PATH . '/core/templates/frontend_init.php'); - -if (isset($_GET['group'])) { - if (!in_array($_GET['group'], json_decode(Settings::get('member_list_viewable_groups', '{}', 'Members'), true))) { - Redirect::to(URL::build('/members')); - } - - $viewing_list = 'group'; - $viewing_group = Group::find($_GET['group']); - $smarty->assign([ - 'VIEWING_GROUP' => [ - 'id' => $viewing_group->id, - 'name' => Output::getClean($viewing_group->name), - ], - ]); - - $lists_viewing = []; -} else { - $viewing_list = $_GET['list'] ?? 'overview'; - if ($viewing_list !== 'overview' - && (!MemberListManager::getInstance()->listExists($viewing_list) || !MemberListManager::getInstance()->getList($viewing_list)->isEnabled()) - ) { - Redirect::to(URL::build('/members')); - } - - $lists_viewing = $viewing_list === 'overview' - ? array_filter(MemberListManager::getInstance()->allEnabledLists(), static fn (MemberListProvider $list) => $list->displayOnOverview()) - : [MemberListManager::getInstance()->getList($viewing_list)]; -} - -// TODO handle this in MemberListManager and cache it using UserRegisteredEvent -$new_members = []; -if (Settings::get('member_list_hide_banned', false, 'Members')) { - $query = DB::getInstance()->query('SELECT id FROM nl2_users WHERE isbanned = 0 ORDER BY joined DESC LIMIT 12'); -} else { - $query = DB::getInstance()->query('SELECT id FROM nl2_users ORDER BY joined DESC LIMIT 12'); -} -foreach ($query->results() as $new_member) { - $new_members[] = new User($new_member->id); -} - -if (isset($error)) { - $smarty->assign([ - 'ERROR_TITLE' => $language->get('general', 'error'), - 'ERROR' => $error, - ]); -} - -$groups = []; -foreach (json_decode(Settings::get('member_list_viewable_groups', '{}', 'Members'), true) as $group_id) { - $group = Group::find($group_id); - if (!$group) { - continue; - } - $groups[] = [ - 'id' => $group->id, - 'name' => Output::getClean($group->name), - ]; -} - -if ($viewing_list !== 'overview') { - $member_count = isset($_GET['group']) - ? MemberListManager::getInstance()->getList($_GET['group'], true)->getMemberCount() - : MemberListManager::getInstance()->getList($viewing_list)->getMemberCount(); - $url_param = isset($_GET['group']) - ? 'group=' . $_GET['group'] - : 'list=' . $viewing_list; - - $template_pagination['div'] = $template_pagination['div'] .= ' centered'; - $paginator = new Paginator( - $template_pagination ?? null, - $template_pagination_left ?? null, - $template_pagination_right ?? null - ); - $paginator->setValues($member_count, 20, $_GET['p'] ?? 1); - $smarty->assign([ - 'PAGINATION' => $paginator->generate(6, URL::build('/members/', $url_param)), - ]); -} - -// Sort sidebar lists to have displayOnOverview lists first -$sidebar_lists = MemberListManager::getInstance()->allEnabledLists(); -usort($sidebar_lists, static function ($a, $b) { - return $b->displayOnOverview() - $a->displayOnOverview(); -}); - -$smarty->assign([ - 'MEMBERS' => $members_language->get('members', 'members'), - 'SIDEBAR_MEMBER_LISTS' => $sidebar_lists, - 'MEMBER_LISTS_VIEWING' => $lists_viewing, - 'VIEWING_LIST' => $viewing_list, - 'MEMBER_LIST_URL' => URL::build('/members'), - 'QUERIES_URL' => URL::build('/queries/member_list', 'list={{list}}&page={{page}}&overview=' . ($viewing_list === 'overview' ? 'true' : 'false')), - 'OVERVIEW' => $language->get('user', 'overview'), - 'VIEW_ALL' => $members_language->get('members', 'view_all'), - 'GROUPS' => $groups, - 'VIEW_GROUP_URL' => URL::build('/members', 'group='), - 'NEW_MEMBERS' => $members_language->get('members', 'new_members'), - 'NEW_MEMBERS_VALUE' => $new_members, - 'FIND_MEMBER' => $members_language->get('members', 'find_member'), - 'NAME' => $members_language->get('members', 'name'), - 'SEARCH_URL' => URL::build('/queries/users'), - 'NO_RESULTS_HEADER' => $members_language->get('members', 'no_results_header'), - 'NO_RESULTS_TEXT' => $members_language->get('members', 'no_results_text'), - 'VIEW_GROUP' => $members_language->get('members', 'view_group'), - 'GROUP' => $members_language->get('members', 'group'), - 'NO_MEMBERS_FOUND' => $members_language->get('members', 'no_members'), - 'NO_OVERVIEW_LISTS_ENABLED' => $members_language->get('members', 'no_overview_lists_enabled'), -]); - -// Load modules + template -Module::loadPage($user, $pages, $cache, $smarty, [$navigation, $cc_nav, $staffcp_nav], $widgets, $template); - -$template->onPageLoad(); - -require(ROOT_PATH . '/core/templates/navbar.php'); -require(ROOT_PATH . '/core/templates/footer.php'); - -// Display template -$template->displayTemplate('members/members.tpl', $smarty); diff --git a/modules/Members/pages/panel/member_lists.php b/modules/Members/pages/panel/member_lists.php deleted file mode 100644 index e3e04fad2e..0000000000 --- a/modules/Members/pages/panel/member_lists.php +++ /dev/null @@ -1,71 +0,0 @@ -handlePanelPageLoad('admincp.members')) { - require_once(ROOT_PATH . '/403.php'); - die(); -} - -const PAGE = 'panel'; -const PARENT_PAGE = 'members'; -const PANEL_PAGE = 'member_lists_settings'; - -$page_title = $members_language->get('members', 'member_lists'); -require_once(ROOT_PATH . '/core/templates/backend_init.php'); - -if (Input::exists()) { - if (Token::check()) { - $list = MemberListManager::getInstance()->getList($_POST['list']); - $enabled = DB::getInstance()->get('member_lists', ['name', $list->getName()])->first()->enabled; - DB::getInstance()->update('member_lists', ['name', $list->getName()], [ - 'enabled' => !$enabled - ]); - - Session::flash('admin_member_lists_success', $members_language->get('members', !$enabled ? 'member_list_toggled_enabled' : 'member_list_toggled_disabled', [ - 'list' => $list->getFriendlyName(), - ])); - - Redirect::to(URL::build('/panel/members/member_lists')); - } else { - Session::flash('admin_member_lists_error', $language->get('general', 'invalid_token')); - } -} - -if (Session::exists('admin_member_lists_error')) { - $smarty->assign([ - 'ERRORS' => [Session::flash('admin_member_lists_error')], - 'ERRORS_TITLE' => $language->get('general', 'error'), - ]); -} - -if (Session::exists('admin_member_lists_success')) { - $smarty->assign([ - 'SUCCESS' => Session::flash('admin_member_lists_success'), - 'SUCCESS_TITLE' => $language->get('general', 'success'), - ]); -} - -$smarty->assign([ - 'PARENT_PAGE' => PARENT_PAGE, - 'DASHBOARD' => $language->get('admin', 'dashboard'), - 'MEMBERS' => $members_language->get('members', 'members'), - 'MEMBER_LISTS' => $members_language->get('members', 'member_lists'), - 'PAGE' => PANEL_PAGE, - 'MEMBER_LISTS_VALUES' => MemberListManager::getInstance()->allLists(), - 'NAME' => $language->get('admin', 'name'), - 'ENABLED' => $language->get('admin', 'enabled'), - 'MODULE' => $language->get('admin', 'module'), - 'EDIT' => $language->get('general', 'edit'), - 'ENABLE' => $language->get('admin', 'enable'), - 'DISABLE' => $language->get('admin', 'disable'), - 'TOKEN' => Token::get(), -]); - -// Load modules + template -Module::loadPage($user, $pages, $cache, $smarty, [$navigation, $cc_nav, $staffcp_nav], $widgets, $template); - -$template->onPageLoad(); - -require(ROOT_PATH . '/core/templates/panel_navbar.php'); - -// Display template -$template->displayTemplate('members/member_lists.tpl', $smarty); diff --git a/modules/Members/pages/panel/settings.php b/modules/Members/pages/panel/settings.php deleted file mode 100644 index df01617cca..0000000000 --- a/modules/Members/pages/panel/settings.php +++ /dev/null @@ -1,104 +0,0 @@ -handlePanelPageLoad('admincp.members')) { - require_once(ROOT_PATH . '/403.php'); - die(); -} - -const PAGE = 'panel'; -const PARENT_PAGE = 'members'; -const PANEL_PAGE = 'members_settings'; - -$page_title = $members_language->get('members', 'members'); -require_once(ROOT_PATH . '/core/templates/backend_init.php'); - -if (Input::exists()) { - if (Token::check()) { - Settings::set('member_list_viewable_groups', json_encode(Input::get('groups')), 'Members'); - Settings::set('member_list_hide_banned', Input::get('hide_banned_users'), 'Members'); - - // Update link location - if (isset($_POST['link_location'])) { - switch ($_POST['link_location']) { - case 1: - case 2: - case 3: - case 4: - $location = $_POST['link_location']; - break; - default: - $location = 1; - } - } else { - $location = 1; - } - - // Update Link location cache - $cache->setCache('nav_location'); - $cache->store('members_location', $location); - - Session::flash('admin_members_settings', $members_language->get('members', 'settings_updated_successfully')); - } else { - // Invalid token - Session::flash('admin_members_settings_error', $language->get('general', 'invalid_token')); - } - Redirect::to(URL::build('/panel/members/settings')); -} - -// Retrieve Link Location from cache -$cache->setCache('nav_location'); -$link_location = $cache->retrieve('members_location'); - -// Load modules + template -Module::loadPage($user, $pages, $cache, $smarty, [$navigation, $cc_nav, $staffcp_nav], $widgets, $template); - -if (Session::exists('admin_members_settings')) { - $smarty->assign([ - 'SUCCESS' => Session::flash('admin_members_settings'), - 'SUCCESS_TITLE' => $language->get('general', 'success') - ]); -} - -if (Session::exists('admin_members_settings_error')) { - $smarty->assign([ - 'ERROR' => Session::flash('admin_members_settings_error'), - 'ERRORS_TITLE' => $language->get('general', 'success') - ]); -} - -$group_array = []; -foreach (Group::all() as $group) { - $group_array[] = [ - 'id' => $group->id, - 'name' => Output::getClean($group->name), - ]; -} - -$smarty->assign([ - 'PARENT_PAGE' => PARENT_PAGE, - 'DASHBOARD' => $language->get('admin', 'dashboard'), - 'MEMBERS' => $members_language->get('members', 'members'), - 'SETTINGS' => $language->get('admin', 'settings'), - 'LINK_LOCATION' => $language->get('admin', 'page_link_location'), - 'LINK_LOCATION_VALUE' => $link_location, - 'LINK_NAVBAR' => $language->get('admin', 'page_link_navbar'), - 'LINK_MORE' => $language->get('admin', 'page_link_more'), - 'LINK_FOOTER' => $language->get('admin', 'page_link_footer'), - 'LINK_NONE' => $language->get('admin', 'page_link_none'), - 'HIDE_BANNED_USERS' => $members_language->get('members', 'member_list_hide_banned_users'), - 'HIDE_BANNED_USERS_VALUE' => Settings::get('member_list_hide_banned', false, 'Members'), - 'GROUPS' => $members_language->get('members', 'viewable_groups'), - 'GROUPS_ARRAY' => $group_array, - 'GROUPS_VALUE' => json_decode(Settings::get('member_list_viewable_groups', '{}', 'Members'), true) ?: [], - 'NO_ITEM_SELECTED' => $language->get('admin', 'no_item_selected'), - 'PAGE' => PANEL_PAGE, - 'TOKEN' => Token::get(), - 'SUBMIT' => $language->get('general', 'submit'), -]); - -$template->onPageLoad(); - -require(ROOT_PATH . '/core/templates/panel_navbar.php'); - -// Display template -$template->displayTemplate('members/members_settings.tpl', $smarty); diff --git a/modules/Members/queries/member_list.php b/modules/Members/queries/member_list.php deleted file mode 100644 index f56eacaf11..0000000000 --- a/modules/Members/queries/member_list.php +++ /dev/null @@ -1,29 +0,0 @@ -setCache('member_list_queries'); -$key = ($list . '_page_' . $page) . ($overview ? '_overview' : '') . (Settings::get('member_list_hide_banned', false, 'Members') ? '_hide_banned' : ''); -if ($cache->isCached($key)) { - die($cache->retrieve($key)); -} - -if (str_starts_with($list, 'group_')) { - $members = MemberListManager::getInstance()->getList((int) substr($list, 6), true)->getMembers(false, $page); -} else { - $members = MemberListManager::getInstance()->getList($list)->getMembers($overview, $page); -} - -$members = json_encode($members); - -$cache->store($key, $members, 60); - -die($members); From f27ad85d1934006c553fe0e8ec07f3690c10a2af Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Sun, 20 Oct 2024 14:36:26 -0700 Subject: [PATCH 04/24] add to navbar in FrontendPages --- core/classes/Extend/FrontendPages.php | 38 ++++- core/init.php | 2 + .../DefaultRevamp/DefaultRevamp_Template.php | 150 ------------------ 3 files changed, 38 insertions(+), 152 deletions(-) delete mode 100644 custom/templates/DefaultRevamp/DefaultRevamp_Template.php diff --git a/core/classes/Extend/FrontendPages.php b/core/classes/Extend/FrontendPages.php index 881b71e1ca..70f91f879c 100644 --- a/core/classes/Extend/FrontendPages.php +++ b/core/classes/Extend/FrontendPages.php @@ -16,6 +16,12 @@ public function extend(Container $container): void { /** @var \Pages */ $pages = $container->get(\Pages::class); + /** @var \Cache */ + $cache = $container->get(\Cache::class); + + /** @var \Navigation */ + $frontendNavigation = $container->get('FrontendNavigation'); + foreach ($this->pages as $page) { // Remove loading / from path - allows devs to ->register('/') $path = ltrim($page['path'], '/'); @@ -23,11 +29,38 @@ public function extend(Container $container): void { // Remove ending / if it exists $path = rtrim($path, '/'); + $pageName = $page['name']; + $pageFriendlyName = $moduleLanguage->get($page['friendly_name_translation']); + + $cache->setCache('navbar_order'); + $pageOrder = $cache->fetch("{$pageName}_order", fn () => 5); + + $cache->setCache('navbar_icons'); + $pageIcon = $cache->fetch("{$pageName}_icon", fn () => ''); + + $cache->setCache('nav_location'); + $pageLocation = $cache->fetch("{$pageName}_location", fn () => 1); + + switch ($pageLocation) { + case 1: + // Navbar + $frontendNavigation->add($pageName, $pageFriendlyName, \URL::build($path), 'top', null, $pageOrder, $pageIcon); + break; + case 2: + // "More" dropdown + $frontendNavigation->addItemToDropdown('more_dropdown', $pageName, $pageFriendlyName, \URL::build($path), 'top', null, $pageIcon, $pageOrder); + break; + case 3: + // Footer + $frontendNavigation->add($pageName, $pageFriendlyName, \URL::build($path), 'footer', null, $pageOrder, $pageIcon); + break; + } + $pages->add( $this->moduleName, $path, $page['handler'], - $moduleLanguage->get($page['name']), + $pageFriendlyName, $page['allowWidgets'], true, ); @@ -41,10 +74,11 @@ public function extend(Container $container): void { } } - public function register(string $path, string $name, string $handler, bool $allowWidgets): FrontendPages { + public function register(string $path, string $name, string $friendlyNameTranslation, string $handler, bool $allowWidgets): FrontendPages { $this->pages[] = [ 'path' => $path, 'name' => $name, + 'friendly_name_translation' => $friendlyNameTranslation, 'handler' => $handler, 'allowWidgets' => $allowWidgets ]; diff --git a/core/init.php b/core/init.php index 88f07b4412..6de3d83391 100644 --- a/core/init.php +++ b/core/init.php @@ -395,6 +395,8 @@ $cc_nav = new Navigation(); $staffcp_nav = new Navigation(true); // $staffcp_nav = panel nav + $container->set('FrontendNavigation', $navigation); + // Add links to cc_nav $cc_nav->add('cc_overview', $language->get('user', 'overview'), URL::build('/user')); $cc_nav->add('cc_alerts', $language->get('user', 'alerts'), URL::build('/user/alerts')); diff --git a/custom/templates/DefaultRevamp/DefaultRevamp_Template.php b/custom/templates/DefaultRevamp/DefaultRevamp_Template.php deleted file mode 100644 index a42b46dbe5..0000000000 --- a/custom/templates/DefaultRevamp/DefaultRevamp_Template.php +++ /dev/null @@ -1,150 +0,0 @@ - 'DefaultRevamp', - 'version' => '2.1.2', - 'nl_version' => '2.1.2', - 'author' => 'Xemah', - ]; - - $template['path'] = (defined('CONFIG_PATH') ? CONFIG_PATH : '') . '/custom/templates/' . $template['name'] . '/'; - - parent::__construct($template['name'], $template['version'], $template['nl_version'], $template['author']); - - $this->_settings = ROOT_PATH . '/custom/templates/DefaultRevamp/template_settings/settings.php'; - - $this->assets()->include([ - AssetTree::FONT_AWESOME, - AssetTree::JQUERY, - AssetTree::JQUERY_COOKIE, - AssetTree::FOMANTIC_UI, - ]); - - $smarty->assign('TEMPLATE', $template); - - // Other variables - $smarty->assign('FORUM_SPAM_WARNING_TITLE', $language->get('general', 'warning')); - - $cache->setCache('template_settings'); - $smartyDarkMode = false; - $smartyNavbarColour = ''; - - if (defined('DARK_MODE') && DARK_MODE == '1') { - $smartyDarkMode = true; - } - - if ($cache->isCached('navbarColour')) { - $navbarColour = $cache->retrieve('navbarColour'); - - if ($navbarColour != 'white') { - $smartyNavbarColour = $navbarColour . ' inverted'; - } - } - - $smarty->assign([ - 'DEFAULT_REVAMP_DARK_MODE' => $smartyDarkMode, - 'DEFAULT_REVAMP_NAVBAR_EXTRA_CLASSES' => $smartyNavbarColour, - ]); - - $this->_template = $template; - $this->_language = $language; - $this->_user = $user; - $this->_pages = $pages; - } - - public function onPageLoad() - { - $page_load = microtime(true) - PAGE_START_TIME; - define('PAGE_LOAD_TIME', $this->_language->get('general', 'page_loaded_in', ['time' => round($page_load, 3)])); - - $this->addCSSFiles([ - $this->_template['path'] . 'css/custom.css?v=211' => [], - ]); - - $route = (isset($_GET['route']) ? rtrim($_GET['route'], '/') : '/'); - - $JSVariables = [ - 'siteName' => Output::getClean(SITE_NAME), - 'siteURL' => URL::build('/'), - 'fullSiteURL' => URL::getSelfURL() . ltrim(URL::build('/'), '/'), - 'page' => PAGE, - 'avatarSource' => AvatarSource::getUrlToFormat(), - 'copied' => $this->_language->get('general', 'copied'), - 'cookieNotice' => $this->_language->get('general', 'cookie_notice'), - 'noMessages' => $this->_language->get('user', 'no_messages'), - 'newMessage1' => $this->_language->get('user', '1_new_message'), - 'newMessagesX' => $this->_language->get('user', 'x_new_messages'), - 'noAlerts' => $this->_language->get('user', 'no_alerts'), - 'newAlert1' => $this->_language->get('user', '1_new_alert'), - 'newAlertsX' => $this->_language->get('user', 'x_new_alerts'), - 'bungeeInstance' => $this->_language->get('general', 'bungee_instance'), - 'andMoreX' => $this->_language->get('general', 'and_x_more'), - 'onePlayerOnline' => $this->_language->get('general', 'currently_1_player_online'), - 'xPlayersOnline' => $this->_language->get('general', 'currently_x_players_online'), - 'noPlayersOnline' => $this->_language->get('general', 'no_players_online'), - 'offline' => $this->_language->get('general', 'offline'), - 'confirmDelete' => $this->_language->get('general', 'confirm_deletion'), - 'debugging' => (defined('DEBUGGING') && DEBUGGING == 1) ? '1' : '0', - 'loggedIn' => $this->_user->isLoggedIn() ? '1' : '0', - 'cookie' => defined('COOKIE_NOTICE') ? '1' : '0', - 'loadingTime' => Settings::get('page_loading') === '1' ? PAGE_LOAD_TIME : '', - 'route' => $route, - 'csrfToken' => Token::get(), - ]; - - // Logo - $cache = new Cache(['name' => 'nameless', 'extension' => '.cache', 'path' => ROOT_PATH . '/cache/']); - $cache->setCache('backgroundcache'); - $logo_image = $cache->retrieve('logo_image'); - $JSVariables['logoImage'] = !empty($logo_image) ? $logo_image : null; - - if (str_contains($route, '/forum/topic/') || PAGE === 'profile') { - $this->assets()->include([ - AssetTree::JQUERY_UI, - ]); - } - - $JSVars = ''; - $i = 0; - foreach ($JSVariables as $var => $value) { - $JSVars .= ($i == 0 ? 'const ' : ', ') . $var . ' = ' . json_encode($value); - $i++; - } - - $this->addJSScript($JSVars); - - $this->addJSFiles([ - $this->_template['path'] . 'js/core/core.js?v=203' => [], - $this->_template['path'] . 'js/core/user.js' => [], - $this->_template['path'] . 'js/core/pages.js?v=203' => [], - ]); - - foreach ($this->_pages->getAjaxScripts() as $script) { - $this->addJSScript('$.getJSON(\'' . $script . '\', function(data) {});'); - } - } -} From 0672ddea4b8981d041aed78486f50a096a36b30f Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Sun, 20 Oct 2024 15:24:25 -0700 Subject: [PATCH 05/24] wip panel pages --- core/classes/Extend/FrontendPages.php | 2 +- core/classes/Extend/PanelPages.php | 42 +++++++++++++++++++++++++-- core/classes/Pages/PanelPage.php | 4 ++- core/init.php | 1 + core/templates/backend_init.php | 4 +-- index.php | 29 +++++++++++++++--- 6 files changed, 72 insertions(+), 10 deletions(-) diff --git a/core/classes/Extend/FrontendPages.php b/core/classes/Extend/FrontendPages.php index 70f91f879c..4c4cae6f1e 100644 --- a/core/classes/Extend/FrontendPages.php +++ b/core/classes/Extend/FrontendPages.php @@ -23,7 +23,7 @@ public function extend(Container $container): void { $frontendNavigation = $container->get('FrontendNavigation'); foreach ($this->pages as $page) { - // Remove loading / from path - allows devs to ->register('/') + // Remove leading / from path - allows devs to ->register('/') $path = ltrim($page['path'], '/'); $path = "/{$this->moduleName}/{$path}"; // Remove ending / if it exists diff --git a/core/classes/Extend/PanelPages.php b/core/classes/Extend/PanelPages.php index 450d48e36d..809ae2110a 100644 --- a/core/classes/Extend/PanelPages.php +++ b/core/classes/Extend/PanelPages.php @@ -7,6 +7,8 @@ class PanelPages extends BaseExtender { private $pages = []; + private $templateDirectories = []; + public function extend(Container $container): void { /** @var \Language */ @@ -15,6 +17,19 @@ public function extend(Container $container): void { /** @var \Pages */ $pages = $container->get(\Pages::class); + /** @var \User */ + $user = $container->get(\User::class); + + /** @var \Cache */ + $cache = $container->get(\Cache::class); + $cache->setCache('panel_sidebar'); + + /** @var \Navigation */ + $panelNavigation = $container->get('PanelNavigation'); + + $moduleSidebarOrder = $cache->fetch("{$this->moduleName}_order", fn () => 10); + $panelNavigation->add("{$this->moduleName}_divider", mb_strtoupper($this->moduleDisplayName), 'divider', 'top', null, $moduleSidebarOrder); + foreach ($this->pages as $page) { // Remove loading / from path - allows devs to ->register('/') $path = ltrim($page['path'], '/'); @@ -22,24 +37,47 @@ public function extend(Container $container): void { // Remove ending / if it exists $path = rtrim($path, '/'); + $friendlyName = $moduleLanguage->get($page['friendly_name_translation']); + + if ($user->hasPermission($page['permission'])) { + $pageIcon = $cache->fetch("{$page['name']}_icon", fn () => ''); + + $panelNavigation->add($page['name'], $friendlyName, \URL::build($path), 'top', null, $moduleSidebarOrder + 0.1, $pageIcon); + } + $pages->add( $this->moduleName, $path, $page['handler'], - $moduleLanguage->get($page['name']), + $friendlyName, false, true, ); } + + /** @var \Smarty */ + $smarty = $container->get(\Smarty::class); + + foreach ($this->templateDirectories as $directory) { + $smarty->addTemplateDir($directory); + } } - public function register(string $path, string $name, string $handler): PanelPages { + public function register(string $path, string $name, string $friendlyNameTranslation, string $handler, string $permission): PanelPages { $this->pages[] = [ 'path' => $path, 'name' => $name, + 'friendly_name_translation' => $friendlyNameTranslation, 'handler' => $handler, + 'permission' => $permission, ]; return $this; } + + public function templateDirectory(string $path): PanelPages { + $this->templateDirectories[] = $path; + + return $this; + } } \ No newline at end of file diff --git a/core/classes/Pages/PanelPage.php b/core/classes/Pages/PanelPage.php index 05e4b51eaf..6439a904d6 100644 --- a/core/classes/Pages/PanelPage.php +++ b/core/classes/Pages/PanelPage.php @@ -3,5 +3,7 @@ namespace NamelessMC\Framework\Pages; abstract class PanelPage extends Page { - // ... + + abstract public function permission(): string; + } \ No newline at end of file diff --git a/core/init.php b/core/init.php index 6de3d83391..fa924bf8f9 100644 --- a/core/init.php +++ b/core/init.php @@ -396,6 +396,7 @@ $staffcp_nav = new Navigation(true); // $staffcp_nav = panel nav $container->set('FrontendNavigation', $navigation); + $container->set('PanelNavigation', $staffcp_nav); // Add links to cc_nav $cc_nav->add('cc_overview', $language->get('user', 'overview'), URL::build('/user')); diff --git a/core/templates/backend_init.php b/core/templates/backend_init.php index 8c16067063..cbdaab1804 100644 --- a/core/templates/backend_init.php +++ b/core/templates/backend_init.php @@ -15,11 +15,11 @@ $smarty->setCompileDir(ROOT_PATH . '/cache/templates_c'); if (file_exists(ROOT_PATH . '/custom/panel_templates/' . PANEL_TEMPLATE . '/template.php')) { - $smarty->setTemplateDir(ROOT_PATH . '/custom/panel_templates/' . PANEL_TEMPLATE); + $smarty->addTemplateDir(ROOT_PATH . '/custom/panel_templates/' . PANEL_TEMPLATE); require(ROOT_PATH . '/custom/panel_templates/' . PANEL_TEMPLATE . '/template.php'); } else { - $smarty->setTemplateDir(ROOT_PATH . '/custom/panel_templates/Default'); + $smarty->addTemplateDir(ROOT_PATH . '/custom/panel_templates/Default'); require(ROOT_PATH . '/custom/panel_templates/Default/template.php'); } diff --git a/index.php b/index.php index 5e1ec8ac82..bd502cf9df 100644 --- a/index.php +++ b/index.php @@ -114,15 +114,36 @@ } if ($active_page['controllerBased']) { + $languageKey = "{$active_page['module']}Language"; + if (str_contains($route, 'queries')) { /** @var \NamelessMC\Framework\Queries\Query */ $controller = $container->make($active_page['file']); $controller->handle(); + } elseif (str_contains($route, 'panel')) { + /** @var \NamelessMC\Framework\Pages\PanelPage */ + $controller = $container->make($active_page['file'], [ + $languageKey => $container->get($languageKey), + ]); + + if (!$user->handlePanelPageLoad($controller->permission())) { + require_once(ROOT_PATH . '/403.php'); + die(); + } + + require_once(ROOT_PATH . '/core/templates/backend_init.php'); + + $controller->render(); + Module::loadPage($user, $pages, $cache, $smarty, [$navigation, $cc_nav, $staffcp_nav], $widgets, $template); + define('PAGE', 'panel'); + define('PARENT_PAGE', $active_page['module']); + define('PANEL_PAGE', $controller->pageName()); + $smarty->assign(['TITLE' => $active_page['name'], 'PAGE' => $controller->pageName()]); + $template->onPageLoad(); + require(ROOT_PATH . '/core/templates/panel_navbar.php'); + return $template->displayTemplate($controller->viewFile(), $smarty); } else { - require_once(ROOT_PATH . '/core/templates/frontend_init.php'); - // todo: may have to change shit for panel pages or queries - $languageKey = "{$active_page['module']}Language"; - + require_once(ROOT_PATH . '/core/templates/frontend_init.php'); /** @var \NamelessMC\Framework\Pages\Page */ $controller = $container->make($active_page['file'], [ 'templatePagination' => $template_pagination, From 791cc49a8607c2b9948b046165e9f11f9510a70b Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Mon, 21 Oct 2024 17:25:09 -0700 Subject: [PATCH 06/24] get module install/enable/disable working --- core/classes/Core/ComposerModuleDiscovery.php | 63 ++++++++++ core/classes/Core/ComposerModuleWrapper.php | 112 ++++++++++++++++++ core/classes/Extend/BaseExtender.php | 9 +- core/classes/Extend/ModuleLifecycle.php | 34 ++++++ core/classes/ModuleLifecycle/Hook.php | 8 ++ core/init.php | 15 +-- .../panel_templates/Default/core/modules.tpl | 3 + modules/Core/pages/panel/modules.php | 60 +++++++++- 8 files changed, 283 insertions(+), 21 deletions(-) create mode 100644 core/classes/Core/ComposerModuleDiscovery.php create mode 100644 core/classes/Core/ComposerModuleWrapper.php create mode 100644 core/classes/Extend/ModuleLifecycle.php create mode 100644 core/classes/ModuleLifecycle/Hook.php diff --git a/core/classes/Core/ComposerModuleDiscovery.php b/core/classes/Core/ComposerModuleDiscovery.php new file mode 100644 index 0000000000..f48edb0208 --- /dev/null +++ b/core/classes/Core/ComposerModuleDiscovery.php @@ -0,0 +1,63 @@ +getName(), array_column($allEnabledModules, 'name'))) { + continue; + } + + self::bootModule($container, $composerModule); + } + } + + public static function bootModule(\DI\Container $container, ComposerModuleWrapper $composerModule): void + { + /** @var NamelessMC\Framework\Extend\BaseExtender[] $extenders */ + $extenders = require_once ROOT_PATH . '/vendor/' . $composerModule->getPackageName() . '/module.php'; + foreach ($extenders as $extender) { + $extender->setModule($composerModule)->extend($container); + } + } + + public static function fromPackage(array $composerPackage): ComposerModuleWrapper + { + return new ComposerModuleWrapper( + $composerPackage['name'], + $composerPackage['extra']['nameless_module']['name'], + $composerPackage['extra']['nameless_module']['display_name'], + $composerPackage['authors'][0]['name'], + $composerPackage['authors'][0]['homepage'], + $composerPackage['extra']['nameless_module']['version'], + $composerPackage['extra']['nameless_module']['nameless_version'], + $composerPackage['source']['url'], + ); + } +} diff --git a/core/classes/Core/ComposerModuleWrapper.php b/core/classes/Core/ComposerModuleWrapper.php new file mode 100644 index 0000000000..97cb840dd3 --- /dev/null +++ b/core/classes/Core/ComposerModuleWrapper.php @@ -0,0 +1,112 @@ +_packageName = $packageName; + $this->_privateName = $privateName; + $this->_authorName = $authorName; + $this->_authorHomepage = $authorHomepage; + $this->_repositoryUrl = $repositoryUrl; + + parent::__construct($this, $displayName, $authorName, $moduleVersion, $namelessVersion); + } + + public function getPackageName(): string + { + return $this->_packageName; + } + + public function getPrivateName(): string + { + return $this->_privateName; + } + + public function getRepositoryUrl(): string + { + return $this->_repositoryUrl; + } + + public function getAuthor(): string + { + return "{$this->_authorName}"; + } + + public function setOnInstall(array $callbacks): void + { + $this->_onInstall = $callbacks; + } + + public function setOnEnable(array $callbacks): void + { + $this->_onEnable = $callbacks; + } + + public function setOnDisable(array $callbacks): void + { + $this->_onDisable = $callbacks; + } + + public function setOnUninstall(array $callbacks): void + { + $this->_onUninstall = $callbacks; + } + + public function onPageLoad(User $user, Pages $pages, Cache $cache, Smarty $smarty, iterable $navs, Widgets $widgets, ?TemplateBase $template) + { + // ... + } + + public function onInstall() + { + $this->callLifecycleHooks($this->_onInstall); + } + + public function onEnable() + { + $this->callLifecycleHooks($this->_onEnable); + } + + public function onDisable() + { + $this->callLifecycleHooks($this->_onDisable); + } + + public function onUninstall() + { + // ... + } + + public function getDebugInfo(): array + { + return []; + } + + private function callLifecycleHooks(array $hooks): void + { + foreach ($hooks as $callback) { + /** @var \NamelessMC\Framework\ModuleLifecycle\Hook $hook */ + $hook = self::$container->make($callback); + $hook->execute(); + } + } +} diff --git a/core/classes/Extend/BaseExtender.php b/core/classes/Extend/BaseExtender.php index a29a662354..7617dfdd0c 100644 --- a/core/classes/Extend/BaseExtender.php +++ b/core/classes/Extend/BaseExtender.php @@ -5,12 +5,15 @@ abstract class BaseExtender { + protected \ComposerModuleWrapper $module; protected string $moduleName; protected string $moduleDisplayName; - public function setModuleName(string $moduleName, string $moduleDisplayName): BaseExtender { - $this->moduleName = $moduleName; - $this->moduleDisplayName = $moduleDisplayName; + public function setModule(\ComposerModuleWrapper $module): BaseExtender { + $this->module = $module; + + $this->moduleName = $module->getPrivateName(); + $this->moduleDisplayName = $module->getName(); return $this; } diff --git a/core/classes/Extend/ModuleLifecycle.php b/core/classes/Extend/ModuleLifecycle.php new file mode 100644 index 0000000000..c9277f193f --- /dev/null +++ b/core/classes/Extend/ModuleLifecycle.php @@ -0,0 +1,34 @@ +module->setOnInstall($this->onInstall); + $this->module->setOnEnable($this->onEnable); + $this->module->setOnDisable($this->onDisable); + } + + public function onInstall(string $hook): ModuleLifecycle { + $this->onInstall[] = $hook; + + return $this; + } + + public function onEnable(string $hook): ModuleLifecycle { + $this->onEnable[] = $hook; + + return $this; + } + + public function onDisable(string $hook): ModuleLifecycle { + $this->onDisable[] = $hook; + + return $this; + } +} \ No newline at end of file diff --git a/core/classes/ModuleLifecycle/Hook.php b/core/classes/ModuleLifecycle/Hook.php new file mode 100644 index 0000000000..ab5d38a8ac --- /dev/null +++ b/core/classes/ModuleLifecycle/Hook.php @@ -0,0 +1,8 @@ +setModuleName( - $package['extra']['nameless_module']['name'], - $package['extra']['nameless_module']['display_name'] - )->extend($container); - } - } - } + ComposerModuleDiscovery::bootModules($container, $enabled_modules, ComposerModuleDiscovery::discoverModules()); // Maintenance mode? if (Settings::get('maintenance') === '1') { diff --git a/custom/panel_templates/Default/core/modules.tpl b/custom/panel_templates/Default/core/modules.tpl index 159b1dbef1..54319a7826 100644 --- a/custom/panel_templates/Default/core/modules.tpl +++ b/custom/panel_templates/Default/core/modules.tpl @@ -54,6 +54,9 @@ {$module.name} {$module.version} + {if $module.repository_url} + + {/if} {if $module.version_mismatch}