From 755f3df33e4c72681cb4ff5315955d9a63a6d2ca Mon Sep 17 00:00:00 2001 From: ljacqu Date: Mon, 10 Oct 2016 22:36:14 +0200 Subject: [PATCH 01/25] #768 Create command for updating messages file --- .../authme/command/CommandInitializer.java | 10 ++ .../executable/authme/MessagesCommand.java | 48 ++++++++ .../xephi/authme/service/MessageUpdater.java | 108 ++++++++++++++++++ .../java/fr/xephi/authme/util/FileUtils.java | 18 ++- .../fr/xephi/authme/util/FileUtilsTest.java | 9 ++ 5 files changed, 189 insertions(+), 4 deletions(-) create mode 100644 src/main/java/fr/xephi/authme/command/executable/authme/MessagesCommand.java create mode 100644 src/main/java/fr/xephi/authme/service/MessageUpdater.java diff --git a/src/main/java/fr/xephi/authme/command/CommandInitializer.java b/src/main/java/fr/xephi/authme/command/CommandInitializer.java index edbbdb201..598f8d3a6 100644 --- a/src/main/java/fr/xephi/authme/command/CommandInitializer.java +++ b/src/main/java/fr/xephi/authme/command/CommandInitializer.java @@ -11,6 +11,7 @@ import fr.xephi.authme.command.executable.authme.ForceLoginCommand; import fr.xephi.authme.command.executable.authme.GetEmailCommand; import fr.xephi.authme.command.executable.authme.GetIpCommand; import fr.xephi.authme.command.executable.authme.LastLoginCommand; +import fr.xephi.authme.command.executable.authme.MessagesCommand; import fr.xephi.authme.command.executable.authme.PurgeBannedPlayersCommand; import fr.xephi.authme.command.executable.authme.PurgeCommand; import fr.xephi.authme.command.executable.authme.PurgeLastPositionCommand; @@ -288,6 +289,15 @@ public class CommandInitializer { .executableCommand(ConverterCommand.class) .build(); + CommandDescription.builder() + .parent(AUTHME_BASE) + .labels("messages") + .description("Add missing messages") + .detailedDescription("Adds missing messages to the current messages file.") + // TODO #768: add permission for command + .executableCommand(MessagesCommand.class) + .build(); + // Register the base login command final CommandDescription LOGIN_BASE = CommandDescription.builder() .parent(null) diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/MessagesCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/MessagesCommand.java new file mode 100644 index 000000000..25e0bf5bb --- /dev/null +++ b/src/main/java/fr/xephi/authme/command/executable/authme/MessagesCommand.java @@ -0,0 +1,48 @@ +package fr.xephi.authme.command.executable.authme; + +import fr.xephi.authme.ConsoleLogger; +import fr.xephi.authme.command.ExecutableCommand; +import fr.xephi.authme.initialization.DataFolder; +import fr.xephi.authme.service.MessageUpdater; +import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.settings.properties.PluginSettings; +import org.bukkit.command.CommandSender; + +import javax.inject.Inject; +import java.io.File; +import java.util.List; + +/** + * Messages command, updates the user's messages file with any missing files + * from the provided file in the JAR. + */ +public class MessagesCommand implements ExecutableCommand { + + private static final String DEFAULT_LANGUAGE = "en"; + + @Inject + private Settings settings; + @Inject + @DataFolder + private File dataFolder; + + @Override + public void executeCommand(CommandSender sender, List arguments) { + final String language = settings.getProperty(PluginSettings.MESSAGES_LANGUAGE); + + try { + new MessageUpdater( + new File(dataFolder, getMessagePath(language)), + getMessagePath(language), + getMessagePath(DEFAULT_LANGUAGE)) + .executeCopy(sender); + } catch (Exception e) { + sender.sendMessage("Could not update messages: " + e.getMessage()); + ConsoleLogger.logException("Could not update messages:", e); + } + } + + private static String getMessagePath(String code) { + return "messages/messages_" + code + ".yml"; + } +} diff --git a/src/main/java/fr/xephi/authme/service/MessageUpdater.java b/src/main/java/fr/xephi/authme/service/MessageUpdater.java new file mode 100644 index 000000000..a94922e8b --- /dev/null +++ b/src/main/java/fr/xephi/authme/service/MessageUpdater.java @@ -0,0 +1,108 @@ +package fr.xephi.authme.service; + +import fr.xephi.authme.ConsoleLogger; +import fr.xephi.authme.message.MessageKey; +import fr.xephi.authme.util.FileUtils; +import fr.xephi.authme.util.StringUtils; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +/** + * Updates a user's messages file with messages from the JAR files. + */ +public class MessageUpdater { + + private final File userFile; + private final FileConfiguration userConfiguration; + private final FileConfiguration localJarConfiguration; + private final FileConfiguration defaultJarConfiguration; + private boolean hasMissingMessages = false; + + public MessageUpdater(File userFile, String jarFile, String jarDefaultsFile) throws Exception { + if (!userFile.exists()) { + throw new Exception("Local messages file does not exist"); + } + this.userFile = userFile; + this.userConfiguration = YamlConfiguration.loadConfiguration(userFile); + + localJarConfiguration = loadJarFileOrSendError(jarFile); + defaultJarConfiguration = jarFile.equals(jarDefaultsFile) + ? null + : loadJarFileOrSendError(jarDefaultsFile); + if (localJarConfiguration == null && defaultJarConfiguration == null) { + throw new Exception("Could not load any JAR messages file to copy from"); + } + } + + public void executeCopy(CommandSender sender) { + copyMissingMessages(); + + if (!hasMissingMessages) { + sender.sendMessage("No new messages to add"); + return; + } + + // Save user configuration file + try { + userConfiguration.save(userFile); + sender.sendMessage("Message file updated with new messages"); + } catch (IOException e) { + sender.sendMessage("Could not save to messages file"); + ConsoleLogger.logException("Could not save new messages to file:", e); + } + } + + private void copyMissingMessages() { + for (MessageKey entry : MessageKey.values()) { + final String key = entry.getKey(); + if (!userConfiguration.contains(key)) { + String jarMessage = getMessageFromJar(key); + if (jarMessage != null) { + hasMissingMessages = true; + userConfiguration.set(key, jarMessage); + } + } + } + } + + private String getMessageFromJar(String key) { + String message = (localJarConfiguration == null ? null : localJarConfiguration.getString(key)); + if (message != null) { + return message; + } + return (defaultJarConfiguration == null ? null : defaultJarConfiguration.getString(key)); + } + + private static FileConfiguration loadJarFileOrSendError(String jarPath) { + try (InputStream stream = FileUtils.getResourceFromJar(jarPath)) { + if (stream == null) { + ConsoleLogger.info("Could not load '" + jarPath + "' from JAR"); + return null; + } + InputStreamReader isr = new InputStreamReader(stream); + FileConfiguration configuration = YamlConfiguration.loadConfiguration(isr); + close(isr); + return configuration; + } catch (IOException e) { + ConsoleLogger.logException("Exception while handling JAR path '" + jarPath + "'", e); + } + return null; + } + + private static void close(Closeable closeable) { + if (closeable != null) { + try { + closeable.close(); + } catch (IOException e) { + ConsoleLogger.info("Cannot close '" + closeable + "': " + StringUtils.formatException(e)); + } + } + } +} diff --git a/src/main/java/fr/xephi/authme/util/FileUtils.java b/src/main/java/fr/xephi/authme/util/FileUtils.java index 831beafd6..86c8cae46 100644 --- a/src/main/java/fr/xephi/authme/util/FileUtils.java +++ b/src/main/java/fr/xephi/authme/util/FileUtils.java @@ -23,7 +23,7 @@ public final class FileUtils { * Copy a resource file (from the JAR) to the given file if it doesn't exist. * * @param destinationFile The file to check and copy to (outside of JAR) - * @param resourcePath Absolute path to the resource file (path to file within JAR) + * @param resourcePath Local path to the resource file (path to file within JAR) * * @return False if the file does not exist and could not be copied, true otherwise */ @@ -35,9 +35,7 @@ public final class FileUtils { return false; } - // ClassLoader#getResourceAsStream does not deal with the '\' path separator: replace to '/' - final String normalizedPath = resourcePath.replace("\\", "/"); - try (InputStream is = AuthMe.class.getClassLoader().getResourceAsStream(normalizedPath)) { + try (InputStream is = getResourceFromJar(resourcePath)) { if (is == null) { ConsoleLogger.warning(format("Cannot copy resource '%s' to file '%s': cannot load resource", resourcePath, destinationFile.getPath())); @@ -52,6 +50,18 @@ public final class FileUtils { return false; } + /** + * Returns a JAR file as stream. Returns null if it doesn't exist. + * + * @param path the local path (starting from resources project, e.g. "config.yml" for 'resources/config.yml') + * @return the stream if the file exists, or false otherwise + */ + public static InputStream getResourceFromJar(String path) { + // ClassLoader#getResourceAsStream does not deal with the '\' path separator: replace to '/' + final String normalizedPath = path.replace("\\", "/"); + return AuthMe.class.getClassLoader().getResourceAsStream(normalizedPath); + } + /** * Delete a given directory and all its content. * diff --git a/src/test/java/fr/xephi/authme/util/FileUtilsTest.java b/src/test/java/fr/xephi/authme/util/FileUtilsTest.java index f36acf755..e7a8d8731 100644 --- a/src/test/java/fr/xephi/authme/util/FileUtilsTest.java +++ b/src/test/java/fr/xephi/authme/util/FileUtilsTest.java @@ -11,6 +11,8 @@ import java.io.File; import java.io.IOException; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertThat; /** @@ -119,6 +121,13 @@ public class FileUtilsTest { // Nothing happens } + @Test + public void shouldGetResourceFromJar() { + // given / when / then + assertThat(FileUtils.getResourceFromJar("config.yml"), not(nullValue())); + assertThat(FileUtils.getResourceFromJar("does-not-exist"), nullValue()); + } + @Test public void shouldConstructPath() { // given/when From 264431c214a205b9176926209605309accce667e Mon Sep 17 00:00:00 2001 From: ljacqu Date: Wed, 12 Oct 2016 22:27:34 +0200 Subject: [PATCH 02/25] #768 Use ConfigMe to set and export messages - Bukkit's FileConfiguration escapes all special characters making the resulting file hard to use --- .../executable/authme/MessagesCommand.java | 8 +- .../xephi/authme/service/MessageUpdater.java | 78 +++++++++++++------ 2 files changed, 62 insertions(+), 24 deletions(-) diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/MessagesCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/MessagesCommand.java index 25e0bf5bb..a7d38d5ac 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/MessagesCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/MessagesCommand.java @@ -3,6 +3,7 @@ package fr.xephi.authme.command.executable.authme; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.initialization.DataFolder; +import fr.xephi.authme.message.Messages; import fr.xephi.authme.service.MessageUpdater; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.properties.PluginSettings; @@ -25,17 +26,22 @@ public class MessagesCommand implements ExecutableCommand { @Inject @DataFolder private File dataFolder; + @Inject + private Messages messages; @Override public void executeCommand(CommandSender sender, List arguments) { final String language = settings.getProperty(PluginSettings.MESSAGES_LANGUAGE); try { - new MessageUpdater( + boolean isFileUpdated = new MessageUpdater( new File(dataFolder, getMessagePath(language)), getMessagePath(language), getMessagePath(DEFAULT_LANGUAGE)) .executeCopy(sender); + if (isFileUpdated) { + messages.reload(); + } } catch (Exception e) { sender.sendMessage("Could not update messages: " + e.getMessage()); ConsoleLogger.logException("Could not update messages:", e); diff --git a/src/main/java/fr/xephi/authme/service/MessageUpdater.java b/src/main/java/fr/xephi/authme/service/MessageUpdater.java index a94922e8b..3bdedef9d 100644 --- a/src/main/java/fr/xephi/authme/service/MessageUpdater.java +++ b/src/main/java/fr/xephi/authme/service/MessageUpdater.java @@ -1,5 +1,10 @@ package fr.xephi.authme.service; +import com.github.authme.configme.SettingsManager; +import com.github.authme.configme.knownproperties.PropertyEntry; +import com.github.authme.configme.properties.Property; +import com.github.authme.configme.properties.StringProperty; +import com.github.authme.configme.resource.YamlFileResource; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.util.FileUtils; @@ -13,62 +18,82 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; /** * Updates a user's messages file with messages from the JAR files. */ public class MessageUpdater { - private final File userFile; private final FileConfiguration userConfiguration; private final FileConfiguration localJarConfiguration; private final FileConfiguration defaultJarConfiguration; + + private final List properties; + private final SettingsManager settingsManager; private boolean hasMissingMessages = false; - public MessageUpdater(File userFile, String jarFile, String jarDefaultsFile) throws Exception { + /** + * Constructor. + * + * @param userFile messages file in the data folder + * @param localJarFile path to messages file in JAR in local language + * @param defaultJarFile path to messages file in JAR for default language + * @throws Exception if userFile does not exist or no JAR messages file can be loaded + */ + public MessageUpdater(File userFile, String localJarFile, String defaultJarFile) throws Exception { if (!userFile.exists()) { throw new Exception("Local messages file does not exist"); } - this.userFile = userFile; - this.userConfiguration = YamlConfiguration.loadConfiguration(userFile); - localJarConfiguration = loadJarFileOrSendError(jarFile); - defaultJarConfiguration = jarFile.equals(jarDefaultsFile) - ? null - : loadJarFileOrSendError(jarDefaultsFile); + userConfiguration = YamlConfiguration.loadConfiguration(userFile); + localJarConfiguration = loadJarFileOrSendError(localJarFile); + defaultJarConfiguration = localJarFile.equals(defaultJarFile) ? null : loadJarFileOrSendError(defaultJarFile); if (localJarConfiguration == null && defaultJarConfiguration == null) { throw new Exception("Could not load any JAR messages file to copy from"); } + + properties = buildPropertyEntriesForMessageKeys(); + settingsManager = new SettingsManager(new YamlFileResource(userFile), (r, p) -> true, properties); } - public void executeCopy(CommandSender sender) { + /** + * Copies missing messages to the messages file. + * + * @param sender sender starting the copy process + * @return true if the messages file was updated, false otherwise + * @throws Exception if an error occurs during saving + */ + public boolean executeCopy(CommandSender sender) throws Exception { copyMissingMessages(); if (!hasMissingMessages) { sender.sendMessage("No new messages to add"); - return; + return false; } // Save user configuration file try { - userConfiguration.save(userFile); + settingsManager.save(); sender.sendMessage("Message file updated with new messages"); - } catch (IOException e) { - sender.sendMessage("Could not save to messages file"); - ConsoleLogger.logException("Could not save new messages to file:", e); + return true; + } catch (Exception e) { + throw new Exception("Could not save to messages file: " + StringUtils.formatException(e)); } } + @SuppressWarnings("unchecked") private void copyMissingMessages() { - for (MessageKey entry : MessageKey.values()) { - final String key = entry.getKey(); - if (!userConfiguration.contains(key)) { - String jarMessage = getMessageFromJar(key); - if (jarMessage != null) { - hasMissingMessages = true; - userConfiguration.set(key, jarMessage); - } + for (PropertyEntry entry : properties) { + final Property property = (Property) entry.getProperty(); + String message = userConfiguration.getString(property.getPath()); + if (message == null) { + hasMissingMessages = true; + message = getMessageFromJar(property.getPath()); } + settingsManager.setProperty(property, message); } } @@ -77,7 +102,7 @@ public class MessageUpdater { if (message != null) { return message; } - return (defaultJarConfiguration == null ? null : defaultJarConfiguration.getString(key)); + return (defaultJarConfiguration == null) ? null : defaultJarConfiguration.getString(key); } private static FileConfiguration loadJarFileOrSendError(String jarPath) { @@ -96,6 +121,13 @@ public class MessageUpdater { return null; } + private static List buildPropertyEntriesForMessageKeys() { + return Arrays.stream(MessageKey.values()) + .map(key -> new StringProperty(key.getKey(), "")) + .map(PropertyEntry::new) + .collect(Collectors.toList()); + } + private static void close(Closeable closeable) { if (closeable != null) { try { From 77d4f4b24da6bb48c496c7993b72b3382cd408b6 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 16 Oct 2016 21:40:59 +0200 Subject: [PATCH 03/25] #768 Adjust to ConfigMe 0.2 and restrict command with permission --- docs/commands.md | 6 +- docs/permission_nodes.md | 8 ++- .../authme/command/CommandInitializer.java | 4 +- .../authme/permission/AdminPermission.java | 57 +++++++++---------- .../authme/permission/PlayerPermission.java | 32 +++++------ .../permission/PlayerStatePermission.java | 5 +- .../xephi/authme/service/MessageUpdater.java | 13 ++--- src/main/resources/plugin.yml | 7 ++- 8 files changed, 67 insertions(+), 65 deletions(-) diff --git a/docs/commands.md b/docs/commands.md index 00f4f8c61..4dd070fd6 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -1,5 +1,5 @@ - + ## AuthMe Commands You can use the following commands to use the features of AuthMe. Mandatory arguments are marked with `< >` @@ -45,6 +45,8 @@ brackets; optional arguments are enclosed in square brackets (`[ ]`). - **/authme version**: Show detailed information about the installed AuthMeReloaded version, the developers, contributors, and license. - **/authme converter** <job>: Converter command for AuthMeReloaded.
Requires `authme.admin.converter` +- **/authme messages**: Adds missing messages to the current messages file. +
Requires `authme.admin.updatemessages` - **/authme help** [query]: View detailed help for /authme commands. - **/login** <password>: Command to log in using AuthMeReloaded.
Requires `authme.player.login` @@ -76,4 +78,4 @@ brackets; optional arguments are enclosed in square brackets (`[ ]`). --- -This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sat Oct 01 23:33:39 CEST 2016 +This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Oct 16 21:39:08 CEST 2016 diff --git a/docs/permission_nodes.md b/docs/permission_nodes.md index 61f61c3e1..60d39a15c 100644 --- a/docs/permission_nodes.md +++ b/docs/permission_nodes.md @@ -1,5 +1,5 @@ - + ## AuthMe Permission Nodes The following are the permission nodes that are currently supported by the latest dev builds. @@ -26,14 +26,16 @@ The following are the permission nodes that are currently supported by the lates - **authme.admin.spawn** – Administrator command to teleport to the AuthMe spawn. - **authme.admin.switchantibot** – Administrator command to toggle the AntiBot protection status. - **authme.admin.unregister** – Administrator command to unregister an existing user. +- **authme.admin.updatemessages** – Permission to use the update messages command. - **authme.allowmultipleaccounts** – Permission to be able to register multiple accounts. - **authme.bypassantibot** – Permission node to bypass AntiBot protection. - **authme.bypassforcesurvival** – Permission for users to bypass force-survival mode. -- **authme.bypasspurge** – Permission to bypass the purging process +- **authme.bypasspurge** – Permission to bypass the purging process. - **authme.player.*** – Permission to use all player (non-admin) commands. - **authme.player.canbeforced** – Permission for users a login can be forced to. - **authme.player.captcha** – Command permission to use captcha. - **authme.player.changepassword** – Command permission to change the password. +- **authme.player.email** – Grants all email permissions. - **authme.player.email.add** – Command permission to add an email address. - **authme.player.email.change** – Command permission to change the email address. - **authme.player.email.recover** – Command permission to recover an account using it's email address. @@ -47,4 +49,4 @@ The following are the permission nodes that are currently supported by the lates --- -This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Oct 02 10:47:16 CEST 2016 +This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Oct 16 21:39:10 CEST 2016 diff --git a/src/main/java/fr/xephi/authme/command/CommandInitializer.java b/src/main/java/fr/xephi/authme/command/CommandInitializer.java index 598f8d3a6..33f27813a 100644 --- a/src/main/java/fr/xephi/authme/command/CommandInitializer.java +++ b/src/main/java/fr/xephi/authme/command/CommandInitializer.java @@ -291,10 +291,10 @@ public class CommandInitializer { CommandDescription.builder() .parent(AUTHME_BASE) - .labels("messages") + .labels("messages", "msg") .description("Add missing messages") .detailedDescription("Adds missing messages to the current messages file.") - // TODO #768: add permission for command + .permission(AdminPermission.UPDATE_MESSAGES) .executableCommand(MessagesCommand.class) .build(); diff --git a/src/main/java/fr/xephi/authme/permission/AdminPermission.java b/src/main/java/fr/xephi/authme/permission/AdminPermission.java index ed5ab9f4c..46d58072a 100644 --- a/src/main/java/fr/xephi/authme/permission/AdminPermission.java +++ b/src/main/java/fr/xephi/authme/permission/AdminPermission.java @@ -8,126 +8,125 @@ public enum AdminPermission implements PermissionNode { /** * Administrator command to register a new user. */ - REGISTER("authme.admin.register", DefaultPermission.OP_ONLY), + REGISTER("authme.admin.register"), /** * Administrator command to unregister an existing user. */ - UNREGISTER("authme.admin.unregister", DefaultPermission.OP_ONLY), + UNREGISTER("authme.admin.unregister"), /** * Administrator command to force-login an existing user. */ - FORCE_LOGIN("authme.admin.forcelogin", DefaultPermission.OP_ONLY), + FORCE_LOGIN("authme.admin.forcelogin"), /** * Administrator command to change the password of a user. */ - CHANGE_PASSWORD("authme.admin.changepassword", DefaultPermission.OP_ONLY), + CHANGE_PASSWORD("authme.admin.changepassword"), /** * Administrator command to see the last login date and time of a user. */ - LAST_LOGIN("authme.admin.lastlogin", DefaultPermission.OP_ONLY), + LAST_LOGIN("authme.admin.lastlogin"), /** * Administrator command to see all accounts associated with a user. */ - ACCOUNTS("authme.admin.accounts", DefaultPermission.OP_ONLY), + ACCOUNTS("authme.admin.accounts"), /** * Administrator command to get the email address of a user, if set. */ - GET_EMAIL("authme.admin.getemail", DefaultPermission.OP_ONLY), + GET_EMAIL("authme.admin.getemail"), /** * Administrator command to set or change the email address of a user. */ - CHANGE_EMAIL("authme.admin.changemail", DefaultPermission.OP_ONLY), + CHANGE_EMAIL("authme.admin.changemail"), /** * Administrator command to get the last known IP of a user. */ - GET_IP("authme.admin.getip", DefaultPermission.OP_ONLY), + GET_IP("authme.admin.getip"), /** * Administrator command to teleport to the AuthMe spawn. */ - SPAWN("authme.admin.spawn", DefaultPermission.OP_ONLY), + SPAWN("authme.admin.spawn"), /** * Administrator command to set the AuthMe spawn. */ - SET_SPAWN("authme.admin.setspawn", DefaultPermission.OP_ONLY), + SET_SPAWN("authme.admin.setspawn"), /** * Administrator command to teleport to the first AuthMe spawn. */ - FIRST_SPAWN("authme.admin.firstspawn", DefaultPermission.OP_ONLY), + FIRST_SPAWN("authme.admin.firstspawn"), /** * Administrator command to set the first AuthMe spawn. */ - SET_FIRST_SPAWN("authme.admin.setfirstspawn", DefaultPermission.OP_ONLY), + SET_FIRST_SPAWN("authme.admin.setfirstspawn"), /** * Administrator command to purge old user data. */ - PURGE("authme.admin.purge", DefaultPermission.OP_ONLY), + PURGE("authme.admin.purge"), /** * Administrator command to purge the last position of a user. */ - PURGE_LAST_POSITION("authme.admin.purgelastpos", DefaultPermission.OP_ONLY), + PURGE_LAST_POSITION("authme.admin.purgelastpos"), /** * Administrator command to purge all data associated with banned players. */ - PURGE_BANNED_PLAYERS("authme.admin.purgebannedplayers", DefaultPermission.OP_ONLY), + PURGE_BANNED_PLAYERS("authme.admin.purgebannedplayers"), /** * Administrator command to toggle the AntiBot protection status. */ - SWITCH_ANTIBOT("authme.admin.switchantibot", DefaultPermission.OP_ONLY), + SWITCH_ANTIBOT("authme.admin.switchantibot"), /** * Administrator command to convert old or other data to AuthMe data. */ - CONVERTER("authme.admin.converter", DefaultPermission.OP_ONLY), + CONVERTER("authme.admin.converter"), /** * Administrator command to reload the plugin configuration. */ - RELOAD("authme.admin.reload", DefaultPermission.OP_ONLY), + RELOAD("authme.admin.reload"), /** * Permission to see Antibot messages. */ - ANTIBOT_MESSAGES("authme.admin.antibotmessages", DefaultPermission.OP_ONLY), + ANTIBOT_MESSAGES("authme.admin.antibotmessages"), + + /** + * Permission to use the update messages command. + */ + UPDATE_MESSAGES("authme.admin.updatemessages"), /** * Permission to see the other accounts of the players that log in. */ - SEE_OTHER_ACCOUNTS("authme.admin.seeotheraccounts", DefaultPermission.OP_ONLY); + SEE_OTHER_ACCOUNTS("authme.admin.seeotheraccounts"); /** * The permission node. */ private String node; - /** - * The default permission level - */ - private DefaultPermission defaultPermission; - /** * Constructor. * * @param node Permission node. */ - AdminPermission(String node, DefaultPermission defaultPermission) { + AdminPermission(String node) { this.node = node; - this.defaultPermission = defaultPermission; } @Override @@ -137,6 +136,6 @@ public enum AdminPermission implements PermissionNode { @Override public DefaultPermission getDefaultPermission() { - return defaultPermission; + return DefaultPermission.OP_ONLY; } } diff --git a/src/main/java/fr/xephi/authme/permission/PlayerPermission.java b/src/main/java/fr/xephi/authme/permission/PlayerPermission.java index e2932e932..48e2a4bc6 100644 --- a/src/main/java/fr/xephi/authme/permission/PlayerPermission.java +++ b/src/main/java/fr/xephi/authme/permission/PlayerPermission.java @@ -8,76 +8,70 @@ public enum PlayerPermission implements PermissionNode { /** * Command permission to login. */ - LOGIN("authme.player.login", DefaultPermission.ALLOWED), + LOGIN("authme.player.login"), /** * Command permission to logout. */ - LOGOUT("authme.player.logout", DefaultPermission.ALLOWED), + LOGOUT("authme.player.logout"), /** * Command permission to register. */ - REGISTER("authme.player.register", DefaultPermission.ALLOWED), + REGISTER("authme.player.register"), /** * Command permission to unregister. */ - UNREGISTER("authme.player.unregister", DefaultPermission.ALLOWED), + UNREGISTER("authme.player.unregister"), /** * Command permission to change the password. */ - CHANGE_PASSWORD("authme.player.changepassword", DefaultPermission.ALLOWED), + CHANGE_PASSWORD("authme.player.changepassword"), /** * Command permission to add an email address. */ - ADD_EMAIL("authme.player.email.add", DefaultPermission.ALLOWED), + ADD_EMAIL("authme.player.email.add"), /** * Command permission to change the email address. */ - CHANGE_EMAIL("authme.player.email.change", DefaultPermission.ALLOWED), + CHANGE_EMAIL("authme.player.email.change"), /** * Command permission to recover an account using it's email address. */ - RECOVER_EMAIL("authme.player.email.recover", DefaultPermission.ALLOWED), + RECOVER_EMAIL("authme.player.email.recover"), /** * Command permission to use captcha. */ - CAPTCHA("authme.player.captcha", DefaultPermission.ALLOWED), + CAPTCHA("authme.player.captcha"), /** * Permission for users a login can be forced to. */ - CAN_LOGIN_BE_FORCED("authme.player.canbeforced", DefaultPermission.ALLOWED), + CAN_LOGIN_BE_FORCED("authme.player.canbeforced"), /** * Permission to use to see own other accounts. */ - SEE_OWN_ACCOUNTS("authme.player.seeownaccounts", DefaultPermission.ALLOWED); + SEE_OWN_ACCOUNTS("authme.player.seeownaccounts"); /** * The permission node. */ private String node; - /** - * The default permission level - */ - private DefaultPermission defaultPermission; - /** * Constructor. * * @param node Permission node. */ - PlayerPermission(String node, DefaultPermission defaultPermission) { + PlayerPermission(String node) { this.node = node; - this.defaultPermission = defaultPermission; } @Override @@ -87,7 +81,7 @@ public enum PlayerPermission implements PermissionNode { @Override public DefaultPermission getDefaultPermission() { - return defaultPermission; + return DefaultPermission.ALLOWED; } } diff --git a/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java b/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java index d733814eb..0820be011 100644 --- a/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java +++ b/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java @@ -27,7 +27,7 @@ public enum PlayerStatePermission implements PermissionNode { ALLOW_MULTIPLE_ACCOUNTS("authme.allowmultipleaccounts", DefaultPermission.OP_ONLY), /** - * Permission to bypass the purging process + * Permission to bypass the purging process. */ BYPASS_PURGE("authme.bypasspurge", DefaultPermission.NOT_ALLOWED); @@ -44,7 +44,8 @@ public enum PlayerStatePermission implements PermissionNode { /** * Constructor. * - * @param node Permission node. + * @param node Permission node + * @param defaultPermission The default permission */ PlayerStatePermission(String node, DefaultPermission defaultPermission) { this.node = node; diff --git a/src/main/java/fr/xephi/authme/service/MessageUpdater.java b/src/main/java/fr/xephi/authme/service/MessageUpdater.java index 3bdedef9d..129a47b81 100644 --- a/src/main/java/fr/xephi/authme/service/MessageUpdater.java +++ b/src/main/java/fr/xephi/authme/service/MessageUpdater.java @@ -1,7 +1,7 @@ package fr.xephi.authme.service; import com.github.authme.configme.SettingsManager; -import com.github.authme.configme.knownproperties.PropertyEntry; +import com.github.authme.configme.knownproperties.ConfigurationData; import com.github.authme.configme.properties.Property; import com.github.authme.configme.properties.StringProperty; import com.github.authme.configme.resource.YamlFileResource; @@ -31,7 +31,7 @@ public class MessageUpdater { private final FileConfiguration localJarConfiguration; private final FileConfiguration defaultJarConfiguration; - private final List properties; + private final List> properties; private final SettingsManager settingsManager; private boolean hasMissingMessages = false; @@ -56,7 +56,8 @@ public class MessageUpdater { } properties = buildPropertyEntriesForMessageKeys(); - settingsManager = new SettingsManager(new YamlFileResource(userFile), (r, p) -> true, properties); + settingsManager = new SettingsManager( + new YamlFileResource(userFile), (r, p) -> true, new ConfigurationData((List) properties)); } /** @@ -86,8 +87,7 @@ public class MessageUpdater { @SuppressWarnings("unchecked") private void copyMissingMessages() { - for (PropertyEntry entry : properties) { - final Property property = (Property) entry.getProperty(); + for (Property property : properties) { String message = userConfiguration.getString(property.getPath()); if (message == null) { hasMissingMessages = true; @@ -121,10 +121,9 @@ public class MessageUpdater { return null; } - private static List buildPropertyEntriesForMessageKeys() { + private static List> buildPropertyEntriesForMessageKeys() { return Arrays.stream(MessageKey.values()) .map(key -> new StringProperty(key.getKey(), "")) - .map(PropertyEntry::new) .collect(Collectors.toList()); } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 2b950e3a7..90ee29bff 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -48,6 +48,7 @@ permissions: description: Give access to all admin commands. children: authme.admin.accounts: true + authme.admin.antibotmessages: true authme.admin.changemail: true authme.admin.changepassword: true authme.admin.converter: true @@ -66,6 +67,7 @@ permissions: authme.admin.spawn: true authme.admin.switchantibot: true authme.admin.unregister: true + authme.admin.updatemessages: true authme.admin.register: description: Administrator command to register a new user. default: op @@ -127,7 +129,10 @@ permissions: description: Administrator command to reload the plugin configuration. default: op authme.admin.antibotmessages: - description: Permission to see Antibot messages + description: Permission to see Antibot messages. + default: op + authme.admin.updatemessages: + description: Permission to use the update messages command. default: op authme.player.*: description: Permission to use all player (non-admin) commands. From bb75d50c065b01b0b8ef29e9a5335c42b81f8c04 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Tue, 18 Oct 2016 17:59:23 +0200 Subject: [PATCH 04/25] Set help command to short description and alternatives - As discussed in https://github.com/AuthMe/AuthMeReloaded/pull/169 --- .../command/executable/HelpCommand.java | 9 +++++-- .../authme/command/help/HelpProvider.java | 27 +++++++++++++------ .../command/executable/HelpCommandTest.java | 11 +++++--- .../authme/command/help/HelpProviderTest.java | 18 +++++++++++++ 4 files changed, 52 insertions(+), 13 deletions(-) diff --git a/src/main/java/fr/xephi/authme/command/executable/HelpCommand.java b/src/main/java/fr/xephi/authme/command/executable/HelpCommand.java index 2076bcbce..0f7d90d20 100644 --- a/src/main/java/fr/xephi/authme/command/executable/HelpCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/HelpCommand.java @@ -14,6 +14,11 @@ import java.util.List; import static fr.xephi.authme.command.FoundResultStatus.MISSING_BASE_COMMAND; import static fr.xephi.authme.command.FoundResultStatus.UNKNOWN_LABEL; +import static fr.xephi.authme.command.help.HelpProvider.ALL_OPTIONS; +import static fr.xephi.authme.command.help.HelpProvider.SHOW_ALTERNATIVES; +import static fr.xephi.authme.command.help.HelpProvider.SHOW_CHILDREN; +import static fr.xephi.authme.command.help.HelpProvider.SHOW_COMMAND; +import static fr.xephi.authme.command.help.HelpProvider.SHOW_DESCRIPTION; public class HelpCommand implements ExecutableCommand { @@ -46,9 +51,9 @@ public class HelpCommand implements ExecutableCommand { int mappedCommandLevel = result.getCommandDescription().getLabelCount(); if (mappedCommandLevel == 1) { - helpProvider.outputHelp(sender, result, HelpProvider.SHOW_CHILDREN); + helpProvider.outputHelp(sender, result, SHOW_COMMAND | SHOW_DESCRIPTION | SHOW_CHILDREN | SHOW_ALTERNATIVES); } else { - helpProvider.outputHelp(sender, result, HelpProvider.ALL_OPTIONS); + helpProvider.outputHelp(sender, result, ALL_OPTIONS); } } diff --git a/src/main/java/fr/xephi/authme/command/help/HelpProvider.java b/src/main/java/fr/xephi/authme/command/help/HelpProvider.java index 8fc941617..dfcbe554e 100644 --- a/src/main/java/fr/xephi/authme/command/help/HelpProvider.java +++ b/src/main/java/fr/xephi/authme/command/help/HelpProvider.java @@ -15,11 +15,12 @@ import org.bukkit.command.CommandSender; import javax.inject.Inject; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.function.Function; import static fr.xephi.authme.command.help.HelpSection.DETAILED_DESCRIPTION; import static fr.xephi.authme.command.help.HelpSection.SHORT_DESCRIPTION; -import static java.util.Arrays.asList; import static java.util.Collections.singletonList; /** @@ -171,19 +172,29 @@ public class HelpProvider implements Reloadable { } private void printAlternatives(CommandDescription command, List correctLabels, List lines) { - if (command.getLabels().size() <= 1 || correctLabels.size() <= 1) { + if (command.getLabels().size() <= 1) { return; } lines.add(ChatColor.GOLD + helpMessagesService.getMessage(HelpSection.ALTERNATIVES) + ":"); - // Get the label used - final String parentLabel = correctLabels.get(0); - final String childLabel = correctLabels.get(1); + + // Label with which the command was called -> don't show it as an alternative + final String usedLabel; + // Takes alternative label and constructs list of labels, e.g. "reg" -> [authme, reg] + final Function> commandLabelsFn; + + if (correctLabels.size() == 1) { + usedLabel = correctLabels.get(0); + commandLabelsFn = label -> singletonList(label); + } else { + usedLabel = correctLabels.get(1); + commandLabelsFn = label -> Arrays.asList(correctLabels.get(0), label); + } // Create a list of alternatives - for (String entry : command.getLabels()) { - if (!entry.equalsIgnoreCase(childLabel)) { - lines.add(" " + CommandSyntaxHelper.getSyntax(command, asList(parentLabel, entry))); + for (String label : command.getLabels()) { + if (!label.equalsIgnoreCase(usedLabel)) { + lines.add(" " + CommandSyntaxHelper.getSyntax(command, commandLabelsFn.apply(label))); } } } diff --git a/src/test/java/fr/xephi/authme/command/executable/HelpCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/HelpCommandTest.java index 143ae26b8..3c57e2148 100644 --- a/src/test/java/fr/xephi/authme/command/executable/HelpCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/HelpCommandTest.java @@ -20,6 +20,10 @@ import static fr.xephi.authme.command.FoundResultStatus.INCORRECT_ARGUMENTS; import static fr.xephi.authme.command.FoundResultStatus.MISSING_BASE_COMMAND; import static fr.xephi.authme.command.FoundResultStatus.SUCCESS; import static fr.xephi.authme.command.FoundResultStatus.UNKNOWN_LABEL; +import static fr.xephi.authme.command.help.HelpProvider.SHOW_ALTERNATIVES; +import static fr.xephi.authme.command.help.HelpProvider.SHOW_CHILDREN; +import static fr.xephi.authme.command.help.HelpProvider.SHOW_COMMAND; +import static fr.xephi.authme.command.help.HelpProvider.SHOW_DESCRIPTION; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import static org.hamcrest.CoreMatchers.containsString; @@ -108,7 +112,7 @@ public class HelpCommandTest { CommandDescription commandDescription = mock(CommandDescription.class); given(commandDescription.getLabelCount()).willReturn(1); FoundCommandResult foundCommandResult = new FoundCommandResult(commandDescription, singletonList("authme"), - Collections.emptyList(), 0.0, SUCCESS); + Collections.emptyList(), 0.0, SUCCESS); given(commandMapper.mapPartsToCommand(sender, arguments)).willReturn(foundCommandResult); // when @@ -116,7 +120,8 @@ public class HelpCommandTest { // then verify(sender, never()).sendMessage(anyString()); - verify(helpProvider).outputHelp(sender, foundCommandResult, HelpProvider.SHOW_CHILDREN); + verify(helpProvider).outputHelp(sender, foundCommandResult, + SHOW_DESCRIPTION | SHOW_COMMAND | SHOW_CHILDREN | SHOW_ALTERNATIVES); } @Test @@ -126,7 +131,7 @@ public class HelpCommandTest { CommandDescription commandDescription = mock(CommandDescription.class); given(commandDescription.getLabelCount()).willReturn(2); FoundCommandResult foundCommandResult = new FoundCommandResult(commandDescription, asList("authme", "getpos"), - Collections.emptyList(), 0.0, INCORRECT_ARGUMENTS); + Collections.emptyList(), 0.0, INCORRECT_ARGUMENTS); given(commandMapper.mapPartsToCommand(sender, arguments)).willReturn(foundCommandResult); // when diff --git a/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java b/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java index 5a0f06f29..0d3983ce5 100644 --- a/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java +++ b/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java @@ -395,6 +395,24 @@ public class HelpProviderTest { assertThat(lines.get(0), equalTo("Command: /authme register ")); } + @Test + public void shouldShowAlternativesForRootCommand() { + // given + CommandDescription command = getCommandWithLabel(commands, "unregister"); + FoundCommandResult result = newFoundResult(command, Collections.singletonList("unreg")); + + // when + helpProvider.outputHelp(sender, result, SHOW_COMMAND | SHOW_ALTERNATIVES); + + // then + List lines = getLines(sender); + assertThat(lines, hasSize(4)); + assertThat(lines.get(0), equalTo("Header")); + assertThat(lines.get(1), equalTo("Command: /unreg ")); + assertThat(lines.get(2), equalTo("Alternatives:")); + assertThat(lines.get(3), equalTo(" /unregister ")); + } + /** * Generate an instance of {@link FoundCommandResult} with the given command and labels. All other fields aren't * retrieved by {@link HelpProvider} and so are initialized to default values for the tests. From 9013b8f9a117d0771af4e317428c2af6081163b6 Mon Sep 17 00:00:00 2001 From: Maxetto Date: Tue, 18 Oct 2016 18:01:39 +0200 Subject: [PATCH 05/25] [IT Translation] Translate help command (#169) * [IT Translation] Translate help command --- src/main/resources/messages/help_it.yml | 154 ++++++++++++++++++++ src/main/resources/messages/messages_it.yml | 2 +- 2 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/messages/help_it.yml diff --git a/src/main/resources/messages/help_it.yml b/src/main/resources/messages/help_it.yml new file mode 100644 index 000000000..b69f85153 --- /dev/null +++ b/src/main/resources/messages/help_it.yml @@ -0,0 +1,154 @@ +# Lingua Italiana creata da Maxetto e sgdc3. +# Translation config for the AuthMe help, e.g. when /authme help or /authme help register is called + +# ------------------------------------------------------- +# List of texts used in the help section +common: + header: '==========[ Assistenza AuthMeReloaded ]==========' + optional: 'Opzionale' + hasPermission: 'Hai il permesso' + noPermission: 'Non hai il permesso' + default: 'Configurazione base' + result: 'Risultato' + defaultPermissions: + notAllowed: 'Nessuno autorizzato' + opOnly: 'Solo per OP' + allowed: 'Tutti autorizzati' + +# ------------------------------------------------------- +# Titles of the individual help sections +# Set the translation text to empty text to disable the section, e.g. to hide alternatives: +# alternatives: '' +section: + command: 'Comando' + description: 'Descrizione breve' + detailedDescription: 'Descrizione dettagliata' + arguments: 'Parametri' + permissions: 'Permessi' + alternatives: 'Alternative' + children: 'Comandi' + +# ------------------------------------------------------- +# You can translate the data for all commands using the below pattern. +# For example to translate /authme reload, create a section "authme.reload", or "login" for /login +# If the command has arguments, you can use arg1 as below to translate the first argument, and so forth +# Translations don't need to be complete; any missing section will be taken from the default silently +# Important: Put main commands like "authme" before their children (e.g. "authme.reload") +commands: + authme.register: + description: 'Registra un giocatore' + detailedDescription: 'Registra il giocatore indicato con la password inserita.' + arg1: + label: 'giocatore' + description: 'Nome del giocatore' + arg2: + label: 'password' + description: 'Password' + authme.unregister: + description: 'Rimuovi un giocatore' + detailedDescription: 'Rimuovi il giocatore indicato dal Database.' + arg1: + label: 'giocatore' + description: 'Nome del giocatore' + authme.forcelogin: + description: 'Forza l''autenticazione ad un giocatore' + detailedDescription: 'Autentica il giocatore indicato.' + arg1: + label: 'giocatore' + description: 'Nome del giocatore connesso' + authme.password: + description: 'Cambia la password di un giocatore' + detailedDescription: 'Cambia la password del giocatore indicato.' + arg1: + label: 'giocatore' + description: 'Nome del giocatore' + arg2: + label: 'password' + description: 'Nuova Password' + authme.lastlogin: + description: 'Ultima autenticazione di un giocatore' + detailedDescription: 'Visualizza l''ultima data di autenticazione del giocatore indicato.' + arg1: + label: 'giocatore' + description: 'Nome del giocatore' + authme.accounts: + description: 'Mostra i profili di un giocatore' + detailedDescription: 'Mostra tutti i profili di un giocatore attraverso il nome o l''indirizzo IP.' + arg1: + label: 'giocatore' + description: 'Nome o indirizzo IP del giocatore' + authme.email: + description: 'Mostra l''indirizzo email di un giocatore' + detailedDescription: 'Mostra l''indirizzo email del giocatore indicato se impostato.' + arg1: + label: 'giocatore' + description: 'Nome del giocatore' + authme.setemail: + description: 'Cambia l''indirizzo email di un giocatore' + detailedDescription: 'Cambia l''indirizzo email del giocatore indicato.' + arg1: + label: 'giocatore' + description: 'Nome del giocatore' + arg2: + label: 'email' + description: 'Indirizzo email del giocatore' + authme.getip: + description: 'Mostra l''indirizzo IP di un giocatore' + detailedDescription: 'Mostra l''indirizzo IP del giocatore indicato.' + arg1: + label: 'giocatore' + description: 'Nome del giocatore connesso' + authme.spawn: + description: 'Teletrasportati al punto di rigenerazione' + detailedDescription: 'Teletrasportati al punto di rigenerazione.' + authme.setspawn: + description: 'Cambia il punto di rigenerazione' + detailedDescription: 'Cambia il punto di rigenerazione dei giocatori alla tua posizione.' + authme.firstspawn: + description: 'Teletrasportati al punto di rigenerazione iniziale' + detailedDescription: 'Teletrasportati al punto di rigenerazione iniziale.' + authme.setfirstspawn: + description: 'Cambia il punto di rigenerazione iniziale' + detailedDescription: 'Cambia il punto di rigenerazione iniziale dei giocatori alla tua posizione.' + authme.purge: + description: 'Elimina i vecchi dati' + detailedDescription: 'Elimina i dati di AuthMeReloaded più vecchi dei giorni indicati.' + arg1: + label: 'giorni' + description: 'Numero di giorni' + arg2: + label: 'all' + description: 'Aggiungi ''all'' alla fine per eliminare anche i giocatori con l''ultima autenticazione pari a 0' + authme.resetpos: + description: 'Elimina l''ultima posizione di un giocatore' + detailedDescription: 'Elimina l''ultima posizione conosciuta del giocatore indicato o di tutti i giocatori.' + arg1: + label: 'giocatore/*' + description: 'Nome del giocatore o ''*'' per tutti i giocatori' + authme.purgebannedplayers: + description: 'Elimina i dati dei giocatori banditi' + detailedDescription: 'Elimina tutti i dati di AuthMeReloaded dei giocatori banditi.' + authme.switchantibot: + description: 'Cambia lo stato del servizio di AntiBot' + detailedDescription: 'Cambia lo stato del servizio di AntiBot allo stato indicato.' + arg1: + label: 'stato' + description: 'ON / OFF' + authme.reload: + description: 'Ricarica il plugin' + detailedDescription: 'Ricarica il plugin AuthMeReloaded.' + authme.version: + description: 'Informazioni sulla versione' + detailedDescription: 'Mostra informazioni dettagliate riguardo la versione di AuthMeReloaded in uso, gli sviluppatori, i collaboratori e la licenza.' + authme.converter: + description: 'Comando per il convertitore' + detailedDescription: 'Comando per il convertitore di AuthMeReloaded.' + arg1: + label: 'incarico' + description: 'Incarico di conversione: xauth / crazylogin / rakamak / royalauth / vauth / sqliteToSql / mysqlToSqlite' + authme.help: + description: 'Visualizza l''assistenza' + detailedDescription: 'Visualizza informazioni dettagliate per i comandi ''/authme''.' + arg1: + label: 'comando' + description: 'Il comando di cui vuoi ricevere assistenza' diff --git a/src/main/resources/messages/messages_it.yml b/src/main/resources/messages/messages_it.yml index 3c0aaed2a..5b0ba558b 100644 --- a/src/main/resources/messages/messages_it.yml +++ b/src/main/resources/messages/messages_it.yml @@ -69,7 +69,7 @@ invalid_name_case: 'Dovresti entrare con questo nome utente: "%valid", al posto tempban_max_logins: '&cSei stato temporaneamente bandito per aver fallito l''autenticazione troppe volte.' accounts_owned_self: 'Possiedi %count account:' accounts_owned_other: 'Il giocatore %name possiede %count account:' -kicked_admin_registered: 'Un amministratore ti ha appena registrato; per favore rientra nel server' +kicked_admin_registered: 'Un amministratore ti ha appena registrato, per favore rientra nel server' incomplete_email_settings: 'Errore: non tutte le impostazioni richieste per inviare le email sono state impostate. Per favore contatta un amministratore.' recovery_code_incorrect: 'Il codice di recupero inserito non è corretto! Scrivi /email recovery per generarne uno nuovo' recovery_code_sent: 'Una email contenente il codice di recupero per reimpostare la tua password è stata appena inviata al tuo indirizzo email.' From a6bbfcfb8967b5b7b4b80ab349b9244c3b006483 Mon Sep 17 00:00:00 2001 From: Maxetto Date: Tue, 18 Oct 2016 18:08:41 +0200 Subject: [PATCH 06/25] [IT Translation] Translate "/email show" command --- src/main/resources/messages/messages_it.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/messages/messages_it.yml b/src/main/resources/messages/messages_it.yml index 5b0ba558b..d257c7465 100644 --- a/src/main/resources/messages/messages_it.yml +++ b/src/main/resources/messages/messages_it.yml @@ -73,5 +73,5 @@ kicked_admin_registered: 'Un amministratore ti ha appena registrato, per favore incomplete_email_settings: 'Errore: non tutte le impostazioni richieste per inviare le email sono state impostate. Per favore contatta un amministratore.' recovery_code_incorrect: 'Il codice di recupero inserito non è corretto! Scrivi /email recovery per generarne uno nuovo' recovery_code_sent: 'Una email contenente il codice di recupero per reimpostare la tua password è stata appena inviata al tuo indirizzo email.' -# TODO email_show: '&2Your current email address is: &f%email' -# TODO show_no_email: '&2You currently don''t have email address associated with this account.' \ No newline at end of file +email_show: '&2Il tuo indirizzo email al momento è: &f%email' +show_no_email: '&2Al momento non hai nessun indirizzo email associato al tuo account.' From 3dab5cd70ce6e391381ac3244f00540f303d9b3e Mon Sep 17 00:00:00 2001 From: ljacqu Date: Tue, 18 Oct 2016 18:31:49 +0200 Subject: [PATCH 07/25] #979 Check that help_xx.yml files are valid YAML - Change existing test checking messages_xx.yml to also have test for help_xx.yml files --- .../message/MessagesFileYamlCheckerTest.java | 75 -------------- .../message/YamlTextFileCheckerTest.java | 98 +++++++++++++++++++ 2 files changed, 98 insertions(+), 75 deletions(-) delete mode 100644 src/test/java/fr/xephi/authme/message/MessagesFileYamlCheckerTest.java create mode 100644 src/test/java/fr/xephi/authme/message/YamlTextFileCheckerTest.java diff --git a/src/test/java/fr/xephi/authme/message/MessagesFileYamlCheckerTest.java b/src/test/java/fr/xephi/authme/message/MessagesFileYamlCheckerTest.java deleted file mode 100644 index ebb04fc2d..000000000 --- a/src/test/java/fr/xephi/authme/message/MessagesFileYamlCheckerTest.java +++ /dev/null @@ -1,75 +0,0 @@ -package fr.xephi.authme.message; - -import fr.xephi.authme.TestHelper; -import fr.xephi.authme.util.StringUtils; -import org.bukkit.configuration.file.YamlConfiguration; -import org.junit.Test; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Pattern; - -import static org.junit.Assert.fail; - -/** - * Tests that all YML message files can be loaded. - */ -public class MessagesFileYamlCheckerTest { - - /** Path in the resources folder where the message files are located. */ - private static final String MESSAGES_FOLDER = "/messages/"; - /** Pattern of the message file names. */ - private static final Pattern MESSAGE_FILE_PATTERN = Pattern.compile("messages_\\w+\\.yml"); - /** Message key that is present in all files. Used to make sure that text is returned. */ - private static final MessageKey MESSAGE_KEY = MessageKey.LOGIN_MESSAGE; - - @Test - public void shouldAllBeValidYaml() { - // given - List messageFiles = getMessageFiles(); - - // when - List errors = new ArrayList<>(); - for (File file : messageFiles) { - String error = null; - try { - YamlConfiguration configuration = YamlConfiguration.loadConfiguration(file); - if (StringUtils.isEmpty(configuration.getString(MESSAGE_KEY.getKey()))) { - error = "Message for '" + MESSAGE_KEY + "' is empty"; - } - } catch (Exception e) { - error = "Could not load file: " + StringUtils.formatException(e); - } - if (!StringUtils.isEmpty(error)) { - errors.add(file.getName() + ": " + error); - } - } - - // then - if (!errors.isEmpty()) { - fail("Errors during verification of message files:\n-" + String.join("\n-", errors)); - } - } - - - private List getMessageFiles() { - File folder = TestHelper.getJarFile(MESSAGES_FOLDER); - File[] files = folder.listFiles(); - if (files == null) { - throw new IllegalStateException("Could not read folder '" + folder.getName() + "'"); - } - - List messageFiles = new ArrayList<>(); - for (File file : files) { - if (MESSAGE_FILE_PATTERN.matcher(file.getName()).matches()) { - messageFiles.add(file); - } - } - if (messageFiles.isEmpty()) { - throw new IllegalStateException("Error getting message files: list of files is empty"); - } - return messageFiles; - } - -} diff --git a/src/test/java/fr/xephi/authme/message/YamlTextFileCheckerTest.java b/src/test/java/fr/xephi/authme/message/YamlTextFileCheckerTest.java new file mode 100644 index 000000000..7fa6fecba --- /dev/null +++ b/src/test/java/fr/xephi/authme/message/YamlTextFileCheckerTest.java @@ -0,0 +1,98 @@ +package fr.xephi.authme.message; + +import fr.xephi.authme.TestHelper; +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.Test; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Pattern; + +import static org.junit.Assert.fail; + +/** + * Tests that all YML text files can be loaded. + */ +public class YamlTextFileCheckerTest { + + /** Path in the resources folder where the message files are located. */ + private static final String MESSAGES_FOLDER = "/messages/"; + /** Contains all files of the MESSAGES_FOLDER. */ + private static List messageFiles; + + @BeforeClass + public static void loadMessagesFiles() { + File folder = TestHelper.getJarFile(MESSAGES_FOLDER); + File[] files = folder.listFiles(); + if (files == null || files.length == 0) { + throw new IllegalStateException("Could not read folder '" + folder.getName() + "'"); + } + messageFiles = Arrays.asList(files); + } + + @Test + public void testAllMessagesYmlFiles() { + checkFiles( + Pattern.compile("messages_\\w+\\.yml"), + MessageKey.LOGIN_MESSAGE.getKey()); + } + + @Test + public void testAllHelpYmlFiles() { + checkFiles( + Pattern.compile("help_\\w+\\.yml"), + HelpSection.ALTERNATIVES.getKey()); + } + + /** + * Checks all files in the messages folder that match the given pattern. + * + * @param pattern the pattern the file name needs to match + * @param mandatoryKey key present in all matched files + */ + private void checkFiles(Pattern pattern, String mandatoryKey) { + List errors = new ArrayList<>(); + + boolean hasMatch = false; + for (File file : messageFiles) { + if (pattern.matcher(file.getName()).matches()) { + checkFile(file, mandatoryKey, errors); + hasMatch = true; + } + } + + if (!errors.isEmpty()) { + fail("Errors while checking files matching '" + pattern + "':\n-" + String.join("\n-", errors)); + } else if (!hasMatch) { + fail("Could not find any files satisfying pattern '" + pattern + "'"); + } + } + + /** + * Checks that the provided YAML file can be loaded and that it contains a non-empty text + * for the provided mandatory key. + * + * @param file the file to check + * @param mandatoryKey the key for which text must be present + * @param errors collection of errors to add to if the verification fails + */ + private void checkFile(File file, String mandatoryKey, List errors) { + String error = null; + try { + YamlConfiguration configuration = YamlConfiguration.loadConfiguration(file); + if (StringUtils.isEmpty(configuration.getString(mandatoryKey))) { + error = "Message for '" + mandatoryKey + "' is empty"; + } + } catch (Exception e) { + error = "Could not load file: " + StringUtils.formatException(e); + } + if (!StringUtils.isEmpty(error)) { + errors.add(file.getName() + ": " + error); + } + } +} From 1d11824367030d645f10de35c9ab872e5ce1fa18 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Tue, 18 Oct 2016 19:47:57 +0200 Subject: [PATCH 08/25] #293 Translatable help - show translated description of child commands - Show translated command descriptions when available - Fix bug where localized command is registered on the parent each time Thanks to @Maxetto --- .../authme/command/CommandDescription.java | 64 ++++++++--------- .../authme/command/CommandInitializer.java | 68 +++++++++---------- .../command/help/HelpMessagesService.java | 4 ++ .../authme/command/help/HelpProvider.java | 2 +- .../authme/permission/PlayerPermission.java | 2 +- .../authme/command/CommandUtilsTest.java | 10 +-- .../authme/command/TestCommandsUtil.java | 4 +- .../command/help/HelpMessagesServiceTest.java | 33 +++++++-- .../authme/command/help/HelpProviderTest.java | 10 ++- 9 files changed, 112 insertions(+), 85 deletions(-) diff --git a/src/main/java/fr/xephi/authme/command/CommandDescription.java b/src/main/java/fr/xephi/authme/command/CommandDescription.java index 36ad6da6e..b6c006f9b 100644 --- a/src/main/java/fr/xephi/authme/command/CommandDescription.java +++ b/src/main/java/fr/xephi/authme/command/CommandDescription.java @@ -56,16 +56,10 @@ public class CommandDescription { private PermissionNode permission; /** - * Private constructor. Use {@link CommandDescription#builder()} to create instances of this class. + * Private constructor. *

