From 07486762dc3932e662a6fe0245d48ab6d49c2094 Mon Sep 17 00:00:00 2001 From: slawkens <slawkens@gmail.com> Date: Tue, 14 Feb 2023 16:03:22 +0100 Subject: [PATCH] Add categories in tabs, move more settings, revert back getPluginSettings Categories and sections are now not numbered Remove example settings plugin --- admin/pages/settings.php | 64 +++- config.php | 59 ---- plugins/example-settings-plugin.json | 11 - plugins/example-settings-plugin/settings.php | 36 -- plugins/example.json | 3 +- system/libs/plugins.php | 22 +- system/settings.php | 327 ++++++++++++++++++- 7 files changed, 396 insertions(+), 126 deletions(-) delete mode 100644 plugins/example-settings-plugin.json delete mode 100644 plugins/example-settings-plugin/settings.php diff --git a/admin/pages/settings.php b/admin/pages/settings.php index 53e5779e..e5eae974 100644 --- a/admin/pages/settings.php +++ b/admin/pages/settings.php @@ -11,14 +11,20 @@ defined('MYAAC') or die('Direct access not allowed!'); $title = 'Settings'; require_once SYSTEM . 'clients.conf.php'; -if (!isset($_GET['plugin']) || empty($_GET['plugin'])) { - error('Please select plugin name from left Panel.'); +if (empty($_GET['plugin'])) { + error('Please select plugin from left Panel.'); return; } $plugin = $_GET['plugin']; if($plugin != 'core') { + $pluginSettings = Plugins::getPluginSettings($plugin); + if (!$pluginSettings) { + error('This plugin does not exist or does not have options defined.'); + return; + } + $settingsFilePath = PLUGINS . $plugin . '/settings.php'; } else { @@ -58,7 +64,7 @@ if (isset($_POST['save'])) { success('Saved at ' . date('H:i')); } -$title = ($plugin == 'core' ? 'MyAAC Settings' : 'Plugin Settings - ' . $plugin); +$title = ($plugin == 'core' ? 'Settings' : 'Plugin Settings - ' . $plugin); $query = 'SELECT `key`, `value` FROM `' . TABLE_PREFIX . 'settings` WHERE `plugin_name` = ' . $db->quote($plugin) . ';'; $query = $db->query($query); @@ -79,16 +85,43 @@ if($query->rowCount() > 0) { <div class="box-body"> <button name="save" type="submit" class="btn btn-primary">Save</button> </div> - <?php + <br/> + <ul class="nav nav-tabs" id="myTab"> + <?php + $i = 0; + foreach($settingsFile as $key => $setting) { + if ($setting['type'] === 'category') { + ?> + <li class="nav-item"> + <button class="nav-link<?= ($i === 0 ? ' active' : ''); ?>" id="home-tab-<?= $i++; ?>" data-toggle="tab" data-target="#tab-<?= str_replace(' ', '', $setting['title']); ?>" type="button"><?= $setting['title']; ?></button> + </li> + <?php + } + } + ?> + </ul> + <div class="tab-content" id="tab-content"> + <?php $checkbox = function ($key, $type, $value) { echo '<label><input type="radio" id="' . $key . '" name="settings[' . $key . ']" value="' . ($type ? 'true' : 'false') . '" ' . ($value === $type ? 'checked' : '') . '/>' . ($type ? 'Yes' : 'No') . '</label> '; }; $i = 0; + $j = 0; foreach($settingsFile as $key => $setting) { - if($setting['type'] === 'section') { - if($i++ !== 0) { + if ($setting['type'] === 'category') { + if ($j++ !== 0) { + echo '</tbody></table></div>'; + } + ?> + <div class="tab-pane fade show<?= ($j === 1 ? ' active' : ''); ?>" id="tab-<?= str_replace(' ', '', $setting['title']); ?>"> + <?php + continue; + } + + if ($setting['type'] === 'section') { + if ($i++ !== 0) { echo '</tbody></table>'; } ?> @@ -120,7 +153,7 @@ if($query->rowCount() > 0) { } } else { - $value = (isset($setting['default']) ? $setting['default'] : false); + $value = ($setting['default'] ?? false); } $checkbox($key, true, $value); @@ -128,11 +161,11 @@ if($query->rowCount() > 0) { } else if (in_array($setting['type'], ['text', 'number', 'email', 'password'])) { - echo '<input class="form-control" type="' . $setting['type'] . '" name="settings[' . $key . ']" value="' . (isset($settingsDb[$key]) ? $settingsDb[$key] : (!empty($setting['default']) ? $setting['default'] : '')) . '" id="' . $key . '"/>'; + echo '<input class="form-control" type="' . $setting['type'] . '" name="settings[' . $key . ']" value="' . ($settingsDb[$key] ?? ($setting['default'] ?? '')) . '" id="' . $key . '"/>'; } else if($setting['type'] === 'textarea') { - echo '<textarea class="form-control" name="settings[' . $key . ']" id="' . $key . '">' . (isset($settingsDb[$key]) ? $settingsDb[$key] : (!empty($setting['default']) ? $setting['default'] : '')) . '</textarea>'; + echo '<textarea class="form-control" name="settings[' . $key . ']" id="' . $key . '">' . ($settingsDb[$key] ?? ($setting['default'] ?? '')) . '</textarea>'; } if ($setting['type'] === 'options') { @@ -159,6 +192,15 @@ if($query->rowCount() > 0) { $setting['options'] = $clients; } + else { + if (is_string($setting['options'])) { + $setting['options'] = explode(',', $setting['options']); + foreach ($setting['options'] as &$option) { + $option = trim($option); + } + } + } + echo '<select class="form-control" name="settings[' . $key . ']" id="' . $key . '">'; foreach ($setting['options'] as $value => $option) { $compareTo = (isset($settingsDb[$key]) ? $settingsDb[$key] : (isset($setting['default']) ? $setting['default'] : '')); @@ -189,10 +231,12 @@ if($query->rowCount() > 0) { ?> </tbody> </table> + </div> + </div> <div class="box-footer"> <button name="save" type="submit" class="btn btn-primary">Save</button> </div> </div> </div> </div> -</form> \ No newline at end of file +</form> diff --git a/config.php b/config.php index 3d8954b1..19d83b30 100644 --- a/config.php +++ b/config.php @@ -54,41 +54,7 @@ $config = array( //'2' => 'Your Second World Name' ), - // images - 'outfit_images_url' => 'https://outfit-images.ots.me/outfit.php', // set to animoutfit.php for animated outfit - 'outfit_images_wrong_looktypes' => [75, 126, 127, 266, 302], // this looktypes needs to have different margin-top and margin-left because they are wrong positioned - 'item_images_url' => 'https://item-images.ots.me/1092/', // set to images/items if you host your own items in images folder - 'item_images_extension' => '.gif', - - // creatures - 'creatures_images_url' => 'images/monsters/', // set to images/monsters if you host your own creatures in images folder - 'creatures_images_extension' => '.gif', - 'creatures_images_preview' => false, // set to true to allow picture previews for creatures - 'creatures_items_url' => 'https://tibia.fandom.com/wiki/', // set to website which shows details about items. - 'creatures_loot_percentage' => true, // set to true to show the loot tooltip percent - - // account - 'account_management' => true, // disable if you're using other method to manage users (fe. tfs account manager) - 'account_login_by_email' => false, // use email instead of Account Name like in latest Tibia - 'account_login_by_email_fallback' => false, // allow also additionally login by Account Name/Number (for users that might forget their email) - 'account_create_auto_login' => false, // auto login after creating account? - 'account_create_character_create' => true, // allow directly to create character on create account page? - 'account_mail_verify' => false, // force users to confirm their email addresses when registering - 'account_mail_confirmed_reward' => [ // reward users for confirming their E-Mails - // account_mail_verify needs to be enabled too - 'premium_days' => 0, - 'premium_points' => 0, - 'coins' => 0, - 'message' => 'You received %d %s for confirming your E-Mail address.' // example: You received 20 premium points for confirming your E-Mail address. - ], - 'account_mail_unique' => true, // email addresses cannot be duplicated? (one account = one email) 'account_mail_block_plus_sign' => true, // block email with '+' signs like test+box@gmail.com (help protect against spamming accounts) - 'account_premium_days' => 0, // default premium days on new account - 'account_premium_points' => 0, // default premium points on new account - 'account_welcome_mail' => true, // send welcome email when user registers - 'account_mail_change' => 2, // how many days user need to change email to account - block hackers - 'account_country' => true, // user will be able to set country of origin when registering account, this information will be viewable in others places aswell - 'account_country_recognize' => true, // should country of user be automatically recognized by his IP? This makes an external API call to http://ipinfo.io 'account_change_character_name' => false, // can user change their character name for premium points? 'account_change_character_name_points' => 30, // cost of name change 'account_change_character_sex' => false, // can user change their character sex for premium points? @@ -169,31 +135,6 @@ $config = array( 1 => 'Sample town' ), - // guilds - 'guild_management' => true, // enable guild management system on the site? - 'guild_need_level' => 1, // min. level to form a guild - 'guild_need_premium' => true, // require premium account to form a guild? - 'guild_image_size_kb' => 80, // maximum size of the guild logo image in KB (kilobytes) - 'guild_description_default' => 'New guild. Leader must edit this text :)', - 'guild_description_chars_limit' => 1000, // limit of guild description - 'guild_description_lines_limit' => 6, // limit of lines, if description has more lines it will be showed as long text, without 'enters' - 'guild_motd_chars_limit' => 150, // limit of MOTD (message of the day) that is shown later in the game on the guild channel - - // online page - 'online_record' => true, // display players record? - 'online_vocations' => false, // display vocation statistics? - 'online_vocations_images' => false, // display vocation images? - 'online_skulls' => false, // display skull images - 'online_outfit' => true, - 'online_afk' => false, - - // support list page - 'team_style' => 2, // 1/2 (1 - normal table, 2 - in boxes, grouped by group id) - 'team_display_status' => true, - 'team_display_lastlogin' => true, - 'team_display_world' => false, - 'team_display_outfit' => true, - // bans page 'bans_per_page' => 20, diff --git a/plugins/example-settings-plugin.json b/plugins/example-settings-plugin.json deleted file mode 100644 index b951b113..00000000 --- a/plugins/example-settings-plugin.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "enabled": 1, - "name": "Example Settings Plugin", - "description": "This is just an example of a Plugin for MyAAC.", - "version": "1.0", - "author": "nobody", - "contact": "nobody@example.org", - "require": { - "myaac": "0.9.0" - } - } diff --git a/plugins/example-settings-plugin/settings.php b/plugins/example-settings-plugin/settings.php deleted file mode 100644 index 6b7a2fe0..00000000 --- a/plugins/example-settings-plugin/settings.php +++ /dev/null @@ -1,36 +0,0 @@ -<?php - -return [ - 'donation_type' => [ - 'name' => 'Donation Type', - 'type' => 'options', - 'options' => ['points' => 'Points', 'coins' => 'Coins'], - 'default' => 'points', - 'desc' => 'What should be added to player account?', - ], - 'default_outfit_colors' => [ - 'name' => 'Default Outfit Colors', - 'type' => 'text', - 'default' => '4,38,87,114', - 'desc' => "Default colors of outfits/addons in addons category<br/> - doesn't matter for othire and other servers without addons<br/> - you can use this outfit generator: http://sleqqus.idl.pl/tlg<br/> - Format: head,body,legs,feet", - ], - 'section_1' => [ - 'type' => 'section', - 'title' => 'Section Test', - ], - 'just_testing_boolean' => [ - 'name' => 'Just Testing Boolean', - 'type' => 'boolean', - 'default' => false, - 'desc' => "Some description.", - ], - 'just_testing_number' => [ - 'name' => 'Just Testing Number', - 'type' => 'number', - 'default' => 999, - 'desc' => "Some description.", - ], -]; \ No newline at end of file diff --git a/plugins/example.json b/plugins/example.json index 6591a333..20415897 100644 --- a/plugins/example.json +++ b/plugins/example.json @@ -39,5 +39,6 @@ "redirect_from": "/redirectExample", "redirect_to": "account/manage" } - } + }, + "settings": "plugins/your-plugin-folder/settings.php" } diff --git a/system/libs/plugins.php b/system/libs/plugins.php index 5568f992..13f8a08f 100644 --- a/system/libs/plugins.php +++ b/system/libs/plugins.php @@ -207,13 +207,33 @@ class Plugins { return $hooks; } + public static function getPluginSettings($pluginName) + { + $plugin_json = self::getPluginJson($pluginName); + if (!$plugin_json) { + return false; + } + + if (!isset($plugin_json['settings']) || !file_exists(BASE . $plugin_json['settings'])) { + return false; + } + + return $plugin_json['settings']; + } + public static function getPluginJson($name = null) { if(!isset($name)) { return self::$plugin_json; } - $string = file_get_contents(PLUGINS . $name . '.json'); + $pathToPlugin = PLUGINS . $name . '.json'; + if (!file_exists($pathToPlugin)) { + self::$warnings[] = "Cannot load " . $name . ".json. File doesn't exist."; + return false; + } + + $string = file_get_contents($pathToPlugin); $string = self::removeComments($string); $plugin_json = json_decode($string, true); if ($plugin_json == null) { diff --git a/system/settings.php b/system/settings.php index 076043e6..ff19ac2f 100644 --- a/system/settings.php +++ b/system/settings.php @@ -1,6 +1,10 @@ <?php return [ + 'category_1' => [ + 'type' => 'category', + 'title' => 'General' + ], 'section_1' => [ 'type' => 'section', 'title' => 'Template' @@ -63,13 +67,13 @@ might bring some performance when disabled', 'charset' => [ 'name' => 'Meta Charset', 'type' => 'text', - 'desc' => 'Charset used in <meta>', + 'desc' => 'Charset used in ' . escapeHtml('<meta>'), 'default' => 'utf-8', ], 'meta_description' => [ 'name' => 'Meta Description', 'type' => 'textarea', - 'desc' => 'description of the site in <meta>', + 'desc' => 'description of the site in ' . escapeHtml('<meta>'), 'default' => 'Tibia is a free massive multiplayer online role playing game (MMORPG).', ], 'meta_keywords' => [ @@ -81,7 +85,7 @@ might bring some performance when disabled', 'footer' => [ 'name' => 'Footer', 'type' => 'textarea', - 'desc' => 'For example: "' . htmlspecialchars('<br/>') . 'Your Server © 2020. All rights reserved."', + 'desc' => 'For example: "' . escapeHtml('<br/>') . 'Your Server © 2020. All rights reserved."', 'default' => '', ], 'language' => [ @@ -90,14 +94,18 @@ might bring some performance when disabled', 'options' => ['en' => 'English'], 'desc' => 'default language (currently only English available)', 'default' => 'en', - ], + ],*/ /*'language_allow_change' => [ 'name' => 'Language Allow Change', 'type' => 'boolean', 'default' => false, 'desc' => 'default language (currently only English available)' ],*/ - 'section_4' => [ + [ + 'type' => 'category', + 'title' => 'Counters', + ], + [ 'type' => 'section', 'title' => 'Visitors Counter & Views Counter' ], @@ -119,9 +127,121 @@ might bring some performance when disabled', 'desc' => 'Enable Views Counter? It will show how many times the website has been viewed by users', 'default' => true, ], - 'section_5' => [ + [ + 'type' => 'category', + 'title' => 'Account', + ], + [ 'type' => 'section', - 'title' => 'Images URL' + 'title' => 'Account Settings' + ], + 'account_management' => [ + 'name' => 'Enable Account Management', + 'type' => 'boolean', + 'desc' => "disable if you're using other method to manage users (fe. tfs account manager)", + 'default' => true, + ], + 'account_login_by_email' => [ + 'name' => 'Account Login By E-Mail', + 'type' => 'boolean', + 'desc' => "use email instead of Account Name like in latest Tibia", + 'default' => true, + ], + 'account_login_by_email_fallback' => [ + 'name' => 'Account Login By E-Mail Fallback', + 'type' => 'boolean', + 'desc' => "allow also additionally login by Account Name/Number (for users that might forget their email). Works only if Account Login By E-Mail is also enabled", + 'default' => false, + ], + 'account_create_auto_login' => [ + 'name' => 'Account Create Auto Login', + 'type' => 'boolean', + 'desc' => 'Auto login after creating account?', + 'default' => false, + ], + 'account_create_character_create' => [ + 'name' => 'Account Create Character Create', + 'type' => 'boolean', + 'desc' => 'Allow to create character directly on create account page?', + 'default' => true, + ], + 'account_mail_verify' => [ + 'name' => 'Account Mail Verify', + 'type' => 'boolean', + 'desc' => 'Force users to confirm their email addresses when registering account', + 'default' => false, + ], + 'account_mail_unique' => [ + 'name' => 'Account Mail Unique', + 'type' => 'boolean', + 'desc' => 'Email addresses cannot be duplicated? (one account = one email)', + 'default' => true, + ], + 'account_premium_days' => [ + 'name' => 'Default Account Premium Days', + 'type' => 'number', + 'desc' => 'Default premium days on new account', + 'default' => 0, + ], + 'account_premium_points' => [ + 'name' => 'Default Account Premium Points', + 'type' => 'number', + 'desc' => 'Default premium points on new account', + 'default' => 0, + ], + 'account_welcome_mail' => [ + 'name' => 'Account Welcome Mail', + 'type' => 'boolean', + 'desc' => 'Send welcome email when user registers', + 'default' => true, + ], + 'account_mail_change' => [ + 'name' => 'Account Mail Change Days', + 'type' => 'number', + 'desc' => 'How many days user need to change email to account - block hackers', + 'default' => 2, + ], + 'account_country' => [ + 'name' => 'Account Country', + 'type' => 'boolean', + 'desc' => 'User will be able to set country of origin when registering account, this information will be viewable in others places as well', + 'default' => true, + ], + 'account_country_recognize' => [ + 'name' => 'Auto Recognize Account Country', + 'type' => 'boolean', + 'desc' => 'should country of user be automatically recognized by his IP? This makes an external API call to http://ipinfo.io', + 'default' => true, + ], + [ + 'type' => 'section', + 'title' => 'Reward Users for confirming their E-Mails. Works only with Account Mail Verify enabled' + ], + 'account_mail_confirmed_reward_premium_days' => [ + 'name' => 'Reward Premium Points', + 'type' => 'number', + 'desc' => '0 to disable', + 'default' => 0, + ], + 'account_mail_confirmed_reward_premium_points' => [ + 'name' => 'Reward Premium Points', + 'type' => 'number', + 'desc' => '0 to disable', + 'default' => 0, + ], + 'account_mail_confirmed_reward_coins' => [ + 'name' => 'Reward Premium Points', + 'type' => 'number', + 'desc' => '0 to disable. Works only with servers that supports coins', + 'default' => 0, + ], + [ + 'type' => 'category', + 'title' => 'Images', + ], + [ + 'type' => 'section', + 'title' => 'Item and Outfit Images' ], 'outfit_images_url' => [ 'name' => 'Outfit Images URL', @@ -129,10 +249,201 @@ might bring some performance when disabled', 'desc' => 'Set to animoutfit.php for animated outfit', 'default' => 'http://outfit-images.ots.me/outfit.php', ], + 'outfit_images_wrong_looktypes' => [ + 'name' => 'Outfit Images Wrong Looktypes', + 'type' => 'text', + 'desc' => 'This looktypes needs to have different margin-top and margin-left because they are wrong positioned', + 'default' => '75, 126, 127, 266, 302', + ], 'item_images_url' => [ 'name' => 'Item Images URL', 'type' => 'text', 'desc' => 'Set to images/items if you host your own items in images folder', 'default' => 'http://item-images.ots.me/1092/', ], -]; \ No newline at end of file + 'item_images_extension' => [ + 'name' => 'Item Images File Extension', + 'type' => 'text', + 'desc' => '', + 'default' => '.gif', + ], + [ + 'type' => 'section', + 'title' => 'Monsters images' + ], + 'creatures_images_url' => [ + 'name' => 'Creatures images URL', + 'type' => 'text', + 'desc' => 'Set to images/monsters if you host your own creatures in images folder', + 'default' => 'images/monsters/', + ], + 'creatures_images_extension' => [ + 'name' => 'Creatures Images File Extension', + 'type' => 'text', + 'desc' => '', + 'default' => '.gif', + ], + 'creatures_images_preview' => [ + 'name' => 'Item Images URL', + 'type' => 'boolean', + 'desc' => 'Set to true to allow picture previews for creatures', + 'default' => false, + ], + 'creatures_items_url' => [ + 'name' => 'Creatures Items URL', + 'type' => 'text', + 'desc' => 'Set to website which shows details about items', + 'default' => 'https://tibia.fandom.com/wiki/', + ], + 'creatures_loot_percentage' => [ + 'name' => 'Creatures Items URL', + 'type' => 'boolean', + 'desc' => 'Set to true to show the loot tooltip percent', + 'default' => true, + ], + [ + 'type' => 'category', + 'title' => 'Guilds', + ], + [ + 'type' => 'section', + 'title' => 'Guilds' + ], + 'guild_management' => [ + 'name' => 'Enable Guilds Management', + 'type' => 'boolean', + 'desc' => 'Enable guild management system on the site', + 'default' => true, + ], + 'guild_need_level' => [ + 'name' => 'Guild Need Level', + 'type' => 'number', + 'desc' => 'Min. level to form a guild', + 'default' => 1, + ], + 'guild_need_premium' => [ + 'name' => 'Guild Need Premium', + 'type' => 'boolean', + 'desc' => 'Require premium account to form a guild?', + 'default' => true, + ], + 'guild_image_size_kb' => [ + 'name' => 'Guild Image Size', + 'type' => 'number', + 'desc' => 'Maximum size of the guild logo image in KB (kilobytes)', + 'default' => 80, + ], + 'guild_description_default' => [ + 'name' => 'Default Guild Description', + 'type' => 'text', + 'desc' => 'Default description set on new guild', + 'default' => 'New guild. Leader must edit this text :)', + ], + 'guild_description_chars_limit' => [ + 'name' => 'Guild Description Characters Limit', + 'type' => 'boolean', + 'desc' => 'How many characters can be in guild description', + 'default' => 1000, + ], + 'guild_description_lines_limit' => [ + 'name' => 'Guild Description Lines Limit', + 'type' => 'number', + 'desc' => "Limit of lines, if description has more lines it will be showed as long text, without 'enters'", + 'default' => 6, + ], + 'guild_motd_chars_limit' => [ + 'name' => 'Guild MOTD Characters Limit', + 'type' => 'boolean', + 'desc' => 'Limit of MOTD (message of the day) that is shown later in the game on the guild channel', + 'default' => 150, + ], + [ + 'type' => 'category', + 'title' => 'Pages', + ], + 'section_10' => [ + 'type' => 'section', + 'title' => 'Online Page' + ], + 'online_record' => [ + 'name' => 'Display Players Record', + 'type' => 'boolean', + 'desc' => '', + 'default' => true, + ], + 'online_vocations' => [ + 'name' => 'Display Vocation Statistics', + 'type' => 'boolean', + 'desc' => '', + 'default' => false, + ], + 'online_vocations_images' => [ + 'name' => 'Display Vocation Images', + 'type' => 'boolean', + 'desc' => 'Only if Display Vocation Statistics enabled', + 'default' => true, + ], + 'online_skulls' => [ + 'name' => 'Display skull images', + 'type' => 'boolean', + 'desc' => '', + 'default' => true, + ], + 'online_outfit' => [ + 'name' => 'Display Player Outfit', + 'type' => 'boolean', + 'desc' => '', + 'default' => true, + ], + 'online_afk' => [ + 'name' => 'Display Players AFK', + 'type' => 'boolean', + 'desc' => '', + 'default' => false, + ], + [ + 'type' => 'section', + 'title' => 'Team Page' + ], + 'team_style' => [ + 'name' => 'Style', + 'type' => 'options', + 'desc' => '', + 'options' => ['normal table', 'in boxes, grouped by group id'], + 'default' => 2, + ], + 'team_display_status' => [ + 'name' => 'Display Online Status', + 'type' => 'boolean', + 'desc' => '', + 'default' => true, + ], + 'team_display_lastlogin' => [ + 'name' => 'Display Last Login', + 'type' => 'boolean', + 'desc' => '', + 'default' => true, + ], + 'team_display_world' => [ + 'name' => 'Display World', + 'type' => 'boolean', + 'desc' => '', + 'default' => false, + ], + 'team_display_outfit' => [ + 'name' => 'Display Outfit', + 'type' => 'boolean', + 'desc' => '', + 'default' => true, + ], + [ + 'type' => 'section', + 'title' => 'Bans Page' + ], + 'bans_per_page' => [ + 'name' => 'Display Players Record', + 'type' => 'boolean', + 'desc' => '', + 'default' => true, + ], +];