From 911be7001808104011efdccb9c9aeef0adfdfc6f Mon Sep 17 00:00:00 2001 From: Robin Date: Thu, 2 Jun 2022 20:33:17 +0200 Subject: [PATCH 001/337] Remove manual setting queries --- modules/Core/pages/panel/avatars.php | 49 ++++--------------- modules/Core/pages/panel/emails.php | 31 ++---------- .../Core/pages/panel/emails_mass_message.php | 7 +-- 3 files changed, 16 insertions(+), 71 deletions(-) diff --git a/modules/Core/pages/panel/avatars.php b/modules/Core/pages/panel/avatars.php index a26248974f..aa49094ef8 100644 --- a/modules/Core/pages/panel/avatars.php +++ b/modules/Core/pages/panel/avatars.php @@ -24,21 +24,11 @@ if (Input::exists()) { if (Token::check()) { if (isset($_POST['avatar_source'])) { - // Custom avatars? - if (isset($_POST['custom_avatars']) && $_POST['custom_avatars'] == 1) { - $custom_avatars = 1; - } else { - $custom_avatars = 0; - } - try { - DB::getInstance()->update('settings', ['name', 'user_avatars'], ['value' => $custom_avatars]); - - DB::getInstance()->update('settings', ['name', 'default_avatar_type'], ['value' => Input::get('default_avatar')]); - - DB::getInstance()->update('settings', ['name', 'avatar_site'], ['value' => Input::get('avatar_source')]); - - DB::getInstance()->update('settings', ['name', 'avatar_type'], ['value' => Input::get('avatar_perspective')]); + Util::setSetting('user_avatars', (isset($_POST['custom_avatars']) && $_POST['custom_avatars']) ? '1' : '0'); + Util::setSetting('default_avatar_type', Input::get('default_avatar')); + Util::setSetting('avatar_site', Input::get('avatar_source')); + Util::setSetting('avatar_type', Input::get('avatar_perspective')); $cache->setCache('avatar_settings_cache'); $cache->store('custom_avatars', $custom_avatars); @@ -52,10 +42,7 @@ if (isset($_POST['avatar'])) { // Selecting a new default avatar try { - $default_avatar = DB::getInstance()->get('settings', ['name', 'custom_default_avatar'])->results(); - $default_avatar = $default_avatar[0]->id; - DB::getInstance()->update('settings', $default_avatar, ['value' => Input::get('avatar')]); - + Util::setSetting('custom_default_avatar', Input::get('avatar')); $cache->setCache('avatar_settings_cache'); $cache->store('default_avatar_image', Input::get('avatar')); } catch (Exception $e) { @@ -98,22 +85,6 @@ ]); } -// Get setting values -$custom_avatars = DB::getInstance()->get('settings', ['name', 'user_avatars'])->results(); -$custom_avatars = $custom_avatars[0]->value; - -$default_avatar_type = DB::getInstance()->get('settings', ['name', 'default_avatar_type'])->results(); -$default_avatar_type = $default_avatar_type[0]->value; - -$mc_avatar_source = DB::getInstance()->get('settings', ['name', 'avatar_site'])->results(); -$mc_avatar_source = $mc_avatar_source[0]->value; - -$mc_avatar_perspective = DB::getInstance()->get('settings', ['name', 'avatar_type'])->results(); -$mc_avatar_perspective = $mc_avatar_perspective[0]->value; - -$default_avatar_image = DB::getInstance()->get('settings', ['name', 'custom_default_avatar'])->results(); -$default_avatar_image = $default_avatar_image[0]->value; - $image_path = implode(DIRECTORY_SEPARATOR, [ROOT_PATH, 'uploads', 'avatars', 'defaults']); $images = scandir($image_path); $template_images = []; @@ -141,16 +112,16 @@ 'TOKEN' => Token::get(), 'SUBMIT' => $language->get('general', 'submit'), 'CUSTOM_AVATARS' => $language->get('admin', 'allow_custom_avatars'), - 'CUSTOM_AVATARS_VALUE' => $custom_avatars, + 'CUSTOM_AVATARS_VALUE' => Util::getSetting('users_avatars'), 'DEFAULT_AVATAR' => $language->get('admin', 'default_avatar'), - 'DEFAULT_AVATAR_VALUE' => $default_avatar_type, + 'DEFAULT_AVATAR_VALUE' => Utils::getSetting('default_avatar_type'), 'MINECRAFT_AVATAR' => $language->get('admin', 'minecraft_avatar'), 'CUSTOM_AVATAR' => $language->get('admin', 'custom_avatar'), 'MINECRAFT_AVATAR_SOURCE' => $language->get('admin', 'minecraft_avatar_source'), 'MINECRAFT_AVATAR_VALUES' => AvatarSource::getAllSourceNames(), - 'MINECRAFT_AVATAR_VALUE' => $mc_avatar_source, + 'MINECRAFT_AVATAR_VALUE' => Util::getSetting('avatar_site'), 'MINECRAFT_AVATAR_PERSPECTIVE' => $language->get('admin', 'minecraft_avatar_perspective'), - 'MINECRAFT_AVATAR_PERSPECTIVE_VALUE' => $mc_avatar_perspective, + 'MINECRAFT_AVATAR_PERSPECTIVE_VALUE' => Util::getSetting('avatar_type'), 'MINECRAFT_AVATAR_PERSPECTIVE_VALUES' => AvatarSource::getAllPerspectives(), 'HEAD' => $language->get('admin', 'head'), 'FACE' => $language->get('admin', 'face'), @@ -158,7 +129,7 @@ 'SELECT_DEFAULT_AVATAR' => $language->get('admin', 'select_default_avatar'), 'IMAGES' => $template_images, 'NO_AVATARS' => $language->get('admin', 'no_avatars_available'), - 'DEFAULT_AVATAR_IMAGE' => $default_avatar_image, + 'DEFAULT_AVATAR_IMAGE' => Util::getSetting('custom_default_avatar'), 'UPLOAD_NEW_IMAGE' => $language->get('admin', 'upload_new_image'), 'UPLOAD_FORM_ACTION' => (defined('CONFIG_PATH') ? CONFIG_PATH : '') . '/core/includes/image_upload.php', 'DRAG_FILES_HERE' => $language->get('admin', 'drag_files_here'), diff --git a/modules/Core/pages/panel/emails.php b/modules/Core/pages/panel/emails.php index 2c9d14a9bc..0010df22d9 100644 --- a/modules/Core/pages/panel/emails.php +++ b/modules/Core/pages/panel/emails.php @@ -158,27 +158,10 @@ Session::flash('emails_success', $language->get('admin', 'email_settings_updated_successfully')); Redirect::to(URL::build('/panel/core/emails', 'action=edit_messages')); } else { - - if (isset($_POST['enable_mailer']) && $_POST['enable_mailer'] == 1) { - $mailer = '1'; - } else { - $mailer = '0'; - } - - $php_mailer = DB::getInstance()->get('settings', ['name', 'phpmailer'])->results(); - $php_mailer = $php_mailer[0]->id; - - DB::getInstance()->update('settings', $php_mailer, [ - 'value' => $mailer - ]); + Util::setSetting('phpmailer', (isset($_POST['enable_mailer']) && $_POST['enable_mailer']) ? '1' : '0') if (!empty($_POST['email'])) { - $outgoing_email = DB::getInstance()->get('settings', ['name', 'outgoing_email'])->results(); - $outgoing_email = $outgoing_email[0]->id; - - DB::getInstance()->update('settings', $outgoing_email, [ - 'value' => Output::getClean($_POST['email']) - ]); + Util::setSetting('outgoing_email', $_POST['email']); } if ($_POST['port'] && !is_numeric($_POST['port'])) { @@ -247,12 +230,6 @@ } } - $php_mailer = DB::getInstance()->get('settings', ['name', 'phpmailer'])->results(); - $php_mailer = $php_mailer[0]->value; - - $outgoing_email = DB::getInstance()->get('settings', ['name', 'outgoing_email'])->results(); - $outgoing_email = $outgoing_email[0]->value; - require(ROOT_PATH . '/core/email.php'); if ($user->hasPermission('admincp.core.emails_mass_message')) { @@ -272,7 +249,7 @@ 'EMAIL_ERRORS' => $language->get('admin', 'email_errors'), 'EMAIL_ERRORS_LINK' => URL::build('/panel/core/emails/errors'), 'ENABLE_MAILER' => $language->get('admin', 'enable_mailer'), - 'ENABLE_MAILER_VALUE' => $php_mailer, + 'ENABLE_MAILER_VALUE' => Util::getSetting('phpmailer'), 'INFO' => $language->get('general', 'info'), 'DEFAULT_LANGUAGE_HELP' => $language->get('admin', 'default_language_help', [ 'docLinkStart' => "", @@ -288,7 +265,7 @@ ]), 'OUTGOING_EMAIL' => $language->get('admin', 'outgoing_email'), 'OUTGOING_EMAIL_INFO' => $language->get('admin', 'outgoing_email_info'), - 'OUTGOING_EMAIL_VALUE' => Output::getClean($outgoing_email), + 'OUTGOING_EMAIL_VALUE' => Output::getClean(Util::getSetting('outgoing_email')), 'USERNAME' => $language->get('user', 'username'), 'USERNAME_VALUE' => (!empty($GLOBALS['email']['username']) ? Output::getClean($GLOBALS['email']['username']) : ''), 'PASSWORD' => $language->get('user', 'password'), diff --git a/modules/Core/pages/panel/emails_mass_message.php b/modules/Core/pages/panel/emails_mass_message.php index 734fdbf45d..f0fd725c1e 100644 --- a/modules/Core/pages/panel/emails_mass_message.php +++ b/modules/Core/pages/panel/emails_mass_message.php @@ -71,11 +71,8 @@ } } -$php_mailer = DB::getInstance()->get('settings', ['name', 'phpmailer'])->results(); -$php_mailer = $php_mailer[0]->value; - -$outgoing_email = DB::getInstance()->get('settings', ['name', 'outgoing_email'])->results(); -$outgoing_email = $outgoing_email[0]->value; +$php_mailer = Util::getSetting('phpmailer'); +$outgoing_email = Util::getSetting('outgoing_email'); require(ROOT_PATH . '/core/email.php'); From 218825dca65e143cb3b178e50ce6a2cb42f9f30b Mon Sep 17 00:00:00 2001 From: Robin Date: Thu, 2 Jun 2022 20:45:06 +0200 Subject: [PATCH 002/337] Remove manual setting queries --- core/classes/Core/User.php | 7 ++----- core/installation/steps/site_configuration.php | 12 ++---------- modules/Core/pages/complete_signup.php | 8 ++------ modules/Core/pages/login.php | 8 +------- modules/Core/pages/privacy.php | 5 +++-- 5 files changed, 10 insertions(+), 30 deletions(-) diff --git a/core/classes/Core/User.php b/core/classes/Core/User.php index 2fc5d5421b..40f40d9fb7 100644 --- a/core/classes/Core/User.php +++ b/core/classes/Core/User.php @@ -1008,10 +1008,7 @@ public function getProfileViews(): int { * @return bool Whether profile privatizing is allowed and if they have permission to use it. */ public function canPrivateProfile(): bool { - $settings_data = $this->_db->get('settings', ['name', 'private_profile']); - $settings_results = $settings_data->results(); - - return (($settings_results[0]->value == 1) && ($this->hasPermission('usercp.private_profile'))); + return Util::getSetting('private_profile') === '1' && $this->hasPermission('usercp.private_profile'); } /** @@ -1031,7 +1028,7 @@ public function isPrivateProfile(): bool { public function getUserTemplates(): array { $groups = '('; foreach ($this->_groups as $group) { - $groups .= ((int)$group->id) . ','; + $groups .= ((int) $group->id) . ','; } $groups = rtrim($groups, ',') . ')'; diff --git a/core/installation/steps/site_configuration.php b/core/installation/steps/site_configuration.php index 32d4bdcfdd..1a3a52aca8 100644 --- a/core/installation/steps/site_configuration.php +++ b/core/installation/steps/site_configuration.php @@ -39,16 +39,8 @@ try { Util::setSetting('sitename', Input::get('sitename')); - - DB::getInstance()->insert('settings', [ - 'name' => 'incoming_email', - 'value' => Input::get('incoming') - ]); - - DB::getInstance()->insert('settings', [ - 'name' => 'outgoing_email', - 'value' => Input::get('outgoing') - ]); + Util::setSetting('incoming_email', Input::get('incoming')); + Util::setSetting('outgoing_email', Input::get('outgoing')); $_SESSION['default_language'] = Input::get('language'); diff --git a/modules/Core/pages/complete_signup.php b/modules/Core/pages/complete_signup.php index f828cd0122..f00f4c4317 100644 --- a/modules/Core/pages/complete_signup.php +++ b/modules/Core/pages/complete_signup.php @@ -24,12 +24,8 @@ } // Ensure API is enabled -$is_api_enabled = DB::getInstance()->get('settings', ['name', 'use_api'])->results(); -if ($is_api_enabled[0]->value != '1') { - $is_legacy_enabled = DB::getInstance()->get('settings', ['name', 'use_legacy_api'])->results(); - if ($is_legacy_enabled[0]->value != '1') { - die('Legacy API is disabled'); - } +if (Util::getSetting('use_api') !== 1) { + die('API is disabled'); } if (!$user->isLoggedIn()) { diff --git a/modules/Core/pages/login.php b/modules/Core/pages/login.php index 59a2948ba6..0490f83160 100644 --- a/modules/Core/pages/login.php +++ b/modules/Core/pages/login.php @@ -151,16 +151,10 @@ // Did the user check 'remember me'? $remember = Input::get('remember') == 1; - // Is Minecraft and AuthMe integration enabled? - $minecraft = MINECRAFT; - - $authme_enabled = DB::getInstance()->get('settings', ['name', 'authme'])->results(); - $authme_enabled = $authme_enabled[0]->value; - $cache->setCache('authme_cache'); $authme_db = $cache->retrieve('authme'); - if ($minecraft == '1' && $authme_enabled == '1' && $authme_db['sync'] == '1') { + if (defined(MINECRAFT) && MINECRAFT && Util::getSetting('authme') === '1' && $authme_db['sync'] == '1') { // Sync AuthMe password try { diff --git a/modules/Core/pages/privacy.php b/modules/Core/pages/privacy.php index 0d7fc2b926..2cb027762a 100644 --- a/modules/Core/pages/privacy.php +++ b/modules/Core/pages/privacy.php @@ -17,9 +17,10 @@ // Retrieve privacy policy from database $policy = DB::getInstance()->get('privacy_terms', ['name', 'privacy'])->results(); if (!count($policy)) { - $policy = DB::getInstance()->get('settings', ['name', 'privacy_policy'])->results(); + $policy = Output::getPurified(Util::getSetting('privacy_policy')); +} else { + $policy = Output::getPurified($policy[0]->value); } -$policy = Output::getPurified($policy[0]->value); $smarty->assign([ 'PRIVACY_POLICY' => $language->get('general', 'privacy_policy'), From ada1c7953d996420c98cdcab52a23f1c912f784a Mon Sep 17 00:00:00 2001 From: Robin Date: Thu, 2 Jun 2022 23:00:21 +0200 Subject: [PATCH 003/337] Check MariaDB version separately --- modules/Core/pages/panel/index.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/Core/pages/panel/index.php b/modules/Core/pages/panel/index.php index 8945ae3916..9d7b5fdd18 100644 --- a/modules/Core/pages/panel/index.php +++ b/modules/Core/pages/panel/index.php @@ -173,10 +173,12 @@ $pdo_server_version = explode('-', $pdo_server_version)[0]; } } - if (!in_array($pdo_driver, ['MySQL', 'MariaDB']) || version_compare($pdo_server_version, '5.7.0', '<')) { - $compat_errors[] = $pdo_driver . ' Server ' . $pdo_server_version; - } else { + + if ($pdo_driver === 'MySQL' && version_compare($pdo_server_version, '5.7', '>=') || + $pdo_driver === 'MariaDB' && version_compare($pdo_server_version, '10.3', '>=')) { $compat_success[] = $pdo_driver . ' Server ' . $pdo_server_version; + } else { + $compat_errors[] = $pdo_driver . ' Server ' . $pdo_server_version; } // Permissions From 37d6ff515630c5d8dcae65989c38f6db06647678 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Thu, 2 Jun 2022 15:05:06 -0600 Subject: [PATCH 004/337] Fix discord widget when error occurs --- modules/Discord Integration/language/en_UK.json | 1 + modules/Discord Integration/widgets/DiscordWidget.php | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/modules/Discord Integration/language/en_UK.json b/modules/Discord Integration/language/en_UK.json index b862c76c11..b34762ed21 100644 --- a/modules/Discord Integration/language/en_UK.json +++ b/modules/Discord Integration/language/en_UK.json @@ -35,6 +35,7 @@ "discord_integration\/discord_username": "Discord Username", "discord_integration\/discord_usernames_updated": "Discord usernames updated successfully", "discord_integration\/discord_widget_disabled": "The widget is disabled for the specified Discord server. Please go to the 'Widget' tab in your Discord server settings, and ensure the Discord widget is enabled and that the ID is correct.", + "discord_integration\/discord_widget_error": "An error occurred when getting Discord widget: {{error}}.", "discord_integration\/discord_widget_theme": "Discord Widget Theme", "discord_integration\/enable_discord_integration": "Enable Discord integration?", "discord_integration\/get_link_code": "Get link code", diff --git a/modules/Discord Integration/widgets/DiscordWidget.php b/modules/Discord Integration/widgets/DiscordWidget.php index 1ba6db7e3b..218806727e 100644 --- a/modules/Discord Integration/widgets/DiscordWidget.php +++ b/modules/Discord Integration/widgets/DiscordWidget.php @@ -49,7 +49,15 @@ public function initialise(): void { $result = $this->_cache->retrieve('discord_widget_check'); } else { - $result = HttpClient::get('https://discord.com/api/guilds/' . Output::getClean($this->_guild_id) . '/widget.json')->json(); + $request = HttpClient::get('https://discord.com/api/guilds/' . Output::getClean($this->_guild_id) . '/widget.json'); + if ($request->hasError()) { + $this->_content = Discord::getLanguageTerm('discord_widget_error', [ + 'error' => $request->getError() + ]); + return; + } + + $result = $request->json(); // Cache for 60 seconds $this->_cache->store('discord_widget_check', $result, 60); From 8ce8a3e2587dcceec5172c409780e4b576815257 Mon Sep 17 00:00:00 2001 From: Robin Date: Thu, 2 Jun 2022 23:09:32 +0200 Subject: [PATCH 005/337] urlencode should be used for urls --- modules/Discord Integration/widgets/DiscordWidget.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/Discord Integration/widgets/DiscordWidget.php b/modules/Discord Integration/widgets/DiscordWidget.php index 218806727e..388b441509 100644 --- a/modules/Discord Integration/widgets/DiscordWidget.php +++ b/modules/Discord Integration/widgets/DiscordWidget.php @@ -49,7 +49,7 @@ public function initialise(): void { $result = $this->_cache->retrieve('discord_widget_check'); } else { - $request = HttpClient::get('https://discord.com/api/guilds/' . Output::getClean($this->_guild_id) . '/widget.json'); + $request = HttpClient::get('https://discord.com/api/guilds/' . urlencode($this->_guild_id) . '/widget.json'); if ($request->hasError()) { $this->_content = Discord::getLanguageTerm('discord_widget_error', [ 'error' => $request->getError() @@ -76,8 +76,7 @@ public function initialise(): void { $theme = $this->_cache->retrieve('discord_widget_theme'); } - $this->_content = '
'; - + $this->_content = '
'; } } } From 67f6d8cc72119851f893faa4411bc760b36974a6 Mon Sep 17 00:00:00 2001 From: Robin Date: Thu, 2 Jun 2022 23:19:09 +0200 Subject: [PATCH 006/337] fix typos --- modules/Core/pages/complete_signup.php | 2 +- modules/Core/pages/panel/avatars.php | 2 +- modules/Core/pages/panel/emails.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/Core/pages/complete_signup.php b/modules/Core/pages/complete_signup.php index f00f4c4317..8f4478e827 100644 --- a/modules/Core/pages/complete_signup.php +++ b/modules/Core/pages/complete_signup.php @@ -24,7 +24,7 @@ } // Ensure API is enabled -if (Util::getSetting('use_api') !== 1) { +if (Util::getSetting('use_api') !== '1') { die('API is disabled'); } diff --git a/modules/Core/pages/panel/avatars.php b/modules/Core/pages/panel/avatars.php index aa49094ef8..cdea863dc0 100644 --- a/modules/Core/pages/panel/avatars.php +++ b/modules/Core/pages/panel/avatars.php @@ -114,7 +114,7 @@ 'CUSTOM_AVATARS' => $language->get('admin', 'allow_custom_avatars'), 'CUSTOM_AVATARS_VALUE' => Util::getSetting('users_avatars'), 'DEFAULT_AVATAR' => $language->get('admin', 'default_avatar'), - 'DEFAULT_AVATAR_VALUE' => Utils::getSetting('default_avatar_type'), + 'DEFAULT_AVATAR_VALUE' => Util::getSetting('default_avatar_type'), 'MINECRAFT_AVATAR' => $language->get('admin', 'minecraft_avatar'), 'CUSTOM_AVATAR' => $language->get('admin', 'custom_avatar'), 'MINECRAFT_AVATAR_SOURCE' => $language->get('admin', 'minecraft_avatar_source'), diff --git a/modules/Core/pages/panel/emails.php b/modules/Core/pages/panel/emails.php index 0010df22d9..e1c4f1070e 100644 --- a/modules/Core/pages/panel/emails.php +++ b/modules/Core/pages/panel/emails.php @@ -158,7 +158,7 @@ Session::flash('emails_success', $language->get('admin', 'email_settings_updated_successfully')); Redirect::to(URL::build('/panel/core/emails', 'action=edit_messages')); } else { - Util::setSetting('phpmailer', (isset($_POST['enable_mailer']) && $_POST['enable_mailer']) ? '1' : '0') + Util::setSetting('phpmailer', (isset($_POST['enable_mailer']) && $_POST['enable_mailer']) ? '1' : '0'); if (!empty($_POST['email'])) { Util::setSetting('outgoing_email', $_POST['email']); From 29d36d4eedc8b3c80b493228b471fffd73e0f8f5 Mon Sep 17 00:00:00 2001 From: PadowYT2 Date: Sat, 4 Jun 2022 22:52:57 +0800 Subject: [PATCH 007/337] Make colors for statistics (#2818) * make colors * remove the border color --- custom/panel_templates/Default/index.tpl | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/custom/panel_templates/Default/index.tpl b/custom/panel_templates/Default/index.tpl index fe7dd189a6..477bf20a13 100644 --- a/custom/panel_templates/Default/index.tpl +++ b/custom/panel_templates/Default/index.tpl @@ -179,8 +179,7 @@ } graphs = [ - {foreach from=$GRAPHS item=graph} - { + {foreach from=$GRAPHS item=graph} { type: 'line', data: { labels: [ @@ -238,12 +237,12 @@ ] }, tooltips: { - backgroundColor: "rgb(255,255,255)", - bodyFontColor: "#858796", + backgroundColor: currentPanelTheme === "dark" ? "#161c25" : "#f8f9fc", + bodyFontColor: currentPanelTheme === "dark" ? "rgb(189,189,189)" : "#858796", + titleFontColor: currentPanelTheme === "dark" ? "rgb(189,189,189)" : "#6e707e", + borderColor: currentPanelTheme !== "dark" ? "#dddfeb" : "#161c25", titleMarginBottom: 10, - titleFontColor: '#6e707e', titleFontSize: 14, - borderColor: '#dddfeb', borderWidth: 1, xPadding: 15, yPadding: 15, From fc8bbd4dbdd2ae908ec86c2a1c4f806df85f8b28 Mon Sep 17 00:00:00 2001 From: PadowYT2 Date: Sat, 4 Jun 2022 22:53:05 +0800 Subject: [PATCH 008/337] Hide statistics on small devices (#2810) --- .../Default/assets/css/custom.css | 6 +++ custom/panel_templates/Default/index.tpl | 45 +++++++++---------- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/custom/panel_templates/Default/assets/css/custom.css b/custom/panel_templates/Default/assets/css/custom.css index 041caa1f91..bf80588365 100644 --- a/custom/panel_templates/Default/assets/css/custom.css +++ b/custom/panel_templates/Default/assets/css/custom.css @@ -451,4 +451,10 @@ footer.sticky-footer { .toast .move-right { position: absolute; left: 20px; +} + +@media only screen and (max-width: 425px) { + .statistics { + display: none; + } } \ No newline at end of file diff --git a/custom/panel_templates/Default/index.tpl b/custom/panel_templates/Default/index.tpl index 477bf20a13..4cbd45e66b 100644 --- a/custom/panel_templates/Default/index.tpl +++ b/custom/panel_templates/Default/index.tpl @@ -46,7 +46,7 @@
{if count($GRAPHS)} -
+
@@ -188,28 +188,27 @@ {/foreach} ], datasets: [ - {foreach from=$graph.datasets item=dataset} - { - fill: false, - borderColor: '{$dataset.colour}', - label: '{$dataset.label}', - yAxisID: '{$dataset.axis}', - lineTension: 0.3, - backgroundColor: "rgba(78, 115, 223, 0.05)", - pointRadius: 3, - pointBackgroundColor: "{$dataset.colour}", - pointBorderColor: "{$dataset.colour}", - pointHoverRadius: 3, - pointHoverBackgroundColor: "{$dataset.colour}", - pointHoverBorderColor: "{$dataset.colour}", - pointHitRadius: 10, - pointBorderWidth: 2, - data: [ - {foreach from=$dataset.data item=data name=ds} - {$data}{if not $smarty.foreach.ds.last}, {/if} - {/foreach} - ] - }, + {foreach from=$graph.datasets item=dataset} { + fill: false, + borderColor: '{$dataset.colour}', + label: '{$dataset.label}', + yAxisID: '{$dataset.axis}', + lineTension: 0.3, + backgroundColor: "rgba(78, 115, 223, 0.05)", + pointRadius: 3, + pointBackgroundColor: "{$dataset.colour}", + pointBorderColor: "{$dataset.colour}", + pointHoverRadius: 3, + pointHoverBackgroundColor: "{$dataset.colour}", + pointHoverBorderColor: "{$dataset.colour}", + pointHitRadius: 10, + pointBorderWidth: 2, + data: [ + {foreach from=$dataset.data item=data name=ds} + {$data}{if not $smarty.foreach.ds.last}, {/if} + {/foreach} + ] + }, {/foreach} ] }, From c802169c035a4094b12daaea63b395d15acf8329 Mon Sep 17 00:00:00 2001 From: Supercrafter100 Date: Thu, 2 Jun 2022 19:20:25 +0000 Subject: [PATCH 009/337] Translated using Weblate (Dutch) Currently translated at 100.0% (1220 of 1220 strings) Translation: NamelessMC/Website - Core Translate-URL: https://translate.namelessmc.com/projects/namelessmc/nameless/nl/ --- custom/languages/nl_NL.json | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/custom/languages/nl_NL.json b/custom/languages/nl_NL.json index d9ff6a726e..c3a8c2d1b4 100644 --- a/custom/languages/nl_NL.json +++ b/custom/languages/nl_NL.json @@ -111,7 +111,7 @@ "admin/default_avatar": "Standaard avatar", "admin/default_group": "Is de standaardgroep (voor nieuwe gebruikers)?", "admin/default_language": "Standaard taal", - "admin/default_language_help": "Gebruikers kunnen kiezen uit alle geinstalleerde talen.", + "admin/default_language_help": "Gebruikers kunnen kiezen uit alle geinstalleerde talen. {{docLinkStart}}Lees meer »{{docLinkEnd}}", "admin/default_server": "Standaard server", "admin/default_template_set": "Standaard sjabloon verzet naar {{template}} succesvol.", "admin/default_timezone": "Standaard tijdzone", @@ -176,7 +176,7 @@ "admin/enable_authme": "AuthMe integratie aanzetten?", "admin/enable_debug_mode": "Wil je debug modus inschakelen?", "admin/enable_mailer": "PHPMailer inschakelen?", - "admin/enable_mailer_help": "Zet dit aan als de emails standaard niet worden verzonden. Als je gebruik wilt maken van PHPMailer heb je een email dienst nodig waarmee je emails kan verzenden, zoals Gmail of een SMTP provider (Outlook/Hotmail).", + "admin/enable_mailer_help": "Als dit aanstaat, worden e-mails verzonden met PHPMailer in plaats van de standaard van het system. Dit zou kunnen helpen met het verzenden van e-mails maar vereist wel dat je een SMTP aanbieder configureert. {{docLinkStart}}Lees meer »{{docLinkEnd}}", "admin/enable_maintenance_mode": "Wil je onderhoud modus inschakelen?", "admin/enable_minecraft_integration": "Minecraft integratie inschakelen?", "admin/enable_nicknames_on_registration": "Bijnamen inschakelen bij het registreren van gebruikers?", @@ -251,7 +251,7 @@ "admin/hook_edited": "Webhook succesvol aangepast", "admin/hook_events": "Gebeurtenissen om deze webhook te activeren", "admin/hook_name": "Webhook Naam", - "admin/hook_select_info": "Alleen Webhooks met 'Nieuw onderwerp' als evenement worden getoond.", + "admin/hook_select_info": "Alleen Webhooks met 'Nieuw onderwerp' of 'Onderwerp reactie' als evenementen worden getoond.", "admin/hook_type": "Webhook-type", "admin/hook_url": "Webhook-URL", "admin/hooks": "Webhooks", @@ -329,7 +329,7 @@ "admin/navbar_icon": "Navbar Icoon", "admin/navbar_icon_instructions": "U kunt hier ook een pictogram aan elk item op de navigatiebalk toevoegen, bijvoorbeeld met behulp van {{faLink}}, {{semLink}}.", "admin/navbar_order": "Navbar ordening", - "admin/navbar_order_instructions": "Je kan elk item een nummer boven de 0 geven om items te ordenen in de navbar, met 1 de eerste en hogere nummers erna.", + "admin/navbar_order_instructions": "Je kan elk item een nummer boven de 0 geven om items te ordenen in de navbar, waar het laagste nummer eerst in de navbar zal komen en hogere nummers erna.", "admin/navigation": "Navigatie", "admin/navigation_settings_updated_successfully": "Navigatie-instellingen succesvol bijgewerkt.", "admin/negative": "Negatief", @@ -571,7 +571,7 @@ "admin/upgrade_php_version": "Upgrade alstublieft uw PHP versie naar tenminste 7.4 - de volgende Nameless release zal de versie die u gebruikt niet langer ondersteunen.", "admin/upload_new_image": "Upload nieuwe afbeelding", "admin/use_friendly_urls": "Vriendelijke URLs", - "admin/use_friendly_urls_help": "BELANGRIJK: Je webserver/webhosting moet geconfigureerd zijn om gebruik te maken van mod_rewrite en .htaccess vooraleer dit werkt.", + "admin/use_friendly_urls_help": "Als dit aanstaat, worden schoner lijkende web adressen gebruikt. Je moet het gebruik van mod_rewrite en .htaccess bestanden toelaten om dit te laten werken. {{docLinkStart}}Lees meer »{{docLinkEnd}}", "admin/user": "Gebruiker", "admin/user_deleted": "Gebruiker succesvol verwijderd.", "admin/user_id": "User ID", @@ -1206,5 +1206,17 @@ "general/purple": "Paars", "general/pink": "Roze", "general/brown": "Bruin", - "general/grey": "Grijs" + "general/grey": "Grijs", + "admin/home_custom_content": "Hoofd Aanpasbare Inhoud", + "installer/database_configured": "De database is geconfigureerd.", + "admin/page_url_contains_nameless_path": "Je aangepaste pagina zou een NamelessMC pagina overschrijven.", + "admin/api_disabled": "API staat uit", + "user/no_providers_admin": "Er zijn nog geen OAuth aanbieders geconfigureerd door de site administrators.", + "admin/debug_link_info": "Belangrijk - Deel deze link alleen met mensen die je vertrouwt!", + "admin/test_email_query": "Komt het niet in je inbox? Probeer het volgende:", + "admin/test_email_suggest_1": "Wacht een paar minuten en check je spam map.", + "admin/test_email_suggest_2": "Update je site zijn DNS records (check SPF & DKIM).", + "admin/test_email_suggest_3": "Configureer een SMTP server. {{docLinkStart}}Lees meer »{{docLinkEnd}}", + "installer/upgrade_error": "Er zijn fouten ontstaan tijdens het upgraden.", + "admin/custom_content": "Aangepaste Inhoud" } From e074cd3ecc1e7d901514a85683a613c05a27e579 Mon Sep 17 00:00:00 2001 From: Supercrafter100 Date: Thu, 2 Jun 2022 19:39:06 +0000 Subject: [PATCH 010/337] Translated using Weblate (Dutch) Currently translated at 100.0% (195 of 195 strings) Translation: NamelessMC/Website - Forum Translate-URL: https://translate.namelessmc.com/projects/namelessmc/website-forum/nl/ --- modules/Forum/language/nl_NL.json | 38 +++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/modules/Forum/language/nl_NL.json b/modules/Forum/language/nl_NL.json index 0d232f05e3..a5ca958685 100644 --- a/modules/Forum/language/nl_NL.json +++ b/modules/Forum/language/nl_NL.json @@ -144,7 +144,7 @@ "forum/forum_icon_maximum": "Het forum icoon mag maximaal 256 karakters lang zijn.", "forum/forum_search": "Forum Zoeken", "forum/forum_updated_successfully": "Forum succesvol geüpdatet.", - "forum/include_in_hook": "Betrek nieuwe berichten van dit forum in webhooks?", + "forum/include_in_hook": "Betrek evenementen van dit forum in webhooks?", "forum/invalid_search_query": "Vul alsjeblieft een zoekterm in tussen {{min}} en {{max}} karakters lang.", "forum/label": "Label", "forum/label_deleted_successfully": "Label succesvol verwijdert.", @@ -159,5 +159,39 @@ "forum/new_search": "Nieuwe zoekopdracht", "forum/new_topic_hook_info": "Nieuw onderwerp", "forum/new_topic_text": "Onderwerp gemaakt in {{forum}} door {{author}}", - "forum/new_reply_in_topic": "{{author}} Heeft gereageerd op onderwerp {{topic}}" + "forum/new_reply_in_topic": "{{author}} Heeft gereageerd op onderwerp {{topic}}", + "forum/search_again_in_x_seconds": "Wacht alstublieft {{count}} seconden voor opnieuw te zoeken.", + "forum/no_news": "Er zijn geen nieuws posts.", + "forum/not_following_any_topics": "Je volgt geen onderwerpen.", + "forum/now_following_topic": "Je volgt nu dit onderwerp, en zult meldingen krijgen van nieuwe reacties.", + "forum/post_id": "Post ID", + "forum/topic_reply": "Onderwerp reactie", + "forum/your_posts": "Jouw post aantal", + "forum/label_type_in_use": "Label type wordt gebruikt, kan niet worden verwijderd.", + "forum/new_topic_reply_text": "Onderwerp reactie gemaakt in {{forum}} door {{author}}", + "forum/no_longer_following_topic": "Je volgt dit onderwerp niet meer, en krijgt geen meldingen meer van nieuwe reacties.", + "forum/no_results_found": "Geen resultaten gevonden.", + "forum/posts_title": "Posts", + "forum/pre_post_create_hook_info": "Voor post aanmaak", + "forum/pre_post_edit_hook_info": "Voor post bewerking", + "forum/pre_topic_create_hook_info": "Voor reactie aanmaak", + "forum/pre_topic_edit_hook_info": "Voor reactie bewerking", + "forum/recent_posts": "Recente Posts", + "forum/recent_topics": "Recente onderwerpen", + "forum/redirect_forum": "Leid forum om?", + "forum/redirect_url": "Omleid URL", + "forum/search_results": "Zoekresultaten", + "forum/settings_updated_successfully": "Instellingen succesvol aangepast.", + "forum/started_by_x": "Gestart door {{author}}", + "forum/sticky_topics": "Plakkende Onderwerpen", + "forum/topic_id": "Onderwerp ID", + "forum/topic_placeholder": "Onderwerp placeholder", + "forum/topics_title": "Onderwerpen", + "forum/total_posts": "Totale post aantal", + "forum/topic_author_uuid": "Onderwerp auteur gebruikers ID", + "forum/topic_author_username": "Onderwerp auteur gebruikersnaam", + "forum/topic_author_nickname": "Topic auteur bijnaam", + "forum/unfollow": "Ontvolg", + "forum/unfollow_all_topics": "Ontvolg alle onderwerpen", + "forum/user_object": "Gebruikersobject" } From 67a8ab545cd5b4ae07460532ee12653bc8646cab Mon Sep 17 00:00:00 2001 From: Marcos Date: Thu, 2 Jun 2022 21:28:32 +0000 Subject: [PATCH 011/337] Translated using Weblate (Spanish) Currently translated at 100.0% (50 of 50 strings) Translation: NamelessMC/Website - Discord Integration Translate-URL: https://translate.namelessmc.com/projects/namelessmc/website-discord-integration/es/ --- modules/Discord Integration/language/es_ES.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/Discord Integration/language/es_ES.json b/modules/Discord Integration/language/es_ES.json index 4ec6a3034c..f6f7575e65 100644 --- a/modules/Discord Integration/language/es_ES.json +++ b/modules/Discord Integration/language/es_ES.json @@ -47,5 +47,6 @@ "discord_integration/get_link_code": "Obtener código de enlace", "discord_integration/discord_invite_info": "Para invitar al bot Nameless Link a tu servidor de Discord, haz clic en {{inviteLinkStart}}aquí{{inviteLinkEnd}}. A continuación, ejecuta el comando {{command}} para enlazar el bot con tu sitio web. También puedes {{selfHostLinkStart}}alojar el bot tú mismo{{selfHostLinkEnd}}.", "discord_integration/discord_user_id": "ID de usuario de Discord", - "discord_integration/discord_widget_disabled": "El widget está desactivado para el servidor de Discord especificado. Ve a la pestaña \"Widget\" en la configuración de tu servidor de Discord y asegúrate de que el widget de Discord está activado y de que el ID es correcto." + "discord_integration/discord_widget_disabled": "El widget está desactivado para el servidor de Discord especificado. Ve a la pestaña \"Widget\" en la configuración de tu servidor de Discord y asegúrate de que el widget de Discord está activado y de que el ID es correcto.", + "discord_integration/discord_widget_error": "Se ha producido un error al obtener el widget de Discord: {{error}}." } From b16e31514d1393c8be341d1f20697e1ca976b87e Mon Sep 17 00:00:00 2001 From: Marcos Date: Thu, 2 Jun 2022 21:30:17 +0000 Subject: [PATCH 012/337] Translated using Weblate (Spanish) Currently translated at 100.0% (1220 of 1220 strings) Translation: NamelessMC/Website - Core Translate-URL: https://translate.namelessmc.com/projects/namelessmc/nameless/es/ --- custom/languages/es_ES.json | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/custom/languages/es_ES.json b/custom/languages/es_ES.json index 7df73dcf27..bb1aec710b 100644 --- a/custom/languages/es_ES.json +++ b/custom/languages/es_ES.json @@ -115,7 +115,7 @@ "admin/default_avatar": "Avatar por defecto", "admin/default_group": "¿Es el grupo por defecto (para los nuevos usuarios)?", "admin/default_language": "Idioma por defecto", - "admin/default_language_help": "Los usuarios podrán elegir entre los idiomas instalados.", + "admin/default_language_help": "Los usuarios podrán elegir entre los idiomas instalados. {{docLinkStart}}Leer más »{{docLinkEnd}}", "admin/default_server": "Servidor por defecto", "admin/default_template_set": "Plantilla por defecto establecida en {{template}} con éxito.", "admin/default_timezone": "Zona horaria por defecto", @@ -182,7 +182,7 @@ "admin/enable_authme": "¿Activar la integración de AuthMe?", "admin/enable_debug_mode": "¿Activar el modo de depuración?", "admin/enable_mailer": "¿Activar PHPMailer?", - "admin/enable_mailer_help": "Habilite esto si los correos electrónicos no están siendo enviados por defecto. El uso de PHPMailer requiere tener un servicio capaz de enviar correos electrónicos, como Gmail o un proveedor SMTP.", + "admin/enable_mailer_help": "Si se activa, los correos electrónicos se enviarán utilizando PHPMailer en lugar del sistema por defecto. Esto puede ayudar a la entrega, pero requiere que se configure un proveedor SMTP. {{docLinkStart}}Leer más »{{docLinkEnd}}", "admin/enable_maintenance_mode": "¿Activar el modo de mantenimiento?", "admin/enable_minecraft_integration": "¿Permitir la integración de Minecraft?", "admin/enable_nicknames_on_registration": "¿Permitir apodos para el registro de usuarios?", @@ -212,7 +212,7 @@ "admin/find_modules": "Buscar módulos", "admin/find_templates": "Buscar plantillas", "admin/force_https": "¿Forzar https?", - "admin/force_https_help": "Si se activa, todas las peticiones a su sitio web serán redirigidas a https. Debe tener un certificado SSL válido activo para que esto funcione correctamente.", + "admin/force_https_help": "Si se activa, todas las peticiones a su sitio web serán redirigidas a https. Debe tener un certificado SSL válido activo para que esto funcione.", "admin/force_premium_accounts": "¿Forzar las cuentas premium de Minecraft?", "admin/force_tfa": "¿Forzar la autenticación de dos factores para los miembros del grupo?", "admin/force_tfa_alert": "Su grupo requiere que tenga activada la autenticación de dos factores.", @@ -337,7 +337,7 @@ "admin/navbar_icon": "Icono de la barra de navegación", "admin/navbar_icon_instructions": "Aquí también puedes añadir un icono a cada elemento de la barra de navegación, por ejemplo con {{faLink}}, {{semLink}}.", "admin/navbar_order": "Orden en la barra de navegación", - "admin/navbar_order_instructions": "Puede dar a cada elemento un número superior al 0 para ordenar los elementos en la barra de navegación, siendo el 1 el primer elemento y los números superiores los que vienen después.", + "admin/navbar_order_instructions": "A cada elemento se le puede asignar un número positivo, donde el número más bajo aparecerá primero en la barra de navegación y los números más altos vendrán después.", "admin/navigation": "Navegación", "admin/navigation_settings_updated_successfully": "La configuración de la navegación se ha actualizado correctamente.", "admin/negative": "Negativo", @@ -583,7 +583,7 @@ "admin/updated_user_languages": "Se han actualizado los idiomas de los usuarios.", "admin/upload_new_image": "Subir una nueva imagen", "admin/use_friendly_urls": "URLs amigables", - "admin/use_friendly_urls_help": "IMPORTANTE: Su servidor debe estar configurado para permitir el uso de archivos mod_rewrite y .htaccess para que esto funcione.", + "admin/use_friendly_urls_help": "Si se activa, se utilizarán direcciones web de aspecto más limpio. Debe permitir el uso de \"mod_rewrite\" y archivos \".htaccess\" para que esto funcione. {{docLinkStart}}Leer más »{{docLinkEnd}}", "admin/user": "Usuario", "admin/user_deleted": "Usuario eliminado con éxito.", "admin/user_id": "ID del usuario", @@ -1208,5 +1208,15 @@ "general/purple": "Morado", "general/pink": "Rosa", "general/brown": "Marrón", - "general/grey": "Gris" + "general/grey": "Gris", + "admin/page_url_contains_nameless_path": "Su página personalizada sobrescribiría una página de NamelessMC.", + "admin/debug_link_info": "Importante: ¡comparte este enlace sólo con personas de confianza!", + "admin/test_email_query": "¿No llega a su bandeja de entrada? Pruebe lo siguiente:", + "admin/test_email_suggest_1": "Espere unos minutos y revise su carpeta de \"Spam\".", + "admin/test_email_suggest_2": "Actualice los registros DNS de su sitio (compruebe SPF y DKIM).", + "admin/test_email_suggest_3": "Configurar un servidor SMTP. {{docLinkStart}}Leer más »{{docLinkEnd}}", + "admin/api_disabled": "La API está desactivada", + "installer/database_configured": "La base de datos ha sido configurada.", + "installer/upgrade_error": "Se han producido errores durante la actualización.", + "user/no_providers_admin": "Los administradores del sitio aún no han configurado ningún proveedor de OAuth." } From b5d1fc1981d34f0c224aa0b1147f6e15acbf0660 Mon Sep 17 00:00:00 2001 From: PadowYT2 Date: Fri, 3 Jun 2022 01:04:55 +0000 Subject: [PATCH 013/337] Translated using Weblate (Russian) Currently translated at 100.0% (1220 of 1220 strings) Translation: NamelessMC/Website - Core Translate-URL: https://translate.namelessmc.com/projects/namelessmc/nameless/ru/ --- custom/languages/ru_RU.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/custom/languages/ru_RU.json b/custom/languages/ru_RU.json index 514af7e8cd..a71cc49002 100644 --- a/custom/languages/ru_RU.json +++ b/custom/languages/ru_RU.json @@ -1215,5 +1215,8 @@ "admin/test_email_query": "Не получаете в ваших входящих? Попробуйте:", "admin/test_email_suggest_1": "Подождите несколько минут и проверьте вашу Спам папку.", "admin/test_email_suggest_2": "Обновите DNS рекорды вашего сайта (проверьте SPF & DKIM).", - "admin/test_email_suggest_3": "Настройте SMTP сервер. {{docLinkStart}}Прочитать больше »{{docLinkEnd}}" + "admin/test_email_suggest_3": "Настройте SMTP сервер. {{docLinkStart}}Прочитать больше »{{docLinkEnd}}", + "installer/database_configured": "Датабаза была настроена.", + "installer/upgrade_error": "Произошли ошибки при обновлении.", + "admin/debug_link_info": "Важно - только делитесь этой ссылкой с людьми которыми вы доверяете!" } From 444e6048d9f5d7a9d77c30b0a2946a77fabf9ad1 Mon Sep 17 00:00:00 2001 From: PadowYT2 Date: Fri, 3 Jun 2022 01:06:12 +0000 Subject: [PATCH 014/337] Translated using Weblate (Russian) Currently translated at 100.0% (50 of 50 strings) Translation: NamelessMC/Website - Discord Integration Translate-URL: https://translate.namelessmc.com/projects/namelessmc/website-discord-integration/ru/ --- modules/Discord Integration/language/ru_RU.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/Discord Integration/language/ru_RU.json b/modules/Discord Integration/language/ru_RU.json index e93c62224a..b637dd24f4 100644 --- a/modules/Discord Integration/language/ru_RU.json +++ b/modules/Discord Integration/language/ru_RU.json @@ -47,5 +47,6 @@ "discord_integration/unable_to_set_discord_id": "Не удалось установить Discord ID.", "discord_integration/unable_to_update_discord_bot_username": "Не удалось обновить никнейм бота в Discord.", "discord_integration/unable_to_update_discord_roles": "Не удалось обновить роли в Discord.", - "discord_integration/unable_to_update_discord_username": "Не удалось обновить никнеймы в Discord." + "discord_integration/unable_to_update_discord_username": "Не удалось обновить никнеймы в Discord.", + "discord_integration/discord_widget_error": "Произошла ошибка при Discord виджете: {{error}}." } From d55141684507c10ad63a356813698e2b52749be7 Mon Sep 17 00:00:00 2001 From: PikaMug Date: Fri, 3 Jun 2022 05:42:34 +0000 Subject: [PATCH 015/337] Translated using Weblate (English (United States)) Currently translated at 100.0% (1220 of 1220 strings) Translation: NamelessMC/Website - Core Translate-URL: https://translate.namelessmc.com/projects/namelessmc/nameless/en_US/ --- custom/languages/en_US.json | 44 ++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/custom/languages/en_US.json b/custom/languages/en_US.json index 6734d46606..efb03e7ed6 100644 --- a/custom/languages/en_US.json +++ b/custom/languages/en_US.json @@ -118,7 +118,7 @@ "admin/default_avatar": "Default Avatar", "admin/default_group": "Is the group the default group (for new users)?", "admin/default_language": "Default Language", - "admin/default_language_help": "Users will be able to choose from any installed languages.", + "admin/default_language_help": "Users will be able to choose from any installed languages. {{docLinkStart}}Read more »{{docLinkEnd}}", "admin/default_server": "Default Server", "admin/default_template_set": "Default template set to {{template}} successfully.", "admin/default_timezone": "Default Timezone", @@ -185,7 +185,7 @@ "admin/enable_authme": "Enable AuthMe integration?", "admin/enable_debug_mode": "Enable debug mode?", "admin/enable_mailer": "Enable PHPMailer?", - "admin/enable_mailer_help": "Enable this if emails aren't being sent by default. The use of PHPMailer requires you to have a service capable of sending emails, such as Gmail or an SMTP provider.", + "admin/enable_mailer_help": "If enabled, emails will be sent using PHPMailer instead of the system default. This may help with delivery, but requires you to configure an SMTP provider. {{docLinkStart}}Read more »{{docLinkEnd}}", "admin/enable_maintenance_mode": "Enable maintenance mode?", "admin/enable_minecraft_integration": "Enable Minecraft integration?", "admin/enable_nicknames_on_registration": "Enable nicknames for registering users?", @@ -215,7 +215,7 @@ "admin/find_modules": "Find Modules", "admin/find_templates": "Find Templates", "admin/force_https": "Force https?", - "admin/force_https_help": "If enabled, all requests to your website will be redirected to https. You must have a valid SSL certificate active for this to work correctly.", + "admin/force_https_help": "If enabled, all requests to your website will be redirected to https. You must have a valid SSL certificate active for this to work.", "admin/force_premium_accounts": "Force premium Minecraft accounts?", "admin/force_tfa": "Force Two Factor Authentication for group members?", "admin/force_tfa_alert": "Your group requires you to have Two Factor Authentication enabled.", @@ -342,7 +342,7 @@ "admin/navbar_icon": "Navbar Icon", "admin/navbar_icon_instructions": "You can also add an icon to each navbar item here, for example using {{faLink}}, {{semLink}}.", "admin/navbar_order": "Navbar Order", - "admin/navbar_order_instructions": "You can give each item a number above 0 to order items in the navbar, with 1 being the first item and higher numbers coming after it.", + "admin/navbar_order_instructions": "Each item can be assigned a positive number, where the lowest number will appear first in the navbar and higher numbers will come after it.", "admin/navigation": "Navigation", "admin/navigation_settings_updated_successfully": "Navigation settings updated successfully.", "admin/negative": "Negative", @@ -598,7 +598,7 @@ "admin/upgrade_php_version": "Please upgrade your PHP version to at least 7.4 - the next Nameless release will no longer support the version you are using.", "admin/upload_new_image": "Upload New Image", "admin/use_friendly_urls": "Friendly URLs", - "admin/use_friendly_urls_help": "IMPORTANT: Your server must be configured to allow the use of mod_rewrite and .htaccess files for this to work.", + "admin/use_friendly_urls_help": "If enabled, cleaner-looking web addresses will be used. You must allow the use of mod_rewrite and .htaccess files for this to work. {{docLinkStart}}Read more »{{docLinkEnd}}", "admin/user": "User", "admin/user_deleted": "User deleted successfully.", "admin/user_id": "User ID", @@ -1186,5 +1186,37 @@ "general/or": "OR", "user/nickname_maximum_20": "Your nickname must be a maximum of 20 characters.", "user/nickname_required": "A nickname is required.", - "user/nickname_minimum_3": "Your nickname must be a minimum of 3 characters." + "user/nickname_minimum_3": "Your nickname must be a minimum of 3 characters.", + "admin/debug_link_info": "Important - only share this link with people you trust!", + "installer/database_configured": "The database has been configured.", + "admin/page_url_contains_nameless_path": "Your custom page would overwrite a NamelessMC page.", + "admin/group_name": "Group Name", + "admin/home_custom_content": "Home Custom Content", + "admin/homepage_news": "News", + "admin/user_group_added_hook_info": "User Group Added", + "admin/test_email_query": "Not reaching your inbox? Try the following:", + "admin/test_email_suggest_1": "Wait a few minutes and check your Spam folder.", + "admin/test_email_suggest_2": "Update your site's DNS records (check SPF & DKIM).", + "admin/test_email_suggest_3": "Set up an SMTP server. {{docLinkStart}}Read more »{{docLinkEnd}}", + "admin/user_group_removed_hook_info": "User Group Removed", + "admin/updated": "Updated", + "general/auto_language": "Auto language", + "general/default": "Default", + "installer/upgrade_error": "There were errors encountered while upgrading.", + "general/violet": "Violet", + "general/purple": "Purple", + "admin/api_disabled": "API is disabled", + "general/teal": "Teal", + "general/blue": "Blue", + "general/pink": "Pink", + "general/orange": "Orange", + "general/yellow": "Yellow", + "general/olive": "Olive", + "general/green": "Green", + "general/brown": "Brown", + "general/grey": "Grey", + "admin/custom_content": "Custom Content", + "user/no_providers_admin": "No OAuth providers have been configured by site administrators yet.", + "general/red": "Red", + "admin/not_set": "Not set" } From d6934c1671360c49ede25ddfe9b6b27476000c46 Mon Sep 17 00:00:00 2001 From: PikaMug Date: Fri, 3 Jun 2022 06:02:00 +0000 Subject: [PATCH 016/337] Translated using Weblate (English (United States)) Currently translated at 100.0% (51 of 51 strings) Translation: NamelessMC/Website - Discord Integration Translate-URL: https://translate.namelessmc.com/projects/namelessmc/website-discord-integration/en_US/ --- modules/Discord Integration/language/en_US.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/Discord Integration/language/en_US.json b/modules/Discord Integration/language/en_US.json index 345ae86a24..3410a3de5b 100644 --- a/modules/Discord Integration/language/en_US.json +++ b/modules/Discord Integration/language/en_US.json @@ -17,8 +17,8 @@ "discord_integration/discord_guild_id": "Discord Server ID", "discord_integration/discord_id_confirm": "Please run the command \"/verify {{token}}\" in Discord to finish linking your Discord account.", "discord_integration/discord_id_help": "For information on where to find Discord IDs, please read {{linkStart}}this.{{linkEnd}}", - "discord_integration/discord_id_length": "Please ensure your Discord ID is 18 characters long.", - "discord_integration/discord_id_numeric": "Please ensure your Discord ID is numeric (Numbers only).", + "discord_integration/discord_id_length": "Please ensure your Discord Server ID is 18 characters long.", + "discord_integration/discord_id_numeric": "Please ensure your Discord Server ID is numeric (Numbers only).", "discord_integration/discord_id_set": "Discord ID set successfully", "discord_integration/discord_id_taken": "That Discord User ID has already been taken.", "discord_integration/discord_id_unlinked": "Successfully unlinked your Discord User ID.", @@ -47,5 +47,7 @@ "discord_integration/unable_to_set_discord_id": "Unable to set Discord ID.", "discord_integration/unable_to_update_discord_bot_username": "Unable to update Discord bot username.", "discord_integration/unable_to_update_discord_roles": "Unable to update Discord roles list.", - "discord_integration/unable_to_update_discord_username": "Unable to update Discord username." + "discord_integration/unable_to_update_discord_username": "Unable to update Discord username.", + "discord_integration/discord_widget_error": "An error occurred when getting Discord widget: {{error}}.", + "discord_integration/discord_id_required": "Please enter your Discord Server ID." } From ca9afc25348cc396ddf15f0b0521c4df73342b0d Mon Sep 17 00:00:00 2001 From: PikaMug Date: Fri, 3 Jun 2022 06:00:29 +0000 Subject: [PATCH 017/337] Translated using Weblate (English (United States)) Currently translated at 100.0% (195 of 195 strings) Translation: NamelessMC/Website - Forum Translate-URL: https://translate.namelessmc.com/projects/namelessmc/website-forum/en_US/ --- modules/Forum/language/en_US.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/modules/Forum/language/en_US.json b/modules/Forum/language/en_US.json index 5ec0a40880..e797dfa25b 100644 --- a/modules/Forum/language/en_US.json +++ b/modules/Forum/language/en_US.json @@ -186,5 +186,12 @@ "forum/topic_id": "Topic ID", "forum/post_id": "Post ID", "forum/pre_post_create_hook_info": "Pre post create", - "forum/user_object": "User object" + "forum/user_object": "User object", + "forum/no_news": "There are no news posts.", + "forum/topic_reply": "Topic reply", + "forum/label_type_in_use": "Label type is being used, cannot be deleted.", + "forum/new_topic_reply_text": "Topic reply created in {{forum}} by {{author}}", + "forum/topic_author_uuid": "Topic author user ID", + "forum/topic_author_username": "Topic author username", + "forum/topic_author_nickname": "Topic author nickname" } From 2bc11f4c3bfccb6cfe2a9ac75ede7a1f8e538247 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Loskot?= Date: Fri, 3 Jun 2022 13:57:21 +0000 Subject: [PATCH 018/337] Translated using Weblate (Czech) Currently translated at 100.0% (1220 of 1220 strings) Translation: NamelessMC/Website - Core Translate-URL: https://translate.namelessmc.com/projects/namelessmc/nameless/cs/ --- custom/languages/cs_CZ.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/custom/languages/cs_CZ.json b/custom/languages/cs_CZ.json index afd75394e0..5ea78c2d91 100644 --- a/custom/languages/cs_CZ.json +++ b/custom/languages/cs_CZ.json @@ -1217,5 +1217,6 @@ "admin/test_email_query": "Nedorazilo? Zkuste následující:", "admin/test_email_suggest_1": "Počkejte pár minut a zkontrolujte složku s nevyžádanou poštou.", "admin/test_email_suggest_2": "Aktualizujte záznamy DNS vašeho webu (zkontrolujte SPF a DKIM).", - "admin/test_email_suggest_3": "Nastavte server SMTP. {{docLinkStart}}Zjistit více »{{docLinkEnd}}" + "admin/test_email_suggest_3": "Nastavte server SMTP. {{docLinkStart}}Zjistit více »{{docLinkEnd}}", + "admin/debug_link_info": "Důležité - tento odkaz sdílejte pouze s lidmi, kterým důvěřujete!" } From ea791c78bf585b35cf9967b92b98621c511ce924 Mon Sep 17 00:00:00 2001 From: enno123 Date: Fri, 3 Jun 2022 13:47:35 +0000 Subject: [PATCH 019/337] Translated using Weblate (German) Currently translated at 100.0% (1220 of 1220 strings) Translation: NamelessMC/Website - Core Translate-URL: https://translate.namelessmc.com/projects/namelessmc/nameless/de/ --- custom/languages/de_DE.json | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/custom/languages/de_DE.json b/custom/languages/de_DE.json index af35ebc1d9..df8c801402 100644 --- a/custom/languages/de_DE.json +++ b/custom/languages/de_DE.json @@ -107,7 +107,7 @@ "admin/default_avatar": "Standard Avatar", "admin/default_group": "Ist diese Gruppe die Standard Gruppe (Für neue User)??", "admin/default_language": "Standardsprache", - "admin/default_language_help": "Benutzer können aus einer Liste ihre eigene Sprache auswählen.", + "admin/default_language_help": "Die Benutzer können aus allen installierten Sprachen wählen. {{docLinkStart}}Weiterlesen \"{{docLinkEnd}}", "admin/default_server": "Standardserver", "admin/default_template_set": "Die Vorlage {{template}} wurde als Standard gesetzt.", "admin/default_timezone": "Standard Zeitzone", @@ -174,7 +174,7 @@ "admin/enable_authme": "Aktiviere AuthMe Integration?", "admin/enable_debug_mode": "Aktiviere den Fehlerbenachrichtungs Modus?", "admin/enable_mailer": "Aktiviere PHPMailer?", - "admin/enable_mailer_help": "Aktiviere dies, wenn E-Mails standardmäßig nicht gesendet werden. Die Verwendung von PHPMailer erfordert, dass Du einen Dienst hast, der in der Lage ist, E-Mails an einen SMTP-Provider zu senden wie zum Beispiel Gmail oder GMX.", + "admin/enable_mailer_help": "Wenn diese Option aktiviert ist, werden E-Mails mit PHPMailer anstelle der Systemvorgabe gesendet. Dies kann bei der Zustellung helfen, erfordert aber die Konfiguration eines SMTP-Providers. {{docLinkStart}}Weiterlesen \"{{docLinkEnd}}", "admin/enable_maintenance_mode": "Wartungsmodus aktivieren?", "admin/enable_minecraft_integration": "Minecraft Integration aktivieren?", "admin/enable_nicknames_on_registration": "Nicknames für registrierte Benutzer?", @@ -202,7 +202,7 @@ "admin/find_modules": "Entdecke Module", "admin/find_templates": "Entdecke Vorlagen", "admin/force_https": "Erzwinge https?", - "admin/force_https_help": "Falls https aktiviert wird, werden alle Anfragen auf das https Protokoll umgeleitet. Bitte überprüfe ob dein SSL Zertifikat gültig und richtig eingerichtet worden ist.", + "admin/force_https_help": "Wenn diese Option aktiviert ist, werden alle Anfragen an deine Website auf https umgeleitet. Du musst ein gültiges SSL-Zertifikat aktiviert haben, damit dies funktioniert.", "admin/force_premium_accounts": "Premium-Minecraft-Konten erzwingen?", "admin/force_tfa": "Zwei-Faktor-Authentifizierung für Gruppenmitglieder erzwingen?", "admin/force_tfa_alert": "Für Deine Gruppe muss die Zwei-Faktor-Authentifizierung aktiviert sein.", @@ -324,7 +324,7 @@ "admin/navbar_icon": "Navbar Icon", "admin/navbar_icon_instructions": "Du kannst hier auch jedem Navigationsleistenelement ein Symbol hinzufügen, z. B. mithilfe von {{faLink}}, {{semLink}}.", "admin/navbar_order": "Navbar Ordnen", - "admin/navbar_order_instructions": "Du kannst jedem Artikel eine Zahl über 0 geben, um Artikel in der Navigationsleiste zu ordnen, wobei 1 der erste Artikel ist und höhere Zahlen danach.", + "admin/navbar_order_instructions": "Jedem Element kann eine positive Nummer zugewiesen werden, wobei die niedrigste Nummer zuerst in der Navigationsleiste erscheint und höhere Nummern danach folgen.", "admin/navigation": "Navigation", "admin/navigation_settings_updated_successfully": "Navigations Einstellungen wurden gespeichert.", "admin/negative": "Negativ", @@ -555,7 +555,7 @@ "admin/upgrade_php_version": "Bitte aktualisiere deine PHP-Version auf mindestens 7.4 - die nächste Nameless-Version wird die von dir verwendete Version nicht mehr unterstützen.", "admin/upload_new_image": "Neues Bild hochladen", "admin/use_friendly_urls": "Benutzerfreundliche URLs", - "admin/use_friendly_urls_help": "WICHTIG: Dein Server muss so konfiguriert sein, dass er die Verwendung von mod_rewrite und .htaccess-Dateien zulässt, damit dies funktioniert.", + "admin/use_friendly_urls_help": "Wenn diese Option aktiviert ist, werden sauberer aussehende Webadressen verwendet. Sie müssen die Verwendung von mod_rewrite und .htaccess-Dateien erlauben, damit dies funktioniert. {{docLinkStart}}Weiterlesen \"{{docLinkEnd}}", "admin/user": "Nutzer", "admin/user_deleted": "Benutzer wurde erfolgreich gelöscht.", "admin/user_management": "Benutzerverwaltung", @@ -1211,5 +1211,12 @@ "admin/group_name": "Gruppen Name", "admin/api_disabled": "API ist deaktiviert", "admin/page_url_contains_nameless_path": "Deine benutzerdefinierte Seite würde eine NamelessMC-Seite überschreiben.", - "user/no_providers_admin": "Es wurden noch keine OAuth-Anbieter von Website-Administratoren konfiguriert." + "user/no_providers_admin": "Es wurden noch keine OAuth-Anbieter von Website-Administratoren konfiguriert.", + "installer/database_configured": "Die Datenbank wurde konfiguriert.", + "installer/upgrade_error": "Während des Upgrades traten Fehler auf.", + "admin/test_email_query": "Du erreichst deinen Posteingang nicht? Versuche folgendes:", + "admin/test_email_suggest_1": "Warte ein paar Minuten und überprüfe deinen Spam-Ordner.", + "admin/test_email_suggest_2": "Aktualisiere die DNS-Einträge deiner Website (prüfe SPF und DKIM).", + "admin/test_email_suggest_3": "Einen SMTP-Server einrichten. {{docLinkStart}}Weiterlesen \"{{docLinkEnd}}", + "admin/debug_link_info": "Wichtig - teile diesen Link nur mit Personen, denen du vertraust!" } From 70daa6d6d8ef43c655af6ac9ac945d89541b9dc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Loskot?= Date: Fri, 3 Jun 2022 13:58:11 +0000 Subject: [PATCH 020/337] Translated using Weblate (Czech) Currently translated at 100.0% (51 of 51 strings) Translation: NamelessMC/Website - Discord Integration Translate-URL: https://translate.namelessmc.com/projects/namelessmc/website-discord-integration/cs/ --- modules/Discord Integration/language/cs_CZ.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/Discord Integration/language/cs_CZ.json b/modules/Discord Integration/language/cs_CZ.json index 34f83cde77..4793950d4a 100644 --- a/modules/Discord Integration/language/cs_CZ.json +++ b/modules/Discord Integration/language/cs_CZ.json @@ -14,8 +14,8 @@ "discord_integration/discord_database_error": "Databáze Nameless Link momentálně není dostupná. Zkuste to prosím znovu za chvíli.", "discord_integration/discord_guild_id": "ID Discord serveru", "discord_integration/discord_id_help": "Pro informace, kde nalézt Discord ID, si přečtěte {{linkStart}}toto.{{linkEnd}}", - "discord_integration/discord_id_length": "Ujistěte se, že vaše Discord ID je dlouhé 18 znaků.", - "discord_integration/discord_id_numeric": "Ujistěte se, že vaše Discord ID obsahuje pouze čísla.", + "discord_integration/discord_id_length": "Ujistěte se, že ID vašeho Discord serveru je dlouhé 18 znaků.", + "discord_integration/discord_id_numeric": "Ujistěte se, že ID vašeho Discord serveru obsahuje pouze čísla.", "discord_integration/discord_id_set": "ID Discordu úspěšně nastaveno", "discord_integration/discord_id_taken": "Toto Discord ID je již zabráno.", "discord_integration/discord_id_unlinked": "Úspěšně jste odpojili své uživatelské ID.", @@ -47,5 +47,7 @@ "discord_integration/discord_bot_check_logs": "Zkuste se podívat po specifičtější chybě (pokud existuje) v Panel -> Zabezpečení -> Všechny protokoly.", "discord_integration/discord_bot_error_partsuccess": "Bot nemohl upravit jednu nebo více rolí kvůli nesprávné konfiguraci hierarchie na Discordu.", "discord_integration/discord_invite_info": "Pro pozvání bota Nameless Link na váš Discord server klikněte {{inviteLinkStart}}sem{{inviteLinkEnd}}. Poté spusťte příkaz {{command}} pro propojení bota s vaším webem. Můžete také {{selfHostLinkStart}}sami hostovat bota{{selfHostLinkEnd}}.", - "discord_integration/discord_widget_disabled": "U zadaného Discord serveru je zakázán widget. Běžte prosím do záložky 'Widget' v nastavení vašeho Discord serveru a ujistěte se, že je možnost povolena a že je ID správné." + "discord_integration/discord_widget_disabled": "U zadaného Discord serveru je zakázán widget. Běžte prosím do záložky 'Widget' v nastavení vašeho Discord serveru a ujistěte se, že je možnost povolena a že je ID správné.", + "discord_integration/discord_widget_error": "Při načítání Discord widgetu se vyskytla chyba: {{error}}.", + "discord_integration/discord_id_required": "Zadejte ID vašeho Discord serveru." } From 556e13df6c54864290bcb3e0f5d47f7769813cb3 Mon Sep 17 00:00:00 2001 From: enno123 Date: Fri, 3 Jun 2022 13:46:16 +0000 Subject: [PATCH 021/337] Translated using Weblate (German) Currently translated at 100.0% (51 of 51 strings) Translation: NamelessMC/Website - Discord Integration Translate-URL: https://translate.namelessmc.com/projects/namelessmc/website-discord-integration/de/ --- modules/Discord Integration/language/de_DE.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/Discord Integration/language/de_DE.json b/modules/Discord Integration/language/de_DE.json index e815327b4c..7c4af23e1b 100644 --- a/modules/Discord Integration/language/de_DE.json +++ b/modules/Discord Integration/language/de_DE.json @@ -12,8 +12,8 @@ "discord_integration/discord_communication_error": "Bei der Kommunikation mit dem Discord Bot ist ein Fehler aufgetreten. Bitte stellen Sie sicher, dass der Bot ausgeführt wird und Ihre Bot-URL korrekt ist.", "discord_integration/discord_database_error": "Die Nameless Link-Datenbank ist derzeit nicht verfügbar. Bitte versuchen Sie es später noch einmal.", "discord_integration/discord_id_help": "Für Informationen darüber, wo man Discord-IDs findet, lies bitte {{linkStart}}hier.{{linkEnd}}", - "discord_integration/discord_id_length": "Bitte stellen Sie sicher, dass Ihre Discord ID 18 Zeichen lang ist.", - "discord_integration/discord_id_numeric": "Bitte stellen Sie sicher, dass Ihre Discord ID numerisch ist (nur Zahlen)..", + "discord_integration/discord_id_length": "Bitte stelle sicher, dass deine Discord Server ID 18 Zeichen lang ist.", + "discord_integration/discord_id_numeric": "Bitte stelle sicher, dass deine Discord Server ID numerisch ist (nur Zahlen)..", "discord_integration/discord_id_set": "Discord ID erfolgreich eingestellt", "discord_integration/discord_id_taken": "Diese Discord ID wurde bereits vergeben.", "discord_integration/discord_id_unlinked": "Die Verknüpfung Ihrer Discord-Benutzer-ID wurde erfolgreich aufgehoben.", @@ -47,5 +47,7 @@ "discord_integration/discord_guild_id": "Discord Server ID", "discord_integration/discord_id_confirm": "Bitte führe den Befehl \"/verify {{token}}\" in Discord aus, um die Verknüpfung deines Discord-Kontos abzuschließen.", "discord_integration/discord_invite_info": "Um den Nameless Link-Bot auf deinen Discord-Server einzuladen, klicke auf {{inviteLinkStart}}hier{{inviteLinkEnd}}. Führe dann den Befehl {{command}} aus, um den Bot mit deiner Website zu verbinden. Alternativ kannst du {{selfHostLinkStart}} den Bot auch selbst hosten{{selfHostLinkEnd}}.", - "discord_integration/discord_widget_theme": "Discord Widget Theme" + "discord_integration/discord_widget_theme": "Discord Widget Theme", + "discord_integration/discord_widget_error": "Beim Abrufen des Discord-Widgets ist ein Fehler aufgetreten: {{error}}.", + "discord_integration/discord_id_required": "Bitte gib deine Discord Server ID ein." } From f0ef495f7d1fb30a03e89f7a6b15e2b599f0d74e Mon Sep 17 00:00:00 2001 From: Supercrafter100 Date: Fri, 3 Jun 2022 15:42:36 +0000 Subject: [PATCH 022/337] Translated using Weblate (Dutch) Currently translated at 100.0% (51 of 51 strings) Translation: NamelessMC/Website - Discord Integration Translate-URL: https://translate.namelessmc.com/projects/namelessmc/website-discord-integration/nl/ --- modules/Discord Integration/language/nl_NL.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/Discord Integration/language/nl_NL.json b/modules/Discord Integration/language/nl_NL.json index a9199125ae..77460db8bf 100644 --- a/modules/Discord Integration/language/nl_NL.json +++ b/modules/Discord Integration/language/nl_NL.json @@ -10,8 +10,8 @@ "discord_integration/discord_communication_error": "Er was een fout in de communicatie met de Discord Bot. Zorg ervoor dat de bot werkt en dat uw Bot-URL correct is.", "discord_integration/discord_database_error": "De Nameless Link database is op dit moment offline. Probeer het later nog eens.", "discord_integration/discord_id_help": "Voor informatie over waar je de Discord IDs kunt vinden, lees alsjeblieft {{linkStart}}dit.{{linkEnd}}", - "discord_integration/discord_id_length": "Zorg ervoor dat uw Discord ID 18 karakters lang is.", - "discord_integration/discord_id_numeric": "Zorg ervoor dat uw Discord ID numeriek is (alleen cijfers).", + "discord_integration/discord_id_length": "Zorg ervoor dat uw Discord server ID 18 karakters lang is.", + "discord_integration/discord_id_numeric": "Zorg ervoor dat uw Discord server ID numeriek is (alleen cijfers).", "discord_integration/discord_id_set": "Discord ID met succes ingesteld", "discord_integration/discord_id_taken": "Die Discord Gebruikers-ID is al ingenomen.", "discord_integration/discord_id_unlinked": "Succesvol ontkoppeld van uw Discord Gebruikers-ID.", @@ -47,5 +47,7 @@ "discord_integration/unable_to_set_discord_bot_url": "Niet mogelijk om de Discord bot URL in te stellen", "discord_integration/unable_to_update_discord_roles": "Niet mogelijk om de Discord rollen lijst up te daten.", "discord_integration/unable_to_update_discord_username": "Niet in staat om de Discord gebruikersnaam aan te passen.", - "discord_integration/no_pending_verification_for_token": "Er zijn geen verificaties in afwachting onder de ingegeven token." + "discord_integration/no_pending_verification_for_token": "Er zijn geen verificaties in afwachting onder de ingegeven token.", + "discord_integration/discord_widget_error": "Er is een fout opgetreden tijdens het ophalen van de Discord widget: {{error}}.", + "discord_integration/discord_id_required": "Vul alsjeblieft je Discord server ID in." } From 4b3e3e63ca089b7d0ace1c70b3349495c5b65290 Mon Sep 17 00:00:00 2001 From: PadowYT2 Date: Fri, 3 Jun 2022 15:42:24 +0000 Subject: [PATCH 023/337] Translated using Weblate (Russian) Currently translated at 100.0% (51 of 51 strings) Translation: NamelessMC/Website - Discord Integration Translate-URL: https://translate.namelessmc.com/projects/namelessmc/website-discord-integration/ru/ --- modules/Discord Integration/language/ru_RU.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/Discord Integration/language/ru_RU.json b/modules/Discord Integration/language/ru_RU.json index b637dd24f4..91e346de2b 100644 --- a/modules/Discord Integration/language/ru_RU.json +++ b/modules/Discord Integration/language/ru_RU.json @@ -14,11 +14,11 @@ "discord_integration/discord_bot_setup": "Бот настроен?", "discord_integration/discord_communication_error": "Произошла ошибка во время связи с Discord. Убедитесь что бот активен и URL страница бота корректна.", "discord_integration/discord_database_error": "База бота Nameless Link не работает в данный момент. Попробуйте в другой раз.", - "discord_integration/discord_guild_id": "ID сервера в Discord", + "discord_integration/discord_guild_id": "Discord Сервер ID", "discord_integration/discord_id_confirm": "Введите команду \"/verify {{token}}\" в Discord для завершения привязки.", "discord_integration/discord_id_help": "Чтобы найти ваш ID сервера в Discord, прочитайте это {{linkStart}}руководство{{linkEnd}}", - "discord_integration/discord_id_length": "Убедитесь что ваш ID длинее 18 символов.", - "discord_integration/discord_id_numeric": "Убедитесь что ваш ID состоит из цифр.", + "discord_integration/discord_id_length": "Убедитесь что ваш Discord Сервер ID длинее 18 символов.", + "discord_integration/discord_id_numeric": "Убедитесь что ваш Discord Сервер ID состоит из цифр.", "discord_integration/discord_id_set": "Discord ID установлен", "discord_integration/discord_id_taken": "Этот User ID в Discord уже занят.", "discord_integration/discord_id_unlinked": "Вы отвязали свой профиль в Discord.", @@ -48,5 +48,6 @@ "discord_integration/unable_to_update_discord_bot_username": "Не удалось обновить никнейм бота в Discord.", "discord_integration/unable_to_update_discord_roles": "Не удалось обновить роли в Discord.", "discord_integration/unable_to_update_discord_username": "Не удалось обновить никнеймы в Discord.", - "discord_integration/discord_widget_error": "Произошла ошибка при Discord виджете: {{error}}." + "discord_integration/discord_widget_error": "Произошла ошибка при Discord виджете: {{error}}.", + "discord_integration/discord_id_required": "Введите ваш Дискорд Сервер ID." } From ae61d1055321a293d9c82e93a0b4f01f426ce93c Mon Sep 17 00:00:00 2001 From: namelessmc-bot <76107159+namelessmc-bot@users.noreply.github.com> Date: Sat, 4 Jun 2022 16:53:14 +0200 Subject: [PATCH 024/337] Translations update (#2815) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Supercrafter100 Co-authored-by: Marcos Co-authored-by: PadowYT2 Co-authored-by: PikaMug Co-authored-by: Jonáš Loskot Co-authored-by: enno123 --- custom/languages/cs_CZ.json | 3 +- custom/languages/de_DE.json | 19 +++++--- custom/languages/en_US.json | 44 ++++++++++++++++--- custom/languages/es_ES.json | 22 +++++++--- custom/languages/nl_NL.json | 24 +++++++--- custom/languages/ru_RU.json | 5 ++- .../Discord Integration/language/cs_CZ.json | 8 ++-- .../Discord Integration/language/de_DE.json | 8 ++-- .../Discord Integration/language/en_US.json | 8 ++-- .../Discord Integration/language/es_ES.json | 3 +- .../Discord Integration/language/nl_NL.json | 8 ++-- .../Discord Integration/language/ru_RU.json | 10 +++-- modules/Forum/language/en_US.json | 9 +++- modules/Forum/language/nl_NL.json | 38 +++++++++++++++- 14 files changed, 163 insertions(+), 46 deletions(-) diff --git a/custom/languages/cs_CZ.json b/custom/languages/cs_CZ.json index afd75394e0..5ea78c2d91 100644 --- a/custom/languages/cs_CZ.json +++ b/custom/languages/cs_CZ.json @@ -1217,5 +1217,6 @@ "admin/test_email_query": "Nedorazilo? Zkuste následující:", "admin/test_email_suggest_1": "Počkejte pár minut a zkontrolujte složku s nevyžádanou poštou.", "admin/test_email_suggest_2": "Aktualizujte záznamy DNS vašeho webu (zkontrolujte SPF a DKIM).", - "admin/test_email_suggest_3": "Nastavte server SMTP. {{docLinkStart}}Zjistit více »{{docLinkEnd}}" + "admin/test_email_suggest_3": "Nastavte server SMTP. {{docLinkStart}}Zjistit více »{{docLinkEnd}}", + "admin/debug_link_info": "Důležité - tento odkaz sdílejte pouze s lidmi, kterým důvěřujete!" } diff --git a/custom/languages/de_DE.json b/custom/languages/de_DE.json index af35ebc1d9..df8c801402 100644 --- a/custom/languages/de_DE.json +++ b/custom/languages/de_DE.json @@ -107,7 +107,7 @@ "admin/default_avatar": "Standard Avatar", "admin/default_group": "Ist diese Gruppe die Standard Gruppe (Für neue User)??", "admin/default_language": "Standardsprache", - "admin/default_language_help": "Benutzer können aus einer Liste ihre eigene Sprache auswählen.", + "admin/default_language_help": "Die Benutzer können aus allen installierten Sprachen wählen. {{docLinkStart}}Weiterlesen \"{{docLinkEnd}}", "admin/default_server": "Standardserver", "admin/default_template_set": "Die Vorlage {{template}} wurde als Standard gesetzt.", "admin/default_timezone": "Standard Zeitzone", @@ -174,7 +174,7 @@ "admin/enable_authme": "Aktiviere AuthMe Integration?", "admin/enable_debug_mode": "Aktiviere den Fehlerbenachrichtungs Modus?", "admin/enable_mailer": "Aktiviere PHPMailer?", - "admin/enable_mailer_help": "Aktiviere dies, wenn E-Mails standardmäßig nicht gesendet werden. Die Verwendung von PHPMailer erfordert, dass Du einen Dienst hast, der in der Lage ist, E-Mails an einen SMTP-Provider zu senden wie zum Beispiel Gmail oder GMX.", + "admin/enable_mailer_help": "Wenn diese Option aktiviert ist, werden E-Mails mit PHPMailer anstelle der Systemvorgabe gesendet. Dies kann bei der Zustellung helfen, erfordert aber die Konfiguration eines SMTP-Providers. {{docLinkStart}}Weiterlesen \"{{docLinkEnd}}", "admin/enable_maintenance_mode": "Wartungsmodus aktivieren?", "admin/enable_minecraft_integration": "Minecraft Integration aktivieren?", "admin/enable_nicknames_on_registration": "Nicknames für registrierte Benutzer?", @@ -202,7 +202,7 @@ "admin/find_modules": "Entdecke Module", "admin/find_templates": "Entdecke Vorlagen", "admin/force_https": "Erzwinge https?", - "admin/force_https_help": "Falls https aktiviert wird, werden alle Anfragen auf das https Protokoll umgeleitet. Bitte überprüfe ob dein SSL Zertifikat gültig und richtig eingerichtet worden ist.", + "admin/force_https_help": "Wenn diese Option aktiviert ist, werden alle Anfragen an deine Website auf https umgeleitet. Du musst ein gültiges SSL-Zertifikat aktiviert haben, damit dies funktioniert.", "admin/force_premium_accounts": "Premium-Minecraft-Konten erzwingen?", "admin/force_tfa": "Zwei-Faktor-Authentifizierung für Gruppenmitglieder erzwingen?", "admin/force_tfa_alert": "Für Deine Gruppe muss die Zwei-Faktor-Authentifizierung aktiviert sein.", @@ -324,7 +324,7 @@ "admin/navbar_icon": "Navbar Icon", "admin/navbar_icon_instructions": "Du kannst hier auch jedem Navigationsleistenelement ein Symbol hinzufügen, z. B. mithilfe von {{faLink}}, {{semLink}}.", "admin/navbar_order": "Navbar Ordnen", - "admin/navbar_order_instructions": "Du kannst jedem Artikel eine Zahl über 0 geben, um Artikel in der Navigationsleiste zu ordnen, wobei 1 der erste Artikel ist und höhere Zahlen danach.", + "admin/navbar_order_instructions": "Jedem Element kann eine positive Nummer zugewiesen werden, wobei die niedrigste Nummer zuerst in der Navigationsleiste erscheint und höhere Nummern danach folgen.", "admin/navigation": "Navigation", "admin/navigation_settings_updated_successfully": "Navigations Einstellungen wurden gespeichert.", "admin/negative": "Negativ", @@ -555,7 +555,7 @@ "admin/upgrade_php_version": "Bitte aktualisiere deine PHP-Version auf mindestens 7.4 - die nächste Nameless-Version wird die von dir verwendete Version nicht mehr unterstützen.", "admin/upload_new_image": "Neues Bild hochladen", "admin/use_friendly_urls": "Benutzerfreundliche URLs", - "admin/use_friendly_urls_help": "WICHTIG: Dein Server muss so konfiguriert sein, dass er die Verwendung von mod_rewrite und .htaccess-Dateien zulässt, damit dies funktioniert.", + "admin/use_friendly_urls_help": "Wenn diese Option aktiviert ist, werden sauberer aussehende Webadressen verwendet. Sie müssen die Verwendung von mod_rewrite und .htaccess-Dateien erlauben, damit dies funktioniert. {{docLinkStart}}Weiterlesen \"{{docLinkEnd}}", "admin/user": "Nutzer", "admin/user_deleted": "Benutzer wurde erfolgreich gelöscht.", "admin/user_management": "Benutzerverwaltung", @@ -1211,5 +1211,12 @@ "admin/group_name": "Gruppen Name", "admin/api_disabled": "API ist deaktiviert", "admin/page_url_contains_nameless_path": "Deine benutzerdefinierte Seite würde eine NamelessMC-Seite überschreiben.", - "user/no_providers_admin": "Es wurden noch keine OAuth-Anbieter von Website-Administratoren konfiguriert." + "user/no_providers_admin": "Es wurden noch keine OAuth-Anbieter von Website-Administratoren konfiguriert.", + "installer/database_configured": "Die Datenbank wurde konfiguriert.", + "installer/upgrade_error": "Während des Upgrades traten Fehler auf.", + "admin/test_email_query": "Du erreichst deinen Posteingang nicht? Versuche folgendes:", + "admin/test_email_suggest_1": "Warte ein paar Minuten und überprüfe deinen Spam-Ordner.", + "admin/test_email_suggest_2": "Aktualisiere die DNS-Einträge deiner Website (prüfe SPF und DKIM).", + "admin/test_email_suggest_3": "Einen SMTP-Server einrichten. {{docLinkStart}}Weiterlesen \"{{docLinkEnd}}", + "admin/debug_link_info": "Wichtig - teile diesen Link nur mit Personen, denen du vertraust!" } diff --git a/custom/languages/en_US.json b/custom/languages/en_US.json index 6734d46606..efb03e7ed6 100644 --- a/custom/languages/en_US.json +++ b/custom/languages/en_US.json @@ -118,7 +118,7 @@ "admin/default_avatar": "Default Avatar", "admin/default_group": "Is the group the default group (for new users)?", "admin/default_language": "Default Language", - "admin/default_language_help": "Users will be able to choose from any installed languages.", + "admin/default_language_help": "Users will be able to choose from any installed languages. {{docLinkStart}}Read more »{{docLinkEnd}}", "admin/default_server": "Default Server", "admin/default_template_set": "Default template set to {{template}} successfully.", "admin/default_timezone": "Default Timezone", @@ -185,7 +185,7 @@ "admin/enable_authme": "Enable AuthMe integration?", "admin/enable_debug_mode": "Enable debug mode?", "admin/enable_mailer": "Enable PHPMailer?", - "admin/enable_mailer_help": "Enable this if emails aren't being sent by default. The use of PHPMailer requires you to have a service capable of sending emails, such as Gmail or an SMTP provider.", + "admin/enable_mailer_help": "If enabled, emails will be sent using PHPMailer instead of the system default. This may help with delivery, but requires you to configure an SMTP provider. {{docLinkStart}}Read more »{{docLinkEnd}}", "admin/enable_maintenance_mode": "Enable maintenance mode?", "admin/enable_minecraft_integration": "Enable Minecraft integration?", "admin/enable_nicknames_on_registration": "Enable nicknames for registering users?", @@ -215,7 +215,7 @@ "admin/find_modules": "Find Modules", "admin/find_templates": "Find Templates", "admin/force_https": "Force https?", - "admin/force_https_help": "If enabled, all requests to your website will be redirected to https. You must have a valid SSL certificate active for this to work correctly.", + "admin/force_https_help": "If enabled, all requests to your website will be redirected to https. You must have a valid SSL certificate active for this to work.", "admin/force_premium_accounts": "Force premium Minecraft accounts?", "admin/force_tfa": "Force Two Factor Authentication for group members?", "admin/force_tfa_alert": "Your group requires you to have Two Factor Authentication enabled.", @@ -342,7 +342,7 @@ "admin/navbar_icon": "Navbar Icon", "admin/navbar_icon_instructions": "You can also add an icon to each navbar item here, for example using {{faLink}}, {{semLink}}.", "admin/navbar_order": "Navbar Order", - "admin/navbar_order_instructions": "You can give each item a number above 0 to order items in the navbar, with 1 being the first item and higher numbers coming after it.", + "admin/navbar_order_instructions": "Each item can be assigned a positive number, where the lowest number will appear first in the navbar and higher numbers will come after it.", "admin/navigation": "Navigation", "admin/navigation_settings_updated_successfully": "Navigation settings updated successfully.", "admin/negative": "Negative", @@ -598,7 +598,7 @@ "admin/upgrade_php_version": "Please upgrade your PHP version to at least 7.4 - the next Nameless release will no longer support the version you are using.", "admin/upload_new_image": "Upload New Image", "admin/use_friendly_urls": "Friendly URLs", - "admin/use_friendly_urls_help": "IMPORTANT: Your server must be configured to allow the use of mod_rewrite and .htaccess files for this to work.", + "admin/use_friendly_urls_help": "If enabled, cleaner-looking web addresses will be used. You must allow the use of mod_rewrite and .htaccess files for this to work. {{docLinkStart}}Read more »{{docLinkEnd}}", "admin/user": "User", "admin/user_deleted": "User deleted successfully.", "admin/user_id": "User ID", @@ -1186,5 +1186,37 @@ "general/or": "OR", "user/nickname_maximum_20": "Your nickname must be a maximum of 20 characters.", "user/nickname_required": "A nickname is required.", - "user/nickname_minimum_3": "Your nickname must be a minimum of 3 characters." + "user/nickname_minimum_3": "Your nickname must be a minimum of 3 characters.", + "admin/debug_link_info": "Important - only share this link with people you trust!", + "installer/database_configured": "The database has been configured.", + "admin/page_url_contains_nameless_path": "Your custom page would overwrite a NamelessMC page.", + "admin/group_name": "Group Name", + "admin/home_custom_content": "Home Custom Content", + "admin/homepage_news": "News", + "admin/user_group_added_hook_info": "User Group Added", + "admin/test_email_query": "Not reaching your inbox? Try the following:", + "admin/test_email_suggest_1": "Wait a few minutes and check your Spam folder.", + "admin/test_email_suggest_2": "Update your site's DNS records (check SPF & DKIM).", + "admin/test_email_suggest_3": "Set up an SMTP server. {{docLinkStart}}Read more »{{docLinkEnd}}", + "admin/user_group_removed_hook_info": "User Group Removed", + "admin/updated": "Updated", + "general/auto_language": "Auto language", + "general/default": "Default", + "installer/upgrade_error": "There were errors encountered while upgrading.", + "general/violet": "Violet", + "general/purple": "Purple", + "admin/api_disabled": "API is disabled", + "general/teal": "Teal", + "general/blue": "Blue", + "general/pink": "Pink", + "general/orange": "Orange", + "general/yellow": "Yellow", + "general/olive": "Olive", + "general/green": "Green", + "general/brown": "Brown", + "general/grey": "Grey", + "admin/custom_content": "Custom Content", + "user/no_providers_admin": "No OAuth providers have been configured by site administrators yet.", + "general/red": "Red", + "admin/not_set": "Not set" } diff --git a/custom/languages/es_ES.json b/custom/languages/es_ES.json index 7df73dcf27..bb1aec710b 100644 --- a/custom/languages/es_ES.json +++ b/custom/languages/es_ES.json @@ -115,7 +115,7 @@ "admin/default_avatar": "Avatar por defecto", "admin/default_group": "¿Es el grupo por defecto (para los nuevos usuarios)?", "admin/default_language": "Idioma por defecto", - "admin/default_language_help": "Los usuarios podrán elegir entre los idiomas instalados.", + "admin/default_language_help": "Los usuarios podrán elegir entre los idiomas instalados. {{docLinkStart}}Leer más »{{docLinkEnd}}", "admin/default_server": "Servidor por defecto", "admin/default_template_set": "Plantilla por defecto establecida en {{template}} con éxito.", "admin/default_timezone": "Zona horaria por defecto", @@ -182,7 +182,7 @@ "admin/enable_authme": "¿Activar la integración de AuthMe?", "admin/enable_debug_mode": "¿Activar el modo de depuración?", "admin/enable_mailer": "¿Activar PHPMailer?", - "admin/enable_mailer_help": "Habilite esto si los correos electrónicos no están siendo enviados por defecto. El uso de PHPMailer requiere tener un servicio capaz de enviar correos electrónicos, como Gmail o un proveedor SMTP.", + "admin/enable_mailer_help": "Si se activa, los correos electrónicos se enviarán utilizando PHPMailer en lugar del sistema por defecto. Esto puede ayudar a la entrega, pero requiere que se configure un proveedor SMTP. {{docLinkStart}}Leer más »{{docLinkEnd}}", "admin/enable_maintenance_mode": "¿Activar el modo de mantenimiento?", "admin/enable_minecraft_integration": "¿Permitir la integración de Minecraft?", "admin/enable_nicknames_on_registration": "¿Permitir apodos para el registro de usuarios?", @@ -212,7 +212,7 @@ "admin/find_modules": "Buscar módulos", "admin/find_templates": "Buscar plantillas", "admin/force_https": "¿Forzar https?", - "admin/force_https_help": "Si se activa, todas las peticiones a su sitio web serán redirigidas a https. Debe tener un certificado SSL válido activo para que esto funcione correctamente.", + "admin/force_https_help": "Si se activa, todas las peticiones a su sitio web serán redirigidas a https. Debe tener un certificado SSL válido activo para que esto funcione.", "admin/force_premium_accounts": "¿Forzar las cuentas premium de Minecraft?", "admin/force_tfa": "¿Forzar la autenticación de dos factores para los miembros del grupo?", "admin/force_tfa_alert": "Su grupo requiere que tenga activada la autenticación de dos factores.", @@ -337,7 +337,7 @@ "admin/navbar_icon": "Icono de la barra de navegación", "admin/navbar_icon_instructions": "Aquí también puedes añadir un icono a cada elemento de la barra de navegación, por ejemplo con {{faLink}}, {{semLink}}.", "admin/navbar_order": "Orden en la barra de navegación", - "admin/navbar_order_instructions": "Puede dar a cada elemento un número superior al 0 para ordenar los elementos en la barra de navegación, siendo el 1 el primer elemento y los números superiores los que vienen después.", + "admin/navbar_order_instructions": "A cada elemento se le puede asignar un número positivo, donde el número más bajo aparecerá primero en la barra de navegación y los números más altos vendrán después.", "admin/navigation": "Navegación", "admin/navigation_settings_updated_successfully": "La configuración de la navegación se ha actualizado correctamente.", "admin/negative": "Negativo", @@ -583,7 +583,7 @@ "admin/updated_user_languages": "Se han actualizado los idiomas de los usuarios.", "admin/upload_new_image": "Subir una nueva imagen", "admin/use_friendly_urls": "URLs amigables", - "admin/use_friendly_urls_help": "IMPORTANTE: Su servidor debe estar configurado para permitir el uso de archivos mod_rewrite y .htaccess para que esto funcione.", + "admin/use_friendly_urls_help": "Si se activa, se utilizarán direcciones web de aspecto más limpio. Debe permitir el uso de \"mod_rewrite\" y archivos \".htaccess\" para que esto funcione. {{docLinkStart}}Leer más »{{docLinkEnd}}", "admin/user": "Usuario", "admin/user_deleted": "Usuario eliminado con éxito.", "admin/user_id": "ID del usuario", @@ -1208,5 +1208,15 @@ "general/purple": "Morado", "general/pink": "Rosa", "general/brown": "Marrón", - "general/grey": "Gris" + "general/grey": "Gris", + "admin/page_url_contains_nameless_path": "Su página personalizada sobrescribiría una página de NamelessMC.", + "admin/debug_link_info": "Importante: ¡comparte este enlace sólo con personas de confianza!", + "admin/test_email_query": "¿No llega a su bandeja de entrada? Pruebe lo siguiente:", + "admin/test_email_suggest_1": "Espere unos minutos y revise su carpeta de \"Spam\".", + "admin/test_email_suggest_2": "Actualice los registros DNS de su sitio (compruebe SPF y DKIM).", + "admin/test_email_suggest_3": "Configurar un servidor SMTP. {{docLinkStart}}Leer más »{{docLinkEnd}}", + "admin/api_disabled": "La API está desactivada", + "installer/database_configured": "La base de datos ha sido configurada.", + "installer/upgrade_error": "Se han producido errores durante la actualización.", + "user/no_providers_admin": "Los administradores del sitio aún no han configurado ningún proveedor de OAuth." } diff --git a/custom/languages/nl_NL.json b/custom/languages/nl_NL.json index d9ff6a726e..c3a8c2d1b4 100644 --- a/custom/languages/nl_NL.json +++ b/custom/languages/nl_NL.json @@ -111,7 +111,7 @@ "admin/default_avatar": "Standaard avatar", "admin/default_group": "Is de standaardgroep (voor nieuwe gebruikers)?", "admin/default_language": "Standaard taal", - "admin/default_language_help": "Gebruikers kunnen kiezen uit alle geinstalleerde talen.", + "admin/default_language_help": "Gebruikers kunnen kiezen uit alle geinstalleerde talen. {{docLinkStart}}Lees meer »{{docLinkEnd}}", "admin/default_server": "Standaard server", "admin/default_template_set": "Standaard sjabloon verzet naar {{template}} succesvol.", "admin/default_timezone": "Standaard tijdzone", @@ -176,7 +176,7 @@ "admin/enable_authme": "AuthMe integratie aanzetten?", "admin/enable_debug_mode": "Wil je debug modus inschakelen?", "admin/enable_mailer": "PHPMailer inschakelen?", - "admin/enable_mailer_help": "Zet dit aan als de emails standaard niet worden verzonden. Als je gebruik wilt maken van PHPMailer heb je een email dienst nodig waarmee je emails kan verzenden, zoals Gmail of een SMTP provider (Outlook/Hotmail).", + "admin/enable_mailer_help": "Als dit aanstaat, worden e-mails verzonden met PHPMailer in plaats van de standaard van het system. Dit zou kunnen helpen met het verzenden van e-mails maar vereist wel dat je een SMTP aanbieder configureert. {{docLinkStart}}Lees meer »{{docLinkEnd}}", "admin/enable_maintenance_mode": "Wil je onderhoud modus inschakelen?", "admin/enable_minecraft_integration": "Minecraft integratie inschakelen?", "admin/enable_nicknames_on_registration": "Bijnamen inschakelen bij het registreren van gebruikers?", @@ -251,7 +251,7 @@ "admin/hook_edited": "Webhook succesvol aangepast", "admin/hook_events": "Gebeurtenissen om deze webhook te activeren", "admin/hook_name": "Webhook Naam", - "admin/hook_select_info": "Alleen Webhooks met 'Nieuw onderwerp' als evenement worden getoond.", + "admin/hook_select_info": "Alleen Webhooks met 'Nieuw onderwerp' of 'Onderwerp reactie' als evenementen worden getoond.", "admin/hook_type": "Webhook-type", "admin/hook_url": "Webhook-URL", "admin/hooks": "Webhooks", @@ -329,7 +329,7 @@ "admin/navbar_icon": "Navbar Icoon", "admin/navbar_icon_instructions": "U kunt hier ook een pictogram aan elk item op de navigatiebalk toevoegen, bijvoorbeeld met behulp van {{faLink}}, {{semLink}}.", "admin/navbar_order": "Navbar ordening", - "admin/navbar_order_instructions": "Je kan elk item een nummer boven de 0 geven om items te ordenen in de navbar, met 1 de eerste en hogere nummers erna.", + "admin/navbar_order_instructions": "Je kan elk item een nummer boven de 0 geven om items te ordenen in de navbar, waar het laagste nummer eerst in de navbar zal komen en hogere nummers erna.", "admin/navigation": "Navigatie", "admin/navigation_settings_updated_successfully": "Navigatie-instellingen succesvol bijgewerkt.", "admin/negative": "Negatief", @@ -571,7 +571,7 @@ "admin/upgrade_php_version": "Upgrade alstublieft uw PHP versie naar tenminste 7.4 - de volgende Nameless release zal de versie die u gebruikt niet langer ondersteunen.", "admin/upload_new_image": "Upload nieuwe afbeelding", "admin/use_friendly_urls": "Vriendelijke URLs", - "admin/use_friendly_urls_help": "BELANGRIJK: Je webserver/webhosting moet geconfigureerd zijn om gebruik te maken van mod_rewrite en .htaccess vooraleer dit werkt.", + "admin/use_friendly_urls_help": "Als dit aanstaat, worden schoner lijkende web adressen gebruikt. Je moet het gebruik van mod_rewrite en .htaccess bestanden toelaten om dit te laten werken. {{docLinkStart}}Lees meer »{{docLinkEnd}}", "admin/user": "Gebruiker", "admin/user_deleted": "Gebruiker succesvol verwijderd.", "admin/user_id": "User ID", @@ -1206,5 +1206,17 @@ "general/purple": "Paars", "general/pink": "Roze", "general/brown": "Bruin", - "general/grey": "Grijs" + "general/grey": "Grijs", + "admin/home_custom_content": "Hoofd Aanpasbare Inhoud", + "installer/database_configured": "De database is geconfigureerd.", + "admin/page_url_contains_nameless_path": "Je aangepaste pagina zou een NamelessMC pagina overschrijven.", + "admin/api_disabled": "API staat uit", + "user/no_providers_admin": "Er zijn nog geen OAuth aanbieders geconfigureerd door de site administrators.", + "admin/debug_link_info": "Belangrijk - Deel deze link alleen met mensen die je vertrouwt!", + "admin/test_email_query": "Komt het niet in je inbox? Probeer het volgende:", + "admin/test_email_suggest_1": "Wacht een paar minuten en check je spam map.", + "admin/test_email_suggest_2": "Update je site zijn DNS records (check SPF & DKIM).", + "admin/test_email_suggest_3": "Configureer een SMTP server. {{docLinkStart}}Lees meer »{{docLinkEnd}}", + "installer/upgrade_error": "Er zijn fouten ontstaan tijdens het upgraden.", + "admin/custom_content": "Aangepaste Inhoud" } diff --git a/custom/languages/ru_RU.json b/custom/languages/ru_RU.json index 514af7e8cd..a71cc49002 100644 --- a/custom/languages/ru_RU.json +++ b/custom/languages/ru_RU.json @@ -1215,5 +1215,8 @@ "admin/test_email_query": "Не получаете в ваших входящих? Попробуйте:", "admin/test_email_suggest_1": "Подождите несколько минут и проверьте вашу Спам папку.", "admin/test_email_suggest_2": "Обновите DNS рекорды вашего сайта (проверьте SPF & DKIM).", - "admin/test_email_suggest_3": "Настройте SMTP сервер. {{docLinkStart}}Прочитать больше »{{docLinkEnd}}" + "admin/test_email_suggest_3": "Настройте SMTP сервер. {{docLinkStart}}Прочитать больше »{{docLinkEnd}}", + "installer/database_configured": "Датабаза была настроена.", + "installer/upgrade_error": "Произошли ошибки при обновлении.", + "admin/debug_link_info": "Важно - только делитесь этой ссылкой с людьми которыми вы доверяете!" } diff --git a/modules/Discord Integration/language/cs_CZ.json b/modules/Discord Integration/language/cs_CZ.json index 34f83cde77..4793950d4a 100644 --- a/modules/Discord Integration/language/cs_CZ.json +++ b/modules/Discord Integration/language/cs_CZ.json @@ -14,8 +14,8 @@ "discord_integration/discord_database_error": "Databáze Nameless Link momentálně není dostupná. Zkuste to prosím znovu za chvíli.", "discord_integration/discord_guild_id": "ID Discord serveru", "discord_integration/discord_id_help": "Pro informace, kde nalézt Discord ID, si přečtěte {{linkStart}}toto.{{linkEnd}}", - "discord_integration/discord_id_length": "Ujistěte se, že vaše Discord ID je dlouhé 18 znaků.", - "discord_integration/discord_id_numeric": "Ujistěte se, že vaše Discord ID obsahuje pouze čísla.", + "discord_integration/discord_id_length": "Ujistěte se, že ID vašeho Discord serveru je dlouhé 18 znaků.", + "discord_integration/discord_id_numeric": "Ujistěte se, že ID vašeho Discord serveru obsahuje pouze čísla.", "discord_integration/discord_id_set": "ID Discordu úspěšně nastaveno", "discord_integration/discord_id_taken": "Toto Discord ID je již zabráno.", "discord_integration/discord_id_unlinked": "Úspěšně jste odpojili své uživatelské ID.", @@ -47,5 +47,7 @@ "discord_integration/discord_bot_check_logs": "Zkuste se podívat po specifičtější chybě (pokud existuje) v Panel -> Zabezpečení -> Všechny protokoly.", "discord_integration/discord_bot_error_partsuccess": "Bot nemohl upravit jednu nebo více rolí kvůli nesprávné konfiguraci hierarchie na Discordu.", "discord_integration/discord_invite_info": "Pro pozvání bota Nameless Link na váš Discord server klikněte {{inviteLinkStart}}sem{{inviteLinkEnd}}. Poté spusťte příkaz {{command}} pro propojení bota s vaším webem. Můžete také {{selfHostLinkStart}}sami hostovat bota{{selfHostLinkEnd}}.", - "discord_integration/discord_widget_disabled": "U zadaného Discord serveru je zakázán widget. Běžte prosím do záložky 'Widget' v nastavení vašeho Discord serveru a ujistěte se, že je možnost povolena a že je ID správné." + "discord_integration/discord_widget_disabled": "U zadaného Discord serveru je zakázán widget. Běžte prosím do záložky 'Widget' v nastavení vašeho Discord serveru a ujistěte se, že je možnost povolena a že je ID správné.", + "discord_integration/discord_widget_error": "Při načítání Discord widgetu se vyskytla chyba: {{error}}.", + "discord_integration/discord_id_required": "Zadejte ID vašeho Discord serveru." } diff --git a/modules/Discord Integration/language/de_DE.json b/modules/Discord Integration/language/de_DE.json index e815327b4c..7c4af23e1b 100644 --- a/modules/Discord Integration/language/de_DE.json +++ b/modules/Discord Integration/language/de_DE.json @@ -12,8 +12,8 @@ "discord_integration/discord_communication_error": "Bei der Kommunikation mit dem Discord Bot ist ein Fehler aufgetreten. Bitte stellen Sie sicher, dass der Bot ausgeführt wird und Ihre Bot-URL korrekt ist.", "discord_integration/discord_database_error": "Die Nameless Link-Datenbank ist derzeit nicht verfügbar. Bitte versuchen Sie es später noch einmal.", "discord_integration/discord_id_help": "Für Informationen darüber, wo man Discord-IDs findet, lies bitte {{linkStart}}hier.{{linkEnd}}", - "discord_integration/discord_id_length": "Bitte stellen Sie sicher, dass Ihre Discord ID 18 Zeichen lang ist.", - "discord_integration/discord_id_numeric": "Bitte stellen Sie sicher, dass Ihre Discord ID numerisch ist (nur Zahlen)..", + "discord_integration/discord_id_length": "Bitte stelle sicher, dass deine Discord Server ID 18 Zeichen lang ist.", + "discord_integration/discord_id_numeric": "Bitte stelle sicher, dass deine Discord Server ID numerisch ist (nur Zahlen)..", "discord_integration/discord_id_set": "Discord ID erfolgreich eingestellt", "discord_integration/discord_id_taken": "Diese Discord ID wurde bereits vergeben.", "discord_integration/discord_id_unlinked": "Die Verknüpfung Ihrer Discord-Benutzer-ID wurde erfolgreich aufgehoben.", @@ -47,5 +47,7 @@ "discord_integration/discord_guild_id": "Discord Server ID", "discord_integration/discord_id_confirm": "Bitte führe den Befehl \"/verify {{token}}\" in Discord aus, um die Verknüpfung deines Discord-Kontos abzuschließen.", "discord_integration/discord_invite_info": "Um den Nameless Link-Bot auf deinen Discord-Server einzuladen, klicke auf {{inviteLinkStart}}hier{{inviteLinkEnd}}. Führe dann den Befehl {{command}} aus, um den Bot mit deiner Website zu verbinden. Alternativ kannst du {{selfHostLinkStart}} den Bot auch selbst hosten{{selfHostLinkEnd}}.", - "discord_integration/discord_widget_theme": "Discord Widget Theme" + "discord_integration/discord_widget_theme": "Discord Widget Theme", + "discord_integration/discord_widget_error": "Beim Abrufen des Discord-Widgets ist ein Fehler aufgetreten: {{error}}.", + "discord_integration/discord_id_required": "Bitte gib deine Discord Server ID ein." } diff --git a/modules/Discord Integration/language/en_US.json b/modules/Discord Integration/language/en_US.json index 345ae86a24..3410a3de5b 100644 --- a/modules/Discord Integration/language/en_US.json +++ b/modules/Discord Integration/language/en_US.json @@ -17,8 +17,8 @@ "discord_integration/discord_guild_id": "Discord Server ID", "discord_integration/discord_id_confirm": "Please run the command \"/verify {{token}}\" in Discord to finish linking your Discord account.", "discord_integration/discord_id_help": "For information on where to find Discord IDs, please read {{linkStart}}this.{{linkEnd}}", - "discord_integration/discord_id_length": "Please ensure your Discord ID is 18 characters long.", - "discord_integration/discord_id_numeric": "Please ensure your Discord ID is numeric (Numbers only).", + "discord_integration/discord_id_length": "Please ensure your Discord Server ID is 18 characters long.", + "discord_integration/discord_id_numeric": "Please ensure your Discord Server ID is numeric (Numbers only).", "discord_integration/discord_id_set": "Discord ID set successfully", "discord_integration/discord_id_taken": "That Discord User ID has already been taken.", "discord_integration/discord_id_unlinked": "Successfully unlinked your Discord User ID.", @@ -47,5 +47,7 @@ "discord_integration/unable_to_set_discord_id": "Unable to set Discord ID.", "discord_integration/unable_to_update_discord_bot_username": "Unable to update Discord bot username.", "discord_integration/unable_to_update_discord_roles": "Unable to update Discord roles list.", - "discord_integration/unable_to_update_discord_username": "Unable to update Discord username." + "discord_integration/unable_to_update_discord_username": "Unable to update Discord username.", + "discord_integration/discord_widget_error": "An error occurred when getting Discord widget: {{error}}.", + "discord_integration/discord_id_required": "Please enter your Discord Server ID." } diff --git a/modules/Discord Integration/language/es_ES.json b/modules/Discord Integration/language/es_ES.json index 4ec6a3034c..f6f7575e65 100644 --- a/modules/Discord Integration/language/es_ES.json +++ b/modules/Discord Integration/language/es_ES.json @@ -47,5 +47,6 @@ "discord_integration/get_link_code": "Obtener código de enlace", "discord_integration/discord_invite_info": "Para invitar al bot Nameless Link a tu servidor de Discord, haz clic en {{inviteLinkStart}}aquí{{inviteLinkEnd}}. A continuación, ejecuta el comando {{command}} para enlazar el bot con tu sitio web. También puedes {{selfHostLinkStart}}alojar el bot tú mismo{{selfHostLinkEnd}}.", "discord_integration/discord_user_id": "ID de usuario de Discord", - "discord_integration/discord_widget_disabled": "El widget está desactivado para el servidor de Discord especificado. Ve a la pestaña \"Widget\" en la configuración de tu servidor de Discord y asegúrate de que el widget de Discord está activado y de que el ID es correcto." + "discord_integration/discord_widget_disabled": "El widget está desactivado para el servidor de Discord especificado. Ve a la pestaña \"Widget\" en la configuración de tu servidor de Discord y asegúrate de que el widget de Discord está activado y de que el ID es correcto.", + "discord_integration/discord_widget_error": "Se ha producido un error al obtener el widget de Discord: {{error}}." } diff --git a/modules/Discord Integration/language/nl_NL.json b/modules/Discord Integration/language/nl_NL.json index a9199125ae..77460db8bf 100644 --- a/modules/Discord Integration/language/nl_NL.json +++ b/modules/Discord Integration/language/nl_NL.json @@ -10,8 +10,8 @@ "discord_integration/discord_communication_error": "Er was een fout in de communicatie met de Discord Bot. Zorg ervoor dat de bot werkt en dat uw Bot-URL correct is.", "discord_integration/discord_database_error": "De Nameless Link database is op dit moment offline. Probeer het later nog eens.", "discord_integration/discord_id_help": "Voor informatie over waar je de Discord IDs kunt vinden, lees alsjeblieft {{linkStart}}dit.{{linkEnd}}", - "discord_integration/discord_id_length": "Zorg ervoor dat uw Discord ID 18 karakters lang is.", - "discord_integration/discord_id_numeric": "Zorg ervoor dat uw Discord ID numeriek is (alleen cijfers).", + "discord_integration/discord_id_length": "Zorg ervoor dat uw Discord server ID 18 karakters lang is.", + "discord_integration/discord_id_numeric": "Zorg ervoor dat uw Discord server ID numeriek is (alleen cijfers).", "discord_integration/discord_id_set": "Discord ID met succes ingesteld", "discord_integration/discord_id_taken": "Die Discord Gebruikers-ID is al ingenomen.", "discord_integration/discord_id_unlinked": "Succesvol ontkoppeld van uw Discord Gebruikers-ID.", @@ -47,5 +47,7 @@ "discord_integration/unable_to_set_discord_bot_url": "Niet mogelijk om de Discord bot URL in te stellen", "discord_integration/unable_to_update_discord_roles": "Niet mogelijk om de Discord rollen lijst up te daten.", "discord_integration/unable_to_update_discord_username": "Niet in staat om de Discord gebruikersnaam aan te passen.", - "discord_integration/no_pending_verification_for_token": "Er zijn geen verificaties in afwachting onder de ingegeven token." + "discord_integration/no_pending_verification_for_token": "Er zijn geen verificaties in afwachting onder de ingegeven token.", + "discord_integration/discord_widget_error": "Er is een fout opgetreden tijdens het ophalen van de Discord widget: {{error}}.", + "discord_integration/discord_id_required": "Vul alsjeblieft je Discord server ID in." } diff --git a/modules/Discord Integration/language/ru_RU.json b/modules/Discord Integration/language/ru_RU.json index e93c62224a..91e346de2b 100644 --- a/modules/Discord Integration/language/ru_RU.json +++ b/modules/Discord Integration/language/ru_RU.json @@ -14,11 +14,11 @@ "discord_integration/discord_bot_setup": "Бот настроен?", "discord_integration/discord_communication_error": "Произошла ошибка во время связи с Discord. Убедитесь что бот активен и URL страница бота корректна.", "discord_integration/discord_database_error": "База бота Nameless Link не работает в данный момент. Попробуйте в другой раз.", - "discord_integration/discord_guild_id": "ID сервера в Discord", + "discord_integration/discord_guild_id": "Discord Сервер ID", "discord_integration/discord_id_confirm": "Введите команду \"/verify {{token}}\" в Discord для завершения привязки.", "discord_integration/discord_id_help": "Чтобы найти ваш ID сервера в Discord, прочитайте это {{linkStart}}руководство{{linkEnd}}", - "discord_integration/discord_id_length": "Убедитесь что ваш ID длинее 18 символов.", - "discord_integration/discord_id_numeric": "Убедитесь что ваш ID состоит из цифр.", + "discord_integration/discord_id_length": "Убедитесь что ваш Discord Сервер ID длинее 18 символов.", + "discord_integration/discord_id_numeric": "Убедитесь что ваш Discord Сервер ID состоит из цифр.", "discord_integration/discord_id_set": "Discord ID установлен", "discord_integration/discord_id_taken": "Этот User ID в Discord уже занят.", "discord_integration/discord_id_unlinked": "Вы отвязали свой профиль в Discord.", @@ -47,5 +47,7 @@ "discord_integration/unable_to_set_discord_id": "Не удалось установить Discord ID.", "discord_integration/unable_to_update_discord_bot_username": "Не удалось обновить никнейм бота в Discord.", "discord_integration/unable_to_update_discord_roles": "Не удалось обновить роли в Discord.", - "discord_integration/unable_to_update_discord_username": "Не удалось обновить никнеймы в Discord." + "discord_integration/unable_to_update_discord_username": "Не удалось обновить никнеймы в Discord.", + "discord_integration/discord_widget_error": "Произошла ошибка при Discord виджете: {{error}}.", + "discord_integration/discord_id_required": "Введите ваш Дискорд Сервер ID." } diff --git a/modules/Forum/language/en_US.json b/modules/Forum/language/en_US.json index 5ec0a40880..e797dfa25b 100644 --- a/modules/Forum/language/en_US.json +++ b/modules/Forum/language/en_US.json @@ -186,5 +186,12 @@ "forum/topic_id": "Topic ID", "forum/post_id": "Post ID", "forum/pre_post_create_hook_info": "Pre post create", - "forum/user_object": "User object" + "forum/user_object": "User object", + "forum/no_news": "There are no news posts.", + "forum/topic_reply": "Topic reply", + "forum/label_type_in_use": "Label type is being used, cannot be deleted.", + "forum/new_topic_reply_text": "Topic reply created in {{forum}} by {{author}}", + "forum/topic_author_uuid": "Topic author user ID", + "forum/topic_author_username": "Topic author username", + "forum/topic_author_nickname": "Topic author nickname" } diff --git a/modules/Forum/language/nl_NL.json b/modules/Forum/language/nl_NL.json index 0d232f05e3..a5ca958685 100644 --- a/modules/Forum/language/nl_NL.json +++ b/modules/Forum/language/nl_NL.json @@ -144,7 +144,7 @@ "forum/forum_icon_maximum": "Het forum icoon mag maximaal 256 karakters lang zijn.", "forum/forum_search": "Forum Zoeken", "forum/forum_updated_successfully": "Forum succesvol geüpdatet.", - "forum/include_in_hook": "Betrek nieuwe berichten van dit forum in webhooks?", + "forum/include_in_hook": "Betrek evenementen van dit forum in webhooks?", "forum/invalid_search_query": "Vul alsjeblieft een zoekterm in tussen {{min}} en {{max}} karakters lang.", "forum/label": "Label", "forum/label_deleted_successfully": "Label succesvol verwijdert.", @@ -159,5 +159,39 @@ "forum/new_search": "Nieuwe zoekopdracht", "forum/new_topic_hook_info": "Nieuw onderwerp", "forum/new_topic_text": "Onderwerp gemaakt in {{forum}} door {{author}}", - "forum/new_reply_in_topic": "{{author}} Heeft gereageerd op onderwerp {{topic}}" + "forum/new_reply_in_topic": "{{author}} Heeft gereageerd op onderwerp {{topic}}", + "forum/search_again_in_x_seconds": "Wacht alstublieft {{count}} seconden voor opnieuw te zoeken.", + "forum/no_news": "Er zijn geen nieuws posts.", + "forum/not_following_any_topics": "Je volgt geen onderwerpen.", + "forum/now_following_topic": "Je volgt nu dit onderwerp, en zult meldingen krijgen van nieuwe reacties.", + "forum/post_id": "Post ID", + "forum/topic_reply": "Onderwerp reactie", + "forum/your_posts": "Jouw post aantal", + "forum/label_type_in_use": "Label type wordt gebruikt, kan niet worden verwijderd.", + "forum/new_topic_reply_text": "Onderwerp reactie gemaakt in {{forum}} door {{author}}", + "forum/no_longer_following_topic": "Je volgt dit onderwerp niet meer, en krijgt geen meldingen meer van nieuwe reacties.", + "forum/no_results_found": "Geen resultaten gevonden.", + "forum/posts_title": "Posts", + "forum/pre_post_create_hook_info": "Voor post aanmaak", + "forum/pre_post_edit_hook_info": "Voor post bewerking", + "forum/pre_topic_create_hook_info": "Voor reactie aanmaak", + "forum/pre_topic_edit_hook_info": "Voor reactie bewerking", + "forum/recent_posts": "Recente Posts", + "forum/recent_topics": "Recente onderwerpen", + "forum/redirect_forum": "Leid forum om?", + "forum/redirect_url": "Omleid URL", + "forum/search_results": "Zoekresultaten", + "forum/settings_updated_successfully": "Instellingen succesvol aangepast.", + "forum/started_by_x": "Gestart door {{author}}", + "forum/sticky_topics": "Plakkende Onderwerpen", + "forum/topic_id": "Onderwerp ID", + "forum/topic_placeholder": "Onderwerp placeholder", + "forum/topics_title": "Onderwerpen", + "forum/total_posts": "Totale post aantal", + "forum/topic_author_uuid": "Onderwerp auteur gebruikers ID", + "forum/topic_author_username": "Onderwerp auteur gebruikersnaam", + "forum/topic_author_nickname": "Topic auteur bijnaam", + "forum/unfollow": "Ontvolg", + "forum/unfollow_all_topics": "Ontvolg alle onderwerpen", + "forum/user_object": "Gebruikersobject" } From 4115b65ce2a31fd49c80791c48a582d2a5f51c2b Mon Sep 17 00:00:00 2001 From: namelessmc-bot <76107159+namelessmc-bot@users.noreply.github.com> Date: Sat, 4 Jun 2022 16:53:26 +0200 Subject: [PATCH 025/337] Translations update (#2821) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Supercrafter100 Co-authored-by: Marcos Co-authored-by: PadowYT2 Co-authored-by: PikaMug Co-authored-by: Jonáš Loskot Co-authored-by: enno123 From 84dc01c4b4f5753d4b953e469474d1890de31546 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Sat, 4 Jun 2022 09:24:26 -0600 Subject: [PATCH 026/337] Fix editing topic title --- custom/templates/DefaultRevamp/forum/forum_edit_post.tpl | 4 ++-- modules/Forum/pages/forum/edit.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/custom/templates/DefaultRevamp/forum/forum_edit_post.tpl b/custom/templates/DefaultRevamp/forum/forum_edit_post.tpl index 548d53967f..981e69ca2e 100755 --- a/custom/templates/DefaultRevamp/forum/forum_edit_post.tpl +++ b/custom/templates/DefaultRevamp/forum/forum_edit_post.tpl @@ -27,7 +27,7 @@ {if isset($EDITING_TOPIC)}
- +
{if count($LABELS)}
@@ -57,4 +57,4 @@
-{include file='footer.tpl'} \ No newline at end of file +{include file='footer.tpl'} diff --git a/modules/Forum/pages/forum/edit.php b/modules/Forum/pages/forum/edit.php index c8482aa32f..d5d8d554cc 100644 --- a/modules/Forum/pages/forum/edit.php +++ b/modules/Forum/pages/forum/edit.php @@ -186,7 +186,7 @@ if (isset($edit_title, $post_labels)) { $smarty->assign('EDITING_TOPIC', true); - $smarty->assign('TOPIC_TITLE', $post_title); + $smarty->assign('TOPIC_TITLE_VALUE', $post_title); // Topic labels $smarty->assign('LABELS_TEXT', $forum_language->get('forum', 'label')); From d5cb2176ca0bfcbb757861c97b3121c589996626 Mon Sep 17 00:00:00 2001 From: Partydragen Date: Sat, 4 Jun 2022 17:34:40 +0200 Subject: [PATCH 027/337] Last_online can be null --- core/classes/DTO/UserData.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/classes/DTO/UserData.php b/core/classes/DTO/UserData.php index e76b2bc9a1..7e7b729a40 100644 --- a/core/classes/DTO/UserData.php +++ b/core/classes/DTO/UserData.php @@ -27,7 +27,7 @@ class UserData { public bool $gravatar; public bool $topic_updates; public bool $private_profile; - public int $last_online; + public ?int $last_online; public ?string $user_title; public ?int $theme_id; public ?int $language_id; From 9a5e51f43e2fe36329eba2190be9f3758c6ba312 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Sat, 4 Jun 2022 09:42:30 -0600 Subject: [PATCH 028/337] Fix #2820 --- modules/Core/module.php | 2 +- modules/Core/pages/panel/update.php | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/modules/Core/module.php b/modules/Core/module.php index af4a585788..1f28f20b41 100644 --- a/modules/Core/module.php +++ b/modules/Core/module.php @@ -743,7 +743,7 @@ public function onPageLoad(User $user, Pages $pages, Cache $cache, Smarty $smart // Check for updates if ($user->isLoggedIn()) { - if ($user->hasPermission('admincp.update')) { + if ((defined('PANEL_PAGE') && PANEL_PAGE !== 'update') && $user->hasPermission('admincp.update')) { $cache->setCache('update_check'); if ($cache->isCached('update_check')) { $update_check = $cache->retrieve('update_check'); diff --git a/modules/Core/pages/panel/update.php b/modules/Core/pages/panel/update.php index 65f22fe28d..5f8b835b52 100644 --- a/modules/Core/pages/panel/update.php +++ b/modules/Core/pages/panel/update.php @@ -57,6 +57,16 @@ if (!is_string($update_check)) { if ($update_check->updateAvailable()) { $smarty->assign([ + 'NEW_UPDATE' => $update_check->isUrgent() + ? $language->get('admin', 'new_urgent_update_available') + : $language->get('admin', 'new_update_available'), + 'NEW_UPDATE_URGENT' => $update_check->isUrgent(), + 'CURRENT_VERSION' => $language->get('admin', 'current_version_x', [ + 'version' => Output::getClean(NAMELESS_VERSION) + ]), + 'NEW_VERSION' => $language->get('admin', 'new_version_x', [ + 'version' => Output::getClean($update_check->version()) + ]), 'INSTRUCTIONS' => $language->get('admin', 'instructions'), 'INSTRUCTIONS_VALUE' => Output::getDecoded($update_check->instructions()), 'UPGRADE_LINK' => URL::build('/panel/upgrade'), From cf25a43bc4a540ce8c53957a93ef9cff56e1bbb8 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Sat, 4 Jun 2022 09:43:51 -0600 Subject: [PATCH 029/337] Add back `DB::decrement(...)` --- core/classes/Database/DB.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/core/classes/Database/DB.php b/core/classes/Database/DB.php index bbf7a2843e..7acb99b1b7 100644 --- a/core/classes/Database/DB.php +++ b/core/classes/Database/DB.php @@ -273,6 +273,20 @@ public function increment(string $table, int $id, string $field): bool { return !$this->query("UPDATE {$table} SET {$field} = {$field} + 1 WHERE id = ?", [$id])->error(); } + /** + * Decrement a numeric column value by 1. + * + * @param string $table The table to use. + * @param int $id The id of the row to decrement a column in. + * @param string $field The field to increment. + * @return bool Whether an error occurred or not. + */ + public function decrement(string $table, int $id, string $field): bool { + $table = $this->_prefix . $table; + + return !$this->query("UPDATE {$table} SET {$field} = {$field} - 1 WHERE id = ?", [$id])->error(); + } + /** * Select rows from the database, ordering by a specific column and sort type. * From 3407ca501cd2a78e3caa4825058a8fb0250c31f5 Mon Sep 17 00:00:00 2001 From: Robin Date: Sat, 4 Jun 2022 21:51:05 +0200 Subject: [PATCH 030/337] add null checks --- core/classes/Templates/AssetResolver.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/classes/Templates/AssetResolver.php b/core/classes/Templates/AssetResolver.php index fd4a72b56e..b94a3e558c 100644 --- a/core/classes/Templates/AssetResolver.php +++ b/core/classes/Templates/AssetResolver.php @@ -27,9 +27,17 @@ public function include($assets): void { } foreach ($assets as $asset) { + if ($asset == null) { + throw new InvalidArgumentException("Attempted to register null asset"); + } + $this->validateAsset($asset); $this->_assets[$asset] = parent::ASSET_TREE[$asset]; + + if ($this->_assets[$asset] == null) { + throw new InvalidArgumentException("Asset missing in asset tree"); + } } } From 2d345d47a6ba1fec6202537a107f0485c2f808e7 Mon Sep 17 00:00:00 2001 From: Partydragen Date: Sun, 5 Jun 2022 19:21:28 +0200 Subject: [PATCH 031/337] Banner image listing Broke in https://github.com/NamelessMC/Nameless/commit/aaacf040ae69bcedb0e156f6cde69c2f1bef28da --- modules/Core/pages/panel/images.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/modules/Core/pages/panel/images.php b/modules/Core/pages/panel/images.php index ec073647ce..c803524a17 100644 --- a/modules/Core/pages/panel/images.php +++ b/modules/Core/pages/panel/images.php @@ -138,6 +138,26 @@ // Only display jpeg, png, jpg, gif $allowed_exts = ['gif', 'png', 'jpg', 'jpeg', 'ico']; +$image_path = implode(DIRECTORY_SEPARATOR, [ROOT_PATH, 'uploads', 'template_banners']); +$images = scandir($image_path); +$template_banner_images = []; + +$n = 1; + +foreach ($images as $image) { + $ext = pathinfo($image, PATHINFO_EXTENSION); + if (!in_array($ext, $allowed_exts)) { + continue; + } + $template_banner_images[] = [ + 'src' => (defined('CONFIG_PATH') ? CONFIG_PATH : '') . '/uploads/template_banners/' . $image, + 'value' => $image, + 'selected' => ($banner_image == (defined('CONFIG_PATH') ? CONFIG_PATH : '') . '/uploads/template_banners/' . $image), + 'n' => $n + ]; + $n++; +} + $image_path = implode(DIRECTORY_SEPARATOR, [ROOT_PATH, 'uploads', 'logos']); $images = scandir($image_path); $logo_images = []; From 6b6da8e398f6a5d500753b26f5d1ed3fa7db973e Mon Sep 17 00:00:00 2001 From: Robin Date: Sun, 5 Jun 2022 23:19:12 +0200 Subject: [PATCH 032/337] Remove unused isConnectionSSL getProtocol() should be (and is) used instead --- core/classes/Core/Util.php | 9 --------- 1 file changed, 9 deletions(-) diff --git a/core/classes/Core/Util.php b/core/classes/Core/Util.php index 97ec2784ee..000174944c 100644 --- a/core/classes/Core/Util.php +++ b/core/classes/Core/Util.php @@ -374,15 +374,6 @@ public static function getSelfURL(bool $show_protocol = true): string { return $url; } - /** - * Detect if the current connection is using SSL. - * - * @return bool Whether SSL is in use or not. - */ - public static function isConnectionSSL(): bool { - return (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'); - } - /** * URL-ify a string * From e278348c871fd3684e741c4b66dc89338c7ad94b Mon Sep 17 00:00:00 2001 From: Robin Date: Sun, 5 Jun 2022 23:47:37 +0200 Subject: [PATCH 033/337] Fix CLI install error, there may not be any address/proto/port this happened when a curl error occured during minecraft uuid request, resulting it getting the IP for logging --- core/classes/Core/Log.php | 6 ++--- core/classes/Core/Util.php | 24 ++++++++++++------- modules/Core/pages/register.php | 2 +- .../Discord Integration/classes/Discord.php | 2 +- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/core/classes/Core/Log.php b/core/classes/Core/Log.php index 98de20a615..22a6a13c1f 100644 --- a/core/classes/Core/Log.php +++ b/core/classes/Core/Log.php @@ -206,16 +206,16 @@ public static function Action(string $path) { * @param string $action The action being logged * @param string $info Some more information about what the action is about * @param ?int $user The User ID who is doing the action - * @param ?string $ip The ip of the user. If not specified, it will try to get the IP from the currently logged in user. * @return bool Return true or false if inserted into the database. */ - public function log(string $action, string $info = '', ?int $user = null, string $ip = null): bool { + public function log(string $action, string $info = '', ?int $user = null): bool { if ($user == null) { $userTemp = new User(); - $ip = Util::getRemoteAddress(); $user = ($userTemp->isLoggedIn() ? $userTemp->data()->id : 0); } + $ip = Util::getRemoteAddress(); + return $this->_db->insert('logs', [ 'time' => date('U'), 'action' => $action, diff --git a/core/classes/Core/Util.php b/core/classes/Core/Util.php index 000174944c..08376a427d 100644 --- a/core/classes/Core/Util.php +++ b/core/classes/Core/Util.php @@ -226,9 +226,9 @@ private static function firstNonProxyAddress(array $addresses): string { /** * Get the client's true IP address, using proxy headers if necessary. * - * @return string Client IP address + * @return ?string Client IP address, or null if there is no remote address, for example in CLI environment */ - public static function getRemoteAddress(): string { + public static function getRemoteAddress(): ?string { $headers = getallheaders(); // Try the simple headers first that only contain an IP address @@ -304,9 +304,9 @@ public static function getRemoteAddress(): string { /** * Get the protocol used by client's HTTP request, using proxy headers if necessary. * - * @return string 'http' if HTTP or 'https' if HTTPS + * @return ?string 'http' if HTTP or 'https' if HTTPS, or null when using the CLI */ - public static function getProtocol(): string { + public static function getProtocol(): ?string { if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) { self::ensureTrustedProxy(); $proto = $_SERVER['HTTP_X_FORWARDED_PROTO']; @@ -316,15 +316,17 @@ public static function getProtocol(): string { return $proto; } - return (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') - ? 'https' - : 'http'; + if (isset($_SERVER['HTTPS'])) { + return $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http'; + } + + return null; } /** * Get port used by client's HTTP request, using proxy headers if necessary. * - * @return int Port number + * @return ?int Port number, or null when using the CLI */ public static function getPort(): int { if (isset($_SERVER['HTTP_X_FORWARDED_PORT'])) { @@ -332,7 +334,11 @@ public static function getPort(): int { return (int) $_SERVER['HTTP_X_FORWARDED_PORT']; } - return (int) $_SERVER['SERVER_PORT']; + if (isset($_SERVER['SERVER_PORT'])) { + return (int) $_SERVER['SERVER_PORT']; + } + + return null; } /** diff --git a/modules/Core/pages/register.php b/modules/Core/pages/register.php index eaf40226d5..3f8eaa4c3c 100644 --- a/modules/Core/pages/register.php +++ b/modules/Core/pages/register.php @@ -355,7 +355,7 @@ } } - Log::getInstance()->log(Log::Action('user/register'), '', $user_id, Util::getRemoteAddress()); + Log::getInstance()->log(Log::Action('user/register'), '', $user_id); $default_language = new Language('core', DEFAULT_LANGUAGE); EventHandler::executeEvent('registerUser', [ diff --git a/modules/Discord Integration/classes/Discord.php b/modules/Discord Integration/classes/Discord.php index 009eed969d..8ff012e918 100644 --- a/modules/Discord Integration/classes/Discord.php +++ b/modules/Discord Integration/classes/Discord.php @@ -78,7 +78,7 @@ public static function updateDiscordRoles(User $user, array $added, array $remov $errors = self::parseErrors($result); foreach ($errors as $error) { - Log::getInstance()->log(Log::Action('discord/role_set'), $error, $user->data()->id, Util::getRemoteAddress()); + Log::getInstance()->log(Log::Action('discord/role_set'), $error, $user->data()->id); } return false; From 67090bdeb4b7b2e72929384191f144cafff708b7 Mon Sep 17 00:00:00 2001 From: Robin Date: Sun, 5 Jun 2022 23:49:33 +0200 Subject: [PATCH 034/337] fix return type --- core/classes/Core/Util.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/classes/Core/Util.php b/core/classes/Core/Util.php index 08376a427d..f2c40a066d 100644 --- a/core/classes/Core/Util.php +++ b/core/classes/Core/Util.php @@ -328,7 +328,7 @@ public static function getProtocol(): ?string { * * @return ?int Port number, or null when using the CLI */ - public static function getPort(): int { + public static function getPort(): ?int { if (isset($_SERVER['HTTP_X_FORWARDED_PORT'])) { self::ensureTrustedProxy(); return (int) $_SERVER['HTTP_X_FORWARDED_PORT']; From 3ac1226c551c6bf7078b0c26e9579d16c02115da Mon Sep 17 00:00:00 2001 From: Partydragen Date: Sun, 5 Jun 2022 23:57:06 +0200 Subject: [PATCH 035/337] Fix missing term --- custom/languages/en_UK.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/custom/languages/en_UK.json b/custom/languages/en_UK.json index 29496157a0..9faefc913e 100644 --- a/custom/languages/en_UK.json +++ b/custom/languages/en_UK.json @@ -829,6 +829,7 @@ "general/pink": "Pink", "general/brown": "Brown", "general/grey": "Grey", + "general/deleted_user": "Deleted User", "installer/back": "Back", "installer/cache_writable": "Cache Writable", "installer/character_set": "Character Set", @@ -1219,4 +1220,4 @@ "user/x_replies": "{{count}} replies", "user/you_have_been_banned": "You have been banned!", "user/you_have_received_a_warning": "You have received a warning!" -} \ No newline at end of file +} From dd51de48e8fd359ea369124ea6d155f01403ac5d Mon Sep 17 00:00:00 2001 From: Anton Date: Sun, 5 Jun 2022 18:51:17 +0000 Subject: [PATCH 036/337] Translated using Weblate (German) Currently translated at 100.0% (1220 of 1220 strings) Translation: NamelessMC/Website - Core Translate-URL: https://translate.namelessmc.com/projects/namelessmc/nameless/de/ --- custom/languages/de_DE.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/custom/languages/de_DE.json b/custom/languages/de_DE.json index df8c801402..5640c0a319 100644 --- a/custom/languages/de_DE.json +++ b/custom/languages/de_DE.json @@ -564,7 +564,7 @@ "admin/users": "Benutzer", "admin/uuid": "UUID", "admin/uuid_max_32": "UUID muss zwischen 2 und 32 Zeichen lang sein.", - "admin/validate_hook_info": "Benutzer Verifizierung", + "admin/validate_hook_info": "Benutzerverifizierung", "admin/validate_user": "Benutzer bestätigen", "admin/validation_promote_group": "Verifiziert Gruppe", "admin/validation_promote_group_info": "Diese Gruppe erhält der Spieler, wenn er sich verifiziert hat.", @@ -880,16 +880,16 @@ "table/no_records": "Keine Eintragungen verfügbar", "table/nothing_found": "Keine Einträge gefunden", "table/page_x_of_y": "Zeige Seite _PAGE_ von _PAGES_", - "time/1_day": "1 Tag her", - "time/1_minute": "1 Minute her", - "time/_days": "{{count}} Tage her", - "time/_hours": "{{count}} Stunden her", - "time/_minutes": "{{count}} Minuten her", - "time/_months": "{{count}} Monate her", + "time/1_day": "Vor 1 Tag", + "time/1_minute": "Vor 1 Minute", + "time/_days": "Vor {{count}} Tagen", + "time/_hours": "Vor {{count}} Stunden", + "time/_minutes": "Vor {{count}} Minuten", + "time/_months": "Vor {{count}} Monaten", "time/about_1_hour": "über 1 Stunde her", "time/about_1_month": "über 1 Monat her", "time/about_1_year": "über 1 Jahr her", - "time/less_than_a_minute": "weniger als eine Minute her", + "time/less_than_a_minute": "vor weniger als einer Minute", "time/over_x_years": "über {{count}} Jahre her", "user/1_new_alert": "Du hast 1 neue Benachrichtigung", "user/1_new_message": "Du hast {{count}} neue Nachrichten", From dba6584eeff4303d28ec05d37511575c1da10736 Mon Sep 17 00:00:00 2001 From: snake Date: Sun, 5 Jun 2022 20:24:52 +0000 Subject: [PATCH 037/337] Translated using Weblate (Japanese) Currently translated at 95.5% (1166 of 1220 strings) Translation: NamelessMC/Website - Core Translate-URL: https://translate.namelessmc.com/projects/namelessmc/nameless/ja/ --- custom/languages/ja_JP.json | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/custom/languages/ja_JP.json b/custom/languages/ja_JP.json index 0852d63412..5535ded9ff 100644 --- a/custom/languages/ja_JP.json +++ b/custom/languages/ja_JP.json @@ -118,7 +118,7 @@ "admin/default_avatar": "デフォルトアバター", "admin/default_group": "このグループは(新規ユーザーの)デフォルトグループですか?", "admin/default_language": "初期言語", - "admin/default_language_help": "初期言語に設定している言語が登録後最初の言語になりますが、各ユーザーは後でインストールされている言語から別の言語を選択できます。", + "admin/default_language_help": "ユーザーは、インストールされている言語から選択することができます。{{docLinkStart}}続きを読む »{{docLinkEnd}}", "admin/default_server": "初期サーバー", "admin/default_template_set": "{{template}} をデフォルトのテンプレートに設定しました。", "admin/default_timezone": "初期タイムゾーン", @@ -185,7 +185,7 @@ "admin/enable_authme": "AuthMe 連携を有効にしますか?", "admin/enable_debug_mode": "デバッグモードを有効にしますか?", "admin/enable_mailer": "PHPMailerを有効にしますか?", - "admin/enable_mailer_help": "php.iniで電子メール設定が完了していない場合こちらを使用できます。PHPMailerを使用するには、GmailやSMTPプロバイダなどの電子メールを送信できるプロバイダーサービスが必要です。", + "admin/enable_mailer_help": "有効にすると、システムのデフォルトではなくPHPMailerを使ってメールを送信するようになります。これはメール配信の助けになるかもしれませんが、SMTP プロバイダを設定する必要があります。{{docLinkStart}}続きを読む »{{docLinkEnd}}", "admin/enable_maintenance_mode": "メンテナンスモードを有効にしますか?", "admin/enable_minecraft_integration": "Minecraft連携を有効にしますか?", "admin/enable_nicknames_on_registration": "ユーザー登録時、Minecarft以外のユーザーネームの登録を許可しますか?", @@ -215,7 +215,7 @@ "admin/find_modules": "モジュール検索", "admin/find_templates": "テンプレートを探す", "admin/force_https": "httpsを強制させますか?", - "admin/force_https_help": "有効にするとhttpは自動でhttpsに置き換わります。有効にするには、必ず有効なサーバー証明書をサーバーに設定しておいてください。", + "admin/force_https_help": "有効にすると、ウェブサイトへの全てのリクエストはhttpsにリダイレクトされます。この機能を使用するには、有効なSSL証明書を設定している必要があります。", "admin/force_premium_accounts": "プレミアムMinecraftアカウントを強制しますか?", "admin/force_tfa": "グループメンバーに二要素認証を強制しますか?", "admin/force_tfa_alert": "あなたのグループでは、二要素認証を有効にする必要があります。", @@ -342,7 +342,7 @@ "admin/navbar_icon": "ナビゲーションバーアイコン", "admin/navbar_icon_instructions": "ナビゲーションバーアイコンは {{faLink}}, {{semLink}} を参照して使用したいアイコンのHTMLソースを貼り付けてください。", "admin/navbar_order": "ナビゲーションバー順番", - "admin/navbar_order_instructions": "ナビゲーションバー順番は、各メニューの順番を設定できます。一番最初は「1」、二番目以降はそれ以上の数字を設定することで順番を調節できます。", + "admin/navbar_order_instructions": "各項目には正の数を割り当てることができ、最も小さい番号がナビバーの最初に表示され、より大きい番号がその後に表示されます。", "admin/navigation": "ナビゲーション", "admin/navigation_settings_updated_successfully": "ナビゲーションバーの設定が正常に更新されました。", "admin/negative": "ネガティブ", @@ -598,7 +598,7 @@ "admin/upgrade_php_version": "PHPのバージョンを7.4以上にアップグレードしてください。次のNamelessのリリースでは、現在使用しているバージョンがサポートされなくなります。", "admin/upload_new_image": "画像アップロード", "admin/use_friendly_urls": "フレンドリーURL", - "admin/use_friendly_urls_help": "重要: サーバー設定にてmod_rewriteと.htaccessを使用できるように設定する必要があります。IISの場合はルートディレクトリのweb.config.exampleをweb.configに変更してください。", + "admin/use_friendly_urls_help": "有効にすると、より見た目の良いURLが使用されます。この機能を使用するためには、mod_rewriteと.htaccessファイルの使用を許可する必要があります。{{docLinkStart}}続きを読む »{{docLinkEnd}}", "admin/user": "ユーザー", "admin/user_deleted": "ユーザーは正常に削除されました。", "admin/user_id": "ユーザーID", @@ -1165,5 +1165,10 @@ "admin/integration_identifier_required": "{{integration}}の識別子は必須です。", "admin/is_verified": "検証が必要ですか?", "admin/link_account_success": "{{user}}は{{integration}}のアカウントと正常にリンクしました。", - "admin/manual_linking": "手動リンク" + "admin/manual_linking": "手動リンク", + "admin/verified": "検証", + "admin/test_email_query": "受信トレイに届きませんか?以下をお試しください:", + "admin/test_email_suggest_1": "数分待って、迷惑メールフォルダを確認してください。", + "admin/test_email_suggest_2": "ウェブサイトのDNSレコードを更新してください。(SPFとDKIMを確認)", + "admin/test_email_suggest_3": "SMTPサーバーを設定する。{{docLinkStart}}続きを読む »{{docLinkEnd}}" } From fd563b78fa06357376031acda47f6a350104a648 Mon Sep 17 00:00:00 2001 From: Marcos Date: Sun, 5 Jun 2022 19:51:12 +0000 Subject: [PATCH 038/337] Translated using Weblate (Spanish) Currently translated at 100.0% (51 of 51 strings) Translation: NamelessMC/Website - Discord Integration Translate-URL: https://translate.namelessmc.com/projects/namelessmc/website-discord-integration/es/ --- modules/Discord Integration/language/es_ES.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/Discord Integration/language/es_ES.json b/modules/Discord Integration/language/es_ES.json index f6f7575e65..d39cc42c59 100644 --- a/modules/Discord Integration/language/es_ES.json +++ b/modules/Discord Integration/language/es_ES.json @@ -16,8 +16,8 @@ "discord_integration/discord_database_error": "La base de datos de Nameless Link no funciona actualmente. Por favor, inténtelo más tarde.", "discord_integration/discord_guild_id": "ID del servidor de Discord", "discord_integration/discord_id_help": "Para obtener información sobre dónde encontrar IDs de Discord, por favor lea {{linkStart}}esto.{{linkEnd}}", - "discord_integration/discord_id_length": "Por favor, asegúrate de que la ID de Discord tiene 18 caracteres.", - "discord_integration/discord_id_numeric": "Por favor, asegúrese de que su ID de Discord es numérica (sólo números).", + "discord_integration/discord_id_length": "Por favor, asegúrate de que la ID del servidor de Discord tiene 18 caracteres.", + "discord_integration/discord_id_numeric": "Por favor, asegúrese de que su ID del servidor de Discord es numérica (sólo números).", "discord_integration/discord_id_set": "ID de Discord establecida con éxito", "discord_integration/discord_id_taken": "Esa ID de Discord ya ha sido tomada.", "discord_integration/discord_id_unlinked": "Se ha desvinculado con éxito su ID de usuario de Discord.", @@ -48,5 +48,6 @@ "discord_integration/discord_invite_info": "Para invitar al bot Nameless Link a tu servidor de Discord, haz clic en {{inviteLinkStart}}aquí{{inviteLinkEnd}}. A continuación, ejecuta el comando {{command}} para enlazar el bot con tu sitio web. También puedes {{selfHostLinkStart}}alojar el bot tú mismo{{selfHostLinkEnd}}.", "discord_integration/discord_user_id": "ID de usuario de Discord", "discord_integration/discord_widget_disabled": "El widget está desactivado para el servidor de Discord especificado. Ve a la pestaña \"Widget\" en la configuración de tu servidor de Discord y asegúrate de que el widget de Discord está activado y de que el ID es correcto.", - "discord_integration/discord_widget_error": "Se ha producido un error al obtener el widget de Discord: {{error}}." + "discord_integration/discord_widget_error": "Se ha producido un error al obtener el widget de Discord: {{error}}.", + "discord_integration/discord_id_required": "Por favor, introduce la ID del servidor de Discord." } From 5b6f67d8784d6add4690a7f7a40e1db51304f853 Mon Sep 17 00:00:00 2001 From: Gabi Date: Sun, 5 Jun 2022 21:26:06 +0000 Subject: [PATCH 039/337] Translated using Weblate (Spanish (Latin America)) Currently translated at 9.0% (1 of 11 strings) Translation: NamelessMC/Website - Cookie Consent Translate-URL: https://translate.namelessmc.com/projects/namelessmc/cookie-consent/es_419/ --- modules/Cookie Consent/language/es_419.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/Cookie Consent/language/es_419.json b/modules/Cookie Consent/language/es_419.json index 0967ef424b..eeea9031a1 100644 --- a/modules/Cookie Consent/language/es_419.json +++ b/modules/Cookie Consent/language/es_419.json @@ -1 +1,3 @@ -{} +{ + "cookie/configure_cookies": "Configurar cookies" +} From c966f50b4ce49ede3c8c0230e077df93c47ee3e8 Mon Sep 17 00:00:00 2001 From: Anton Date: Sun, 5 Jun 2022 18:43:34 +0000 Subject: [PATCH 040/337] Translated using Weblate (German) Currently translated at 100.0% (195 of 195 strings) Translation: NamelessMC/Website - Forum Translate-URL: https://translate.namelessmc.com/projects/namelessmc/website-forum/de/ --- modules/Forum/language/de_DE.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/Forum/language/de_DE.json b/modules/Forum/language/de_DE.json index bc68e656b7..99a8d181fd 100644 --- a/modules/Forum/language/de_DE.json +++ b/modules/Forum/language/de_DE.json @@ -115,7 +115,7 @@ "forum/no_topics": "Es wurden noch keine Themen erstellt.", "forum/no_topics_short": "Keine Themen", "forum/no_users_online": "Keine Benutzer online.", - "forum/not_following_any_topics": "Du folgst keine Themen.", + "forum/not_following_any_topics": "Du folgst keinen Themen.", "forum/now_following_topic": "Du folgst diesem Thema jetzt und wirst über neue Antworten informiert.", "forum/online_users": "Benutzer Online", "forum/overview": "Überblick", @@ -157,7 +157,7 @@ "forum/title_required": "Gib bitte einen Titel an", "forum/topic": "Thema", "forum/topic_locked": "Thema geschlossen", - "forum/topic_locked_notice": "Dieses Thema ist geschlossen, du bist trotzdem dazu berechtigt Beiträge erstellen.", + "forum/topic_locked_notice": "Dieses Thema ist geschlossen, du bist trotzdem dazu berechtigt Beiträge zu erstellen.", "forum/topic_stuck": "Thema wurde angeheftet.", "forum/topic_title": "Titel des Themas", "forum/topic_unstuck": "Thema wurde abgeheftet.", From a81268efc1bb4b1dcdda0d0d6c0750256f8a6679 Mon Sep 17 00:00:00 2001 From: Kipper Chau Date: Sun, 5 Jun 2022 07:54:45 +0000 Subject: [PATCH 041/337] Translated using Weblate (Chinese (Traditional)) Currently translated at 80.0% (156 of 195 strings) Translation: NamelessMC/Website - Forum Translate-URL: https://translate.namelessmc.com/projects/namelessmc/website-forum/zh_Hant/ --- modules/Forum/language/zh_TW.json | 301 ++++++++++++++++-------------- 1 file changed, 157 insertions(+), 144 deletions(-) diff --git a/modules/Forum/language/zh_TW.json b/modules/Forum/language/zh_TW.json index 8e361845f4..7c925e5432 100644 --- a/modules/Forum/language/zh_TW.json +++ b/modules/Forum/language/zh_TW.json @@ -1,145 +1,158 @@ { - "forum\/by": "by", - "forum\/can_create_topic": "可以建立主題?", - "forum\/can_edit_topic": "Can edit their topics?", - "forum\/can_moderate_forum": "可以審核論壇?", - "forum\/can_post_reply": "可以建立回覆?", - "forum\/can_view_forum": "可以查看論壇?", - "forum\/can_view_other_topics": "可以查看其他人的文章?", - "forum\/confirm_delete_post": "確認移除文章?", - "forum\/confirm_delete_short": "確認移除", - "forum\/confirm_delete_topic": "確認移除主題?", - "forum\/content_max_50000": "文章內容最高限制 50000 字元", - "forum\/content_min_2": "文章內容最低限制 2 字元", - "forum\/content_required": "請輸入文章內容", - "forum\/creating_forum": "建立新論壇", - "forum\/creating_label": "建立新標籤", - "forum\/creating_label_type": "建立新標籤類型", - "forum\/creating_topic_in_x": "在 {{forum}} 建立主題", - "forum\/delete_forum": "移除論壇", - "forum\/delete_topic": "移除主題", - "forum\/delete_topics_and_posts": "移除主題和文章", - "forum\/discussion": "討論串", - "forum\/display_topics_as_news": "顯示此主題的文章在首頁?", - "forum\/edit": "編輯", - "forum\/edit_post": "編輯文章", - "forum\/editing_label": "編輯標籤", - "forum\/editing_label_type": "編輯標籤類型", - "forum\/error_quoting_posts": "抱歉,引用文章時出了錯.", - "forum\/error_rating_post": "抱歉,文章發生錯誤.", - "forum\/forum": "論壇", - "forum\/forum_created_successfully": "論壇建立成功.", - "forum\/forum_description": "論壇說明", - "forum\/forum_description_maximum": "論壇說明最高限制 255 字元.", - "forum\/forum_description_minimum": "論壇說明最低限制 2 字元.", - "forum\/forum_index": "首頁", - "forum\/forum_layout": "論壇佈局", - "forum\/forum_name": "論壇名稱", - "forum\/forum_name_maximum": "論壇名稱最高限制 150 字元.", - "forum\/forum_name_minimum": "論壇名稱最低限制 2 字元.", - "forum\/forum_permissions": "論壇權限", - "forum\/forum_search": "論壇搜尋", - "forum\/forum_type": "論壇類型", - "forum\/forum_type_category": "類別", - "forum\/forum_type_forum": "論壇", - "forum\/forums": "論壇", - "forum\/group": "群組", - "forum\/guests": "遊客", - "forum\/has_no_parent": "沒有父論壇", - "forum\/in": "in", - "forum\/input_forum_description": "請輸入論壇說明.", - "forum\/input_forum_title": "P請輸入論壇標題.", - "forum\/insert_quotes": "Insert Quotes", - "forum\/invalid_action": "無效操作", - "forum\/invalid_search_query": "搜尋限制 3~128 字元.", - "forum\/label": "標籤", - "forum\/label_creation_error": "無法建立標籤. 請確認輸入的內容沒有超過 32 字元.", - "forum\/label_creation_success": "標籤建立成功.", - "forum\/label_edit_success": "標籤編輯成功.", - "forum\/label_forums": "標籤論壇", - "forum\/label_groups": "標籤群組", - "forum\/label_name": "標籤名稱", - "forum\/label_type": "標籤類型", - "forum\/label_type_creation_error": "無法建立標籤類型. 請確認輸入的內容沒有超過 32 字元,HTML沒有超過 1024 字元.", - "forum\/label_type_creation_success": "標籤類型建立成功.", - "forum\/label_type_edit_success": "標籤類型編輯成功.", - "forum\/label_type_html": "標籤類型HTML", - "forum\/label_type_html_help": "標籤必須包含 {x} 做為標籤的佔位符", - "forum\/label_type_name": "標籤類型名稱", - "forum\/label_types": "標籤類型", - "forum\/labels": "標籤", - "forum\/last_edited": "最後編輯: {{lastEditedAt}}", - "forum\/last_reply": "最後回覆", - "forum\/latest_announcements": "最新公告", - "forum\/latest_discussions": "最新的討論串", - "forum\/latest_discussions_view": "最新的討論統計圖", - "forum\/latest_posts": "最新文章", - "forum\/lock_topic": "鎖定主題", - "forum\/merge_instructions": "合併指令必須只能在一個論壇中. 如有必要請移動一整個線程.", - "forum\/merge_topic": "合併主題", - "forum\/merge_topics": "合併文章", - "forum\/mod_actions": "審核", - "forum\/move_topic": "移動主題", - "forum\/move_topic_to": "移動主題至:", - "forum\/move_topics_and_posts_to": "移動主題和文章到", - "forum\/new_forum": "<\/i> 新論壇", - "forum\/new_label": "<\/i> 新標籤", - "forum\/new_label_type": "<\/i> 新標籤類型", - "forum\/new_reply": "新回覆", - "forum\/new_search": "新搜尋", - "forum\/new_topic": "新主題", - "forum\/no_forums": "沒有論壇", - "forum\/no_label": "沒有標籤", - "forum\/no_label_types_defined": "無定義標籤類型.", - "forum\/no_labels_defined": "無定義標籤.", - "forum\/no_results_found": "找不到資料.", - "forum\/no_topics": "沒有主題被建立.", - "forum\/no_topics_short": "沒有主題", - "forum\/no_users_online": "沒有使用者在線上.", - "forum\/online_users": "線上使用者", - "forum\/overview": "總覽", - "forum\/parent_forum": "父論壇", - "forum\/parent_forum_x": "Parent Forum: {{forum}}", - "forum\/post_already_reported": "你已經回報過這篇文章!", - "forum\/post_edited_successfully": "文章編輯成功.", - "forum\/post_successful": "成功發文.", - "forum\/posts": "文章", - "forum\/quote": "引用", - "forum\/quoted_post": "文章已新增至引用.", - "forum\/quoting_posts": "插入引用..", - "forum\/re": "RE: ", - "forum\/read_full_post": "閱讀全部", - "forum\/registered_x": "Joined: {{registeredAt}}", - "forum\/removed_quoted_post": "文章已從引用中移除.", - "forum\/search_again_in_x_seconds": "請等待 {{count}} 秒後再次搜尋.", - "forum\/search_results": "搜尋結果", - "forum\/select_a_parent_forum": "選擇父論壇", - "forum\/share": "分享", - "forum\/share_facebook": "在 Facebook 上分享", - "forum\/share_twitter": "在 Twitter 上分享", - "forum\/spam_wait": "請等待 {{count}} 秒後再發言.", - "forum\/stats": "統計", - "forum\/stick_topic": "置頂主題", - "forum\/subforum": "子論壇", - "forum\/subforums": "子論壇", - "forum\/table_view": "統計圖", - "forum\/title_max_64": "主題標題最低限制 64 字元", - "forum\/title_min_2": "主題標題最低限制 2 字元", - "forum\/title_required": "請輸入主題標題", - "forum\/topic": "主題", - "forum\/topic_locked": "主題鎖定", - "forum\/topic_locked_notice": "主題已鎖定,但是你的權限可以建立回覆.", - "forum\/topic_stuck": "文章已被置頂.", - "forum\/topic_title": "主題標題", - "forum\/topic_unstuck": "文章已被取消置頂.", - "forum\/topics": "主題", - "forum\/unlock_topic": "解鎖主題", - "forum\/unstick_topic": "取消置頂主題", - "forum\/use_reactions": "使用回應?", - "forum\/user_no_posts": "使用者尚未在論壇發布貼文.", - "forum\/user_tag": "你被標註在一則文章中.", - "forum\/user_tag_info": "你已被標註在 {{author}} 的文章中.", - "forum\/views": "觀看數", - "forum\/x_posts": "{{count}} posts", - "forum\/x_topics": "{{count}} topics" -} \ No newline at end of file + "forum/by": "by", + "forum/can_create_topic": "可以建立主題?", + "forum/can_edit_topic": "Can edit their topics?", + "forum/can_moderate_forum": "可以審核論壇?", + "forum/can_post_reply": "可以建立回覆?", + "forum/can_view_forum": "可以查看論壇?", + "forum/can_view_other_topics": "可以查看其他人的文章?", + "forum/confirm_delete_post": "確認移除文章?", + "forum/confirm_delete_short": "確認移除", + "forum/confirm_delete_topic": "確認移除主題?", + "forum/content_max_50000": "文章內容最高限制 50000 字元", + "forum/content_min_2": "文章內容最低限制 2 字元", + "forum/content_required": "請輸入文章內容", + "forum/creating_forum": "建立新論壇", + "forum/creating_label": "建立新標籤", + "forum/creating_label_type": "建立新標籤類型", + "forum/creating_topic_in_x": "在 {{forum}} 建立主題", + "forum/delete_forum": "移除論壇", + "forum/delete_topic": "移除主題", + "forum/delete_topics_and_posts": "移除主題和文章", + "forum/discussion": "討論串", + "forum/display_topics_as_news": "顯示此主題的文章在首頁?", + "forum/edit": "編輯", + "forum/edit_post": "編輯文章", + "forum/editing_label": "編輯標籤", + "forum/editing_label_type": "編輯標籤類型", + "forum/error_quoting_posts": "抱歉,引用文章時出了錯.", + "forum/error_rating_post": "抱歉,文章發生錯誤.", + "forum/forum": "論壇", + "forum/forum_created_successfully": "論壇建立成功.", + "forum/forum_description": "論壇說明", + "forum/forum_description_maximum": "論壇說明最高限制 255 字元.", + "forum/forum_description_minimum": "論壇說明最低限制 2 字元.", + "forum/forum_index": "首頁", + "forum/forum_layout": "論壇佈局", + "forum/forum_name": "論壇名稱", + "forum/forum_name_maximum": "論壇名稱最高限制 150 字元.", + "forum/forum_name_minimum": "論壇名稱最低限制 2 字元.", + "forum/forum_permissions": "論壇權限", + "forum/forum_search": "論壇搜尋", + "forum/forum_type": "論壇類型", + "forum/forum_type_category": "類別", + "forum/forum_type_forum": "論壇", + "forum/forums": "論壇", + "forum/group": "群組", + "forum/guests": "遊客", + "forum/has_no_parent": "沒有父論壇", + "forum/in": "in", + "forum/input_forum_description": "請輸入論壇說明.", + "forum/input_forum_title": "P請輸入論壇標題.", + "forum/insert_quotes": "Insert Quotes", + "forum/invalid_action": "無效操作", + "forum/invalid_search_query": "搜尋限制 3~128 字元.", + "forum/label": "標籤", + "forum/label_creation_error": "無法建立標籤. 請確認輸入的內容沒有超過 32 字元.", + "forum/label_creation_success": "標籤建立成功.", + "forum/label_edit_success": "標籤編輯成功.", + "forum/label_forums": "標籤論壇", + "forum/label_groups": "標籤群組", + "forum/label_name": "標籤名稱", + "forum/label_type": "標籤類型", + "forum/label_type_creation_error": "無法建立標籤類型. 請確認輸入的內容沒有超過 32 字元,HTML沒有超過 1024 字元.", + "forum/label_type_creation_success": "標籤類型建立成功.", + "forum/label_type_edit_success": "標籤類型編輯成功.", + "forum/label_type_html": "標籤類型HTML", + "forum/label_type_html_help": "標籤必須包含 {x} 做為標籤的佔位符", + "forum/label_type_name": "標籤類型名稱", + "forum/label_types": "標籤類型", + "forum/labels": "標籤", + "forum/last_edited": "最後編輯: {{lastEditedAt}}", + "forum/last_reply": "最後回覆", + "forum/latest_announcements": "最新公告", + "forum/latest_discussions": "最新的討論串", + "forum/latest_discussions_view": "最新的討論統計圖", + "forum/latest_posts": "最新文章", + "forum/lock_topic": "鎖定主題", + "forum/merge_instructions": "合併指令必須只能在一個論壇中. 如有必要請移動一整個線程.", + "forum/merge_topic": "合併主題", + "forum/merge_topics": "合併文章", + "forum/mod_actions": "審核", + "forum/move_topic": "移動主題", + "forum/move_topic_to": "移動主題至:", + "forum/move_topics_and_posts_to": "移動主題和文章到", + "forum/new_forum": " 新論壇", + "forum/new_label": " 新標籤", + "forum/new_label_type": " 新標籤類型", + "forum/new_reply": "新回覆", + "forum/new_search": "新搜尋", + "forum/new_topic": "新主題", + "forum/no_forums": "沒有論壇", + "forum/no_label": "沒有標籤", + "forum/no_label_types_defined": "無定義標籤類型.", + "forum/no_labels_defined": "無定義標籤.", + "forum/no_results_found": "找不到資料.", + "forum/no_topics": "沒有主題被建立.", + "forum/no_topics_short": "沒有主題", + "forum/no_users_online": "沒有使用者在線上.", + "forum/online_users": "線上使用者", + "forum/overview": "總覽", + "forum/parent_forum": "父論壇", + "forum/parent_forum_x": "Parent Forum: {{forum}}", + "forum/post_already_reported": "你已經回報過這篇文章!", + "forum/post_edited_successfully": "文章編輯成功.", + "forum/post_successful": "成功發文.", + "forum/posts": "文章", + "forum/quote": "引用", + "forum/quoted_post": "文章已新增至引用.", + "forum/quoting_posts": "插入引用..", + "forum/re": "RE: ", + "forum/read_full_post": "閱讀全部", + "forum/registered_x": "Joined: {{registeredAt}}", + "forum/removed_quoted_post": "文章已從引用中移除.", + "forum/search_again_in_x_seconds": "請等待 {{count}} 秒後再次搜尋.", + "forum/search_results": "搜尋結果", + "forum/select_a_parent_forum": "選擇父論壇", + "forum/share": "分享", + "forum/share_facebook": "在 Facebook 上分享", + "forum/share_twitter": "在 Twitter 上分享", + "forum/spam_wait": "請等待 {{count}} 秒後再發言.", + "forum/stats": "統計", + "forum/stick_topic": "置頂主題", + "forum/subforum": "子論壇", + "forum/subforums": "子論壇", + "forum/table_view": "統計圖", + "forum/title_max_64": "主題標題最低限制 64 字元", + "forum/title_min_2": "主題標題最低限制 2 字元", + "forum/title_required": "請輸入主題標題", + "forum/topic": "主題", + "forum/topic_locked": "主題鎖定", + "forum/topic_locked_notice": "主題已鎖定,但是你的權限可以建立回覆.", + "forum/topic_stuck": "文章已被置頂.", + "forum/topic_title": "主題標題", + "forum/topic_unstuck": "文章已被取消置頂.", + "forum/topics": "主題", + "forum/unlock_topic": "解鎖主題", + "forum/unstick_topic": "取消置頂主題", + "forum/use_reactions": "使用回應?", + "forum/user_no_posts": "使用者尚未在論壇發布貼文.", + "forum/user_tag": "你被標註在一則文章中.", + "forum/user_tag_info": "你已被標註在 {{author}} 的文章中.", + "forum/views": "觀看數", + "forum/x_posts": "{{count}} posts", + "forum/x_topics": "{{count}} topics", + "forum/all_topics_unfollowed": "所有主題已被取消訂閱。", + "forum/average_posts": "平均同戶貼文數", + "forum/default_labels": "預設標籤", + "forum/topic_reply": "回覆主題", + "forum/confirm_unfollow_all_topics": "是否確定取消訂閱所有標題?", + "forum/default_labels_info": "除非被在新增標題時被修改,這些會在論壇被安排到新的標題。同時Ctrl及按下按鈕以選擇多個選項", + "forum/follow": "追蹤", + "forum/following_topics": "已追蹤標題", + "forum/forum_deleted_successfully": "論壇已被刪除。", + "forum/forum_icon": "論壇圖案", + "forum/forum_icon_maximum": "論壇圖案必須為最多256字元數。", + "forum/forum_redirect_warning": "注意: 你準備離開此網頁! 是否確定要去 {{url}} ?", + "forum/forum_updated_successfully": "成功更新論壇。" +} From b471e8c9994bb3f8345c615994146d61205efa08 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Sun, 5 Jun 2022 23:12:55 -0600 Subject: [PATCH 042/337] Show error message during DB init if it does not succeed --- core/installation/steps/ajax_initialise.php | 9 ++++++--- core/installation/steps/database_initialization.php | 11 ++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/core/installation/steps/ajax_initialise.php b/core/installation/steps/ajax_initialise.php index ce4fb93130..f9a301bf7b 100644 --- a/core/installation/steps/ajax_initialise.php +++ b/core/installation/steps/ajax_initialise.php @@ -7,12 +7,15 @@ $redirect_url = (($_SESSION['action'] == 'install') ? '?step=site_configuration' : '?step=upgrade'); $json = [ - 'message' => defined('DEBUGGING') && DEBUGGING ? $message : $language->get('installer', 'database_configured'), - 'success' => $success, + 'message' => $language->get('installer', 'database_configured'), 'redirect_url' => $redirect_url, ]; - $_SESSION['database_initialized'] = true; + if (!str_contains($message, 'All Done')) { + $json['error'] = $message; + } else { + $_SESSION['database_initialized'] = true; + } } else { if ($_GET['initialise'] === 'site') { diff --git a/core/installation/steps/database_initialization.php b/core/installation/steps/database_initialization.php index b2c93ae262..ad44723105 100644 --- a/core/installation/steps/database_initialization.php +++ b/core/installation/steps/database_initialization.php @@ -15,13 +15,14 @@ if (response.success) { window.location.replace(response.redirect_url); } else { - $("#info").html(response.message); - if (response.redirect_url) { - $("#continue-button").attr("href", response.redirect_url); - $("#continue-button").removeClass("disabled"); - } if (response.error) { + $("#info").parent().attr("class", "ui red message"); + $("#info").html(response.error); $("#continue-button").before(""); + } else if (response.redirect_url) { + $("#info").html(response.message); + $("#continue-button").attr("href", response.redirect_url); + $("#continue-button").removeClass("disabled"); } } }); From 5683436a5eef0fd9a8015941697134721a905069 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Sun, 5 Jun 2022 23:17:54 -0600 Subject: [PATCH 043/337] Fix already installed check --- install.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.php b/install.php index e21ccf47f6..84b74e145c 100644 --- a/install.php +++ b/install.php @@ -43,7 +43,7 @@ // Get installation path $install_path = substr(str_replace('\\', '/', substr(__DIR__, strlen($_SERVER['DOCUMENT_ROOT']))), 1); -if (!isset($CONFIG['installed'])) { +if (isset($GLOBALS['config']['core'])) { if (isset($_GET['language'])) { // Set language if (is_file('custom/languages/' . $_GET['language'] . '.json')) { From 76ad8e83fd2b32cb6016a6036cc808b19bc1316e Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Sun, 5 Jun 2022 23:18:49 -0600 Subject: [PATCH 044/337] Fix already installed check --- install.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.php b/install.php index 84b74e145c..9e48defdab 100644 --- a/install.php +++ b/install.php @@ -43,7 +43,7 @@ // Get installation path $install_path = substr(str_replace('\\', '/', substr(__DIR__, strlen($_SERVER['DOCUMENT_ROOT']))), 1); -if (isset($GLOBALS['config']['core'])) { +if (!isset($GLOBALS['config']['core'])) { if (isset($_GET['language'])) { // Set language if (is_file('custom/languages/' . $_GET['language'] . '.json')) { From db77317b960aa1d7dfc0253788d2ed96ed788c90 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Sun, 5 Jun 2022 23:26:10 -0600 Subject: [PATCH 045/337] Fix already installed check (actually) --- core/installation/steps/finish.php | 2 +- install.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/installation/steps/finish.php b/core/installation/steps/finish.php index 194da23803..018b009fac 100644 --- a/core/installation/steps/finish.php +++ b/core/installation/steps/finish.php @@ -9,7 +9,7 @@ if (!is_writable('core/config.php')) { $error = $language->get('installer', 'config_not_writable'); } else { - file_put_contents('core/config.php', PHP_EOL . '$CONFIG[\'installed\'] = true;', FILE_APPEND); + Config::set('core/installed', true); } unset($_SESSION['admin_setup'], $_SESSION['database_initialized'], $_SESSION['site_initialized']); diff --git a/install.php b/install.php index 9e48defdab..dc6eb1ad0f 100644 --- a/install.php +++ b/install.php @@ -43,7 +43,7 @@ // Get installation path $install_path = substr(str_replace('\\', '/', substr(__DIR__, strlen($_SERVER['DOCUMENT_ROOT']))), 1); -if (!isset($GLOBALS['config']['core'])) { +if (!isset($GLOBALS['config']['core']['installed'])) { if (isset($_GET['language'])) { // Set language if (is_file('custom/languages/' . $_GET['language'] . '.json')) { From 254202989b881cb64693059a9b5c24a6bf86d9c5 Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 6 Jun 2022 13:52:47 +0200 Subject: [PATCH 046/337] Rename PHPMailer option to better explain what it does --- custom/languages/en_UK.json | 2 +- modules/Core/pages/panel/emails.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/custom/languages/en_UK.json b/custom/languages/en_UK.json index 9faefc913e..1f102d1b4c 100644 --- a/custom/languages/en_UK.json +++ b/custom/languages/en_UK.json @@ -194,7 +194,7 @@ "admin/enable_api": "Enable API?", "admin/enable_authme": "Enable AuthMe integration?", "admin/enable_debug_mode": "Enable debug mode?", - "admin/enable_mailer": "Enable PHPMailer?", + "admin/use_external_mail_server": "Use external mail server", "admin/enable_mailer_help": "If enabled, emails will be sent using PHPMailer instead of the system default. This may help with delivery, but requires you to configure an SMTP provider. {{docLinkStart}}Read more »{{docLinkEnd}}", "admin/enable_maintenance_mode": "Enable maintenance mode?", "admin/enable_minecraft_integration": "Enable Minecraft integration?", diff --git a/modules/Core/pages/panel/emails.php b/modules/Core/pages/panel/emails.php index ca77a0c212..f4f59788c6 100644 --- a/modules/Core/pages/panel/emails.php +++ b/modules/Core/pages/panel/emails.php @@ -248,7 +248,7 @@ 'SEND_TEST_EMAIL_LINK' => URL::build('/panel/core/emails/', 'action=test'), 'EMAIL_ERRORS' => $language->get('admin', 'email_errors'), 'EMAIL_ERRORS_LINK' => URL::build('/panel/core/emails/errors'), - 'ENABLE_MAILER' => $language->get('admin', 'enable_mailer'), + 'ENABLE_MAILER' => $language->get('admin', 'use_external_mail_server'), 'ENABLE_MAILER_VALUE' => Util::getSetting('phpmailer'), 'INFO' => $language->get('general', 'info'), 'ENABLE_MAILER_HELP' => $language->get('admin', 'enable_mailer_help', [ From 2a2c3ddda5e8217187a0163822d9cfa8736048a5 Mon Sep 17 00:00:00 2001 From: Partydragen Date: Mon, 6 Jun 2022 19:57:45 +0200 Subject: [PATCH 047/337] Fix selected images --- modules/Core/pages/panel/images.php | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/Core/pages/panel/images.php b/modules/Core/pages/panel/images.php index c803524a17..6acae755a4 100644 --- a/modules/Core/pages/panel/images.php +++ b/modules/Core/pages/panel/images.php @@ -104,6 +104,7 @@ } // Get banner from cache +$cache->setCache('backgroundcache'); if (!$cache->isCached('banner_image')) { $cache->store('banner_image', (defined('CONFIG_PATH') ? CONFIG_PATH : '') . '/uploads/template_banners/homepage_bg_trimmed.jpg'); $banner_image = (defined('CONFIG_PATH') ? CONFIG_PATH : '') . '/uploads/template_banners/homepage_bg_trimmed.jpg'; From 0aeea02a2b46315640914d8e88fa2ba996101598 Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 6 Jun 2022 22:50:21 +0200 Subject: [PATCH 048/337] Remove email verification setting from API page --- custom/panel_templates/Default/core/api.tpl | 9 +-------- modules/Core/pages/panel/api.php | 6 ------ 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/custom/panel_templates/Default/core/api.tpl b/custom/panel_templates/Default/core/api.tpl index 5f0d0af23b..fb671e0276 100644 --- a/custom/panel_templates/Default/core/api.tpl +++ b/custom/panel_templates/Default/core/api.tpl @@ -81,13 +81,6 @@
-
- - -
-
@@ -177,4 +170,4 @@ - \ No newline at end of file + diff --git a/modules/Core/pages/panel/api.php b/modules/Core/pages/panel/api.php index 02f22d635d..c8c372d613 100644 --- a/modules/Core/pages/panel/api.php +++ b/modules/Core/pages/panel/api.php @@ -60,10 +60,6 @@ ] ); - // Update email verification - $verification = isset($_POST['verification']) && $_POST['verification'] == 'on' ? '1' : '0'; - Util::setSetting('email_verification', $verification); - // Update Username sync $username_sync = isset($_POST['username_sync']) && $_POST['username_sync'] == 'on' ? '1' : '0'; Util::setSetting('username_sync', $username_sync); @@ -240,8 +236,6 @@ 'API_URL_VALUE' => rtrim(Util::getSelfURL(), '/') . rtrim(URL::build('/api/v2/', '', 'non-friendly'), '/'), 'ENABLE_API_FOR_URL' => $language->get('admin', 'api_disabled'), 'COPY' => $language->get('admin', 'copy'), - 'EMAIL_VERIFICATION' => $language->get('admin', 'email_verification'), - 'EMAIL_VERIFICATION_VALUE' => Util::getSetting('email_verification') === '1', 'USERNAME_SYNC' => $language->get('admin', 'enable_username_sync'), 'USERNAME_SYNC_INFO' => $language->get('admin', 'enable_username_sync_info'), 'USERNAME_SYNC_VALUE' => Util::getSetting('username_sync') === '1', From ddaf1682882cd98ccb907874bb57296530c148fa Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 6 Jun 2022 22:53:01 +0200 Subject: [PATCH 049/337] Explain that username sync requires the in-game plugin --- custom/languages/en_UK.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom/languages/en_UK.json b/custom/languages/en_UK.json index 1f102d1b4c..c3498c7975 100644 --- a/custom/languages/en_UK.json +++ b/custom/languages/en_UK.json @@ -205,7 +205,7 @@ "admin/enable_registration": "Enable registration?", "admin/enable_status_query": "Enable status query?", "admin/enable_username_sync": "Enable username sync?", - "admin/enable_username_sync_info": "If enabled, website usernames will be updated to match in-game usernames.", + "admin/enable_username_sync_info": "If enabled, website usernames will be updated to match in-game usernames. This happens when the in-game plugin sends a list of UUIDs and usernames, for online players, to the website.", "admin/enabled": "Enabled", "admin/enter_authme_db_details": "Please enter valid database details.", "admin/error_deleted_successfully": "The error has been deleted successfully.", From 2d6befd1b94e1e1ffcb05eb9fc435b6186b83800 Mon Sep 17 00:00:00 2001 From: Bram Standaert Date: Mon, 6 Jun 2022 10:53:35 +0000 Subject: [PATCH 050/337] Translated using Weblate (Dutch) Currently translated at 99.9% (1220 of 1221 strings) Translation: NamelessMC/Website - Core Translate-URL: https://translate.namelessmc.com/projects/namelessmc/nameless/nl/ --- custom/languages/nl_NL.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom/languages/nl_NL.json b/custom/languages/nl_NL.json index c3a8c2d1b4..7a2e52b035 100644 --- a/custom/languages/nl_NL.json +++ b/custom/languages/nl_NL.json @@ -743,7 +743,7 @@ "installer/continue": "Doorgaan", "installer/convert": "Converteer", "installer/convert_message": "Tot slot, wil je data overzetten van een ander forum software?", - "installer/converter": "Converter", + "installer/converter": "Converteer", "installer/creating_admin_account": "Admin account maken", "installer/credits": "Credits", "installer/credits_message": "Een grote dank aan alle NamelessMC bijdragers sinds 2014: {{contribLinkStart}}NamelessMC contributors{{contribLinkEnd}}", From 01b6ea6e9b98bb55598f84c9b6f8b11e4935e0af Mon Sep 17 00:00:00 2001 From: namelessmc-bot Date: Mon, 6 Jun 2022 11:52:56 +0000 Subject: [PATCH 051/337] Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: NamelessMC/Website - Core Translate-URL: https://translate.namelessmc.com/projects/namelessmc/nameless/ --- custom/languages/cs_CZ.json | 1 - custom/languages/de_DE.json | 1 - custom/languages/en_US.json | 1 - custom/languages/es_419.json | 1 - custom/languages/es_ES.json | 1 - custom/languages/fr_FR.json | 1 - custom/languages/it_IT.json | 1 - custom/languages/ja_JP.json | 1 - custom/languages/lt_LT.json | 1 - custom/languages/nl_NL.json | 1 - custom/languages/no_NO.json | 1 - custom/languages/pl_PL.json | 1 - custom/languages/pt_BR.json | 1 - custom/languages/ro_RO.json | 1 - custom/languages/ru_RU.json | 1 - custom/languages/sk_SK.json | 1 - custom/languages/sv_SE.json | 1 - custom/languages/th_TH.json | 1 - custom/languages/tr_TR.json | 1 - custom/languages/uk_UA.json | 1 - custom/languages/zh_CN.json | 1 - custom/languages/zh_TW.json | 1 - 22 files changed, 22 deletions(-) diff --git a/custom/languages/cs_CZ.json b/custom/languages/cs_CZ.json index 5ea78c2d91..e0c7c7cc4b 100644 --- a/custom/languages/cs_CZ.json +++ b/custom/languages/cs_CZ.json @@ -181,7 +181,6 @@ "admin/enable_api": "Povolit API?", "admin/enable_authme": "Povolit integraci AuthMe?", "admin/enable_debug_mode": "Povolit režim ladění?", - "admin/enable_mailer": "Povolit PHPMailer?", "admin/enable_mailer_help": "Pokud je povoleno, budou e-maily odesílány pomocí PHPMaileru místo výchozí služby systému. Může to pomoci s doručením, ale vyžaduje to nastavení poskytovatele SMTP. {{docLinkStart}}Zjistit více »{{docLinkEnd}}", "admin/enable_maintenance_mode": "Povolit režim údržby?", "admin/enable_minecraft_integration": "Povolit integraci Minecraftu?", diff --git a/custom/languages/de_DE.json b/custom/languages/de_DE.json index 5640c0a319..18b9b35b67 100644 --- a/custom/languages/de_DE.json +++ b/custom/languages/de_DE.json @@ -173,7 +173,6 @@ "admin/enable_api": "API aktivieren?", "admin/enable_authme": "Aktiviere AuthMe Integration?", "admin/enable_debug_mode": "Aktiviere den Fehlerbenachrichtungs Modus?", - "admin/enable_mailer": "Aktiviere PHPMailer?", "admin/enable_mailer_help": "Wenn diese Option aktiviert ist, werden E-Mails mit PHPMailer anstelle der Systemvorgabe gesendet. Dies kann bei der Zustellung helfen, erfordert aber die Konfiguration eines SMTP-Providers. {{docLinkStart}}Weiterlesen \"{{docLinkEnd}}", "admin/enable_maintenance_mode": "Wartungsmodus aktivieren?", "admin/enable_minecraft_integration": "Minecraft Integration aktivieren?", diff --git a/custom/languages/en_US.json b/custom/languages/en_US.json index efb03e7ed6..e1f001f4be 100644 --- a/custom/languages/en_US.json +++ b/custom/languages/en_US.json @@ -184,7 +184,6 @@ "admin/enable_api": "Enable API?", "admin/enable_authme": "Enable AuthMe integration?", "admin/enable_debug_mode": "Enable debug mode?", - "admin/enable_mailer": "Enable PHPMailer?", "admin/enable_mailer_help": "If enabled, emails will be sent using PHPMailer instead of the system default. This may help with delivery, but requires you to configure an SMTP provider. {{docLinkStart}}Read more »{{docLinkEnd}}", "admin/enable_maintenance_mode": "Enable maintenance mode?", "admin/enable_minecraft_integration": "Enable Minecraft integration?", diff --git a/custom/languages/es_419.json b/custom/languages/es_419.json index 82164c30f2..bcc002240c 100644 --- a/custom/languages/es_419.json +++ b/custom/languages/es_419.json @@ -176,7 +176,6 @@ "admin/enable_api": "¿Habilitar la API?", "admin/enable_authme": "¿Habilitar la integración con AuthMe?", "admin/enable_debug_mode": "¿Habilitar modo de depuración?", - "admin/enable_mailer": "¿Habilitar PHPMailer?", "admin/enable_mailer_help": "Habilite esto si los correos electrónicos no están siendo enviados por defecto. El uso de PHPMailer requiere tener un servicio capaz de enviar correos electrónicos, como Gmail o un proveedor SMTP. ", "admin/enable_maintenance_mode": "¿Activar el modo de mantenimiento?", "admin/enable_minecraft_integration": "¿Permitir la integración de Minecraft?", diff --git a/custom/languages/es_ES.json b/custom/languages/es_ES.json index bb1aec710b..aae29e8d36 100644 --- a/custom/languages/es_ES.json +++ b/custom/languages/es_ES.json @@ -181,7 +181,6 @@ "admin/enable_api": "¿Activar la API?", "admin/enable_authme": "¿Activar la integración de AuthMe?", "admin/enable_debug_mode": "¿Activar el modo de depuración?", - "admin/enable_mailer": "¿Activar PHPMailer?", "admin/enable_mailer_help": "Si se activa, los correos electrónicos se enviarán utilizando PHPMailer en lugar del sistema por defecto. Esto puede ayudar a la entrega, pero requiere que se configure un proveedor SMTP. {{docLinkStart}}Leer más »{{docLinkEnd}}", "admin/enable_maintenance_mode": "¿Activar el modo de mantenimiento?", "admin/enable_minecraft_integration": "¿Permitir la integración de Minecraft?", diff --git a/custom/languages/fr_FR.json b/custom/languages/fr_FR.json index eadb8ac48a..1b5904ef68 100644 --- a/custom/languages/fr_FR.json +++ b/custom/languages/fr_FR.json @@ -154,7 +154,6 @@ "admin/enable_api": "Activer l'API ?", "admin/enable_authme": "Activer l’intégration AuthMe?", "admin/enable_debug_mode": "Activer le mode de débogage ?", - "admin/enable_mailer": "Activer PHPMailer ?", "admin/enable_mailer_help": "Activez ceci si les e-mails ne sont pas envoyés par défaut. L’utilisation de PHPMailer nécessite que vous ayez un service capable d’envoyer des courriels, comme Gmail ou un fournisseur SMTP.", "admin/enable_maintenance_mode": "Activer le mode de maintenance?", "admin/enable_minecraft_integration": "Activer l’intégration de Minecraft?", diff --git a/custom/languages/it_IT.json b/custom/languages/it_IT.json index 5bfc64f28c..ca2e0edd63 100644 --- a/custom/languages/it_IT.json +++ b/custom/languages/it_IT.json @@ -167,7 +167,6 @@ "admin/enable_api": "Abilitare l'API?", "admin/enable_authme": "Abilitare l'integrazione con AuthMe?", "admin/enable_debug_mode": "Abilitare la modalità debug?", - "admin/enable_mailer": "Abilitare PHPMailer?", "admin/enable_mailer_help": "Abilitalo se le email non vengono inviate di default. L'uso di PHPMailer richiede che tu abbia un servizio capace di inviare email, come Gmail o un provider SMTP.", "admin/enable_maintenance_mode": "Abilita la modalità di manutenzione?", "admin/enable_minecraft_integration": "Abilitare l'integrazione con Minecraft?", diff --git a/custom/languages/ja_JP.json b/custom/languages/ja_JP.json index 5535ded9ff..8765d7370a 100644 --- a/custom/languages/ja_JP.json +++ b/custom/languages/ja_JP.json @@ -184,7 +184,6 @@ "admin/enable_api": "APIを有効にしますか?", "admin/enable_authme": "AuthMe 連携を有効にしますか?", "admin/enable_debug_mode": "デバッグモードを有効にしますか?", - "admin/enable_mailer": "PHPMailerを有効にしますか?", "admin/enable_mailer_help": "有効にすると、システムのデフォルトではなくPHPMailerを使ってメールを送信するようになります。これはメール配信の助けになるかもしれませんが、SMTP プロバイダを設定する必要があります。{{docLinkStart}}続きを読む »{{docLinkEnd}}", "admin/enable_maintenance_mode": "メンテナンスモードを有効にしますか?", "admin/enable_minecraft_integration": "Minecraft連携を有効にしますか?", diff --git a/custom/languages/lt_LT.json b/custom/languages/lt_LT.json index 56b6642ac2..8bd3e4adc7 100644 --- a/custom/languages/lt_LT.json +++ b/custom/languages/lt_LT.json @@ -129,7 +129,6 @@ "admin/enable_api": "Įjungti API?", "admin/enable_authme": "Įjungti AuthMe integraciją?", "admin/enable_debug_mode": "Įjungti derinimo režimą?", - "admin/enable_mailer": "Įjungti PHPMailer?", "admin/enable_mailer_help": "Įjunkite tai, jei el. Laiškai nebus siunčiami pagal numatytuosius nustatymus. Naudojant PHPMailer reikia turėti paslaugą, galinčią siųsti el. Laiškus, pvz., \"Gmail\" ar SMTP teikėją.", "admin/enable_maintenance_mode": "Įjungti priežiūros režimą?", "admin/enable_minecraft_integration": "Įjungti Minecraft integraciją?", diff --git a/custom/languages/nl_NL.json b/custom/languages/nl_NL.json index 7a2e52b035..6d86bc750a 100644 --- a/custom/languages/nl_NL.json +++ b/custom/languages/nl_NL.json @@ -175,7 +175,6 @@ "admin/enable_api": "API aanzetten?", "admin/enable_authme": "AuthMe integratie aanzetten?", "admin/enable_debug_mode": "Wil je debug modus inschakelen?", - "admin/enable_mailer": "PHPMailer inschakelen?", "admin/enable_mailer_help": "Als dit aanstaat, worden e-mails verzonden met PHPMailer in plaats van de standaard van het system. Dit zou kunnen helpen met het verzenden van e-mails maar vereist wel dat je een SMTP aanbieder configureert. {{docLinkStart}}Lees meer »{{docLinkEnd}}", "admin/enable_maintenance_mode": "Wil je onderhoud modus inschakelen?", "admin/enable_minecraft_integration": "Minecraft integratie inschakelen?", diff --git a/custom/languages/no_NO.json b/custom/languages/no_NO.json index cab9aba81d..d157ff3d3c 100644 --- a/custom/languages/no_NO.json +++ b/custom/languages/no_NO.json @@ -167,7 +167,6 @@ "admin/enable_api": "Aktiver API?", "admin/enable_authme": "Aktiver AuthMe-integrasjon", "admin/enable_debug_mode": "Tillatt feilsøkingsmodus?", - "admin/enable_mailer": "Aktiver PHPMailer?", "admin/enable_mailer_help": "Aktiver denne funksjonen hvis e-postene ikke blir sendt automatisk. Bruk av PHPMailer krever at du har tilgang til for eksempel Gmail eller en annen e-postleverandør som støtter SMTP.", "admin/enable_maintenance_mode": "Aktiver vedlikeholdsmodus?", "admin/enable_minecraft_integration": "Aktiver Minecraft-integrasjon", diff --git a/custom/languages/pl_PL.json b/custom/languages/pl_PL.json index a940788305..6067d66314 100644 --- a/custom/languages/pl_PL.json +++ b/custom/languages/pl_PL.json @@ -176,7 +176,6 @@ "admin/enable_api": "Włączyć API?", "admin/enable_authme": "Włączyć integrację AuthMe?", "admin/enable_debug_mode": "Włączyć tryb debugowania?", - "admin/enable_mailer": "Użyć PHPMailera?", "admin/enable_mailer_help": "Włącz tą funkcję jeśli emaile nie są wysyłane przy domyślnej konfiguracji. Korzystanie z PHPMailer wymaga posiadania usługi umożliwiającej wysyłanie wiadomości e-mail, takich jak Gmail lub dostawca SMTP.", "admin/enable_maintenance_mode": "Włączyć tryb konserwacji?", "admin/enable_minecraft_integration": "Włączyć integrację minecraft?", diff --git a/custom/languages/pt_BR.json b/custom/languages/pt_BR.json index 642c14a869..19c15def13 100644 --- a/custom/languages/pt_BR.json +++ b/custom/languages/pt_BR.json @@ -180,7 +180,6 @@ "admin/enable_api": "Ativar a API?", "admin/enable_authme": "Ativar a integração com o AuthMe?", "admin/enable_debug_mode": "Habilitar o modo de depuração?", - "admin/enable_mailer": "Ativar o PHPMailer?", "admin/enable_mailer_help": "Habilite isso se os emails não estiverem sendo enviados por padrão. O uso de PHPMailer exige que você tenha um serviço capaz de enviar emails, como o Gmail ou um provedor SMTP.", "admin/enable_maintenance_mode": "Habilitar modo de manutenção?", "admin/enable_minecraft_integration": "Ativar a integração do Minecraft?", diff --git a/custom/languages/ro_RO.json b/custom/languages/ro_RO.json index 8bb52654e9..aaac72913f 100644 --- a/custom/languages/ro_RO.json +++ b/custom/languages/ro_RO.json @@ -127,7 +127,6 @@ "admin/enable_api": "Activare API?", "admin/enable_authme": "Activați integrarea AuthMe?", "admin/enable_debug_mode": "Activați modul de depanare?", - "admin/enable_mailer": "Activati PHPMailer?", "admin/enable_mailer_help": "Activați această opțiune dacă e-mailurile nu sunt trimise în mod implicit. Utilizarea programului PHPMailer necesită un serviciu care să poată trimite e-mailuri, cum ar fi Gmail sau un furnizor SMTP.", "admin/enable_maintenance_mode": "Activați modul de întreținere?", "admin/enable_minecraft_integration": "Activați integrarea Minecraft?", diff --git a/custom/languages/ru_RU.json b/custom/languages/ru_RU.json index a71cc49002..04a100bc87 100644 --- a/custom/languages/ru_RU.json +++ b/custom/languages/ru_RU.json @@ -184,7 +184,6 @@ "admin/enable_api": "Включить API?", "admin/enable_authme": "Включить интеграцию с AuthMe?", "admin/enable_debug_mode": "Включить режим отладки?", - "admin/enable_mailer": "Включить PHPMailer?", "admin/enable_mailer_help": "Если включено, письма будут отправлены с помощью PHPMailer вместо системы по умолчанию. Это может помочь с отправкой, но требует вашу настройку SMTP провайдера. {{docLinkStart}}Прочитать больше »{{docLinkEnd}}", "admin/enable_maintenance_mode": "Включить режим обслуживания?", "admin/enable_minecraft_integration": "Включить интеграцию с Minecraft?", diff --git a/custom/languages/sk_SK.json b/custom/languages/sk_SK.json index 1aa1a50567..3d2951bf22 100644 --- a/custom/languages/sk_SK.json +++ b/custom/languages/sk_SK.json @@ -182,7 +182,6 @@ "admin/enable_api": "Povoliť API?", "admin/enable_authme": "Povoliť AuthMe integráciu?", "admin/enable_debug_mode": "Povoliť debug mód?", - "admin/enable_mailer": "Povoliť PHPMailer?", "admin/enable_mailer_help": "Túto možnosť povoľte, ak sa emaily predvolene neposielajú. Používanie PHPMaileru vyžaduje, aby ste mali službu schopnú odosielať emaily, napríklad Gmail alebo SMTP poskytovateľ.", "admin/enable_maintenance_mode": "Povoliť režim údržby?", "admin/enable_minecraft_integration": "Povoliť Minecraft integráciu?", diff --git a/custom/languages/sv_SE.json b/custom/languages/sv_SE.json index 910632cdd1..363c82d053 100644 --- a/custom/languages/sv_SE.json +++ b/custom/languages/sv_SE.json @@ -166,7 +166,6 @@ "admin/enable_api": "Aktivera API?", "admin/enable_authme": "Aktivera AuthMe integration?", "admin/enable_debug_mode": "Aktivera debug-läge?", - "admin/enable_mailer": "Aktivera PHPMailer?", "admin/enable_mailer_help": "Aktivera det här om e-postmeddelanden inte skickas som standard. Användningen av PHPMailer kräver att du har en tjänst som kan skicka e-postmeddelanden, till exempel Gmail eller en SMTP-leverantör.", "admin/enable_maintenance_mode": "Aktivera uppbyggnadsläge?", "admin/enable_minecraft_integration": "Aktivera Minecraft Integration?", diff --git a/custom/languages/th_TH.json b/custom/languages/th_TH.json index 70067ba589..f6025aa808 100644 --- a/custom/languages/th_TH.json +++ b/custom/languages/th_TH.json @@ -173,7 +173,6 @@ "admin/enable_api": "เปิดใช้งาน API?", "admin/enable_authme": "เปิดใช้งาน AuthMe integration หรือไม่", "admin/enable_debug_mode": "เปิดใช้งานโหมดดีบักหรือไม่", - "admin/enable_mailer": "เปิดใช้งาน PHPMailer หรือไม่", "admin/enable_mailer_help": "เปิดใช้งานสิ่งนี้หากอีเมลไม่ได้ถูกส่งตามค่าเริ่มต้น การใช้ PHPMailer กําหนดให้คุณต้องมีบริการที่สามารถส่งอีเมลเช่น Gmail หรือผู้ให้บริการ SMTP", "admin/enable_maintenance_mode": "เปิดใช้งานโหมดปรับปรุงไหม", "admin/enable_minecraft_integration": "เปิดใช้งานการรวม Minecraft หริอไหม่", diff --git a/custom/languages/tr_TR.json b/custom/languages/tr_TR.json index 8d08c5bc06..ec1e69c2c6 100644 --- a/custom/languages/tr_TR.json +++ b/custom/languages/tr_TR.json @@ -135,7 +135,6 @@ "admin/enable_api": "API etkinleştirilsin mi?", "admin/enable_authme": "AuthMe entegrasyonu etkinleştirilsin mi?", "admin/enable_debug_mode": "Hata ayıklama modu etkinleştirilsin mi?", - "admin/enable_mailer": "PHPMailer etkinleştirilsin mi?", "admin/enable_mailer_help": "Varsayılan olarak e-postalar gönderilmiyorsa bunu etkinleştirin. PHPMailer kullanımı için Gmail veya SMTP sağlayıcısı gibi e-posta gönderebilecek bir hizmetinizin olması gerekir.", "admin/enable_maintenance_mode": "Bakım modu etkinleştirilsin mi?", "admin/enable_minecraft_integration": "Minecraft entegrasyonu etkinleştirilsin mi?", diff --git a/custom/languages/uk_UA.json b/custom/languages/uk_UA.json index 9c02936a68..afcf39ce09 100644 --- a/custom/languages/uk_UA.json +++ b/custom/languages/uk_UA.json @@ -177,7 +177,6 @@ "admin/enable_api": "Увімкнути API?", "admin/enable_authme": "Увімкнути інтеграцію із AuthMe?", "admin/enable_debug_mode": "Увімкнути режим відладки?", - "admin/enable_mailer": "Увімкнути PHPMailer?", "admin/enable_mailer_help": "Увімкніть цю функцію, якщо електронні листи не надсилаються за замовчуванням. Використання PHPMailer вимагає наявності служби, здатної надсилати електронні листи, наприклад, Gmail або SMTP-провайдера.", "admin/enable_maintenance_mode": "Увімкнути режим обслуговування?", "admin/enable_minecraft_integration": "Увімкнути інтеграцію з Minecraft?", diff --git a/custom/languages/zh_CN.json b/custom/languages/zh_CN.json index ff06f9997f..2736a69ebd 100644 --- a/custom/languages/zh_CN.json +++ b/custom/languages/zh_CN.json @@ -179,7 +179,6 @@ "admin/enable_api": "是否启用 API?", "admin/enable_authme": "是否启用 AuthMe 集成?", "admin/enable_debug_mode": "是否启用调试模式?", - "admin/enable_mailer": "是否启用 PHPMailer?", "admin/enable_mailer_help": "如果默认情况下无法发送电子邮件,请启用此功能。使用 PHPMailer 要求您具有能够发送电子邮件的服务,例如 Gmail 或 SMTP 提供程序。", "admin/enable_maintenance_mode": "是否启用维护模式?", "admin/enable_minecraft_integration": "是否启用 Minecraft 集成?", diff --git a/custom/languages/zh_TW.json b/custom/languages/zh_TW.json index 81b0e51d5b..1f14677a66 100644 --- a/custom/languages/zh_TW.json +++ b/custom/languages/zh_TW.json @@ -81,7 +81,6 @@ "admin/enable": "啟用", "admin/enable_authme": "啟用 AuthMe 連結?", "admin/enable_debug_mode": "啟用除錯模式?", - "admin/enable_mailer": "使用 PHPMailer?", "admin/enable_mailer_help": "如果電子郵件無法成功發送請啟用PHPMailer,將讓您可以正常地發送郵件,例如: Google的SMTP。", "admin/enable_maintenance_mode": "啟用維護模式?", "admin/enable_minecraft_integration": "啟用 Minecraft 連結?", From 1263f10c3dad83bd046e1989d1e61c8403e93290 Mon Sep 17 00:00:00 2001 From: Supercrafter100 Date: Mon, 6 Jun 2022 16:34:58 +0000 Subject: [PATCH 052/337] Translated using Weblate (Dutch) Currently translated at 100.0% (1221 of 1221 strings) Translation: NamelessMC/Website - Core Translate-URL: https://translate.namelessmc.com/projects/namelessmc/nameless/nl/ --- custom/languages/nl_NL.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/custom/languages/nl_NL.json b/custom/languages/nl_NL.json index 6d86bc750a..bb81fa8b90 100644 --- a/custom/languages/nl_NL.json +++ b/custom/languages/nl_NL.json @@ -1217,5 +1217,7 @@ "admin/test_email_suggest_2": "Update je site zijn DNS records (check SPF & DKIM).", "admin/test_email_suggest_3": "Configureer een SMTP server. {{docLinkStart}}Lees meer »{{docLinkEnd}}", "installer/upgrade_error": "Er zijn fouten ontstaan tijdens het upgraden.", - "admin/custom_content": "Aangepaste Inhoud" + "admin/custom_content": "Aangepaste Inhoud", + "general/deleted_user": "Verwijderde gebruiker", + "admin/use_external_mail_server": "Gebruik externe mail server" } From fddbe841fc24fd5be23f761eddcf1fa412d9e447 Mon Sep 17 00:00:00 2001 From: PadowYT2 Date: Mon, 6 Jun 2022 16:48:11 +0000 Subject: [PATCH 053/337] Translated using Weblate (Russian) Currently translated at 100.0% (1221 of 1221 strings) Translation: NamelessMC/Website - Core Translate-URL: https://translate.namelessmc.com/projects/namelessmc/nameless/ru/ --- custom/languages/ru_RU.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/custom/languages/ru_RU.json b/custom/languages/ru_RU.json index 04a100bc87..6fb82772c4 100644 --- a/custom/languages/ru_RU.json +++ b/custom/languages/ru_RU.json @@ -1217,5 +1217,7 @@ "admin/test_email_suggest_3": "Настройте SMTP сервер. {{docLinkStart}}Прочитать больше »{{docLinkEnd}}", "installer/database_configured": "Датабаза была настроена.", "installer/upgrade_error": "Произошли ошибки при обновлении.", - "admin/debug_link_info": "Важно - только делитесь этой ссылкой с людьми которыми вы доверяете!" + "admin/debug_link_info": "Важно - только делитесь этой ссылкой с людьми которыми вы доверяете!", + "general/deleted_user": "Удаленный Пользователь", + "admin/use_external_mail_server": "Использовать внешний почтовый сервер" } From 4a7d3a6411afca213f78e27c3ca52cf134e20eb4 Mon Sep 17 00:00:00 2001 From: enno123 Date: Mon, 6 Jun 2022 20:48:23 +0000 Subject: [PATCH 054/337] Translated using Weblate (German) Currently translated at 100.0% (1221 of 1221 strings) Translation: NamelessMC/Website - Core Translate-URL: https://translate.namelessmc.com/projects/namelessmc/nameless/de/ --- custom/languages/de_DE.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/custom/languages/de_DE.json b/custom/languages/de_DE.json index 18b9b35b67..cb73df605c 100644 --- a/custom/languages/de_DE.json +++ b/custom/languages/de_DE.json @@ -1217,5 +1217,7 @@ "admin/test_email_suggest_1": "Warte ein paar Minuten und überprüfe deinen Spam-Ordner.", "admin/test_email_suggest_2": "Aktualisiere die DNS-Einträge deiner Website (prüfe SPF und DKIM).", "admin/test_email_suggest_3": "Einen SMTP-Server einrichten. {{docLinkStart}}Weiterlesen \"{{docLinkEnd}}", - "admin/debug_link_info": "Wichtig - teile diesen Link nur mit Personen, denen du vertraust!" + "admin/debug_link_info": "Wichtig - teile diesen Link nur mit Personen, denen du vertraust!", + "general/deleted_user": "Gelöschte Benutzer", + "admin/use_external_mail_server": "Externen Mailserver verwenden" } From 99d16db49d9d988c4492643573f8b93d8dc0338a Mon Sep 17 00:00:00 2001 From: Robin Date: Wed, 8 Jun 2022 09:38:44 +0200 Subject: [PATCH 055/337] Use Util::getProtocol, move autoload #2828 --- core/init.php | 3 --- index.php | 13 ++++++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/core/init.php b/core/init.php index fdab433ad6..a0092b4901 100644 --- a/core/init.php +++ b/core/init.php @@ -9,9 +9,6 @@ * Initialisation file */ -require_once ROOT_PATH . '/vendor/autoload.php'; -require_once ROOT_PATH . '/core/includes/constants/autoload.php'; - // Nameless error handling set_exception_handler([ErrorHandler::class, 'catchException']); // catchError() used for throw_error or any exceptions which may be missed by catchException() diff --git a/index.php b/index.php index 5a5fed726f..b7c02a5934 100644 --- a/index.php +++ b/index.php @@ -29,6 +29,9 @@ die('NamelessMC is not compatible with PHP versions older than 7.4'); } +// Start page load timer +define('PAGE_START_TIME', microtime(true)); + if (!is_dir(__DIR__ . '/vendor') || !is_dir(__DIR__ . '/core/assets/vendor')) { die( "Your installation is missing the 'vendor' or 'core/assets/vendor' directory. These directories are included in @@ -39,12 +42,12 @@ ); } -// Start page load timer -define('PAGE_START_TIME', microtime(true)); - -// Definitions const PATH = '/'; const ROOT_PATH = __DIR__; + +require_once __DIR__ . '/vendor/autoload.php'; +require_once __DIR__ . '/core/includes/constants/autoload.php'; + $page = 'Home'; if (!ini_get('upload_tmp_dir')) { @@ -53,7 +56,7 @@ $tmp_dir = ini_get('upload_tmp_dir'); } -if ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) { +if (Util::getProtocol() === 'https') { ini_set('session.cookie_secure', 'On'); } From 1e007bebe87b4a0aa20216b150b9e9b72add4ac0 Mon Sep 17 00:00:00 2001 From: Robin Date: Wed, 8 Jun 2022 09:43:44 +0200 Subject: [PATCH 056/337] Don't check trusted proxy for protocol and port Spoofing these values is not a security issue and the config is not available when getProtocol() is called during the installer --- core/classes/Core/Util.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/classes/Core/Util.php b/core/classes/Core/Util.php index f2c40a066d..d0780e3e4b 100644 --- a/core/classes/Core/Util.php +++ b/core/classes/Core/Util.php @@ -308,7 +308,6 @@ public static function getRemoteAddress(): ?string { */ public static function getProtocol(): ?string { if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) { - self::ensureTrustedProxy(); $proto = $_SERVER['HTTP_X_FORWARDED_PROTO']; if ($proto !== 'http' && $proto !== 'https') { die("Invalid X-Forwarded-Proto header, should be 'http' or 'https'."); @@ -330,7 +329,6 @@ public static function getProtocol(): ?string { */ public static function getPort(): ?int { if (isset($_SERVER['HTTP_X_FORWARDED_PORT'])) { - self::ensureTrustedProxy(); return (int) $_SERVER['HTTP_X_FORWARDED_PORT']; } From 632cd776b5291fbc1c292093c5807409d6f08b68 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Wed, 8 Jun 2022 22:04:58 -0600 Subject: [PATCH 057/337] Fix nullable username in user integrations table --- .../20220519041811_create_users_integrations_table.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/migrations/20220519041811_create_users_integrations_table.php b/core/migrations/20220519041811_create_users_integrations_table.php index 56ffab996a..983e33b722 100644 --- a/core/migrations/20220519041811_create_users_integrations_table.php +++ b/core/migrations/20220519041811_create_users_integrations_table.php @@ -13,7 +13,7 @@ public function change(): void ->addColumn('user_id', 'integer', ['length' => 11]) ->addColumn('integration_id', 'integer', ['length' => 11]) ->addColumn('identifier', 'string', ['length' => 64, 'null' => true, 'default' => null]) - ->addColumn('username', 'string', ['length' => 32]) + ->addColumn('username', 'string', ['length' => 32, 'null' => true, 'default' => null]) ->addColumn('verified', 'boolean', ['default' => false]) ->addColumn('date', 'integer', ['length' => 11]) ->addColumn('code', 'string', ['length' => 64, 'null' => true, 'default' => null]) From bf1c7f0a0cab3a13de6cb76629311edf0e9a2dc6 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Wed, 8 Jun 2022 22:08:57 -0600 Subject: [PATCH 058/337] Fix placeholder seeder --- scripts/seeder/MinecraftPlaceholderSeeder.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/seeder/MinecraftPlaceholderSeeder.php b/scripts/seeder/MinecraftPlaceholderSeeder.php index 79524147f9..49f26bbc4f 100644 --- a/scripts/seeder/MinecraftPlaceholderSeeder.php +++ b/scripts/seeder/MinecraftPlaceholderSeeder.php @@ -7,7 +7,9 @@ class MinecraftPlaceholderSeeder extends Seeder { ]; protected function run(DB $db, \Faker\Generator $faker): void { - Util::setSetting('placeholders', 1); + $db->query('UPDATE nl2_settings SET value = ? WHERE name = ?', [ + 1, 'placeholders', + ]); $servers = $db->get('mc_servers', ['id', '<>', 0])->results(); From 54b974714b41d5d2eb0956afc877ee3e148acf43 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Wed, 8 Jun 2022 22:20:20 -0600 Subject: [PATCH 059/337] Fix MariaDB version display (Closes #2834) --- modules/Core/pages/panel/index.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/modules/Core/pages/panel/index.php b/modules/Core/pages/panel/index.php index 65a80f879c..b2b43a4203 100644 --- a/modules/Core/pages/panel/index.php +++ b/modules/Core/pages/panel/index.php @@ -168,15 +168,14 @@ $pdo_driver = 'MySQL'; } else { $pdo_driver = 'MariaDB'; - // MariaDB version strings are displayed as: "-..-MariaDB", + // MariaDB version strings are displayed as: "..-MariaDB", // and we only want the version number. - // See: https://stackoverflow.com/a/56607492 - $pdo_server_version = explode('-', $pdo_server_version)[1]; + $pdo_server_version = explode('-', $pdo_server_version)[0]; } } - if ($pdo_driver === 'MySQL' && version_compare($pdo_server_version, '5.7', '>=') || - $pdo_driver === 'MariaDB' && version_compare($pdo_server_version, '10.3', '>=')) { + if (($pdo_driver === 'MySQL' && version_compare($pdo_server_version, '5.7', '>=')) || + ($pdo_driver === 'MariaDB' && version_compare($pdo_server_version, '10.3', '>='))) { $compat_success[] = $pdo_driver . ' Server ' . $pdo_server_version; } else { $compat_errors[] = $pdo_driver . ' Server ' . $pdo_server_version; From fed41416ef4785bdd42d3e3e79f6ba75ca84d5c8 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Wed, 8 Jun 2022 23:15:12 -0600 Subject: [PATCH 060/337] Fix install autoloader --- install.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/install.php b/install.php index dc6eb1ad0f..3781b32c26 100644 --- a/install.php +++ b/install.php @@ -9,6 +9,8 @@ * Installer */ +require_once __DIR__ . '/vendor/autoload.php'; + // Definitions if (!defined('PATH')) { define('PATH', '/'); From 4be06eabe26bc1f7b9aeee72cf72d17a8ba567a4 Mon Sep 17 00:00:00 2001 From: Robin Date: Thu, 9 Jun 2022 20:14:12 +0200 Subject: [PATCH 061/337] New API error for missing API key This makes troubleshooting easier if a web server or proxy strips the Authorization header --- core/classes/Endpoints/KeyAuthEndpoint.php | 5 +++-- modules/Core/classes/Misc/Nameless2API.php | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/core/classes/Endpoints/KeyAuthEndpoint.php b/core/classes/Endpoints/KeyAuthEndpoint.php index 1e006788cf..09063cc287 100644 --- a/core/classes/Endpoints/KeyAuthEndpoint.php +++ b/core/classes/Endpoints/KeyAuthEndpoint.php @@ -19,14 +19,14 @@ final public function isAuthorised(Nameless2API $api): bool { $headers = getallheaders(); if (!isset($headers['Authorization'])) { - return false; + $api->throwError(Nameless2API::ERROR_MISSING_API_KEY, $meta="Missing authorization header"); } $exploded = explode(' ', trim($headers['Authorization'])); if (count($exploded) !== 2 || strcasecmp($exploded[0], 'Bearer') !== 0) { - return false; + $api->throwError(Nameless2API::ERROR_MISSING_API_KEY, $meta="Authorization header not in expected format"); } $api_key = $exploded[1]; @@ -46,6 +46,7 @@ private function validateKey(Nameless2API $api, string $api_key): bool { if ($correct_key == null) { die('API key is null'); } + return hash_equals($api_key, $correct_key); } diff --git a/modules/Core/classes/Misc/Nameless2API.php b/modules/Core/classes/Misc/Nameless2API.php index c9be6a0cfb..0f1565f7d2 100644 --- a/modules/Core/classes/Misc/Nameless2API.php +++ b/modules/Core/classes/Misc/Nameless2API.php @@ -17,6 +17,7 @@ class Nameless2API { public const ERROR_UNKNOWN_ERROR = 'nameless:unknown_error'; public const ERROR_NOT_AUTHORIZED = 'nameless:not_authorized'; public const ERROR_INVALID_API_KEY = 'nameless:invalid_api_key'; + public const ERROR_MISSING_API_KEY = 'nameless:missing_api_key'; public const ERROR_INVALID_API_METHOD = 'nameless:invalid_api_method'; public const ERROR_CANNOT_FIND_USER = 'nameless:cannot_find_user'; public const ERROR_INVALID_POST_CONTENTS = 'nameless:invalid_post_contents'; From 0f01e8e94e6862b8b05f75a854f20ef031633a5e Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Thu, 9 Jun 2022 12:47:51 -0600 Subject: [PATCH 062/337] Make nullable username its own migration --- ...041811_create_users_integrations_table.php | 2 +- ...mn_nullable_on_user_integrations_table.php | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 core/migrations/20220609184529_make_username_column_nullable_on_user_integrations_table.php diff --git a/core/migrations/20220519041811_create_users_integrations_table.php b/core/migrations/20220519041811_create_users_integrations_table.php index 983e33b722..56ffab996a 100644 --- a/core/migrations/20220519041811_create_users_integrations_table.php +++ b/core/migrations/20220519041811_create_users_integrations_table.php @@ -13,7 +13,7 @@ public function change(): void ->addColumn('user_id', 'integer', ['length' => 11]) ->addColumn('integration_id', 'integer', ['length' => 11]) ->addColumn('identifier', 'string', ['length' => 64, 'null' => true, 'default' => null]) - ->addColumn('username', 'string', ['length' => 32, 'null' => true, 'default' => null]) + ->addColumn('username', 'string', ['length' => 32]) ->addColumn('verified', 'boolean', ['default' => false]) ->addColumn('date', 'integer', ['length' => 11]) ->addColumn('code', 'string', ['length' => 64, 'null' => true, 'default' => null]) diff --git a/core/migrations/20220609184529_make_username_column_nullable_on_user_integrations_table.php b/core/migrations/20220609184529_make_username_column_nullable_on_user_integrations_table.php new file mode 100644 index 0000000000..1f796c5a45 --- /dev/null +++ b/core/migrations/20220609184529_make_username_column_nullable_on_user_integrations_table.php @@ -0,0 +1,27 @@ +table('nl2_users_integrations'); + + $table->changeColumn('username', 'string', ['length' => 32, 'null' => true, 'default' => null]); + + $table->update(); + } +} From 1cc52ce5344182da5a8e62ae7e62796e7bcfd94b Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Thu, 9 Jun 2022 12:48:30 -0600 Subject: [PATCH 063/337] Fix cli install `core/installed` value --- scripts/cli_install.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/cli_install.php b/scripts/cli_install.php index 3192a5f565..d859b3bd09 100644 --- a/scripts/cli_install.php +++ b/scripts/cli_install.php @@ -202,6 +202,8 @@ function getEnvVar(string $name, string $fallback = null, array $valid_values = DatabaseInitialiser::runPostUser(); +Config::set('core/installed', true); + print(PHP_EOL . '✅ Installation complete! (Took ' . round(microtime(true) - $start, 2) . ' seconds)' . PHP_EOL); print(PHP_EOL . '🖥 URL: http://' . $conf['core']['hostname'] . $conf['core']['path']); print(PHP_EOL . '🔑 Admin username: ' . $username); From d5952736edeb4152ed99bf85ad56095c3bde6e00 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Thu, 9 Jun 2022 12:49:06 -0600 Subject: [PATCH 064/337] Revert Fix cli install `core/installed` value --- scripts/cli_install.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/cli_install.php b/scripts/cli_install.php index d859b3bd09..3192a5f565 100644 --- a/scripts/cli_install.php +++ b/scripts/cli_install.php @@ -202,8 +202,6 @@ function getEnvVar(string $name, string $fallback = null, array $valid_values = DatabaseInitialiser::runPostUser(); -Config::set('core/installed', true); - print(PHP_EOL . '✅ Installation complete! (Took ' . round(microtime(true) - $start, 2) . ' seconds)' . PHP_EOL); print(PHP_EOL . '🖥 URL: http://' . $conf['core']['hostname'] . $conf['core']['path']); print(PHP_EOL . '🔑 Admin username: ' . $username); From d5f55bc2faab8ec4aa39398279970a9298b8cc78 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Thu, 9 Jun 2022 12:49:42 -0600 Subject: [PATCH 065/337] Style fixes --- core/classes/Endpoints/KeyAuthEndpoint.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/classes/Endpoints/KeyAuthEndpoint.php b/core/classes/Endpoints/KeyAuthEndpoint.php index 09063cc287..d8eb9079d4 100644 --- a/core/classes/Endpoints/KeyAuthEndpoint.php +++ b/core/classes/Endpoints/KeyAuthEndpoint.php @@ -19,14 +19,14 @@ final public function isAuthorised(Nameless2API $api): bool { $headers = getallheaders(); if (!isset($headers['Authorization'])) { - $api->throwError(Nameless2API::ERROR_MISSING_API_KEY, $meta="Missing authorization header"); + $api->throwError(Nameless2API::ERROR_MISSING_API_KEY, 'Missing authorization header'); } $exploded = explode(' ', trim($headers['Authorization'])); if (count($exploded) !== 2 || strcasecmp($exploded[0], 'Bearer') !== 0) { - $api->throwError(Nameless2API::ERROR_MISSING_API_KEY, $meta="Authorization header not in expected format"); + $api->throwError(Nameless2API::ERROR_MISSING_API_KEY, 'Authorization header not in expected format'); } $api_key = $exploded[1]; From 1234ad0ee0bbdb7458e7237b3171ba73f2edad4f Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Thu, 9 Jun 2022 13:00:48 -0600 Subject: [PATCH 066/337] Fix `OAuth` class name being overridden Some systems have this ext installed by default, which clashes with the name: https://www.php.net/manual/en/class.oauth.php --- .../Misc/{OAuth.php => NamelessOAuth.php} | 2 +- modules/Core/module.php | 4 ++-- modules/Core/pages/login.php | 4 ++-- modules/Core/pages/oauth.php | 16 ++++++++-------- modules/Core/pages/panel/registration.php | 16 ++++++++-------- modules/Core/pages/panel/users_oauth.php | 6 +++--- modules/Core/pages/register.php | 6 +++--- modules/Core/pages/user/oauth.php | 6 +++--- 8 files changed, 30 insertions(+), 30 deletions(-) rename core/classes/Misc/{OAuth.php => NamelessOAuth.php} (99%) diff --git a/core/classes/Misc/OAuth.php b/core/classes/Misc/NamelessOAuth.php similarity index 99% rename from core/classes/Misc/OAuth.php rename to core/classes/Misc/NamelessOAuth.php index 1c11c35f31..72c1231ce2 100644 --- a/core/classes/Misc/OAuth.php +++ b/core/classes/Misc/NamelessOAuth.php @@ -10,7 +10,7 @@ * @version 2.0.0-pr13 * @license MIT */ -class OAuth extends Instanceable { +class NamelessOAuth extends Instanceable { private array $_providers = []; private array $_provider_instances = []; diff --git a/modules/Core/module.php b/modules/Core/module.php index 1f28f20b41..49690511ff 100644 --- a/modules/Core/module.php +++ b/modules/Core/module.php @@ -442,14 +442,14 @@ public function __construct(Language $language, Pages $pages, User $user, Naviga ); // TODO: should this be in the Discord Integration module? - OAuth::getInstance()->registerProvider('discord', [ + NamelessOAuth::getInstance()->registerProvider('discord', [ 'class' => \Wohali\OAuth2\Client\Provider\Discord::class, 'user_id_name' => 'id', 'scope_id_name' => 'identify', 'icon' => 'fab fa-discord', ]); - OAuth::getInstance()->registerProvider('google', [ + NamelessOAuth::getInstance()->registerProvider('google', [ 'class' => \League\OAuth2\Client\Provider\Google::class, 'user_id_name' => 'sub', 'scope_id_name' => 'openid', diff --git a/modules/Core/pages/login.php b/modules/Core/pages/login.php index 0490f83160..ea6588e982 100644 --- a/modules/Core/pages/login.php +++ b/modules/Core/pages/login.php @@ -289,8 +289,8 @@ 'ERROR_TITLE' => $language->get('general', 'error'), 'ERROR' => ($return_error ?? []), 'NOT_REGISTERED_YET' => $language->get('general', 'not_registered_yet'), - 'OAUTH_AVAILABLE' => OAuth::getInstance()->isAvailable(), - 'OAUTH_PROVIDERS' => OAuth::getInstance()->getProvidersAvailable(), + 'OAUTH_AVAILABLE' => NamelessOAuth::getInstance()->isAvailable(), + 'OAUTH_PROVIDERS' => NamelessOAuth::getInstance()->getProvidersAvailable(), ]); if (Session::exists('oauth_error')) { diff --git a/modules/Core/pages/oauth.php b/modules/Core/pages/oauth.php index 92d709fec2..974b212457 100644 --- a/modules/Core/pages/oauth.php +++ b/modules/Core/pages/oauth.php @@ -1,7 +1,7 @@ getProvidersAvailable())) { + if (!array_key_exists($_GET['provider'], NamelessOAuth::getInstance()->getProvidersAvailable())) { throw new RuntimeException("Invalid provider {$_GET['provider']}"); } } @@ -11,16 +11,16 @@ } $provider_name = $_GET['provider']; -$provider = OAuth::getInstance()->getProviderInstance($provider_name); +$provider = NamelessOAuth::getInstance()->getProviderInstance($provider_name); $token = $provider->getAccessToken('authorization_code', [ 'code' => $_GET['code'] ]); $oauth_user = $provider->getResourceOwner($token)->toArray(); -$provider_id = $oauth_user[OAuth::getInstance()->getUserIdName($provider_name)]; +$provider_id = $oauth_user[NamelessOAuth::getInstance()->getUserIdName($provider_name)]; // register if (Session::get('oauth_method') === 'register') { - if (OAuth::getInstance()->userExistsByProviderId($provider_name, $provider_id)) { + if (NamelessOAuth::getInstance()->userExistsByProviderId($provider_name, $provider_id)) { Session::flash('oauth_error', $language->get('user', 'oauth_already_linked', ['provider' => ucfirst($provider_name)])); Redirect::to(URL::build('/register')); } @@ -37,13 +37,13 @@ // login if (Session::get('oauth_method') === 'login') { - if (!OAuth::getInstance()->userExistsByProviderId($provider_name, $provider_id)) { + if (!NamelessOAuth::getInstance()->userExistsByProviderId($provider_name, $provider_id)) { Session::flash('oauth_error', $language->get('user', 'no_user_found_with_provider', ['provider' => ucfirst($provider_name)])); Redirect::to(URL::build('/login')); } if ((new User())->login( - OAuth::getInstance()->getUserIdFromProviderId($provider_name, $provider_id), + NamelessOAuth::getInstance()->getUserIdFromProviderId($provider_name, $provider_id), '', true, 'oauth' )) { Log::getInstance()->log(Log::Action('user/login')); @@ -62,12 +62,12 @@ // link if (Session::get('oauth_method') === 'link') { - if (OAuth::getInstance()->userExistsByProviderId($provider_name, $provider_id)) { + if (NamelessOAuth::getInstance()->userExistsByProviderId($provider_name, $provider_id)) { Session::flash('oauth_error', $language->get('user', 'oauth_already_linked', ['provider' => ucfirst($provider_name)])); Redirect::to(URL::build('/user/oauth')); } - OAuth::getInstance()->saveUserProvider( + NamelessOAuth::getInstance()->saveUserProvider( $user->data()->id, $provider_name, $provider_id, diff --git a/modules/Core/pages/panel/registration.php b/modules/Core/pages/panel/registration.php index f8124bf88e..2f6b022910 100644 --- a/modules/Core/pages/panel/registration.php +++ b/modules/Core/pages/panel/registration.php @@ -38,16 +38,16 @@ if (Input::get('action') == 'oauth') { - foreach (array_keys(OAuth::getInstance()->getProviders()) as $provider_name) { + foreach (array_keys(NamelessOAuth::getInstance()->getProviders()) as $provider_name) { $client_id = Input::get("client-id-{$provider_name}"); $client_secret = Input::get("client-secret-{$provider_name}"); if ($client_id && $client_secret) { - OAuth::getInstance()->setEnabled($provider_name, Input::get("enable-{$provider_name}") == 'on' ? 1 : 0); + NamelessOAuth::getInstance()->setEnabled($provider_name, Input::get("enable-{$provider_name}") == 'on' ? 1 : 0); } else { - OAuth::getInstance()->setEnabled($provider_name, 0); + NamelessOAuth::getInstance()->setEnabled($provider_name, 0); } - OAuth::getInstance()->setCredentials($provider_name, $client_id, $client_secret); + NamelessOAuth::getInstance()->setCredentials($provider_name, $client_id, $client_secret); } } else { @@ -158,11 +158,11 @@ } $oauth_provider_data = []; -foreach (OAuth::getInstance()->getProviders() as $provider_name => $provider_data) { - [$client_id, $client_secret] = OAuth::getInstance()->getCredentials($provider_name); +foreach (NamelessOAuth::getInstance()->getProviders() as $provider_name => $provider_data) { + [$client_id, $client_secret] = NamelessOAuth::getInstance()->getCredentials($provider_name); $oauth_provider_data[$provider_name] = [ - 'enabled' => OAuth::getInstance()->isEnabled($provider_name), - 'setup' => OAuth::getInstance()->isSetup($provider_name), + 'enabled' => NamelessOAuth::getInstance()->isEnabled($provider_name), + 'setup' => NamelessOAuth::getInstance()->isSetup($provider_name), 'icon' => $provider_data['icon'], 'client_id' => $client_id, 'client_secret' => $client_secret, diff --git a/modules/Core/pages/panel/users_oauth.php b/modules/Core/pages/panel/users_oauth.php index ce8928f51e..86820a8246 100644 --- a/modules/Core/pages/panel/users_oauth.php +++ b/modules/Core/pages/panel/users_oauth.php @@ -26,7 +26,7 @@ if (Token::check(Input::get('token'))) { if (isset($_POST['provider_name'], $_POST['user_id'])) { - OAuth::getInstance()->unlinkProviderForUser($_POST['user_id'], $_POST['provider_name']); + NamelessOAuth::getInstance()->unlinkProviderForUser($_POST['user_id'], $_POST['provider_name']); Session::flash('oauth_success', $language->get('admin', 'unlink_account_success', ['provider' => ucfirst($_POST['provider_name'])])); } @@ -45,8 +45,8 @@ } $user_query = $view_user->data(); -$oauth_providers = OAuth::getInstance()->getProvidersAvailable(); -$user_oauth_providers = OAuth::getInstance()->getAllProvidersForUser($user_query->id); +$oauth_providers = NamelessOAuth::getInstance()->getProvidersAvailable(); +$user_oauth_providers = NamelessOAuth::getInstance()->getAllProvidersForUser($user_query->id); $user_providers_template = []; foreach ($user_oauth_providers as $user_provider) { diff --git a/modules/Core/pages/register.php b/modules/Core/pages/register.php index 3f8eaa4c3c..5402dc2b42 100644 --- a/modules/Core/pages/register.php +++ b/modules/Core/pages/register.php @@ -334,7 +334,7 @@ if (Session::exists('oauth_register_data')) { $data = json_decode(Session::get('oauth_register_data'), true); - OAuth::getInstance()->saveUserProvider( + NamelessOAuth::getInstance()->saveUserProvider( $user_id, $data['provider'], $data['id'], @@ -476,8 +476,8 @@ 'ERROR_TITLE' => $language->get('general', 'error'), 'OR' => $language->get('general', 'or'), 'OAUTH_FLOW' => $oauth_flow, - 'OAUTH_AVAILABLE' => OAuth::getInstance()->isAvailable(), - 'OAUTH_PROVIDERS' => OAuth::getInstance()->getProvidersAvailable(), + 'OAUTH_AVAILABLE' => NamelessOAuth::getInstance()->isAvailable(), + 'OAUTH_PROVIDERS' => NamelessOAuth::getInstance()->getProvidersAvailable(), ]); if ($captcha) { diff --git a/modules/Core/pages/user/oauth.php b/modules/Core/pages/user/oauth.php index 733ce14bf2..918b852691 100644 --- a/modules/Core/pages/user/oauth.php +++ b/modules/Core/pages/user/oauth.php @@ -25,7 +25,7 @@ $provider_name = Input::get('provider'); if (Input::get('action') === 'unlink') { - OAuth::getInstance()->unlinkProviderForUser($user->data()->id, $provider_name); + NamelessOAuth::getInstance()->unlinkProviderForUser($user->data()->id, $provider_name); Session::flash('oauth_success', $language->get('user', 'oauth_unlinked')); } } else { @@ -36,8 +36,8 @@ Session::put('oauth_method', 'link'); -$providers = OAuth::getInstance()->getProvidersAvailable(); -$user_providers = OAuth::getInstance()->getAllProvidersForUser($user->data()->id); +$providers = NamelessOAuth::getInstance()->getProvidersAvailable(); +$user_providers = NamelessOAuth::getInstance()->getAllProvidersForUser($user->data()->id); $user_providers_template = []; foreach ($user_providers as $user_provider) { From 4235f6ab6519e60408d2834bec9e3c755c561ed0 Mon Sep 17 00:00:00 2001 From: Robin Date: Fri, 10 Jun 2022 10:43:13 +0200 Subject: [PATCH 067/337] Set CGIPassAuth On --- .htaccess | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.htaccess b/.htaccess index f0e2447a10..9b77365958 100644 --- a/.htaccess +++ b/.htaccess @@ -29,3 +29,6 @@ Deny from all + + # Prevent Apache from removing the Authorization header, we need to check it for the API. + CGIPassAuth On From f0869338da89be8b5d8ae9408b9d0e23872aee50 Mon Sep 17 00:00:00 2001 From: Partydragen Date: Fri, 10 Jun 2022 18:31:42 +0200 Subject: [PATCH 068/337] Fix fatal error for deleted users in logs --- modules/Core/pages/panel/security.php | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/modules/Core/pages/panel/security.php b/modules/Core/pages/panel/security.php index 26efe18b2a..b04f0a5bb9 100644 --- a/modules/Core/pages/panel/security.php +++ b/modules/Core/pages/panel/security.php @@ -89,7 +89,9 @@ $rows[] = [ 0 => [ - 'content' => '' . Output::getClean($target_user->getDisplayname()) . '' + 'content' => $target_user->exists() + ? '' . Output::getClean($target_user->getDisplayname()) . '' + : $language->get('general', 'deleted_user') ], 1 => [ 'content' => '' . Output::getClean($log->ip) . '' @@ -125,7 +127,9 @@ $rows[] = [ 0 => [ - 'content' => '' . Output::getClean($target_user->getDisplayname()) . '' + 'content' => $target_user->exists() + ? '' . Output::getClean($target_user->getDisplayname()) . '' + : $language->get('general', 'deleted_user') ], 1 => [ 'content' => '' . Output::getClean($log->ip) . '' @@ -163,7 +167,9 @@ $rows[] = [ 0 => [ - 'content' => '' . Output::getClean($target_user->getDisplayname()) . '' + 'content' => $target_user->exists() + ? '' . Output::getClean($target_user->getDisplayname()) . '' + : $language->get('general', 'deleted_user') ], 1 => [ 'content' => '' . Output::getClean($log->ip) . '' @@ -211,7 +217,9 @@ $rows[] = [ 0 => [ - 'content' => '' . Output::getClean($target_user->getDisplayname()) . '' + 'content' => $target_user->exists() + ? '' . Output::getClean($target_user->getDisplayname()) . '' + : $language->get('general', 'deleted_user') ], 1 => [ 'content' => date(DATE_FORMAT, $log->time), @@ -259,7 +267,8 @@ 0 => [ 'content' => $log->user_id == 0 ? $language->get('general', 'none') - : '' . Output::getClean($target_user->getDisplayname()) . '' + : ($target_user->exists() ? '' . Output::getClean($target_user->getDisplayname()) . '' + : $language->get('general', 'deleted_user')) ], 1 => [ 'content' => '' . Output::getClean($log->ip) . '' From 082d2c5ab1e430e31c7164e61d5d90d32371203b Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Fri, 10 Jun 2022 18:41:09 -0600 Subject: [PATCH 069/337] New contributing doc & notes about versioning --- CONTRIBUTING.md | 57 +++++++++++++++++++++++++++++++++++++++++++++++++ CONTRIBUTORS.md | 30 -------------------------- README.md | 33 +--------------------------- 3 files changed, 58 insertions(+), 62 deletions(-) create mode 100644 CONTRIBUTING.md delete mode 100644 CONTRIBUTORS.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..0cdf4aa64a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,57 @@ +# Contributing +We welcome all contributions of code and translations. Please feel free to fork the repository on GitHub and create any pull requests! + +Document in progress! + +## Tips +Here are some things you should know when contributing: +- We generally keep a todo list in the Milestones tab of the Issues page. +- We use Composer to manage dependencies. Before you can install the dependencies, you need to install Composer on your local computer. Installation instructions are [here](https://getcomposer.org/doc/00-intro.md). + - To install the Composer packages we depend on, run the following command in the root directory of the NamelessMC repository: + ```console + composer install --dev + ``` + - This could take up to about a minute depending on your internet connection. +- You can use the CLI (command line) install script to reset your development environment in less than 5 seconds! + - Run the following command when in the root directory: + ```console + php scripts/cli_install.php --iSwearIKnowWhatImDoing --reinstall + ``` +- To populate the database with some fake data, you can use the seeder. + - Run the following command when in the root directory: + ```console + php scripts/seeder/db_seeder.php wipe + ``` + - This will wipe the database and populate it with lots of fake users, forums, and much, much more. + - *Note: Login to the admin account with `admin@localhost` and `password` after running the seeder* +- To make changes to the database schema (add, modify or remove a table), please create a new migration with Phinx: + - Run the following command when in the root directory: + ```console + vendor/bin/phinx create MigrationNameInCamelCase -c core/migrations/phinx.php + ``` + - This will create a new migration file in the `./core/migrations` directory, where you can use the Phinx table builder to make your changes. + Please try to stick with the conventions of pre-existing migrations. + - To execute the migration, run the following command: + ```console + vendor/bin/phinx migrate -c core/migrations/phinx.php + ``` + +## Versioning +As of NamelessMC 2.0.0 (to be released at time of writing), we use a unique versioning system. +Similar to [semver](https://semver.org), we follow the `major.minor.patch` versioning pattern, however there are a few things to note: +- The `major` version is pinned at `2` for the time being. +- The `minor` version is only changed when *breaking changes are made*. These include: + - Changes that require modules to update + - Changes that require templates to update + - Changes that require updates to the Nameless-Link Discord bot + - Changes that require updates to the debug.namelessmc.com repo + - **If the minor version is bumped, we will inform users about which of the above aspects were affected.** +- The `patch` version will change for any releases which do not include breaking changes, in our case this will generally mean a bug fix release. + +Examples: +- `2.0.1` + - A bug fix release. Fully backwards compatible with `2.0.0` modules, templates & other integrations. +- `2.1.0` + - A "major" release. Modules and/or templates and/or other integrations will need to be updated to support this release. +- `2.1.4` + - A bug fix release. Fully backwards compatible with `2.1.0` modules, templates & other integrations, but not compatible with (at least 1) `2.0.0` integration diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md deleted file mode 100644 index e45c33a776..0000000000 --- a/CONTRIBUTORS.md +++ /dev/null @@ -1,30 +0,0 @@ -# NamelessMC v2 Contributors - -Please feel free to update this list along with any pull requests. - -A full list of contributors for v2 can be found [here](https://github.com/NamelessMC/Nameless/graphs/contributors). - -### v1 -Unfortunately it's only possible to view contributors for the default branch. For the previous version v1.x.x, contributors can be found in the [v1 readme](https://github.com/NamelessMC/Nameless/blob/master/README.md). - -### Translations -- Chinese: [ahdg](https://github.com/ahdg6), [Hi_Michael](https://github.com/haer0248) -- Czech: Ethxrnity, [LukarioJapans](https://github.com/LucarioJapans), [Nekomitsuki](https://github.com/Nekomitsuki), [Renzotom](https://github.com/Renzotom), [Volgeop](https://github.com/Volgeop), Zemos -- Danish: Codiaz -- Dutch: [Akela](https://github.com/Akelah), [Derkades](https://github.com/Derkades), [Jesse Geerts](https://github.com/jesseke55), [Rody Molenaar](https://github.com/rodymolenaar), [Sander Lambrechts](https://github.com/TheSander562), [smessie](https://github.com/smessie) -- English UK (default) -- English US (default) -- German: [BattleDev](https://github.com/BinFlauschigDEV), [BukkitTNT](https://github.com/BukkitTNT), [H4nSolo](https://github.com/H4nSolo) -- Greek: [ArisC](https://github.com/Ar1sC) -- Italian: [alsoGAMER](https://github.com/alsoGAMER) -- Japanese: [Mari0914](https://github.com/Mari0914), [SimplyRin](https://www.simplyrin.net), [snake](https://viasnake.com) -- Lithuanian: [Govindas](https://github.com/Govindass), [Justas](https://github.com/madebyjustas) -- Norwegian: [HeyImSushii](https://github.com/HeyImSushii), [Maiu](https://github.com/Maiu15), [OscarWoHA](https://github.com/OscarWoHA) -- Polish: brzezinsky, Cubixor, [kacperleague9](https://github.com/kacperleague9) -- Portuguese: [dasilvaj4](https://github.com/dasilvaj4), [Douglas Teles](https://github.com/dgateles) -- Romanian: [BaxAndrei](https://github.com/baxandrei) -- Slovak: [RobiNN1](https://github.com/RobiNN1) -- Spanish: [Ariuw](https://github.com/Ariuw), [iMaykolRD_](https://namelessmc.com/profile/iMaykolRD_/), TheSuperSkills, [zJerino](https://namelessmc.com/profile/zJerino/) -- Swedish: [IsS127](https://github.com/IsS127), [ItsLynix](https://github.com/ItsLynix) -- Turkish: xOrcun -- French: [WhiteSkyAngel](https://github.com/WhiteSkyAngel) diff --git a/README.md b/README.md index f070847bde..bcfe04743e 100644 --- a/README.md +++ b/README.md @@ -70,38 +70,7 @@ If you would like to assist with the NamelessMC development by translating to yo ![Translation progress](https://translate.namelessmc.com/widgets/namelessmc/-/nameless/multi-auto.svg) ## Contributing -We welcome all contributions of code and translations. Please feel free to fork the repository on GitHub and create any pull requests! -Here are some things you should know when contributing: -- We generally keep a todo list in the Milestones tab of the Issues page. -- We use Composer to manage dependencies. Before you can install the dependencies, you need to install Composer on your local computer. Installation instructions are [here](https://getcomposer.org/doc/00-intro.md). - - To install the Composer packages we depend on, run the following command in the root directory of the NamelessMC repository: - ```console - composer install --dev - ``` - - This could take up to about a minute depending on your internet connection. -- You can use the CLI (command line) install script to reset your development environment in less than 5 seconds! - - Run the following command when in the root directory: - ```console - php scripts/cli_install.php --iSwearIKnowWhatImDoing --reinstall - ``` -- To populate the database with some fake data, you can use the seeder. - - Run the following command when in the root directory: - ```console - php scripts/seeder/db_seeder.php wipe - ``` - - This will wipe the database and populate it with lots of fake users, forums, and much, much more. - - *Note: Login to the admin account with `admin@localhost` and `password` after running the seeder* -- To make changes to the database schema (add, modify or remove a table), please create a new migration with Phinx: - - Run the following command when in the root directory: - ```console - vendor/bin/phinx create MigrationNameInCamelCase -c core/migrations/phinx.php - ``` - - This will create a new migration file in the `./core/migrations` directory, where you can use the Phinx table builder to make your changes. - Please try to stick with the conventions of pre-existing migrations. - - To execute the migration, run the following command: - ```console - vendor/bin/phinx migrate -c core/migrations/phinx.php - ``` +Please see the contributing document for information on how to contribute to NamelessMC. ## Special Thanks - All NamelessMC [contributors](https://github.com/NamelessMC/Nameless/graphs/contributors). From c4130972b487762c55d6fbe2644df91790dd0726 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Fri, 10 Jun 2022 18:58:36 -0600 Subject: [PATCH 070/337] Fix #2843 --- core/classes/Database/DB.php | 11 + core/classes/Misc/UpgradeScript.php | 25 +- core/includes/updates/200-pr12.php | 367 ---------------------------- core/includes/updates/200-pr13.php | 18 ++ 4 files changed, 44 insertions(+), 377 deletions(-) delete mode 100644 core/includes/updates/200-pr12.php create mode 100644 core/includes/updates/200-pr13.php diff --git a/core/classes/Database/DB.php b/core/classes/Database/DB.php index 7acb99b1b7..add027c852 100644 --- a/core/classes/Database/DB.php +++ b/core/classes/Database/DB.php @@ -13,6 +13,7 @@ class DB { private static ?DB $_instance = null; private string $_prefix; + private string $_database; private ?string $_force_charset; protected PDO $_pdo; private PDOStatement $_statement; @@ -25,6 +26,7 @@ private function __construct(string $host, string $database, string $username, s try { $this->_force_charset = $force_charset; $this->_prefix = $prefix; + $this->_database = $database; $connection_string = 'mysql:host=' . $host . ';port=' . $port . ';dbname=' . $database; if ($force_charset) { @@ -55,6 +57,15 @@ public function getPDO(): PDO { return $this->_pdo; } + /** + * Get the database name this instance is connected to. + * + * @return string Database name. + */ + public function getDatabase(): string { + return $this->_database; + } + /** * Get the first row of the result. * diff --git a/core/classes/Misc/UpgradeScript.php b/core/classes/Misc/UpgradeScript.php index 0f535c8550..75bec1fa7c 100644 --- a/core/classes/Misc/UpgradeScript.php +++ b/core/classes/Misc/UpgradeScript.php @@ -38,6 +38,16 @@ public static function get(string $current_version): ?UpgradeScript { */ abstract public function run(): void; + /** + * Logs a message to the screen and the warning-log.log file. + * + * @param string $message Message to log + */ + protected function log(string $message): void { + echo $message . '
'; + ErrorHandler::logWarning('UPGRADING EXCEPTION: ' . $exception->getMessage()); + } + /** * Run a single database query * @@ -62,8 +72,7 @@ protected function databaseQueries(array $queries): array { $results[] = $query(DB::getInstance()); } catch (Exception $exception) { $results[] = null; - ErrorHandler::logWarning('UPGRADING EXCEPTION: ' . $exception->getMessage()); - echo $exception->getMessage() . '
'; + $this->log($exception->getMessage()); } } @@ -100,8 +109,7 @@ protected function deleteFilesInPath(string $path, array $files, bool $recursive } } else { - ErrorHandler::logWarning('UPGRADING EXCEPTION: ' . "'$newFile' does not exist, cannot delete.
"); - echo "'$newFile' does not exist, cannot delete.
"; + $this->log("'$newFile' does not exist, cannot delete."); } } @@ -116,20 +124,17 @@ protected function deleteFiles($paths): void { foreach ((array) $paths as $path) { $path = ROOT_PATH . '/' . $path; if (!file_exists($path)) { - ErrorHandler::logWarning('UPGRADING EXCEPTION: ' . "'$path' does not exist, cannot delete.
"); - echo "'$path' does not exist, cannot delete.
"; + $this->log("'$path' does not exist, cannot delete."); continue; } if (!is_writable($path)) { - ErrorHandler::logWarning('UPGRADING EXCEPTION: ' . "'$path' is not writable, cannot delete.
"); - echo "'$path' is not writable, cannot delete.
"; + $this->log("'$path' is not writable, cannot delete."); return; } if (is_dir($path) && !rmdir($path)) { - ErrorHandler::logWarning('UPGRADING EXCEPTION: ' . "Could not delete '$path', is it empty?
"); - echo "Could not delete '$path', is it empty?
"; + $this->log("Could not delete '$path', is it empty?"); } unlink($path); diff --git a/core/includes/updates/200-pr12.php b/core/includes/updates/200-pr12.php deleted file mode 100644 index f36c75bd73..0000000000 --- a/core/includes/updates/200-pr12.php +++ /dev/null @@ -1,367 +0,0 @@ -databaseQuery(function (DB $db) { - // Disable all modules and templates & reset defaults - $db->query("UPDATE `nl2_modules` SET `enabled` = 0 WHERE `name` NOT IN ('Core', 'Forum')"); - $this->_cache->setCache('modulescache'); - $this->_cache->eraseAll(); - $arr = [ - ['name' => 'Core', 'priority' => 1] - ]; - if ($db->query("SELECT enabled FROM nl2_modules WHERE name = 'Forum' AND enabled = 1")->count() > 0) { - $arr[] = ['name' => 'Forum', 'priority' => 2]; - } - $this->_cache->store('enabled_modules', $arr); - $this->_cache->store('module_core', true); - - $db->query("UPDATE `nl2_templates` SET `enabled` = 0 WHERE `name` <> 'DefaultRevamp'"); - $db->query("UPDATE `nl2_templates` SET `enabled` = 1, `is_default` = 1 WHERE `name` = 'DefaultRevamp'"); - $db->query("UPDATE `nl2_panel_templates` SET `enabled` = 0 WHERE `name` <> 'Default'"); - $db->query("UPDATE `nl2_panel_templates` SET `enabled` = 1, `is_default` = 1 WHERE `name` = 'Default'"); - $this->_cache->setCache('templatecache'); - $this->_cache->eraseAll(); - }); - - // Default night mode to null instead of 0 - $this->databaseQuery(function (DB $db) { - $db->query('ALTER TABLE nl2_users MODIFY night_mode tinyint(1) DEFAULT NULL NULL'); - }); - - // Default log table user IP to null - $this->databaseQuery(function (DB $db) { - $db->query('ALTER TABLE nl2_logs MODIFY ip varchar(128) DEFAULT NULL NULL'); - }); - - // Cookie policy - $this->databaseQuery(function (DB $db) { - if (!$db->query('SELECT `id` FROM nl2_privacy_terms WHERE `name` = ?', ['cookies'])->count()) { - $db->insert('privacy_terms', array( - 'name' => 'cookies', - 'value' => 'What are cookies?
Cookies are small files which are stored on your device by a website, unique to your web browser. The web browser will send these files to the website each time it communicates with the website.
Cookies are used by this website for a variety of reasons which are outlined below.

Necessary cookies
Necessary cookies are required for this website to function. These are used by the website to maintain your session, allowing for you to submit any forms, log into the website amongst other essential behaviour. It is not possible to disable these within the website, however you can disable cookies altogether via your browser.

Functional cookies
Functional cookies allow for the website to work as you choose. For example, enabling the "Remember Me" option as you log in will create a functional cookie to automatically log you in on future visits.

Analytical cookies
Analytical cookies allow both this website, and any third party services used by this website, to collect non-personally identifiable data about the user. This allows us (the website staff) to continue to improve the user experience and understand how the website is used.

Further information about cookies can be found online, including the ICO's website which contains useful links to further documentation about configuring your browser.

Configuring cookie use
By default, only necessary cookies are used by this website. However, some website functionality may be unavailable until the use of cookies has been opted into.
You can opt into, or continue to disallow, the use of cookies using the cookie notice popup on this website. If you would like to update your preference, the cookie notice popup can be re-enabled by clicking the button below.' - )); - } - }); - - $this->databaseQuery(function (DB $db) { - // make the name column in nl2_settings table unique - // first remove duplicates - $to_delete = $db->query('SELECT s.id FROM nl2_settings s - WHERE s.name IN (SELECT name FROM nl2_settings GROUP BY name HAVING count(*) > 1) - AND id <> (SELECT MIN(id) FROM nl2_settings WHERE name = s.name) - '); - - if ($to_delete->count()) { - $items = '('; - foreach ($to_delete->results() as $item) { - $items .= ((int)$item->id) . ','; - } - $items = rtrim($items, ',') . ')'; - - $db->query('DELETE FROM nl2_settings WHERE id IN ' . $items); - } - - // now add unique constraint - $db->query('ALTER TABLE nl2_settings ADD CONSTRAINT UNIQUE(`name`)'); - }); - - // delete old "version" row - $this->databaseQuery(function (DB $db) { - Util::setSetting('version', null); - }); - - // oauth - $this->databaseQuery(function (DB $db) { - $db->createTable('oauth', " - `provider` varchar(256) NOT NULL, - `enabled` tinyint(1) NOT NULL DEFAULT '0', - `client_id` varchar(256) DEFAULT NULL, - `client_secret` varchar(256) DEFAULT NULL, - PRIMARY KEY (`provider`), - UNIQUE KEY `id` (`provider`)"); - $db->createTable('oauth_users', " - `user_id` int NOT NULL, - `provider` varchar(256) NOT NULL, - `provider_id` varchar(256) NOT NULL, - PRIMARY KEY (`user_id`,`provider`,`provider_id`), - UNIQUE KEY `user_id` (`user_id`,`provider`,`provider_id`)"); - }); - - // User integrations - $this->databaseQueries([ - function (DB $db) { - $db->createTable('integrations', " `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(32) NOT NULL, `enabled` tinyint(1) NOT NULL DEFAULT '1', `can_unlink` tinyint(1) NOT NULL DEFAULT '1', `required` tinyint(1) NOT NULL DEFAULT '0', `order` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`id`)"); - $db->createTable('users_integrations', " `id` int(11) NOT NULL AUTO_INCREMENT, `integration_id` int(11) NOT NULL, `user_id` int(11) NOT NULL, `identifier` varchar(64) DEFAULT NULL, `username` varchar(32) DEFAULT NULL, `verified` tinyint(1) NOT NULL DEFAULT '0', `date` int(11) NOT NULL, `code` varchar(64) DEFAULT NULL, `show_publicly` tinyint(1) NOT NULL DEFAULT '1', `last_sync` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`id`)"); - }, - function (DB $db) { - $db->insert('integrations', [ - 'name' => 'Minecraft', - 'enabled' => true, - 'can_unlink' => false, - 'required' => false, - ]); - - $db->insert('integrations', [ - 'name' => 'Discord', - 'enabled' => true, - 'can_unlink' => true, - 'required' => false - ]); - } - ]); - - $this->databaseQuery( - function (DB $db) { - $db->query('ALTER TABLE `nl2_users_integrations` ADD INDEX `nl2_users_integrations_idx_integration_id` (`integration_id`)'); - $db->query('ALTER TABLE `nl2_users_integrations` ADD INDEX `nl2_users_integrations_idx_user_id` (`user_id`)'); - } - ); - - // Convert users integrations - $this->databaseQuery(function (DB $db) { - $users = $db->query('SELECT id, username, uuid, discord_id, discord_username, joined FROM nl2_users')->results(); - $query = 'INSERT INTO nl2_users_integrations (integration_id, user_id, identifier, username, verified, date) VALUES '; - foreach ($users as $item) { - $inserts = []; - - if (!empty($item->uuid) && $item->uuid != 'none') { - $inserts[] = '(1,' . $item->id . ',\'' . $item->uuid . '\',\'' . $item->username . '\',1,' . $item->joined . '),'; - } - - if ($item->discord_id != null && $item->discord_username != null && $item->discord_id != 010) { - $inserts[] = '(2,' . $item->id . ',\'' . $item->discord_id . '\',\'' . $item->discord_username . '\',1,' . $item->joined . '),'; - } - - $query .= implode('', $inserts); - } - $db->query(rtrim($query, ',')); - - // Only delete after successful conversion - $db->query('ALTER TABLE `nl2_users` DROP COLUMN `uuid`;'); - $db->query('ALTER TABLE `nl2_users` DROP COLUMN `discord_id`;'); - $db->query('ALTER TABLE `nl2_users` DROP COLUMN `discord_username`;'); - }); - - // Add bedrock to nl2_mc_servers table - $this->databaseQuery(function (DB $db) { - $db->query('ALTER TABLE `nl2_mc_servers` ADD `bedrock` tinyint(1) NOT NULL DEFAULT \'0\''); - }); - - // Increase length of name column - $this->databaseQuery(function (DB $db) { - $db->query('ALTER TABLE nl2_mc_servers MODIFY `name` VARCHAR(128) NOT NULL'); - }); - - // add unique constraint to modules table - $this->databaseQuery(function (DB $db) { - $db->query('ALTER TABLE nl2_modules ADD UNIQUE (`name`)'); - }); - - // Increase length of reset_code column - $this->databaseQuery(function (DB $db) { - $db->query('ALTER TABLE nl2_users MODIFY `reset_code` VARCHAR(64) NOT NULL'); - }); - - // delete language cache since it will contain the old language names and not the short codes - $this->_cache->setCache('languagecache'); - $this->_cache->eraseAll(); - - // add short code column to languages table - $this->databaseQuery(function (DB $db) { - $db->query('ALTER TABLE nl2_languages ADD `short_code` VARCHAR(64) NOT NULL'); - - $languages = $db->query('SELECT * FROM nl2_languages')->results(); - $converted_languages = []; - foreach (Language::LANGUAGES as $short_code => $meta) { - $key = array_search(str_replace(' ', '', $meta['name']), array_column($languages, 'name')); - - if ($key !== false) { - $db->update('languages', $languages[$key]->id, [ - 'name' => $meta['name'], - 'short_code' => $short_code - ]); - - $converted_languages[] = $languages[$key]->id; - } else { - $db->insert('languages', [ - 'name' => $meta['name'], - 'short_code' => $short_code - ]); - - $converted_languages[] = $db->lastId(); - } - } - - $db->query('DELETE FROM nl2_languages WHERE `short_code` IS NULL'); - - $default_language = $db->query('SELECT id, short_code FROM nl2_languages WHERE `is_default` = 1'); - - if (!$default_language->count()) { - // Default to 1 (EnglishUK) - $default_language = 1; - $default_short_code = 'en_UK'; - $db->query('UPDATE nl2_languages SET `is_default` = 1 WHERE `id` = 1'); - } else { - $default_language = $default_language->first()->id; - $default_short_code = $default_language->short_code; - } - - $this->_cache->store('language', $default_short_code); - - $db->query('UPDATE nl2_users SET `language_id` = ? WHERE `language_id` NOT IN (' . implode(', ', $converted_languages) . ')', [$default_language]); - }); - - // add updated column to users profile fields - $this->databaseQuery(function (DB $db) { - $db->addColumn('users_profile_fields', 'updated', 'int(11)'); - }); - - // update settings from true/false to 1/0 - $settings = ['displaynames', 'recaptcha', 'recaptcha_login', 'version_update', 'maintenance']; - foreach ($settings as $setting) { - $value = Util::getSetting($setting); - if ($value === 'true' || $value === '1') { - Util::setSetting($setting, '1'); - } else { - Util::setSetting($setting, '0'); - } - } - - // add captcha default - if (Util::getSetting('recaptcha_type') == null) { - Util::getSetting('recaptcha_type', 'Recaptcha3'); - } - - // delete old class files - $this->deleteFiles([ - 'core/classes/Alert.php', - 'core/classes/Announcements.php', - 'core/classes/AvatarSource.php', - 'core/classes/Cache.php', - 'core/classes/CaptchaBase.php', - 'core/classes/CollectionItemBase.php', - 'core/classes/CollectionManager.php', - 'core/classes/Config.php', - 'core/classes/Configuration.php', - 'core/classes/Cookie.php', - 'core/classes/DB.php', - 'core/classes/DB_Custom.php', - 'core/classes/Discord.php', - 'core/classes/Email.php', - 'core/classes/EndpointBase.php', - 'core/classes/Endpoints.php', - 'core/classes/ErrorHandler.php', - 'core/classes/ExternalMCQuery.php', - 'core/classes/Hash.php', - 'core/classes/HookHandler.php', - 'core/classes/Input.php', - 'core/classes/Language.php', - 'core/classes/Log.php', - 'core/classes/MCAssoc.php', - 'core/classes/MCQuery.php', - 'core/classes/MentionsParser.php', - 'core/classes/MinecraftBanner.php', - 'core/classes/MinecraftPing.php', - 'core/classes/Module.php', - 'core/classes/Navigation.php', - 'core/classes/Output.php', - 'core/classes/Pages.php', - 'core/classes/Paginator.php', - 'core/classes/PermissionHandler.php', - 'core/classes/Placeholders.php', - 'core/classes/Queries.php', - 'core/classes/Redirect.php', - 'core/classes/Report.php', - 'core/classes/ServerBanner.php', - 'core/classes/Session.php', - 'core/classes/TemplateBase.php', - 'core/classes/Timeago.php', - 'core/classes/Token.php', - 'core/classes/URL.php', - 'core/classes/User.php', - 'core/classes/Util.php', - 'core/classes/Validate.php', - 'core/classes/WidgetBase.php', - 'core/classes/Widgets.php', - 'modules/Core/classes/Core_Sitemap.php', - 'modules/Core/classes/CrafatarAvatarSource.php', - 'modules/Core/classes/CraftheadAvatarSource.php', - 'modules/Core/classes/CravatarAvatarSource.php', - 'modules/Core/classes/MCHeadsAvatarSource.php', - 'modules/Core/classes/MinotarAvatarSource.php', - 'modules/Core/classes/NamelessMCAvatarSource.php', - 'modules/Core/classes/Recaptcha2.php', - 'modules/Core/classes/Recaptcha3.php', - 'modules/Core/classes/VisageAvatarSource.php', - 'modules/Core/classes/hCaptcha.php', - 'modules/Core/includes/endpoints/discord/SetDiscordRolesEndpoint.php', - 'modules/Core/includes/endpoints/discord/SubmitDiscordRoleListEndpoint.php', - 'modules/Core/includes/endpoints/discord/UpdateDiscordBotSettingsEndpoint.php', - 'modules/Core/includes/endpoints/discord/UpdateDiscordUsernames.php', - 'modules/Core/includes/endpoints/discord/VerifyDiscordEndpoint.php', - 'modules/Core/includes/endpoints/ListGroupsEndpoint.php', - 'modules/Core/includes/endpoints/VerifyMinecraftEndpoint.php', - ]); - - // delete old home type cache & update new cache - $this->_cache->setCache('portal_cache'); - $portal = $this->_cache->retrieve('portal'); - $this->_cache->eraseAll(); - $this->databaseQuery(function (DB $db) use ($portal) { - Util::setSetting('portal', null); - Util::setSetting('home_type', $portal ? 'portal' : 'news'); - }); - - // add existing migrations to phinxlog table, so it doesn't try to run them again - $migrations = []; - $migrations_dir = ROOT_PATH . '/core/migrations'; - $files = scandir($migrations_dir); - foreach ($files as $file) { - if ($file === 'phinx.php' || str_starts_with($file, '.')) { - continue; - } - $file = explode('.', $file)[0]; - [$time, $name] = explode('_', $file, 2); - $name_parts = explode('_', $name); - // join name parts with upper case - $name = implode('', array_map('ucfirst', $name_parts)); - $epoch = time(); - $dt = new DateTime("@$epoch"); - $migrations[] = [ - 'version' => $time, - 'name' => $name, - 'start_time' => $dt->format('Y-m-d H:i:s'), - 'end_time' => $dt->format('Y-m-d H:i:s'), - 'breakpoint' => 0, - ]; - } - - $this->databaseQuery(function (DB $db) use ($migrations) { - $db->query("CREATE TABLE IF NOT EXISTS `nl2_phinxlog` ( - `version` bigint NOT NULL, - `migration_name` varchar(100) NULL DEFAULT NULL, - `start_time` timestamp NULL DEFAULT NULL, - `end_time` timestamp NULL DEFAULT NULL, - `breakpoint` tinyint(1) NOT NULL DEFAULT '0', - PRIMARY KEY (`version`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"); - $db->query("TRUNCATE TABLE `nl2_phinxlog`"); - - foreach ($migrations as $migration) { - $db->query("INSERT INTO nl2_phinxlog (`version`, `migration_name`, `start_time`, `end_time`, `breakpoint`) VALUES (?, ?, ?, ?, ?)", [ - $migration['version'], - $migration['name'], - $migration['start_time'], - $migration['end_time'], - $migration['breakpoint'], - ]); - } - }); - - $this->setVersion('2.0.0-pr13'); - } -} - -return new Pre13(); diff --git a/core/includes/updates/200-pr13.php b/core/includes/updates/200-pr13.php new file mode 100644 index 0000000000..83a1d1985b --- /dev/null +++ b/core/includes/updates/200-pr13.php @@ -0,0 +1,18 @@ +query('ALTER TABLE nl2_groups DROP COLUMN group_html_lg;'); + } catch (PDOException $e) { + if (!str_contains($e->getMessage(), 'check that column/key exists')) { + $this->log($e->getMessage()); + } + } + + $this->setVersion('2.0.0'); + } +} From b47135214d63dd41069ffd34b72c5ecc16b6dd69 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Fri, 10 Jun 2022 22:12:31 -0600 Subject: [PATCH 071/337] Fix MCAssoc client js path --- core/classes/Templates/AssetTree.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/classes/Templates/AssetTree.php b/core/classes/Templates/AssetTree.php index 85f4beaeb4..8ef1e95c94 100644 --- a/core/classes/Templates/AssetTree.php +++ b/core/classes/Templates/AssetTree.php @@ -191,7 +191,7 @@ class AssetTree { ], self::MCASSOC_CLIENT => [ 'js' => [ - 'js/mcassoc-client.js', + 'js/mcassoc_client.js', ], ], self::MOMENT => [ From f547b1d80990b4d9f879d90c203eca40fee75646 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Fri, 10 Jun 2022 22:24:18 -0600 Subject: [PATCH 072/337] Fix #2796 --- modules/Core/pages/panel/users_edit.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/modules/Core/pages/panel/users_edit.php b/modules/Core/pages/panel/users_edit.php index 4bfb91a989..57ea7c9ad0 100644 --- a/modules/Core/pages/panel/users_edit.php +++ b/modules/Core/pages/panel/users_edit.php @@ -170,6 +170,7 @@ 'theme_id' => $new_template ]); + $group_sync_log = []; if ($view_user->data()->id != $user->data()->id || $user->hasPermission('admincp.groups.self')) { if ($view_user->data()->id == 1 || (isset($_POST['groups']) && count($_POST['groups']))) { $modified = []; @@ -192,7 +193,7 @@ } // Dispatch the modified groups - GroupSyncManager::getInstance()->broadcastChange( + $group_sync_log = GroupSyncManager::getInstance()->broadcastChange( $view_user, NamelessMCGroupSyncInjector::class, $modified @@ -200,6 +201,16 @@ } } + if (!count($group_sync_log)) { + // TODO: more "dynamic" since we should not assume they don't have other group sync injectors installed by a module + $rules = DB::getInstance()->query( + 'SELECT COUNT(*) AS count FROM nl2_group_sync WHERE website_group_id IN (' . implode(', ', $modified) . ') AND discord_role_id IS NOT NULL;' + )->first()->count; + if ($rules > 0) { + Session::flash('edit_user_warnings', 'Group sync rules are setup but no changes were reported. This could indicate a misconfiguration.'); + } + } + Session::flash('edit_user_success', $language->get('admin', 'user_updated_successfully')); Redirect::to(URL::build('/panel/users/edit/', 'id=' . urlencode($user_query->id))); } catch (Exception $e) { @@ -240,7 +251,7 @@ } if (Session::exists('edit_user_warnings')) { - $warnings = Session::flash('edit_user_warnings'); + $warnings = [Session::flash('edit_user_warnings')]; } if (isset($success)) { From 35dff72296594f022e190577fbf079a29040d0f8 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Fri, 10 Jun 2022 22:37:20 -0600 Subject: [PATCH 073/337] Add method to execute a DB query within a MySQL transaction (See: #2812) --- core/classes/Database/DB.php | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/core/classes/Database/DB.php b/core/classes/Database/DB.php index add027c852..ee48bd3fe8 100644 --- a/core/classes/Database/DB.php +++ b/core/classes/Database/DB.php @@ -13,7 +13,6 @@ class DB { private static ?DB $_instance = null; private string $_prefix; - private string $_database; private ?string $_force_charset; protected PDO $_pdo; private PDOStatement $_statement; @@ -26,7 +25,6 @@ private function __construct(string $host, string $database, string $username, s try { $this->_force_charset = $force_charset; $this->_prefix = $prefix; - $this->_database = $database; $connection_string = 'mysql:host=' . $host . ';port=' . $port . ';dbname=' . $database; if ($force_charset) { @@ -58,12 +56,27 @@ public function getPDO(): PDO { } /** - * Get the database name this instance is connected to. + * Execute a database query within a MySQL transaction, and get the results of the query, if any. * - * @return string Database name. + * @param Closure(DB): mixed $closure The closure to pass this instance to and execute within a transaction context. + * @return mixed The results of the query, null if none. */ - public function getDatabase(): string { - return $this->_database; + public function transaction(Closure $closure) { + $result = null; + + try { + $this->_pdo->beginTransaction(); + + $result = $closure($this); + + $this->_pdo->commit(); + } catch (Exception $exception) { + if ($this->_pdo->inTransaction()) { + $this->_pdo->rollBack(); + } + } + + return $result; } /** From 6dda4dba80de37d9646f4e3ffc2151a8aa93415c Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Fri, 10 Jun 2022 23:15:05 -0600 Subject: [PATCH 074/337] Send data about OAuth providers to debug link --- core/classes/Misc/NamelessOAuth.php | 5 +++-- modules/Core/module.php | 5 ++--- modules/Core/queries/debug_link.php | 15 +++++++++++++++ 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/core/classes/Misc/NamelessOAuth.php b/core/classes/Misc/NamelessOAuth.php index 72c1231ce2..e005f14e22 100644 --- a/core/classes/Misc/NamelessOAuth.php +++ b/core/classes/Misc/NamelessOAuth.php @@ -25,10 +25,11 @@ public function __construct() { * Add an OAuth provider to the system. * * @param string $name The name of the provider (Discord, Google, etc). + * @param string $module Name of the module which registered this provider. * @param array $data Metadata about the provider: class, user_id_name, scope_id_name, icon */ - public function registerProvider(string $name, array $data): void { - $this->_providers[$name] = $data; + public function registerProvider(string $name, string $module, array $data): void { + $this->_providers[$name] = array_merge(['module' => $module], $data); } /** diff --git a/modules/Core/module.php b/modules/Core/module.php index 49690511ff..7ee36fe88b 100644 --- a/modules/Core/module.php +++ b/modules/Core/module.php @@ -441,15 +441,14 @@ public function __construct(Language $language, Pages $pages, User $user, Naviga ] ); - // TODO: should this be in the Discord Integration module? - NamelessOAuth::getInstance()->registerProvider('discord', [ + NamelessOAuth::getInstance()->registerProvider('discord', 'Core', [ 'class' => \Wohali\OAuth2\Client\Provider\Discord::class, 'user_id_name' => 'id', 'scope_id_name' => 'identify', 'icon' => 'fab fa-discord', ]); - NamelessOAuth::getInstance()->registerProvider('google', [ + NamelessOAuth::getInstance()->registerProvider('google', 'Core', [ 'class' => \League\OAuth2\Client\Provider\Google::class, 'user_id_name' => 'sub', 'scope_id_name' => 'openid', diff --git a/modules/Core/queries/debug_link.php b/modules/Core/queries/debug_link.php index bf7eab0309..8c654e36db 100755 --- a/modules/Core/queries/debug_link.php +++ b/modules/Core/queries/debug_link.php @@ -150,6 +150,20 @@ ]; } +$oauth_providers = []; +$providers_available = array_keys(NamelessOAuth::getInstance()->getProvidersAvailable()); +foreach (NamelessOAuth::getInstance()->getProviders() as $provider_name => $data) { + $oauth_providers[$provider_name] = [ + 'provider_name' => $provider_name, + 'module' => $data['module'], + 'class' => $data['class'], + 'user_id_name' => $data['user_id_name'], + 'scope_id_name' => $data['scope_id_name'], + 'enabled' => in_array($provider_name, $providers_available), + 'client_id' => NamelessOAuth::getInstance()->getCredentials($provider_name)[0], + ]; +} + $namelessmc_version = Util::getSetting('nameless_version'); $uuid = DB::getInstance()->query('SELECT identifier FROM nl2_users_integrations INNER JOIN nl2_integrations on integration_id=nl2_integrations.id WHERE name = \'Minecraft\' AND user_id = ?;', [$user->data()->id]); @@ -204,6 +218,7 @@ 'panel' => $namelessmc_panel_templates, ], 'integrations' => $integrations, + 'oauth_providers' => $oauth_providers, ], 'logs' => [ 'fatal' => $logs['fatal'], From 21825f657a84bb2184866aa8addbf1060783c724 Mon Sep 17 00:00:00 2001 From: Robin Date: Sat, 11 Jun 2022 13:00:55 +0200 Subject: [PATCH 075/337] Assume server is not a bedrock server if not specified --- core/classes/Minecraft/MCQuery.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/classes/Minecraft/MCQuery.php b/core/classes/Minecraft/MCQuery.php index 091119099a..498ddaa921 100644 --- a/core/classes/Minecraft/MCQuery.php +++ b/core/classes/Minecraft/MCQuery.php @@ -303,7 +303,9 @@ public static function multiQuery(array $servers, string $type, Language $langua continue; } - $query = ExternalMCQuery::query($query_ip[0], ($query_ip[1] ?? ($server['bedrock'] ? 19132 : 25565)), $server['bedrock']); + $is_bedrock = isset($server['bedrock']) && $server['bedrock'] === true; + + $query = ExternalMCQuery::query($query_ip[0], ($query_ip[1] ?? ($is_bedrock ? 19132 : 25565)), $is_bedrock); if ($query !== false && !$query->error && isset($query->response)) { if ($accumulate === false) { From a30c3f829e1238fab22d1d91bc1c022e21289270 Mon Sep 17 00:00:00 2001 From: Robin Date: Sat, 11 Jun 2022 13:05:02 +0200 Subject: [PATCH 076/337] Never return null protocol, fix #2846 --- core/classes/Core/Util.php | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/core/classes/Core/Util.php b/core/classes/Core/Util.php index d0780e3e4b..ec4146ffcb 100644 --- a/core/classes/Core/Util.php +++ b/core/classes/Core/Util.php @@ -304,9 +304,9 @@ public static function getRemoteAddress(): ?string { /** * Get the protocol used by client's HTTP request, using proxy headers if necessary. * - * @return ?string 'http' if HTTP or 'https' if HTTPS, or null when using the CLI + * @return string 'http' if HTTP or 'https' if HTTPS. If the protocol is not known, for example when using the CLI, 'http' is always returned. */ - public static function getProtocol(): ?string { + public static function getProtocol(): string { if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) { $proto = $_SERVER['HTTP_X_FORWARDED_PROTO']; if ($proto !== 'http' && $proto !== 'https') { @@ -319,7 +319,7 @@ public static function getProtocol(): ?string { return $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http'; } - return null; + return 'http'; } /** @@ -353,9 +353,6 @@ public static function getSelfURL(bool $show_protocol = true): string { $hostname = $_SERVER['SERVER_NAME']; } - // https and www checks - $protocol = self::getProtocol() . '://'; - $url = $hostname; if (defined('FORCE_WWW') && FORCE_WWW && !str_contains($hostname, 'www')) { @@ -363,10 +360,11 @@ public static function getSelfURL(bool $show_protocol = true): string { } if ($show_protocol) { - $url = $protocol . $url; + $protocol = self::getProtocol() + $url = $protocol . '://' . $url; $port = self::getPort(); // Add port if it is non-standard for the current protocol - if (!(($port === 80 && $protocol === 'http://') || ($port === 443 && $protocol === 'https://'))) { + if (!(($port === 80 && $protocol === 'http') || ($port === 443 && $protocol === 'https'))) { $url .= ':' . $port; } } From c3173ee26f5cd666bb6b94ad8ee01921bf73f822 Mon Sep 17 00:00:00 2001 From: Robin Date: Sat, 11 Jun 2022 13:08:17 +0200 Subject: [PATCH 077/337] Fix syntax error --- core/classes/Core/Util.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/classes/Core/Util.php b/core/classes/Core/Util.php index ec4146ffcb..54e979969c 100644 --- a/core/classes/Core/Util.php +++ b/core/classes/Core/Util.php @@ -360,7 +360,7 @@ public static function getSelfURL(bool $show_protocol = true): string { } if ($show_protocol) { - $protocol = self::getProtocol() + $protocol = self::getProtocol(); $url = $protocol . '://' . $url; $port = self::getPort(); // Add port if it is non-standard for the current protocol From 1cdebe48c830c644e057d65f5cc1180b640fb679 Mon Sep 17 00:00:00 2001 From: Partydragen Date: Sat, 11 Jun 2022 17:05:14 +0200 Subject: [PATCH 078/337] Set active provider before validation checks --- modules/Core/pages/panel/registration.php | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/Core/pages/panel/registration.php b/modules/Core/pages/panel/registration.php index 2f6b022910..9dfd9d0485 100644 --- a/modules/Core/pages/panel/registration.php +++ b/modules/Core/pages/panel/registration.php @@ -62,6 +62,7 @@ // Validate captcha key and secret key if (!empty(Input::get('recaptcha_key')) || !empty(Input::get('recaptcha_secret')) || Input::get('enable_recaptcha') == 1 || Input::get('enable_recaptcha_login') == 1) { + $provider = CaptchaBase::setActiveProvider(Input::get('captcha_type')); $provider = CaptchaBase::getActiveProvider(); if ($provider->validateSecret(Input::get('recaptcha_secret')) == false || $provider->validateKey(Input::get('recaptcha')) == false) { $errors[] = $language->get('admin', 'invalid_recaptcha_settings', [ From 3221cdec415404fdfdf83851e2d3d68eebe39c55 Mon Sep 17 00:00:00 2001 From: Partydragen Date: Sat, 11 Jun 2022 17:10:28 +0200 Subject: [PATCH 079/337] Fix phpstan --- modules/Core/pages/panel/registration.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/Core/pages/panel/registration.php b/modules/Core/pages/panel/registration.php index 9dfd9d0485..15db580514 100644 --- a/modules/Core/pages/panel/registration.php +++ b/modules/Core/pages/panel/registration.php @@ -62,7 +62,8 @@ // Validate captcha key and secret key if (!empty(Input::get('recaptcha_key')) || !empty(Input::get('recaptcha_secret')) || Input::get('enable_recaptcha') == 1 || Input::get('enable_recaptcha_login') == 1) { - $provider = CaptchaBase::setActiveProvider(Input::get('captcha_type')); + CaptchaBase::setActiveProvider(Input::get('captcha_type')); + $provider = CaptchaBase::getActiveProvider(); if ($provider->validateSecret(Input::get('recaptcha_secret')) == false || $provider->validateKey(Input::get('recaptcha')) == false) { $errors[] = $language->get('admin', 'invalid_recaptcha_settings', [ From a0a8df5612dcbdacbde95af591708194fec23655 Mon Sep 17 00:00:00 2001 From: Supercrafter100 <58982133+supercrafter100@users.noreply.github.com> Date: Sat, 11 Jun 2022 18:30:42 +0200 Subject: [PATCH 080/337] Update hCaptcha.php (#2849) --- modules/Core/classes/Captcha/hCaptcha.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/modules/Core/classes/Captcha/hCaptcha.php b/modules/Core/classes/Captcha/hCaptcha.php index f5353d3f0b..c64900d6ac 100755 --- a/modules/Core/classes/Captcha/hCaptcha.php +++ b/modules/Core/classes/Captcha/hCaptcha.php @@ -33,12 +33,7 @@ public function validateSecret(string $_secret) : bool { } public function validateKey(string $key) : bool { - $url = 'https://api.hcaptcha.com/checksiteconfig?sitekey=' . $key; - $client = HttpClient::get($url); - if ($client->hasError()) { - return false; - } - return $client->json(true)['pass'] == true; + return true; // hCaptcha changed their validation so this is a temporary fix } public function getHtml(): string { From 95dd115e17a6c902bfeca9b86dd18b50a50065f0 Mon Sep 17 00:00:00 2001 From: Robin Date: Sat, 11 Jun 2022 20:58:44 +0200 Subject: [PATCH 081/337] Workaround for broken determineOrder() for empty arrays --- core/classes/Core/Util.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/classes/Core/Util.php b/core/classes/Core/Util.php index 54e979969c..7428ecb52e 100644 --- a/core/classes/Core/Util.php +++ b/core/classes/Core/Util.php @@ -723,6 +723,10 @@ public static function readFileEnd(string $file_path, int $max_bytes = 100_000): * @return array Ordered items */ public static function determineOrder(array $items): array { + if (empty($items)) { + return $items; + } + $order = [array_shift($items)['name']]; foreach ($items as $item) { From d98c9657dc126739d26652966b26f17bf84472dd Mon Sep 17 00:00:00 2001 From: Partydragen Date: Sat, 11 Jun 2022 22:41:04 +0200 Subject: [PATCH 082/337] Make transform public --- core/classes/Endpoints/ManagesTransformers.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/classes/Endpoints/ManagesTransformers.php b/core/classes/Endpoints/ManagesTransformers.php index d27a5a9194..b863edee50 100644 --- a/core/classes/Endpoints/ManagesTransformers.php +++ b/core/classes/Endpoints/ManagesTransformers.php @@ -67,7 +67,7 @@ public static function registerTransformer(string $type, string $module, Closure * @param string $value The value to convert. * @return mixed The converted value. */ - private static function transform(Nameless2API $api, string $type, string $value) { + public static function transform(Nameless2API $api, string $type, string $value) { if (array_key_exists($type, self::$_transformers)) { return self::$_transformers[$type]['transformer']($api, $value); } From a01120d1fe1919e9f90ff5401460905d46b0b192 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Sat, 11 Jun 2022 22:16:59 -0600 Subject: [PATCH 083/337] Use migration to drop group_html_lg column --- core/includes/updates/200-pr13.php | 10 ------- ...p_group_html_lg_column_on_groups_table.php | 28 +++++++++++++++++++ 2 files changed, 28 insertions(+), 10 deletions(-) create mode 100644 core/migrations/20220612041555_drop_group_html_lg_column_on_groups_table.php diff --git a/core/includes/updates/200-pr13.php b/core/includes/updates/200-pr13.php index 83a1d1985b..8c852dac48 100644 --- a/core/includes/updates/200-pr13.php +++ b/core/includes/updates/200-pr13.php @@ -3,16 +3,6 @@ class Nameless200 extends UpgradeScript { public function run(): void { - $db = DB::getInstance(); - - try { - $db->query('ALTER TABLE nl2_groups DROP COLUMN group_html_lg;'); - } catch (PDOException $e) { - if (!str_contains($e->getMessage(), 'check that column/key exists')) { - $this->log($e->getMessage()); - } - } - $this->setVersion('2.0.0'); } } diff --git a/core/migrations/20220612041555_drop_group_html_lg_column_on_groups_table.php b/core/migrations/20220612041555_drop_group_html_lg_column_on_groups_table.php new file mode 100644 index 0000000000..c8bac648a9 --- /dev/null +++ b/core/migrations/20220612041555_drop_group_html_lg_column_on_groups_table.php @@ -0,0 +1,28 @@ +table('nl2_groups'); + + if ($table->hasColumn('group_html_lg')) { + $table->removeColumn('group_html_lg'); + $table->update(); + } + } +} From 5a9b32ccbc6dab202e537d0c4a6e4b8fe0a0f937 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Sat, 11 Jun 2022 22:37:16 -0600 Subject: [PATCH 084/337] Fix #2785 --- custom/templates/DefaultRevamp/widgets/statistics.tpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom/templates/DefaultRevamp/widgets/statistics.tpl b/custom/templates/DefaultRevamp/widgets/statistics.tpl index f7498e9fdb..132b5a3e5f 100755 --- a/custom/templates/DefaultRevamp/widgets/statistics.tpl +++ b/custom/templates/DefaultRevamp/widgets/statistics.tpl @@ -17,7 +17,7 @@ {$USERS_REGISTERED}
{$USERS_REGISTERED_VALUE}
-
+
{$LATEST_MEMBER}
-
\ No newline at end of file +
From d3de874575293b6ee2991050d8d9539e66983de4 Mon Sep 17 00:00:00 2001 From: Robin Date: Sun, 12 Jun 2022 14:01:39 +0200 Subject: [PATCH 085/337] don't require tps, it's not used anyway --- modules/Core/includes/endpoints/ServerInfoEndpoint.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Core/includes/endpoints/ServerInfoEndpoint.php b/modules/Core/includes/endpoints/ServerInfoEndpoint.php index d7b1af70be..22880fad2c 100644 --- a/modules/Core/includes/endpoints/ServerInfoEndpoint.php +++ b/modules/Core/includes/endpoints/ServerInfoEndpoint.php @@ -10,7 +10,7 @@ public function __construct() { } public function execute(Nameless2API $api): void { - $api->validateParams($_POST, ['server-id', 'max-memory', 'free-memory', 'allocated-memory', 'tps']); + $api->validateParams($_POST, ['server-id', 'max-memory', 'free-memory', 'allocated-memory']); if (!isset($_POST['players'])) { $api->throwError(Nameless2API::ERROR_INVALID_POST_CONTENTS, 'players'); } From 1642b9107b44da736d7e655f191f9bdbed0e81b8 Mon Sep 17 00:00:00 2001 From: Robin Date: Sun, 12 Jun 2022 22:30:37 +0200 Subject: [PATCH 086/337] Verify that the provided converter exists --- core/installation/steps/conversion_perform.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/core/installation/steps/conversion_perform.php b/core/installation/steps/conversion_perform.php index 371990ca92..e9191fbc51 100644 --- a/core/installation/steps/conversion_perform.php +++ b/core/installation/steps/conversion_perform.php @@ -69,7 +69,16 @@ $password, Input::get('db_port') ); - require_once(ROOT_PATH . '/custom/converters/' . $_POST['converter'] . '/converter.php'); + + $converter_dir = ROOT_PATH . '/custom/converters/' . $_POST['converter']; + + $converter_dirs = glob(ROOT_PATH . '/custom/converters/*', GLOB_ONLYDIR); + + if (!in_array($converter_dir, $converter_dirs)) { + throw new InvalidArgumentException("Invalid converter"); + } + + require_once($converter_dir . '/converter.php'); if (!isset($error)) { Redirect::to('?step=finish'); From 7f6fc69c3eedf49cc2eefd394cc139bb0497944f Mon Sep 17 00:00:00 2001 From: Robin Date: Sun, 12 Jun 2022 23:12:21 +0200 Subject: [PATCH 087/337] Bring back trusted proxies, somewhat securly Ideal situation: Completely deny ALL requests with a proxy header if no trusted proxies are configured. Force proper configuration. After Samerton's change just before pr13: If not configured (there is no warning), anyone can bypass IP checks, like for IP bans. Just to be clear: this affects EVERYONE, not just people with or without a proxy. Situation now: If not configured, only the actual client address is trusted, not any header. This means users are not able to bypass IP bans, but if an admin bans a user, if that site uses a proxy, and if trusted proxies is not configured, they wil ban the proxy, meaning all users will be ip-banned. A warning is displayed in StaffCP if trusted proxies is not configured. --- core/classes/Core/Util.php | 61 ++++++++----------- core/includes/updates/200-pr13.php | 12 ++++ .../steps/database_configuration.php | 2 +- custom/languages/en_UK.json | 2 + modules/Core/pages/panel/index.php | 9 +++ scripts/cli_install.php | 2 +- 6 files changed, 52 insertions(+), 36 deletions(-) diff --git a/core/classes/Core/Util.php b/core/classes/Core/Util.php index 7428ecb52e..4ca0a6dd24 100644 --- a/core/classes/Core/Util.php +++ b/core/classes/Core/Util.php @@ -130,55 +130,51 @@ public static function isExternalURL(string $url): bool { return !(str_replace('www.', '', rtrim(self::getSelfURL(false), '/')) == str_replace('www.', '', $parsed['host'])); } + public static function isTrustedProxiesConfigured() { + $config_proxies = Config::get('core/trustedProxies'); + $env_proxies = getenv('NAMELESS_TRUSTED_PROXIES'); + return $config_proxies !== false && $config_proxies !== null && is_array($config_proxies) + || $env_proxies !== false; + } + /** * @return array List of trusted proxy networks according to config file and environment */ public static function getTrustedProxies(): array { - $trustedProxies = []; + $trusted_proxies = []; // Add trusted proxies from config file - $configProxies = Config::get('core/trustedProxies'); - if ($configProxies !== false) { - if (!is_array($configProxies)) { + $config_proxies = Config::get('core/trustedProxies'); + if ($config_proxies !== false && $config_proxies !== null) { + if (!is_array($config_proxies)) { die('Trusted proxies should be an array'); } - $trustedProxies = array_merge($trustedProxies, $configProxies); + $trusted_proxies = array_merge($trusted_proxies, $config_proxies); } // Add trusted proxies from environment variable (comma-separated string) - $envProxies = getenv('NAMELESS_TRUSTED_PROXIES'); - if ($envProxies !== false) { - $envProxiesArray = explode(',', $envProxies); - $trustedProxies = array_merge($trustedProxies, $envProxiesArray); + $env_proxies = getenv('NAMELESS_TRUSTED_PROXIES'); + if ($env_proxies !== false && $env_proxies !== 'none') { + $env_proxies_array = explode(',', $env_proxies); + $trusted_proxies = array_merge($trusted_proxies, $env_proxies_array); } - return $trustedProxies; + return $trusted_proxies; } /** - * Checks whether the client making the request is a trusted proxy. If not, - * abruptly aborts the request using die(). + * Checks whether the client making the request is a trusted proxy. */ - private static function ensureTrustedProxy(): void { - $trustedProxies = self::getTrustedProxies(); - - if (count($trustedProxies) === 0) { - ErrorHandler::logWarning('Received proxy header but no trusted proxies are configured. Please see https://docs.namelessmc.com/trusted-proxies for more information.'); - return; - } - - $trusted = false; + private static function isTrustedProxy(): bool { + $trusted_proxies = self::getTrustedProxies(); - foreach ($trustedProxies as $trustedProxy) { + foreach ($trusted_proxies as $trustedProxy) { if (IpUtils::checkIp($_SERVER['REMOTE_ADDR'], $trustedProxy)) { - $trusted = true; - break; + return true; } } - if (!$trusted) { - die('Received proxy header from untrusted remote address: ' . $_SERVER['REMOTE_ADDR']); - } + return false; } /** @@ -229,19 +225,21 @@ private static function firstNonProxyAddress(array $addresses): string { * @return ?string Client IP address, or null if there is no remote address, for example in CLI environment */ public static function getRemoteAddress(): ?string { + if (!self::isTrustedProxy()) { + return $_SERVER['REMOTE_ADDR']; + } + $headers = getallheaders(); // Try the simple headers first that only contain an IP address // Non standard header that only contains the origin address if (isset($headers['X-Real-Ip'])) { - self::ensureTrustedProxy(); return $headers['X-Real-Ip']; } // Non standard header sent by CloudFlare that only contains the origin address if (isset($headers['Cf-Connecting-Ip'])) { - self::ensureTrustedProxy(); return $headers['Cf-Connecting-Ip']; } @@ -263,8 +261,6 @@ public static function getRemoteAddress(): ?string { */ if (isset($headers['X-Forwarded-For'])) { - self::ensureTrustedProxy(); - $addresses = []; foreach (explode(',', $headers['X-Forwarded-For']) as $part) { $addresses[] = trim($part); @@ -274,8 +270,6 @@ public static function getRemoteAddress(): ?string { } if (isset($headers['Forwarded'])) { - self::ensureTrustedProxy(); - $addresses = []; foreach (explode(',', $headers['Forwarded']) as $part1) { // Extract the optional 'for=
' bit @@ -297,7 +291,6 @@ public static function getRemoteAddress(): ?string { } } - // No supported proxy headers in use return $_SERVER['REMOTE_ADDR']; } diff --git a/core/includes/updates/200-pr13.php b/core/includes/updates/200-pr13.php index 8c852dac48..92dba53523 100644 --- a/core/includes/updates/200-pr13.php +++ b/core/includes/updates/200-pr13.php @@ -3,6 +3,18 @@ class Nameless200 extends UpgradeScript { public function run(): void { + $trusted_proxies = Config::get('core/trustedProxies'); + // If trusted proxies is an empty array + if ($trusted_proxies !== null && + is_countable($trusted_proxies) && + count($trusted_proxies) == 0) { + + // The core/trustedProxies option was mistakenly set during the installer for pr13. If we decide to + // allow not configuring it, at least it must be in an "unconfigured" state by default so StaffCP + // can display a warning until it is explicitly set to an empty or non-empty array by the user. + Config::set('core/trustedProxies', null); + } + $this->setVersion('2.0.0'); } } diff --git a/core/installation/steps/database_configuration.php b/core/installation/steps/database_configuration.php index 88593a140f..95fa98925a 100644 --- a/core/installation/steps/database_configuration.php +++ b/core/installation/steps/database_configuration.php @@ -80,7 +80,7 @@ 'force_www' => false, 'captcha' => false, 'date_format' => 'd M Y, H:i', - 'trustedProxies' => [], + 'trustedProxies' => null, ], ]; diff --git a/custom/languages/en_UK.json b/custom/languages/en_UK.json index c3498c7975..aa90dfb67c 100644 --- a/custom/languages/en_UK.json +++ b/custom/languages/en_UK.json @@ -679,6 +679,8 @@ "admin/x_directory_not_writable": "The {{directory}} directory is not writable!", "admin/youtube_url": "Youtube URL", "admin/api_disabled": "API is disabled", + "admin/trusted_proxies_configured": "Trusted proxies", + "admin/trusted_proxies_not_configured": "{{linkStart}}Trusted proxies{{linkEnd}} are not configured, IP bans may not work properly.", "api/account_validated": "Account validated successfully", "api/finish_registration_email": "Please check your emails to complete registration.", "api/finish_registration_link": "Please click on the following link to complete registration:", diff --git a/modules/Core/pages/panel/index.php b/modules/Core/pages/panel/index.php index b2b43a4203..f5d499cea0 100644 --- a/modules/Core/pages/panel/index.php +++ b/modules/Core/pages/panel/index.php @@ -198,6 +198,15 @@ $compat_success[] = $language->get('installer', 'template_cache_writable'); } + if (Util::isTrustedProxiesConfigured()) { + $compat_success[] = $language->get('admin', 'trusted_proxies_configured'); + } else { + $compat_errors[] = $language->get('admin', 'trusted_proxies_not_configured', [ + 'linkStart' => '', + 'linkEnd' => '', + ]); + } + $smarty->assign([ 'SERVER_COMPATIBILITY' => $language->get('admin', 'server_compatibility'), 'COMPAT_SUCCESS' => $compat_success, diff --git a/scripts/cli_install.php b/scripts/cli_install.php index 3192a5f565..f8d96731d0 100644 --- a/scripts/cli_install.php +++ b/scripts/cli_install.php @@ -116,7 +116,7 @@ function getEnvVar(string $name, string $fallback = null, array $valid_values = 'force_www' => false, 'captcha' => false, 'date_format' => 'd M Y, H:i', - 'trustedProxies' => [], + 'trustedProxies' => null, ], ]; From ada40cd5a5dd566a65bea02331bbab144d3da3a9 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Sun, 12 Jun 2022 16:00:27 -0600 Subject: [PATCH 088/337] Fix PhinxAdapter error --- core/classes/Database/PhinxAdapter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/classes/Database/PhinxAdapter.php b/core/classes/Database/PhinxAdapter.php index 13b4d14842..5b7b8ca421 100644 --- a/core/classes/Database/PhinxAdapter.php +++ b/core/classes/Database/PhinxAdapter.php @@ -18,7 +18,7 @@ public static function ensureUpToDate(): void { // Likely a pull from the repo dev branch or migrations // weren't run during an upgrade script. - if (($diff = abs($migration_files - $migration_database_entries)) > 0) { + if (($diff = $migration_files - $migration_database_entries) > 0) { throw new RuntimeException("There are {$diff} database migrations pending."); } From 3b1bfa654a5101fac9817f8707e664cc370243d2 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Sun, 12 Jun 2022 16:08:59 -0600 Subject: [PATCH 089/337] Fix TinyMCE to not have to rely on dark mode constant --- core/classes/Core/Input.php | 10 +++++++++- custom/templates/DefaultRevamp/template.php | 1 - .../DefaultRevamp/template_settings/settings.php | 5 ----- modules/Core/module.php | 4 ---- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/core/classes/Core/Input.php b/core/classes/Core/Input.php index 7656b6c08c..738240eb2b 100644 --- a/core/classes/Core/Input.php +++ b/core/classes/Core/Input.php @@ -57,7 +57,15 @@ public static function get(string $item) { * @param bool $mentions Whether to enable mention autocompletion/parsing or not. */ public static function createTinyEditor(Language $language, string $name, ?string $content = null, bool $mentions = false): string { - $skin = defined('TEMPLATE_TINY_EDITOR_DARKMODE') ? 'oxide-dark' : 'oxide'; + if ( + (defined('DARK_MODE') && DARK_MODE) || + (Cookie::exists('nmc_panel_theme') && Cookie::get('nmc_panel_theme') === 'dark') + ) { + $skin = 'oxide-dark'; + } else { + $skin = 'oxide'; + } + $js = ''; if ($mentions) { diff --git a/custom/templates/DefaultRevamp/template.php b/custom/templates/DefaultRevamp/template.php index f5c7440c06..bbf33a24c4 100755 --- a/custom/templates/DefaultRevamp/template.php +++ b/custom/templates/DefaultRevamp/template.php @@ -61,7 +61,6 @@ public function __construct($cache, $smarty, $language, $user, $pages) { if (defined('DARK_MODE') && DARK_MODE == '1') { $smartyDarkMode = true; - define('TEMPLATE_TINY_EDITOR_DARKMODE', true); } if ($cache->isCached('navbarColour')) { diff --git a/custom/templates/DefaultRevamp/template_settings/settings.php b/custom/templates/DefaultRevamp/template_settings/settings.php index aca1cb8387..34b87b807d 100644 --- a/custom/templates/DefaultRevamp/template_settings/settings.php +++ b/custom/templates/DefaultRevamp/template_settings/settings.php @@ -117,11 +117,6 @@ AssetTree::TINYMCE, ]); -// We have to define this here because this is run before Module::onPageLoad, so it hasn't been defined yet -if (Cookie::exists('nmc_panel_theme') && Cookie::get('nmc_panel_theme') === 'dark') { - define('TEMPLATE_TINY_EDITOR_DARKMODE', true); -} - $current_template->addJSScript(Input::createTinyEditor($language, 'inputHomeCustomContent', Util::getSetting('home_custom_content'))); $smarty->assign([ diff --git a/modules/Core/module.php b/modules/Core/module.php index 7ee36fe88b..2982d6e88e 100644 --- a/modules/Core/module.php +++ b/modules/Core/module.php @@ -1532,10 +1532,6 @@ public function onPageLoad(User $user, Pages $pages, Cache $cache, Smarty $smart if ($user->hasPermission('modcp.reports')) { self::addUserAction($language->get('moderator', 'reports'), URL::build('/panel/users/reports/', 'uid={id}')); } - - if (Cookie::exists('nmc_panel_theme') && Cookie::get('nmc_panel_theme') === 'dark') { - define('TEMPLATE_TINY_EDITOR_DARKMODE', true); - } } require_once(ROOT_PATH . '/modules/Core/hooks/DeleteUserHook.php'); From bf23040247e2580aba69dac698d4a807a7a758c5 Mon Sep 17 00:00:00 2001 From: PadowYT2 Date: Mon, 13 Jun 2022 10:15:20 +0800 Subject: [PATCH 090/337] Dark/light mode for Captcha (#2852) Co-authored-by: Tadhg Boyle --- modules/Core/classes/Captcha/Recaptcha2.php | 6 +++++- modules/Core/classes/Captcha/hCaptcha.php | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/modules/Core/classes/Captcha/Recaptcha2.php b/modules/Core/classes/Captcha/Recaptcha2.php index 36e681b24c..25f70dedf9 100755 --- a/modules/Core/classes/Captcha/Recaptcha2.php +++ b/modules/Core/classes/Captcha/Recaptcha2.php @@ -44,7 +44,11 @@ public function validateKey(string $key) : bool { } public function getHtml(): string { - return '
'; + if (defined('DARK_MODE') && DARK_MODE == 1) { + return '
'; + } else { + return '
'; + } } public function getJavascriptSource(): string { diff --git a/modules/Core/classes/Captcha/hCaptcha.php b/modules/Core/classes/Captcha/hCaptcha.php index c64900d6ac..37c5f82fcb 100755 --- a/modules/Core/classes/Captcha/hCaptcha.php +++ b/modules/Core/classes/Captcha/hCaptcha.php @@ -37,7 +37,11 @@ public function validateKey(string $key) : bool { } public function getHtml(): string { - return '
'; + if (defined('DARK_MODE') && DARK_MODE == 1) { + return '
'; + } else { + return '
'; + } } public function getJavascriptSource(): string { From 4d16d3f555f1d783910498487405898f8fe743f5 Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 13 Jun 2022 02:21:21 +0000 Subject: [PATCH 091/337] Rewrite configuration file operations (#2850) Co-authored-by: Tadhg Boyle --- core/classes/Core/Config.php | 131 ++++++++++-------- core/classes/Core/URL.php | 25 ++-- core/classes/Database/DB.php | 31 ++--- core/classes/Database/DatabaseInitialiser.php | 15 +- core/classes/Database/QueryRecorder.php | 2 +- core/classes/Misc/DebugBarHelper.php | 2 +- core/classes/Misc/ErrorHandler.php | 6 +- core/includes/updates/200-pr13.php | 12 ++ core/init.php | 32 +++-- core/installation/steps/ajax_initialise.php | 2 +- .../installation/steps/conversion_perform.php | 35 +---- .../steps/database_configuration.php | 119 ++++++---------- core/installation/steps/finish.php | 7 +- .../steps/requirements_validation.php | 13 +- core/installation/steps/upgrade.php | 14 +- custom/languages/en_UK.json | 3 +- index.php | 12 +- install.php | 27 ++-- modules/Core/pages/panel/general_settings.php | 11 -- modules/Core/pages/panel/registration.php | 11 -- modules/Core/queries/debug_link.php | 4 +- modules/Core/widgets/ServerStatusWidget.php | 22 +-- scripts/cli_install.php | 26 ++-- scripts/seeder/db_seeder.php | 10 +- 24 files changed, 261 insertions(+), 311 deletions(-) diff --git a/core/classes/Core/Config.php b/core/classes/Core/Config.php index 2f805d2994..a4fc9a8b52 100644 --- a/core/classes/Core/Config.php +++ b/core/classes/Core/Config.php @@ -4,40 +4,84 @@ * * @package NamelessMC\Core * @author Samerton - * @version 2.0.0-pr8 + * @version 2.0.0 * @license MIT */ class Config { + private static ?array $_config_cache = null; + + /** + * @return bool Whether config file exists + */ + public static function exists(): bool { + return file_exists(ROOT_PATH . '/core/config.php'); + } + + /** + * Read `core/config.php` file and load into cache + * + * @return array The entire config array + */ + public static function all(): array { + if (self::$_config_cache !== null) { + return self::$_config_cache; + } + + if (!self::exists()) { + throw new RuntimeException('Config file does not exist'); + } + + require(ROOT_PATH . '/core/config.php'); + + /** @phpstan-ignore-next-line */ + if (!isset($conf) || !is_array($conf)) { + throw new RuntimeException('Config file is invalid'); + } + + /** @phpstan-ignore-next-line */ + return self::$_config_cache = $conf; + } + + /** + * Overwrite new `core/config.php` file. + * + * @param array $config New config array to store. + */ + public static function write(array $config): void { + $contents = ' $value) { $path = explode('/', $key); if (!is_array($path)) { - $conf[$key] = $value; + $config[$key] = $value; } else { - $loc = &$conf; + $loc = &$config; foreach ($path as $step) { $loc = &$loc[$step]; } @@ -118,6 +133,6 @@ public static function setMultiple(array $values): bool { } } - return static::write($conf); + static::write($config); } } diff --git a/core/classes/Core/URL.php b/core/classes/Core/URL.php index f068fb93fa..6a5246e196 100644 --- a/core/classes/Core/URL.php +++ b/core/classes/Core/URL.php @@ -19,25 +19,30 @@ class URL { * @return string Assembled URL, false on failure. */ public static function build(string $url, string $params = '', ?string $force = null): string { - if (is_null($force)) { - if ((defined('FRIENDLY_URLS') && FRIENDLY_URLS == true) || (!defined('FRIENDLY_URLS') && Config::get('core/friendly') == true)) { - // Friendly URLs are enabled - return self::buildFriendly($url, $params); - } + if ($force === 'friendly') { + return self::buildFriendly($url, $params); + } - // Friendly URLs are disabled, we need to change it + if ($force === 'non-friendly') { return self::buildNonFriendly($url, $params); } - if ($force === 'friendly') { + // Use non-friendly URLs if NamelessMC is not installed yet + if (!Config::exists()) { return self::buildFriendly($url, $params); } - if ($force === 'non-friendly') { - return self::buildNonFriendly($url, $params); + if (!is_null($force)) { + throw new InvalidArgumentException('Invalid force string: ' . $force); + } + + if ((defined('FRIENDLY_URLS') && FRIENDLY_URLS == true) || (!defined('FRIENDLY_URLS') && Config::get('core/friendly') == true)) { + // Friendly URLs are enabled + return self::buildFriendly($url, $params); } - throw new InvalidArgumentException('Invalid force string: ' . $force); + // Friendly URLs are disabled, we need to change it + return self::buildNonFriendly($url, $params); } /** diff --git a/core/classes/Database/DB.php b/core/classes/Database/DB.php index ee48bd3fe8..f98733bb68 100644 --- a/core/classes/Database/DB.php +++ b/core/classes/Database/DB.php @@ -22,26 +22,21 @@ class DB { protected QueryRecorder $_query_recorder; private function __construct(string $host, string $database, string $username, string $password, int $port, ?string $force_charset, string $prefix) { - try { - $this->_force_charset = $force_charset; - $this->_prefix = $prefix; + $this->_force_charset = $force_charset; + $this->_prefix = $prefix; - $connection_string = 'mysql:host=' . $host . ';port=' . $port . ';dbname=' . $database; - if ($force_charset) { - $connection_string .= ';charset=' . $force_charset; - } - $this->_pdo = new PDO( - $connection_string, - $username, - $password, - [ - PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, - ] - ); - - } catch (PDOException $e) { - die("Error:
" . $e->getMessage() . '
Please check your database connection settings.'); + $connection_string = 'mysql:host=' . $host . ';port=' . $port . ';dbname=' . $database; + if ($force_charset) { + $connection_string .= ';charset=' . $force_charset; } + $this->_pdo = new PDO( + $connection_string, + $username, + $password, + [ + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + ] + ); $this->_query_recorder = QueryRecorder::getInstance(); } diff --git a/core/classes/Database/DatabaseInitialiser.php b/core/classes/Database/DatabaseInitialiser.php index f32920be6a..2e68c64069 100644 --- a/core/classes/Database/DatabaseInitialiser.php +++ b/core/classes/Database/DatabaseInitialiser.php @@ -4,16 +4,14 @@ class DatabaseInitialiser { private DB $_db; private Cache $_cache; - private array $_config; - private function __construct(array $config = []) { + private function __construct() { $this->_db = DB::getInstance(); $this->_cache = new Cache(); - $this->_config = $config; } - public static function runPreUser(array $config) { - $instance = new self($config); + public static function runPreUser() { + $instance = new self(); $instance->initialiseGroups(); $instance->initialiseLanguages(); $instance->initialiseModules(); @@ -247,9 +245,10 @@ private function initialiseTemplates(): void { ]); $this->_cache->store('panel_default', 'Default'); - - $config_path = $this->_config['core']['path']; - $config_path = ($config_path ? '/' . trim($config_path, '/') : ''); + $config_path = Config::get('core/path'); + if (!empty($config_path)) { + $config_path = '/' . trim($config_path, '/'); + } $this->_cache->setCache('backgroundcache'); $this->_cache->store('banner_image', $config_path . '/uploads/template_banners/homepage_bg_trimmed.jpg'); diff --git a/core/classes/Database/QueryRecorder.php b/core/classes/Database/QueryRecorder.php index 5c501fd7cc..ceb8437c6f 100644 --- a/core/classes/Database/QueryRecorder.php +++ b/core/classes/Database/QueryRecorder.php @@ -10,7 +10,7 @@ */ class QueryRecorder extends Instanceable { - private array $_query_stack; + private array $_query_stack = []; private int $_query_stack_num = 1; /** diff --git a/core/classes/Misc/DebugBarHelper.php b/core/classes/Misc/DebugBarHelper.php index bf8c0c5e5a..2806cadd34 100644 --- a/core/classes/Misc/DebugBarHelper.php +++ b/core/classes/Misc/DebugBarHelper.php @@ -31,7 +31,7 @@ public function enable(Smarty $smarty): void { $debugbar->addCollector(new RequestDataCollector()); $configCollector = new ConfigCollector(); - $configCollector->setData(array_filter($GLOBALS['config'], static function ($key) { + $configCollector->setData(array_filter(Config::all(), static function ($key) { return $key !== 'mysql'; }, ARRAY_FILTER_USE_KEY)); $debugbar->addCollector($configCollector); diff --git a/core/classes/Misc/ErrorHandler.php b/core/classes/Misc/ErrorHandler.php index 85139c193e..30021208d5 100644 --- a/core/classes/Misc/ErrorHandler.php +++ b/core/classes/Misc/ErrorHandler.php @@ -110,14 +110,14 @@ public static function catchException(?Throwable $exception, ?string $error_stri $language = new Language('core', 'en_UK'); } - $detailed_error = defined('DEBUGGING'); - $can_generate_debug = defined('DEBUGGING'); + $detailed_error = defined('DEBUGGING') && DEBUGGING; + $can_generate_debug = defined('DEBUGGING') && DEBUGGING; try { $user = new User(); $detailed_error |= $user->isLoggedIn() && $user->hasPermission('admincp.errors'); $can_generate_debug |= $user->hasPermission('admincp.core.debugging'); - } catch (Error $ignored) { + } catch (Exception $ignored) { // Getting user info might fail, for example if the website isn't // installed yet. Assume the user does not have permission. } diff --git a/core/includes/updates/200-pr13.php b/core/includes/updates/200-pr13.php index 92dba53523..9afbec0c02 100644 --- a/core/includes/updates/200-pr13.php +++ b/core/includes/updates/200-pr13.php @@ -15,6 +15,18 @@ public function run(): void { Config::set('core/trustedProxies', null); } + $trusted_proxies = Config::get('core/trustedProxies'); + // If trusted proxies is an empty array + if ($trusted_proxies !== null && + is_countable($trusted_proxies) && + count($trusted_proxies) == 0) { + + // The core/trustedProxies option was mistakenly set during the installer for pr13. If we decide to + // allow not configuring it, at least it must be in an "unconfigured" state by default so StaffCP + // can display a warning until it is explicitly set to an empty or non-empty array by the user. + Config::set('core/trustedProxies', null); + } + $this->setVersion('2.0.0'); } } diff --git a/core/init.php b/core/init.php index a0092b4901..072e8ba6d5 100644 --- a/core/init.php +++ b/core/init.php @@ -22,11 +22,22 @@ die('$page variable is unset. Cannot continue.'); } -if (!file_exists(ROOT_PATH . '/core/config.php')) { - if (is_writable(ROOT_PATH . '/core')) { - fopen(ROOT_PATH . '/core/config.php', 'w'); - } else { - die('Your /core directory is not writable, please check your file permissions.'); +// All paths should be writable, but recursively checking everything would take too much time. +// Only check the most important paths. +$writable_check_paths = [ + ROOT_PATH, + ROOT_PATH . '/cache', + ROOT_PATH . '/cache/logs', + ROOT_PATH . '/cache/sitemaps', + ROOT_PATH . '/cache/templates_c', + ROOT_PATH . '/uploads', + ROOT_PATH . '/core/email.php' +]; + +foreach ($writable_check_paths as $path) { + if (is_dir($path) && !is_writable($path)) { + die('

Your website directory or a subdirectory is not writable. Please ensure all files and directories are owned by + the correct user.

Example command to change owner recursively: sudo chown -R www-data: ' . Output::getClean(ROOT_PATH) . '

'); } } @@ -38,15 +49,8 @@ } } -// Require config -require(ROOT_PATH . '/core/config.php'); - -if (isset($conf) && is_array($conf)) { - $GLOBALS['config'] = $conf; -} else { - if (!isset($GLOBALS['config'])) { - $page = 'install'; - } +if (!Config::exists()) { + $page = 'install'; } // If we're accessing the upgrade script don't initialise further diff --git a/core/installation/steps/ajax_initialise.php b/core/installation/steps/ajax_initialise.php index f9a301bf7b..87c91afc9f 100644 --- a/core/installation/steps/ajax_initialise.php +++ b/core/installation/steps/ajax_initialise.php @@ -19,7 +19,7 @@ } else { if ($_GET['initialise'] === 'site') { - DatabaseInitialiser::runPreUser($conf); + DatabaseInitialiser::runPreUser(); $json = [ 'success' => true, diff --git a/core/installation/steps/conversion_perform.php b/core/installation/steps/conversion_perform.php index e9191fbc51..5007af2632 100644 --- a/core/installation/steps/conversion_perform.php +++ b/core/installation/steps/conversion_perform.php @@ -36,37 +36,17 @@ ]); if (!$validation->passed()) { - $error = $language->get('installer', 'database_error'); - } else { - - $db_address = $_POST['db_address']; - $db_port = $_POST['db_port']; - $db_username = $_POST['db_username']; - $db_password = ((isset($_POST['db_password']) && !empty($_POST['db_password'])) ? str_replace('\'', '\\\'', $_POST['db_password']) : ''); - $db_name = $_POST['db_name']; - - $mysqli = new mysqli($db_address, $db_username, $db_password, $db_name, $db_port); - if ($mysqli->connect_errno) { - - $error = $mysqli->connect_errno . ' - ' . $mysqli->connect_error; - + if (!isset($_POST['converter']) || !in_array($_POST['converter'], $converters)) { + $error = $language->get('installer', 'unable_to_load_converter'); } else { - - $mysqli->close(); - - if (!isset($_POST['converter']) || !in_array($_POST['converter'], $converters)) { - - $error = $language->get('installer', 'unable_to_load_converter'); - - } else { - + try { $conn = DB::getCustomInstance( Input::get('db_address'), Input::get('db_name'), Input::get('db_username'), - $password, + Input::get('db_password'), Input::get('db_port') ); @@ -83,15 +63,12 @@ if (!isset($error)) { Redirect::to('?step=finish'); } - + } catch (PDOException $e) { + $error = $language->get('installer', 'database_connection_failed', ['message' => $e->getMessage()]); } - } - } - } - } ?> diff --git a/core/installation/steps/database_configuration.php b/core/installation/steps/database_configuration.php index 95fa98925a..8064be13f7 100644 --- a/core/installation/steps/database_configuration.php +++ b/core/installation/steps/database_configuration.php @@ -29,92 +29,61 @@ $error = $language->get('installer', 'database_error'); } else { - $db_address = $_POST['db_address']; $db_port = $_POST['db_port']; $db_username = $_POST['db_username']; $db_password = ((isset($_POST['db_password']) && !empty($_POST['db_password'])) ? str_replace('\'', '\\\'', $_POST['db_password']) : ''); $db_name = $_POST['db_name']; - - $charset = ($_POST['charset'] == 'latin1') ? 'latin1' : 'utf8mb4'; + $db_charset = ($_POST['charset'] == 'latin1') ? 'latin1' : 'utf8mb4'; try { - $mysqli = new mysqli($db_address, $db_username, $db_password, $db_name, $db_port); + // This throws a PDOException if the connection fails + DB::getCustomInstance($db_address, $db_name, $db_username, $db_password, $db_port, $force_charset=$db_charset); + + $conf = [ + 'mysql' => [ + 'host' => $db_address, + 'port' => $db_port, + 'username' => $db_username, + 'password' => $db_password, + 'db' => $db_name, + 'charset' => $charset, + 'initialise_charset' => true, + ], + 'remember' => [ + 'cookie_name' => 'nl2', + 'cookie_expiry' => 604800, + ], + 'session' => [ + 'session_name' => '2user', + 'admin_name' => '2admin', + 'token_name' => '2token', + ], + 'core' => [ + 'hostname' => $_SESSION['hostname'], + 'path' => $_SESSION['install_path'], + 'friendly' => $_SESSION['friendly_urls'] === 'true', + 'force_https' => false, + 'force_www' => false, + 'captcha' => false, + 'date_format' => 'd M Y, H:i', + 'trustedProxies' => null, + ], + ]; + + try { + Config::write($conf); + $_SESSION['charset'] = $charset; + Redirect::to('?step=database_initialization'); + } catch (RuntimeException $e) { + $error = $language->get('installer', 'config_write_failed', ['message' => $e->getMessage()]); + } + } catch (PDOException $e) { + $error = $language->get('installer', 'database_connection_failed', ['message' => $e->getMessage()]); } catch (Exception $e) { $error = $e->getMessage(); } - - if (!$error) { - if ($mysqli->connect_errno) { - - $error = $mysqli->connect_errno . ' - ' . $mysqli->connect_error; - - } else { - - $mysqli->close(); - - $conf = [ - 'mysql' => [ - 'host' => $db_address, - 'port' => $db_port, - 'username' => $db_username, - 'password' => $db_password, - 'db' => $db_name, - 'charset' => $charset, - 'initialise_charset' => true, - ], - 'remember' => [ - 'cookie_name' => 'nl2', - 'cookie_expiry' => 604800, - ], - 'session' => [ - 'session_name' => '2user', - 'admin_name' => '2admin', - 'token_name' => '2token', - ], - 'core' => [ - 'hostname' => $_SESSION['hostname'], - 'path' => $_SESSION['install_path'], - 'friendly' => $_SESSION['friendly_urls'] == 'true', - 'force_https' => false, - 'force_www' => false, - 'captcha' => false, - 'date_format' => 'd M Y, H:i', - 'trustedProxies' => null, - ], - ]; - - try { - - if (!is_writable(ROOT_PATH . '/core/config.php')) { - - $error = $language->get('installer', 'config_not_writable'); - - } else { - - $config_content = 'getMessage(); - - } - - } - - } - } - } ?> diff --git a/core/installation/steps/finish.php b/core/installation/steps/finish.php index 018b009fac..44f37e17f0 100644 --- a/core/installation/steps/finish.php +++ b/core/installation/steps/finish.php @@ -5,12 +5,7 @@ } try { - - if (!is_writable('core/config.php')) { - $error = $language->get('installer', 'config_not_writable'); - } else { - Config::set('core/installed', true); - } + Config::set('core/installed', true); unset($_SESSION['admin_setup'], $_SESSION['database_initialized'], $_SESSION['site_initialized']); diff --git a/core/installation/steps/requirements_validation.php b/core/installation/steps/requirements_validation.php index 1ff55976e2..68aa03972e 100644 --- a/core/installation/steps/requirements_validation.php +++ b/core/installation/steps/requirements_validation.php @@ -23,19 +23,14 @@ validate_requirement('PHP PDO', extension_loaded('PDO')); validate_requirement('PHP XML', extension_loaded('xml')); validate_requirement('PHP MBString', extension_loaded('mbstring')); - validate_requirement('PHP GD', extension_loaded('gd')); - validate_requirement('PHP cURL', function_exists('curl_version')); - validate_requirement('PHP Exif', function_exists('exif_imagetype')); - validate_requirement('PHP JSON', function_exists('json_decode')); ?>
/core', is_writable('core')); - validate_requirement('Core Config Writable /core/config.php', is_writable('core/config.php')); - validate_requirement('Core Email Writable /core/email.php', is_writable('core/email.php')); - validate_requirement('Cache Writable /cache', is_writable('cache')); - validate_requirement('Template Cache Writable /cache/templates_c', is_writable('cache/templates_c')); + validate_requirement('PHP GD', extension_loaded('gd')); + validate_requirement('PHP cURL', function_exists('curl_version')); + validate_requirement('PHP Exif', function_exists('exif_imagetype')); + validate_requirement('PHP JSON', function_exists('json_decode')); ?>
diff --git a/core/installation/steps/upgrade.php b/core/installation/steps/upgrade.php index 6ed6a81518..fe93afbca7 100644 --- a/core/installation/steps/upgrade.php +++ b/core/installation/steps/upgrade.php @@ -42,13 +42,11 @@ $db_password = ((isset($_POST['db_password']) && !empty($_POST['db_password'])) ? $_POST['db_password'] : ''); $db_name = $_POST['db_name']; - $mysqli = new mysqli($db_address, $db_username, $db_password, $db_name, $db_port); - if ($mysqli->connect_errno) { - - $error = $mysqli->connect_errno . ' - ' . $mysqli->connect_error; - - } else { + try { + // Check database details + DB::getCustomInstance($db_address, $db_name, $db_username, $db_password, $db_port); + // Database connection successful $_SESSION['db_address'] = $db_address; $_SESSION['db_port'] = $db_port; $_SESSION['db_username'] = $db_username; @@ -56,10 +54,10 @@ $_SESSION['db_name'] = $db_name; Redirect::to('?step=upgrade_perform'); + } catch (PDOException $e) { + $error = $language->get('installer', 'database_connection_failed', ['message' => $e->getMessage()]); } - } - } ?> diff --git a/custom/languages/en_UK.json b/custom/languages/en_UK.json index aa90dfb67c..31681def7b 100644 --- a/custom/languages/en_UK.json +++ b/custom/languages/en_UK.json @@ -835,7 +835,8 @@ "installer/back": "Back", "installer/cache_writable": "Cache Writable", "installer/character_set": "Character Set", - "installer/config_not_writable": "The config file is not writable.", + "installer/config_write_failed": "Failed to write to config file: {{message}}", + "installer/database_connection_failed": "Failed to connect to the database:
{{message}}", "installer/config_writable": "core\/config.php Writable", "installer/configuration": "Configuration", "installer/configuration_error": "Please input a valid site name between 1 and 32 characters long, and valid email addresses between 4 and 64 characters long.", diff --git a/index.php b/index.php index b7c02a5934..82c4e882ca 100644 --- a/index.php +++ b/index.php @@ -48,6 +48,14 @@ require_once __DIR__ . '/vendor/autoload.php'; require_once __DIR__ . '/core/includes/constants/autoload.php'; +if (!Config::exists()) { + if (is_file(ROOT_PATH . '/install.php')) { + Redirect::to('install.php'); + } else { + die('Config does not exist, but neither does the installer'); + } +} + $page = 'Home'; if (!ini_get('upload_tmp_dir')) { @@ -76,10 +84,6 @@ // Start initialising the page require(ROOT_PATH . '/core/init.php'); -if (!isset($GLOBALS['config']['core']) && is_file(ROOT_PATH . '/install.php')) { - Redirect::to('install.php'); -} - // Get page to load from URL if (!isset($_GET['route']) || $_GET['route'] == '/') { if (((!isset($_GET['route']) || ($_GET['route'] != '/')) && count($directories) > 1)) { diff --git a/install.php b/install.php index 3781b32c26..d5f2217443 100644 --- a/install.php +++ b/install.php @@ -11,6 +11,10 @@ require_once __DIR__ . '/vendor/autoload.php'; +if (getenv('NAMELESS_DEBUGGING') || isset($_SERVER['NAMELESS_DEBUGGING'])) { + define('DEBUGGING', 1); +} + // Definitions if (!defined('PATH')) { define('PATH', '/'); @@ -45,16 +49,17 @@ // Get installation path $install_path = substr(str_replace('\\', '/', substr(__DIR__, strlen($_SERVER['DOCUMENT_ROOT']))), 1); -if (!isset($GLOBALS['config']['core']['installed'])) { - if (isset($_GET['language'])) { - // Set language - if (is_file('custom/languages/' . $_GET['language'] . '.json')) { - $_SESSION['installer_language'] = $_GET['language']; - die('OK'); - } - die($_GET['language'] . ' is not a valid language'); - } - require(ROOT_PATH . '/core/installation/installer.php'); -} else { +if (Config::exists() && Config::get('core/installed') === true) { require(ROOT_PATH . '/core/installation/already_installed.php'); + return; +} + +if (isset($_GET['language'])) { + // Set language + if (is_file('custom/languages/' . $_GET['language'] . '.json')) { + $_SESSION['installer_language'] = $_GET['language']; + die('OK'); + } + die($_GET['language'] . ' is not a valid language'); } +require(ROOT_PATH . '/core/installation/installer.php'); diff --git a/modules/Core/pages/panel/general_settings.php b/modules/Core/pages/panel/general_settings.php index 24953b097b..98d02a1235 100644 --- a/modules/Core/pages/panel/general_settings.php +++ b/modules/Core/pages/panel/general_settings.php @@ -148,17 +148,6 @@ // Update config if (is_writable(ROOT_PATH . '/' . implode(DIRECTORY_SEPARATOR, ['core', 'config.php']))) { - // Require config - if (isset($path) && file_exists($path . 'core/config.php')) { - $loadedConfig = json_decode(file_get_contents($path . 'core/config.php'), true); - } else { - $loadedConfig = json_decode(file_get_contents(ROOT_PATH . '/core/config.php'), true); - } - - if (is_array($loadedConfig)) { - $GLOBALS['config'] = $loadedConfig; - } - Config::setMultiple([ 'core/friendly' => $friendly, 'core/force_https' => $https, diff --git a/modules/Core/pages/panel/registration.php b/modules/Core/pages/panel/registration.php index 15db580514..3b00c448af 100644 --- a/modules/Core/pages/panel/registration.php +++ b/modules/Core/pages/panel/registration.php @@ -87,17 +87,6 @@ // Config value if (Input::get('enable_recaptcha') == 1 || Input::get('enable_recaptcha_login') == 1) { if (is_writable(ROOT_PATH . '/' . implode(DIRECTORY_SEPARATOR, ['core', 'config.php']))) { - // Require config - if (isset($path) && file_exists($path . 'core/config.php')) { - $loadedConfig = json_decode(file_get_contents($path . 'core/config.php'), true); - } else { - $loadedConfig = json_decode(file_get_contents(ROOT_PATH . '/core/config.php'), true); - } - - if (is_array($loadedConfig)) { - $GLOBALS['config'] = $loadedConfig; - } - Config::set('core/captcha', true); } else { $errors = [$language->get('admin', 'config_not_writable')]; diff --git a/modules/Core/queries/debug_link.php b/modules/Core/queries/debug_link.php index 8c654e36db..d49492b27a 100755 --- a/modules/Core/queries/debug_link.php +++ b/modules/Core/queries/debug_link.php @@ -207,8 +207,8 @@ 'groups' => $groups, 'config' => [ 'core' => array_filter( - $GLOBALS['config']['core'], - static fn(string $key) => $key != 'hostname' && $key != 'trustedProxies', + Config::get('core'), + static fn(string $key) => $key !== 'hostname' && $key !== 'trustedProxies', ARRAY_FILTER_USE_KEY ), ], diff --git a/modules/Core/widgets/ServerStatusWidget.php b/modules/Core/widgets/ServerStatusWidget.php index a857cae20b..013b846e4c 100644 --- a/modules/Core/widgets/ServerStatusWidget.php +++ b/modules/Core/widgets/ServerStatusWidget.php @@ -46,18 +46,20 @@ public function initialise(): void { $server = $server[0]; if ($server != null) { - $server_array = HttpClient::get(rtrim(Util::getSelfURL(), '/') . URL::build('/queries/server/', 'id=' . $server->id))->json(true); - - foreach ($server_array as $key => $value) { - // we have to NOT escape the player list or the formatted player list. luckily these are the only arrays - if (is_array($value)) { - $server_array[$key] = $value; - } else { - $server_array[$key] = Output::getClean($value); + $server_array_request = HttpClient::get(rtrim(Util::getSelfURL(), '/') . URL::build('/queries/server/', 'id=' . $server->id)); + if (!$server_array_request->hasError()) { + $server_array = $server_array_request->json(true); + foreach ($server_array as $key => $value) { + // we have to NOT escape the player list or the formatted player list. luckily these are the only arrays + if (is_array($value)) { + $server_array[$key] = $value; + } else { + $server_array[$key] = Output::getClean($value); + } } + $server_array['name'] = $server->name; + $server_array['join_at'] = $server->ip; } - $server_array['name'] = $server->name; - $server_array['join_at'] = $server->ip; $this->_cache->store('server_status', $server_array, 120); } diff --git a/scripts/cli_install.php b/scripts/cli_install.php index f8d96731d0..7aaf8c6d05 100644 --- a/scripts/cli_install.php +++ b/scripts/cli_install.php @@ -87,7 +87,10 @@ function getEnvVar(string $name, string $fallback = null, array $valid_values = } } -const ROOT_PATH = __DIR__ . '..'; +const ROOT_PATH = __DIR__ . '/..'; + +print('♻️ Registering autoloader...' . PHP_EOL); +require './vendor/autoload.php'; print('✍️ Creating new config.php file...' . PHP_EOL); $conf = [ @@ -111,7 +114,7 @@ function getEnvVar(string $name, string $fallback = null, array $valid_values = 'core' => [ 'hostname' => getEnvVar('NAMELESS_HOSTNAME', 'localhost'), 'path' => getEnvVar('NAMELESS_PATH', ''), - 'friendly' => getEnvVar('NAMELESS_FRIENDLY_URLS', 'false') === 'true' ? true : false, + 'friendly' => getEnvVar('NAMELESS_FRIENDLY_URLS', 'false') === 'true', 'force_https' => false, 'force_www' => false, 'captcha' => false, @@ -120,14 +123,7 @@ function getEnvVar(string $name, string $fallback = null, array $valid_values = ], ]; -file_put_contents( - './core/config.php', - ' Date: Sun, 12 Jun 2022 20:22:53 -0600 Subject: [PATCH 092/337] Fix legacy install check --- install.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.php b/install.php index d5f2217443..a774656119 100644 --- a/install.php +++ b/install.php @@ -49,7 +49,7 @@ // Get installation path $install_path = substr(str_replace('\\', '/', substr(__DIR__, strlen($_SERVER['DOCUMENT_ROOT']))), 1); -if (Config::exists() && Config::get('core/installed') === true) { +if (isset($CONFIG['installed']) || (Config::exists() && Config::get('core/installed') === true)) { require(ROOT_PATH . '/core/installation/already_installed.php'); return; } From 3df85ce05ae4317642993366636374c54175c867 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Sun, 12 Jun 2022 20:35:45 -0600 Subject: [PATCH 093/337] Swap Config class to prefer paths seperated by `.` --- core/classes/Core/Config.php | 31 ++++++++++++++++--- core/classes/Core/Token.php | 6 ++-- core/classes/Core/URL.php | 2 +- core/classes/Core/User.php | 8 ++--- core/classes/Core/Util.php | 14 +++++---- core/classes/Core/Validate.php | 2 +- core/classes/Database/DB.php | 14 ++++----- core/classes/Database/DatabaseInitialiser.php | 2 +- core/classes/Misc/CaptchaBase.php | 2 +- core/includes/updates/200-pr13.php | 9 ++---- core/init.php | 18 +++++------ install.php | 2 +- modules/Core/pages/panel/general_settings.php | 2 +- 13 files changed, 66 insertions(+), 46 deletions(-) diff --git a/core/classes/Core/Config.php b/core/classes/Core/Config.php index a4fc9a8b52..6745ab7787 100644 --- a/core/classes/Core/Config.php +++ b/core/classes/Core/Config.php @@ -62,7 +62,7 @@ public static function write(array $config): void { /** * Get a config value from `core/config.php` file. * - * @param string $path `/` seperated path of key to get from config file. + * @param string $path `.` seperated path of key to get from config file. * @return false|mixed Returns false if key doesn't exist, otherwise returns the value. * * @throws RuntimeException If the config file is not found. @@ -70,7 +70,7 @@ public static function write(array $config): void { public static function get(string $path) { $config = self::all(); - $path = explode('/', $path); + $path = self::parsePath($path); foreach ($path as $bit) { if (isset($config[$bit])) { @@ -90,13 +90,13 @@ public static function get(string $path) { /** * Write a value to `core/config.php` file. * - * @param string $key `/` seperated path of key to set. + * @param string $key `.` seperated path of key to set. * @param mixed $value Value to set under $key. */ public static function set(string $key, $value): void { $config = self::all(); - $path = explode('/', $key); + $path = self::parsePath($key); if (!is_array($path)) { $config[$key] = $value; @@ -120,7 +120,7 @@ public static function setMultiple(array $values): void { $config = self::all(); foreach ($values as $key => $value) { - $path = explode('/', $key); + $path = self::parsePath($key); if (!is_array($path)) { $config[$key] = $value; @@ -135,4 +135,25 @@ public static function setMultiple(array $values): void { static::write($config); } + + /** + * Parse a string path to an array of config paths. + * Will log a warning if a legacy path (using `/` is used). + * + * @param string $path Path to parse. + * @return string|array Path split into sections or plain string if no section seperator was found. + */ + private static function parsePath(string $path) { + if (str_contains($path, '.')) { + return explode('.', $path); + } + + // TODO: Remove for 2.1.0 + if (str_contains($path, '/')) { + ErrorHandler::logWarning("Legacy config path: {$path}. Please use periods to seperate paths."); + return explode('/', $path); + } + + return $path; + } } diff --git a/core/classes/Core/Token.php b/core/classes/Core/Token.php index 72ab8a3c2d..44e9350334 100644 --- a/core/classes/Core/Token.php +++ b/core/classes/Core/Token.php @@ -15,7 +15,7 @@ class Token { * @return string current form token. */ public static function get(): string { - $tokenName = Config::get('session/token_name'); + $tokenName = Config::get('session.token_name'); // Return if it already exists if (Session::exists($tokenName)) { @@ -33,7 +33,7 @@ public static function get(): string { */ public static function generate(): void { // Generate random token using md5 - Session::put(Config::get('session/token_name'), md5(uniqid('', true))); + Session::put(Config::get('session.token_name'), md5(uniqid('', true))); } /** @@ -49,7 +49,7 @@ public static function check(string $token = null): bool { $token = Input::get('token'); } - $tokenName = Config::get('session/token_name'); + $tokenName = Config::get('session.token_name'); // Check the token matches return Session::exists($tokenName) && $token === Session::get($tokenName); diff --git a/core/classes/Core/URL.php b/core/classes/Core/URL.php index 6a5246e196..ffbc93ecf4 100644 --- a/core/classes/Core/URL.php +++ b/core/classes/Core/URL.php @@ -36,7 +36,7 @@ public static function build(string $url, string $params = '', ?string $force = throw new InvalidArgumentException('Invalid force string: ' . $force); } - if ((defined('FRIENDLY_URLS') && FRIENDLY_URLS == true) || (!defined('FRIENDLY_URLS') && Config::get('core/friendly') == true)) { + if ((defined('FRIENDLY_URLS') && FRIENDLY_URLS == true) || (!defined('FRIENDLY_URLS') && Config::get('core.friendly') == true)) { // Friendly URLs are enabled return self::buildFriendly($url, $params); } diff --git a/core/classes/Core/User.php b/core/classes/Core/User.php index eeda404d02..7af63b4a2f 100644 --- a/core/classes/Core/User.php +++ b/core/classes/Core/User.php @@ -67,9 +67,9 @@ class User { public function __construct(string $user = null, string $field = 'id') { $this->_db = DB::getInstance(); - $this->_sessionName = Config::get('session/session_name'); - $this->_cookieName = Config::get('remember/cookie_name'); - $this->_admSessionName = Config::get('session/admin_name'); + $this->_sessionName = Config::get('session.session_name'); + $this->_cookieName = Config::get('remember.cookie_name'); + $this->_admSessionName = Config::get('session.admin_name'); if ($user === null) { if (Session::exists($this->_sessionName)) { @@ -327,7 +327,7 @@ private function _commonLogin(?string $username, ?string $password, bool $rememb $hash = $hashCheck->first()->hash; } - $expiry = $is_admin ? 3600 : Config::get('remember/cookie_expiry'); + $expiry = $is_admin ? 3600 : Config::get('remember.cookie_expiry'); $cookieName = $is_admin ? ($this->_cookieName . '_adm') : $this->_cookieName; Cookie::put($cookieName, $hash, $expiry, Util::getProtocol() === 'https', true); } diff --git a/core/classes/Core/Util.php b/core/classes/Core/Util.php index 4ca0a6dd24..eaa69e2b45 100644 --- a/core/classes/Core/Util.php +++ b/core/classes/Core/Util.php @@ -130,11 +130,13 @@ public static function isExternalURL(string $url): bool { return !(str_replace('www.', '', rtrim(self::getSelfURL(false), '/')) == str_replace('www.', '', $parsed['host'])); } - public static function isTrustedProxiesConfigured() { - $config_proxies = Config::get('core/trustedProxies'); + public static function isTrustedProxiesConfigured(): bool { + $config_proxies = Config::get('core.trustedProxies'); $env_proxies = getenv('NAMELESS_TRUSTED_PROXIES'); - return $config_proxies !== false && $config_proxies !== null && is_array($config_proxies) - || $env_proxies !== false; + return $config_proxies !== false + && $config_proxies !== null + && is_array($config_proxies) + || $env_proxies !== false; } /** @@ -144,7 +146,7 @@ public static function getTrustedProxies(): array { $trusted_proxies = []; // Add trusted proxies from config file - $config_proxies = Config::get('core/trustedProxies'); + $config_proxies = Config::get('core.trustedProxies'); if ($config_proxies !== false && $config_proxies !== null) { if (!is_array($config_proxies)) { die('Trusted proxies should be an array'); @@ -340,7 +342,7 @@ public static function getPort(): ?int { * @return string Compiled URL. */ public static function getSelfURL(bool $show_protocol = true): string { - $hostname = Config::get('core/hostname'); + $hostname = Config::get('core.hostname'); if (!$hostname) { $hostname = $_SERVER['SERVER_NAME']; diff --git a/core/classes/Core/Validate.php b/core/classes/Core/Validate.php index 217590fad5..c3cfe34cf7 100644 --- a/core/classes/Core/Validate.php +++ b/core/classes/Core/Validate.php @@ -95,7 +95,7 @@ class Validate { private function __construct() { // Connect to database for rules which need DB access try { - $host = Config::get('mysql/host'); + $host = Config::get('mysql.host'); } catch (Exception $e) { $host = null; } diff --git a/core/classes/Database/DB.php b/core/classes/Database/DB.php index f98733bb68..2916745800 100644 --- a/core/classes/Database/DB.php +++ b/core/classes/Database/DB.php @@ -482,18 +482,18 @@ public static function getInstance(): DB { return self::$_instance; } - if (Config::get('mysql/initialise_charset')) { - $force_charset = Config::get('mysql/charset') ?: 'utf8mb4'; + if (Config::get('mysql.initialise_charset')) { + $force_charset = Config::get('mysql.charset') ?: 'utf8mb4'; } else { $force_charset = null; } self::$_instance = self::getCustomInstance( - Config::get('mysql/host'), - Config::get('mysql/db'), - Config::get('mysql/username'), - Config::get('mysql/password'), - Config::get('mysql/port'), + Config::get('mysql.host'), + Config::get('mysql.db'), + Config::get('mysql.username'), + Config::get('mysql.password'), + Config::get('mysql.port'), $force_charset ); diff --git a/core/classes/Database/DatabaseInitialiser.php b/core/classes/Database/DatabaseInitialiser.php index 2e68c64069..134a6cd697 100644 --- a/core/classes/Database/DatabaseInitialiser.php +++ b/core/classes/Database/DatabaseInitialiser.php @@ -245,7 +245,7 @@ private function initialiseTemplates(): void { ]); $this->_cache->store('panel_default', 'Default'); - $config_path = Config::get('core/path'); + $config_path = Config::get('core.path'); if (!empty($config_path)) { $config_path = '/' . trim($config_path, '/'); } diff --git a/core/classes/Misc/CaptchaBase.php b/core/classes/Misc/CaptchaBase.php index 33cb3a89fa..517bfd7c4f 100644 --- a/core/classes/Misc/CaptchaBase.php +++ b/core/classes/Misc/CaptchaBase.php @@ -77,7 +77,7 @@ public static function getAllProviders(): iterable { * @return bool Whether captcha is enabled or not */ public static function isCaptchaEnabled(string $key = 'recaptcha'): bool { - if (!Config::get('core/captcha')) { + if (!Config::get('core.captcha')) { return false; } diff --git a/core/includes/updates/200-pr13.php b/core/includes/updates/200-pr13.php index 9afbec0c02..4653872a1f 100644 --- a/core/includes/updates/200-pr13.php +++ b/core/includes/updates/200-pr13.php @@ -3,7 +3,7 @@ class Nameless200 extends UpgradeScript { public function run(): void { - $trusted_proxies = Config::get('core/trustedProxies'); + $trusted_proxies = Config::get('core.trustedProxies'); // If trusted proxies is an empty array if ($trusted_proxies !== null && is_countable($trusted_proxies) && @@ -15,12 +15,9 @@ public function run(): void { Config::set('core/trustedProxies', null); } - $trusted_proxies = Config::get('core/trustedProxies'); + $trusted_proxies = Config::get('core.trustedProxies'); // If trusted proxies is an empty array - if ($trusted_proxies !== null && - is_countable($trusted_proxies) && - count($trusted_proxies) == 0) { - + if (is_countable($trusted_proxies) && count($trusted_proxies) === 0) { // The core/trustedProxies option was mistakenly set during the installer for pr13. If we decide to // allow not configuring it, at least it must be in an "unconfigured" state by default so StaffCP // can display a warning until it is explicitly set to an empty or non-empty array by the user. diff --git a/core/init.php b/core/init.php index 072e8ba6d5..a8cca532d2 100644 --- a/core/init.php +++ b/core/init.php @@ -66,16 +66,16 @@ */ // Friendly URLs? - define('FRIENDLY_URLS', Config::get('core/friendly') == 'true'); + define('FRIENDLY_URLS', Config::get('core.friendly') == 'true'); // Set up cache $cache = new Cache(['name' => 'nameless', 'extension' => '.cache', 'path' => ROOT_PATH . '/cache/']); // Force https/www? - if (Config::get('core/force_https')) { + if (Config::get('core.force_https')) { define('FORCE_SSL', true); } - if (Config::get('core/force_www')) { + if (Config::get('core.force_www')) { define('FORCE_WWW', true); } @@ -121,13 +121,13 @@ define('NAMELESS_VERSION', Util::getSetting('nameless_version')); // Set the date format - define('DATE_FORMAT', Config::get('core/date_format') ?: 'd M Y, H:i'); + define('DATE_FORMAT', Config::get('core.date_format') ?: 'd M Y, H:i'); // User initialisation $user = new User(); // Do they need logging in (checked remember me)? - if (Cookie::exists(Config::get('remember/cookie_name')) && !Session::exists(Config::get('session/session_name'))) { - $hash = Cookie::get(Config::get('remember/cookie_name')); + if (Cookie::exists(Config::get('remember.cookie_name')) && !Session::exists(Config::get('session.session_name'))) { + $hash = Cookie::get(Config::get('remember.cookie_name')); $hashCheck = DB::getInstance()->get('users_session', ['hash', $hash]); if ($hashCheck->count()) { @@ -144,16 +144,16 @@ $directories = array_values($directories); - $config_path = Config::get('core/path'); + $config_path = Config::get('core.path'); if (!empty($config_path)) { - $config_path = explode('/', Config::get('core/path')); + $config_path = explode('/', Config::get('core.path')); for ($i = 0, $iMax = count($config_path); $i < $iMax; $i++) { unset($directories[$i]); } - define('CONFIG_PATH', '/' . Config::get('core/path')); + define('CONFIG_PATH', '/' . Config::get('core.path')); $directories = array_values($directories); } diff --git a/install.php b/install.php index a774656119..79c98d6ccd 100644 --- a/install.php +++ b/install.php @@ -49,7 +49,7 @@ // Get installation path $install_path = substr(str_replace('\\', '/', substr(__DIR__, strlen($_SERVER['DOCUMENT_ROOT']))), 1); -if (isset($CONFIG['installed']) || (Config::exists() && Config::get('core/installed') === true)) { +if (isset($CONFIG['installed']) || (Config::exists() && Config::get('core.installed') === true)) { require(ROOT_PATH . '/core/installation/already_installed.php'); return; } diff --git a/modules/Core/pages/panel/general_settings.php b/modules/Core/pages/panel/general_settings.php index 98d02a1235..5e1adb67c7 100644 --- a/modules/Core/pages/panel/general_settings.php +++ b/modules/Core/pages/panel/general_settings.php @@ -265,7 +265,7 @@ 'HOMEPAGE_CUSTOM' => $language->get('admin', 'custom_content'), 'HOMEPAGE_VALUE' => Util::getSetting('home_type'), 'USE_FRIENDLY_URLS' => $language->get('admin', 'use_friendly_urls'), - 'USE_FRIENDLY_URLS_VALUE' => Config::get('core/friendly'), + 'USE_FRIENDLY_URLS_VALUE' => Config::get('core.friendly'), 'USE_FRIENDLY_URLS_HELP' => $language->get('admin', 'use_friendly_urls_help', [ 'docLinkStart' => "", 'docLinkEnd' => '' From a839f78b05a061a3b56486bf86fd55c52b244a57 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Sun, 12 Jun 2022 20:39:39 -0600 Subject: [PATCH 094/337] Misc --- core/classes/Core/Util.php | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/core/classes/Core/Util.php b/core/classes/Core/Util.php index eaa69e2b45..77ddb1ff09 100644 --- a/core/classes/Core/Util.php +++ b/core/classes/Core/Util.php @@ -130,12 +130,16 @@ public static function isExternalURL(string $url): bool { return !(str_replace('www.', '', rtrim(self::getSelfURL(false), '/')) == str_replace('www.', '', $parsed['host'])); } + /** + * Determine whether the trusted proxies config option is set to a valid value or not. + * + * @return bool Whether the trusted proxies option is configured or not + */ public static function isTrustedProxiesConfigured(): bool { $config_proxies = Config::get('core.trustedProxies'); $env_proxies = getenv('NAMELESS_TRUSTED_PROXIES'); - return $config_proxies !== false - && $config_proxies !== null - && is_array($config_proxies) + return ($config_proxies !== false + && is_array($config_proxies)) || $env_proxies !== false; } @@ -387,11 +391,6 @@ public static function stringToURL(string $string = null): string { return ''; } - /* - * The truncate function is taken from CakePHP, license MIT - * https://github.com/cakephp/cakephp/blob/master/LICENSE - */ - /** * Truncates text. * @@ -403,13 +402,13 @@ public static function stringToURL(string $string = null): string { * - `ending` Will be used as Ending and appended to the trimmed string * - `exact` If false, $text will not be cut mid-word * - `html` If true, HTML tags would be handled correctly + * @link http://book.cakephp.org/view/1469/Text#truncate-1625 + * @link https://github.com/cakephp/cakephp/blob/master/LICENSE * * @param string $text String to truncate. * @param int $length Length of returned string, including ellipsis. * @param array $options An array of html attributes and options. * @return string Trimmed string. - * @access public - * @link http://book.cakephp.org/view/1469/Text#truncate-1625 */ public static function truncate(string $text, int $length = 750, array $options = []): string { $default = [ @@ -593,18 +592,14 @@ public static function getSetting(string $setting, ?string $fallback = null, ?st } } - if (isset(self::$_cached_settings[$setting])) { - return self::$_cached_settings[$setting]; - } else { - return null; - } + return self::$_cached_settings[$setting] ?? null; } /** * Modify a setting in the database table `nl2_settings`. * * @param string $setting Setting name. - * @param string $new_value New setting value, or null to delete + * @param string|null $new_value New setting value, or null to delete * @param ?string $module Alphanumeric (no spaces!) module name to use as a settings table prefix. For example, * specify 'store' to use the 'nl2_store_settings' table. Null to use the standard * nl2_settings table. @@ -697,7 +692,7 @@ public static function bold(string $text): string { * @return string Read string */ public static function readFileEnd(string $file_path, int $max_bytes = 100_000): string { - $fp = fopen($file_path, 'r'); + $fp = fopen($file_path, 'rb'); $size = filesize($file_path); $start = max([$size - $max_bytes, 0]); fseek($fp, $start); From 6266a806962416b9f93b446d6f89a5bacf89ac38 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Sun, 12 Jun 2022 20:54:30 -0600 Subject: [PATCH 095/337] Create `Redirect::back()` method --- core/classes/Core/Redirect.php | 17 +++++++++++++++++ modules/Core/pages/login.php | 2 +- modules/Core/pages/oauth.php | 2 +- modules/Core/pages/panel/auth.php | 2 +- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/core/classes/Core/Redirect.php b/core/classes/Core/Redirect.php index 466c617e2b..6614bbaf7e 100644 --- a/core/classes/Core/Redirect.php +++ b/core/classes/Core/Redirect.php @@ -25,4 +25,21 @@ public static function to(string $location): void { } die(); } + + /** + * Attempt to redirect the user to the previous page. + * + * @return never + */ + public static function back(): void { + if (isset($_SESSION['last_page'])) { + self::to($_SESSION['last_page']); + } + + if (isset($_SESSION['HTTP_REFERER'])) { + self::to($_SESSION['HTTP_REFERER']); + } + + self::to(URL::build('/')); + } } diff --git a/modules/Core/pages/login.php b/modules/Core/pages/login.php index ea6588e982..784d4fd9c7 100644 --- a/modules/Core/pages/login.php +++ b/modules/Core/pages/login.php @@ -234,7 +234,7 @@ // Redirect to a certain page? if (isset($_SESSION['last_page']) && substr($_SESSION['last_page'], -1) != '=') { - Redirect::to($_SESSION['last_page']); + Redirect::back(); } else { Session::flash('home', $language->get('user', 'successful_login')); Redirect::to(URL::build('/')); diff --git a/modules/Core/pages/oauth.php b/modules/Core/pages/oauth.php index 974b212457..bc4d66b8b8 100644 --- a/modules/Core/pages/oauth.php +++ b/modules/Core/pages/oauth.php @@ -51,7 +51,7 @@ Session::delete('oauth_method'); if (isset($_SESSION['last_page']) && substr($_SESSION['last_page'], -1) != '=') { - Redirect::to($_SESSION['last_page']); + Redirect::back(); } Redirect::to(URL::build('/')); diff --git a/modules/Core/pages/panel/auth.php b/modules/Core/pages/panel/auth.php index b8dcc52062..0018bda4f4 100644 --- a/modules/Core/pages/panel/auth.php +++ b/modules/Core/pages/panel/auth.php @@ -92,7 +92,7 @@ // Redirect to a certain page? if (isset($_SESSION['last_page']) && substr($_SESSION['last_page'], -1) != '=') { - Redirect::to($_SESSION['last_page']); + Redirect::back(); } else { Redirect::to(URL::build('/panel')); } From 476b8df406da7eb32d46a8dfd21e8ae6903c703b Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Sun, 12 Jun 2022 21:10:14 -0600 Subject: [PATCH 096/337] Cleanup upgrade script --- core/classes/Misc/UpgradeScript.php | 2 +- core/includes/updates/200-pr13.php | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/core/classes/Misc/UpgradeScript.php b/core/classes/Misc/UpgradeScript.php index 75bec1fa7c..28d1459af5 100644 --- a/core/classes/Misc/UpgradeScript.php +++ b/core/classes/Misc/UpgradeScript.php @@ -144,7 +144,7 @@ protected function deleteFiles($paths): void { /** * Execute any pending database migrations. */ - protected function migrateDb(): void { + protected function runMigrations(): void { PhinxAdapter::migrate(); } diff --git a/core/includes/updates/200-pr13.php b/core/includes/updates/200-pr13.php index 4653872a1f..ddd0327b57 100644 --- a/core/includes/updates/200-pr13.php +++ b/core/includes/updates/200-pr13.php @@ -1,14 +1,11 @@ runMigrations(); + $this->setVersion('2.0.0'); } -} +}; From 1419cdeddfb5d24750418d587d7b83d88849def1 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Sun, 12 Jun 2022 21:21:07 -0600 Subject: [PATCH 097/337] Use config class in Phinx config, fix `Config::get()` --- core/classes/Core/Config.php | 8 ++++++-- core/migrations/phinx.php | 13 ++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/core/classes/Core/Config.php b/core/classes/Core/Config.php index 6745ab7787..138a1beed0 100644 --- a/core/classes/Core/Config.php +++ b/core/classes/Core/Config.php @@ -70,9 +70,13 @@ public static function write(array $config): void { public static function get(string $path) { $config = self::all(); - $path = self::parsePath($path); + $parsed_path = self::parsePath($path); - foreach ($path as $bit) { + if (!is_array($parsed_path)) { + return $config[$parsed_path] ?? false; + } + + foreach ($parsed_path as $bit) { if (isset($config[$bit])) { $config = $config[$bit]; } else { diff --git a/core/migrations/phinx.php b/core/migrations/phinx.php index 4cbb09acf6..24c33c53a0 100644 --- a/core/migrations/phinx.php +++ b/core/migrations/phinx.php @@ -1,7 +1,6 @@ [ @@ -10,11 +9,11 @@ 'environments' => [ 'nameless' => [ 'adapter' => 'mysql', - 'host' => $conf['host'], - 'name' => $conf['db'], - 'user' => $conf['username'], - 'pass' => $conf['password'], - 'port' => $conf['port'], + 'host' => $config['host'], + 'name' => $config['db'], + 'user' => $config['username'], + 'pass' => $config['password'], + 'port' => $config['port'], 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'default_migration_table' => 'nl2_phinxlog', From 2796bc5d6482578c377a5b11f73d829dfcdc4432 Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 13 Jun 2022 11:47:49 +0200 Subject: [PATCH 098/337] Check for https port 80 misconfiguration --- custom/languages/en_UK.json | 1 + modules/Core/pages/panel/index.php | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/custom/languages/en_UK.json b/custom/languages/en_UK.json index 31681def7b..51114af390 100644 --- a/custom/languages/en_UK.json +++ b/custom/languages/en_UK.json @@ -681,6 +681,7 @@ "admin/api_disabled": "API is disabled", "admin/trusted_proxies_configured": "Trusted proxies", "admin/trusted_proxies_not_configured": "{{linkStart}}Trusted proxies{{linkEnd}} are not configured, IP bans may not work properly.", + "admin/https_port_80": "You appear as if you are using HTTPS on port 80, which is almost definitely not true. If you use CloudFlare, make sure to set TLS encryption mode to Full (strict). If you run your own proxy, please configure it to send the X-Forwarded-Port header.", "api/account_validated": "Account validated successfully", "api/finish_registration_email": "Please check your emails to complete registration.", "api/finish_registration_link": "Please click on the following link to complete registration:", diff --git a/modules/Core/pages/panel/index.php b/modules/Core/pages/panel/index.php index f5d499cea0..05feb1752b 100644 --- a/modules/Core/pages/panel/index.php +++ b/modules/Core/pages/panel/index.php @@ -207,6 +207,10 @@ ]); } + if (Util::getPort() === 80 && Util::getProtocol() === 'https') { + $compat_errors[] = $language->get('admin', 'https_port_80'); + } + $smarty->assign([ 'SERVER_COMPATIBILITY' => $language->get('admin', 'server_compatibility'), 'COMPAT_SUCCESS' => $compat_success, From 313cfd1a1eda4e134f6c169cbd2a5ea403f8bf0b Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 13 Jun 2022 11:50:27 +0200 Subject: [PATCH 099/337] Remove permissions checks The page won't load if permissions are wrong because of a die() earlier, so there's no point in checking permissions here. --- modules/Core/pages/panel/index.php | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/modules/Core/pages/panel/index.php b/modules/Core/pages/panel/index.php index 05feb1752b..305f1a8aab 100644 --- a/modules/Core/pages/panel/index.php +++ b/modules/Core/pages/panel/index.php @@ -181,23 +181,6 @@ $compat_errors[] = $pdo_driver . ' Server ' . $pdo_server_version; } - // Permissions - if (!is_writable(ROOT_PATH . '/core/config.php')) { - $compat_errors[] = $language->get('installer', 'config_writable'); - } else { - $compat_success[] = $language->get('installer', 'config_writable'); - } - if (!is_writable(ROOT_PATH . '/cache')) { - $compat_errors[] = $language->get('installer', 'cache_writable'); - } else { - $compat_success[] = $language->get('installer', 'cache_writable'); - } - if (!is_writable(ROOT_PATH . '/cache/templates_c')) { - $compat_errors[] = $language->get('installer', 'template_cache_writable'); - } else { - $compat_success[] = $language->get('installer', 'template_cache_writable'); - } - if (Util::isTrustedProxiesConfigured()) { $compat_success[] = $language->get('admin', 'trusted_proxies_configured'); } else { From 5073aeb42ac5ef18f3b70368a10998f2e009a290 Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 13 Jun 2022 11:57:02 +0200 Subject: [PATCH 100/337] Warnings for versions that still work but are quite old --- custom/panel_templates/Default/index.tpl | 7 +++++++ modules/Core/pages/panel/index.php | 13 ++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/custom/panel_templates/Default/index.tpl b/custom/panel_templates/Default/index.tpl index 4cbd45e66b..86e1996e7b 100644 --- a/custom/panel_templates/Default/index.tpl +++ b/custom/panel_templates/Default/index.tpl @@ -118,6 +118,13 @@ {$item}
{/foreach} + {if count($COMPAT_WARNINGS)} +
+ {foreach from=$COMPAT_WARNINGS item=item} + {$item} +
+ {/foreach} + {/if} {if count($COMPAT_ERRORS)}
{foreach from=$COMPAT_ERRORS item=item} diff --git a/modules/Core/pages/panel/index.php b/modules/Core/pages/panel/index.php index 305f1a8aab..50cc6c74ad 100644 --- a/modules/Core/pages/panel/index.php +++ b/modules/Core/pages/panel/index.php @@ -113,10 +113,13 @@ // Compatibility if ($user->hasPermission('admincp.core.debugging')) { $compat_success = []; + $compat_warnings = []; $compat_errors = []; if (PHP_VERSION_ID < 70400) { $compat_errors[] = 'PHP ' . PHP_VERSION; + } else if (PHP_VERSION_ID < 80000) { + $compat_warnings[] = 'PHP ' . PHP_VERSION; } else { $compat_success[] = 'PHP ' . PHP_VERSION; } @@ -174,9 +177,12 @@ } } - if (($pdo_driver === 'MySQL' && version_compare($pdo_server_version, '5.7', '>=')) || - ($pdo_driver === 'MariaDB' && version_compare($pdo_server_version, '10.3', '>='))) { + if (($pdo_driver === 'MySQL' && version_compare($pdo_server_version, '8.0', '>=')) || + ($pdo_driver === 'MariaDB' && version_compare($pdo_server_version, '10.5', '>='))) { $compat_success[] = $pdo_driver . ' Server ' . $pdo_server_version; + } else if (($pdo_driver === 'MySQL' && version_compare($pdo_server_version, '5.7', '>=')) || + ($pdo_driver === 'MariaDB' && version_compare($pdo_server_version, '10.3', '>='))) { + $compat_warnings[] = $pdo_driver . ' Server ' . $pdo_server_version; } else { $compat_errors[] = $pdo_driver . ' Server ' . $pdo_server_version; } @@ -197,7 +203,8 @@ $smarty->assign([ 'SERVER_COMPATIBILITY' => $language->get('admin', 'server_compatibility'), 'COMPAT_SUCCESS' => $compat_success, - 'COMPAT_ERRORS' => $compat_errors + 'COMPAT_WARNINGS' => $compat_warnings, + 'COMPAT_ERRORS' => $compat_errors, ]); } From 06dd7935d206123b3cd84bd102be4697e48e4380 Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 13 Jun 2022 15:12:36 +0200 Subject: [PATCH 101/337] Fix {{minPassword}}, also replace other hardcoded numbers --- .../steps/admin_account_setup.php | 31 ++++++++++++++----- custom/languages/en_UK.json | 4 +-- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/core/installation/steps/admin_account_setup.php b/core/installation/steps/admin_account_setup.php index 78e6ec60a4..68a7832ec9 100644 --- a/core/installation/steps/admin_account_setup.php +++ b/core/installation/steps/admin_account_setup.php @@ -12,22 +12,29 @@ function display_error(string $message) { } if ($_SERVER['REQUEST_METHOD'] == 'POST') { + $username_min = 3; + $username_max = 20; + $email_min = 4; + $email_max = 64; + $password_min = 6; + $password_max = 30; + $validation = Validate::check($_POST, [ 'username' => [ Validate::REQUIRED => true, - Validate::MIN => 3, - Validate::MAX => 20, + Validate::MIN => $username_min, + Validate::MAX => $username_max, ], 'email' => [ Validate::REQUIRED => true, - Validate::MIN => 4, - Validate::MAX => 64, + Validate::MIN => $email_min, + Validate::MAX => $email_max, Validate::EMAIL => true, ], 'password' => [ Validate::REQUIRED => true, - Validate::MIN => 6, - Validate::MAX => 30, + Validate::MIN => $password_min, + Validate::MAX => $password_max, ], 'password_again' => [ Validate::REQUIRED => true, @@ -40,9 +47,17 @@ function display_error(string $message) { if (strpos($item, 'is required') !== false) { display_error($language->get('installer', 'input_required')); } else if (strpos($item, 'minimum') !== false) { - display_error($language->get('installer', 'input_minimum')); + display_error($language->get('installer', 'input_minimum', [ + 'minUsername' => $username_min, + 'minEmail' => $email_min, + 'minPassword' => $password_min, + ])); } else if (strpos($item, 'maximum') !== false) { - display_error($language->get('installer', 'input_maximum')); + display_error($language->get('installer', 'input_maximum', [ + 'maxUsername' => $username_max, + 'maxEmail' => $email_max, + 'maxPassword' => $password_max, + ])); } else if (strpos($item, 'must match') !== false) { display_error($language->get('installer', 'passwords_must_match')); } else if (strpos($item, 'not a valid email') !== false) { diff --git a/custom/languages/en_UK.json b/custom/languages/en_UK.json index 51114af390..6b39e1db83 100644 --- a/custom/languages/en_UK.json +++ b/custom/languages/en_UK.json @@ -873,8 +873,8 @@ "installer/host_help": "The hostname is the base URL for your website. Do not include the subfolders from the Installation Path field, or http(s):\/\/ here!", "installer/hostname_error": "Please enter a valid hostname without http:\/\/ or https:\/\/", "installer/initialising_database_and_cache": "Initialising database and cache, please wait...", - "installer/input_maximum": "Please ensure your username is a maximum of 20 characters, and your email address and password are a maximum of 64 characters.", - "installer/input_minimum": "Please ensure your username is a minimum of 3 characters, your email address is a minimum of 4 characters, and your password is a minimum of {{minPassword}} characters.", + "installer/input_maximum": "Please ensure your username is a maximum of {{maxUsername}} characters, your email address is a maximum of {{maxEmail}} characters, and your password ia a maximum of {{maxPassword}} characters.", + "installer/input_minimum": "Please ensure your username is a minimum of {{minUsername}} characters, your email address is a minimum of {{minEmail}} characters, and your password is a minimum of {{minPassword}} characters.", "installer/input_required": "Please input a valid username, email address and password.", "installer/input_v1_details": "Please input the database details for your Nameless version 1 installation.", "installer/install": "Install", From 67ff00f7b56a1edf2d33ffab3e15dd3b1c5fd942 Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 13 Jun 2022 17:40:51 +0200 Subject: [PATCH 102/337] Add warning when debugging is enabled In case someone enables it at some point but forgets to disable it on a public site --- custom/languages/en_UK.json | 1 + modules/Core/pages/panel/index.php | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/custom/languages/en_UK.json b/custom/languages/en_UK.json index 6b39e1db83..5f5de75884 100644 --- a/custom/languages/en_UK.json +++ b/custom/languages/en_UK.json @@ -682,6 +682,7 @@ "admin/trusted_proxies_configured": "Trusted proxies", "admin/trusted_proxies_not_configured": "{{linkStart}}Trusted proxies{{linkEnd}} are not configured, IP bans may not work properly.", "admin/https_port_80": "You appear as if you are using HTTPS on port 80, which is almost definitely not true. If you use CloudFlare, make sure to set TLS encryption mode to Full (strict). If you run your own proxy, please configure it to send the X-Forwarded-Port header.", + "admin/debugging_enabled": "Debugging is enabled, sensitive information may be exposed to unauthorized visitors. Debugging should only be used for development, not on public sites.", "api/account_validated": "Account validated successfully", "api/finish_registration_email": "Please check your emails to complete registration.", "api/finish_registration_link": "Please click on the following link to complete registration:", diff --git a/modules/Core/pages/panel/index.php b/modules/Core/pages/panel/index.php index 50cc6c74ad..3d80b13813 100644 --- a/modules/Core/pages/panel/index.php +++ b/modules/Core/pages/panel/index.php @@ -200,6 +200,10 @@ $compat_errors[] = $language->get('admin', 'https_port_80'); } + if (defined('DEBUGGING') && DEBUGGING) { + $compat_errors[] = $language->get('admin', 'debugging_enabled'); + } + $smarty->assign([ 'SERVER_COMPATIBILITY' => $language->get('admin', 'server_compatibility'), 'COMPAT_SUCCESS' => $compat_success, From e5f28b3c27f2b0140cc11d934495e496ff3bffad Mon Sep 17 00:00:00 2001 From: Partydragen Date: Mon, 13 Jun 2022 18:53:55 +0200 Subject: [PATCH 103/337] Re-add maintenance mode enabled message --- custom/templates/DefaultRevamp/navbar.tpl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/custom/templates/DefaultRevamp/navbar.tpl b/custom/templates/DefaultRevamp/navbar.tpl index b89a771911..0afd7f2d67 100755 --- a/custom/templates/DefaultRevamp/navbar.tpl +++ b/custom/templates/DefaultRevamp/navbar.tpl @@ -179,4 +179,11 @@
{$MUST_VALIDATE_ACCOUNT}
- {/if} \ No newline at end of file + {/if} + + {if isset($MAINTENANCE_ENABLED)} +
+ + {$MAINTENANCE_ENABLED} +
+ {/if} From 61273704b1a8ba218dd20cf8535a26723aa5b553 Mon Sep 17 00:00:00 2001 From: Partydragen Date: Mon, 13 Jun 2022 19:14:02 +0200 Subject: [PATCH 104/337] Unauthorized to unauthorised --- custom/languages/en_UK.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom/languages/en_UK.json b/custom/languages/en_UK.json index 5f5de75884..424a24dcec 100644 --- a/custom/languages/en_UK.json +++ b/custom/languages/en_UK.json @@ -682,7 +682,7 @@ "admin/trusted_proxies_configured": "Trusted proxies", "admin/trusted_proxies_not_configured": "{{linkStart}}Trusted proxies{{linkEnd}} are not configured, IP bans may not work properly.", "admin/https_port_80": "You appear as if you are using HTTPS on port 80, which is almost definitely not true. If you use CloudFlare, make sure to set TLS encryption mode to Full (strict). If you run your own proxy, please configure it to send the X-Forwarded-Port header.", - "admin/debugging_enabled": "Debugging is enabled, sensitive information may be exposed to unauthorized visitors. Debugging should only be used for development, not on public sites.", + "admin/debugging_enabled": "Debugging is enabled, sensitive information may be exposed to unauthorised visitors. Debugging should only be used for development, not on public sites.", "api/account_validated": "Account validated successfully", "api/finish_registration_email": "Please check your emails to complete registration.", "api/finish_registration_link": "Please click on the following link to complete registration:", From e1255e07a6b2a21bd33556de5f81971eb7776876 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Mon, 13 Jun 2022 22:02:59 -0600 Subject: [PATCH 105/337] Add deprecation notices for 2.1.0 --- core/classes/Core/Hash.php | 2 +- core/classes/Core/Pages.php | 2 +- core/classes/Core/Paginator.php | 2 +- core/classes/Core/User.php | 2 +- core/classes/Database/DB.php | 74 +++++++++++++++---------------- core/classes/Database/Queries.php | 24 +++++----- 6 files changed, 51 insertions(+), 55 deletions(-) diff --git a/core/classes/Core/Hash.php b/core/classes/Core/Hash.php index ef10578730..e0809a77d9 100644 --- a/core/classes/Core/Hash.php +++ b/core/classes/Core/Hash.php @@ -13,7 +13,7 @@ class Hash { * Generate a unique hash. * * @return string Generated hash. - * @deprecated Use SecureRandom::alphanumeric() instead which is in a more appropriately named class + * @deprecated Use SecureRandom::alphanumeric() instead which is in a more appropriately named class. Will be removed in 2.1.0 * @throws Exception If an appropriate source of randomness cannot be found. */ public static function unique(): string { diff --git a/core/classes/Core/Pages.php b/core/classes/Core/Pages.php index ca4799e127..584c06ba16 100644 --- a/core/classes/Core/Pages.php +++ b/core/classes/Core/Pages.php @@ -152,7 +152,7 @@ public function getPageByURL(string $url): ?array { /** * Get the page details the user currently viewing. - * @deprecated Not used internally. + * @deprecated Not used internally. Will be removed in 2.1.0 * * @return array Details of current page. */ diff --git a/core/classes/Core/Paginator.php b/core/classes/Core/Paginator.php index 51b57db9dc..8dffb1dbf5 100644 --- a/core/classes/Core/Paginator.php +++ b/core/classes/Core/Paginator.php @@ -181,7 +181,7 @@ public function generate(int $links, string $href = '?'): string { /** * Set values of instance variables, alternative function (as they are set in getLimited()). - * @deprecated Not used internally. + * @deprecated Not used internally. Will be removed in 2.1.0 * * @param int $total * @param int $limit diff --git a/core/classes/Core/User.php b/core/classes/Core/User.php index 7af63b4a2f..336161975b 100644 --- a/core/classes/Core/User.php +++ b/core/classes/Core/User.php @@ -201,7 +201,7 @@ public function data(): ?UserData { } /** - * @deprecated Use getGroupStyle instead + * @deprecated Use getGroupStyle instead. Will be removed in 2.1.0 */ public function getGroupClass(): string { return $this->getGroupStyle(); diff --git a/core/classes/Database/DB.php b/core/classes/Database/DB.php index 2916745800..e47196b8dd 100644 --- a/core/classes/Database/DB.php +++ b/core/classes/Database/DB.php @@ -3,7 +3,6 @@ * Creates a singleton connection to the database with credentials from the config file. * * @package NamelessMC\Database - * @see InteractsWithDatabase * @author Samerton * @version 2.0.0-pr13 * @license MIT @@ -41,6 +40,39 @@ private function __construct(string $host, string $database, string $username, s $this->_query_recorder = QueryRecorder::getInstance(); } + public static function getCustomInstance( + string $host, + string $database, + string $username, + string $password, + int $port = 3306, + ?string $force_charset = null, + string $prefix = 'nl2_' + ): DB { + return new DB($host, $database, $username, $password, $port, $force_charset, $prefix); + } + + public static function getInstance(): DB { + if (self::$_instance) { + return self::$_instance; + } + + if (Config::get('mysql.initialise_charset')) { + $force_charset = Config::get('mysql.charset') ?: 'utf8mb4'; + } else { + $force_charset = null; + } + + return self::$_instance = self::getCustomInstance( + Config::get('mysql.host'), + Config::get('mysql.db'), + Config::get('mysql.username'), + Config::get('mysql.password'), + Config::get('mysql.port'), + $force_charset + ); + } + /** * Get the underlying PDO instance. * @@ -183,7 +215,7 @@ public function query(string $sql, array $params = [], int $fetch_method = PDO:: } /** - * @deprecated Use query() instead + * @deprecated Use query() instead. Will be removed in 2.1.0 * @return static */ public function selectQuery(string $sql, array $params = [], int $fetch_method = PDO::FETCH_OBJ) { @@ -191,7 +223,7 @@ public function selectQuery(string $sql, array $params = [], int $fetch_method = } /** - * @deprecated Use query() instead + * @deprecated Use query() instead. Will be removed in 2.1.0 * @return static */ public function createQuery(string $sql, array $params = []) { @@ -464,40 +496,4 @@ private function makeWhere(array $clauses): array { return [$where, $params]; } - - public static function getCustomInstance( - string $host, - string $database, - string $username, - string $password, - int $port = 3306, - ?string $force_charset = null, - string $prefix = 'nl2_' - ): DB { - return new DB($host, $database, $username, $password, $port, $force_charset, $prefix); - } - - public static function getInstance(): DB { - if (self::$_instance) { - return self::$_instance; - } - - if (Config::get('mysql.initialise_charset')) { - $force_charset = Config::get('mysql.charset') ?: 'utf8mb4'; - } else { - $force_charset = null; - } - - self::$_instance = self::getCustomInstance( - Config::get('mysql.host'), - Config::get('mysql.db'), - Config::get('mysql.username'), - Config::get('mysql.password'), - Config::get('mysql.port'), - $force_charset - ); - - return self::$_instance; - } - } diff --git a/core/classes/Database/Queries.php b/core/classes/Database/Queries.php index 3c5c3189b3..2fe207ae3e 100644 --- a/core/classes/Database/Queries.php +++ b/core/classes/Database/Queries.php @@ -21,7 +21,7 @@ private function warnDeprecated() { } /** - * @deprecated Use DB::getInstance()->get(...)->results() with identical parameters instead + * @deprecated Use DB::getInstance()->get(...)->results() with identical parameters instead. Will be removed in 2.1.0 * * find and replace * from: \$queries->getWhere\((.*)\) @@ -33,7 +33,7 @@ public function getWhere(string $table, array $where): array { } /** - * @deprecated Use DB::getInstance()->orderAll(...)->results() with identical parameters instead. + * @deprecated Use DB::getInstance()->orderAll(...)->results() with identical parameters instead. Will be removed in 2.1.0 * * find and replace * from: \$queries->orderAll\((.*)\) @@ -45,7 +45,7 @@ public function orderAll(string $table, string $order, string $sort = null): arr } /** - * @deprecated Use DB::getInstance()->orderWhere(...)->results() with identical parameters instead + * @deprecated Use DB::getInstance()->orderWhere(...)->results() with identical parameters instead. Will be removed in 2.1.0 * * find and replace * from: \$queries->orderWhere\((.*)\) @@ -57,7 +57,7 @@ public function orderWhere(string $table, string $where, string $order, string $ } /** - * @deprecated Use DB::getInstance()->update(...) with identical parameters instead + * @deprecated Use DB::getInstance()->update(...) with identical parameters instead. Will be removed in 2.1.0 * * find and replace * from: \$queries->update\((.*)\) @@ -71,7 +71,7 @@ public function update(string $table, $where, array $fields = []): void { } /** - * @deprecated Use DB::getInstance()->insert(...) with identical parameters instead + * @deprecated Use DB::getInstance()->insert(...) with identical parameters instead. Will be removed in 2.1.0 * * find and replace * from: \$queries->create\((.*)\) @@ -85,7 +85,7 @@ public function create(string $table, array $fields = []): void { } /** - * @deprecated Use DB::getInstance()->delete(...) with identical parameters instead + * @deprecated Use DB::getInstance()->delete(...) with identical parameters instead. Will be removed in 2.1.0 * * find and replace * from: \$queries->delete\((.*)\) @@ -99,7 +99,7 @@ public function delete(string $table, array $where): void { } /** - * @deprecated Use DB::getInstance()->increment(...) with identical parameters instead + * @deprecated Use DB::getInstance()->increment(...) with identical parameters instead. Will be removed in 2.1.0 * * find and replace * from: \$queries->increment\((.*)\) @@ -113,7 +113,7 @@ public function increment(string $table, int $id, string $field): void { } /** - * @deprecated Use DB::getInstance()->createTable(...) with identical parameters instead + * @deprecated Use DB::getInstance()->createTable(...) with identical parameters instead. Will be removed in 2.1.0 * * find and replace * from: \$queries->createTable\((.*)\) @@ -129,7 +129,7 @@ public function createTable(string $table, string $columns): void { /** * Get the last inserted ID * - * @deprecated Use DB::getInstance()->lastId() instead + * @deprecated Use DB::getInstance()->lastId() instead. Will be removed in 2.1.0 * find and replace * from: \$queries->getLastId\(\) * to: DB::getInstance()->lastId() @@ -142,7 +142,7 @@ public function getLastId() { } /** - * @deprecated Use DB::getInstance()->addColumn() with identical parameters instead + * @deprecated Use DB::getInstance()->addColumn() with identical parameters instead. Will be removed in 2.1.0 * * find and replace * from: \$queries->addColumn\((.*)\) @@ -156,7 +156,7 @@ public function addColumn(string $table, string $column, string $attributes): vo } /** - * @deprecated Use DB::getInstance()->showTables() with identical parameters instead + * @deprecated Use DB::getInstance()->showTables() with identical parameters instead. Will be removed in 2.1.0 * * find and replace * from: \$queries->tableExists\((.*)\) @@ -168,7 +168,7 @@ public function tableExists(string $table) { } /** - * @deprecated Seems to be unused + * Used in upgrade scripts to add permissions to a group. For example, if a new staffcp page has been added. */ public function addPermissionGroup(int $group_id, string $permission): void { $group = Group::find($group_id); From 307096fb54b3e46176819d03ed00278f8655c089 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Mon, 13 Jun 2022 22:24:43 -0600 Subject: [PATCH 106/337] Create and utilize `HttpUtils` class --- core/classes/Core/Log.php | 2 +- core/classes/Core/User.php | 2 +- core/classes/Core/Util.php | 185 +--------------- core/classes/Misc/ErrorHandler.php | 2 +- core/classes/Misc/HttpUtils.php | 206 ++++++++++++++++++ core/init.php | 6 +- .../steps/admin_account_setup.php | 2 +- core/integration/run_mcassoc.php | 2 +- index.php | 2 +- modules/Core/pages/authme_connector.php | 2 +- modules/Core/pages/panel/auth.php | 2 +- modules/Core/pages/panel/index.php | 4 +- modules/Core/pages/register.php | 2 +- modules/Core/queries/debug_link.php | 2 +- 14 files changed, 233 insertions(+), 188 deletions(-) create mode 100644 core/classes/Misc/HttpUtils.php diff --git a/core/classes/Core/Log.php b/core/classes/Core/Log.php index 22a6a13c1f..b44aa20780 100644 --- a/core/classes/Core/Log.php +++ b/core/classes/Core/Log.php @@ -214,7 +214,7 @@ public function log(string $action, string $info = '', ?int $user = null): bool $user = ($userTemp->isLoggedIn() ? $userTemp->data()->id : 0); } - $ip = Util::getRemoteAddress(); + $ip = HttpUtils::getRemoteAddress(); return $this->_db->insert('logs', [ 'time' => date('U'), diff --git a/core/classes/Core/User.php b/core/classes/Core/User.php index 336161975b..39f61001bb 100644 --- a/core/classes/Core/User.php +++ b/core/classes/Core/User.php @@ -329,7 +329,7 @@ private function _commonLogin(?string $username, ?string $password, bool $rememb $expiry = $is_admin ? 3600 : Config::get('remember.cookie_expiry'); $cookieName = $is_admin ? ($this->_cookieName . '_adm') : $this->_cookieName; - Cookie::put($cookieName, $hash, $expiry, Util::getProtocol() === 'https', true); + Cookie::put($cookieName, $hash, $expiry, HttpUtils::getProtocol() === 'https', true); } return true; diff --git a/core/classes/Core/Util.php b/core/classes/Core/Util.php index 77ddb1ff09..8127912ac2 100644 --- a/core/classes/Core/Util.php +++ b/core/classes/Core/Util.php @@ -1,7 +1,6 @@ When choosing the first trustworthy X-Forwarded-For client IP address, additional configuration is required. - > - > The IPs or IP ranges of the trusted reverse proxies are configured. The X-Forwarded-For IP list is searched - > from the rightmost, skipping all addresses that are on the trusted proxy list. The first non-matching - > address is the target address. - > - > The first trustworthy X-Forwarded-For IP address may belong to an untrusted intermediate proxy rather than - > the actual client computer, but it is the only IP suitable for security uses. - */ - - for ($i = count($addresses) - 1; $i >= 0; $i--) { - $address = $addresses[$i]; - - foreach ($trusted_proxies as $trusted_proxy) { - if (IpUtils::checkIp($address, $trusted_proxy)) { - // This address is trusted, move one left - continue 2; - } - } - - // Address is not trusted, this is the client IP we should use - return $address; - } - - // All addresses are in a trusted network, use leftmost address - return $addresses[0]; + return HttpUtils::getTrustedProxies(); } /** * Get the client's true IP address, using proxy headers if necessary. * + * @deprecated Use `HttpUtils::getRemoteAddress`. Will be removed in 2.1.0 * @return ?string Client IP address, or null if there is no remote address, for example in CLI environment */ public static function getRemoteAddress(): ?string { - if (!self::isTrustedProxy()) { - return $_SERVER['REMOTE_ADDR']; - } - - $headers = getallheaders(); - - // Try the simple headers first that only contain an IP address - - // Non standard header that only contains the origin address - if (isset($headers['X-Real-Ip'])) { - return $headers['X-Real-Ip']; - } - - // Non standard header sent by CloudFlare that only contains the origin address - if (isset($headers['Cf-Connecting-Ip'])) { - return $headers['Cf-Connecting-Ip']; - } - - /* - Now the more complicated (X-)Forwarded(-For) headers. - - Quote from MDN https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For#parsing: - > There may be multiple X-Forwarded-For headers present in a request (per RFC 2616). The IP addresses in - > these headers must be treated as a single list, starting with the first IP address of the first header - > and continuing to the last IP address of the last header. - > It is insufficient to use only one of multiple X-Forwarded-For headers. - - Unfortunately, we cannot follow this advice since PHP only seems to return the last header. However, since - supposedly the addresses should be read from right to left, only using the last header is not insecure, while - the using the first header would be. - In case of a weirdly behaving proxy that sends an additional Forwarded header instead of appending to an - existing one, the worst that would happen is an IP ban affecting the proxy (every user). Under no - circumstance would a user be able to spoof their address. - */ - - if (isset($headers['X-Forwarded-For'])) { - $addresses = []; - foreach (explode(',', $headers['X-Forwarded-For']) as $part) { - $addresses[] = trim($part); - } - - return self::firstNonProxyAddress($addresses); - } - - if (isset($headers['Forwarded'])) { - $addresses = []; - foreach (explode(',', $headers['Forwarded']) as $part1) { - // Extract the optional 'for=
' bit - foreach (explode(';', trim($part1)) as $part2) { - $part2 = explode('=', $part2); - if (count($part2) != 2) { - die("Invalid Forwarded header"); - } - - if ($part2[0] === 'for') { - $addresses[] = trim($part2[1]); - break; - } - } - } - - if (count($addresses) > 0) { - return self::firstNonProxyAddress($addresses); - } - } - - return $_SERVER['REMOTE_ADDR']; + return HttpUtils::getRemoteAddress(); } /** * Get the protocol used by client's HTTP request, using proxy headers if necessary. * + * @deprecated Use `HttpUtils::getProtocol`. Will be removed in 2.1.0 * @return string 'http' if HTTP or 'https' if HTTPS. If the protocol is not known, for example when using the CLI, 'http' is always returned. */ public static function getProtocol(): string { - if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) { - $proto = $_SERVER['HTTP_X_FORWARDED_PROTO']; - if ($proto !== 'http' && $proto !== 'https') { - die("Invalid X-Forwarded-Proto header, should be 'http' or 'https'."); - } - return $proto; - } - - if (isset($_SERVER['HTTPS'])) { - return $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http'; - } - - return 'http'; + return HttpUtils::getProtocol(); } /** * Get port used by client's HTTP request, using proxy headers if necessary. * + * @deprecated Use `HttpUtils::getPort`. Will be removed in 2.1.0 * @return ?int Port number, or null when using the CLI */ public static function getPort(): ?int { - if (isset($_SERVER['HTTP_X_FORWARDED_PORT'])) { - return (int) $_SERVER['HTTP_X_FORWARDED_PORT']; - } - - if (isset($_SERVER['SERVER_PORT'])) { - return (int) $_SERVER['SERVER_PORT']; - } - - return null; + return HttpUtils::getPort(); } /** @@ -359,9 +198,9 @@ public static function getSelfURL(bool $show_protocol = true): string { } if ($show_protocol) { - $protocol = self::getProtocol(); + $protocol = HttpUtils::getProtocol(); $url = $protocol . '://' . $url; - $port = self::getPort(); + $port = HttpUtils::getPort(); // Add port if it is non-standard for the current protocol if (!(($port === 80 && $protocol === 'http') || ($port === 443 && $protocol === 'https'))) { $url .= ':' . $port; diff --git a/core/classes/Misc/ErrorHandler.php b/core/classes/Misc/ErrorHandler.php index 30021208d5..1473158023 100644 --- a/core/classes/Misc/ErrorHandler.php +++ b/core/classes/Misc/ErrorHandler.php @@ -158,7 +158,7 @@ public static function catchException(?Throwable $exception, ?string $error_stri 'DEBUG_LINK_URL' => URL::build('/queries/debug_link'), // TODO: should we skip the 2 frames that are from the "new User()" above? 'ERROR_SQL_STACK' => QueryRecorder::getInstance()->getSqlStack(), - 'CURRENT_URL' => Util::getProtocol() . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], + 'CURRENT_URL' => HttpUtils::getProtocol() . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], 'FRAMES' => $frames, 'SKIP_FRAMES' => $skip_frames, 'BACK' => $language->get('general', 'back'), diff --git a/core/classes/Misc/HttpUtils.php b/core/classes/Misc/HttpUtils.php new file mode 100644 index 0000000000..f1ce6404cb --- /dev/null +++ b/core/classes/Misc/HttpUtils.php @@ -0,0 +1,206 @@ + There may be multiple X-Forwarded-For headers present in a request (per RFC 2616). The IP addresses in + // > these headers must be treated as a single list, starting with the first IP address of the first header + // > and continuing to the last IP address of the last header. + // > It is insufficient to use only one of multiple X-Forwarded-For headers. + // + // Unfortunately, we cannot follow this advice since PHP only seems to return the last header. However, since + // supposedly the addresses should be read from right to left, only using the last header is not insecure, while + // the using the first header would be. + // In case of a weirdly behaving proxy that sends an additional Forwarded header instead of appending to an + // existing one, the worst that would happen is an IP ban affecting the proxy (every user). Under no + // circumstance would a user be able to spoof their address. + if (isset($headers['X-Forwarded-For'])) { + $addresses = []; + foreach (explode(',', $headers['X-Forwarded-For']) as $part) { + $addresses[] = trim($part); + } + + return self::firstNonProxyAddress($addresses); + } + + if (isset($headers['Forwarded'])) { + $addresses = []; + foreach (explode(',', $headers['Forwarded']) as $part1) { + // Extract the optional 'for=
' bit + foreach (explode(';', trim($part1)) as $part2) { + $part2 = explode('=', $part2); + if (count($part2) != 2) { + die("Invalid Forwarded header"); + } + + if ($part2[0] === 'for') { + $addresses[] = trim($part2[1]); + break; + } + } + } + + if (count($addresses) > 0) { + return self::firstNonProxyAddress($addresses); + } + } + + return $_SERVER['REMOTE_ADDR']; + } + + /** + * Get the protocol used by client's HTTP request, using proxy headers if necessary. + * + * @return string 'http' if HTTP or 'https' if HTTPS. If the protocol is not known, for example when using the CLI, 'http' is always returned. + */ + public static function getProtocol(): string { + if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) { + $proto = $_SERVER['HTTP_X_FORWARDED_PROTO']; + if ($proto !== 'http' && $proto !== 'https') { + die("Invalid X-Forwarded-Proto header, should be 'http' or 'https'."); + } + return $proto; + } + + if (isset($_SERVER['HTTPS'])) { + return $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http'; + } + + return 'http'; + } + + /** + * Get port used by client's HTTP request, using proxy headers if necessary. + * + * @return ?int Port number, or null when using the CLI + */ + public static function getPort(): ?int { + if (isset($_SERVER['HTTP_X_FORWARDED_PORT'])) { + return (int) $_SERVER['HTTP_X_FORWARDED_PORT']; + } + + if (isset($_SERVER['SERVER_PORT'])) { + return (int) $_SERVER['SERVER_PORT']; + } + + return null; + } + + /** + * Determine whether the trusted proxies config option is set to a valid value or not. + * + * @return bool Whether the trusted proxies option is configured or not + */ + public static function isTrustedProxiesConfigured(): bool { + $config_proxies = Config::get('core.trustedProxies'); + $env_proxies = getenv('NAMELESS_TRUSTED_PROXIES'); + return ($config_proxies !== false && is_array($config_proxies)) || $env_proxies !== false; + } + + /** + * @return array List of trusted proxy networks according to config file and environment + */ + public static function getTrustedProxies(): array { + $trusted_proxies = []; + + // Add trusted proxies from config file + $config_proxies = Config::get('core.trustedProxies'); + if ($config_proxies !== false && $config_proxies !== null) { + if (!is_array($config_proxies)) { + die('Trusted proxies should be an array'); + } + $trusted_proxies = array_merge($trusted_proxies, $config_proxies); + } + + // Add trusted proxies from environment variable (comma-separated string) + $env_proxies = getenv('NAMELESS_TRUSTED_PROXIES'); + if ($env_proxies !== false && $env_proxies !== 'none') { + $env_proxies_array = explode(',', $env_proxies); + $trusted_proxies = array_merge($trusted_proxies, $env_proxies_array); + } + + return $trusted_proxies; + } + + /** + * Checks whether the client making the request is a trusted proxy. + * + * @return bool Whether the client is a trusted proxy or not. + */ + private static function isTrustedProxy(): bool { + $trusted_proxies = self::getTrustedProxies(); + + foreach ($trusted_proxies as $trustedProxy) { + if (IpUtils::checkIp($_SERVER['REMOTE_ADDR'], $trustedProxy)) { + return true; + } + } + + return false; + } + + /** + * Extract trustworthy address from a list of addresses provided by the Forwarded or X-Forwarded-For header. + * + * @return string Address that may be used for security purposes + */ + private static function firstNonProxyAddress(array $addresses): string { + if (count($addresses) === 0) { + throw new InvalidArgumentException('Addresses must not be empty'); + } + + $trusted_proxies = self::getTrustedProxies(); + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For#parsing + // > When choosing the first trustworthy X-Forwarded-For client IP address, additional configuration is required. + // > The IPs or IP ranges of the trusted reverse proxies are configured. The X-Forwarded-For IP list is searched + // > from the rightmost, skipping all addresses that are on the trusted proxy list. The first non-matching + // > address is the target address. + // > The first trustworthy X-Forwarded-For IP address may belong to an untrusted intermediate proxy rather than + // > the actual client computer, but it is the only IP suitable for security uses. + for ($i = count($addresses) - 1; $i >= 0; $i--) { + $address = $addresses[$i]; + + foreach ($trusted_proxies as $trusted_proxy) { + if (IpUtils::checkIp($address, $trusted_proxy)) { + // This address is trusted, move one left + continue 2; + } + } + + // Address is not trusted, this is the client IP we should use + return $address; + } + + // All addresses are in a trusted network, use leftmost address + return $addresses[0]; + } + +} diff --git a/core/init.php b/core/init.php index a8cca532d2..ef4308fa18 100644 --- a/core/init.php +++ b/core/init.php @@ -79,7 +79,7 @@ define('FORCE_WWW', true); } - if (defined('FORCE_SSL') && Util::getProtocol() === 'http') { + if (defined('FORCE_SSL') && HttpUtils::getProtocol() === 'http') { if (defined('FORCE_WWW') && !str_contains($_SERVER['HTTP_HOST'], 'www.')) { header('Location: https://www.' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']); die(); @@ -90,7 +90,7 @@ } if (defined('FORCE_WWW') && !str_contains($_SERVER['HTTP_HOST'], 'www.')) { - header('Location: ' . Util::getProtocol() . '://www.' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']); + header('Location: ' . HttpUtils::getProtocol() . '://www.' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']); } // Ensure database is up-to-date @@ -496,7 +496,7 @@ EventHandler::registerWebhooks($hook_array); // Get IP - $ip = Util::getRemoteAddress(); + $ip = HttpUtils::getRemoteAddress(); // Perform tasks if the user is logged in if ($user->isLoggedIn()) { diff --git a/core/installation/steps/admin_account_setup.php b/core/installation/steps/admin_account_setup.php index 68a7832ec9..8bd9d13ed4 100644 --- a/core/installation/steps/admin_account_setup.php +++ b/core/installation/steps/admin_account_setup.php @@ -72,7 +72,7 @@ function display_error(string $message) { try { $default_language = DB::getInstance()->get('languages', ['is_default', true])->results(); - $ip = Util::getRemoteAddress(); + $ip = HttpUtils::getRemoteAddress(); $user->create([ 'username' => Input::get('username'), diff --git a/core/integration/run_mcassoc.php b/core/integration/run_mcassoc.php index 964698d975..dae1531663 100644 --- a/core/integration/run_mcassoc.php +++ b/core/integration/run_mcassoc.php @@ -93,7 +93,7 @@ $password = $_SESSION['password']; // Get IP - $ip = Util::getRemoteAddress(); + $ip = HttpUtils::getRemoteAddress(); $user->create([ 'username' => $username, diff --git a/index.php b/index.php index 82c4e882ca..1b1af95de8 100644 --- a/index.php +++ b/index.php @@ -64,7 +64,7 @@ $tmp_dir = ini_get('upload_tmp_dir'); } -if (Util::getProtocol() === 'https') { +if (HttpUtils::getProtocol() === 'https') { ini_set('session.cookie_secure', 'On'); } diff --git a/modules/Core/pages/authme_connector.php b/modules/Core/pages/authme_connector.php index df16647897..02d306f71a 100644 --- a/modules/Core/pages/authme_connector.php +++ b/modules/Core/pages/authme_connector.php @@ -84,7 +84,7 @@ $language_id = $language_id[0]->id; } - $ip = Util::getRemoteAddress(); + $ip = HttpUtils::getRemoteAddress(); if (filter_var($ip, FILTER_VALIDATE_IP)) { // Valid IP } else { diff --git a/modules/Core/pages/panel/auth.php b/modules/Core/pages/panel/auth.php index 0018bda4f4..6f55eca86e 100644 --- a/modules/Core/pages/panel/auth.php +++ b/modules/Core/pages/panel/auth.php @@ -85,7 +85,7 @@ if ($login) { // Get IP - $ip = Util::getRemoteAddress(); + $ip = HttpUtils::getRemoteAddress(); // Create log Log::getInstance()->log(Log::Action('admin/login')); diff --git a/modules/Core/pages/panel/index.php b/modules/Core/pages/panel/index.php index 3d80b13813..93d6feee22 100644 --- a/modules/Core/pages/panel/index.php +++ b/modules/Core/pages/panel/index.php @@ -187,7 +187,7 @@ $compat_errors[] = $pdo_driver . ' Server ' . $pdo_server_version; } - if (Util::isTrustedProxiesConfigured()) { + if (HttpUtils::isTrustedProxiesConfigured()) { $compat_success[] = $language->get('admin', 'trusted_proxies_configured'); } else { $compat_errors[] = $language->get('admin', 'trusted_proxies_not_configured', [ @@ -196,7 +196,7 @@ ]); } - if (Util::getPort() === 80 && Util::getProtocol() === 'https') { + if (HttpUtils::getPort() === 80 && HttpUtils::getProtocol() === 'https') { $compat_errors[] = $language->get('admin', 'https_port_80'); } diff --git a/modules/Core/pages/register.php b/modules/Core/pages/register.php index 5402dc2b42..69f4be4b30 100644 --- a/modules/Core/pages/register.php +++ b/modules/Core/pages/register.php @@ -267,7 +267,7 @@ // Disabled $user = new User(); - $ip = Util::getRemoteAddress(); + $ip = HttpUtils::getRemoteAddress(); if (!filter_var($ip, FILTER_VALIDATE_IP)) { // TODO: Invalid IP, do something } diff --git a/modules/Core/queries/debug_link.php b/modules/Core/queries/debug_link.php index d49492b27a..47f2caf2e1 100755 --- a/modules/Core/queries/debug_link.php +++ b/modules/Core/queries/debug_link.php @@ -202,7 +202,7 @@ 'hooks' => $webhooks, 'forum_hooks' => $forum_hooks, ], - 'trusted_proxies' => Util::getTrustedProxies(), + 'trusted_proxies' => HttpUtils::getTrustedProxies(), ], 'groups' => $groups, 'config' => [ From 6352c474629e81c597f6242b29c6e30f1ffd4f65 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Mon, 13 Jun 2022 22:28:37 -0600 Subject: [PATCH 107/337] Remove some deprecations + add notice about deprecations --- CONTRIBUTING.md | 11 +++++++++-- core/classes/DTO/Announcement.php | 2 +- modules/Forum/pages/forum/view_topic.php | 2 +- scripts/seeder/MinecraftPlaceholderDataSeeder.php | 2 +- scripts/seeder/UserSeeder.php | 6 +++--- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0cdf4aa64a..03842339a8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -39,11 +39,13 @@ Here are some things you should know when contributing: ## Versioning As of NamelessMC 2.0.0 (to be released at time of writing), we use a unique versioning system. Similar to [semver](https://semver.org), we follow the `major.minor.patch` versioning pattern, however there are a few things to note: -- The `major` version is pinned at `2` for the time being. -- The `minor` version is only changed when *breaking changes are made*. These include: +- We use the naming `constant.major.patch` compared to semver. +- The `constant` version is pinned at `2` for the time being. +- The `major` version is only changed when *breaking changes are made*. These include: - Changes that require modules to update - Changes that require templates to update - Changes that require updates to the Nameless-Link Discord bot + - Changes that require updates to the Nameless-Link Discord bot - Changes that require updates to the debug.namelessmc.com repo - **If the minor version is bumped, we will inform users about which of the above aspects were affected.** - The `patch` version will change for any releases which do not include breaking changes, in our case this will generally mean a bug fix release. @@ -55,3 +57,8 @@ Examples: - A "major" release. Modules and/or templates and/or other integrations will need to be updated to support this release. - `2.1.4` - A bug fix release. Fully backwards compatible with `2.1.0` modules, templates & other integrations, but not compatible with (at least 1) `2.0.0` integration + +Deprecations rule of thumb: +- We might deprecate methods, classes or constants within a minor release. +- These will get tagged with `@deprecated` and will be announced. +- When something is marked as deprecated, it will not be removed until at least the next major release. diff --git a/core/classes/DTO/Announcement.php b/core/classes/DTO/Announcement.php index fb39d95acd..4010359229 100644 --- a/core/classes/DTO/Announcement.php +++ b/core/classes/DTO/Announcement.php @@ -27,7 +27,7 @@ public function __construct(object $row) { } public static function find(int $id): ?Announcement { - $row = DB::getInstance()->selectQuery('SELECT * FROM nl2_custom_announcements WHERE id = ?', [$id])->results(); + $row = DB::getInstance()->query('SELECT * FROM nl2_custom_announcements WHERE id = ?', [$id])->results(); return $row ? new Announcement($row[0]) : null; diff --git a/modules/Forum/pages/forum/view_topic.php b/modules/Forum/pages/forum/view_topic.php index 15ccf6877b..e81357fb49 100644 --- a/modules/Forum/pages/forum/view_topic.php +++ b/modules/Forum/pages/forum/view_topic.php @@ -815,7 +815,7 @@ 'INSERT_QUOTES' => $forum_language->get('forum', 'insert_quotes'), 'FORUM_TITLE' => Output::getClean($forum_parent[0]->forum_title), 'STARTED_BY' => $forum_language->get('forum', 'started_by_x', [ - 'author' => '' . $topic_user->getDisplayname() . '', + 'author' => '' . $topic_user->getDisplayname() . '', ]), 'SUCCESS' => $language->get('general', 'success'), 'ERROR' => $language->get('general', 'error') diff --git a/scripts/seeder/MinecraftPlaceholderDataSeeder.php b/scripts/seeder/MinecraftPlaceholderDataSeeder.php index 89789a95a0..780e3ae131 100644 --- a/scripts/seeder/MinecraftPlaceholderDataSeeder.php +++ b/scripts/seeder/MinecraftPlaceholderDataSeeder.php @@ -17,7 +17,7 @@ protected function run(DB $db, \Faker\Generator $faker): void { $user = $faker->randomElement($users); if (!array_key_exists($user->id, $user_uuids)) { - $uuid = hex2bin($db->selectQuery('SELECT identifier FROM nl2_users_integrations WHERE user_id = ?', [$user->id])->first()->identifier); + $uuid = hex2bin($db->query('SELECT identifier FROM nl2_users_integrations WHERE user_id = ?', [$user->id])->first()->identifier); $user_uuids[$user->id] = $uuid; } else { $uuid = $user_uuids[$user->id]; diff --git a/scripts/seeder/UserSeeder.php b/scripts/seeder/UserSeeder.php index 662254facd..4eb770a543 100644 --- a/scripts/seeder/UserSeeder.php +++ b/scripts/seeder/UserSeeder.php @@ -24,13 +24,13 @@ public function run(DB $db, \Faker\Generator $faker): void { 'language_id' => $db->get('languages', ['is_default', '=', 1])->first()->id, ]); $user_id = $db->lastId(); - $db->createQuery('INSERT INTO `nl2_users_groups` (`user_id`, `group_id`, `received`, `expire`) VALUES (?, ?, ?, ?)', [ + $db->query('INSERT INTO `nl2_users_groups` (`user_id`, `group_id`, `received`, `expire`) VALUES (?, ?, ?, ?)', [ 1, 2, date('U'), 0, ]); - $db->createQuery( + $db->query( 'INSERT INTO nl2_users_integrations (user_id, integration_id, identifier, username, verified, date, code) VALUES (?, ?, ?, ?, ?, ?, ?)', [ $user_id, 1, @@ -87,7 +87,7 @@ public function run(DB $db, \Faker\Generator $faker): void { ]); } - $db->createQuery( + $db->query( 'INSERT INTO nl2_users_integrations (user_id, integration_id, identifier, username, verified, date, code) VALUES (?, ?, ?, ?, ?, ?, ?)', [ $user_id, 1, From 5e07ac2d70b96e695a579f928abedab59b780da2 Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Mon, 13 Jun 2022 22:44:01 -0600 Subject: [PATCH 108/337] Create and utilize `Text` class, add deprecation warnings --- core/classes/Avatars/AvatarSource.php | 4 +- core/classes/Core/URL.php | 74 +++++++- core/classes/Core/Util.php | 156 ++--------------- core/classes/Integrations/IntegrationUser.php | 6 +- core/classes/Misc/HttpUtils.php | 8 + core/classes/Misc/NamelessOAuth.php | 2 +- core/classes/Misc/Report.php | 2 +- core/classes/Misc/Text.php | 162 ++++++++++++++++++ core/init.php | 4 +- core/integration/run_mcassoc.php | 2 +- custom/templates/DefaultRevamp/template.php | 2 +- modules/Core/hooks/ContentHook.php | 4 +- modules/Core/includes/emails/register.php | 2 +- .../endpoints/GetNotificationsEndpoint.php | 4 +- .../includes/endpoints/ListUsersEndpoint.php | 2 +- .../includes/endpoints/RegisterEndpoint.php | 6 +- modules/Core/pages/complete_signup.php | 2 +- modules/Core/pages/custom.php | 2 +- modules/Core/pages/forgot_password.php | 2 +- modules/Core/pages/panel/api.php | 2 +- modules/Core/pages/panel/emails.php | 2 +- modules/Core/pages/panel/emails_errors.php | 2 +- modules/Core/pages/panel/images.php | 14 +- modules/Core/pages/panel/index.php | 2 +- .../pages/panel/minecraft_server_banners.php | 2 +- modules/Core/pages/panel/modules.php | 6 +- modules/Core/pages/panel/pages.php | 2 +- modules/Core/pages/panel/panel_templates.php | 2 +- modules/Core/pages/panel/registration.php | 2 +- modules/Core/pages/panel/seo.php | 10 +- modules/Core/pages/panel/templates.php | 16 +- modules/Core/pages/panel/users_ip_lookup.php | 4 +- modules/Core/pages/panel/users_oauth.php | 2 +- modules/Core/pages/panel/widgets.php | 4 +- modules/Core/pages/register.php | 2 +- modules/Core/pages/validate.php | 2 +- modules/Core/widgets/ProfilePostsWidget.php | 2 +- modules/Core/widgets/ServerStatusWidget.php | 2 +- modules/Forum/classes/Forum.php | 2 +- modules/Forum/classes/Forum_Sitemap.php | 4 +- modules/Forum/pages/forum/index.php | 2 +- modules/Forum/pages/forum/new_topic.php | 2 +- modules/Forum/pages/forum/view_forum.php | 2 +- modules/Forum/pages/forum/view_topic.php | 10 +- 44 files changed, 330 insertions(+), 218 deletions(-) create mode 100644 core/classes/Misc/Text.php diff --git a/core/classes/Avatars/AvatarSource.php b/core/classes/Avatars/AvatarSource.php index 7e752952fb..9463650a0c 100644 --- a/core/classes/Avatars/AvatarSource.php +++ b/core/classes/Avatars/AvatarSource.php @@ -57,7 +57,7 @@ public static function getAvatarFromUserData(object $data, bool $allow_gifs = fa foreach ($exts as $ext) { if (file_exists(ROOT_PATH . '/uploads/avatars/' . $data->id . '.' . $ext)) { // We don't check the validity here since we know the file exists for sure - return ($full ? rtrim(Util::getSelfURL(), '/') : '') . ((defined('CONFIG_PATH')) ? CONFIG_PATH . '/' : '/') . 'uploads/avatars/' . $data->id . '.' . $ext . '?v=' . urlencode($data->avatar_updated); + return ($full ? rtrim(URL::getSelfURL(), '/') : '') . ((defined('CONFIG_PATH')) ? CONFIG_PATH . '/' : '/') . 'uploads/avatars/' . $data->id . '.' . $ext . '?v=' . urlencode($data->avatar_updated); } } } @@ -67,7 +67,7 @@ public static function getAvatarFromUserData(object $data, bool $allow_gifs = fa if (defined('DEFAULT_AVATAR_TYPE') && DEFAULT_AVATAR_TYPE == 'custom' && DEFAULT_AVATAR_IMAGE !== '') { if (file_exists(ROOT_PATH . '/uploads/avatars/defaults/' . DEFAULT_AVATAR_IMAGE)) { // We don't check the validity here since we know the file exists for sure - return ($full ? rtrim(Util::getSelfURL(), '/') : '') . ((defined('CONFIG_PATH')) ? CONFIG_PATH . '/' : '/') . 'uploads/avatars/defaults/' . DEFAULT_AVATAR_IMAGE; + return ($full ? rtrim(URL::getSelfURL(), '/') : '') . ((defined('CONFIG_PATH')) ? CONFIG_PATH . '/' : '/') . 'uploads/avatars/defaults/' . DEFAULT_AVATAR_IMAGE; } } diff --git a/core/classes/Core/URL.php b/core/classes/Core/URL.php index ffbc93ecf4..1ca2f201dd 100644 --- a/core/classes/Core/URL.php +++ b/core/classes/Core/URL.php @@ -4,7 +4,7 @@ * * @package NamelessMC\Core * @author Samerton - * @version 2.0.0-pr8 + * @version 2.0.0 * @license MIT */ class URL { @@ -15,7 +15,6 @@ class URL { * @param string $url Contains the URL which will be formatted. * @param string $params Contains string with URL parameters. * @param ?string $force Determines whether to force a URL type (optional, can be either "friendly" or "non-friendly"). - * * @return string Assembled URL, false on failure. */ public static function build(string $url, string $params = '', ?string $force = null): string { @@ -77,4 +76,75 @@ private static function buildNonFriendly(string $url, string $params): string { return (defined('CONFIG_PATH') ? CONFIG_PATH : '') . '/index.php?route=' . $url . ((substr($url, -1) == '/') ? '' : '/'); } + + /** + * Get the server name. + * + * @param bool $show_protocol Whether to show http(s) at front or not. + * @return string Compiled URL. + */ + public static function getSelfURL(bool $show_protocol = true): string { + $hostname = Config::get('core.hostname'); + + if (!$hostname) { + $hostname = $_SERVER['SERVER_NAME']; + } + + $url = $hostname; + + if (defined('FORCE_WWW') && FORCE_WWW && !str_contains($hostname, 'www')) { + $url = 'www.' . $url; + } + + if ($show_protocol) { + $protocol = HttpUtils::getProtocol(); + $url = $protocol . '://' . $url; + $port = HttpUtils::getPort(); + // Add port if it is non-standard for the current protocol + if (!(($port === 80 && $protocol === 'http') || ($port === 443 && $protocol === 'https'))) { + $url .= ':' . $port; + } + } + + if (substr($url, -1) !== '/') { + $url .= '/'; + } + + return $url; + } + + /** + * Is a URL internal or external? Accepts full URL and also just a path. + * + * @param string $url URL/path to check. + * + * @return bool Whether URL is external or not. + */ + public static function isExternalURL(string $url): bool { + if ($url[0] == '/' && $url[1] != '/') { + return false; + } + + $parsed = parse_url($url); + + return !(str_replace('www.', '', rtrim(self::getSelfURL(false), '/')) == str_replace('www.', '', $parsed['host'])); + } + + /** + * Add target and rel attributes to external links only. + * From https://stackoverflow.com/a/53461987 + * + * @param string $data Data to replace. + * @return string Replaced string. + */ + public static function replaceAnchorsWithText(string $data): string { + return preg_replace_callback('/]*href=["|\']([^"|\']*)["|\'][^>]*>([^<]*)<\/a>/i', static function ($m): string { + if (!str_contains($m[1], self::getSelfURL())) { + return '' . $m[2] . ''; + } + + return '' . $m[2] . ''; + }, $data); + } + } diff --git a/core/classes/Core/Util.php b/core/classes/Core/Util.php index 8127912ac2..b75f130ab7 100644 --- a/core/classes/Core/Util.php +++ b/core/classes/Core/Util.php @@ -115,18 +115,12 @@ public static function listTimezones(): array { /** * Is a URL internal or external? Accepts full URL and also just a path. * + * @deprecated Use `URL::isExternalURL` instead. Will be removed in 2.1.0 * @param string $url URL/path to check. - * * @return bool Whether URL is external or not. */ public static function isExternalURL(string $url): bool { - if ($url[0] == '/' && $url[1] != '/') { - return false; - } - - $parsed = parse_url($url); - - return !(str_replace('www.', '', rtrim(self::getSelfURL(false), '/')) == str_replace('www.', '', $parsed['host'])); + return URL::isExternalURL($url); } /** @@ -180,54 +174,23 @@ public static function getPort(): ?int { /** * Get the server name. * + * @deprecated Use `URL::getSelfURL` instead. Will be removed in 2.1.0 * @param bool $show_protocol Whether to show http(s) at front or not. - * * @return string Compiled URL. */ public static function getSelfURL(bool $show_protocol = true): string { - $hostname = Config::get('core.hostname'); - - if (!$hostname) { - $hostname = $_SERVER['SERVER_NAME']; - } - - $url = $hostname; - - if (defined('FORCE_WWW') && FORCE_WWW && !str_contains($hostname, 'www')) { - $url = 'www.' . $url; - } - - if ($show_protocol) { - $protocol = HttpUtils::getProtocol(); - $url = $protocol . '://' . $url; - $port = HttpUtils::getPort(); - // Add port if it is non-standard for the current protocol - if (!(($port === 80 && $protocol === 'http') || ($port === 443 && $protocol === 'https'))) { - $url .= ':' . $port; - } - } - - if (substr($url, -1) !== '/') { - $url .= '/'; - } - - return $url; + return URL::getSelfURL($show_protocol); } /** * URL-ify a string * + * @deprecated Use `Text::urlSafe` instead. Will be removed in 2.1.0 * @param string|null $string $string String to URLify - * * @return string Url-ified string. (I dont know what this means) */ public static function stringToURL(string $string = null): string { - if ($string) { - $string = preg_replace('/[^A-Za-z0-9 ]/', '', $string); - return Output::getClean(strtolower(urlencode(str_replace(' ', '-', $string)))); - } - - return ''; + return Text::urlSafe($string); } /** @@ -244,98 +207,14 @@ public static function stringToURL(string $string = null): string { * @link http://book.cakephp.org/view/1469/Text#truncate-1625 * @link https://github.com/cakephp/cakephp/blob/master/LICENSE * + * @deprecated Use `Text::truncate` instead. Will be removed in 2.1.0 * @param string $text String to truncate. * @param int $length Length of returned string, including ellipsis. * @param array $options An array of html attributes and options. * @return string Trimmed string. */ public static function truncate(string $text, int $length = 750, array $options = []): string { - $default = [ - 'ending' => '...', 'exact' => true, 'html' => false - ]; - $options = array_merge($default, $options); - extract($options); - - if ($html) { - if (mb_strlen(preg_replace('/<.*?>/', '', $text)) <= $length) { - return $text; - } - $totalLength = mb_strlen(strip_tags($ending)); - $openTags = []; - $truncate = ''; - - preg_match_all('/(<\/?([\w+]+)[^>]*>)?([^<>]*)/', $text, $tags, PREG_SET_ORDER); - foreach ($tags as $tag) { - if (!preg_match('/img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param/s', $tag[2])) { - if (preg_match('/<[\w]+[^>]*>/s', $tag[0])) { - array_unshift($openTags, $tag[2]); - } else { - if (preg_match('/<\/([\w]+)[^>]*>/s', $tag[0], $closeTag)) { - $pos = array_search($closeTag[1], $openTags); - if ($pos !== false) { - array_splice($openTags, $pos, 1); - } - } - } - } - $truncate .= $tag[1]; - - $contentLength = mb_strlen(preg_replace('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', ' ', $tag[3])); - if ($contentLength + $totalLength > $length) { - $left = $length - $totalLength; - $entitiesLength = 0; - if (preg_match_all('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', $tag[3], $entities, PREG_OFFSET_CAPTURE)) { - foreach ($entities[0] as $entity) { - if ($entity[1] + 1 - $entitiesLength <= $left) { - $left--; - $entitiesLength += mb_strlen($entity[0]); - } else { - break; - } - } - } - - $truncate .= mb_substr($tag[3], 0, $left + $entitiesLength); - break; - } - - $truncate .= $tag[3]; - $totalLength += $contentLength; - if ($totalLength >= $length) { - break; - } - } - } else { - if (mb_strlen($text) <= $length) { - return $text; - } - - $truncate = mb_substr($text, 0, $length - mb_strlen($ending)); - } - if (!$exact) { - $spacepos = mb_strrpos($truncate, ' '); - if ($html) { - $bits = mb_substr($truncate, $spacepos); - preg_match_all('/<\/([a-z]+)>/', $bits, $droppedTags, PREG_SET_ORDER); - if (!empty($droppedTags)) { - foreach ($droppedTags as $closingTag) { - if (!in_array($closingTag[1], $openTags)) { - array_unshift($openTags, $closingTag[1]); - } - } - } - } - $truncate = mb_substr($truncate, 0, $spacepos); - } - $truncate .= $ending; - - if ($html) { - foreach ($openTags as $tag) { - $truncate .= ''; - } - } - - return $truncate; + return Text::truncate($text, $length, $options); } /** @@ -396,17 +275,12 @@ public static function getLatestNews(): string { * Add target and rel attributes to external links only. * From https://stackoverflow.com/a/53461987 * + * @deprecated Use `URL::replaceAnchorsWithText`. Will be removed in 2.1.0 * @param string $data Data to replace. * @return string Replaced string. */ public static function replaceAnchorsWithText(string $data): string { - return preg_replace_callback('/]*href=["|\']([^"|\']*)["|\'][^>]*>([^<]*)<\/a>/i', static function ($m): string { - if (!str_contains($m[1], self::getSelfURL())) { - return '' . $m[2] . ''; - } - - return '' . $m[2] . ''; - }, $data); + return URL::replaceAnchorsWithText($data); } /** @@ -502,26 +376,24 @@ public static function isModuleEnabled(string $name): bool { /** * Replace native emojis with their Twemoji equivalent. * + * @deprecated Use `Text::renderEmojis` instead. Will be removed in 2.1.0 * @param string $text Text to parse * @return string Text with emojis replaced with URLs to their Twemoji equivalent. */ public static function renderEmojis(string $text): string { - return Twemoji::text($text)->toHtml(null, [ - 'width' => 20, - 'height' => 20, - 'style' => 'vertical-align: middle;' - ]); + return Text::renderEmojis($text); } /** * Wrap text in HTML `` tags. Used for when variables in translations are bolded, * since we want as little HTML in the translation strings as possible. * + * @deprecated Use `Text::bold` instead. Will be removed in 2.1.0 * @param string $text Text to wrap * @return string Text wrapped in `` tags */ public static function bold(string $text): string { - return '' . $text . ''; + return Text::bold($text); } /** diff --git a/core/classes/Integrations/IntegrationUser.php b/core/classes/Integrations/IntegrationUser.php index c0d920d63c..9b2f38f9e4 100644 --- a/core/classes/Integrations/IntegrationUser.php +++ b/core/classes/Integrations/IntegrationUser.php @@ -122,7 +122,7 @@ public function linkIntegration(User $user, ?string $identifier, ?string $userna 'integration' => $this->_integration->getName(), ]), 'avatar_url' => $user->getAvatar(128, true), - 'url' => Util::getSelfURL() . ltrim($user->getProfileURL(), '/'), + 'url' => URL::getSelfURL() . ltrim($user->getProfileURL(), '/'), 'integration_user' => [ 'identifier' => $identifier, 'username' => $username, @@ -153,7 +153,7 @@ public function verifyIntegration(): void { 'integration' => $this->_integration->getName(), ]), 'avatar_url' => $user->getAvatar(128, true), - 'url' => Util::getSelfURL() . ltrim($user->getProfileURL(), '/'), + 'url' => URL::getSelfURL() . ltrim($user->getProfileURL(), '/'), 'integration_user' => [ 'identifier' => $this->data()->identifier, 'username' => $this->data()->username, @@ -184,7 +184,7 @@ public function unlinkIntegration(): void { 'integration' => $this->_integration->getName(), ]), 'avatar_url' => $user->getAvatar(128, true), - 'url' => Util::getSelfURL() . ltrim($user->getProfileURL(), '/'), + 'url' => URL::getSelfURL() . ltrim($user->getProfileURL(), '/'), 'integration_user' => [ 'identifier' => $this->data()->identifier, 'username' => $this->data()->username, diff --git a/core/classes/Misc/HttpUtils.php b/core/classes/Misc/HttpUtils.php index f1ce6404cb..d7a55c32bd 100644 --- a/core/classes/Misc/HttpUtils.php +++ b/core/classes/Misc/HttpUtils.php @@ -2,6 +2,14 @@ use Symfony\Component\HttpFoundation\IpUtils; +/** + * Helps with common HTTP related tasks. + * + * @package NamelessMC\Misc + * @author Derkades + * @version 2.0.0 + * @license MIT + */ class HttpUtils { /** diff --git a/core/classes/Misc/NamelessOAuth.php b/core/classes/Misc/NamelessOAuth.php index e005f14e22..a39e852235 100644 --- a/core/classes/Misc/NamelessOAuth.php +++ b/core/classes/Misc/NamelessOAuth.php @@ -91,7 +91,7 @@ public function getProvidersAvailable(): array { */ public function getProviderInstance(string $provider): AbstractProvider { [$clientId, $clientSecret] = $this->getCredentials($provider); - $url = rtrim(Util::getSelfURL(), '/') . URL::build('/oauth', "provider=" . urlencode($provider), 'non-friendly'); + $url = rtrim(URL::getSelfURL(), '/') . URL::build('/oauth', "provider=" . urlencode($provider), 'non-friendly'); $options = [ 'clientId' => $clientId, 'clientSecret' => $clientSecret, diff --git a/core/classes/Misc/Report.php b/core/classes/Misc/Report.php index 16a7eed032..f5857860cd 100644 --- a/core/classes/Misc/Report.php +++ b/core/classes/Misc/Report.php @@ -59,7 +59,7 @@ public static function create(Language $language, User $user_reporting, User $re 'content_full' => $data['report_reason'], 'avatar_url' => $data['reported_id'] == 0 ? null : ($data['reported_uuid'] !== null ? AvatarSource::getAvatarFromUUID($data['reported_uuid']) : $reported_user->getAvatar()), 'title' => $language->get('general', 'view_report'), - 'url' => rtrim(Util::getSelfURL(), '/') . URL::build('/panel/users/reports/', 'id=' . $id) + 'url' => rtrim(URL::getSelfURL(), '/') . URL::build('/panel/users/reports/', 'id=' . $id) ]); } } diff --git a/core/classes/Misc/Text.php b/core/classes/Misc/Text.php new file mode 100644 index 0000000000..0db2507d50 --- /dev/null +++ b/core/classes/Misc/Text.php @@ -0,0 +1,162 @@ + '...', 'exact' => true, 'html' => false + ]; + $options = array_merge($default, $options); + extract($options); + + if ($html) { + if (mb_strlen(preg_replace('/<.*?>/', '', $text)) <= $length) { + return $text; + } + $totalLength = mb_strlen(strip_tags($ending)); + $openTags = []; + $truncate = ''; + + preg_match_all('/(<\/?([\w+]+)[^>]*>)?([^<>]*)/', $text, $tags, PREG_SET_ORDER); + foreach ($tags as $tag) { + if (!preg_match('/img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param/s', $tag[2])) { + if (preg_match('/<[\w]+[^>]*>/s', $tag[0])) { + array_unshift($openTags, $tag[2]); + } else { + if (preg_match('/<\/([\w]+)[^>]*>/s', $tag[0], $closeTag)) { + $pos = array_search($closeTag[1], $openTags); + if ($pos !== false) { + array_splice($openTags, $pos, 1); + } + } + } + } + $truncate .= $tag[1]; + + $contentLength = mb_strlen(preg_replace('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', ' ', $tag[3])); + if ($contentLength + $totalLength > $length) { + $left = $length - $totalLength; + $entitiesLength = 0; + if (preg_match_all('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', $tag[3], $entities, PREG_OFFSET_CAPTURE)) { + foreach ($entities[0] as $entity) { + if ($entity[1] + 1 - $entitiesLength <= $left) { + $left--; + $entitiesLength += mb_strlen($entity[0]); + } else { + break; + } + } + } + + $truncate .= mb_substr($tag[3], 0, $left + $entitiesLength); + break; + } + + $truncate .= $tag[3]; + $totalLength += $contentLength; + if ($totalLength >= $length) { + break; + } + } + } else { + if (mb_strlen($text) <= $length) { + return $text; + } + + $truncate = mb_substr($text, 0, $length - mb_strlen($ending)); + } + if (!$exact) { + $spacepos = mb_strrpos($truncate, ' '); + if ($html) { + $bits = mb_substr($truncate, $spacepos); + preg_match_all('/<\/([a-z]+)>/', $bits, $droppedTags, PREG_SET_ORDER); + if (!empty($droppedTags)) { + foreach ($droppedTags as $closingTag) { + if (!in_array($closingTag[1], $openTags)) { + array_unshift($openTags, $closingTag[1]); + } + } + } + } + $truncate = mb_substr($truncate, 0, $spacepos); + } + $truncate .= $ending; + + if ($html) { + foreach ($openTags as $tag) { + $truncate .= ''; + } + } + + return $truncate; + } + + /** + * URL-ify a string + * + * @param string|null $string $string String to URLify + * @return string Url-ified string. (I dont know what this means) + */ + public static function urlSafe(string $string = null): string { + if ($string) { + $string = preg_replace('/[^A-Za-z0-9 ]/', '', $string); + return Output::getClean(strtolower(urlencode(str_replace(' ', '-', $string)))); + } + + return ''; + } + + /** + * Wrap text in HTML `` tags. Used for when variables in translations are bolded, + * since we want as little HTML in the translation strings as possible. + * + * @param string $text Text to wrap + * @return string Text wrapped in `` tags + */ + public static function bold(string $text): string { + return '' . $text . ''; + } + + /** + * Replace native emojis with their Twemoji equivalent. + * + * @param string $text Text to parse + * @return string Text with emojis replaced with URLs to their Twemoji equivalent. + */ + public static function renderEmojis(string $text): string { + return Twemoji::text($text)->toHtml(null, [ + 'width' => 20, + 'height' => 20, + 'style' => 'vertical-align: middle;' + ]); + } +} diff --git a/core/init.php b/core/init.php index ef4308fa18..370910b328 100644 --- a/core/init.php +++ b/core/init.php @@ -316,8 +316,8 @@ // Basic Smarty variables $smarty->assign([ 'CONFIG_PATH' => defined('CONFIG_PATH') ? CONFIG_PATH . '/' : '/', - 'OG_URL' => Output::getClean(rtrim(Util::getSelfURL(), '/') . $_SERVER['REQUEST_URI']), - 'OG_IMAGE' => Output::getClean(rtrim(Util::getSelfURL(), '/') . '/core/assets/img/site_image.png'), + 'OG_URL' => Output::getClean(rtrim(URL::getSelfURL(), '/') . $_SERVER['REQUEST_URI']), + 'OG_IMAGE' => Output::getClean(rtrim(URL::getSelfURL(), '/') . '/core/assets/img/site_image.png'), 'SITE_NAME' => Output::getClean(SITE_NAME), 'SITE_HOME' => URL::build('/'), 'USER_INFO_URL' => URL::build('/queries/user/', 'id='), diff --git a/core/integration/run_mcassoc.php b/core/integration/run_mcassoc.php index dae1531663..4ba53782a1 100644 --- a/core/integration/run_mcassoc.php +++ b/core/integration/run_mcassoc.php @@ -44,7 +44,7 @@ } } - $return_link = rtrim(Util::getSelfURL(), '/') . URL::build('/register/', 'step=2'); + $return_link = rtrim(URL::getSelfURL(), '/') . URL::build('/register/', 'step=2'); $key = $mcassoc->generateKey($username); $smarty->assign('MCASSOC', ' diff --git a/custom/templates/DefaultRevamp/template.php b/custom/templates/DefaultRevamp/template.php index bbf33a24c4..08692ea31b 100755 --- a/custom/templates/DefaultRevamp/template.php +++ b/custom/templates/DefaultRevamp/template.php @@ -95,7 +95,7 @@ public function onPageLoad() { $JSVariables = [ 'siteName' => Output::getClean(SITE_NAME), 'siteURL' => URL::build('/'), - 'fullSiteUrl' => Util::getSelfURL() . ltrim(URL::build('/'), '/'), + 'fullSiteUrl' => URL::getSelfURL() . ltrim(URL::build('/'), '/'), 'page' => PAGE, 'avatarSource' => AvatarSource::getUrlToFormat(), 'copied' => $this->_language->get('general', 'copied'), diff --git a/modules/Core/hooks/ContentHook.php b/modules/Core/hooks/ContentHook.php index ce2f17991d..f5403ced05 100644 --- a/modules/Core/hooks/ContentHook.php +++ b/modules/Core/hooks/ContentHook.php @@ -56,7 +56,7 @@ public static function purify(array $params = []): array { public static function renderEmojis(array $params = []): array { if (parent::validateParams($params, ['content'])) { - $params['content'] = Util::renderEmojis($params['content']); + $params['content'] = Text::renderEmojis($params['content']); } return $params; @@ -64,7 +64,7 @@ public static function renderEmojis(array $params = []): array { public static function replaceAnchors(array $params = []): array { if (parent::validateParams($params, ['content'])) { - $params['content'] = Util::replaceAnchorsWithText($params['content']); + $params['content'] = URL::replaceAnchorsWithText($params['content']); } return $params; diff --git a/modules/Core/includes/emails/register.php b/modules/Core/includes/emails/register.php index 80cbe04301..7aa32fb3b4 100644 --- a/modules/Core/includes/emails/register.php +++ b/modules/Core/includes/emails/register.php @@ -10,7 +10,7 @@ */ function sendRegisterEmail(Language $language, string $email_address, string $username, int $user_id, string $code): bool { - $link = rtrim(Util::getSelfURL(), '/') . URL::build('/validate/', 'c=' . urlencode($code)); + $link = rtrim(URL::getSelfURL(), '/') . URL::build('/validate/', 'c=' . urlencode($code)); $sent = Email::send( ['email' => Output::getClean($email_address), 'name' => Output::getClean($username)], diff --git a/modules/Core/includes/endpoints/GetNotificationsEndpoint.php b/modules/Core/includes/endpoints/GetNotificationsEndpoint.php index 1552933d5a..a72e70ae3f 100644 --- a/modules/Core/includes/endpoints/GetNotificationsEndpoint.php +++ b/modules/Core/includes/endpoints/GetNotificationsEndpoint.php @@ -28,7 +28,7 @@ public function execute(Nameless2API $api, User $user): void { 'type' => $result->type, 'message_short' => $result->content_short, 'message' => ($result->content) ? strip_tags($result->content) : $result->content_short, - 'url' => rtrim(Util::getSelfURL(), '/') . URL::build('/user/alerts/', 'view=' . urlencode($result->id)), + 'url' => rtrim(URL::getSelfURL(), '/') . URL::build('/user/alerts/', 'view=' . urlencode($result->id)), 'received_at' => $result->created, ]; } @@ -40,7 +40,7 @@ public function execute(Nameless2API $api, User $user): void { foreach ($messages->results() as $result) { $return['notifications'][] = [ 'type' => 'message', - 'url' => Util::getSelfURL() . ltrim(URL::build('/user/messaging/', 'action=view&message=' . urlencode($result->id)), '/'), + 'url' => URL::getSelfURL() . ltrim(URL::build('/user/messaging/', 'action=view&message=' . urlencode($result->id)), '/'), 'message_short' => $result->title, 'message' => $result->title ]; diff --git a/modules/Core/includes/endpoints/ListUsersEndpoint.php b/modules/Core/includes/endpoints/ListUsersEndpoint.php index bc057a680d..a6b674ed91 100644 --- a/modules/Core/includes/endpoints/ListUsersEndpoint.php +++ b/modules/Core/includes/endpoints/ListUsersEndpoint.php @@ -59,7 +59,7 @@ public function execute(Nameless2API $api): void { 'previous_page' => null, ]; - $base_url = Util::getSelfURL() . 'index.php?route=/api/v2/users&'; + $base_url = URL::getSelfURL() . 'index.php?route=/api/v2/users&'; if (isset($_GET['limit']) && is_numeric($_GET['limit'])) { $limit = (int) $_GET['limit']; if ($limit >= 1) { diff --git a/modules/Core/includes/endpoints/RegisterEndpoint.php b/modules/Core/includes/endpoints/RegisterEndpoint.php index 8256703095..983f4b5d8d 100644 --- a/modules/Core/includes/endpoints/RegisterEndpoint.php +++ b/modules/Core/includes/endpoints/RegisterEndpoint.php @@ -166,13 +166,13 @@ private function createUser(Nameless2API $api, string $username, string $email, 'user' => $user->getDisplayname(), ]), 'avatar_url' => $user->getAvatar(128, true), - 'url' => Util::getSelfURL() . ltrim($user->getProfileURL(), '/'), + 'url' => URL::getSelfURL() . ltrim($user->getProfileURL(), '/'), 'language' => $api->getLanguage(), ] ); if ($return) { - $api->returnArray(['message' => $api->getLanguage()->get('api', 'finish_registration_link'), 'user_id' => $user_id, 'link' => rtrim(Util::getSelfURL(), '/') . URL::build('/complete_signup/', 'c=' . urlencode($code))]); + $api->returnArray(['message' => $api->getLanguage()->get('api', 'finish_registration_link'), 'user_id' => $user_id, 'link' => rtrim(URL::getSelfURL(), '/') . URL::build('/complete_signup/', 'c=' . urlencode($code))]); } return ['user_id' => $user_id]; @@ -201,7 +201,7 @@ private function sendRegistrationEmail(Nameless2API $api, string $username, stri $user_id = $user_id['user_id']; // Get link + template - $link = Util::getSelfURL() . ltrim(URL::build('/complete_signup/', 'c=' . urlencode($code)), '/'); + $link = URL::getSelfURL() . ltrim(URL::build('/complete_signup/', 'c=' . urlencode($code)), '/'); $sent = Email::send( ['email' => Output::getClean($email), 'name' => Output::getClean($username)], diff --git a/modules/Core/pages/complete_signup.php b/modules/Core/pages/complete_signup.php index b5d8aae265..6272dcc451 100644 --- a/modules/Core/pages/complete_signup.php +++ b/modules/Core/pages/complete_signup.php @@ -73,7 +73,7 @@ 'username' => $target_user->getDisplayname(), 'content' => $default_language->get('user', 'user_x_has_validated', ['user' => $target_user->getDisplayname()]), 'avatar_url' => $target_user->getAvatar(128, true), - 'url' => Util::getSelfURL() . ltrim($target_user->getProfileURL(), '/'), + 'url' => URL::getSelfURL() . ltrim($target_user->getProfileURL(), '/'), 'language' => $default_language ]); diff --git a/modules/Core/pages/custom.php b/modules/Core/pages/custom.php index 80c2906590..9e68944676 100644 --- a/modules/Core/pages/custom.php +++ b/modules/Core/pages/custom.php @@ -75,7 +75,7 @@ $smarty->assign([ 'WIDGETS_LEFT' => $widgets->getWidgets('left'), 'WIDGETS_RIGHT' => $widgets->getWidgets('right'), - 'CONTENT' => Util::renderEmojis( + 'CONTENT' => Text::renderEmojis( $custom_page->all_html ? Output::getDecoded($custom_page->content) : Output::getPurified($custom_page->content) diff --git a/modules/Core/pages/forgot_password.php b/modules/Core/pages/forgot_password.php index 9d4c80751c..6ba141d869 100644 --- a/modules/Core/pages/forgot_password.php +++ b/modules/Core/pages/forgot_password.php @@ -33,7 +33,7 @@ $code = SecureRandom::alphanumeric(); // Send an email - $link = rtrim(Util::getSelfURL(), '/') . URL::build('/forgot_password/', 'c=' . urlencode($code)); + $link = rtrim(URL::getSelfURL(), '/') . URL::build('/forgot_password/', 'c=' . urlencode($code)); $sent = Email::send( ['email' => Output::getClean($target_user->data()->email), 'name' => $target_user->getDisplayname()], diff --git a/modules/Core/pages/panel/api.php b/modules/Core/pages/panel/api.php index c8c372d613..46c569daca 100644 --- a/modules/Core/pages/panel/api.php +++ b/modules/Core/pages/panel/api.php @@ -233,7 +233,7 @@ 'NO' => $language->get('general', 'no'), 'CHANGE' => $language->get('general', 'change'), 'API_URL' => $language->get('admin', 'api_url'), - 'API_URL_VALUE' => rtrim(Util::getSelfURL(), '/') . rtrim(URL::build('/api/v2/', '', 'non-friendly'), '/'), + 'API_URL_VALUE' => rtrim(URL::getSelfURL(), '/') . rtrim(URL::build('/api/v2/', '', 'non-friendly'), '/'), 'ENABLE_API_FOR_URL' => $language->get('admin', 'api_disabled'), 'COPY' => $language->get('admin', 'copy'), 'USERNAME_SYNC' => $language->get('admin', 'enable_username_sync'), diff --git a/modules/Core/pages/panel/emails.php b/modules/Core/pages/panel/emails.php index f4f59788c6..e390fe7095 100644 --- a/modules/Core/pages/panel/emails.php +++ b/modules/Core/pages/panel/emails.php @@ -73,7 +73,7 @@ } else { $smarty->assign([ 'SEND_TEST_EMAIL_INFO' => $language->get('admin', 'send_test_email_info', [ - 'email' => Util::bold(Output::getClean($user->data()->email)) + 'email' => Text::bold(Output::getClean($user->data()->email)) ]), 'INFO' => $language->get('general', 'info'), 'SEND' => $language->get('admin', 'send'), diff --git a/modules/Core/pages/panel/emails_errors.php b/modules/Core/pages/panel/emails_errors.php index 68976bc2cf..8f02117a8e 100644 --- a/modules/Core/pages/panel/emails_errors.php +++ b/modules/Core/pages/panel/emails_errors.php @@ -109,7 +109,7 @@ $smarty->assign([ 'REGISTRATION_LINK' => $language->get('admin', 'registration_link'), 'SHOW_REGISTRATION_LINK' => $language->get('admin', 'show_registration_link'), - 'REGISTRATION_LINK_VALUE' => rtrim(Util::getSelfURL(), '/') . URL::build('/complete_signup/', 'c=' . urlencode($user_error->reset_code)) + 'REGISTRATION_LINK_VALUE' => rtrim(URL::getSelfURL(), '/') . URL::build('/complete_signup/', 'c=' . urlencode($user_error->reset_code)) ]); } } diff --git a/modules/Core/pages/panel/images.php b/modules/Core/pages/panel/images.php index 6acae755a4..03f9e3185a 100644 --- a/modules/Core/pages/panel/images.php +++ b/modules/Core/pages/panel/images.php @@ -201,25 +201,25 @@ if (!is_writable(ROOT_PATH . '/uploads/backgrounds')) { $smarty->assign('BACKGROUNDS_NOT_WRITABLE', $language->get('admin', 'x_directory_not_writable', [ - 'directory' => Util::bold('uploads/backgrounds') + 'directory' => Text::bold('uploads/backgrounds') ])); } if (!is_writable(ROOT_PATH . '/uploads/template_banners')) { $smarty->assign('TEMPLATE_BANNERS_DIRECTORY_NOT_WRITABLE', $language->get('admin', 'x_directory_not_writable', [ - 'directory' => Util::bold('uploads/template_banners') + 'directory' => Text::bold('uploads/template_banners') ])); } if (!is_writable(ROOT_PATH . '/uploads/logos')) { $smarty->assign('LOGOS_DIRECTORY_NOT_WRITABLE', $language->get('admin', 'x_directory_not_writable', [ - 'directory' => Util::bold('uploads/logos') + 'directory' => Text::bold('uploads/logos') ])); } if (!is_writable(ROOT_PATH . '/uploads/favicons')) { $smarty->assign('FAVICONS_DIRECTORY_NOT_WRITABLE', $language->get('admin', 'x_directory_not_writable', [ - 'directory' => Util::bold('uploads/favicons') + 'directory' => Text::bold('uploads/favicons') ])); } @@ -244,15 +244,15 @@ 'RESET_FAVICON_LINK' => URL::build('/panel/core/images/', 'action=reset_favicon'), 'BANNER_IMAGES_ARRAY' => $template_banner_images, 'BANNER_IMAGE' => $language->get('admin', 'banner_image_x', [ - 'imageName' => Util::bold($banner_img) + 'imageName' => Text::bold($banner_img) ]), 'LOGO_IMAGES_ARRAY' => $logo_images, 'LOGO_IMAGE' => $language->get('admin', 'logo_image_x', [ - 'imageName' => Util::bold($logo_img) + 'imageName' => Text::bold($logo_img) ]), 'FAVICON_IMAGES_ARRAY' => $favicon_images, 'FAVICON_IMAGE' => $language->get('admin', 'favicon_image_x', [ - 'imageName' => Util::bold($favicon_img) + 'imageName' => Text::bold($favicon_img) ]), 'ERRORS_TITLE' => $language->get('general', 'error'), 'INFO' => $language->get('general', 'info'), diff --git a/modules/Core/pages/panel/index.php b/modules/Core/pages/panel/index.php index 93d6feee22..819b6273d0 100644 --- a/modules/Core/pages/panel/index.php +++ b/modules/Core/pages/panel/index.php @@ -241,7 +241,7 @@ 'SIDE_ITEMS' => CollectionManager::getEnabledCollection('dashboard_side_items'), // TODO: show latest git commit hash? 'NAMELESS_VERSION' => $language->get('admin', 'running_nameless_version', [ - 'version' => Util::bold(NAMELESS_VERSION) + 'version' => Text::bold(NAMELESS_VERSION) ]), ]); diff --git a/modules/Core/pages/panel/minecraft_server_banners.php b/modules/Core/pages/panel/minecraft_server_banners.php index 966c6e8ac8..4464a439c6 100644 --- a/modules/Core/pages/panel/minecraft_server_banners.php +++ b/modules/Core/pages/panel/minecraft_server_banners.php @@ -65,7 +65,7 @@ 'BACK' => $language->get('general', 'back'), 'BACK_LINK' => URL::build('/panel/minecraft/banners'), 'SERVER_NAME' => Output::getClean($server->name), - 'BANNER_URL' => Util::getSelfURL() . ltrim(rtrim(URL::build('/banner/' . urlencode($server->name) . '.png'), '/'), '/'), + 'BANNER_URL' => URL::getSelfURL() . ltrim(rtrim(URL::build('/banner/' . urlencode($server->name) . '.png'), '/'), '/'), 'BANNER_PATH' => rtrim(URL::build('/banner/' . urlencode($server->name) . '.png'), '/') ]); diff --git a/modules/Core/pages/panel/modules.php b/modules/Core/pages/panel/modules.php index bce7e15513..53faa15d6a 100644 --- a/modules/Core/pages/panel/modules.php +++ b/modules/Core/pages/panel/modules.php @@ -55,8 +55,8 @@ 'author' => Output::getPurified($module->getAuthor()), 'author_x' => $language->get('admin', 'author_x', ['author' => Output::getPurified($module->getAuthor())]), 'version_mismatch' => (($module->getNamelessVersion() != NAMELESS_VERSION) ? $language->get('admin', 'module_outdated', [ - 'intendedVersion' => Util::bold(Output::getClean($module->getNamelessVersion())), - 'actualVersion' => Util::bold(NAMELESS_VERSION) + 'intendedVersion' => Text::bold(Output::getClean($module->getNamelessVersion())), + 'actualVersion' => Text::bold(NAMELESS_VERSION) ]) : false), 'disable_link' => (($module->getName() != 'Core' && $item->enabled) ? URL::build('/panel/core/modules/', 'action=disable&m=' . urlencode($item->id)) : null), 'enable_link' => (($module->getName() != 'Core' && !$item->enabled) ? URL::build('/panel/core/modules/', 'action=enable&m=' . urlencode($item->id)) : null), @@ -89,7 +89,7 @@ $all_modules[] = [ 'name' => Output::getClean($item->name), 'description' => Output::getPurified($item->description), - 'description_short' => Util::truncate(Output::getPurified($item->description)), + 'description_short' => Text::truncate(Output::getPurified($item->description)), 'author' => Output::getClean($item->author), 'author_x' => $language->get('admin', 'author_x', ['author' => Output::getClean($item->author)]), 'updated_x' => $language->get('admin', 'updated_x', ['updatedAt' => date(DATE_FORMAT, $item->updated)]), diff --git a/modules/Core/pages/panel/pages.php b/modules/Core/pages/panel/pages.php index e4a33840cf..7d42765256 100644 --- a/modules/Core/pages/panel/pages.php +++ b/modules/Core/pages/panel/pages.php @@ -479,7 +479,7 @@ 'YES' => $language->get('general', 'yes'), 'NO' => $language->get('general', 'no'), 'EDITING_PAGE' => $language->get('admin', 'editing_page_x', [ - 'page' => Util::bold(Output::getClean($page->title)) + 'page' => Text::bold(Output::getClean($page->title)) ]), 'PAGE_TITLE' => $language->get('admin', 'page_title'), 'PAGE_TITLE_VALUE' => (isset($_POST['page_title']) ? Output::getClean(Input::get('page_title')) : Output::getClean($page->title)), diff --git a/modules/Core/pages/panel/panel_templates.php b/modules/Core/pages/panel/panel_templates.php index 7a93691798..2d5a51a90c 100644 --- a/modules/Core/pages/panel/panel_templates.php +++ b/modules/Core/pages/panel/panel_templates.php @@ -90,7 +90,7 @@ $all_templates[] = [ 'name' => Output::getClean($item->name), 'description' => Output::getPurified($item->description), - 'description_short' => Util::truncate(Output::getPurified($item->description)), + 'description_short' => Text::truncate(Output::getPurified($item->description)), 'author' => Output::getClean($item->author), 'author_x' => $language->get('admin', 'author_x', ['author' => Output::getClean($item->author)]), 'updated_x' => $language->get('admin', 'updated_x', ['updatedAt' => date(DATE_FORMAT, $item->updated)]), diff --git a/modules/Core/pages/panel/registration.php b/modules/Core/pages/panel/registration.php index 3b00c448af..5b2ec1d6ef 100644 --- a/modules/Core/pages/panel/registration.php +++ b/modules/Core/pages/panel/registration.php @@ -67,7 +67,7 @@ $provider = CaptchaBase::getActiveProvider(); if ($provider->validateSecret(Input::get('recaptcha_secret')) == false || $provider->validateKey(Input::get('recaptcha')) == false) { $errors[] = $language->get('admin', 'invalid_recaptcha_settings', [ - 'recaptchaProvider' => Util::bold(Input::get('captcha_type')) + 'recaptchaProvider' => Text::bold(Input::get('captcha_type')) ]); } else { diff --git a/modules/Core/pages/panel/seo.php b/modules/Core/pages/panel/seo.php index e7468dbcc0..2c3dcfd166 100644 --- a/modules/Core/pages/panel/seo.php +++ b/modules/Core/pages/panel/seo.php @@ -41,7 +41,7 @@ if (Token::check(Input::get('token'))) { if (Input::get('type') == 'sitemap') { - $sitemap = new \SitemapPHP\Sitemap(rtrim(Util::getSelfURL(), '/')); + $sitemap = new \SitemapPHP\Sitemap(rtrim(URL::getSelfURL(), '/')); $sitemap->setPath(ROOT_PATH . '/cache/sitemaps/'); $methods = $pages->getSitemapMethods(); @@ -54,7 +54,7 @@ $method($sitemap, $cache); } - $sitemap->createSitemapIndex(rtrim(Util::getSelfURL(), '/') . (defined('CONFIG_PATH') ? CONFIG_PATH : '') . '/cache/sitemaps/'); + $sitemap->createSitemapIndex(rtrim(URL::getSelfURL(), '/') . (defined('CONFIG_PATH') ? CONFIG_PATH : '') . '/cache/sitemaps/'); $cache->setCache('sitemap_cache'); $cache->store('updated', date(DATE_FORMAT)); @@ -85,10 +85,10 @@ $smarty->assign([ 'SITEMAP_LAST_GENERATED' => $language->get('admin', 'sitemap_last_generated_x', [ - 'generatedAt' => Util::bold($updated) + 'generatedAt' => Text::bold($updated) ]), 'SITEMAP_LINK' => (defined('CONFIG_PATH') ? CONFIG_PATH : '') . '/cache/sitemaps/sitemap-index.xml', - 'SITEMAP_FULL_LINK' => rtrim(Util::getSelfURL(), '/') . (defined('CONFIG_PATH') ? CONFIG_PATH : '') . '/cache/sitemaps/sitemap-index.xml', + 'SITEMAP_FULL_LINK' => rtrim(URL::getSelfURL(), '/') . (defined('CONFIG_PATH') ? CONFIG_PATH : '') . '/cache/sitemaps/sitemap-index.xml', 'DOWNLOAD_SITEMAP' => $language->get('admin', 'download_sitemap'), 'LINK' => $language->get('admin', 'sitemap_link') ]); @@ -159,7 +159,7 @@ 'BACK' => $language->get('general', 'back'), 'BACK_LINK' => URL::build('/panel/core/seo'), 'EDITING_PAGE' => $language->get('admin', 'editing_page_x', [ - 'page' => Util::bold(Output::getClean($page['key'])) + 'page' => Text::bold(Output::getClean($page['key'])) ]), 'DESCRIPTION' => $language->get('admin', 'description'), 'DESCRIPTION_VALUE' => $description, diff --git a/modules/Core/pages/panel/templates.php b/modules/Core/pages/panel/templates.php index f784109d65..9a9a758718 100644 --- a/modules/Core/pages/panel/templates.php +++ b/modules/Core/pages/panel/templates.php @@ -58,8 +58,8 @@ 'author_x' => $language->get('admin', 'author_x', ['author' => $template->getAuthor()]), 'version_mismatch' => (($template->getNamelessVersion() != NAMELESS_VERSION) ? $language->get('admin', 'template_outdated', [ - 'intendedVersion' => Util::bold(Output::getClean($template->getNamelessVersion())), - 'actualVersion' => Util::bold(NAMELESS_VERSION) + 'intendedVersion' => Text::bold(Output::getClean($template->getNamelessVersion())), + 'actualVersion' => Text::bold(NAMELESS_VERSION) ]) : false ), @@ -100,7 +100,7 @@ $all_templates[] = [ 'name' => Output::getClean($item->name), 'description' => Output::getPurified($item->description), - 'description_short' => Util::truncate(Output::getPurified($item->description)), + 'description_short' => Text::truncate(Output::getPurified($item->description)), 'author' => Output::getClean($item->author), 'author_x' => $language->get('admin', 'author_x', ['author' => Output::getClean($item->author)]), 'updated_x' => $language->get('admin', 'updated_x', ['updatedAt' => date(DATE_FORMAT, $item->updated)]), @@ -352,7 +352,7 @@ $smarty->assign([ 'EDITING_TEMPLATE' => $language->get('admin', 'editing_template_x', [ - 'template' => Util::bold(Output::getClean($template_query->name)) + 'template' => Text::bold(Output::getClean($template_query->name)) ]), 'BACK' => $language->get('general', 'back'), 'BACK_LINK' => URL::build('/panel/core/templates'), @@ -476,7 +476,7 @@ $smarty->assign([ 'EDITING_TEMPLATE' => $language->get('admin', 'editing_template_x', [ - 'template' => Util::bold(Output::getClean($template_query->name)) + 'template' => Text::bold(Output::getClean($template_query->name)) ]), 'BACK' => $language->get('general', 'back'), 'BACK_LINK' => URL::build('/panel/core/templates'), @@ -683,8 +683,8 @@ $smarty->assign([ 'EDITING_FILE' => $language->get('admin', 'editing_template_file_in_template', [ - 'file' => Util::bold($template_path), - 'template' => Util::bold(Output::getClean($template_query->name)), + 'file' => Text::bold($template_path), + 'template' => Text::bold(Output::getClean($template_query->name)), ]), 'CANCEL' => $language->get('general', 'cancel'), 'ARE_YOU_SURE' => $language->get('general', 'are_you_sure'), @@ -703,7 +703,7 @@ $smarty->assign([ 'EDITING_TEMPLATE' => $language->get('admin', 'editing_template_x', [ - 'template' => Util::bold(Output::getClean($template_query->name)) + 'template' => Text::bold(Output::getClean($template_query->name)) ]), ]); diff --git a/modules/Core/pages/panel/users_ip_lookup.php b/modules/Core/pages/panel/users_ip_lookup.php index 6b61d38275..be7d5963d4 100644 --- a/modules/Core/pages/panel/users_ip_lookup.php +++ b/modules/Core/pages/panel/users_ip_lookup.php @@ -47,12 +47,12 @@ if (count($user_ips) == 1) { $count_accounts = $language->get('moderator', '1_ip_with_name', [ - 'user' => Util::bold(Output::getClean($user_query->username)) + 'user' => Text::bold(Output::getClean($user_query->username)) ]); } else { $count_accounts = $language->get('moderator', 'count_ips_with_name', [ 'count' => count($user_ips), - 'user' => Util::bold(Output::getClean($user_query->username)) + 'user' => Text::bold(Output::getClean($user_query->username)) ]); } diff --git a/modules/Core/pages/panel/users_oauth.php b/modules/Core/pages/panel/users_oauth.php index 86820a8246..b50717083e 100644 --- a/modules/Core/pages/panel/users_oauth.php +++ b/modules/Core/pages/panel/users_oauth.php @@ -69,7 +69,7 @@ 'TOKEN' => Token::get(), 'SUBMIT' => $language->get('general', 'submit'), 'EDITING_USER' => $language->get('admin', 'editing_user_x', [ - 'user' => Util::bold(Output::getClean($user_query->nickname)) + 'user' => Text::bold(Output::getClean($user_query->nickname)) ]), 'USER_ID' => $user_query->id, 'BACK_LINK' => URL::build('/panel/user/' . urlencode($user_query->id)), diff --git a/modules/Core/pages/panel/widgets.php b/modules/Core/pages/panel/widgets.php index 98924ee388..8e8e6d9a5a 100644 --- a/modules/Core/pages/panel/widgets.php +++ b/modules/Core/pages/panel/widgets.php @@ -199,7 +199,7 @@ $smarty->assign( [ 'EDITING_WIDGET' => $language->get('admin', 'editing_widget_x', [ - 'widget' => Util::bold(Output::getClean($widget->name)) + 'widget' => Text::bold(Output::getClean($widget->name)) ]), 'BACK' => $language->get('general', 'back'), 'BACK_LINK' => URL::build('/panel/core/widgets'), @@ -242,7 +242,7 @@ $smarty->assign( [ 'EDITING_WIDGET' => $language->get('admin', 'editing_widget_x', [ - 'widget' => Util::bold(Output::getClean($widget->name)) + 'widget' => Text::bold(Output::getClean($widget->name)) ]), 'BACK' => $language->get('general', 'back'), 'BACK_LINK' => URL::build('/panel/core/widgets/', 'action=edit&w=' . urlencode($widget->id)) diff --git a/modules/Core/pages/register.php b/modules/Core/pages/register.php index 69f4be4b30..c3470f7679 100644 --- a/modules/Core/pages/register.php +++ b/modules/Core/pages/register.php @@ -365,7 +365,7 @@ 'user' => Input::get('username'), ]), 'avatar_url' => $user->getAvatar(128, true), - 'url' => Util::getSelfURL() . ltrim(URL::build('/profile/' . urlencode(Input::get('username'))), '/'), + 'url' => URL::getSelfURL() . ltrim(URL::build('/profile/' . urlencode(Input::get('username'))), '/'), 'language' => $default_language, ]); diff --git a/modules/Core/pages/validate.php b/modules/Core/pages/validate.php index 706e68003b..846f33a54e 100644 --- a/modules/Core/pages/validate.php +++ b/modules/Core/pages/validate.php @@ -31,7 +31,7 @@ 'username' => $user->getDisplayname(), 'content' => $default_language->get('user', 'user_x_has_validated', ['user' => $user->getDisplayname()]), 'avatar_url' => $user->getAvatar(128, true), - 'url' => Util::getSelfURL() . ltrim($user->getProfileURL(), '/'), + 'url' => URL::getSelfURL() . ltrim($user->getProfileURL(), '/'), 'language' => $default_language ]); diff --git a/modules/Core/widgets/ProfilePostsWidget.php b/modules/Core/widgets/ProfilePostsWidget.php index 15144d4ec6..bf8157d659 100644 --- a/modules/Core/widgets/ProfilePostsWidget.php +++ b/modules/Core/widgets/ProfilePostsWidget.php @@ -73,7 +73,7 @@ public function initialise(): void { 'avatar' => $post_author->getAvatar(), 'username' => $post_author->getDisplayname(), 'username_style' => $post_author->getGroupStyle(), - 'content' => Util::truncate(strip_tags($post->content), 20), + 'content' => Text::truncate(strip_tags($post->content), 20), 'link' => $link . '/#post-' . $post->id, 'date_ago' => date(DATE_FORMAT, $post->time), 'user_id' => $post->author_id, diff --git a/modules/Core/widgets/ServerStatusWidget.php b/modules/Core/widgets/ServerStatusWidget.php index 013b846e4c..69daa0946d 100644 --- a/modules/Core/widgets/ServerStatusWidget.php +++ b/modules/Core/widgets/ServerStatusWidget.php @@ -46,7 +46,7 @@ public function initialise(): void { $server = $server[0]; if ($server != null) { - $server_array_request = HttpClient::get(rtrim(Util::getSelfURL(), '/') . URL::build('/queries/server/', 'id=' . $server->id)); + $server_array_request = HttpClient::get(rtrim(URL::getSelfURL(), '/') . URL::build('/queries/server/', 'id=' . $server->id)); if (!$server_array_request->hasError()) { $server_array = $server_array_request->json(true); foreach ($server_array as $key => $value) { diff --git a/modules/Forum/classes/Forum.php b/modules/Forum/classes/Forum.php index 6e2583afe5..6891687ccd 100644 --- a/modules/Forum/classes/Forum.php +++ b/modules/Forum/classes/Forum.php @@ -513,7 +513,7 @@ public function getLatestNews(int $number = 5): array { 'topic_title' => $item->topic_title, 'topic_views' => $item->topic_views, 'author' => $item->topic_creator, - 'content' => Util::truncate($post), + 'content' => Text::truncate($post), 'replies' => $posts, 'label' => count($labels) ? $labels[0] : null, 'labels' => $labels diff --git a/modules/Forum/classes/Forum_Sitemap.php b/modules/Forum/classes/Forum_Sitemap.php index 43bf6d6444..11f36c9e25 100644 --- a/modules/Forum/classes/Forum_Sitemap.php +++ b/modules/Forum/classes/Forum_Sitemap.php @@ -27,7 +27,7 @@ public static function generateSitemap(Sitemap $sitemap): void { $forums = $db->query('SELECT id, forum_title, last_post_date FROM nl2_forums WHERE id IN (SELECT forum_id FROM nl2_forums_permissions WHERE group_id = 0 AND `view` = 1)')->results(); foreach ($forums as $forum) { - $sitemap->addItem(URL::build('/forum/view/' . urlencode($forum->id) . '-' . Util::stringToURL($forum->forum_title)), 0.5, 'daily', date('Y-m-d', $forum->last_post_date)); + $sitemap->addItem(URL::build('/forum/view/' . urlencode($forum->id) . '-' . Text::urlSafe($forum->forum_title)), 0.5, 'daily', date('Y-m-d', $forum->last_post_date)); } $forums = null; @@ -35,7 +35,7 @@ public static function generateSitemap(Sitemap $sitemap): void { $topics = $db->query('SELECT id, forum_id, topic_title FROM nl2_topics WHERE deleted = 0 AND forum_id IN (SELECT forum_id FROM nl2_forums_permissions WHERE group_id = 0 AND `view` = 1)')->results(); foreach ($topics as $topic) { - $sitemap->addItem(URL::build('/forum/topic/' . urlencode($topic->id) . '-' . Util::stringToURL($topic->topic_title)), 0.5); + $sitemap->addItem(URL::build('/forum/topic/' . urlencode($topic->id) . '-' . Text::urlSafe($topic->topic_title)), 0.5); } $topics = null; diff --git a/modules/Forum/pages/forum/index.php b/modules/Forum/pages/forum/index.php index d3463eda30..5a20ad28c5 100644 --- a/modules/Forum/pages/forum/index.php +++ b/modules/Forum/pages/forum/index.php @@ -87,7 +87,7 @@ } } - if ($forums[$key]['subforums'][$subforum_id]->redirect_forum == 1 && Util::isExternalURL($forums[$key]['subforums'][$subforum_id]->redirect_url)) { + if ($forums[$key]['subforums'][$subforum_id]->redirect_forum == 1 && URL::isExternalURL($forums[$key]['subforums'][$subforum_id]->redirect_url)) { $forums[$key]['subforums'][$subforum_id]->redirect_confirm = $forum_language->get('forum', 'forum_redirect_warning', ['url' => $forums[$key]['subforums'][$subforum_id]->redirect_to]); } } diff --git a/modules/Forum/pages/forum/new_topic.php b/modules/Forum/pages/forum/new_topic.php index ed246b219f..5ba41b8a57 100644 --- a/modules/Forum/pages/forum/new_topic.php +++ b/modules/Forum/pages/forum/new_topic.php @@ -213,7 +213,7 @@ 'content_full' => strip_tags(str_ireplace(['
', '
', '
'], "\r\n", Input::get('content'))), 'avatar_url' => $user->getAvatar(128, true), 'title' => Input::get('title'), - 'url' => Util::getSelfURL() . ltrim(URL::build('/forum/topic/' . urlencode($topic_id) . '-' . $forum->titleToURL(Input::get('title'))), '/'), + 'url' => URL::getSelfURL() . ltrim(URL::build('/forum/topic/' . urlencode($topic_id) . '-' . $forum->titleToURL(Input::get('title'))), '/'), 'available_hooks' => $available_hooks == null ? [] : $available_hooks ]); diff --git a/modules/Forum/pages/forum/view_forum.php b/modules/Forum/pages/forum/view_forum.php index 0d6e380874..e8040fca3f 100644 --- a/modules/Forum/pages/forum/view_forum.php +++ b/modules/Forum/pages/forum/view_forum.php @@ -78,7 +78,7 @@ // Redirect forum? if ($forum_query->redirect_forum == 1) { - if (!Util::isExternalURL($forum_query->redirect_url)) { + if (!URL::isExternalURL($forum_query->redirect_url)) { Redirect::to(Output::getClean($forum_query->redirect_url)); } diff --git a/modules/Forum/pages/forum/view_topic.php b/modules/Forum/pages/forum/view_topic.php index e81357fb49..0382718014 100644 --- a/modules/Forum/pages/forum/view_topic.php +++ b/modules/Forum/pages/forum/view_topic.php @@ -309,7 +309,7 @@ 'content_full' => strip_tags(str_ireplace(['
', '
', '
'], "\r\n", $content)), 'avatar_url' => $user->getAvatar(128, true), 'title' => $topic->topic_title, - 'url' => Util::getSelfURL() . ltrim(URL::build('/forum/topic/' . urlencode($topic->id) . '-' . $forum->titleToURL($topic->topic_title)), '/'), + 'url' => URL::getSelfURL() . ltrim(URL::build('/forum/topic/' . urlencode($topic->id) . '-' . $forum->titleToURL($topic->topic_title)), '/'), 'topic_author_user_id' => $topic_user->data()->id, 'topic_author_username' => $topic_user->data()->username, 'topic_author_nickname' => $topic_user->data()->nickname, @@ -352,7 +352,7 @@ $language->get('emails', 'forum_topic_reply_subject', ['author' => $user->data()->username, 'topic' => $topic->topic_title]), $language->get('emails', 'greeting'), $language->get('emails', 'forum_topic_reply_message', ['author' => $user->data()->username, 'content' => html_entity_decode($content)]), - rtrim(Util::getSelfURL(), '/') . URL::build('/forum/topic/' . urlencode($tid) . '-' . $forum->titleToURL($topic->topic_title), 'pid=' . $last_post_id), + rtrim(URL::getSelfURL(), '/') . URL::build('/forum/topic/' . urlencode($tid) . '-' . $forum->titleToURL($topic->topic_title), 'pid=' . $last_post_id), $language->get('emails', 'thanks') ], $html @@ -532,9 +532,9 @@ $smarty->assign([ 'SHARE' => $forum_language->get('forum', 'share'), 'SHARE_TWITTER' => $forum_language->get('forum', 'share_twitter'), - 'SHARE_TWITTER_URL' => 'https://twitter.com/intent/tweet?text=' . urlencode(rtrim(Util::getSelfURL(), '/')) . URL::build('/forum/topic/' . urlencode($tid) . '-' . $forum->titleToURL($topic->topic_title)), + 'SHARE_TWITTER_URL' => 'https://twitter.com/intent/tweet?text=' . urlencode(rtrim(URL::getSelfURL(), '/')) . URL::build('/forum/topic/' . urlencode($tid) . '-' . $forum->titleToURL($topic->topic_title)), 'SHARE_FACEBOOK' => $forum_language->get('forum', 'share_facebook'), - 'SHARE_FACEBOOK_URL' => 'https://www.facebook.com/sharer/sharer.php?u=' . urlencode(rtrim(Util::getSelfURL(), '/')) . URL::build('/forum/topic/' . urlencode($tid) . '-' . $forum->titleToURL($topic->topic_title)) + 'SHARE_FACEBOOK_URL' => 'https://www.facebook.com/sharer/sharer.php?u=' . urlencode(rtrim(URL::getSelfURL(), '/')) . URL::build('/forum/topic/' . urlencode($tid) . '-' . $forum->titleToURL($topic->topic_title)) ]); // Pagination @@ -730,7 +730,7 @@ 'post_date' => $post_date, 'buttons' => $buttons, 'content' => $content, - 'signature' => Output::getPurified(Util::renderEmojis($signature)), + 'signature' => Output::getPurified(Text::renderEmojis($signature)), 'fields' => (empty($fields) ? [] : $fields), 'edited' => is_null($nValue->last_edited) ? null From 957121ae3a5474275500df7fb07c72f44225ca06 Mon Sep 17 00:00:00 2001 From: PadowYT2 Date: Tue, 14 Jun 2022 12:45:46 +0800 Subject: [PATCH 109/337] Patch dropdown (#2853) --- custom/templates/DefaultRevamp/css/custom.css | 158 ++++++++++-------- custom/templates/DefaultRevamp/footer.tpl | 4 +- 2 files changed, 89 insertions(+), 73 deletions(-) diff --git a/custom/templates/DefaultRevamp/css/custom.css b/custom/templates/DefaultRevamp/css/custom.css index 6ae2b3586b..bb90d020ab 100755 --- a/custom/templates/DefaultRevamp/css/custom.css +++ b/custom/templates/DefaultRevamp/css/custom.css @@ -12,8 +12,8 @@ body.pushable>.pusher { } /* - * [ NAVIGATION BAR ] - */ + * [ NAVIGATION BAR ] + */ .ui.secondary.menu { background: #fff; @@ -71,8 +71,8 @@ body.pushable>.pusher { } /* - * [ HEADER ] - */ + * [ HEADER ] + */ .ui.masthead { background: linear-gradient(90deg, rgb(41, 117, 286) 0%, rgb(2, 117, 216) 100%); @@ -109,8 +109,8 @@ body.pushable>.pusher { } /* - * -[ SEGMENT ]- - */ + * -[ SEGMENT ]- + */ .ui.segment { background: #fff; @@ -130,8 +130,8 @@ body.pushable>.pusher { } /* - * [ NEWS POST ] - */ + * [ NEWS POST ] + */ #news-post .badge, #news-post .ui.label { @@ -146,8 +146,8 @@ body.pushable>.pusher { } /* - * [ FORUM NODE ] - */ + * [ FORUM NODE ] + */ #forum-node #last-post { width: 250px; @@ -158,8 +158,8 @@ body.pushable>.pusher { } /* - * [ FORUM PAGE ] - */ + * [ FORUM PAGE ] + */ #sticky-threads tbody tr td:last-child:not(:first-child), #normal-threads tbody tr td:last-child:not(:first-child) { @@ -187,8 +187,8 @@ body.pushable>.pusher { } /* - * [ TOPIC PAGE ] - */ + * [ TOPIC PAGE ] + */ #topic-post #post-sidebar .ui.small.image, #topic-reply #reply-sidebar .ui.small.image { @@ -296,8 +296,8 @@ body.pushable>.pusher { } /* - * [ ACCOUNT MESSAGES ] - */ + * [ ACCOUNT MESSAGES ] + */ #view-message #message .header { font-size: 1.15rem; @@ -320,8 +320,8 @@ body.pushable>.pusher { } /* - * -[ 404 ERROR ]- - */ + * -[ 404 ERROR ]- + */ #error-403 .ui.container, #error-404 .ui.container, @@ -342,8 +342,8 @@ body.pushable>.pusher { } /* - * [ PROFILE PAGE ] - */ + * [ PROFILE PAGE ] + */ #profile-header { background: #fff; @@ -366,8 +366,8 @@ body.pushable>.pusher { } /* - * [ FORUM SEARCH ] - */ + * [ FORUM SEARCH ] + */ #forum-search-result h3.ui.header { margin-top: 0; @@ -375,16 +375,16 @@ body.pushable>.pusher { } /* - * [ SERVER PAGE ] - */ + * [ SERVER PAGE ] + */ [id*="server"] #server-players a:not(:last-child) { margin-right: .3rem; } /* - * [ WIDGETS ] - */ + * [ WIDGETS ] + */ [id*="widget"] .item .content { width: calc(100% - 40px) !important; @@ -437,8 +437,8 @@ body.pushable>.pusher { } /* - * -[ FOOTER ]- - */ + * -[ FOOTER ]- + */ .ui.footer.segment { margin: 1rem 0 -.5rem 0; @@ -451,9 +451,21 @@ body.pushable>.pusher { } } +.ui.link.list.list .active.item { + color: rgba(255, 255, 255, .5); +} + +.ui.link.list.list .active.item a:not(.ui) { + color: rgba(0, 0, 0, .87) !important; +} + +.ui.link.list.list .active.item a:not(.ui):hover { + background: rgba(0, 0, 0, .05) !important; +} + /* - * [ TABLE ] - */ + * [ TABLE ] + */ @media (max-width: 576px) { .ui.table.res thead tr th:first-child { @@ -480,8 +492,8 @@ body.pushable>.pusher { } /* - * -[ GRID ]- - */ + * -[ GRID ]- + */ .ui.grid+.grid { margin-top: 0.3rem; @@ -502,8 +514,8 @@ body.pushable>.pusher { } /* - * [ LINK LIST ] - */ + * [ LINK LIST ] + */ .ui.link.list.list .item a:not(.ui):hover, .ui.link.list.list a.item:hover { @@ -515,8 +527,8 @@ body.pushable>.pusher { } /* - * [ USES POPUP ] - */ + * [ USES POPUP ] + */ #user-popup .header { text-align: center; @@ -531,8 +543,8 @@ body.pushable>.pusher { } /* - * [ COOKIE NOTICE ] - */ + * [ COOKIE NOTICE ] + */ .cc-window.cc-floating { padding: 1rem 1.5rem; @@ -568,8 +580,8 @@ body.pushable>.pusher { } /* - * [ SPOILER ] - */ + * [ SPOILER ] + */ #tinymce .spoiler, .spoiler { @@ -591,16 +603,16 @@ body.pushable>.pusher { } /* - * [ MESSAGE ] - */ + * [ MESSAGE ] + */ .ui.message>.close.icon { right: .8em; } /* - * [ UPDATE MESSAGE ] - */ + * [ UPDATE MESSAGE ] + */ #update-message { margin-bottom: 1rem; @@ -632,8 +644,8 @@ body.pushable>.pusher { } /* - * [ PAGINATION ] - */ + * [ PAGINATION ] + */ .ui.mini.pagination.menu .item:first-child, .ui.mini.pagination.menu .item:last-child { @@ -641,8 +653,8 @@ body.pushable>.pusher { } /* - * -[ ALIGNMENTS ]- - */ + * -[ ALIGNMENTS ]- + */ [class*="left aligned"] { text-align: left; @@ -657,8 +669,8 @@ body.pushable>.pusher { } /* - * [ FLOATS ] - */ + * [ FLOATS ] + */ [class*="left floated"], [class*="res left floated"] { @@ -696,8 +708,8 @@ body.pushable>.pusher { } /* - * [ DISPLAY ] - */ + * [ DISPLAY ] + */ [display="block"] { display: block !important; @@ -712,8 +724,8 @@ body.pushable>.pusher { } /* - * [ VISIBILITY ] - */ + * [ VISIBILITY ] + */ @media only screen and (max-width: 576px) { @@ -776,8 +788,8 @@ body.pushable>.pusher { } /* - * [ USER BADGES ] - */ + * [ USER BADGES ] + */ .badge { display: inline-block; @@ -895,8 +907,8 @@ a.badge-dark:focus { } /* - * [ OTHER ] - */ + * [ OTHER ] + */ select { font-family: Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif; @@ -959,8 +971,8 @@ select { } /* - * [ DARK MODE ] - */ + * [ DARK MODE ] + */ body.dark, body.dark>.pusher, @@ -1019,11 +1031,6 @@ body.dark .ui.dropdown .menu { color: rgba(255, 255, 255, 0.6); } -body.dark .ui.menu .dropdown.item .menu, -body.dark .ui.dropdown .menu { - min-width: calc(100% - 1px); -} - body.dark .ui.button, body.dark .ui.default.button, body.dark .ui.mini.icon.button, @@ -1134,8 +1141,15 @@ body.dark .ui.comments .comment .actions a, body.dark .ui.card>.extra a:not(.ui), body.dark .ui.cards>.card>.extra a:not(.ui), body.dark .ui.relaxed.list .item .content, -body.dark .ui.horizontal.divider { - color: rgba(255, 255, 255, 0.6); +body.dark .ui.horizontal.divider, +body.dark .ui.dropdown .menu>.header:not(.ui), +body.dark .ui.link.list.list .active.item, +body.dark .ui.link.list.list .active.item a:not(.ui) { + color: rgba(255, 255, 255, 0.6) !important; +} + +body.dark .ui.menu .ui.dropdown .menu>.item:hover { + background-color: rgba(0, 0, 0, .05) !important; } body.dark .ui.secondary.inverted.menu .popup .list a.item, @@ -1144,8 +1158,10 @@ body.dark .ui.pointing.dropdown>.menu>.item { } body.dark .ui.menu .ui.dropdown .menu>.item:hover, +body.dark .ui.dropdown .menu>.item:hover, body.dark .ui.menu .ui.dropdown .menu>.item.active, -body.dark .ui.list>.item a.header { +body.dark .ui.list>.item a.header, +body.dark .ui.link.list.list .active.item a:not(.ui):hover { color: #fff !important; } @@ -1350,9 +1366,9 @@ body.dark .cc-window.cc-floating .cc-highlight .cc-btn.cc-allow { } /* - * Colours - */ + * Colours + */ body.dark .white { color: #fff; -} +} \ No newline at end of file diff --git a/custom/templates/DefaultRevamp/footer.tpl b/custom/templates/DefaultRevamp/footer.tpl index e0658526a5..1db808052e 100755 --- a/custom/templates/DefaultRevamp/footer.tpl +++ b/custom/templates/DefaultRevamp/footer.tpl @@ -23,8 +23,8 @@ + {/if}