- * Note for developers: Instances should be created with {@link CommandDescription#createInstance} to be properly + * Note for developers: Instances should be created with {@link CommandBuilder#register()} to be properly * registered in the command tree. - */ - private CommandDescription() { - } - - /** - * Create an instance. * * @param labels command labels * @param description description of the command @@ -74,30 +68,17 @@ public class CommandDescription { * @param parent parent command * @param arguments command arguments * @param permission permission node required to execute this command - * - * @return the created instance - * @see CommandDescription#builder() */ - private static CommandDescription createInstance(List labels, String description, - String detailedDescription, Class executableCommand, CommandDescription parent, - List arguments, PermissionNode permission) { - CommandDescription instance = new CommandDescription(); - instance.labels = labels; - instance.description = description; - instance.detailedDescription = detailedDescription; - instance.executableCommand = executableCommand; - instance.parent = parent; - instance.arguments = arguments; - instance.permission = permission; - - if (parent != null) { - parent.addChild(instance); - } - return instance; - } - - private void addChild(CommandDescription command) { - children.add(command); + private CommandDescription(List labels, String description, String detailedDescription, + Class executableCommand, CommandDescription parent, + List arguments, PermissionNode permission) { + this.labels = labels; + this.description = description; + this.detailedDescription = detailedDescription; + this.executableCommand = executableCommand; + this.parent = parent; + this.arguments = arguments; + this.permission = permission; } /** @@ -224,8 +205,21 @@ public class CommandDescription { private PermissionNode permission; /** - * Build a CommandDescription from the builder or throw an exception if a mandatory - * field has not been set. + * Build a CommandDescription and register it onto the parent if available. + * + * @return The generated CommandDescription object + */ + public CommandDescription register() { + CommandDescription command = build(); + + if (command.parent != null) { + command.parent.children.add(command); + } + return command; + } + + /** + * Build a CommandDescription (without registering it on the parent). * * @return The generated CommandDescription object */ @@ -236,8 +230,8 @@ public class CommandDescription { checkArgument(executableCommand != null, "Executable command must be set"); // parents and permissions may be null; arguments may be empty - return createInstance(labels, description, detailedDescription, executableCommand, - parent, arguments, permission); + return new CommandDescription(labels, description, detailedDescription, executableCommand, + parent, arguments, permission); } public CommandBuilder labels(List labels) { diff --git a/src/main/java/fr/xephi/authme/command/CommandInitializer.java b/src/main/java/fr/xephi/authme/command/CommandInitializer.java index 808bbdbf4..60eec7905 100644 --- a/src/main/java/fr/xephi/authme/command/CommandInitializer.java +++ b/src/main/java/fr/xephi/authme/command/CommandInitializer.java @@ -70,7 +70,7 @@ public class CommandInitializer { .description("Main command") .detailedDescription("The main AuthMeReloaded command. The root for all admin commands.") .executableCommand(AuthMeCommand.class) - .build(); + .register(); // Register the register command CommandDescription.builder() @@ -82,7 +82,7 @@ public class CommandInitializer { .withArgument("password", "Password", false) .permission(AdminPermission.REGISTER) .executableCommand(RegisterAdminCommand.class) - .build(); + .register(); // Register the unregister command CommandDescription.builder() @@ -93,7 +93,7 @@ public class CommandInitializer { .withArgument("player", "Player name", false) .permission(AdminPermission.UNREGISTER) .executableCommand(UnregisterAdminCommand.class) - .build(); + .register(); // Register the forcelogin command CommandDescription.builder() @@ -104,7 +104,7 @@ public class CommandInitializer { .withArgument("player", "Online player name", true) .permission(AdminPermission.FORCE_LOGIN) .executableCommand(ForceLoginCommand.class) - .build(); + .register(); // Register the changepassword command CommandDescription.builder() @@ -116,7 +116,7 @@ public class CommandInitializer { .withArgument("pwd", "New password", false) .permission(AdminPermission.CHANGE_PASSWORD) .executableCommand(ChangePasswordAdminCommand.class) - .build(); + .register(); // Register the last login command CommandDescription.builder() @@ -127,7 +127,7 @@ public class CommandInitializer { .withArgument("player", "Player name", true) .permission(AdminPermission.LAST_LOGIN) .executableCommand(LastLoginCommand.class) - .build(); + .register(); // Register the accounts command CommandDescription.builder() @@ -138,7 +138,7 @@ public class CommandInitializer { .withArgument("player", "Player name or IP", true) .permission(AdminPermission.ACCOUNTS) .executableCommand(AccountsCommand.class) - .build(); + .register(); // Register the getemail command CommandDescription.builder() @@ -149,7 +149,7 @@ public class CommandInitializer { .withArgument("player", "Player name", true) .permission(AdminPermission.GET_EMAIL) .executableCommand(GetEmailCommand.class) - .build(); + .register(); // Register the setemail command CommandDescription.builder() @@ -161,7 +161,7 @@ public class CommandInitializer { .withArgument("email", "Player email", false) .permission(AdminPermission.CHANGE_EMAIL) .executableCommand(SetEmailCommand.class) - .build(); + .register(); // Register the getip command CommandDescription.builder() @@ -172,7 +172,7 @@ public class CommandInitializer { .withArgument("player", "Player name", false) .permission(AdminPermission.GET_IP) .executableCommand(GetIpCommand.class) - .build(); + .register(); // Register the spawn command CommandDescription.builder() @@ -182,7 +182,7 @@ public class CommandInitializer { .detailedDescription("Teleport to the spawn.") .permission(AdminPermission.SPAWN) .executableCommand(SpawnCommand.class) - .build(); + .register(); // Register the setspawn command CommandDescription.builder() @@ -192,7 +192,7 @@ public class CommandInitializer { .detailedDescription("Change the player's spawn to your current position.") .permission(AdminPermission.SET_SPAWN) .executableCommand(SetSpawnCommand.class) - .build(); + .register(); // Register the firstspawn command CommandDescription.builder() @@ -202,7 +202,7 @@ public class CommandInitializer { .detailedDescription("Teleport to the first spawn.") .permission(AdminPermission.FIRST_SPAWN) .executableCommand(FirstSpawnCommand.class) - .build(); + .register(); // Register the setfirstspawn command CommandDescription.builder() @@ -212,7 +212,7 @@ public class CommandInitializer { .detailedDescription("Change the first player's spawn to your current position.") .permission(AdminPermission.SET_FIRST_SPAWN) .executableCommand(SetFirstSpawnCommand.class) - .build(); + .register(); // Register the purge command CommandDescription.builder() @@ -224,7 +224,7 @@ public class CommandInitializer { .withArgument("all", "Add 'all' at the end to also purge players with lastlogin = 0", true) .permission(AdminPermission.PURGE) .executableCommand(PurgeCommand.class) - .build(); + .register(); // Register the purgelastposition command CommandDescription.builder() @@ -236,7 +236,7 @@ public class CommandInitializer { .withArgument("player/*", "Player name or * for all players", false) .permission(AdminPermission.PURGE_LAST_POSITION) .executableCommand(PurgeLastPositionCommand.class) - .build(); + .register(); // Register the purgebannedplayers command CommandDescription.builder() @@ -246,7 +246,7 @@ public class CommandInitializer { .detailedDescription("Purge all AuthMeReloaded data for banned players.") .permission(AdminPermission.PURGE_BANNED_PLAYERS) .executableCommand(PurgeBannedPlayersCommand.class) - .build(); + .register(); // Register the switchantibot command CommandDescription.builder() @@ -257,7 +257,7 @@ public class CommandInitializer { .withArgument("mode", "ON / OFF", true) .permission(AdminPermission.SWITCH_ANTIBOT) .executableCommand(SwitchAntiBotCommand.class) - .build(); + .register(); // Register the reload command CommandDescription.builder() @@ -267,7 +267,7 @@ public class CommandInitializer { .detailedDescription("Reload the AuthMeReloaded plugin.") .permission(AdminPermission.RELOAD) .executableCommand(ReloadCommand.class) - .build(); + .register(); // Register the version command CommandDescription.builder() @@ -277,7 +277,7 @@ public class CommandInitializer { .detailedDescription("Show detailed information about the installed AuthMeReloaded version, the " + "developers, contributors, and license.") .executableCommand(VersionCommand.class) - .build(); + .register(); CommandDescription.builder() .parent(AUTHME_BASE) @@ -288,7 +288,7 @@ public class CommandInitializer { "royalauth / vauth / sqliteToSql / mysqlToSqlite", false) .permission(AdminPermission.CONVERTER) .executableCommand(ConverterCommand.class) - .build(); + .register(); CommandDescription.builder() .parent(AUTHME_BASE) @@ -297,7 +297,7 @@ public class CommandInitializer { .detailedDescription("Adds missing messages to the current messages file.") .permission(AdminPermission.UPDATE_MESSAGES) .executableCommand(MessagesCommand.class) - .build(); + .register(); // Register the base login command final CommandDescription LOGIN_BASE = CommandDescription.builder() @@ -308,7 +308,7 @@ public class CommandInitializer { .withArgument("password", "Login password", false) .permission(PlayerPermission.LOGIN) .executableCommand(LoginCommand.class) - .build(); + .register(); // Register the base logout command CommandDescription LOGOUT_BASE = CommandDescription.builder() @@ -318,7 +318,7 @@ public class CommandInitializer { .detailedDescription("Command to logout using AuthMeReloaded.") .permission(PlayerPermission.LOGOUT) .executableCommand(LogoutCommand.class) - .build(); + .register(); // Register the base register command final CommandDescription REGISTER_BASE = CommandDescription.builder() @@ -330,7 +330,7 @@ public class CommandInitializer { .withArgument("verifyPassword", "Verify password", true) .permission(PlayerPermission.REGISTER) .executableCommand(RegisterCommand.class) - .build(); + .register(); // Register the base unregister command CommandDescription UNREGISTER_BASE = CommandDescription.builder() @@ -341,7 +341,7 @@ public class CommandInitializer { .withArgument("password", "Password", false) .permission(PlayerPermission.UNREGISTER) .executableCommand(UnregisterCommand.class) - .build(); + .register(); // Register the base changepassword command final CommandDescription CHANGE_PASSWORD_BASE = CommandDescription.builder() @@ -353,7 +353,7 @@ public class CommandInitializer { .withArgument("newPassword", "New Password.", false) .permission(PlayerPermission.CHANGE_PASSWORD) .executableCommand(ChangePasswordCommand.class) - .build(); + .register(); // Register the base Email command CommandDescription EMAIL_BASE = CommandDescription.builder() @@ -362,7 +362,7 @@ public class CommandInitializer { .description("Email command") .detailedDescription("The AuthMeReloaded Email command base.") .executableCommand(EmailBaseCommand.class) - .build(); + .register(); // Register the show command CommandDescription.builder() @@ -371,7 +371,7 @@ public class CommandInitializer { .description("Show Email") .detailedDescription("Show your current email address.") .executableCommand(ShowEmailCommand.class) - .build(); + .register(); // Register the add command CommandDescription.builder() @@ -383,7 +383,7 @@ public class CommandInitializer { .withArgument("verifyEmail", "Email address verification", false) .permission(PlayerPermission.ADD_EMAIL) .executableCommand(AddEmailCommand.class) - .build(); + .register(); // Register the change command CommandDescription.builder() @@ -395,7 +395,7 @@ public class CommandInitializer { .withArgument("newEmail", "New email address", false) .permission(PlayerPermission.CHANGE_EMAIL) .executableCommand(ChangeEmailCommand.class) - .build(); + .register(); // Register the recover command CommandDescription.builder() @@ -408,7 +408,7 @@ public class CommandInitializer { .withArgument("code", "Recovery code", true) .permission(PlayerPermission.RECOVER_EMAIL) .executableCommand(RecoverEmailCommand.class) - .build(); + .register(); // Register the base captcha command CommandDescription CAPTCHA_BASE = CommandDescription.builder() @@ -419,7 +419,7 @@ public class CommandInitializer { .withArgument("captcha", "The Captcha", false) .permission(PlayerPermission.CAPTCHA) .executableCommand(CaptchaCommand.class) - .build(); + .register(); Set baseCommands = ImmutableSet.of( AUTHME_BASE, @@ -451,7 +451,7 @@ public class CommandInitializer { .detailedDescription("View detailed help for /" + base.getLabels().get(0) + " commands.") .withArgument("query", "The command or query to view help for.", true) .executableCommand(HelpCommand.class) - .build(); + .register(); } } } diff --git a/src/main/java/fr/xephi/authme/command/help/HelpMessagesService.java b/src/main/java/fr/xephi/authme/command/help/HelpMessagesService.java index b500e4310..c2cbaff99 100644 --- a/src/main/java/fr/xephi/authme/command/help/HelpMessagesService.java +++ b/src/main/java/fr/xephi/authme/command/help/HelpMessagesService.java @@ -67,6 +67,10 @@ public class HelpMessagesService implements Reloadable { return localCommand; } + public String getDescription(CommandDescription command) { + return getText(getCommandPath(command) + DESCRIPTION_SUFFIX, command::getDescription); + } + public String getMessage(HelpMessage message) { return messageFileHandler.getMessage(message.getKey()); } diff --git a/src/main/java/fr/xephi/authme/command/help/HelpProvider.java b/src/main/java/fr/xephi/authme/command/help/HelpProvider.java index dfcbe554e..413c42c10 100644 --- a/src/main/java/fr/xephi/authme/command/help/HelpProvider.java +++ b/src/main/java/fr/xephi/authme/command/help/HelpProvider.java @@ -249,7 +249,7 @@ public class HelpProvider implements Reloadable { String parentCommandPath = String.join(" ", parentLabels); for (CommandDescription child : command.getChildren()) { lines.add(" /" + parentCommandPath + " " + child.getLabels().get(0) - + ChatColor.GRAY + ChatColor.ITALIC + ": " + child.getDescription()); + + ChatColor.GRAY + ChatColor.ITALIC + ": " + helpMessagesService.getDescription(child)); } } diff --git a/src/main/java/fr/xephi/authme/permission/PlayerPermission.java b/src/main/java/fr/xephi/authme/permission/PlayerPermission.java index 48e2a4bc6..a42c9c9c8 100644 --- a/src/main/java/fr/xephi/authme/permission/PlayerPermission.java +++ b/src/main/java/fr/xephi/authme/permission/PlayerPermission.java @@ -41,7 +41,7 @@ public enum PlayerPermission implements PermissionNode { CHANGE_EMAIL("authme.player.email.change"), /** - * Command permission to recover an account using it's email address. + * Command permission to recover an account using its email address. */ RECOVER_EMAIL("authme.player.email.recover"), diff --git a/src/test/java/fr/xephi/authme/command/CommandUtilsTest.java b/src/test/java/fr/xephi/authme/command/CommandUtilsTest.java index 2d73549d8..173a0919f 100644 --- a/src/test/java/fr/xephi/authme/command/CommandUtilsTest.java +++ b/src/test/java/fr/xephi/authme/command/CommandUtilsTest.java @@ -19,14 +19,14 @@ public class CommandUtilsTest { .description("Base") .detailedDescription("Test base command.") .executableCommand(ExecutableCommand.class) - .build(); + .register(); CommandDescription command = CommandDescription.builder() .parent(base) .labels("help", "h", "?") .description("Child") .detailedDescription("Test child command.") .executableCommand(ExecutableCommand.class) - .build(); + .register(); // when String commandPath = CommandUtils.constructCommandPath(command); @@ -42,7 +42,7 @@ public class CommandUtilsTest { @Test public void shouldComputeMinAndMaxOnEmptyCommand() { // given - CommandDescription command = getBuilderForArgsTest().build(); + CommandDescription command = getBuilderForArgsTest().register(); // when / then checkArgumentCount(command, 0, 0); @@ -54,7 +54,7 @@ public class CommandUtilsTest { CommandDescription command = getBuilderForArgsTest() .withArgument("Test", "Arg description", false) .withArgument("Test22", "Arg description 2", false) - .build(); + .register(); // when / then checkArgumentCount(command, 2, 2); @@ -67,7 +67,7 @@ public class CommandUtilsTest { .withArgument("arg1", "Arg description", false) .withArgument("arg2", "Arg description 2", true) .withArgument("arg3", "Arg description 3", true) - .build(); + .register(); // when / then checkArgumentCount(command, 1, 3); diff --git a/src/test/java/fr/xephi/authme/command/TestCommandsUtil.java b/src/test/java/fr/xephi/authme/command/TestCommandsUtil.java index 285369973..9c5d469ab 100644 --- a/src/test/java/fr/xephi/authme/command/TestCommandsUtil.java +++ b/src/test/java/fr/xephi/authme/command/TestCommandsUtil.java @@ -42,7 +42,7 @@ public final class TestCommandsUtil { newArgument("player", true)); // Register /email helptest -- use only to test for help command arguments special case CommandDescription.builder().parent(emailBase).labels("helptest").executableCommand(HelpCommand.class) - .description("test").detailedDescription("Test.").withArgument("Query", "", false).build(); + .description("test").detailedDescription("Test.").withArgument("Query", "", false).register(); // Register /unregister , alias: /unreg CommandDescription unregisterBase = createCommand(AdminPermission.UNREGISTER, null, @@ -101,7 +101,7 @@ public final class TestCommandsUtil { } } - return command.build(); + return command.register(); } /** Shortcut command to initialize a new argument description. */ diff --git a/src/test/java/fr/xephi/authme/command/help/HelpMessagesServiceTest.java b/src/test/java/fr/xephi/authme/command/help/HelpMessagesServiceTest.java index a451ff4d2..3a9c993d1 100644 --- a/src/test/java/fr/xephi/authme/command/help/HelpMessagesServiceTest.java +++ b/src/test/java/fr/xephi/authme/command/help/HelpMessagesServiceTest.java @@ -16,6 +16,7 @@ import java.util.Set; import java.util.function.Function; import static fr.xephi.authme.TestHelper.getJarFile; +import static fr.xephi.authme.command.TestCommandsUtil.getCommandWithLabel; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.sameInstance; @@ -48,7 +49,7 @@ public class HelpMessagesServiceTest { @Test public void shouldReturnLocalizedCommand() { // given - CommandDescription command = TestCommandsUtil.getCommandWithLabel(COMMANDS, "authme", "register"); + CommandDescription command = getCommandWithLabel(COMMANDS, "authme", "register"); // when CommandDescription localCommand = helpMessagesService.buildLocalizedDescription(command); @@ -68,7 +69,7 @@ public class HelpMessagesServiceTest { @Test public void shouldReturnLocalizedCommandWithDefaults() { // given - CommandDescription command = TestCommandsUtil.getCommandWithLabel(COMMANDS, "authme", "login"); + CommandDescription command = getCommandWithLabel(COMMANDS, "authme", "login"); // when CommandDescription localCommand = helpMessagesService.buildLocalizedDescription(command); @@ -84,7 +85,7 @@ public class HelpMessagesServiceTest { @Test public void shouldReturnSameCommandForNoLocalization() { // given - CommandDescription command = TestCommandsUtil.getCommandWithLabel(COMMANDS, "email"); + CommandDescription command = getCommandWithLabel(COMMANDS, "email"); // when CommandDescription localCommand = helpMessagesService.buildLocalizedDescription(command); @@ -96,7 +97,7 @@ public class HelpMessagesServiceTest { @Test public void shouldKeepChildrenInLocalCommand() { // given - CommandDescription command = TestCommandsUtil.getCommandWithLabel(COMMANDS, "authme"); + CommandDescription command = getCommandWithLabel(COMMANDS, "authme"); // when CommandDescription localCommand = helpMessagesService.buildLocalizedDescription(command); @@ -114,4 +115,28 @@ public class HelpMessagesServiceTest { assertThat(helpMessagesService.getMessage(HelpMessage.RESULT), equalTo("res.")); assertThat(helpMessagesService.getMessage(HelpSection.ARGUMENTS), equalTo("arg.")); } + + @Test + public void shouldGetLocalCommandDescription() { + // given + CommandDescription command = getCommandWithLabel(COMMANDS, "authme", "register"); + + // when + String description = helpMessagesService.getDescription(command); + + // then + assertThat(description, equalTo("Registration")); + } + + @Test + public void shouldFallbackToDescriptionOnCommandObject() { + // given + CommandDescription command = getCommandWithLabel(COMMANDS, "unregister"); + + // when + String description = helpMessagesService.getDescription(command); + + // then + assertThat(description, equalTo(command.getDescription())); + } } diff --git a/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java b/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java index 0d3983ce5..1e8962f8d 100644 --- a/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java +++ b/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java @@ -251,6 +251,10 @@ public class HelpProviderTest { // given CommandDescription command = getCommandWithLabel(commands, "authme"); FoundCommandResult result = newFoundResult(command, Collections.singletonList("authme")); + given(helpMessagesService.getDescription(getCommandWithLabel(commands, "authme", "login"))) + .willReturn("Command for login [localized]"); + given(helpMessagesService.getDescription(getCommandWithLabel(commands, "authme", "register"))) + .willReturn("Registration command [localized]"); // when helpProvider.outputHelp(sender, result, SHOW_CHILDREN); @@ -258,9 +262,9 @@ public class HelpProviderTest { // then List lines = getLines(sender); assertThat(lines, hasSize(4)); - assertThat(lines.get(1), containsString("Children:")); - assertThat(lines.get(2), containsString("/authme login: login cmd")); - assertThat(lines.get(3), containsString("/authme register: register cmd")); + assertThat(lines.get(1), equalTo("Children:")); + assertThat(lines.get(2), equalTo(" /authme login: Command for login [localized]")); + assertThat(lines.get(3), equalTo(" /authme register: Registration command [localized]")); } @Test From 1867617dbb6e9de6e59917a94568dfa2dbc154af Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sat, 22 Oct 2016 00:46:28 +0200 Subject: [PATCH 09/25] Add option to override dbcp size --- src/main/java/fr/xephi/authme/datasource/MySQL.java | 7 ++++++- .../xephi/authme/settings/properties/DatabaseSettings.java | 4 ++++ src/main/resources/config.yml | 2 ++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index 9c613ec35..9da225b94 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -40,6 +40,7 @@ public class MySQL implements DataSource { private String password; private String database; private String tableName; + private int poolSize; private List columnOthers; private Columns col; private HashAlgorithm hashAlgorithm; @@ -98,6 +99,10 @@ public class MySQL implements DataSource { this.phpBbPrefix = settings.getProperty(HooksSettings.PHPBB_TABLE_PREFIX); this.phpBbGroup = settings.getProperty(HooksSettings.PHPBB_ACTIVATED_GROUP_ID); this.wordpressPrefix = settings.getProperty(HooksSettings.WORDPRESS_TABLE_PREFIX); + this.poolSize = settings.getProperty(DatabaseSettings.MYSQL_POOL_SIZE); + if(poolSize == -1) { + poolSize = RuntimeUtils.getCoreCount(); + } } private void setConnectionArguments() throws RuntimeException { @@ -105,7 +110,7 @@ public class MySQL implements DataSource { ds.setPoolName("AuthMeMYSQLPool"); // Pool size - ds.setMaximumPoolSize(RuntimeUtils.getCoreCount()); + ds.setMaximumPoolSize(poolSize); // Database URL ds.setJdbcUrl("jdbc:mysql://" + this.host + ":" + this.port + "/" + this.database); diff --git a/src/main/java/fr/xephi/authme/settings/properties/DatabaseSettings.java b/src/main/java/fr/xephi/authme/settings/properties/DatabaseSettings.java index 2dc769ec6..c82a7a81d 100644 --- a/src/main/java/fr/xephi/authme/settings/properties/DatabaseSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/DatabaseSettings.java @@ -98,6 +98,10 @@ public class DatabaseSettings implements SettingsHolder { public static final Property MYSQL_COL_GROUP = newProperty("ExternalBoardOptions.mySQLColumnGroup", ""); + @Comment("Overrides the size of the DB Connection Pool, -1 = Auto") + public static final Property MYSQL_POOL_SIZE = + newProperty("DataSource.poolSize", -1); + private DatabaseSettings() { } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index bed1d2c43..aba5a8658 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -40,6 +40,8 @@ DataSource: mySQLlastlocWorld: world # Column for RealName mySQLRealName: realname + # Overrides the size of the DB Connection Pool, -1 = Auto + poolSize: -1 settings: sessions: # Do you want to enable the session feature? From d09964f1cb7eeef9636813d0cb1274301205038d Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 23 Oct 2016 12:17:37 +0200 Subject: [PATCH 10/25] #963 Create tool task to generate plugin.yml - Create task that generates commands/permissions section of plugin.yml - Change CommandInitializer to return a List instead of Set (preserve insertion order) - Merge CommandSyntaxHelper into CommandUtils --- .../authme/command/CommandInitializer.java | 27 +- .../xephi/authme/command/CommandMapper.java | 3 +- .../fr/xephi/authme/command/CommandUtils.java | 41 ++ .../command/help/CommandSyntaxHelper.java | 36 -- .../authme/command/help/HelpProvider.java | 4 +- src/main/resources/plugin.yml | 380 +++++++++--------- .../command/CommandInitializerTest.java | 5 +- .../authme/command/CommandMapperTest.java | 2 +- .../authme/command/CommandUtilsTest.java | 54 +++ .../authme/command/TestCommandsUtil.java | 7 +- .../command/help/CommandSyntaxHelperTest.java | 76 ---- .../help/HelpMessagesConsistencyTest.java | 4 +- .../command/help/HelpMessagesServiceTest.java | 4 +- .../authme/command/help/HelpProviderTest.java | 4 +- .../permission/PermissionConsistencyTest.java | 2 +- .../docs/commands/CommandPageCreater.java | 3 +- .../permissions/PermissionNodesGatherer.java | 30 +- .../filegeneration/GeneratePluginYml.java | 182 +++++++++ 18 files changed, 527 insertions(+), 337 deletions(-) delete mode 100644 src/main/java/fr/xephi/authme/command/help/CommandSyntaxHelper.java delete mode 100644 src/test/java/fr/xephi/authme/command/help/CommandSyntaxHelperTest.java create mode 100644 src/test/java/tools/filegeneration/GeneratePluginYml.java diff --git a/src/main/java/fr/xephi/authme/command/CommandInitializer.java b/src/main/java/fr/xephi/authme/command/CommandInitializer.java index 60eec7905..7e01e0e30 100644 --- a/src/main/java/fr/xephi/authme/command/CommandInitializer.java +++ b/src/main/java/fr/xephi/authme/command/CommandInitializer.java @@ -1,6 +1,6 @@ package fr.xephi.authme.command; -import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableList; import fr.xephi.authme.command.executable.HelpCommand; import fr.xephi.authme.command.executable.authme.AccountsCommand; import fr.xephi.authme.command.executable.authme.AuthMeCommand; @@ -41,14 +41,13 @@ import fr.xephi.authme.permission.PlayerPermission; import java.util.Arrays; import java.util.Collection; import java.util.List; -import java.util.Set; /** * Initializes all available AuthMe commands. */ public class CommandInitializer { - private Set commands; + private List commands; public CommandInitializer() { buildCommands(); @@ -59,7 +58,7 @@ public class CommandInitializer { * * @return the command descriptions */ - public Set getCommands() { + public List getCommands() { return commands; } @@ -67,7 +66,7 @@ public class CommandInitializer { // Register the base AuthMe Reloaded command final CommandDescription AUTHME_BASE = CommandDescription.builder() .labels("authme") - .description("Main command") + .description("AuthMe op commands") .detailedDescription("The main AuthMeReloaded command. The root for all admin commands.") .executableCommand(AuthMeCommand.class) .register(); @@ -324,7 +323,7 @@ public class CommandInitializer { final CommandDescription REGISTER_BASE = CommandDescription.builder() .parent(null) .labels("register", "reg") - .description("Registration command") + .description("Register an account") .detailedDescription("Command to register using AuthMeReloaded.") .withArgument("password", "Password", true) .withArgument("verifyPassword", "Verify password", true) @@ -336,7 +335,7 @@ public class CommandInitializer { CommandDescription UNREGISTER_BASE = CommandDescription.builder() .parent(null) .labels("unregister", "unreg") - .description("Unregistration Command") + .description("Unregister an account") .detailedDescription("Command to unregister using AuthMeReloaded.") .withArgument("password", "Password", false) .permission(PlayerPermission.UNREGISTER) @@ -347,10 +346,10 @@ public class CommandInitializer { final CommandDescription CHANGE_PASSWORD_BASE = CommandDescription.builder() .parent(null) .labels("changepassword", "changepass", "cp") - .description("Change password Command") + .description("Change password of an account") .detailedDescription("Command to change your password using AuthMeReloaded.") - .withArgument("oldPassword", "Old Password", false) - .withArgument("newPassword", "New Password.", false) + .withArgument("oldPassword", "Old password", false) + .withArgument("newPassword", "New password", false) .permission(PlayerPermission.CHANGE_PASSWORD) .executableCommand(ChangePasswordCommand.class) .register(); @@ -359,8 +358,8 @@ public class CommandInitializer { CommandDescription EMAIL_BASE = CommandDescription.builder() .parent(null) .labels("email") - .description("Email command") - .detailedDescription("The AuthMeReloaded Email command base.") + .description("Add email or recover password") + .detailedDescription("The AuthMeReloaded email command base.") .executableCommand(EmailBaseCommand.class) .register(); @@ -401,7 +400,7 @@ public class CommandInitializer { CommandDescription.builder() .parent(EMAIL_BASE) .labels("recover", "recovery", "recoveremail", "recovermail") - .description("Recover password using Email") + .description("Recover password using email") .detailedDescription("Recover your account using an Email address by sending a mail containing " + "a new password.") .withArgument("email", "Email address", false) @@ -421,7 +420,7 @@ public class CommandInitializer { .executableCommand(CaptchaCommand.class) .register(); - Set baseCommands = ImmutableSet.of( + List baseCommands = ImmutableList.of( AUTHME_BASE, LOGIN_BASE, LOGOUT_BASE, diff --git a/src/main/java/fr/xephi/authme/command/CommandMapper.java b/src/main/java/fr/xephi/authme/command/CommandMapper.java index 44d5b5833..e36664929 100644 --- a/src/main/java/fr/xephi/authme/command/CommandMapper.java +++ b/src/main/java/fr/xephi/authme/command/CommandMapper.java @@ -8,6 +8,7 @@ import org.bukkit.command.CommandSender; import javax.inject.Inject; import java.util.ArrayList; +import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -26,7 +27,7 @@ public class CommandMapper { */ private static final Class HELP_COMMAND_CLASS = HelpCommand.class; - private final Set baseCommands; + private final Collection baseCommands; private final PermissionsManager permissionsManager; @Inject diff --git a/src/main/java/fr/xephi/authme/command/CommandUtils.java b/src/main/java/fr/xephi/authme/command/CommandUtils.java index 9ea1f5c55..699e4f37e 100644 --- a/src/main/java/fr/xephi/authme/command/CommandUtils.java +++ b/src/main/java/fr/xephi/authme/command/CommandUtils.java @@ -1,9 +1,11 @@ package fr.xephi.authme.command; import com.google.common.collect.Lists; +import org.bukkit.ChatColor; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; public final class CommandUtils { @@ -34,6 +36,14 @@ public final class CommandUtils { return sb.toString(); } + /** + * Constructs a hierarchical list of commands for the given command. The commands are in order: + * the parents of the given command precede the provided command. For example, given the command + * for {@code /authme register}, a list with {@code [{authme}, {authme register}]} is returned. + * + * @param command the command to build a parent list for + * @return the parent list + */ public static List constructParentList(CommandDescription command) { List commands = new ArrayList<>(); CommandDescription currentCommand = command; @@ -43,4 +53,35 @@ public final class CommandUtils { } return Lists.reverse(commands); } + + public static String buildSyntax(CommandDescription command) { + String arguments = command.getArguments().stream() + .map(arg -> formatArgument(arg)) + .collect(Collectors.joining(" ")); + return (constructCommandPath(command) + " " + arguments).trim(); + } + + public static String buildSyntax(CommandDescription command, List correctLabels) { + String commandSyntax = ChatColor.WHITE + "/" + correctLabels.get(0) + ChatColor.YELLOW; + for (int i = 1; i < correctLabels.size(); ++i) { + commandSyntax += " " + correctLabels.get(i); + } + for (CommandArgumentDescription argument : command.getArguments()) { + commandSyntax += " " + formatArgument(argument); + } + return commandSyntax; + } + + /** + * Format a command argument with the proper type of brackets. + * + * @param argument the argument to format + * @return the formatted argument + */ + public static String formatArgument(CommandArgumentDescription argument) { + if (argument.isOptional()) { + return "[" + argument.getName() + "]"; + } + return "<" + argument.getName() + ">"; + } } diff --git a/src/main/java/fr/xephi/authme/command/help/CommandSyntaxHelper.java b/src/main/java/fr/xephi/authme/command/help/CommandSyntaxHelper.java deleted file mode 100644 index 86ffb5427..000000000 --- a/src/main/java/fr/xephi/authme/command/help/CommandSyntaxHelper.java +++ /dev/null @@ -1,36 +0,0 @@ -package fr.xephi.authme.command.help; - -import fr.xephi.authme.command.CommandArgumentDescription; -import fr.xephi.authme.command.CommandDescription; -import org.bukkit.ChatColor; - -import java.util.List; - -/** - * Helper class for displaying the syntax of a command properly to a user. - */ -final class CommandSyntaxHelper { - - private CommandSyntaxHelper() { - } - - public static String getSyntax(CommandDescription command, List correctLabels) { - String commandSyntax = ChatColor.WHITE + "/" + correctLabels.get(0) + ChatColor.YELLOW; - for (int i = 1; i < correctLabels.size(); ++i) { - commandSyntax += " " + correctLabels.get(i); - } - for (CommandArgumentDescription argument : command.getArguments()) { - commandSyntax += " " + formatArgument(argument); - } - return commandSyntax; - } - - /** Format a command argument with the proper type of brackets. */ - private static String formatArgument(CommandArgumentDescription argument) { - if (argument.isOptional()) { - return "[" + argument.getName() + "]"; - } - return "<" + argument.getName() + ">"; - } - -} diff --git a/src/main/java/fr/xephi/authme/command/help/HelpProvider.java b/src/main/java/fr/xephi/authme/command/help/HelpProvider.java index 413c42c10..23e87cab6 100644 --- a/src/main/java/fr/xephi/authme/command/help/HelpProvider.java +++ b/src/main/java/fr/xephi/authme/command/help/HelpProvider.java @@ -80,7 +80,7 @@ public class HelpProvider implements Reloadable { if (hasFlag(SHOW_COMMAND, options)) { lines.add(ChatColor.GOLD + helpMessagesService.getMessage(HelpSection.COMMAND) + ": " - + CommandSyntaxHelper.getSyntax(command, correctLabels)); + + CommandUtils.buildSyntax(command, correctLabels)); } if (hasFlag(SHOW_DESCRIPTION, options)) { lines.add(ChatColor.GOLD + helpMessagesService.getMessage(SHORT_DESCRIPTION) + ": " @@ -194,7 +194,7 @@ public class HelpProvider implements Reloadable { // Create a list of alternatives for (String label : command.getLabels()) { if (!label.equalsIgnoreCase(usedLabel)) { - lines.add(" " + CommandSyntaxHelper.getSyntax(command, commandLabelsFn.apply(label))); + lines.add(" " + CommandUtils.buildSyntax(command, commandLabelsFn.apply(label))); } } } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 90ee29bff..9ca68c314 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -15,191 +15,197 @@ softdepend: - EssentialsSpawn - ProtocolLib commands: - authme: - description: AuthMe op commands - usage: '/authme reload|register playername password|changepassword playername password|unregister playername|version|converter' - register: - description: Register an account - usage: /register - aliases: [reg] - login: - description: Login command - usage: /login - aliases: [l,log] - changepassword: - description: Change password of an account - usage: /changepassword - aliases: [cp,changepass] - logout: - description: Logout - usage: /logout - unregister: - description: Unregister your account - usage: /unregister - aliases: [unreg] - email: - description: Add Email or recover password - usage: '/email add your@email.com your@email.com|change oldEmail newEmail|recovery your@email.com' - captcha: - description: Captcha command - usage: /captcha + authme: + description: AuthMe op commands + usage: /authme register|unregister|forcelogin|password|lastlogin|accounts|email|setemail|getip|spawn|setspawn|firstspawn|setfirstspawn|purge|resetpos|purgebannedplayers|switchantibot|reload|version|converter|messages + login: + description: Login command + usage: /login + aliases: + - l + - log + logout: + description: Logout command + usage: /logout + register: + description: Register an account + usage: /register [password] [verifyPassword] + aliases: + - reg + unregister: + description: Unregister an account + usage: /unregister + aliases: + - unreg + changepassword: + description: Change password of an account + usage: /changepassword + aliases: + - changepass + - cp + email: + description: Add email or recover password + usage: /email show|add|change|recover + captcha: + description: Captcha Command + usage: /captcha permissions: - authme.admin.*: - description: Give access to all admin commands. - children: - authme.admin.accounts: true - authme.admin.antibotmessages: true - authme.admin.changemail: true - authme.admin.changepassword: true - authme.admin.converter: true - authme.admin.firstspawn: true - authme.admin.forcelogin: true - authme.admin.getemail: true - authme.admin.getip: true - authme.admin.lastlogin: true - authme.admin.purge: true - authme.admin.purgebannedplayers: true - authme.admin.purgelastpos: true - authme.admin.register: true - authme.admin.reload: true - authme.admin.setfirstspawn: true - authme.admin.setspawn: true - authme.admin.spawn: true - authme.admin.switchantibot: true - authme.admin.unregister: true - authme.admin.updatemessages: true - authme.admin.register: - description: Administrator command to register a new user. - default: op - authme.admin.unregister: - description: Administrator command to unregister an existing user. - default: op - authme.admin.forcelogin: - description: Administrator command to force-login an existing user. - default: op - authme.admin.changepassword: - description: Administrator command to change the password of a user. - default: op - authme.admin.lastlogin: - description: Administrator command to see the last login date and time of a user. - default: op - authme.admin.accounts: - description: Administrator command to see all accounts associated with a user. - default: op - authme.admin.getemail: - description: Administrator command to get the email address of a user, if set. - default: op - authme.admin.changemail: - description: Administrator command to set or change the email address of a user. - default: op - authme.admin.getip: - description: Administrator command to get the last known IP of a user. - default: op - authme.admin.spawn: - description: Administrator command to teleport to the AuthMe spawn. - default: op - authme.admin.setspawn: - description: Administrator command to set the AuthMe spawn. - default: op - authme.admin.firstspawn: - description: Administrator command to teleport to the first AuthMe spawn. - default: op - authme.admin.setfirstspawn: - description: Administrator command to set the first AuthMe spawn. - default: op - authme.admin.purge: - description: Administrator command to purge old user data. - default: op - authme.admin.purgelastpos: - description: Administrator command to purge the last position of a user. - default: op - authme.admin.purgebannedplayers: - description: Administrator command to purge all data associated with banned players. - default: op - authme.admin.seeotheraccounts: - description: Permission for user to see other accounts. - default: op - authme.admin.switchantibot: - description: Administrator command to toggle the AntiBot protection status. - default: op - authme.admin.converter: - description: Administrator command to convert old or other data to AuthMe data. - default: op - authme.admin.reload: - description: Administrator command to reload the plugin configuration. - default: op - authme.admin.antibotmessages: - description: Permission to see Antibot messages. - default: op - authme.admin.updatemessages: - description: Permission to use the update messages command. - default: op - authme.player.*: - description: Permission to use all player (non-admin) commands. - children: - authme.player.canbeforced: true - authme.player.captcha: true - authme.player.changepassword: true - authme.player.email.add: true - authme.player.email.change: true - authme.player.email.recover: true - authme.player.login: true - authme.player.logout: true - authme.player.register: true - authme.player.unregister: true - authme.player.seeownaccounts: true - authme.player.email: - description: Gives access to player email commands - default: false - children: - authme.player.email.add: true - authme.player.email.change: true - authme.player.email.recover: true - authme.player.login: - description: Command permission to login. - default: true - authme.player.logout: - description: Command permission to logout. - default: true - authme.player.register: - description: Command permission to register. - default: true - authme.player.unregister: - description: Command permission to unregister. - default: true - authme.player.changepassword: - description: Command permission to change the password. - default: true - authme.player.email.add: - description: Command permission to add an email address. - default: true - authme.player.email.change: - description: Command permission to change the email address. - default: true - authme.player.email.recover: - description: Command permission to recover an account using its email address. - default: true - authme.player.captcha: - description: Command permission to use captcha. - default: true - authme.player.canbeforced: - description: Permission for users a login can be forced to. - default: true - authme.player.seeownaccounts: - description: Permission to use to see own other accounts. - default: true - authme.vip: - description: Allow vip slot when the server is full - default: op - authme.bypassantibot: - description: Bypass the AntiBot check - default: op - authme.allowmultipleaccounts: - description: Allow more accounts for same ip - default: op - authme.bypassforcesurvival: - description: Bypass all ForceSurvival features - default: op - authme.bypasspurge: - description: Permission to bypass the purging process - default: false + authme.admin.*: + description: Gives access to all admin commands + children: + authme.admin.accounts: true + authme.admin.antibotmessages: true + authme.admin.changemail: true + authme.admin.changepassword: true + authme.admin.converter: true + authme.admin.firstspawn: true + authme.admin.forcelogin: true + authme.admin.getemail: true + authme.admin.getip: true + authme.admin.lastlogin: true + authme.admin.purge: true + authme.admin.purgebannedplayers: true + authme.admin.purgelastpos: true + authme.admin.register: true + authme.admin.reload: true + authme.admin.seeotheraccounts: true + authme.admin.setfirstspawn: true + authme.admin.setspawn: true + authme.admin.spawn: true + authme.admin.switchantibot: true + authme.admin.unregister: true + authme.admin.updatemessages: true + authme.admin.accounts: + description: Administrator command to see all accounts associated with a user. + default: op + authme.admin.antibotmessages: + description: Permission to see Antibot messages. + default: op + authme.admin.changemail: + description: Administrator command to set or change the email address of a user. + default: op + authme.admin.changepassword: + description: Administrator command to change the password of a user. + default: op + authme.admin.converter: + description: Administrator command to convert old or other data to AuthMe data. + default: op + authme.admin.firstspawn: + description: Administrator command to teleport to the first AuthMe spawn. + default: op + authme.admin.forcelogin: + description: Administrator command to force-login an existing user. + default: op + authme.admin.getemail: + description: Administrator command to get the email address of a user, if set. + default: op + authme.admin.getip: + description: Administrator command to get the last known IP of a user. + default: op + authme.admin.lastlogin: + description: Administrator command to see the last login date and time of a user. + default: op + authme.admin.purge: + description: Administrator command to purge old user data. + default: op + authme.admin.purgebannedplayers: + description: Administrator command to purge all data associated with banned players. + default: op + authme.admin.purgelastpos: + description: Administrator command to purge the last position of a user. + default: op + authme.admin.register: + description: Administrator command to register a new user. + default: op + authme.admin.reload: + description: Administrator command to reload the plugin configuration. + default: op + authme.admin.seeotheraccounts: + description: Permission to see the other accounts of the players that log in. + default: op + authme.admin.setfirstspawn: + description: Administrator command to set the first AuthMe spawn. + default: op + authme.admin.setspawn: + description: Administrator command to set the AuthMe spawn. + default: op + authme.admin.spawn: + description: Administrator command to teleport to the AuthMe spawn. + default: op + authme.admin.switchantibot: + description: Administrator command to toggle the AntiBot protection status. + default: op + authme.admin.unregister: + description: Administrator command to unregister an existing user. + default: op + authme.admin.updatemessages: + description: Permission to use the update messages command. + default: op + authme.allowmultipleaccounts: + description: Permission to be able to register multiple accounts. + default: op + authme.bypassantibot: + description: Permission node to bypass AntiBot protection. + default: op + authme.bypassforcesurvival: + description: Permission for users to bypass force-survival mode. + default: op + authme.bypasspurge: + description: Permission to bypass the purging process. + default: false + authme.player.*: + description: Gives access to all player commands + children: + authme.player.canbeforced: true + authme.player.captcha: true + authme.player.changepassword: true + authme.player.email.add: true + authme.player.email.change: true + authme.player.email.recover: true + authme.player.login: true + authme.player.logout: true + authme.player.register: true + authme.player.seeownaccounts: true + authme.player.unregister: true + authme.player.canbeforced: + description: Permission for users a login can be forced to. + default: true + authme.player.captcha: + description: Command permission to use captcha. + default: true + authme.player.changepassword: + description: Command permission to change the password. + default: true + authme.player.email: + description: Gives access to all email commands + children: + authme.player.email.add: true + authme.player.email.change: true + authme.player.email.recover: true + authme.player.email.add: + description: Command permission to add an email address. + default: true + authme.player.email.change: + description: Command permission to change the email address. + default: true + authme.player.email.recover: + description: Command permission to recover an account using its email address. + default: true + authme.player.login: + description: Command permission to login. + default: true + authme.player.logout: + description: Command permission to logout. + default: true + authme.player.register: + description: Command permission to register. + default: true + authme.player.seeownaccounts: + description: Permission to use to see own other accounts. + default: true + authme.player.unregister: + description: Command permission to unregister. + default: true + authme.vip: + description: Permission node to identify VIP users. + default: op diff --git a/src/test/java/fr/xephi/authme/command/CommandInitializerTest.java b/src/test/java/fr/xephi/authme/command/CommandInitializerTest.java index 944424f52..a4e51e28c 100644 --- a/src/test/java/fr/xephi/authme/command/CommandInitializerTest.java +++ b/src/test/java/fr/xephi/authme/command/CommandInitializerTest.java @@ -18,6 +18,7 @@ import java.util.regex.Pattern; import static fr.xephi.authme.permission.DefaultPermission.OP_ONLY; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; @@ -32,7 +33,7 @@ public class CommandInitializerTest { */ private static int MAX_ALLOWED_DEPTH = 1; - private static Set commands; + private static Collection commands; @BeforeClass public static void initializeCommandCollection() { @@ -46,7 +47,7 @@ public class CommandInitializerTest { // It obviously doesn't make sense to test much of the concrete data // that is being initialized; we just want to guarantee with this test // that data is indeed being initialized and we take a few "probes" - assertThat(commands.size(), equalTo(8)); + assertThat(commands, hasSize(8)); assertThat(commandsIncludeLabel(commands, "authme"), equalTo(true)); assertThat(commandsIncludeLabel(commands, "register"), equalTo(true)); assertThat(commandsIncludeLabel(commands, "help"), equalTo(false)); diff --git a/src/test/java/fr/xephi/authme/command/CommandMapperTest.java b/src/test/java/fr/xephi/authme/command/CommandMapperTest.java index 3fd023a4e..46efdaec4 100644 --- a/src/test/java/fr/xephi/authme/command/CommandMapperTest.java +++ b/src/test/java/fr/xephi/authme/command/CommandMapperTest.java @@ -39,7 +39,7 @@ import static org.mockito.Mockito.mock; @RunWith(DelayedInjectionRunner.class) public class CommandMapperTest { - private static Set commands; + private static List commands; @InjectDelayed private CommandMapper mapper; diff --git a/src/test/java/fr/xephi/authme/command/CommandUtilsTest.java b/src/test/java/fr/xephi/authme/command/CommandUtilsTest.java index 173a0919f..c0b4771cd 100644 --- a/src/test/java/fr/xephi/authme/command/CommandUtilsTest.java +++ b/src/test/java/fr/xephi/authme/command/CommandUtilsTest.java @@ -1,8 +1,15 @@ package fr.xephi.authme.command; import fr.xephi.authme.TestHelper; +import org.bukkit.ChatColor; +import org.junit.BeforeClass; import org.junit.Test; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; @@ -11,6 +18,13 @@ import static org.junit.Assert.assertThat; */ public class CommandUtilsTest { + private static Collection commands; + + @BeforeClass + public static void setUpTestCommands() { + commands = TestCommandsUtil.generateCommands(); + } + @Test public void shouldReturnCommandPath() { // given @@ -79,6 +93,46 @@ public class CommandUtilsTest { TestHelper.validateHasOnlyPrivateEmptyConstructor(CommandUtils.class); } + @Test + public void shouldFormatSimpleArgument() { + // given + CommandDescription command = TestCommandsUtil.getCommandWithLabel(commands, "authme"); + List labels = Collections.singletonList("authme"); + + // when + String result = CommandUtils.buildSyntax(command, labels); + + // then + assertThat(result, equalTo(ChatColor.WHITE + "/authme" + ChatColor.YELLOW)); + } + + @Test + public void shouldFormatCommandWithMultipleArguments() { + // given + CommandDescription command = TestCommandsUtil.getCommandWithLabel(commands, "authme", "register"); + List labels = Arrays.asList("authme", "reg"); + + // when + String result = CommandUtils.buildSyntax(command, labels); + + // then + assertThat(result, equalTo(ChatColor.WHITE + "/authme" + ChatColor.YELLOW + " reg ")); + } + + + @Test + public void shouldFormatCommandWithOptionalArgument() { + // given + CommandDescription command = TestCommandsUtil.getCommandWithLabel(commands, "email"); + List labels = Collections.singletonList("email"); + + // when + String result = CommandUtils.buildSyntax(command, labels); + + // then + assertThat(result, equalTo(ChatColor.WHITE + "/email" + ChatColor.YELLOW + " [player]")); + } + private static void checkArgumentCount(CommandDescription command, int expectedMin, int expectedMax) { assertThat(CommandUtils.getMinNumberOfArguments(command), equalTo(expectedMin)); diff --git a/src/test/java/fr/xephi/authme/command/TestCommandsUtil.java b/src/test/java/fr/xephi/authme/command/TestCommandsUtil.java index 9c5d469ab..9f9b02ca2 100644 --- a/src/test/java/fr/xephi/authme/command/TestCommandsUtil.java +++ b/src/test/java/fr/xephi/authme/command/TestCommandsUtil.java @@ -1,5 +1,6 @@ package fr.xephi.authme.command; +import com.google.common.collect.ImmutableList; import fr.xephi.authme.command.executable.HelpCommand; import fr.xephi.authme.permission.AdminPermission; import fr.xephi.authme.permission.PermissionNode; @@ -8,9 +9,7 @@ import org.bukkit.command.CommandSender; import java.util.Collection; import java.util.List; -import java.util.Set; -import static com.google.common.collect.Sets.newHashSet; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; @@ -27,7 +26,7 @@ public final class TestCommandsUtil { * * @return The generated commands */ - public static Set generateCommands() { + public static List generateCommands() { // Register /authme CommandDescription authMeBase = createCommand(null, null, singletonList("authme"), ExecutableCommand.class); // Register /authme login @@ -48,7 +47,7 @@ public final class TestCommandsUtil { CommandDescription unregisterBase = createCommand(AdminPermission.UNREGISTER, null, asList("unregister", "unreg"), TestUnregisterCommand.class, newArgument("player", false)); - return newHashSet(authMeBase, emailBase, unregisterBase); + return ImmutableList.of(authMeBase, emailBase, unregisterBase); } /** diff --git a/src/test/java/fr/xephi/authme/command/help/CommandSyntaxHelperTest.java b/src/test/java/fr/xephi/authme/command/help/CommandSyntaxHelperTest.java deleted file mode 100644 index 77320d151..000000000 --- a/src/test/java/fr/xephi/authme/command/help/CommandSyntaxHelperTest.java +++ /dev/null @@ -1,76 +0,0 @@ -package fr.xephi.authme.command.help; - -import fr.xephi.authme.TestHelper; -import fr.xephi.authme.command.CommandDescription; -import fr.xephi.authme.command.TestCommandsUtil; -import org.bukkit.ChatColor; -import org.junit.BeforeClass; -import org.junit.Test; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; - -/** - * Test for {@link CommandSyntaxHelper}. - */ -public class CommandSyntaxHelperTest { - - private static Set commands; - - @BeforeClass - public static void setUpTestCommands() { - commands = TestCommandsUtil.generateCommands(); - } - - @Test - public void shouldFormatSimpleArgument() { - // given - CommandDescription command = TestCommandsUtil.getCommandWithLabel(commands, "authme"); - List labels = Collections.singletonList("authme"); - - // when - String result = CommandSyntaxHelper.getSyntax(command, labels); - - // then - assertThat(result, equalTo(ChatColor.WHITE + "/authme" + ChatColor.YELLOW)); - } - - @Test - public void shouldFormatCommandWithMultipleArguments() { - // given - CommandDescription command = TestCommandsUtil.getCommandWithLabel(commands, "authme", "register"); - List labels = Arrays.asList("authme", "reg"); - - // when - String result = CommandSyntaxHelper.getSyntax(command, labels); - - // then - assertThat(result, equalTo(ChatColor.WHITE + "/authme" + ChatColor.YELLOW + " reg ")); - } - - - @Test - public void shouldFormatCommandWithOptionalArgument() { - // given - CommandDescription command = TestCommandsUtil.getCommandWithLabel(commands, "email"); - List labels = Collections.singletonList("email"); - - // when - String result = CommandSyntaxHelper.getSyntax(command, labels); - - // then - assertThat(result, equalTo(ChatColor.WHITE + "/email" + ChatColor.YELLOW + " [player]")); - } - - @Test - public void shouldHaveHiddenConstructor() { - // given / when / then - TestHelper.validateHasOnlyPrivateEmptyConstructor(CommandSyntaxHelper.class); - } - -} diff --git a/src/test/java/fr/xephi/authme/command/help/HelpMessagesConsistencyTest.java b/src/test/java/fr/xephi/authme/command/help/HelpMessagesConsistencyTest.java index 7c50829f8..5e79ef993 100644 --- a/src/test/java/fr/xephi/authme/command/help/HelpMessagesConsistencyTest.java +++ b/src/test/java/fr/xephi/authme/command/help/HelpMessagesConsistencyTest.java @@ -9,8 +9,8 @@ import org.bukkit.configuration.file.YamlConfiguration; import org.junit.Test; import java.io.File; +import java.util.Collection; import java.util.List; -import java.util.Set; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.equalTo; @@ -78,7 +78,7 @@ public class HelpMessagesConsistencyTest { * @return the CommandDescription object for the {@code /authme register} command. */ private static CommandDescription getAuthMeRegisterDescription() { - Set commands = new CommandInitializer().getCommands(); + Collection commands = new CommandInitializer().getCommands(); List children = commands.stream() .filter(command -> command.getLabels().contains("authme")) diff --git a/src/test/java/fr/xephi/authme/command/help/HelpMessagesServiceTest.java b/src/test/java/fr/xephi/authme/command/help/HelpMessagesServiceTest.java index 3a9c993d1..150bb42f5 100644 --- a/src/test/java/fr/xephi/authme/command/help/HelpMessagesServiceTest.java +++ b/src/test/java/fr/xephi/authme/command/help/HelpMessagesServiceTest.java @@ -12,7 +12,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import java.util.Set; +import java.util.Collection; import java.util.function.Function; import static fr.xephi.authme.TestHelper.getJarFile; @@ -31,7 +31,7 @@ import static org.mockito.Matchers.any; public class HelpMessagesServiceTest { private static final String TEST_FILE = "/fr/xephi/authme/command/help/help_test.yml"; - private static final Set COMMANDS = TestCommandsUtil.generateCommands(); + private static final Collection COMMANDS = TestCommandsUtil.generateCommands(); @InjectDelayed private HelpMessagesService helpMessagesService; diff --git a/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java b/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java index 1e8962f8d..e90a76120 100644 --- a/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java +++ b/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java @@ -20,9 +20,9 @@ import org.mockito.Mock; import org.mockito.internal.stubbing.answers.ReturnsArgumentAt; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Set; import java.util.stream.Collectors; import static fr.xephi.authme.command.TestCommandsUtil.getCommandWithLabel; @@ -53,7 +53,7 @@ import static org.mockito.Mockito.verify; @RunWith(DelayedInjectionRunner.class) public class HelpProviderTest { - private static Set commands; + private static Collection commands; @InjectDelayed private HelpProvider helpProvider; diff --git a/src/test/java/fr/xephi/authme/permission/PermissionConsistencyTest.java b/src/test/java/fr/xephi/authme/permission/PermissionConsistencyTest.java index bd18df8ad..f44ef2220 100644 --- a/src/test/java/fr/xephi/authme/permission/PermissionConsistencyTest.java +++ b/src/test/java/fr/xephi/authme/permission/PermissionConsistencyTest.java @@ -26,7 +26,7 @@ public class PermissionConsistencyTest { /** All classes defining permission nodes. */ private static final Set> PERMISSION_CLASSES = ImmutableSet - .>of(PlayerPermission.class, AdminPermission.class, PlayerStatePermission.class); + .of(PlayerPermission.class, AdminPermission.class, PlayerStatePermission.class); /** Wildcard permissions (present in plugin.yml but not in the codebase). */ private static final Set PLUGIN_YML_PERMISSIONS_WILDCARDS = diff --git a/src/test/java/tools/docs/commands/CommandPageCreater.java b/src/test/java/tools/docs/commands/CommandPageCreater.java index 6a2f5edfe..b975c34f5 100644 --- a/src/test/java/tools/docs/commands/CommandPageCreater.java +++ b/src/test/java/tools/docs/commands/CommandPageCreater.java @@ -13,7 +13,6 @@ import tools.utils.ToolsConstants; import java.util.Collection; import java.util.Scanner; -import java.util.Set; public class CommandPageCreater implements AutoToolTask { @@ -32,7 +31,7 @@ public class CommandPageCreater implements AutoToolTask { @Override public void executeDefault() { CommandInitializer commandInitializer = new CommandInitializer(); - final Set baseCommands = commandInitializer.getCommands(); + final Collection baseCommands = commandInitializer.getCommands(); NestedTagValue commandTags = new NestedTagValue(); addCommandsInfo(commandTags, baseCommands); diff --git a/src/test/java/tools/docs/permissions/PermissionNodesGatherer.java b/src/test/java/tools/docs/permissions/PermissionNodesGatherer.java index f6221ac5f..034677cb8 100644 --- a/src/test/java/tools/docs/permissions/PermissionNodesGatherer.java +++ b/src/test/java/tools/docs/permissions/PermissionNodesGatherer.java @@ -7,10 +7,12 @@ import tools.utils.ToolsConstants; import java.util.EnumSet; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; /** * Gatherer to generate up-to-date lists of the AuthMe permission nodes. @@ -27,6 +29,11 @@ public class PermissionNodesGatherer { + "(.*?)\\s+\\*/" // Capture everything until we encounter '*/' + "\\s+([A-Z_]+)\\("); // Match the enum name (e.g. 'LOGIN'), until before the first '(' + /** + * List of all enum classes that implement the {@link PermissionNode} interface. + */ + private List> permissionClasses; + /** * Return a sorted collection of all permission nodes, including its JavaDoc description. * @@ -39,14 +46,27 @@ public class PermissionNodesGatherer { result.put("authme.player.*", "Permission to use all player (non-admin) commands."); result.put("authme.player.email", "Grants all email permissions."); - new ClassCollector(ToolsConstants.MAIN_SOURCE_ROOT, "") - .collectClasses(PermissionNode.class) - .stream() - .filter(Class::isEnum) - .forEach(clz -> addDescriptionsForClass((Class) clz, result)); + getPermissionClasses().forEach(clz -> addDescriptionsForClass((Class) clz, result)); return result; } + /** + * Return all enum classes implementing the PermissionNode interface. + * + * @return all permission node enums + */ + public List> getPermissionClasses() { + if (permissionClasses == null) { + ClassCollector classCollector = new ClassCollector(ToolsConstants.MAIN_SOURCE_ROOT, ""); + permissionClasses = classCollector + .collectClasses(PermissionNode.class) + .stream() + .filter(Class::isEnum) + .collect(Collectors.toList()); + } + return permissionClasses; + } + private & PermissionNode> void addDescriptionsForClass(Class clazz, Map descriptions) { String classSource = getSourceForClass(clazz); diff --git a/src/test/java/tools/filegeneration/GeneratePluginYml.java b/src/test/java/tools/filegeneration/GeneratePluginYml.java new file mode 100644 index 000000000..c3d332f24 --- /dev/null +++ b/src/test/java/tools/filegeneration/GeneratePluginYml.java @@ -0,0 +1,182 @@ +package tools.filegeneration; + +import com.google.common.collect.ImmutableMap; +import fr.xephi.authme.command.CommandDescription; +import fr.xephi.authme.command.CommandInitializer; +import fr.xephi.authme.command.CommandUtils; +import fr.xephi.authme.permission.DefaultPermission; +import fr.xephi.authme.permission.PermissionNode; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import tools.docs.permissions.PermissionNodesGatherer; +import tools.utils.AutoToolTask; +import tools.utils.FileUtils; +import tools.utils.ToolsConstants; + +import java.io.StringReader; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Scanner; +import java.util.TreeMap; +import java.util.stream.Collectors; + +/** + * Generates the command and permission section of plugin.yml. + */ +public class GeneratePluginYml implements AutoToolTask { + + private static final String PLUGIN_YML_FILE = ToolsConstants.MAIN_RESOURCES_ROOT + "plugin.yml"; + + private static final Map WILDCARD_PERMISSIONS = ImmutableMap.of( + "authme.player.*", "Gives access to all player commands", + "authme.admin.*", "Gives access to all admin commands", + "authme.player.email", "Gives access to all email commands"); + + private List permissionNodes; + + private String pluginYmlStart; + + @Override + public void executeDefault() { + FileConfiguration configuration = loadPartialPluginYmlFile(); + + configuration.set("commands", generateCommands()); + configuration.set("permissions", generatePermissions()); + + FileUtils.writeToFile(PLUGIN_YML_FILE, + pluginYmlStart + "\n" + configuration.saveToString()); + } + + @Override + public String getTaskName() { + return "generatePluginYml"; + } + + @Override + public void execute(Scanner scanner) { + executeDefault(); + } + + /** + * Because some parts above the commands section have placeholders that aren't valid YAML, we need + * to split the contents into an upper part that we ignore and a lower part we load as YAML. When + * saving we prepend the YAML export with the stripped off part of the file again. + * + * @return file configuration with the lower part of the plugin.yml file + */ + private FileConfiguration loadPartialPluginYmlFile() { + List pluginYmlLines = FileUtils.readLinesFromFile(Paths.get(PLUGIN_YML_FILE)); + int lineNr = 0; + for (String line : pluginYmlLines) { + if (line.equals("commands:")) { + break; + } + ++lineNr; + } + if (lineNr == pluginYmlLines.size()) { + throw new IllegalStateException("Could not find line starting 'commands:' section"); + } + pluginYmlStart = String.join("\n", pluginYmlLines.subList(0, lineNr)); + String yamlContents = String.join("\n", pluginYmlLines.subList(lineNr, pluginYmlLines.size())); + return YamlConfiguration.loadConfiguration(new StringReader(yamlContents)); + } + + private static Map generateCommands() { + Collection commands = new CommandInitializer().getCommands(); + Map entries = new LinkedHashMap<>(); + for (CommandDescription command : commands) { + entries.put(command.getLabels().get(0), buildCommandEntry(command)); + } + return entries; + } + + private Map generatePermissions() { + PermissionNodesGatherer gatherer = new PermissionNodesGatherer(); + Map permissionDescriptions = gatherer.gatherNodesWithJavaDoc(); + + permissionNodes = gatherer.getPermissionClasses().stream() + // Note ljacqu 20161023: The compiler fails if we use method references below + .map(clz -> clz.getEnumConstants()) + .flatMap((PermissionNode[] nodes) -> Arrays.stream(nodes)) + .collect(Collectors.toList()); + + Map descriptions = new TreeMap<>(); + for (PermissionNode node : permissionNodes) { + descriptions.put(node.getNode(), buildPermissionEntry(node, permissionDescriptions.get(node.getNode()))); + } + addWildcardPermissions(descriptions); + return descriptions; + } + + private void addWildcardPermissions(Map permissions) { + for (Map.Entry entry : WILDCARD_PERMISSIONS.entrySet()) { + permissions.put(entry.getKey(), + buildWildcardPermissionEntry(entry.getValue(), gatherChildren(entry.getKey()))); + } + } + + private Map gatherChildren(String parentNode) { + String parentPath = parentNode.replaceAll("\\.\\*$", ""); + + Map children = new TreeMap<>(); + for (PermissionNode node : permissionNodes) { + if (node.getNode().startsWith(parentPath)) { + children.put(node.getNode(), Boolean.TRUE); + } + } + return children; + } + + private static Map buildCommandEntry(CommandDescription command) { + if (command.getLabels().size() > 1) { + return ImmutableMap.of( + "description", command.getDescription(), + "usage", buildUsage(command), + "aliases", command.getLabels().subList(1, command.getLabels().size())); + } else { + return ImmutableMap.of( + "description", command.getDescription(), + "usage", buildUsage(command)); + } + } + + private static String buildUsage(CommandDescription command) { + if (!command.getArguments().isEmpty()) { + return CommandUtils.buildSyntax(command); + } + final String commandStart = "/" + command.getLabels().get(0); + String usage = commandStart + " " + command.getChildren() + .stream() + .filter(cmd -> !cmd.getLabels().contains("help")) + .map(cmd -> cmd.getLabels().get(0)) + .collect(Collectors.joining("|")); + return usage.trim(); + } + + private static Map buildPermissionEntry(PermissionNode permissionNode, String description) { + return ImmutableMap.of( + "description", description, + "default", convertDefaultPermission(permissionNode.getDefaultPermission())); + } + + private static Map buildWildcardPermissionEntry(String description, Map children) { + return ImmutableMap.of( + "description", description, + "children", children); + } + + private static Object convertDefaultPermission(DefaultPermission defaultPermission) { + switch (defaultPermission) { + // Returning true/false as booleans will make SnakeYAML avoid using quotes + case ALLOWED: return true; + case NOT_ALLOWED: return false; + case OP_ONLY: return "op"; + default: + throw new IllegalArgumentException("Unknown default permission '" + defaultPermission + "'"); + } + } +} From edf7c227b218458369c451132e3901e5e8d1ef52 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 23 Oct 2016 13:14:06 +0200 Subject: [PATCH 11/25] Minor - create abstract SimpleAutoTask for simple tool tasks --- .../java/tools/checktestmocks/CheckTestMocks.java | 10 ++-------- .../tools/docs/commands/CommandPageCreater.java | 10 ++-------- .../HashAlgorithmsDescriptionTask.java | 10 ++-------- .../docs/permissions/PermissionsListWriter.java | 14 ++------------ .../translations/TranslationPageGenerator.java | 10 ++-------- .../tools/filegeneration/GeneratePluginYml.java | 10 ++-------- src/test/java/tools/utils/SimpleAutoTask.java | 15 +++++++++++++++ 7 files changed, 27 insertions(+), 52 deletions(-) create mode 100644 src/test/java/tools/utils/SimpleAutoTask.java diff --git a/src/test/java/tools/checktestmocks/CheckTestMocks.java b/src/test/java/tools/checktestmocks/CheckTestMocks.java index def4e822f..1e8817aa2 100644 --- a/src/test/java/tools/checktestmocks/CheckTestMocks.java +++ b/src/test/java/tools/checktestmocks/CheckTestMocks.java @@ -4,15 +4,14 @@ import com.google.common.collect.Sets; import fr.xephi.authme.ClassCollector; import fr.xephi.authme.TestHelper; import org.mockito.Mock; -import tools.utils.AutoToolTask; import tools.utils.InjectorUtils; +import tools.utils.SimpleAutoTask; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; -import java.util.Scanner; import java.util.Set; import java.util.stream.Collectors; @@ -20,7 +19,7 @@ import java.util.stream.Collectors; * Task checking if all tests' {@code @Mock} fields have a corresponding * {@code @Inject} field in the class they are testing. */ -public class CheckTestMocks implements AutoToolTask { +public class CheckTestMocks extends SimpleAutoTask { private List errors = new ArrayList<>(); @@ -29,11 +28,6 @@ public class CheckTestMocks implements AutoToolTask { return "checkTestMocks"; } - @Override - public void execute(Scanner scanner) { - executeDefault(); - } - @Override public void executeDefault() { ClassCollector collector = new ClassCollector(TestHelper.TEST_SOURCES_FOLDER, TestHelper.PROJECT_ROOT); diff --git a/src/test/java/tools/docs/commands/CommandPageCreater.java b/src/test/java/tools/docs/commands/CommandPageCreater.java index b975c34f5..eab18256a 100644 --- a/src/test/java/tools/docs/commands/CommandPageCreater.java +++ b/src/test/java/tools/docs/commands/CommandPageCreater.java @@ -5,16 +5,15 @@ import fr.xephi.authme.command.CommandDescription; import fr.xephi.authme.command.CommandInitializer; import fr.xephi.authme.command.CommandUtils; import fr.xephi.authme.permission.PermissionNode; -import tools.utils.AutoToolTask; import tools.utils.FileUtils; +import tools.utils.SimpleAutoTask; import tools.utils.TagValue.NestedTagValue; import tools.utils.TagValueHolder; import tools.utils.ToolsConstants; import java.util.Collection; -import java.util.Scanner; -public class CommandPageCreater implements AutoToolTask { +public class CommandPageCreater extends SimpleAutoTask { private static final String OUTPUT_FILE = ToolsConstants.DOCS_FOLDER + "commands.md"; @@ -23,11 +22,6 @@ public class CommandPageCreater implements AutoToolTask { return "createCommandPage"; } - @Override - public void execute(Scanner scanner) { - executeDefault(); - } - @Override public void executeDefault() { CommandInitializer commandInitializer = new CommandInitializer(); diff --git a/src/test/java/tools/docs/hashmethods/HashAlgorithmsDescriptionTask.java b/src/test/java/tools/docs/hashmethods/HashAlgorithmsDescriptionTask.java index 95da44d53..d6ba721cc 100644 --- a/src/test/java/tools/docs/hashmethods/HashAlgorithmsDescriptionTask.java +++ b/src/test/java/tools/docs/hashmethods/HashAlgorithmsDescriptionTask.java @@ -1,30 +1,24 @@ package tools.docs.hashmethods; import fr.xephi.authme.security.HashAlgorithm; -import tools.utils.AutoToolTask; import tools.utils.FileUtils; +import tools.utils.SimpleAutoTask; import tools.utils.TagValue.NestedTagValue; import tools.utils.TagValueHolder; import tools.utils.ToolsConstants; import java.util.Map; -import java.util.Scanner; /** * Task for generating the markdown page describing the AuthMe hash algorithms. * * @see fr.xephi.authme.security.HashAlgorithm */ -public class HashAlgorithmsDescriptionTask implements AutoToolTask { +public class HashAlgorithmsDescriptionTask extends SimpleAutoTask { private static final String CUR_FOLDER = ToolsConstants.TOOLS_SOURCE_ROOT + "docs/hashmethods/"; private static final String OUTPUT_FILE = ToolsConstants.DOCS_FOLDER + "hash_algorithms.md"; - @Override - public void execute(Scanner scanner) { - executeDefault(); - } - @Override public void executeDefault() { // Gather info and construct a row for each method diff --git a/src/test/java/tools/docs/permissions/PermissionsListWriter.java b/src/test/java/tools/docs/permissions/PermissionsListWriter.java index 6d1b48d74..ffd418e21 100644 --- a/src/test/java/tools/docs/permissions/PermissionsListWriter.java +++ b/src/test/java/tools/docs/permissions/PermissionsListWriter.java @@ -1,19 +1,18 @@ package tools.docs.permissions; -import tools.utils.AutoToolTask; import tools.utils.FileUtils; +import tools.utils.SimpleAutoTask; import tools.utils.TagValue.NestedTagValue; import tools.utils.TagValueHolder; import tools.utils.ToolsConstants; import java.util.Map; -import java.util.Scanner; /** * Task responsible for formatting a permissions node list and * for writing it to a file if desired. */ -public class PermissionsListWriter implements AutoToolTask { +public class PermissionsListWriter extends SimpleAutoTask { private static final String TEMPLATE_FILE = ToolsConstants.TOOLS_SOURCE_ROOT + "docs/permissions/permission_nodes.tpl.md"; private static final String PERMISSIONS_OUTPUT_FILE = ToolsConstants.DOCS_FOLDER + "permission_nodes.md"; @@ -23,17 +22,8 @@ public class PermissionsListWriter implements AutoToolTask { return "writePermissionsList"; } - @Override - public void execute(Scanner scanner) { - generateAndWriteFile(); - } - @Override public void executeDefault() { - generateAndWriteFile(); - } - - private static void generateAndWriteFile() { final NestedTagValue permissionsTagValue = generatePermissionsList(); TagValueHolder tags = TagValueHolder.create().put("nodes", permissionsTagValue); diff --git a/src/test/java/tools/docs/translations/TranslationPageGenerator.java b/src/test/java/tools/docs/translations/TranslationPageGenerator.java index e7785bd7a..80619ba56 100644 --- a/src/test/java/tools/docs/translations/TranslationPageGenerator.java +++ b/src/test/java/tools/docs/translations/TranslationPageGenerator.java @@ -2,15 +2,14 @@ package tools.docs.translations; import com.google.common.collect.ImmutableMap; import tools.docs.translations.TranslationsGatherer.TranslationInfo; -import tools.utils.AutoToolTask; import tools.utils.FileUtils; +import tools.utils.SimpleAutoTask; import tools.utils.TagValue.NestedTagValue; import tools.utils.TagValueHolder; import tools.utils.ToolsConstants; import java.util.Arrays; import java.util.Map; -import java.util.Scanner; import java.util.stream.Collectors; import static com.google.common.base.Objects.firstNonNull; @@ -18,7 +17,7 @@ import static com.google.common.base.Objects.firstNonNull; /** * Generates the translations page in docs. */ -public class TranslationPageGenerator implements AutoToolTask { +public class TranslationPageGenerator extends SimpleAutoTask { private static final String DOCS_PAGE = ToolsConstants.DOCS_FOLDER + "translations.md"; private static final String TEMPLATE_FILE = ToolsConstants.TOOLS_SOURCE_ROOT + "docs/translations/translations.tpl.md"; @@ -42,11 +41,6 @@ public class TranslationPageGenerator implements AutoToolTask { return "updateTranslations"; } - @Override - public void execute(Scanner scanner) { - executeDefault(); - } - @Override public void executeDefault() { NestedTagValue translationValuesHolder = new NestedTagValue(); diff --git a/src/test/java/tools/filegeneration/GeneratePluginYml.java b/src/test/java/tools/filegeneration/GeneratePluginYml.java index c3d332f24..633c5aac8 100644 --- a/src/test/java/tools/filegeneration/GeneratePluginYml.java +++ b/src/test/java/tools/filegeneration/GeneratePluginYml.java @@ -9,8 +9,8 @@ import fr.xephi.authme.permission.PermissionNode; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import tools.docs.permissions.PermissionNodesGatherer; -import tools.utils.AutoToolTask; import tools.utils.FileUtils; +import tools.utils.SimpleAutoTask; import tools.utils.ToolsConstants; import java.io.StringReader; @@ -20,14 +20,13 @@ import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Scanner; import java.util.TreeMap; import java.util.stream.Collectors; /** * Generates the command and permission section of plugin.yml. */ -public class GeneratePluginYml implements AutoToolTask { +public class GeneratePluginYml extends SimpleAutoTask { private static final String PLUGIN_YML_FILE = ToolsConstants.MAIN_RESOURCES_ROOT + "plugin.yml"; @@ -56,11 +55,6 @@ public class GeneratePluginYml implements AutoToolTask { return "generatePluginYml"; } - @Override - public void execute(Scanner scanner) { - executeDefault(); - } - /** * Because some parts above the commands section have placeholders that aren't valid YAML, we need * to split the contents into an upper part that we ignore and a lower part we load as YAML. When diff --git a/src/test/java/tools/utils/SimpleAutoTask.java b/src/test/java/tools/utils/SimpleAutoTask.java new file mode 100644 index 000000000..4c0c936d0 --- /dev/null +++ b/src/test/java/tools/utils/SimpleAutoTask.java @@ -0,0 +1,15 @@ +package tools.utils; + +import java.util.Scanner; + +/** + * Abstract class for auto tool tasks that perform exactly the same action for + * {@link ToolTask#execute(Scanner)} and {@link AutoToolTask#executeDefault()}. + */ +public abstract class SimpleAutoTask implements AutoToolTask { + + @Override + public final void execute(Scanner scanner) { + executeDefault(); + } +} From f8745876de942add599a22066dcea30daa155e04 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 23 Oct 2016 14:36:30 +0200 Subject: [PATCH 12/25] Generate config file automatically --- src/main/java/fr/xephi/authme/AuthMe.java | 3 + .../authme/initialization/Initializer.java | 12 +- src/main/resources/config.yml | 444 ------------------ 3 files changed, 9 insertions(+), 450 deletions(-) delete mode 100644 src/main/resources/config.yml diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 8e9818bf2..b52caf32e 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -199,6 +199,9 @@ public class AuthMe extends JavaPlugin { ConsoleLogger.setLogger(getLogger()); ConsoleLogger.setLogFile(new File(getDataFolder(), LOG_FILENAME)); + // Create plugin folder + getDataFolder().mkdir(); + // Load settings and set up the console and console filter settings = Initializer.createSettings(this); bukkitService = new BukkitService(this, settings); diff --git a/src/main/java/fr/xephi/authme/initialization/Initializer.java b/src/main/java/fr/xephi/authme/initialization/Initializer.java index eaac2abc9..525334c27 100644 --- a/src/main/java/fr/xephi/authme/initialization/Initializer.java +++ b/src/main/java/fr/xephi/authme/initialization/Initializer.java @@ -62,13 +62,13 @@ public class Initializer { */ public static Settings createSettings(AuthMe authMe) throws Exception { File configFile = new File(authMe.getDataFolder(), "config.yml"); - if (FileUtils.copyFileFromResource(configFile, "config.yml")) { - PropertyResource resource = new YamlFileResource(configFile); - SettingsMigrationService migrationService = new SettingsMigrationService(authMe.getDataFolder()); - ConfigurationData configurationData = AuthMeSettingsRetriever.buildConfigurationData(); - return new Settings(authMe.getDataFolder(), resource, migrationService, configurationData); + if(!configFile.exists()) { + configFile.createNewFile(); } - throw new Exception("Could not copy config.yml from JAR to plugin folder"); + PropertyResource resource = new YamlFileResource(configFile); + SettingsMigrationService migrationService = new SettingsMigrationService(authMe.getDataFolder()); + ConfigurationData configurationData = AuthMeSettingsRetriever.buildConfigurationData(); + return new Settings(authMe.getDataFolder(), resource, migrationService, configurationData); } /** diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml deleted file mode 100644 index aba5a8658..000000000 --- a/src/main/resources/config.yml +++ /dev/null @@ -1,444 +0,0 @@ -DataSource: - # What type of database do you want to use? - # Valid values: sqlite, mysql - backend: sqlite - # Enable database caching, should improve database performance - caching: true - # Database location - mySQLHost: 127.0.0.1 - # Database Port - mySQLPort: '3306' - # Username about Database Connection Infos - mySQLUsername: authme - # Password about Database Connection Infos - mySQLPassword: '12345' - # Database Name, use with converters or as SQLITE database name - mySQLDatabase: authme - # Table of the database - mySQLTablename: authme - # Column of IDs to sort data - mySQLColumnId: id - # Column for storing or checking players nickname - mySQLColumnName: username - # Column for storing players passwords - mySQLColumnPassword: password - # Column for storing players emails - mySQLColumnEmail: email - # Column for Saving if a player is logged in or not - mySQLColumnLogged: isLogged - # Column for storing players IPs - mySQLColumnIp: ip - # Column for storing players lastlogins - mySQLColumnLastLogin: lastlogin - # Column for SaveQuitLocation - X - mySQLlastlocX: x - # Column for SaveQuitLocation - Y - mySQLlastlocY: y - # Column for SaveQuitLocation - Z - mySQLlastlocZ: z - # Column for SaveQuitLocation - World name - mySQLlastlocWorld: world - # Column for RealName - mySQLRealName: realname - # Overrides the size of the DB Connection Pool, -1 = Auto - poolSize: -1 -settings: - sessions: - # Do you want to enable the session feature? - # If enabled, when a player authenticates successfully, - # his IP and his nickname is saved. - # The next time the player joins the server, if his IP - # is the same of the last time, and the timeout time - # hasn't expired, he will not need to authenticate. - enabled: false - # After how many minutes a session should expire? - # Consider that session will end only after the timeout time, and - # if the player's ip has changed but the timeout hasn't expired, - # player will be kicked out of sever due to invalidSession! - timeout: 10 - # Should the session expire if the player try to login with an - # another IP Address? - sessionExpireOnIpChange: true - restrictions: - # Can not authenticated players chat and see the chat log? - # Care that this feature blocks also all the commands not - # listed in the list below. - allowChat: false - # Can not authenticated players see the chat log? - hideChat: false - # Commands allowed when a player is not authenticated - allowCommands: - - /login - - /register - - /l - - /reg - - /email - - /captcha - # Max number of allowed registrations per IP (default: 1) - maxRegPerIp: 1 - # Max allowed username length - maxNicknameLength: 16 - # When this setting is enabled, online players can't be kicked out - # due to "Logged in from another Location" - # This setting will prevent potetial security exploits. - ForceSingleSession: true - ForceSpawnLocOnJoin: - # If enabled, every player will be teleported to the world spawnpoint - # after successful authentication. - # The quit location of the player will be overwritten. - # This is different from "teleportUnAuthedToSpawn" that teleport player - # back to his quit location after the authentication. - enabled: false - # WorldNames where we need to force the spawn location - # Case-sensitive! - worlds: - - 'world' - - 'world_nether' - - 'world_the_end' - # This option will save the quit location of the players. - SaveQuitLocation: false - # To activate the restricted user feature you need - # to enable this option and configure the - # AllowedRestrctedUser field. - AllowRestrictedUser: false - # The restricted user feature will kick players listed below - # if they don't match of the defined ip address. - # Example: - # AllowedRestrictedUser: - # - playername;127.0.0.1 - AllowedRestrictedUser: [] - # Should unregistered players be kicked immediately? - kickNonRegistered: false - # Should players be kicked on wrong password? - kickOnWrongPassword: false - # Should not logged in players be teleported to the spawn? - # After the authentication they will be teleported back to - # their normal position. - teleportUnAuthedToSpawn: false - # Minimum allowed nick length - minNicknameLength: 4 - # Can unregistered players walk around? - allowMovement: false - # Should not authenticated players have speed = 0? - # This will reset the fly/walk speed to default value after the login. - removeSpeed: true - # After how many time players who fail to login or register - # should be kicked? Set to 0 to disable. - timeout: 30 - # Regex sintax of allowed characters in the player name. - allowedNicknameCharacters: '[a-zA-Z0-9_]*' - # How far can unregistered players walk? Set to 0 - # for unlimited radius - allowedMovementRadius: 100 - # Enable double check of password when you register - # when it's true, registration require that kind of command: - # /register - enablePasswordConfirmation: true - # Should we protect the player inventory before logging in? Requires ProtocolLib. - ProtectInventoryBeforeLogIn: true - # Should we deny the tabcomplete feature before logging in? Requires ProtocolLib. - DenyTabCompleteBeforeLogin: true - # Should we display all other accounts from a player when he joins? - # permission: /authme.admin.accounts - displayOtherAccounts: true - # Ban ip when the ip is not the ip registered in database - banUnsafedIP: false - # Spawn Priority, Values : authme, essentials, multiverse, default - spawnPriority: authme,essentials,multiverse,default - # Maximum Login authorized by IP - maxLoginPerIp: 0 - # Maximum Join authorized by IP - maxJoinPerIp: 0 - # AuthMe will NEVER teleport players ! - noTeleport: false - # Regex syntax for allowed Chars in passwords. - allowedPasswordCharacters: '[\x21-\x7E]*' - # Keeps collisions disabled for logged players - # Works only with MC 1.9 - keepCollisionsDisabled: false - GameMode: - # ForceSurvivalMode to player when join ? - ForceSurvivalMode: false - security: - # Minimum length of password - minPasswordLength: 5 - # Maximum length of password - passwordMaxLength: 30 - # this is very important options, - # every time player join the server, - # if they are registered, AuthMe will switch him - # to unLoggedInGroup, this - # should prevent all major exploit. - # So you can set up on your Permission Plugin - # this special group with 0 permissions, or permissions to chat, - # or permission to - # send private message or all other perms that you want, - # the better way is to set up - # this group with few permissions, - # so if player try to exploit some account, - # they can - # do anything except what you set in perm Group. - # After a correct logged-in player will be - # moved to his correct permissions group! - # Pay attention group name is case sensitive, - # so Admin is different from admin, - # otherwise your group will be wiped, - # and player join in default group []! - # Example unLoggedinGroup: NotLogged - unLoggedinGroup: unLoggedinGroup - # possible values: MD5, SHA1, SHA256, WHIRLPOOL, XAUTH, MD5VB, PHPBB, - # MYBB, IPB3, IPB4, PHPFUSION, SMF, XENFORO, SALTED2MD5, JOOMLA, BCRYPT, WBB3, SHA512, - # DOUBLEMD5, PBKDF2, PBKDF2DJANGO, WORDPRESS, ROYALAUTH, CUSTOM(for developpers only) - passwordHash: SHA256 - # salt length for the SALTED2MD5 MD5(MD5(password)+salt) - doubleMD5SaltLength: 8 - # If password checking return false, do we need to check with all - # other password algorithm to check an old password? - # AuthMe will update the password to the new passwordHash! - supportOldPasswordHash: false - # Cancel unsafe passwords for being used, put them on lowercase! - #unsafePasswords: - #- '123456' - #- 'password' - unsafePasswords: - - '123456' - - 'password' - - 'qwerty' - - '12345' - - '54321' - - '123456789' - registration: - # enable registration on the server? - enabled: true - # Send every X seconds a message to a player to - # remind him that he has to login/register - messageInterval: 5 - # Only registered and logged in players can play. - # See restrictions for exceptions - force: true - # Do we replace password registration by an email registration method? - enableEmailRegistrationSystem: false - # Enable double check of email when you register - # when it's true, registration require that kind of command: - # /register - doubleEmailCheck: false - # Do we force kicking player after a successful registration? - # Do not use with login feature below - forceKickAfterRegister: false - # Does AuthMe need to enforce a /login after a successful registration? - forceLoginAfterRegister: false - unrestrictions: - # below you can list all account names that - # AuthMe will ignore for registration or login, configure it - # at your own risk!! Remember that if you are going to add - # nickname with [], you have to delimit name with ' '. - # this option add compatibility with BuildCraft and some - # other mods. - # It is CaseSensitive! - UnrestrictedName: [] - # Message language, available : en, de, br, cz, pl, fr, ru, hu, sk, es, zhtw, fi, zhcn, lt, it, ko, pt - messagesLanguage: en - # Force these commands after /login, without any '/', use %p for replace with player name - forceCommands: [] - # Force these commands after /login as a server console, without any '/', use %p for replace with player name - forceCommandsAsConsole: [] - # Force these commands after /register, without any '/', use %p for replace with player name - forceRegisterCommands: [] - # Force these commands after /register as a server console, without any '/', use %p for replace with player name - forceRegisterCommandsAsConsole: [] - # Do we need to display the welcome message (welcome.txt) after a login? - # You can use colors in this welcome.txt + some replaced strings: - # {PLAYER}: player name, {ONLINE}: display number of online players, {MAXPLAYERS}: display server slots, - # {IP}: player ip, {LOGINS}: number of players logged, {WORLD}: player current world, {SERVER}: server name - # {VERSION}: get current bukkit version, {COUNTRY}: player country - useWelcomeMessage: true - # Do we need to broadcast the welcome message to all server or only to the player? set true for server or false for player - broadcastWelcomeMessage: false - # Should we delay the join message and display it once the player has logged in? - delayJoinMessage: false - # Should we remove the leave messages of unlogged users? - removeUnloggedLeaveMessage: false - # Should we remove join messages altogether? - removeJoinMessage: false - # Should we remove leave messages altogether? - removeLeaveMessage: false - # Do we need to add potion effect Blinding before login/register? - applyBlindEffect: false - # Do we need to prevent people to login with another case? - # If Xephi is registered, then Xephi can login, but not XEPHI/xephi/XePhI - preventOtherCase: false - # Log level: INFO, FINE, DEBUG. Use INFO for general messages, - # FINE for some additional detailed ones (like password failed), - # and DEBUG for debug messages - logLevel: 'FINE' - # By default we schedule async tasks when talking to the database - # If you want typical communication with the database to happen synchronously, set this to false - useAsyncTasks: true -ExternalBoardOptions: - # MySQL column for the salt, needed for some forum/cms support - mySQLColumnSalt: '' - # MySQL column for the group, needed for some forum/cms support - mySQLColumnGroup: '' - # -1 mean disabled. If u want that only - # activated player can login in your server - # u can put in this options the group number - # of unactivated user, needed for some forum/cms support - nonActivedUserGroup: -1 - # Other MySQL columns where we need to put the Username (case sensitive) - mySQLOtherUsernameColumns: [] - # How much Log to Round needed in BCrypt(do not change it if you do not know what's your doing) - bCryptLog2Round: 10 - # phpBB prefix defined during phpbb installation process - phpbbTablePrefix: 'phpbb_' - # phpBB activated group id, 2 is default registered group defined by phpbb - phpbbActivatedGroupId: 2 - # WordPress prefix defined during WordPress installation process - wordpressTablePrefix: 'wp_' -permission: - # Take care with this options, if you dont want - # to use Vault and Group Switching of - # AuthMe for unloggedIn players put true - # below, default is false. - EnablePermissionCheck: false -BackupSystem: - # Enable or Disable Automatic Backup - ActivateBackup: false - # set Backup at every start of Server - OnServerStart: false - # set Backup at every stop of Server - OnServerStop: true - # Windows only mysql installation Path - MysqlWindowsPath: 'C:\Program Files\MySQL\MySQL Server 5.1\' -Security: - SQLProblem: - # Stop the server if we can't contact the sql database - # Take care with this, if you set that to false, - # AuthMe automatically disable and the server is not protected! - stopServer: true - ReloadCommand: - # /reload support - useReloadCommandSupport: true - console: - # Replace passwords in the console when player type a command like /login - removePassword: true - # Copy AuthMe log output in a separate file as well? - logConsole: true - captcha: - # Enable captcha when a player uses wrong password too many times - useCaptcha: false - # Max allowed tries before a captcha is required - maxLoginTry: 5 - # Captcha length - captchaLength: 5 - tempban: - # Tempban a user's IP address if they enter the wrong password too many times - enableTempban: false - # How many times a user can attempt to login before their IP being tempbanned - maxLoginTries: 10 - # The length of time a IP address will be tempbanned in minutes - # Default: 480 minutes, or 8 hours - tempbanLength: 480 - # How many minutes before resetting the count for failed logins by IP and username - # Default: 480 minutes (8 hours) - minutesBeforeCounterReset: 480 - recoveryCode: - # Number of characters a recovery code should have (0 to disable) - length: 8 - # How many hours is a recovery code valid for? - validForHours: 4 -Converter: - Rakamak: - # Rakamak file name - fileName: users.rak - # Rakamak use ip ? - useIP: false - # IP file name for rakamak - ipFileName: UsersIp.rak - CrazyLogin: - # CrazyLogin database file - fileName: accounts.db -Email: - # Email SMTP server host - mailSMTP: smtp.gmail.com - # Email SMTP server port - mailPort: 465 - # Email account that send the mail - mailAccount: '' - # Email account password - mailPassword: '' - # Custom SenderName, that replace the mailAccount name in the email - mailSenderName: '' - # Random password length - RecoveryPasswordLength: 8 - # Email subject of password get - mailSubject: 'Your new AuthMe password' - # Like maxRegPerIp but with email - maxRegPerEmail: 1 - # Recall players to add an email? - recallPlayers: false - # Delay in minute for the recall scheduler - delayRecall: 5 - # Blacklist these domains for emails - emailBlacklisted: - - 10minutemail.com - # WhiteList only these domains for emails - emailWhitelisted: [] - # Do we need to send new password draw in an image? - generateImage: false - # The email OAuth 2 token (leave empty if not used) - emailOauth2Token: '' -Hooks: - # Do we need to hook with multiverse for spawn checking? - multiverse: true - # Do we need to hook with BungeeCord ? - bungeecord: false - # Send player to this BungeeCord server after register/login - sendPlayerTo: '' - # Do we need to disable Essentials SocialSpy on join? - disableSocialSpy: true - # Do we need to force /motd Essentials command on join? - useEssentialsMotd: false -Purge: - # If enabled, AuthMe automatically purges old, unused accounts - useAutoPurge: false - # Number of Days an account become Unused - daysBeforeRemovePlayer: 60 - # Do we need to remove the player.dat file during purge process? - removePlayerDat: false - # Do we need to remove the Essentials/userdata/player.yml file during purge process? - removeEssentialsFile: false - # World where are players.dat stores - defaultWorld: 'world' - # Do we need to remove LimitedCreative/inventories/player.yml, player_creative.yml files during purge process ? - removeLimitedCreativesInventories: false - # Do we need to remove the AntiXRayData/PlayerData/player file during purge process? - removeAntiXRayFile: false - # Do we need to remove permissions? - removePermissions: false -Protection: - # Enable some servers protection ( country based login, antibot ) - enableProtection: false - # Apply the protection also to registered usernames - enableProtectionRegistered: true - # Countries allowed to join the server and register, see http://dev.bukkit.org/bukkit-plugins/authme-reloaded/pages/countries-codes/ for countries' codes - # PLEASE USE QUOTES! - countries: - - 'US' - - 'GB' - # Countries blacklisted automatically (without any needed to enable protection) - # PLEASE USE QUOTES! - countriesBlacklist: - - 'A1' - # Do we need to enable automatic antibot system? - enableAntiBot: true - # Max number of player allowed to login in 5 secs before enable AntiBot system automatically - antiBotSensibility: 10 - # Duration in minutes of the antibot automatic system - antiBotDuration: 10 - # Delay in seconds before the antibot activation - antiBotDelay: 60 -GroupOptions: - # Registered permission group - RegisteredPlayerGroup: '' - # Unregistered permission group - UnregisteredPlayerGroup: '' From 232153813dc4f25cdb03ca7b910786e9461030ab Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 23 Oct 2016 15:25:02 +0200 Subject: [PATCH 13/25] Fix unit test --- .../settings/ConfigFileConsistencyTest.java | 105 ------------------ .../SettingsMigrationServiceTest.java | 67 ----------- .../fr/xephi/authme/util/FileUtilsTest.java | 6 +- 3 files changed, 3 insertions(+), 175 deletions(-) delete mode 100644 src/test/java/fr/xephi/authme/settings/ConfigFileConsistencyTest.java delete mode 100644 src/test/java/fr/xephi/authme/settings/SettingsMigrationServiceTest.java diff --git a/src/test/java/fr/xephi/authme/settings/ConfigFileConsistencyTest.java b/src/test/java/fr/xephi/authme/settings/ConfigFileConsistencyTest.java deleted file mode 100644 index ab4031e25..000000000 --- a/src/test/java/fr/xephi/authme/settings/ConfigFileConsistencyTest.java +++ /dev/null @@ -1,105 +0,0 @@ -package fr.xephi.authme.settings; - -import com.github.authme.configme.knownproperties.ConfigurationData; -import com.github.authme.configme.migration.MigrationService; -import com.github.authme.configme.migration.PlainMigrationService; -import com.github.authme.configme.properties.Property; -import com.github.authme.configme.resource.PropertyResource; -import com.github.authme.configme.resource.YamlFileResource; -import fr.xephi.authme.TestHelper; -import fr.xephi.authme.settings.properties.AuthMeSettingsRetriever; -import org.bukkit.configuration.MemorySection; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; -import org.junit.Test; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; - -/** - * Test for {@link Settings} and the project's config.yml, - * verifying that no settings are missing from the file. - */ -public class ConfigFileConsistencyTest { - - /** The file name of the project's sample config file. */ - private static final String CONFIG_FILE = "/config.yml"; - - @Test - public void shouldHaveAllConfigs() throws IOException { - // given - File configFile = TestHelper.getJarFile(CONFIG_FILE); - PropertyResource resource = new YamlFileResource(configFile); - MigrationService migration = new PlainMigrationService(); - - // when - boolean result = migration.checkAndMigrate( - resource, AuthMeSettingsRetriever.buildConfigurationData().getProperties()); - - // then - if (result) { - Set knownProperties = getAllKnownPropertyPaths(); - List missingProperties = new ArrayList<>(); - for (String path : knownProperties) { - if (!resource.contains(path)) { - missingProperties.add(path); - } - } - fail("Found missing properties!\n-" + String.join("\n-", missingProperties)); - } - } - - @Test - public void shouldNotHaveUnknownConfigs() { - // given - File configFile = TestHelper.getJarFile(CONFIG_FILE); - FileConfiguration configuration = YamlConfiguration.loadConfiguration(configFile); - Map allReadProperties = configuration.getValues(true); - Set knownKeys = getAllKnownPropertyPaths(); - - // when - List unknownPaths = new ArrayList<>(); - for (Map.Entry entry : allReadProperties.entrySet()) { - // The value being a MemorySection means it's a parent node - if (!(entry.getValue() instanceof MemorySection) && !knownKeys.contains(entry.getKey())) { - unknownPaths.add(entry.getKey()); - } - } - - // then - if (!unknownPaths.isEmpty()) { - fail("Found " + unknownPaths.size() + " unknown property paths in the project's config.yml: \n- " - + String.join("\n- ", unknownPaths)); - } - } - - @Test - public void shouldHaveValueCorrespondingToPropertyDefault() { - // given - File configFile = TestHelper.getJarFile(CONFIG_FILE); - PropertyResource resource = new YamlFileResource(configFile); - ConfigurationData configurationData = AuthMeSettingsRetriever.buildConfigurationData(); - - // when / then - for (Property property : configurationData.getProperties()) { - assertThat("Default value of '" + property.getPath() + "' in config.yml should be the same as in Property", - property.getValue(resource).equals(property.getDefaultValue()), equalTo(true)); - } - } - - private static Set getAllKnownPropertyPaths() { - return AuthMeSettingsRetriever.buildConfigurationData() - .getProperties().stream() - .map(Property::getPath) - .collect(Collectors.toSet()); - } -} diff --git a/src/test/java/fr/xephi/authme/settings/SettingsMigrationServiceTest.java b/src/test/java/fr/xephi/authme/settings/SettingsMigrationServiceTest.java deleted file mode 100644 index 93325110a..000000000 --- a/src/test/java/fr/xephi/authme/settings/SettingsMigrationServiceTest.java +++ /dev/null @@ -1,67 +0,0 @@ -package fr.xephi.authme.settings; - -import com.github.authme.configme.knownproperties.ConfigurationData; -import com.github.authme.configme.resource.PropertyResource; -import com.github.authme.configme.resource.YamlFileResource; -import com.google.common.io.Files; -import fr.xephi.authme.TestHelper; -import fr.xephi.authme.settings.properties.AuthMeSettingsRetriever; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -import java.io.File; -import java.io.IOException; - -import static org.hamcrest.Matchers.arrayWithSize; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; -import static org.junit.Assume.assumeThat; - -/** - * Test for {@link SettingsMigrationService}. - */ -public class SettingsMigrationServiceTest { - - @Rule - public TemporaryFolder testFolderHandler = new TemporaryFolder(); - - private File testFolder; - private File configTestFile; - - /** - * Ensure that AuthMe regards the JAR's own config.yml as complete. - * If something legitimately needs migrating, a test from {@link ConfigFileConsistencyTest} should fail. - * If none fails in that class, it means something is wrong with the migration service - * as it wants to perform a migration on our up-to-date config.yml. - */ - @Test - public void shouldNotRewriteJarConfig() throws IOException { - // given - copyConfigToTestFolder(); - PropertyResource resource = new YamlFileResource(configTestFile); - ConfigurationData configurationData = AuthMeSettingsRetriever.buildConfigurationData(); - assumeThat(testFolder.listFiles(), arrayWithSize(1)); - SettingsMigrationService migrationService = new SettingsMigrationService(testFolder); - - // when - boolean result = migrationService.checkAndMigrate(resource, configurationData.getProperties()); - - // then - assertThat(result, equalTo(false)); - assertThat(testFolder.listFiles(), arrayWithSize(1)); - } - - private void copyConfigToTestFolder() throws IOException { - testFolder = testFolderHandler.newFolder("migrationtest"); - - final File testConfig = testFolderHandler.newFile("migrationtest/config.yml"); - final File realConfig = TestHelper.getJarFile("/config.yml"); - - Files.copy(realConfig, testConfig); - if (!testConfig.exists()) { - throw new IOException("Could not copy project's config.yml to test folder"); - } - configTestFile = testConfig; - } -} diff --git a/src/test/java/fr/xephi/authme/util/FileUtilsTest.java b/src/test/java/fr/xephi/authme/util/FileUtilsTest.java index e7a8d8731..fa8ee9c6d 100644 --- a/src/test/java/fr/xephi/authme/util/FileUtilsTest.java +++ b/src/test/java/fr/xephi/authme/util/FileUtilsTest.java @@ -49,15 +49,15 @@ public class FileUtilsTest { public void shouldCopyFileFromJar() throws IOException { // given File folder = temporaryFolder.newFolder(); - File file = new File(folder, "some/folders/config.yml"); + File file = new File(folder, "some/folders/welcome.txt"); // when - boolean result = FileUtils.copyFileFromResource(file, "config.yml"); + boolean result = FileUtils.copyFileFromResource(file, "welcome.txt"); // then assertThat(result, equalTo(true)); assertThat(file.exists(), equalTo(true)); - File configJarFile = TestHelper.getJarFile("/config.yml"); + File configJarFile = TestHelper.getJarFile("/welcome.txt"); assertThat(file.length(), equalTo(configJarFile.length())); } From cc151e6e8db1fa916d3a69fe1138760aecec0b62 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 23 Oct 2016 15:31:58 +0200 Subject: [PATCH 14/25] Update HU messages #836 --- src/main/resources/messages/messages_hu.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/messages/messages_hu.yml b/src/main/resources/messages/messages_hu.yml index 88142bbce..daabe5734 100644 --- a/src/main/resources/messages/messages_hu.yml +++ b/src/main/resources/messages/messages_hu.yml @@ -72,5 +72,5 @@ kicked_admin_registered: 'Adminisztrátor által regisztrálva lettél; kérlek accounts_owned_self: '%count db regisztrációd van:' recovery_code_incorrect: 'A visszaállító kód helytelen volt! Használd a következő parancsot: /email recovery [email címed] egy új generálásához' recovery_code_sent: 'A jelszavad visszaállításához szükséges kódot sikeresen kiküldtük az email címedre!' -# TODO email_show: '&2Your current email address is: &f%email' -# TODO show_no_email: '&2You currently don''t have email address associated with this account.' \ No newline at end of file +email_show: '&2A jelenlegi email-ed a következő: &f%email' +show_no_email: '&2Ehhez a felhasználóhoz jelenleg még nincs email hozzárendelve.' From dd9ac75f3a804d1ef3cfc7194edaa155a1675205 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 23 Oct 2016 15:39:53 +0200 Subject: [PATCH 15/25] #916 Fix authme.vip node description --- docs/permission_nodes.md | 8 ++++---- .../fr/xephi/authme/permission/PlayerStatePermission.java | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/permission_nodes.md b/docs/permission_nodes.md index 60d39a15c..fb6408206 100644 --- a/docs/permission_nodes.md +++ b/docs/permission_nodes.md @@ -1,5 +1,5 @@ - + ## AuthMe Permission Nodes The following are the permission nodes that are currently supported by the latest dev builds. @@ -38,15 +38,15 @@ The following are the permission nodes that are currently supported by the lates - **authme.player.email** – Grants all email permissions. - **authme.player.email.add** – Command permission to add an email address. - **authme.player.email.change** – Command permission to change the email address. -- **authme.player.email.recover** – Command permission to recover an account using it's email address. +- **authme.player.email.recover** – Command permission to recover an account using its email address. - **authme.player.login** – Command permission to login. - **authme.player.logout** – Command permission to logout. - **authme.player.register** – Command permission to register. - **authme.player.seeownaccounts** – Permission to use to see own other accounts. - **authme.player.unregister** – Command permission to unregister. -- **authme.vip** – Permission node to identify VIP users. +- **authme.vip** – When the server is full and someone with this permission joins the server, someone will be kicked. --- -This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Oct 16 21:39:10 CEST 2016 +This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Oct 23 15:38:58 CEST 2016 diff --git a/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java b/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java index 0820be011..aaeb0eea3 100644 --- a/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java +++ b/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java @@ -17,7 +17,7 @@ public enum PlayerStatePermission implements PermissionNode { BYPASS_FORCE_SURVIVAL("authme.bypassforcesurvival", DefaultPermission.OP_ONLY), /** - * Permission node to identify VIP users. + * When the server is full and someone with this permission joins the server, someone will be kicked. */ IS_VIP("authme.vip", DefaultPermission.OP_ONLY), From 8f6643207e7fc6ad5fb867c0803f5cc94aa7dd87 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 23 Oct 2016 16:25:34 +0200 Subject: [PATCH 16/25] #979 Create tool task to verify help translations --- .../HelpTranslationVerifier.java | 162 ++++++++++++++++++ .../VerifyHelpTranslations.java | 72 ++++++++ 2 files changed, 234 insertions(+) create mode 100644 src/test/java/tools/helptranslation/HelpTranslationVerifier.java create mode 100644 src/test/java/tools/helptranslation/VerifyHelpTranslations.java diff --git a/src/test/java/tools/helptranslation/HelpTranslationVerifier.java b/src/test/java/tools/helptranslation/HelpTranslationVerifier.java new file mode 100644 index 000000000..2ed130fa0 --- /dev/null +++ b/src/test/java/tools/helptranslation/HelpTranslationVerifier.java @@ -0,0 +1,162 @@ +package tools.helptranslation; + +import com.google.common.collect.Sets; +import de.bananaco.bpermissions.imp.YamlConfiguration; +import fr.xephi.authme.command.CommandDescription; +import fr.xephi.authme.command.CommandInitializer; +import fr.xephi.authme.command.CommandUtils; +import fr.xephi.authme.command.help.HelpMessage; +import fr.xephi.authme.command.help.HelpSection; +import org.bukkit.configuration.MemorySection; +import org.bukkit.configuration.file.FileConfiguration; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import static com.google.common.collect.Lists.newArrayList; + +/** + * Verifies a help messages translation. + */ +public class HelpTranslationVerifier { + + private final FileConfiguration configuration; + + // missing and unknown HelpSection and HelpMessage entries + private final List missingSections = new ArrayList<>(); + private final List unknownSections = new ArrayList<>(); + // missing and unknown command entries + private final List missingCommands = new ArrayList<>(); + private final List unknownCommands = new ArrayList<>(); + + public HelpTranslationVerifier(File translation) { + this.configuration = YamlConfiguration.loadConfiguration(translation); + checkFile(); + } + + private void checkFile() { + checkHelpSections(); + checkCommands(); + } + + public List getMissingSections() { + return missingSections; + } + + public List getUnknownSections() { + return unknownSections; + } + + public List getMissingCommands() { + return missingCommands; + } + + public List getUnknownCommands() { + return unknownCommands; + } + + /** + * Verifies that the file has the expected entries for {@link HelpSection} and {@link HelpMessage}. + */ + private void checkHelpSections() { + Set knownSections = Arrays.stream(HelpSection.values()) + .map(HelpSection::getKey).collect(Collectors.toSet()); + knownSections.addAll(Arrays.stream(HelpMessage.values()).map(HelpMessage::getKey).collect(Collectors.toSet())); + knownSections.addAll(Arrays.asList("common.defaultPermissions.notAllowed", + "common.defaultPermissions.opOnly", "common.defaultPermissions.allowed")); + Set sectionKeys = getLeafKeys("section"); + sectionKeys.addAll(getLeafKeys("common")); + + if (sectionKeys.isEmpty()) { + missingSections.addAll(knownSections); + } else { + missingSections.addAll(Sets.difference(knownSections, sectionKeys)); + unknownSections.addAll(Sets.difference(sectionKeys, knownSections)); + } + } + + /** + * Verifies that the file has the expected entries for AuthMe commands. + */ + private void checkCommands() { + Set commandPaths = buildCommandPaths(); + Set existingKeys = getLeafKeys("commands"); + if (existingKeys.isEmpty()) { + missingCommands.addAll(commandPaths); + } else { + missingCommands.addAll(Sets.difference(commandPaths, existingKeys)); + unknownCommands.addAll(Sets.difference(existingKeys, commandPaths)); + } + } + + private static Set buildCommandPaths() { + Set commandPaths = new LinkedHashSet<>(); + for (CommandDescription command : new CommandInitializer().getCommands()) { + commandPaths.addAll(getYamlPaths(command)); + command.getChildren().forEach(child -> commandPaths.addAll(getYamlPaths(child))); + } + return commandPaths; + } + + private static List getYamlPaths(CommandDescription command) { + // e.g. commands.authme.register + String commandPath = "commands." + CommandUtils.constructParentList(command).stream() + .map(cmd -> cmd.getLabels().get(0)) + .collect(Collectors.joining(".")); + + // Entries each command can have + List paths = newArrayList(commandPath + ".description", commandPath + ".detailedDescription"); + + // Add argument entries that may exist + for (int argIndex = 1; argIndex <= command.getArguments().size(); ++argIndex) { + String argPath = String.format("%s.arg%d", commandPath, argIndex); + paths.add(argPath + ".label"); + paths.add(argPath + ".description"); + } + return paths; + } + + /** + * Returns the leaf keys of the section at the given path of the file configuration. + * + * @param path the path whose leaf keys should be retrieved + * @return leaf keys of the memory section, + * empty set if the configuration does not have a memory section at the given path + */ + private Set getLeafKeys(String path) { + if (!(configuration.get(path) instanceof MemorySection)) { + return Collections.emptySet(); + } + MemorySection memorySection = (MemorySection) configuration.get(path); + + // MemorySection#getKeys(true) returns all keys on all levels, e.g. if the configuration has + // 'commands.authme.register' then it also has 'commands.authme' and 'commands'. We can traverse each node and + // build its parents (e.g. for commands.authme.register.description: commands.authme.register, commands.authme, + // and commands, which we can remove from the collection since we know they are not a leaf. + Set leafKeys = memorySection.getKeys(true); + Set allKeys = new HashSet<>(leafKeys); + + for (String key : allKeys) { + List pathParts = Arrays.asList(key.split("\\.")); + + // We perform construction of parents & their removal in reverse order so we can build the lowest-level + // parent of a node first. As soon as the parent doesn't exist in the set already, we know we can continue + // with the next node since another node has already removed the concerned parents. + for (int i = pathParts.size() - 1; i > 0; --i) { + // e.g. for commands.authme.register -> i = {2, 1} => {commands.authme, commands} + String parentPath = String.join(".", pathParts.subList(0, i)); + if (!leafKeys.remove(parentPath)) { + break; + } + } + } + return leafKeys.stream().map(leaf -> path + "." + leaf).collect(Collectors.toSet()); + } +} diff --git a/src/test/java/tools/helptranslation/VerifyHelpTranslations.java b/src/test/java/tools/helptranslation/VerifyHelpTranslations.java new file mode 100644 index 000000000..f97447bf9 --- /dev/null +++ b/src/test/java/tools/helptranslation/VerifyHelpTranslations.java @@ -0,0 +1,72 @@ +package tools.helptranslation; + +import tools.utils.ToolTask; +import tools.utils.ToolsConstants; + +import java.io.File; +import java.util.Arrays; +import java.util.List; +import java.util.Scanner; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * Verifies the help translations for validity and completeness. + */ +public class VerifyHelpTranslations implements ToolTask { + + private static final Pattern HELP_MESSAGE_PATTERN = Pattern.compile("help_[a-z]{2,7}\\.yml"); + private static final String FOLDER = ToolsConstants.MAIN_RESOURCES_ROOT + "messages/"; + + @Override + public String getTaskName() { + return "verifyHelpTranslations"; + } + + @Override + public void execute(Scanner scanner) { + System.out.println("Check specific language file?"); + System.out.println("Enter the language code for a specific file (e.g. 'it' for help_it.yml)"); + System.out.println("Empty line will check all files in the resources messages folder (default)"); + + String language = scanner.nextLine(); + if (language.isEmpty()) { + getHelpTranslations().forEach(this::processFile); + } else { + processFile(new File(FOLDER, "help_" + language + ".yml")); + } + } + + private void processFile(File file) { + System.out.println("Checking '" + file.getName() + "'"); + HelpTranslationVerifier verifier = new HelpTranslationVerifier(file); + + // Check and output errors + if (!verifier.getMissingSections().isEmpty()) { + System.out.println("Missing sections: " + String.join(", ", verifier.getMissingSections())); + } + if (!verifier.getUnknownSections().isEmpty()) { + System.out.println("Unknown sections: " + String.join(", ", verifier.getUnknownSections())); + } + if (!verifier.getMissingCommands().isEmpty()) { + System.out.println("Missing command entries: " + String.join(", ", verifier.getMissingCommands())); + } + if (!verifier.getUnknownCommands().isEmpty()) { + System.out.println("Unknown command entries: " + String.join(", ", verifier.getUnknownCommands())); + } + } + + private static List getHelpTranslations() { + File[] files = new File(FOLDER).listFiles(); + if (files == null) { + throw new IllegalStateException("Could not get files from '" + FOLDER + "'"); + } + List helpFiles = Arrays.stream(files) + .filter(file -> HELP_MESSAGE_PATTERN.matcher(file.getName()).matches()) + .collect(Collectors.toList()); + if (helpFiles.isEmpty()) { + throw new IllegalStateException("Could not get any matching files!"); + } + return helpFiles; + } +} From 9d21a4cda288acd658121b694bb5783d0030a5d7 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 23 Oct 2016 18:17:09 +0200 Subject: [PATCH 17/25] Minor maintenance on ToolTask classes - Use default method on AutoToolTask interface in favor of abstract SimpleAutoTask class - Adjust the path in various .tpl.md files - Remove unused constant in ToolsConstants --- .../tools/checktestmocks/CheckTestMocks.java | 4 +-- src/test/java/tools/docs/UpdateDocsTask.java | 35 ++++++++----------- .../docs/commands/CommandPageCreater.java | 4 +-- .../java/tools/docs/commands/commands.tpl.md | 2 +- .../HashAlgorithmsDescriptionTask.java | 4 +-- .../docs/hashmethods/hash_algorithms.tpl.md | 2 +- .../permissions/PermissionsListWriter.java | 4 +-- .../docs/permissions/permission_nodes.tpl.md | 2 +- .../TranslationPageGenerator.java | 4 +-- .../docs/translations/translations.tpl.md | 2 +- .../filegeneration/GeneratePluginYml.java | 4 +-- src/test/java/tools/utils/AutoToolTask.java | 7 ++++ src/test/java/tools/utils/SimpleAutoTask.java | 15 -------- src/test/java/tools/utils/ToolsConstants.java | 3 -- 14 files changed, 37 insertions(+), 55 deletions(-) delete mode 100644 src/test/java/tools/utils/SimpleAutoTask.java diff --git a/src/test/java/tools/checktestmocks/CheckTestMocks.java b/src/test/java/tools/checktestmocks/CheckTestMocks.java index 1e8817aa2..9af3ae040 100644 --- a/src/test/java/tools/checktestmocks/CheckTestMocks.java +++ b/src/test/java/tools/checktestmocks/CheckTestMocks.java @@ -4,8 +4,8 @@ import com.google.common.collect.Sets; import fr.xephi.authme.ClassCollector; import fr.xephi.authme.TestHelper; import org.mockito.Mock; +import tools.utils.AutoToolTask; import tools.utils.InjectorUtils; -import tools.utils.SimpleAutoTask; import java.lang.reflect.Field; import java.util.ArrayList; @@ -19,7 +19,7 @@ import java.util.stream.Collectors; * Task checking if all tests' {@code @Mock} fields have a corresponding * {@code @Inject} field in the class they are testing. */ -public class CheckTestMocks extends SimpleAutoTask { +public class CheckTestMocks implements AutoToolTask { private List errors = new ArrayList<>(); diff --git a/src/test/java/tools/docs/UpdateDocsTask.java b/src/test/java/tools/docs/UpdateDocsTask.java index cfdb69ef9..84f723c64 100644 --- a/src/test/java/tools/docs/UpdateDocsTask.java +++ b/src/test/java/tools/docs/UpdateDocsTask.java @@ -1,26 +1,20 @@ package tools.docs; -import com.google.common.collect.ImmutableSet; -import tools.docs.commands.CommandPageCreater; -import tools.docs.hashmethods.HashAlgorithmsDescriptionTask; -import tools.docs.permissions.PermissionsListWriter; -import tools.docs.translations.TranslationPageGenerator; +import fr.xephi.authme.ClassCollector; +import fr.xephi.authme.TestHelper; import tools.utils.AutoToolTask; import tools.utils.ToolTask; +import java.util.List; import java.util.Scanner; -import java.util.Set; import java.util.function.Consumer; +import java.util.stream.Collectors; /** * Task that runs all tasks which update files in the docs folder. */ public class UpdateDocsTask implements AutoToolTask { - private static final Set> TASKS = ImmutableSet - .of(CommandPageCreater.class, HashAlgorithmsDescriptionTask.class, - PermissionsListWriter.class, TranslationPageGenerator.class); - @Override public String getTaskName() { return "updateDocs"; @@ -40,19 +34,18 @@ public class UpdateDocsTask implements AutoToolTask { }); } - private static ToolTask instantiateTask(Class clazz) { - try { - return clazz.newInstance(); - } catch (IllegalAccessException | InstantiationException e) { - throw new UnsupportedOperationException("Could not instantiate task class '" + clazz + "'", e); - } - } - - private static void executeTasks(Consumer taskRunner) { - for (Class taskClass : TASKS) { - ToolTask task = instantiateTask(taskClass); + private void executeTasks(Consumer taskRunner) { + for (ToolTask task : getDocTasks()) { System.out.println("\nRunning " + task.getTaskName() + "\n-------------------"); taskRunner.accept(task); } } + + private List getDocTasks() { + ClassCollector classCollector = + new ClassCollector(TestHelper.TEST_SOURCES_FOLDER, "tools/docs"); + return classCollector.getInstancesOfType(ToolTask.class).stream() + .filter(task -> task.getClass() != getClass()) + .collect(Collectors.toList()); + } } diff --git a/src/test/java/tools/docs/commands/CommandPageCreater.java b/src/test/java/tools/docs/commands/CommandPageCreater.java index eab18256a..ecf984664 100644 --- a/src/test/java/tools/docs/commands/CommandPageCreater.java +++ b/src/test/java/tools/docs/commands/CommandPageCreater.java @@ -5,15 +5,15 @@ import fr.xephi.authme.command.CommandDescription; import fr.xephi.authme.command.CommandInitializer; import fr.xephi.authme.command.CommandUtils; import fr.xephi.authme.permission.PermissionNode; +import tools.utils.AutoToolTask; import tools.utils.FileUtils; -import tools.utils.SimpleAutoTask; import tools.utils.TagValue.NestedTagValue; import tools.utils.TagValueHolder; import tools.utils.ToolsConstants; import java.util.Collection; -public class CommandPageCreater extends SimpleAutoTask { +public class CommandPageCreater implements AutoToolTask { private static final String OUTPUT_FILE = ToolsConstants.DOCS_FOLDER + "commands.md"; diff --git a/src/test/java/tools/docs/commands/commands.tpl.md b/src/test/java/tools/docs/commands/commands.tpl.md index c0f4da120..61018634c 100644 --- a/src/test/java/tools/docs/commands/commands.tpl.md +++ b/src/test/java/tools/docs/commands/commands.tpl.md @@ -1,5 +1,5 @@ - + ## AuthMe Commands You can use the following commands to use the features of AuthMe. Mandatory arguments are marked with `< >` diff --git a/src/test/java/tools/docs/hashmethods/HashAlgorithmsDescriptionTask.java b/src/test/java/tools/docs/hashmethods/HashAlgorithmsDescriptionTask.java index d6ba721cc..998214cf3 100644 --- a/src/test/java/tools/docs/hashmethods/HashAlgorithmsDescriptionTask.java +++ b/src/test/java/tools/docs/hashmethods/HashAlgorithmsDescriptionTask.java @@ -1,8 +1,8 @@ package tools.docs.hashmethods; import fr.xephi.authme.security.HashAlgorithm; +import tools.utils.AutoToolTask; import tools.utils.FileUtils; -import tools.utils.SimpleAutoTask; import tools.utils.TagValue.NestedTagValue; import tools.utils.TagValueHolder; import tools.utils.ToolsConstants; @@ -14,7 +14,7 @@ import java.util.Map; * * @see fr.xephi.authme.security.HashAlgorithm */ -public class HashAlgorithmsDescriptionTask extends SimpleAutoTask { +public class HashAlgorithmsDescriptionTask implements AutoToolTask { private static final String CUR_FOLDER = ToolsConstants.TOOLS_SOURCE_ROOT + "docs/hashmethods/"; private static final String OUTPUT_FILE = ToolsConstants.DOCS_FOLDER + "hash_algorithms.md"; diff --git a/src/test/java/tools/docs/hashmethods/hash_algorithms.tpl.md b/src/test/java/tools/docs/hashmethods/hash_algorithms.tpl.md index 17431eb5b..2f542b50f 100644 --- a/src/test/java/tools/docs/hashmethods/hash_algorithms.tpl.md +++ b/src/test/java/tools/docs/hashmethods/hash_algorithms.tpl.md @@ -1,5 +1,5 @@ - + ## Hash Algorithms AuthMe supports the following hash algorithms for storing your passwords safely. diff --git a/src/test/java/tools/docs/permissions/PermissionsListWriter.java b/src/test/java/tools/docs/permissions/PermissionsListWriter.java index ffd418e21..4e2197eed 100644 --- a/src/test/java/tools/docs/permissions/PermissionsListWriter.java +++ b/src/test/java/tools/docs/permissions/PermissionsListWriter.java @@ -1,7 +1,7 @@ package tools.docs.permissions; +import tools.utils.AutoToolTask; import tools.utils.FileUtils; -import tools.utils.SimpleAutoTask; import tools.utils.TagValue.NestedTagValue; import tools.utils.TagValueHolder; import tools.utils.ToolsConstants; @@ -12,7 +12,7 @@ import java.util.Map; * Task responsible for formatting a permissions node list and * for writing it to a file if desired. */ -public class PermissionsListWriter extends SimpleAutoTask { +public class PermissionsListWriter implements AutoToolTask { private static final String TEMPLATE_FILE = ToolsConstants.TOOLS_SOURCE_ROOT + "docs/permissions/permission_nodes.tpl.md"; private static final String PERMISSIONS_OUTPUT_FILE = ToolsConstants.DOCS_FOLDER + "permission_nodes.md"; diff --git a/src/test/java/tools/docs/permissions/permission_nodes.tpl.md b/src/test/java/tools/docs/permissions/permission_nodes.tpl.md index 8d2a2b4f4..8987f08bb 100644 --- a/src/test/java/tools/docs/permissions/permission_nodes.tpl.md +++ b/src/test/java/tools/docs/permissions/permission_nodes.tpl.md @@ -1,5 +1,5 @@ - + ## AuthMe Permission Nodes The following are the permission nodes that are currently supported by the latest dev builds. diff --git a/src/test/java/tools/docs/translations/TranslationPageGenerator.java b/src/test/java/tools/docs/translations/TranslationPageGenerator.java index 80619ba56..75232d287 100644 --- a/src/test/java/tools/docs/translations/TranslationPageGenerator.java +++ b/src/test/java/tools/docs/translations/TranslationPageGenerator.java @@ -2,8 +2,8 @@ package tools.docs.translations; import com.google.common.collect.ImmutableMap; import tools.docs.translations.TranslationsGatherer.TranslationInfo; +import tools.utils.AutoToolTask; import tools.utils.FileUtils; -import tools.utils.SimpleAutoTask; import tools.utils.TagValue.NestedTagValue; import tools.utils.TagValueHolder; import tools.utils.ToolsConstants; @@ -17,7 +17,7 @@ import static com.google.common.base.Objects.firstNonNull; /** * Generates the translations page in docs. */ -public class TranslationPageGenerator extends SimpleAutoTask { +public class TranslationPageGenerator implements AutoToolTask { private static final String DOCS_PAGE = ToolsConstants.DOCS_FOLDER + "translations.md"; private static final String TEMPLATE_FILE = ToolsConstants.TOOLS_SOURCE_ROOT + "docs/translations/translations.tpl.md"; diff --git a/src/test/java/tools/docs/translations/translations.tpl.md b/src/test/java/tools/docs/translations/translations.tpl.md index 199d4029c..5308b6554 100644 --- a/src/test/java/tools/docs/translations/translations.tpl.md +++ b/src/test/java/tools/docs/translations/translations.tpl.md @@ -1,5 +1,5 @@ - + # AuthMe Translations The following translations are available in AuthMe. Set `messagesLanguage` to the language code diff --git a/src/test/java/tools/filegeneration/GeneratePluginYml.java b/src/test/java/tools/filegeneration/GeneratePluginYml.java index 633c5aac8..3b5737be8 100644 --- a/src/test/java/tools/filegeneration/GeneratePluginYml.java +++ b/src/test/java/tools/filegeneration/GeneratePluginYml.java @@ -9,8 +9,8 @@ import fr.xephi.authme.permission.PermissionNode; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import tools.docs.permissions.PermissionNodesGatherer; +import tools.utils.AutoToolTask; import tools.utils.FileUtils; -import tools.utils.SimpleAutoTask; import tools.utils.ToolsConstants; import java.io.StringReader; @@ -26,7 +26,7 @@ import java.util.stream.Collectors; /** * Generates the command and permission section of plugin.yml. */ -public class GeneratePluginYml extends SimpleAutoTask { +public class GeneratePluginYml implements AutoToolTask { private static final String PLUGIN_YML_FILE = ToolsConstants.MAIN_RESOURCES_ROOT + "plugin.yml"; diff --git a/src/test/java/tools/utils/AutoToolTask.java b/src/test/java/tools/utils/AutoToolTask.java index b635fe5fe..61b909a52 100644 --- a/src/test/java/tools/utils/AutoToolTask.java +++ b/src/test/java/tools/utils/AutoToolTask.java @@ -1,5 +1,7 @@ package tools.utils; +import java.util.Scanner; + /** * Interface for tasks that can be run automatically, i.e. without any user input. */ @@ -10,4 +12,9 @@ public interface AutoToolTask extends ToolTask { */ void executeDefault(); + @Override + default void execute(Scanner scanner) { + executeDefault(); + } + } diff --git a/src/test/java/tools/utils/SimpleAutoTask.java b/src/test/java/tools/utils/SimpleAutoTask.java deleted file mode 100644 index 4c0c936d0..000000000 --- a/src/test/java/tools/utils/SimpleAutoTask.java +++ /dev/null @@ -1,15 +0,0 @@ -package tools.utils; - -import java.util.Scanner; - -/** - * Abstract class for auto tool tasks that perform exactly the same action for - * {@link ToolTask#execute(Scanner)} and {@link AutoToolTask#executeDefault()}. - */ -public abstract class SimpleAutoTask implements AutoToolTask { - - @Override - public final void execute(Scanner scanner) { - executeDefault(); - } -} diff --git a/src/test/java/tools/utils/ToolsConstants.java b/src/test/java/tools/utils/ToolsConstants.java index 5986c378b..e7ba3e05a 100644 --- a/src/test/java/tools/utils/ToolsConstants.java +++ b/src/test/java/tools/utils/ToolsConstants.java @@ -9,9 +9,6 @@ public final class ToolsConstants { public static final String MAIN_RESOURCES_ROOT = "src/main/resources/"; - // Add specific `fr.xephi.authme` package as not to include the tool tasks in the `tools` package - public static final String TEST_SOURCE_ROOT = "src/test/java/fr/xephi/authme"; - public static final String TOOLS_SOURCE_ROOT = "src/test/java/tools/"; public static final String DOCS_FOLDER = "docs/"; From b7a7d5b3bd5583dced41681096577451c1c8e86b Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 23 Oct 2016 18:29:00 +0200 Subject: [PATCH 18/25] #989 Create configuration docs page - Create tool task to generate a doc page with the generated config.yml - Rename tools.utils.FileUtils to FileIoUtils to avoid naming conflict with fr.xephi.authme.utils.FileUtils - Make all doc tasks output a success message at the end - Update all docs pages that have changed --- docs/commands.md | 8 +- docs/config.md | 451 ++++++++++++++++++ docs/translations.md | 52 +- .../docs/commands/CommandPageCreater.java | 4 +- .../docs/config/UpdateConfigPageTask.java | 49 ++ src/test/java/tools/docs/config/config.tpl.md | 16 + .../HashAlgorithmsDescriptionTask.java | 5 +- .../permissions/PermissionNodesGatherer.java | 4 +- .../permissions/PermissionsListWriter.java | 5 +- .../TranslationPageGenerator.java | 5 +- .../filegeneration/GeneratePluginYml.java | 6 +- .../tools/messages/MessageFileVerifier.java | 6 +- .../translation/ImportMessagesTask.java | 6 +- .../translation/WriteAllExportsTask.java | 4 +- .../{FileUtils.java => FileIoUtils.java} | 12 +- 15 files changed, 577 insertions(+), 56 deletions(-) create mode 100644 docs/config.md create mode 100644 src/test/java/tools/docs/config/UpdateConfigPageTask.java create mode 100644 src/test/java/tools/docs/config/config.tpl.md rename src/test/java/tools/utils/{FileUtils.java => FileIoUtils.java} (86%) diff --git a/docs/commands.md b/docs/commands.md index 4dd070fd6..b9f68054e 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -1,5 +1,5 @@ - + ## AuthMe Commands You can use the following commands to use the features of AuthMe. Mandatory arguments are marked with `< >` @@ -63,7 +63,8 @@ brackets; optional arguments are enclosed in square brackets (`[ ]`). - **/changepassword** <oldPassword> <newPassword>: Command to change your password using AuthMeReloaded.
Requires `authme.player.changepassword` - **/changepassword help** [query]: View detailed help for /changepassword commands. -- **/email**: The AuthMeReloaded Email command base. +- **/email**: The AuthMeReloaded email command base. +- **/email show**: Show your current email address. - **/email add** <email> <verifyEmail>: Add a new email address to your account.
Requires `authme.player.email.add` - **/email change** <oldEmail> <newEmail>: Change an email address of your account. @@ -75,7 +76,6 @@ brackets; optional arguments are enclosed in square brackets (`[ ]`).
Requires `authme.player.captcha` - **/captcha help** [query]: View detailed help for /captcha commands. - --- -This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Oct 16 21:39:08 CEST 2016 +This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Oct 23 18:25:12 CEST 2016 diff --git a/docs/config.md b/docs/config.md new file mode 100644 index 000000000..95e1de399 --- /dev/null +++ b/docs/config.md @@ -0,0 +1,451 @@ + + + +## AuthMe Configuration +The first time you run AuthMe it will create a config.yml file in the plugins/AuthMe folder, +with which you can configure various settings. This following is the initial contents of +the generated config.yml file. + +```yml + +DataSource: + # What type of database do you want to use? + # Valid values: sqlite, mysql + backend: 'SQLITE' + # Enable database caching, should improve database performance + caching: true + # Database host address + mySQLHost: '127.0.0.1' + # Database port + mySQLPort: '3306' + # Username about Database Connection Infos + mySQLUsername: 'authme' + # Password about Database Connection Infos + mySQLPassword: '12345' + # Database Name, use with converters or as SQLITE database name + mySQLDatabase: 'authme' + # Table of the database + mySQLTablename: 'authme' + # Column of IDs to sort data + mySQLColumnId: 'id' + # Column for storing or checking players nickname + mySQLColumnName: 'username' + # Column for storing or checking players RealName + mySQLRealName: 'realname' + # Column for storing players passwords + mySQLColumnPassword: 'password' + # Column for storing players emails + mySQLColumnEmail: 'email' + # Column for storing if a player is logged in or not + mySQLColumnLogged: 'isLogged' + # Column for storing players ips + mySQLColumnIp: 'ip' + # Column for storing players lastlogins + mySQLColumnLastLogin: 'lastlogin' + # Column for storing player LastLocation - X + mySQLlastlocX: 'x' + # Column for storing player LastLocation - Y + mySQLlastlocY: 'y' + # Column for storing player LastLocation - Z + mySQLlastlocZ: 'z' + # Column for storing player LastLocation - World Name + mySQLlastlocWorld: 'world' + # Overrides the size of the DB Connection Pool, -1 = Auto + poolSize: -1 +ExternalBoardOptions: + # Column for storing players passwords salts + mySQLColumnSalt: '' + # Column for storing players groups + mySQLColumnGroup: '' + # -1 means disabled. If you want that only activated players + # can log into your server, you can set here the group number + # of unactivated users, needed for some forum/CMS support + nonActivedUserGroup: -1 + # Other MySQL columns where we need to put the username (case-sensitive) + mySQLOtherUsernameColumns: [] + # How much log2 rounds needed in BCrypt (do not change if you do not know what it does) + bCryptLog2Round: 10 + # phpBB table prefix defined during the phpBB installation process + phpbbTablePrefix: 'phpbb_' + # phpBB activated group ID; 2 is the default registered group defined by phpBB + phpbbActivatedGroupId: 2 + # Wordpress prefix defined during WordPress installation + wordpressTablePrefix: 'wp_' +Converter: + Rakamak: + # Rakamak file name + fileName: 'users.rak' + # Rakamak use IP? + useIP: false + # Rakamak IP file name + ipFileName: 'UsersIp.rak' + CrazyLogin: + # CrazyLogin database file name + fileName: 'accounts.db' +settings: + sessions: + # Do you want to enable the session feature? + # If enabled, when a player authenticates successfully, + # his IP and his nickname is saved. + # The next time the player joins the server, if his IP + # is the same as last time and the timeout hasn't + # expired, he will not need to authenticate. + enabled: false + # After how many minutes should a session expire? + # Remember that sessions will end only after the timeout, and + # if the player's IP has changed but the timeout hasn't expired, + # the player will be kicked from the server due to invalid session + timeout: 10 + # Should the session expire if the player tries to log in with + # another IP address? + sessionExpireOnIpChange: true + # Message language, available: en, de, br, cz, pl, fr, ru, hu, sk, es, zhtw, fi, zhcn, lt, it, ko, pt + messagesLanguage: 'en' + restrictions: + # Keeps collisions disabled for logged players + # Works only with MC 1.9 + keepCollisionsDisabled: false + # Can not authenticated players chat? + # Keep in mind that this feature also blocks all commands not + # listed in the list below. + allowChat: false + # Hide the chat log from players who are not authenticated? + hideChat: false + # Allowed commands for unauthenticated players + allowCommands: + - '/login' + - '/register' + - '/l' + - '/reg' + - '/email' + - '/captcha' + # Max number of allowed registrations per IP + # The value 0 means an unlimited number of registrations! + maxRegPerIp: 1 + # Minimum allowed username length + minNicknameLength: 4 + # Maximum allowed username length + maxNicknameLength: 16 + # When this setting is enabled, online players can't be kicked out + # due to "Logged in from another Location" + # This setting will prevent potential security exploits. + ForceSingleSession: true + ForceSpawnLocOnJoin: + # If enabled, every player that spawn in one of the world listed in "ForceSpawnLocOnJoin.worlds" + # will be teleported to the spawnpoint after successful authentication. + # The quit location of the player will be overwritten. + # This is different from "teleportUnAuthedToSpawn" that teleport player + # to the spawnpoint on join. + enabled: false + # WorldNames where we need to force the spawn location + # Case-sensitive! + worlds: + - 'world' + - 'world_nether' + - 'world_the_end' + # This option will save the quit location of the players. + SaveQuitLocation: false + # To activate the restricted user feature you need + # to enable this option and configure the AllowedRestrictedUser field. + AllowRestrictedUser: false + # The restricted user feature will kick players listed below + # if they don't match the defined IP address. + # Example: + # AllowedRestrictedUser: + # - playername;127.0.0.1 + AllowedRestrictedUser: [] + # Should unregistered players be kicked immediately? + kickNonRegistered: false + # Should players be kicked on wrong password? + kickOnWrongPassword: false + # Should not logged in players be teleported to the spawn? + # After the authentication they will be teleported back to + # their normal position. + teleportUnAuthedToSpawn: false + # Can unregistered players walk around? + allowMovement: false + # Should not authenticated players have speed = 0? + # This will reset the fly/walk speed to default value after the login. + removeSpeed: true + # After how many seconds should players who fail to login or register + # be kicked? Set to 0 to disable. + timeout: 30 + # Regex syntax of allowed characters in the player name. + allowedNicknameCharacters: '[a-zA-Z0-9_]*' + # How far can unregistered players walk? + # Set to 0 for unlimited radius + allowedMovementRadius: 100 + # Enable double check of password when you register + # when it's true, registration requires that kind of command: + # /register + enablePasswordConfirmation: true + # Should we protect the player inventory before logging in? Requires ProtocolLib. + ProtectInventoryBeforeLogIn: true + # Should we deny the tabcomplete feature before logging in? Requires ProtocolLib. + DenyTabCompleteBeforeLogin: true + # Should we display all other accounts from a player when he joins? + # permission: /authme.admin.accounts + displayOtherAccounts: true + # Ban ip when the ip is not the ip registered in database + banUnsafedIP: false + # Spawn priority; values: authme, essentials, multiverse, default + spawnPriority: 'authme,essentials,multiverse,default' + # Maximum Login authorized by IP + maxLoginPerIp: 0 + # Maximum Join authorized by IP + maxJoinPerIp: 0 + # AuthMe will NEVER teleport players if set to true! + noTeleport: false + # Regex syntax for allowed chars in passwords + allowedPasswordCharacters: '[\x21-\x7E]*' + # Log level: INFO, FINE, DEBUG. Use INFO for general messages, + # FINE for some additional detailed ones (like password failed), + # and DEBUG for debugging + logLevel: 'FINE' + # By default we schedule async tasks when talking to the database + # If you want typical communication with the database to happen synchronously, set this to false + useAsyncTasks: true + GameMode: + # Force survival gamemode when player joins? + ForceSurvivalMode: false + unrestrictions: + # Below you can list all account names that + # AuthMe will ignore for registration or login, configure it + # at your own risk!! Remember that if you are going to add + # nickname with [], you have to delimit name with ' '. + # this option add compatibility with BuildCraft and some + # other mods. + # It is case-sensitive! + UnrestrictedName: [] + security: + # Minimum length of password + minPasswordLength: 5 + # Maximum length of password + passwordMaxLength: 30 + # This is a very important option: every time a player joins the server, + # if they are registered, AuthMe will switch him to unLoggedInGroup. + # This should prevent all major exploits. + # You can set up your permission plugin with this special group to have no permissions, + # or only permission to chat (or permission to send private messages etc.). + # The better way is to set up this group with few permissions, so if a player + # tries to exploit an account they can do only what you've defined for the group. + # After, a logged in player will be moved to his correct permissions group! + # Please note that the group name is case-sensitive, so 'admin' is different from 'Admin' + # Otherwise your group will be wiped and the player will join in the default group []! + # Example unLoggedinGroup: NotLogged + unLoggedinGroup: 'unLoggedinGroup' + # Possible values: MD5, SHA1, SHA256, WHIRLPOOL, XAUTH, MD5VB, PHPBB, + # MYBB, IPB3, PHPFUSION, SMF, XENFORO, SALTED2MD5, JOOMLA, BCRYPT, WBB3, SHA512, + # DOUBLEMD5, PBKDF2, PBKDF2DJANGO, WORDPRESS, ROYALAUTH, CUSTOM (for developers only) + passwordHash: 'SHA256' + # Salt length for the SALTED2MD5 MD5(MD5(password)+salt) + doubleMD5SaltLength: 8 + # If password checking return false, do we need to check with all + # other password algorithm to check an old password? + # AuthMe will update the password to the new password hash + supportOldPasswordHash: false + # Prevent unsafe passwords from being used; put them in lowercase! + # unsafePasswords: + # - '123456' + # - 'password' + unsafePasswords: + - '123456' + - 'password' + - 'qwerty' + - '12345' + - '54321' + - '123456789' + registration: + # Enable registration on the server? + enabled: true + # Send every X seconds a message to a player to + # remind him that he has to login/register + messageInterval: 5 + # Only registered and logged in players can play. + # See restrictions for exceptions + force: true + # Do we replace password registration by an email registration method? + enableEmailRegistrationSystem: false + # Enable double check of email when you register + # when it's true, registration requires that kind of command: + # /register + doubleEmailCheck: false + # Do we force kick a player after a successful registration? + # Do not use with login feature below + forceKickAfterRegister: false + # Does AuthMe need to enforce a /login after a successful registration? + forceLoginAfterRegister: false + # Force these commands after /login, without any '/', use %p to replace with player name + forceCommands: [] + # Force these commands after /login as service console, without any '/'. Use %p to replace with player name + forceCommandsAsConsole: [] + # Force these commands after /register, without any '/', use %p to replace with player name + forceRegisterCommands: [] + # Force these commands after /register as a server console, without any '/'. Use %p to replace with player name + forceRegisterCommandsAsConsole: [] + # Enable to display the welcome message (welcome.txt) after a login + # You can use colors in this welcome.txt + some replaced strings: + # {PLAYER}: player name, {ONLINE}: display number of online players, {MAXPLAYERS}: display server slots, + # {IP}: player ip, {LOGINS}: number of players logged, {WORLD}: player current world, {SERVER}: server name + # {VERSION}: get current bukkit version, {COUNTRY}: player country + useWelcomeMessage: true + # Do we need to broadcast the welcome message to all server or only to the player? set true for server or false for player + broadcastWelcomeMessage: false + # Should we delay the join message and display it once the player has logged in? + delayJoinMessage: false + # Should we remove the leave messages of unlogged users? + removeUnloggedLeaveMessage: false + # Should we remove join messages altogether? + removeJoinMessage: false + # Should we remove leave messages altogether? + removeLeaveMessage: false + # Do we need to add potion effect Blinding before login/reigster? + applyBlindEffect: false + # Do we need to prevent people to login with another case? + # If Xephi is registered, then Xephi can login, but not XEPHI/xephi/XePhI + preventOtherCase: false +permission: + # Take care with this option; if you want + # to use group switching of AuthMe + # for unloggedIn players, set this setting to true. + # Default is false. + EnablePermissionCheck: false +Email: + # Email SMTP server host + mailSMTP: 'smtp.gmail.com' + # Email SMTP server port + mailPort: 465 + # Email account which sends the mails + mailAccount: '' + # Email account password + mailPassword: '' + # Custom sender name, replacing the mailAccount name in the email + mailSenderName: '' + # Recovery password length + RecoveryPasswordLength: 8 + # Mail Subject + mailSubject: 'Your new AuthMe password' + # Like maxRegPerIP but with email + maxRegPerEmail: 1 + # Recall players to add an email? + recallPlayers: false + # Delay in minute for the recall scheduler + delayRecall: 5 + # Blacklist these domains for emails + emailBlacklisted: + - '10minutemail.com' + # Whitelist ONLY these domains for emails + emailWhitelisted: [] + # Send the new password drawn in an image? + generateImage: false + # The OAuth2 token + emailOauth2Token: '' +Hooks: + # Do we need to hook with multiverse for spawn checking? + multiverse: true + # Do we need to hook with BungeeCord? + bungeecord: false + # Send player to this BungeeCord server after register/login + sendPlayerTo: '' + # Do we need to disable Essentials SocialSpy on join? + disableSocialSpy: true + # Do we need to force /motd Essentials command on join? + useEssentialsMotd: false +GroupOptions: + # Unregistered permission group + UnregisteredPlayerGroup: '' + # Registered permission group + RegisteredPlayerGroup: '' +Protection: + # Enable some servers protection (country based login, antibot) + enableProtection: false + # Apply the protection also to registered usernames + enableProtectionRegistered: true + # Countries allowed to join the server and register, see http://dev.bukkit.org/bukkit-plugins/authme-reloaded/pages/countries-codes/ for countries' codes + # PLEASE USE QUOTES! + countries: + - 'US' + - 'GB' + # Countries not allowed to join the server and register + # PLEASE USE QUOTES! + countriesBlacklist: + - 'A1' + # Do we need to enable automatic antibot system? + enableAntiBot: true + # Max number of players allowed to login in 5 secs before the AntiBot system is enabled automatically + antiBotSensibility: 10 + # Duration in minutes of the antibot automatic system + antiBotDuration: 10 + # Delay in seconds before the antibot activation + antiBotDelay: 60 +Purge: + # If enabled, AuthMe automatically purges old, unused accounts + useAutoPurge: false + # Number of Days an account become Unused + daysBeforeRemovePlayer: 60 + # Do we need to remove the player.dat file during purge process? + removePlayerDat: false + # Do we need to remove the Essentials/userdata/player.yml file during purge process? + removeEssentialsFile: false + # World where are players.dat stores + defaultWorld: 'world' + # Do we need to remove LimitedCreative/inventories/player.yml, player_creative.yml files during purge process ? + removeLimitedCreativesInventories: false + # Do we need to remove the AntiXRayData/PlayerData/player file during purge process? + removeAntiXRayFile: false + # Do we need to remove permissions? + removePermissions: false +Security: + SQLProblem: + # Stop the server if we can't contact the sql database + # Take care with this, if you set this to false, + # AuthMe will automatically disable and the server won't be protected! + stopServer: true + ReloadCommand: + # /reload support + useReloadCommandSupport: true + console: + # Remove passwords from console? + removePassword: true + # Copy AuthMe log output in a separate file as well? + logConsole: true + captcha: + # Enable captcha when a player uses wrong password too many times + useCaptcha: false + # Max allowed tries before a captcha is required + maxLoginTry: 5 + # Captcha length + captchaLength: 5 + tempban: + # Tempban a user's IP address if they enter the wrong password too many times + enableTempban: false + # How many times a user can attempt to login before their IP being tempbanned + maxLoginTries: 10 + # The length of time a IP address will be tempbanned in minutes + # Default: 480 minutes, or 8 hours + tempbanLength: 480 + # How many minutes before resetting the count for failed logins by IP and username + # Default: 480 minutes (8 hours) + minutesBeforeCounterReset: 480 + recoveryCode: + # Number of characters a recovery code should have (0 to disable) + length: 8 + # How many hours is a recovery code valid for? + validForHours: 4 +BackupSystem: + # Enable or disable automatic backup + ActivateBackup: false + # Set backup at every start of server + OnServerStart: false + # Set backup at every stop of server + OnServerStop: true + # Windows only mysql installation Path + MysqlWindowsPath: 'C:\Program Files\MySQL\MySQL Server 5.1\' +``` + +To change settings on a running server, save your changes to config.yml and use +`/authme reload`. + +--- + +This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Oct 23 18:25:12 CEST 2016 diff --git a/docs/translations.md b/docs/translations.md index c261bb8f6..c4288f152 100644 --- a/docs/translations.md +++ b/docs/translations.md @@ -1,5 +1,5 @@ - + # AuthMe Translations The following translations are available in AuthMe. Set `messagesLanguage` to the language code @@ -8,32 +8,32 @@ in your config.yml to use the language, or use another language code to start a Code | Language | Translated |   ---- | -------- | ---------: | ------ [en](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_en.yml) | English | 100% | bar -[bg](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_bg.yml) | Bulgarian | 73% | bar -[br](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_br.yml) | Brazilian | 100% | bar -[cz](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_cz.yml) | Czech | 91% | bar -[de](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_de.yml) | German | 97% | bar -[es](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_es.yml) | Spanish | 100% | bar -[eu](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_eu.yml) | Basque | 66% | bar -[fi](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_fi.yml) | Finnish | 70% | bar -[fr](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_fr.yml) | French | 97% | bar -[gl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_gl.yml) | Galician | 74% | bar -[hu](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_hu.yml) | Hungarian | 100% | bar -[id](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_id.yml) | Indonesian | 74% | bar +[bg](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_bg.yml) | Bulgarian | 71% | bar +[br](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_br.yml) | Brazilian | 97% | bar +[cz](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_cz.yml) | Czech | 88% | bar +[de](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_de.yml) | German | 95% | bar +[es](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_es.yml) | Spanish | 97% | bar +[eu](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_eu.yml) | Basque | 64% | bar +[fi](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_fi.yml) | Finnish | 68% | bar +[fr](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_fr.yml) | French | 95% | bar +[gl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_gl.yml) | Galician | 72% | bar +[hu](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_hu.yml) | Hungarian | 97% | bar +[id](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_id.yml) | Indonesian | 72% | bar [it](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_it.yml) | Italian | 100% | bar -[ko](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ko.yml) | Korean | 76% | bar -[lt](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_lt.yml) | Latvian | 57% | bar -[nl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_nl.yml) | Dutch | 80% | bar -[pl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_pl.yml) | Polish | 95% | bar -[pt](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_pt.yml) | Portuguese | 91% | bar -[ru](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ru.yml) | Russian | 97% | bar -[sk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_sk.yml) | Slovakian | 50% | bar -[tr](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_tr.yml) | Turkish | 85% | bar -[uk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_uk.yml) | Ukrainian | 97% | bar -[vn](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_vn.yml) | Vietnamese | 85% | bar -[zhcn](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhcn.yml) | Chinese (China) | 85% | bar -[zhhk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhhk.yml) | Chinese (Hong Kong) | 85% | bar -[zhtw](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhtw.yml) | Chinese (Taiwan) | 85% | bar +[ko](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ko.yml) | Korean | 74% | bar +[lt](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_lt.yml) | Latvian | 55% | bar +[nl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_nl.yml) | Dutch | 78% | bar +[pl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_pl.yml) | Polish | 92% | bar +[pt](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_pt.yml) | Portuguese | 88% | bar +[ru](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ru.yml) | Russian | 95% | bar +[sk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_sk.yml) | Slovakian | 49% | bar +[tr](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_tr.yml) | Turkish | 83% | bar +[uk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_uk.yml) | Ukrainian | 95% | bar +[vn](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_vn.yml) | Vietnamese | 83% | bar +[zhcn](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhcn.yml) | Chinese (China) | 83% | bar +[zhhk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhhk.yml) | Chinese (Hong Kong) | 83% | bar +[zhtw](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhtw.yml) | Chinese (Taiwan) | 83% | bar --- -This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Oct 09 09:42:48 CEST 2016 +This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Oct 23 18:25:14 CEST 2016 diff --git a/src/test/java/tools/docs/commands/CommandPageCreater.java b/src/test/java/tools/docs/commands/CommandPageCreater.java index ecf984664..ff1500a77 100644 --- a/src/test/java/tools/docs/commands/CommandPageCreater.java +++ b/src/test/java/tools/docs/commands/CommandPageCreater.java @@ -6,7 +6,7 @@ import fr.xephi.authme.command.CommandInitializer; import fr.xephi.authme.command.CommandUtils; import fr.xephi.authme.permission.PermissionNode; import tools.utils.AutoToolTask; -import tools.utils.FileUtils; +import tools.utils.FileIoUtils; import tools.utils.TagValue.NestedTagValue; import tools.utils.TagValueHolder; import tools.utils.ToolsConstants; @@ -29,7 +29,7 @@ public class CommandPageCreater implements AutoToolTask { NestedTagValue commandTags = new NestedTagValue(); addCommandsInfo(commandTags, baseCommands); - FileUtils.generateFileFromTemplate( + FileIoUtils.generateFileFromTemplate( ToolsConstants.TOOLS_SOURCE_ROOT + "docs/commands/commands.tpl.md", OUTPUT_FILE, TagValueHolder.create().put("commands", commandTags)); diff --git a/src/test/java/tools/docs/config/UpdateConfigPageTask.java b/src/test/java/tools/docs/config/UpdateConfigPageTask.java new file mode 100644 index 000000000..f9a249a70 --- /dev/null +++ b/src/test/java/tools/docs/config/UpdateConfigPageTask.java @@ -0,0 +1,49 @@ +package tools.docs.config; + +import com.github.authme.configme.SettingsManager; +import com.github.authme.configme.resource.YamlFileResource; +import fr.xephi.authme.settings.properties.AuthMeSettingsRetriever; +import fr.xephi.authme.util.FileUtils; +import tools.utils.AutoToolTask; +import tools.utils.FileIoUtils; +import tools.utils.TagValueHolder; +import tools.utils.ToolsConstants; + +import java.io.File; +import java.io.IOException; + +/** + * Task for updating the config docs page. + */ +public class UpdateConfigPageTask implements AutoToolTask { + + private static final String TEMPLATE_FILE = ToolsConstants.TOOLS_SOURCE_ROOT + "docs/config/config.tpl.md"; + private static final String OUTPUT_FILE = ToolsConstants.DOCS_FOLDER + "config.md"; + + @Override + public String getTaskName() { + return "updateConfigPage"; + } + + @Override + public void executeDefault() { + File config = null; + try { + // Create empty temporary .yml file and save the config to it + config = File.createTempFile("authme-config-", ".yml"); + SettingsManager settingsManager = new SettingsManager( + new YamlFileResource(config), null, AuthMeSettingsRetriever.buildConfigurationData()); + settingsManager.save(); + + // Get the contents and generate template file + TagValueHolder tagValueHolder = TagValueHolder.create() + .put("config", FileIoUtils.readFromFile(config.toPath())); + FileIoUtils.generateFileFromTemplate(TEMPLATE_FILE, OUTPUT_FILE, tagValueHolder); + System.out.println("Wrote to '" + OUTPUT_FILE + "'"); + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + FileUtils.delete(config); + } + } +} diff --git a/src/test/java/tools/docs/config/config.tpl.md b/src/test/java/tools/docs/config/config.tpl.md new file mode 100644 index 000000000..25cf8c2c0 --- /dev/null +++ b/src/test/java/tools/docs/config/config.tpl.md @@ -0,0 +1,16 @@ + + + +## AuthMe Configuration +The first time you run AuthMe it will create a config.yml file in the plugins/AuthMe folder, +with which you can configure various settings. This following is the initial contents of +the generated config.yml file. + +```yml +{config} +``` + +To change settings on a running server, save your changes to config.yml and use +`/authme reload`. + +{gen_footer} diff --git a/src/test/java/tools/docs/hashmethods/HashAlgorithmsDescriptionTask.java b/src/test/java/tools/docs/hashmethods/HashAlgorithmsDescriptionTask.java index 998214cf3..b21d7fda3 100644 --- a/src/test/java/tools/docs/hashmethods/HashAlgorithmsDescriptionTask.java +++ b/src/test/java/tools/docs/hashmethods/HashAlgorithmsDescriptionTask.java @@ -2,7 +2,7 @@ package tools.docs.hashmethods; import fr.xephi.authme.security.HashAlgorithm; import tools.utils.AutoToolTask; -import tools.utils.FileUtils; +import tools.utils.FileIoUtils; import tools.utils.TagValue.NestedTagValue; import tools.utils.TagValueHolder; import tools.utils.ToolsConstants; @@ -28,7 +28,8 @@ public class HashAlgorithmsDescriptionTask implements AutoToolTask { // Write to the docs file TagValueHolder tags = TagValueHolder.create().put("algorithms", methodRows); - FileUtils.generateFileFromTemplate(CUR_FOLDER + "hash_algorithms.tpl.md", OUTPUT_FILE, tags); + FileIoUtils.generateFileFromTemplate(CUR_FOLDER + "hash_algorithms.tpl.md", OUTPUT_FILE, tags); + System.out.println("Wrote to '" + OUTPUT_FILE + "'"); } private static NestedTagValue constructMethodRows(Map descriptions) { diff --git a/src/test/java/tools/docs/permissions/PermissionNodesGatherer.java b/src/test/java/tools/docs/permissions/PermissionNodesGatherer.java index 034677cb8..e36355121 100644 --- a/src/test/java/tools/docs/permissions/PermissionNodesGatherer.java +++ b/src/test/java/tools/docs/permissions/PermissionNodesGatherer.java @@ -2,7 +2,7 @@ package tools.docs.permissions; import fr.xephi.authme.ClassCollector; import fr.xephi.authme.permission.PermissionNode; -import tools.utils.FileUtils; +import tools.utils.FileIoUtils; import tools.utils.ToolsConstants; import java.util.EnumSet; @@ -103,7 +103,7 @@ public class PermissionNodesGatherer { */ private static & PermissionNode> String getSourceForClass(Class clazz) { String classFile = ToolsConstants.MAIN_SOURCE_ROOT + clazz.getName().replace(".", "/") + ".java"; - return FileUtils.readFromFile(classFile); + return FileIoUtils.readFromFile(classFile); } } diff --git a/src/test/java/tools/docs/permissions/PermissionsListWriter.java b/src/test/java/tools/docs/permissions/PermissionsListWriter.java index 4e2197eed..797e26e79 100644 --- a/src/test/java/tools/docs/permissions/PermissionsListWriter.java +++ b/src/test/java/tools/docs/permissions/PermissionsListWriter.java @@ -1,7 +1,7 @@ package tools.docs.permissions; import tools.utils.AutoToolTask; -import tools.utils.FileUtils; +import tools.utils.FileIoUtils; import tools.utils.TagValue.NestedTagValue; import tools.utils.TagValueHolder; import tools.utils.ToolsConstants; @@ -27,9 +27,8 @@ public class PermissionsListWriter implements AutoToolTask { final NestedTagValue permissionsTagValue = generatePermissionsList(); TagValueHolder tags = TagValueHolder.create().put("nodes", permissionsTagValue); - FileUtils.generateFileFromTemplate(TEMPLATE_FILE, PERMISSIONS_OUTPUT_FILE, tags); + FileIoUtils.generateFileFromTemplate(TEMPLATE_FILE, PERMISSIONS_OUTPUT_FILE, tags); System.out.println("Wrote to '" + PERMISSIONS_OUTPUT_FILE + "'"); - System.out.println("Before committing, please verify the output!"); } private static NestedTagValue generatePermissionsList() { diff --git a/src/test/java/tools/docs/translations/TranslationPageGenerator.java b/src/test/java/tools/docs/translations/TranslationPageGenerator.java index 75232d287..240e7a640 100644 --- a/src/test/java/tools/docs/translations/TranslationPageGenerator.java +++ b/src/test/java/tools/docs/translations/TranslationPageGenerator.java @@ -3,7 +3,7 @@ package tools.docs.translations; import com.google.common.collect.ImmutableMap; import tools.docs.translations.TranslationsGatherer.TranslationInfo; import tools.utils.AutoToolTask; -import tools.utils.FileUtils; +import tools.utils.FileIoUtils; import tools.utils.TagValue.NestedTagValue; import tools.utils.TagValueHolder; import tools.utils.ToolsConstants; @@ -57,7 +57,8 @@ public class TranslationPageGenerator implements AutoToolTask { } TagValueHolder tags = TagValueHolder.create().put("languages", translationValuesHolder); - FileUtils.generateFileFromTemplate(TEMPLATE_FILE, DOCS_PAGE, tags); + FileIoUtils.generateFileFromTemplate(TEMPLATE_FILE, DOCS_PAGE, tags); + System.out.println("Wrote to '" + DOCS_PAGE + "'"); } /** diff --git a/src/test/java/tools/filegeneration/GeneratePluginYml.java b/src/test/java/tools/filegeneration/GeneratePluginYml.java index 3b5737be8..b4a017c62 100644 --- a/src/test/java/tools/filegeneration/GeneratePluginYml.java +++ b/src/test/java/tools/filegeneration/GeneratePluginYml.java @@ -10,7 +10,7 @@ import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import tools.docs.permissions.PermissionNodesGatherer; import tools.utils.AutoToolTask; -import tools.utils.FileUtils; +import tools.utils.FileIoUtils; import tools.utils.ToolsConstants; import java.io.StringReader; @@ -46,7 +46,7 @@ public class GeneratePluginYml implements AutoToolTask { configuration.set("commands", generateCommands()); configuration.set("permissions", generatePermissions()); - FileUtils.writeToFile(PLUGIN_YML_FILE, + FileIoUtils.writeToFile(PLUGIN_YML_FILE, pluginYmlStart + "\n" + configuration.saveToString()); } @@ -63,7 +63,7 @@ public class GeneratePluginYml implements AutoToolTask { * @return file configuration with the lower part of the plugin.yml file */ private FileConfiguration loadPartialPluginYmlFile() { - List pluginYmlLines = FileUtils.readLinesFromFile(Paths.get(PLUGIN_YML_FILE)); + List pluginYmlLines = FileIoUtils.readLinesFromFile(Paths.get(PLUGIN_YML_FILE)); int lineNr = 0; for (String line : pluginYmlLines) { if (line.equals("commands:")) { diff --git a/src/test/java/tools/messages/MessageFileVerifier.java b/src/test/java/tools/messages/MessageFileVerifier.java index f0be6bb44..b151228c1 100644 --- a/src/test/java/tools/messages/MessageFileVerifier.java +++ b/src/test/java/tools/messages/MessageFileVerifier.java @@ -8,7 +8,7 @@ import com.google.common.collect.Multimap; import fr.xephi.authme.message.MessageKey; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; -import tools.utils.FileUtils; +import tools.utils.FileIoUtils; import java.io.File; import java.util.ArrayList; @@ -104,7 +104,7 @@ public class MessageFileVerifier { * @param defaultMessages The collection of default messages */ public void addMissingKeys(FileConfiguration defaultMessages) { - final List fileLines = FileUtils.readLinesFromFile(messagesFile.toPath()); + final List fileLines = FileIoUtils.readLinesFromFile(messagesFile.toPath()); List keysToAdd = new ArrayList<>(); for (MissingKey entry : missingKeys) { @@ -135,7 +135,7 @@ public class MessageFileVerifier { addCommentForMissingTags(fileLines, key, entry.getValue()); } - FileUtils.writeToFile(messagesFile.toPath(), String.join("\n", fileLines)); + FileIoUtils.writeToFile(messagesFile.toPath(), String.join("\n", fileLines)); } /** diff --git a/src/test/java/tools/messages/translation/ImportMessagesTask.java b/src/test/java/tools/messages/translation/ImportMessagesTask.java index c70caaa3a..765c49f1f 100644 --- a/src/test/java/tools/messages/translation/ImportMessagesTask.java +++ b/src/test/java/tools/messages/translation/ImportMessagesTask.java @@ -7,7 +7,7 @@ import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import tools.messages.MessageFileVerifier; import tools.messages.VerifyMessagesTask; -import tools.utils.FileUtils; +import tools.utils.FileIoUtils; import tools.utils.ToolTask; import tools.utils.ToolsConstants; @@ -108,9 +108,9 @@ public class ImportMessagesTask implements ToolTask { * @param file The file whose to-do comments should be removed */ private static void removeAllTodoComments(String file) { - String contents = FileUtils.readFromFile(file); + String contents = FileIoUtils.readFromFile(file); String regex = "^# TODO .*$"; contents = Pattern.compile(regex, Pattern.MULTILINE).matcher(contents).replaceAll(""); - FileUtils.writeToFile(file, contents); + FileIoUtils.writeToFile(file, contents); } } diff --git a/src/test/java/tools/messages/translation/WriteAllExportsTask.java b/src/test/java/tools/messages/translation/WriteAllExportsTask.java index f5f3825bc..f0faf3b03 100644 --- a/src/test/java/tools/messages/translation/WriteAllExportsTask.java +++ b/src/test/java/tools/messages/translation/WriteAllExportsTask.java @@ -2,7 +2,7 @@ package tools.messages.translation; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; -import tools.utils.FileUtils; +import tools.utils.FileIoUtils; import tools.utils.ToolsConstants; import java.io.File; @@ -31,7 +31,7 @@ public class WriteAllExportsTask extends ExportMessagesTask { for (File file : messageFiles) { String code = file.getName().substring("messages_".length(), file.getName().length() - ".yml".length()); String json = convertToJson(code, defaultMessages, YamlConfiguration.loadConfiguration(file)); - FileUtils.writeToFile(OUTPUT_FOLDER + "messages_" + code + ".json", json); + FileIoUtils.writeToFile(OUTPUT_FOLDER + "messages_" + code + ".json", json); } } } diff --git a/src/test/java/tools/utils/FileUtils.java b/src/test/java/tools/utils/FileIoUtils.java similarity index 86% rename from src/test/java/tools/utils/FileUtils.java rename to src/test/java/tools/utils/FileIoUtils.java index 44bf5a296..4683633f9 100644 --- a/src/test/java/tools/utils/FileUtils.java +++ b/src/test/java/tools/utils/FileIoUtils.java @@ -9,11 +9,11 @@ import java.nio.file.StandardOpenOption; import java.util.List; /** - * Utility class for reading from and writing to files. + * Utility class for I/O operations on files. */ -public final class FileUtils { +public final class FileIoUtils { - private FileUtils() { + private FileIoUtils() { } public static void generateFileFromTemplate(String templateFile, String destinationFile, TagValueHolder tags) { @@ -43,8 +43,12 @@ public final class FileUtils { } public static String readFromFile(String file) { + return readFromFile(Paths.get(file)); + } + + public static String readFromFile(Path file) { try { - return new String(Files.readAllBytes(Paths.get(file)), StandardCharsets.UTF_8); + return new String(Files.readAllBytes(file), StandardCharsets.UTF_8); } catch (IOException e) { throw new UnsupportedOperationException("Could not read from file '" + file + "'", e); } From 9466577993ccea0d74d5f4a72947aa8ba4988193 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 23 Oct 2016 21:12:49 +0200 Subject: [PATCH 19/25] #989 Ensure config comments never exceed 90 chars - Prevents horizontal scrollbar on markdown page (and in users' editors) - Add test that each property is accompanied with a comment --- docs/config.md | 41 ++++++----- .../settings/properties/PluginSettings.java | 9 ++- .../properties/ProtectionSettings.java | 15 ++-- .../settings/properties/PurgeSettings.java | 4 +- .../properties/RegistrationSettings.java | 20 +++--- .../properties/RestrictionSettings.java | 6 +- .../settings/SettingsConsistencyTest.java | 69 +++++++++++++++++++ 7 files changed, 126 insertions(+), 38 deletions(-) create mode 100644 src/test/java/fr/xephi/authme/settings/SettingsConsistencyTest.java diff --git a/docs/config.md b/docs/config.md index 95e1de399..10980d8a5 100644 --- a/docs/config.md +++ b/docs/config.md @@ -1,5 +1,5 @@ - + ## AuthMe Configuration The first time you run AuthMe it will create a config.yml file in the plugins/AuthMe folder, @@ -99,7 +99,8 @@ settings: # Should the session expire if the player tries to log in with # another IP address? sessionExpireOnIpChange: true - # Message language, available: en, de, br, cz, pl, fr, ru, hu, sk, es, zhtw, fi, zhcn, lt, it, ko, pt + # Message language, available languages: + # https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/translations.md messagesLanguage: 'en' restrictions: # Keeps collisions disabled for logged players @@ -131,9 +132,9 @@ settings: # This setting will prevent potential security exploits. ForceSingleSession: true ForceSpawnLocOnJoin: - # If enabled, every player that spawn in one of the world listed in "ForceSpawnLocOnJoin.worlds" - # will be teleported to the spawnpoint after successful authentication. - # The quit location of the player will be overwritten. + # If enabled, every player that spawn in one of the world listed in + # "ForceSpawnLocOnJoin.worlds" will be teleported to the spawnpoint after successful + # authentication. The quit location of the player will be overwritten. # This is different from "teleportUnAuthedToSpawn" that teleport player # to the spawnpoint on join. enabled: false @@ -202,8 +203,8 @@ settings: # FINE for some additional detailed ones (like password failed), # and DEBUG for debugging logLevel: 'FINE' - # By default we schedule async tasks when talking to the database - # If you want typical communication with the database to happen synchronously, set this to false + # By default we schedule async tasks when talking to the database. If you want + # typical communication with the database to happen synchronously, set this to false useAsyncTasks: true GameMode: # Force survival gamemode when player joins? @@ -277,19 +278,23 @@ settings: forceLoginAfterRegister: false # Force these commands after /login, without any '/', use %p to replace with player name forceCommands: [] - # Force these commands after /login as service console, without any '/'. Use %p to replace with player name + # Force these commands after /login as service console, without any '/'. + # Use %p to replace with player name forceCommandsAsConsole: [] # Force these commands after /register, without any '/', use %p to replace with player name forceRegisterCommands: [] - # Force these commands after /register as a server console, without any '/'. Use %p to replace with player name + # Force these commands after /register as a server console, without any '/'. + # Use %p to replace with player name forceRegisterCommandsAsConsole: [] # Enable to display the welcome message (welcome.txt) after a login # You can use colors in this welcome.txt + some replaced strings: - # {PLAYER}: player name, {ONLINE}: display number of online players, {MAXPLAYERS}: display server slots, - # {IP}: player ip, {LOGINS}: number of players logged, {WORLD}: player current world, {SERVER}: server name + # {PLAYER}: player name, {ONLINE}: display number of online players, + # {MAXPLAYERS}: display server slots, {IP}: player ip, {LOGINS}: number of players logged, + # {WORLD}: player current world, {SERVER}: server name # {VERSION}: get current bukkit version, {COUNTRY}: player country useWelcomeMessage: true - # Do we need to broadcast the welcome message to all server or only to the player? set true for server or false for player + # Broadcast the welcome message to the server or only to the player? + # set true for server or false for player broadcastWelcomeMessage: false # Should we delay the join message and display it once the player has logged in? delayJoinMessage: false @@ -361,7 +366,8 @@ Protection: enableProtection: false # Apply the protection also to registered usernames enableProtectionRegistered: true - # Countries allowed to join the server and register, see http://dev.bukkit.org/bukkit-plugins/authme-reloaded/pages/countries-codes/ for countries' codes + # Countries allowed to join the server and register. For country codes, see + # http://dev.bukkit.org/bukkit-plugins/authme-reloaded/pages/countries-codes/ # PLEASE USE QUOTES! countries: - 'US' @@ -372,7 +378,8 @@ Protection: - 'A1' # Do we need to enable automatic antibot system? enableAntiBot: true - # Max number of players allowed to login in 5 secs before the AntiBot system is enabled automatically + # Max number of players allowed to login in 5 secs + # before the AntiBot system is enabled automatically antiBotSensibility: 10 # Duration in minutes of the antibot automatic system antiBotDuration: 10 @@ -381,7 +388,7 @@ Protection: Purge: # If enabled, AuthMe automatically purges old, unused accounts useAutoPurge: false - # Number of Days an account become Unused + # Number of days after which an account should be purged daysBeforeRemovePlayer: 60 # Do we need to remove the player.dat file during purge process? removePlayerDat: false @@ -389,7 +396,7 @@ Purge: removeEssentialsFile: false # World where are players.dat stores defaultWorld: 'world' - # Do we need to remove LimitedCreative/inventories/player.yml, player_creative.yml files during purge process ? + # Remove LimitedCreative/inventories/player.yml, player_creative.yml files during purge? removeLimitedCreativesInventories: false # Do we need to remove the AntiXRayData/PlayerData/player file during purge process? removeAntiXRayFile: false @@ -448,4 +455,4 @@ To change settings on a running server, save your changes to config.yml and use --- -This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Oct 23 18:25:12 CEST 2016 +This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Oct 23 21:08:57 CEST 2016 diff --git a/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java b/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java index bfb565337..094a3d5b9 100644 --- a/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java @@ -36,7 +36,10 @@ public class PluginSettings implements SettingsHolder { public static final Property SESSIONS_EXPIRE_ON_IP_CHANGE = newProperty("settings.sessions.sessionExpireOnIpChange", true); - @Comment("Message language, available: en, de, br, cz, pl, fr, ru, hu, sk, es, zhtw, fi, zhcn, lt, it, ko, pt") + @Comment({ + "Message language, available languages:", + "https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/translations.md" + }) public static final Property MESSAGES_LANGUAGE = newProperty("settings.messagesLanguage", "en"); @@ -65,8 +68,8 @@ public class PluginSettings implements SettingsHolder { newProperty(LogLevel.class, "settings.logLevel", LogLevel.FINE); @Comment({ - "By default we schedule async tasks when talking to the database", - "If you want typical communication with the database to happen synchronously, set this to false" + "By default we schedule async tasks when talking to the database. If you want", + "typical communication with the database to happen synchronously, set this to false" }) public static final Property USE_ASYNC_TASKS = newProperty("settings.useAsyncTasks", true); diff --git a/src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java b/src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java index cdd760bd2..834b7dd9e 100644 --- a/src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java @@ -20,13 +20,16 @@ public class ProtectionSettings implements SettingsHolder { public static final Property ENABLE_PROTECTION_REGISTERED = newProperty("Protection.enableProtectionRegistered", true); - @Comment({"Countries allowed to join the server and register, see http://dev.bukkit.org/bukkit-plugins/authme-reloaded/pages/countries-codes/ for countries' codes", - "PLEASE USE QUOTES!"}) + @Comment({ + "Countries allowed to join the server and register. For country codes, see", + "http://dev.bukkit.org/bukkit-plugins/authme-reloaded/pages/countries-codes/", + "PLEASE USE QUOTES!"}) public static final Property> COUNTRIES_WHITELIST = newListProperty("Protection.countries", "US", "GB"); - @Comment({"Countries not allowed to join the server and register", - "PLEASE USE QUOTES!"}) + @Comment({ + "Countries not allowed to join the server and register", + "PLEASE USE QUOTES!"}) public static final Property> COUNTRIES_BLACKLIST = newListProperty("Protection.countriesBlacklist", "A1"); @@ -34,7 +37,9 @@ public class ProtectionSettings implements SettingsHolder { public static final Property ENABLE_ANTIBOT = newProperty("Protection.enableAntiBot", true); - @Comment("Max number of players allowed to login in 5 secs before the AntiBot system is enabled automatically") + @Comment({ + "Max number of players allowed to login in 5 secs", + "before the AntiBot system is enabled automatically"}) public static final Property ANTIBOT_SENSIBILITY = newProperty("Protection.antiBotSensibility", 10); diff --git a/src/main/java/fr/xephi/authme/settings/properties/PurgeSettings.java b/src/main/java/fr/xephi/authme/settings/properties/PurgeSettings.java index f23a3eb12..b3733b5ac 100644 --- a/src/main/java/fr/xephi/authme/settings/properties/PurgeSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/PurgeSettings.java @@ -12,7 +12,7 @@ public class PurgeSettings implements SettingsHolder { public static final Property USE_AUTO_PURGE = newProperty("Purge.useAutoPurge", false); - @Comment("Number of Days an account become Unused") + @Comment("Number of days after which an account should be purged") public static final Property DAYS_BEFORE_REMOVE_PLAYER = newProperty("Purge.daysBeforeRemovePlayer", 60); @@ -28,7 +28,7 @@ public class PurgeSettings implements SettingsHolder { public static final Property DEFAULT_WORLD = newProperty("Purge.defaultWorld", "world"); - @Comment("Do we need to remove LimitedCreative/inventories/player.yml, player_creative.yml files during purge process ?") + @Comment("Remove LimitedCreative/inventories/player.yml, player_creative.yml files during purge?") public static final Property REMOVE_LIMITED_CREATIVE_INVENTORIES = newProperty("Purge.removeLimitedCreativesInventories", false); diff --git a/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java b/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java index b593869a3..487039ba7 100644 --- a/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java @@ -52,8 +52,9 @@ public class RegistrationSettings implements SettingsHolder { public static final Property> FORCE_COMMANDS = newListProperty("settings.forceCommands"); - @Comment("Force these commands after /login as service console, without any '/'. " - + "Use %p to replace with player name") + @Comment({ + "Force these commands after /login as service console, without any '/'.", + "Use %p to replace with player name"}) public static final Property> FORCE_COMMANDS_AS_CONSOLE = newListProperty("settings.forceCommandsAsConsole"); @@ -61,22 +62,25 @@ public class RegistrationSettings implements SettingsHolder { public static final Property> FORCE_REGISTER_COMMANDS = newListProperty("settings.forceRegisterCommands"); - @Comment("Force these commands after /register as a server console, without any '/'. " - + "Use %p to replace with player name") + @Comment({ + "Force these commands after /register as a server console, without any '/'.", + "Use %p to replace with player name"}) public static final Property> FORCE_REGISTER_COMMANDS_AS_CONSOLE = newListProperty("settings.forceRegisterCommandsAsConsole"); @Comment({ "Enable to display the welcome message (welcome.txt) after a login", "You can use colors in this welcome.txt + some replaced strings:", - "{PLAYER}: player name, {ONLINE}: display number of online players, {MAXPLAYERS}: display server slots,", - "{IP}: player ip, {LOGINS}: number of players logged, {WORLD}: player current world, {SERVER}: server name", + "{PLAYER}: player name, {ONLINE}: display number of online players,", + "{MAXPLAYERS}: display server slots, {IP}: player ip, {LOGINS}: number of players logged,", + "{WORLD}: player current world, {SERVER}: server name", "{VERSION}: get current bukkit version, {COUNTRY}: player country"}) public static final Property USE_WELCOME_MESSAGE = newProperty("settings.useWelcomeMessage", true); - @Comment("Do we need to broadcast the welcome message to all server or only to the player? set true for " - + "server or false for player") + @Comment({ + "Broadcast the welcome message to the server or only to the player?", + "set true for server or false for player"}) public static final Property BROADCAST_WELCOME_MESSAGE = newProperty("settings.broadcastWelcomeMessage", false); diff --git a/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java b/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java index 9e16714dd..4cd321f6b 100644 --- a/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java @@ -50,9 +50,9 @@ public class RestrictionSettings implements SettingsHolder { newProperty("settings.restrictions.ForceSingleSession", true); @Comment({ - "If enabled, every player that spawn in one of the world listed in \"ForceSpawnLocOnJoin.worlds\"", - "will be teleported to the spawnpoint after successful authentication.", - "The quit location of the player will be overwritten.", + "If enabled, every player that spawn in one of the world listed in", + "\"ForceSpawnLocOnJoin.worlds\" will be teleported to the spawnpoint after successful", + "authentication. The quit location of the player will be overwritten.", "This is different from \"teleportUnAuthedToSpawn\" that teleport player", "to the spawnpoint on join."}) public static final Property FORCE_SPAWN_LOCATION_AFTER_LOGIN = diff --git a/src/test/java/fr/xephi/authme/settings/SettingsConsistencyTest.java b/src/test/java/fr/xephi/authme/settings/SettingsConsistencyTest.java new file mode 100644 index 000000000..7123ac26b --- /dev/null +++ b/src/test/java/fr/xephi/authme/settings/SettingsConsistencyTest.java @@ -0,0 +1,69 @@ +package fr.xephi.authme.settings; + +import com.github.authme.configme.knownproperties.ConfigurationData; +import com.github.authme.configme.properties.Property; +import fr.xephi.authme.settings.properties.AuthMeSettingsRetriever; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import static org.junit.Assert.fail; + +/** + * Tests the consistency of the settings configuration. + */ +public class SettingsConsistencyTest { + + /** + * Maximum characters one comment line may have (prevents horizontal scrolling). + */ + private static final int MAX_COMMENT_LENGTH = 90; + + private static ConfigurationData configurationData; + + @BeforeClass + public static void buildConfigurationData() { + configurationData = AuthMeSettingsRetriever.buildConfigurationData(); + } + + @Test + public void shouldHaveCommentOnEachProperty() { + // given + List> properties = configurationData.getProperties(); + + // when / then + for (Property property : properties) { + if (configurationData.getCommentsForSection(property.getPath()).length == 0) { + fail("No comment defined for '" + property + "'"); + } + } + } + + @Test + public void shouldNotHaveVeryLongCommentLines() { + // given + List> properties = configurationData.getProperties(); + List> badProperties = new ArrayList<>(); + + // when + for (Property property : properties) { + for (String comment : configurationData.getCommentsForSection(property.getPath())) { + if (comment.length() > MAX_COMMENT_LENGTH) { + badProperties.add(property); + break; + } + } + } + + // then + if (!badProperties.isEmpty()) { + fail("Comment lines should not be longer than " + MAX_COMMENT_LENGTH + " chars, " + + "but found too long comments for:\n- " + + badProperties.stream().map(Property::getPath).collect(Collectors.joining("\n- "))); + } + } + +} From 3216a7ab27ca066a926bb7d9dcca0976c1acb4a3 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 23 Oct 2016 21:39:54 +0200 Subject: [PATCH 20/25] #987 Add "help" as default unsafe password --- .../authme/settings/properties/SecuritySettings.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java b/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java index 7d91f8183..92ce2e5ec 100644 --- a/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java @@ -18,10 +18,6 @@ public class SecuritySettings implements SettingsHolder { public static final Property STOP_SERVER_ON_PROBLEM = newProperty("Security.SQLProblem.stopServer", true); - @Comment("/reload support") - public static final Property USE_RELOAD_COMMAND_SUPPORT = - newProperty("Security.ReloadCommand.useReloadCommandSupport", true); - @Comment("Remove passwords from console?") public static final Property REMOVE_PASSWORD_FROM_CONSOLE = newProperty("Security.console.removePassword", true); @@ -85,11 +81,13 @@ public class SecuritySettings implements SettingsHolder { newProperty("settings.security.supportOldPasswordHash", false); @Comment({"Prevent unsafe passwords from being used; put them in lowercase!", + "You should always set 'help' as unsafePassword due to possible conflicts.", "unsafePasswords:", "- '123456'", - "- 'password'"}) + "- 'password'", + "- 'help'"}) public static final Property> UNSAFE_PASSWORDS = - newLowercaseListProperty("settings.security.unsafePasswords", "123456", "password", "qwerty", "12345", "54321", "123456789"); + newLowercaseListProperty("settings.security.unsafePasswords", "123456", "password", "qwerty", "12345", "54321", "123456789", "help"); @Comment("Tempban a user's IP address if they enter the wrong password too many times") public static final Property TEMPBAN_ON_MAX_LOGINS = From 0fc04e2bcfa06baae322edd4bbee0b3a2562a9be Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 23 Oct 2016 21:45:12 +0200 Subject: [PATCH 21/25] #823 Change default minimum username length to 3 --- .../xephi/authme/settings/properties/RestrictionSettings.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java b/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java index 4cd321f6b..c05efa4b5 100644 --- a/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java @@ -36,7 +36,7 @@ public class RestrictionSettings implements SettingsHolder { @Comment("Minimum allowed username length") public static final Property MIN_NICKNAME_LENGTH = - newProperty("settings.restrictions.minNicknameLength", 4); + newProperty("settings.restrictions.minNicknameLength", 3); @Comment("Maximum allowed username length") public static final Property MAX_NICKNAME_LENGTH = From 50610f630541feb53165deb2ebf2ea4433c2f8da Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 23 Oct 2016 21:50:44 +0200 Subject: [PATCH 22/25] #979 Provide more succinct error messages for missing command entries - Show only one error message if a command section is missing altogether - Remove "commands." prefix in missing command errors --- .../HelpTranslationVerifier.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/test/java/tools/helptranslation/HelpTranslationVerifier.java b/src/test/java/tools/helptranslation/HelpTranslationVerifier.java index 2ed130fa0..9cbf12b5c 100644 --- a/src/test/java/tools/helptranslation/HelpTranslationVerifier.java +++ b/src/test/java/tools/helptranslation/HelpTranslationVerifier.java @@ -55,11 +55,15 @@ public class HelpTranslationVerifier { } public List getMissingCommands() { - return missingCommands; + // All entries start with "command.", so remove that + return missingCommands.stream() + .map(s -> s.substring(9)).collect(Collectors.toList()); } public List getUnknownCommands() { - return unknownCommands; + // All entries start with "command.", so remove that + return unknownCommands.stream() + .map(s -> s.substring(9)).collect(Collectors.toList()); } /** @@ -89,14 +93,14 @@ public class HelpTranslationVerifier { Set commandPaths = buildCommandPaths(); Set existingKeys = getLeafKeys("commands"); if (existingKeys.isEmpty()) { - missingCommands.addAll(commandPaths); + missingCommands.addAll(commandPaths); // commandPaths should be empty in this case } else { missingCommands.addAll(Sets.difference(commandPaths, existingKeys)); unknownCommands.addAll(Sets.difference(existingKeys, commandPaths)); } } - private static Set buildCommandPaths() { + private Set buildCommandPaths() { Set commandPaths = new LinkedHashSet<>(); for (CommandDescription command : new CommandInitializer().getCommands()) { commandPaths.addAll(getYamlPaths(command)); @@ -105,11 +109,16 @@ public class HelpTranslationVerifier { return commandPaths; } - private static List getYamlPaths(CommandDescription command) { + private List getYamlPaths(CommandDescription command) { // e.g. commands.authme.register String commandPath = "commands." + CommandUtils.constructParentList(command).stream() .map(cmd -> cmd.getLabels().get(0)) .collect(Collectors.joining(".")); + // The entire command is not present, so just add it as a missing command and don't return any YAML path + if (!configuration.contains(commandPath)) { + missingCommands.add(commandPath); + return Collections.emptyList(); + } // Entries each command can have List paths = newArrayList(commandPath + ".description", commandPath + ".detailedDescription"); From 31d8b38fe5d0197aa51a7add59e5c20f3861444a Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sun, 23 Oct 2016 22:05:07 +0200 Subject: [PATCH 23/25] #826 add setting to define the antibot interval --- src/main/java/fr/xephi/authme/service/AntiBotService.java | 4 +++- .../authme/settings/properties/ProtectionSettings.java | 6 +++++- .../java/fr/xephi/authme/service/AntiBotServiceTest.java | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/fr/xephi/authme/service/AntiBotService.java b/src/main/java/fr/xephi/authme/service/AntiBotService.java index 24118d40c..c0d8b4390 100644 --- a/src/main/java/fr/xephi/authme/service/AntiBotService.java +++ b/src/main/java/fr/xephi/authme/service/AntiBotService.java @@ -30,6 +30,7 @@ public class AntiBotService implements SettingsDependent { private int duration; private int sensibility; private int delay; + private int interval; // Service status private AntiBotStatus antiBotStatus; @@ -60,6 +61,7 @@ public class AntiBotService implements SettingsDependent { duration = settings.getProperty(ProtectionSettings.ANTIBOT_DURATION); sensibility = settings.getProperty(ProtectionSettings.ANTIBOT_SENSIBILITY); delay = settings.getProperty(ProtectionSettings.ANTIBOT_DELAY); + interval = settings.getProperty(ProtectionSettings.ANTIBOT_INTERVAL); // Stop existing protection stopProtection(); @@ -174,7 +176,7 @@ public class AntiBotService implements SettingsDependent { public void run() { antibotPlayers--; } - }, 5 * TICKS_PER_SECOND); + }, interval * TICKS_PER_SECOND); } /** diff --git a/src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java b/src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java index 834b7dd9e..b725172f0 100644 --- a/src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java @@ -37,8 +37,12 @@ public class ProtectionSettings implements SettingsHolder { public static final Property ENABLE_ANTIBOT = newProperty("Protection.enableAntiBot", true); + @Comment("The interval in seconds") + public static final Property ANTIBOT_INTERVAL = + newProperty("Protection.antiBotInterval", 5); + @Comment({ - "Max number of players allowed to login in 5 secs", + "Max number of players allowed to login in the interval", "before the AntiBot system is enabled automatically"}) public static final Property ANTIBOT_SENSIBILITY = newProperty("Protection.antiBotSensibility", 10); diff --git a/src/test/java/fr/xephi/authme/service/AntiBotServiceTest.java b/src/test/java/fr/xephi/authme/service/AntiBotServiceTest.java index e40d5ca79..365313956 100644 --- a/src/test/java/fr/xephi/authme/service/AntiBotServiceTest.java +++ b/src/test/java/fr/xephi/authme/service/AntiBotServiceTest.java @@ -52,6 +52,7 @@ public class AntiBotServiceTest { @BeforeInjecting public void initSettings() { given(settings.getProperty(ProtectionSettings.ANTIBOT_DURATION)).willReturn(10); + given(settings.getProperty(ProtectionSettings.ANTIBOT_INTERVAL)).willReturn(5); given(settings.getProperty(ProtectionSettings.ANTIBOT_SENSIBILITY)).willReturn(5); given(settings.getProperty(ProtectionSettings.ENABLE_ANTIBOT)).willReturn(true); given(settings.getProperty(ProtectionSettings.ANTIBOT_DELAY)).willReturn(8); From 75425b439a6a4f9c6102e9f1893f7099c6e0af3e Mon Sep 17 00:00:00 2001 From: DeathrushW Date: Thu, 27 Oct 2016 02:03:06 -0200 Subject: [PATCH 24/25] Updating Translation BR! messages_br: show_no_email and email_show added help_br added --- src/main/resources/messages/help_br.yml | 45 +++++++++++++++++++++ src/main/resources/messages/messages_br.yml | 4 +- 2 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 src/main/resources/messages/help_br.yml diff --git a/src/main/resources/messages/help_br.yml b/src/main/resources/messages/help_br.yml new file mode 100644 index 000000000..fb33f375d --- /dev/null +++ b/src/main/resources/messages/help_br.yml @@ -0,0 +1,45 @@ +# Translation config for the AuthMe help, e.g. when /authme help or /authme help register is called + +# ------------------------------------------------------- +# List of texts used in the help section +common: + header: '==========[ CraftSkull HELP ]==========' + optional: 'Opcional' + hasPermission: 'Você tem permissão' + noPermission: 'Sem Permissão' + default: 'Default' + result: 'Resultado' + defaultPermissions: + notAllowed: 'Sem Permissão' + opOnly: 'OP''s only' + allowed: 'Todos podem' + +# ------------------------------------------------------- +# Titles of the individual help sections +# Set the translation text to empty text to disable the section, e.g. to hide alternatives: +# alternatives: '' +section: + command: 'Comando' + description: 'Pequena descrição' + detailedDescription: 'Descrição detalhada' + arguments: 'Argumentos' + permissions: 'Permissões' + alternatives: 'Alternativas' + children: 'Comandos' + +# ------------------------------------------------------- +# You can translate the data for all commands using the below pattern. +# For example to translate /authme reload, create a section "authme.reload", or "login" for /login +# If the command has arguments, you can use arg1 as below to translate the first argument, and so forth +# Translations don't need to be complete; any missing section will be taken from the default silently +# Important: Put main commands like "authme" before their children (e.g. "authme.reload") +commands: + authme.register: + description: 'Registra um jogador' + detailedDescription: 'Registra um esprecifico jogador com uma senha especifica.' + arg1: + label: 'player' + description: 'Nome do player' + arg2: + label: 'password' + description: 'Senha' diff --git a/src/main/resources/messages/messages_br.yml b/src/main/resources/messages/messages_br.yml index 8002a7a1a..8181658cd 100644 --- a/src/main/resources/messages/messages_br.yml +++ b/src/main/resources/messages/messages_br.yml @@ -61,6 +61,8 @@ email_confirm: '&cPor favor confirme seu endereço de email!' email_changed: '&2Troca de email com sucesso.!' email_send: '&2Recuperação de email enviada com sucesso! Por favor, verifique sua caixa de entrada de e-mail!' email_exists: '&cUm e-mail de recuperação já foi enviado! Você pode descartá-lo e enviar um novo usando o comando abaixo:' +email_show: '&2O seu endereço de e-mail atual é: &f%email' +show_no_email: '&2Você atualmente não têm endereço de e-mail associado a esta conta.' country_banned: '&4O seu país está banido neste servidor!' antibot_auto_enabled: '&4[AntiBotService] habilitado devido ao enorme número de conexões!' antibot_auto_disabled: '&2[AntiBotService] AntiBot desativada após %m minutos!' @@ -75,5 +77,3 @@ kicked_admin_registered: 'Um administrador registrou você; por favor faça logi incomplete_email_settings: 'Erro: Nem todas as configurações necessárias estão definidas para o envio de e-mails. Entre em contato com um administrador.' recovery_code_sent: 'Um código de recuperação para redefinir sua senha foi enviada para o seu e-mail.' recovery_code_incorrect: 'O código de recuperação esta incorreto! Use /email recovery [email] para gerar um novo!' -# TODO email_show: '&2Your current email address is: &f%email' -# TODO show_no_email: '&2You currently don''t have email address associated with this account.' \ No newline at end of file From b3e276d277765ca4fd2f007236caf7b08e9e8b6e Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Sat, 29 Oct 2016 14:00:51 +0200 Subject: [PATCH 25/25] Remove wrong header from BR help file --- src/main/resources/messages/help_br.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/resources/messages/help_br.yml b/src/main/resources/messages/help_br.yml index fb33f375d..90fc6cc04 100644 --- a/src/main/resources/messages/help_br.yml +++ b/src/main/resources/messages/help_br.yml @@ -3,7 +3,6 @@ # ------------------------------------------------------- # List of texts used in the help section common: - header: '==========[ CraftSkull HELP ]==========' optional: 'Opcional' hasPermission: 'Você tem permissão' noPermission: 'Sem Permissão'