Merge branch '768-update-messages-cmd' of https://github.com/AuthMe-Team/AuthMeReloaded

This commit is contained in:
ljacqu 2016-10-18 17:09:13 +02:00
commit dc8d0b9b6b
11 changed files with 285 additions and 60 deletions

View File

@ -1,5 +1,5 @@
<!-- AUTO-GENERATED FILE! Do not edit this directly -->
<!-- File auto-generated on Sat Oct 01 23:33:39 CEST 2016. See commands/commands.tpl.md -->
<!-- File auto-generated on Sun Oct 16 21:39:08 CEST 2016. See commands/commands.tpl.md -->
## 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** &lt;job>: Converter command for AuthMeReloaded.
<br />Requires `authme.admin.converter`
- **/authme messages**: Adds missing messages to the current messages file.
<br />Requires `authme.admin.updatemessages`
- **/authme help** [query]: View detailed help for /authme commands.
- **/login** &lt;password>: Command to log in using AuthMeReloaded.
<br />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

View File

@ -1,5 +1,5 @@
<!-- AUTO-GENERATED FILE! Do not edit this directly -->
<!-- File auto-generated on Sun Oct 02 10:47:16 CEST 2016. See permissions/permission_nodes.tpl.md -->
<!-- File auto-generated on Sun Oct 16 21:39:10 CEST 2016. See permissions/permission_nodes.tpl.md -->
## 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

View File

@ -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;
@ -289,6 +290,15 @@ public class CommandInitializer {
.executableCommand(ConverterCommand.class)
.build();
CommandDescription.builder()
.parent(AUTHME_BASE)
.labels("messages", "msg")
.description("Add missing messages")
.detailedDescription("Adds missing messages to the current messages file.")
.permission(AdminPermission.UPDATE_MESSAGES)
.executableCommand(MessagesCommand.class)
.build();
// Register the base login command
final CommandDescription LOGIN_BASE = CommandDescription.builder()
.parent(null)

View File

@ -0,0 +1,54 @@
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;
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;
@Inject
private Messages messages;
@Override
public void executeCommand(CommandSender sender, List<String> arguments) {
final String language = settings.getProperty(PluginSettings.MESSAGES_LANGUAGE);
try {
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);
}
}
private static String getMessagePath(String code) {
return "messages/messages_" + code + ".yml";
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -0,0 +1,139 @@
package fr.xephi.authme.service;
import com.github.authme.configme.SettingsManager;
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;
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;
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 FileConfiguration userConfiguration;
private final FileConfiguration localJarConfiguration;
private final FileConfiguration defaultJarConfiguration;
private final List<Property<String>> properties;
private final SettingsManager settingsManager;
private boolean hasMissingMessages = false;
/**
* 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");
}
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, new ConfigurationData((List) properties));
}
/**
* 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 false;
}
// Save user configuration file
try {
settingsManager.save();
sender.sendMessage("Message file updated with new messages");
return true;
} catch (Exception e) {
throw new Exception("Could not save to messages file: " + StringUtils.formatException(e));
}
}
@SuppressWarnings("unchecked")
private void copyMissingMessages() {
for (Property<String> property : properties) {
String message = userConfiguration.getString(property.getPath());
if (message == null) {
hasMissingMessages = true;
message = getMessageFromJar(property.getPath());
}
settingsManager.setProperty(property, message);
}
}
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 List<Property<String>> buildPropertyEntriesForMessageKeys() {
return Arrays.stream(MessageKey.values())
.map(key -> new StringProperty(key.getKey(), ""))
.collect(Collectors.toList());
}
private static void close(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (IOException e) {
ConsoleLogger.info("Cannot close '" + closeable + "': " + StringUtils.formatException(e));
}
}
}
}

View File

@ -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.
*

View File

@ -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.

View File

@ -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