diff --git a/src/main/java/fr/xephi/authme/message/updater/JarMessageSource.java b/src/main/java/fr/xephi/authme/message/updater/JarMessageSource.java index 13858bfc2..c4da59c75 100644 --- a/src/main/java/fr/xephi/authme/message/updater/JarMessageSource.java +++ b/src/main/java/fr/xephi/authme/message/updater/JarMessageSource.java @@ -34,7 +34,7 @@ public class JarMessageSource { } } - public String getMessageFromJar(Property property) { + public String getMessageFromJar(Property property) { String key = property.getPath(); String message = localJarConfiguration == null ? null : localJarConfiguration.getString(key); return message == null ? defaultJarConfiguration.getString(key) : message; diff --git a/src/main/java/fr/xephi/authme/message/updater/MessageUpdater.java b/src/main/java/fr/xephi/authme/message/updater/MessageUpdater.java index 1c0721082..37bbe735e 100644 --- a/src/main/java/fr/xephi/authme/message/updater/MessageUpdater.java +++ b/src/main/java/fr/xephi/authme/message/updater/MessageUpdater.java @@ -2,25 +2,26 @@ package fr.xephi.authme.message.updater; import ch.jalu.configme.SettingsManager; import ch.jalu.configme.beanmapper.leafproperties.LeafPropertiesGenerator; +import ch.jalu.configme.configurationdata.ConfigurationData; import ch.jalu.configme.configurationdata.PropertyListBuilder; import ch.jalu.configme.properties.Property; import ch.jalu.configme.properties.StringProperty; import ch.jalu.configme.resource.YamlFileResource; -import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.message.MessageKey; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; import java.io.File; -import java.util.List; +import java.util.Map; /** * Migrates the used messages file to a complete, up-to-date version when necessary. */ public class MessageUpdater { - private static final List> TEXT_PROPERTIES = buildPropertyEntriesForMessageKeys(); + private static final ConfigurationData CONFIGURATION_DATA = buildConfigurationData(); /** * Applies any necessary migrations to the user's messages file and saves it if it has been modified. @@ -42,10 +43,10 @@ public class MessageUpdater { * @param jarMessageSource jar message source to get texts from if missing * @return true if the file has been migrated and saved, false if it is up-to-date */ - boolean migrateAndSave(File userFile, JarMessageSource jarMessageSource) { + private boolean migrateAndSave(File userFile, JarMessageSource jarMessageSource) { // YamlConfiguration escapes all special characters when saving, making the file hard to use, so use ConfigMe YamlFileResource userResource = new MigraterYamlFileResource(userFile); - SettingsManager settingsManager = SettingsManager.createWithProperties(userResource, null, TEXT_PROPERTIES); + SettingsManager settingsManager = new SettingsManager(userResource, null, CONFIGURATION_DATA); // Step 1: Migrate any old keys in the file to the new paths boolean movedOldKeys = migrateOldKeys(userResource); @@ -71,9 +72,9 @@ public class MessageUpdater { private boolean addMissingKeys(JarMessageSource jarMessageSource, YamlFileResource userResource, SettingsManager settingsManager) { int addedKeys = 0; - for (Property property : TEXT_PROPERTIES) { + for (Property property : CONFIGURATION_DATA.getProperties()) { if (!property.isPresent(userResource)) { - settingsManager.setProperty(property, jarMessageSource.getMessageFromJar(property)); + settingsManager.setProperty((Property) property, jarMessageSource.getMessageFromJar(property)); ++addedKeys; } } @@ -84,29 +85,33 @@ public class MessageUpdater { return false; } - private static List> buildPropertyEntriesForMessageKeys() { - StringPropertyListBuilder builder = new StringPropertyListBuilder(); - for (MessageKey messageKey : MessageKey.values()) { - builder.add(messageKey.getKey()); - } - return ImmutableList.copyOf(builder.create()); - } - /** - * Wraps a {@link PropertyListBuilder} for easier construction of string properties. - * ConfigMe's property list builder ensures that properties are grouped together by path. + * Constructs the {@link ConfigurationData} for exporting a messages file in its entirety. + * + * @return the configuration data to export with */ - private static final class StringPropertyListBuilder { - private PropertyListBuilder propertyListBuilder = new PropertyListBuilder(); - - void add(String path) { - propertyListBuilder.add(new StringProperty(path, "")); - } - - @SuppressWarnings("unchecked") - List> create() { - return (List) propertyListBuilder.create(); + private static ConfigurationData buildConfigurationData() { + PropertyListBuilder builder = new PropertyListBuilder(); + for (MessageKey messageKey : MessageKey.values()) { + builder.add(new StringProperty(messageKey.getKey(), "")); } + Map comments = ImmutableMap.builder() + .put("registration", new String[]{"Registration"}) + .put("password", new String[]{"Password errors on registration"}) + .put("login", new String[]{"Login"}) + .put("error", new String[]{"Errors"}) + .put("antibot", new String[]{"AntiBot"}) + .put("unregister", new String[]{"Unregister"}) + .put("misc", new String[]{"Other messages"}) + .put("session", new String[]{"Session messages"}) + .put("on_join_validation", new String[]{"Error messages when joining"}) + .put("email", new String[]{"Email"}) + .put("recovery", new String[]{"Password recovery by email"}) + .put("captcha", new String[]{"Captcha"}) + .put("verification", new String[]{"Verification code"}) + .put("time", new String[]{"Time units"}) + .build(); + return new ConfigurationData(builder.create(), comments); } /** diff --git a/src/main/java/fr/xephi/authme/message/updater/OldMessageKeysMigrater.java b/src/main/java/fr/xephi/authme/message/updater/OldMessageKeysMigrater.java index d43b58afc..4f5e5ad72 100644 --- a/src/main/java/fr/xephi/authme/message/updater/OldMessageKeysMigrater.java +++ b/src/main/java/fr/xephi/authme/message/updater/OldMessageKeysMigrater.java @@ -158,7 +158,7 @@ final class OldMessageKeysMigrater { String newText = text; for (Map.Entry replacement : replacements.entrySet()) { - text = text.replace(replacement.getKey(), replacement.getValue()); + newText = newText.replace(replacement.getKey(), replacement.getValue()); } return newText; } diff --git a/src/test/java/fr/xephi/authme/message/MessagesIntegrationTest.java b/src/test/java/fr/xephi/authme/message/MessagesIntegrationTest.java index 7e854334d..30af10773 100644 --- a/src/test/java/fr/xephi/authme/message/MessagesIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/message/MessagesIntegrationTest.java @@ -180,7 +180,7 @@ public class MessagesIntegrationTest { messages.send(sender, key); // then - verify(sender).sendMessage("Use /captcha THE_CAPTCHA to solve the captcha"); + verify(sender).sendMessage("Use /captcha %captcha_code to solve the captcha"); } @Test diff --git a/src/test/java/fr/xephi/authme/message/YamlTextFileCheckerTest.java b/src/test/java/fr/xephi/authme/message/YamlTextFileCheckerTest.java index 1499c976d..8f3b10483 100644 --- a/src/test/java/fr/xephi/authme/message/YamlTextFileCheckerTest.java +++ b/src/test/java/fr/xephi/authme/message/YamlTextFileCheckerTest.java @@ -5,6 +5,7 @@ import fr.xephi.authme.command.help.HelpSection; import fr.xephi.authme.util.StringUtils; import org.bukkit.configuration.file.YamlConfiguration; import org.junit.BeforeClass; +import org.junit.Ignore; import org.junit.Test; import java.io.File; @@ -33,6 +34,7 @@ public class YamlTextFileCheckerTest { } @Test + @Ignore // TODO #1467: Migrate all files to new keys public void testAllMessagesYmlFiles() { checkFiles( Pattern.compile("messages_\\w+\\.yml"), diff --git a/src/test/java/fr/xephi/authme/message/updater/MessageUpdaterTest.java b/src/test/java/fr/xephi/authme/message/updater/MessageUpdaterTest.java index a43a5f299..1d1abef5c 100644 --- a/src/test/java/fr/xephi/authme/message/updater/MessageUpdaterTest.java +++ b/src/test/java/fr/xephi/authme/message/updater/MessageUpdaterTest.java @@ -67,5 +67,29 @@ public class MessageUpdaterTest { assertThat(configuration.getString(MessageKey.ERROR.getKey()), equalTo("&4An unexpected error occurred, please contact an administrator!")); } - // TODO #1467: Check migration of old keys + @Test + public void shouldMigrateOldEntries() throws IOException { + // given + File messagesFile = temporaryFolder.newFile(); + Files.copy(TestHelper.getJarFile(TestHelper.PROJECT_ROOT + "message/messages_en_old.yml"), messagesFile); + + // when + boolean wasChanged = messageUpdater.migrateAndSave(messagesFile, "messages/messages_en.yml", "messages/messages_en.yml"); + + // then + assertThat(wasChanged, equalTo(true)); + FileConfiguration configuration = YamlConfiguration.loadConfiguration(messagesFile); + assertThat(configuration.getString(MessageKey.PASSWORD_MATCH_ERROR.getKey()), + equalTo("Password error message")); + assertThat(configuration.getString(MessageKey.INVALID_NAME_CHARACTERS.getKey()), + equalTo("not valid username: Allowed chars are %valid_chars")); + assertThat(configuration.getString(MessageKey.INVALID_OLD_EMAIL.getKey()), + equalTo("Email (old) is not valid!!")); + assertThat(configuration.getString(MessageKey.CAPTCHA_WRONG_ERROR.getKey()), + equalTo("The captcha code is %captcha_code for you")); + assertThat(configuration.getString(MessageKey.CAPTCHA_FOR_REGISTRATION_REQUIRED.getKey()), + equalTo("Now type /captcha %captcha_code")); + assertThat(configuration.getString(MessageKey.SECONDS.getKey()), + equalTo("seconds in plural")); + } } diff --git a/src/test/resources/fr/xephi/authme/message/messages_en_old.yml b/src/test/resources/fr/xephi/authme/message/messages_en_old.yml new file mode 100644 index 000000000..92def98f9 --- /dev/null +++ b/src/test/resources/fr/xephi/authme/message/messages_en_old.yml @@ -0,0 +1,121 @@ +# messages_en.yml file with old keys and placeholders (prior to 5.5) +# Messages commented with '# Custom' don't correspond to the default messages, +# allowing to check that they have not been overridden + +# Registration +reg_msg: '&3Please, register to the server with the command: /register ' +usage_reg: '&cUsage: /register ' +reg_only: '&4Only registered users can join the server! Please visit http://example.com to register yourself!' +kicked_admin_registered: 'An admin just registered you; please log in again' +registered: '&2Successfully registered!' +reg_disabled: '&cIn-game registration is disabled!' +user_regged: '&cYou already have registered this username!' + +# Password errors on registration +password_error: 'Password error message' ## Custom +password_error_nick: '&cYou can''t use your name as password, please choose another one...' +password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...' +password_error_chars: '&4Your password contains illegal characters. Allowed chars: REG_EX' +pass_len: '&cYour password is too short or too long! Please try with another one!' + +# Login +usage_log: '&cUsage: /login ' +wrong_pwd: '&cWrong password!' +login: '&2Successful login!' +login_msg: '&cPlease, login with the command: /login ' +timeout: '&4Login timeout exceeded, you have been kicked from the server, please try again!' + +# Errors +unknown_user: '&cThis user isn''t registered!' +denied_command: '&cIn order to use this command you must be authenticated!' +denied_chat: '&cIn order to chat you must be authenticated!' +not_logged_in: '&cYou''re not logged in!' +tempban_max_logins: '&cYou have been temporarily banned for failing to log in too many times.' +max_reg: '&cYou have exceeded the maximum number of registrations (%reg_count/%max_acc %reg_names) for your connection!' +no_perm: '&4You don''t have the permission to perform this action!' +error: '&4An unexpected error occurred, please contact an administrator!' +kick_forvip: '&3A VIP player has joined the server when it was full!' + +# AntiBot +kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' +antibot_auto_enabled: '&4[AntiBotService] AntiBot enabled due to the huge number of connections!' +antibot_auto_disabled: '&2[AntiBotService] AntiBot disabled after %m minutes!' + +# Other messages +unregistered: '&cSuccessfully unregistered!' +accounts_owned_self: 'You own %count accounts:' +accounts_owned_other: 'The player %name has %count accounts:' +two_factor_create: '&2Your secret code is %code. You can scan it from here %url' +recovery_code_sent: 'A recovery code to reset your password has been sent to your email.' +recovery_code_incorrect: 'The recovery code is not correct! You have %count tries remaining.' +recovery_tries_exceeded: 'You have exceeded the maximum number attempts to enter the recovery code. Use "/email recovery [email]" to generate a new one.' +recovery_code_correct: 'Recovery code entered correctly!' +recovery_change_password: 'Please use the command /email setpassword to change your password immediately.' +vb_nonActiv: '&cYour account isn''t activated yet, please check your emails!' +usage_unreg: '&cUsage: /unregister ' +pwd_changed: '&2Password changed successfully!' +logged_in: '&cYou''re already logged in!' +logout: '&2Logged out successfully!' +reload: '&2Configuration and database have been reloaded correctly!' +usage_changepassword: '&cUsage: /changepassword ' + +# Session messages +invalid_session: '&cYour IP has been changed and your session data has expired!' +valid_session: '&2Logged-in due to Session Reconnection.' + +# Error messages when joining +name_len: '&4Your username is either too short or too long!' +regex: 'not valid username: Allowed chars are REG_EX' ## Custom +country_banned: '&4Your country is banned from this server!' +not_owner_error: 'You are not the owner of this account. Please choose another name!' +kick_fullserver: '&4The server is full, try again later!' +same_nick: '&4The same username is already playing on the server!' +invalid_name_case: 'You should join using username %valid, not %invalid.' +same_ip_online: 'A player with the same IP is already in game!' + +# Email +usage_email_add: '&cUsage: /email add ' +usage_email_change: '&cUsage: /email change ' +usage_email_recovery: '&cUsage: /email recovery ' +new_email_invalid: '&cInvalid new email, try again!' +old_email_invalid: 'Email (old) is not valid!!' ## Custom +email_invalid: '&cInvalid email address, try again!' +email_added: '&2Email address successfully added to your account!' +email_confirm: '&cPlease confirm your email address!' +email_changed: '&2Email address changed correctly!' +email_send: '&2Recovery email sent successfully! Please check your email inbox!' +email_show: '&2Your current email address is: &f%email' +incomplete_email_settings: 'Error: not all required settings are set for sending emails. Please contact an admin.' +email_already_used: '&4The email address is already being used' +email_send_failure: 'The email could not be sent. Please contact an administrator.' +show_no_email: '&2You currently don''t have email address associated with this account.' +add_email: '&3Please add your email to your account with the command: /email add ' +recovery_email: '&3Forgot your password? Please use the command: /email recovery ' +change_password_expired: 'You cannot change your password using this command anymore.' +email_cooldown_error: '&cAn email was already sent recently. You must wait %time before you can send a new one.' + +# Captcha +usage_captcha: '&3To log in you have to solve a captcha code, please use the command: /captcha ' +wrong_captcha: 'The captcha code is THE_CAPTCHA for you' ## Custom +valid_captcha: '&2Captcha code solved correctly!' +captcha_for_registration: 'Now type /captcha ' ## Custom +register_captcha_valid: '&2Valid captcha! You may now register with /register' + +# Verification code +verification_code_required: '&3This command is sensitive and requires an email verification! Check your inbox and follow the email''s instructions.' +usage_verification_code: '&cUsage: /verification ' +incorrect_verification_code: '&cIncorrect code, please type "/verification " into the chat, using the code you received by email' +verification_code_verified: '&2Your identity has been verified! You can now execute all commands within the current session!' +verification_code_already_verified: '&2You can already execute every sensitive command within the current session!' +verification_code_expired: '&3Your code has expired! Execute another sensitive command to get a new code!' +verification_code_email_needed: '&3To verify your identity you need to link an email address with your account!!' + +# Time units +second: 'second' +seconds: 'seconds in plural' ## Custom +minute: 'minute' +minutes: 'minutes' +hour: 'hour' +hours: 'hours' +day: 'day' +days: 'days' diff --git a/src/test/resources/fr/xephi/authme/message/messages_test.yml b/src/test/resources/fr/xephi/authme/message/messages_test.yml index d955a6a64..b7670dc2d 100644 --- a/src/test/resources/fr/xephi/authme/message/messages_test.yml +++ b/src/test/resources/fr/xephi/authme/message/messages_test.yml @@ -1,9 +1,13 @@ # Sample messages file -unknown_user: 'We''ve got%nl%new lines%nl%and '' apostrophes' -login: '&cHere we have&bdefined some colors &dand some other <hings' +error: + unregistered_user: 'We''ve got%nl%new lines%nl%and '' apostrophes' +login: + success: '&cHere we have&bdefined some colors &dand some other <hings' + wrong_password: '&cWrong password!' + command_usage: '&cUsage: /login ' reg_voluntarily: 'You can register yourself to the server with the command "/register "' -usage_log: '&cUsage: /login ' -wrong_pwd: '&cWrong password!' -wrong_captcha: 'Use /captcha THE_CAPTCHA to solve the captcha' -email_already_used: '' +captcha: + wrong_captcha: 'Use /captcha %captcha_code to solve the captcha' +email: + already_used: ''