diff --git a/pom.xml b/pom.xml index e92495db..574f362f 100644 --- a/pom.xml +++ b/pom.xml @@ -90,6 +90,14 @@ plugin.yml + + . + true + src/main/resources/ + + email.html + + . false diff --git a/src/main/java/fr/xephi/authme/DataManager.java b/src/main/java/fr/xephi/authme/DataManager.java index c3847f3b..451667ad 100644 --- a/src/main/java/fr/xephi/authme/DataManager.java +++ b/src/main/java/fr/xephi/authme/DataManager.java @@ -203,7 +203,7 @@ public class DataManager { } catch (Exception ignored) { } } - ConsoleLogger.info("AutoPurgeDatabase : Removed " + i + " permissions"); + ConsoleLogger.info("AutoPurgeDatabase : Removed " + i + "permissions"); /*int i = 0; for (String name : cleared) { diff --git a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java index b07c74d9..38784b16 100644 --- a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java +++ b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java @@ -5,7 +5,6 @@ import com.google.common.io.Files; import com.google.gson.*; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.util.Utils; import org.bukkit.entity.Player; import java.io.File; @@ -109,7 +108,7 @@ public class JsonCache { } File file = new File(cacheDir, path); if (file.exists()) { - Utils.purgeDirectory(file); + purgeDirectory(file); if (!file.delete()) { ConsoleLogger.showError("Failed to remove" + player.getName() + "cache."); } @@ -194,4 +193,25 @@ public class JsonCache { } } + /** + * Delete a given directory and all its content. + * + * @param directory The directory to remove + */ + private static void purgeDirectory(File directory) { + if (!directory.isDirectory()) { + return; + } + File[] files = directory.listFiles(); + if (files == null) { + return; + } + for (File target : files) { + if (target.isDirectory()) { + purgeDirectory(target); + } + target.delete(); + } + } + } diff --git a/src/main/java/fr/xephi/authme/command/CommandUtils.java b/src/main/java/fr/xephi/authme/command/CommandUtils.java index faed9639..e0ff117d 100644 --- a/src/main/java/fr/xephi/authme/command/CommandUtils.java +++ b/src/main/java/fr/xephi/authme/command/CommandUtils.java @@ -1,7 +1,12 @@ package fr.xephi.authme.command; +import com.google.common.collect.Lists; +import fr.xephi.authme.util.CollectionUtils; import fr.xephi.authme.util.StringUtils; +import java.util.ArrayList; +import java.util.List; + public final class CommandUtils { public static int getMinNumberOfArguments(CommandDescription command) { @@ -23,10 +28,20 @@ public final class CommandUtils { * the items ["authme", "register", "player"] it will return "authme register player". * * @param labels The labels to format + * * @return The space-separated labels */ public static String labelsToString(Iterable labels) { return StringUtils.join(" ", labels); } + public static String constructCommandPath(CommandDescription command) { + List labels = new ArrayList<>(); + CommandDescription currentCommand = command; + while (currentCommand != null) { + labels.add(currentCommand.getLabels().get(0)); + currentCommand = currentCommand.getParent(); + } + return "/" + labelsToString(Lists.reverse(labels)); + } } diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java index 0ef44a58..ea403554 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java @@ -52,7 +52,7 @@ public class UnregisterAdminCommand extends ExecutableCommand { } // Unregister the player - Player target = Bukkit.getPlayer(playerNameLowerCase); + Player target = Utils.getPlayer(playerNameLowerCase); PlayerCache.getInstance().removePlayer(playerNameLowerCase); Utils.setGroup(target, Utils.GroupType.UNREGISTERED); if (target != null && target.isOnline()) { @@ -68,11 +68,9 @@ public class UnregisterAdminCommand extends ExecutableCommand { LimboCache.getInstance().getLimboPlayer(playerNameLowerCase).setMessageTaskId( scheduler.runTaskAsynchronously(plugin, new MessageTask(plugin, playerNameLowerCase, m.retrieve(MessageKey.REGISTER_MESSAGE), interval))); - if (Settings.applyBlindEffect) - target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, Settings.getRegistrationTimeout * 20, 2)); - if (!Settings.isMovementAllowed && Settings.isRemoveSpeedEnabled) { - target.setWalkSpeed(0.0f); - target.setFlySpeed(0.0f); + if (Settings.applyBlindEffect) { + target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, + Settings.getRegistrationTimeout * 20, 2)); } m.send(target, MessageKey.UNREGISTERED_SUCCESS); diff --git a/src/main/java/fr/xephi/authme/command/executable/captcha/CaptchaCommand.java b/src/main/java/fr/xephi/authme/command/executable/captcha/CaptchaCommand.java index cca74066..2373f773 100644 --- a/src/main/java/fr/xephi/authme/command/executable/captcha/CaptchaCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/captcha/CaptchaCommand.java @@ -57,9 +57,7 @@ public class CaptchaCommand extends ExecutableCommand { plugin.cap.remove(playerNameLowerCase); String randStr = new RandomString(Settings.captchaLength).nextString(); plugin.cap.put(playerNameLowerCase, randStr); - for (String s : m.retrieve(MessageKey.CAPTCHA_WRONG_ERROR)) { - player.sendMessage(s.replace("THE_CAPTCHA", plugin.cap.get(playerNameLowerCase))); - } + m.send(player, MessageKey.CAPTCHA_WRONG_ERROR, plugin.cap.get(playerNameLowerCase)); return; } diff --git a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java index 2d12a720..8b26b08c 100644 --- a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java @@ -1,5 +1,6 @@ package fr.xephi.authme.datasource; +import com.google.common.base.Optional; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; @@ -21,7 +22,7 @@ public class CacheDataSource implements DataSource { private final DataSource source; private final ExecutorService exec; - private final LoadingCache cachedAuths; + private final LoadingCache> cachedAuths; /** * Constructor for CacheDataSource. @@ -33,9 +34,9 @@ public class CacheDataSource implements DataSource { this.exec = Executors.newCachedThreadPool(); cachedAuths = CacheBuilder.newBuilder() .expireAfterWrite(5, TimeUnit.MINUTES) - .removalListener(RemovalListeners.asynchronous(new RemovalListener() { + .removalListener(RemovalListeners.asynchronous(new RemovalListener>() { @Override - public void onRemoval(RemovalNotification removalNotification) { + public void onRemoval(RemovalNotification> removalNotification) { String name = removalNotification.getKey(); if (PlayerCache.getInstance().isAuthenticated(name)) { cachedAuths.getUnchecked(name); @@ -43,9 +44,9 @@ public class CacheDataSource implements DataSource { } }, exec)) .build( - new CacheLoader() { - public PlayerAuth load(String key) { - return source.getAuth(key); + new CacheLoader>() { + public Optional load(String key) { + return Optional.fromNullable(source.getAuth(key)); } }); } @@ -76,7 +77,7 @@ public class CacheDataSource implements DataSource { @Override public synchronized PlayerAuth getAuth(String user) { user = user.toLowerCase(); - return cachedAuths.getUnchecked(user); + return cachedAuths.getUnchecked(user).orNull(); } /** @@ -178,9 +179,9 @@ public class CacheDataSource implements DataSource { public int purgeDatabase(long until) { int cleared = source.purgeDatabase(until); if (cleared > 0) { - for (PlayerAuth auth : cachedAuths.asMap().values()) { - if (auth != null && auth.getLastLogin() < until) { - cachedAuths.invalidate(auth.getNickname()); + for (Optional auth : cachedAuths.asMap().values()) { + if (auth.isPresent() && auth.get().getLastLogin() < until) { + cachedAuths.invalidate(auth.get().getNickname()); } } } diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java index 30b4af72..1d407a3b 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeEntityListener.java @@ -36,6 +36,7 @@ public class AuthMeEntityListener implements Listener { } } + // TODO: npc status can be used to bypass security!!! /** * Method onEntityDamage. * @@ -53,7 +54,6 @@ public class AuthMeEntityListener implements Listener { return; } - // TODO: npc status can be used to bypass security!!! if (Utils.isNPC(player)) { return; } @@ -78,7 +78,6 @@ public class AuthMeEntityListener implements Listener { return; } - // TODO: npc status can be used to bypass security!!! if (Utils.isNPC((Player) entity)) { return; } @@ -104,7 +103,6 @@ public class AuthMeEntityListener implements Listener { return; } - // TODO: npc status can be used to bypass security!!! if (Utils.isNPC(player)) { return; } @@ -128,7 +126,6 @@ public class AuthMeEntityListener implements Listener { return; } - // TODO: npc status can be used to bypass security!!! if (Utils.isNPC((Player) entity)) { return; } @@ -152,7 +149,6 @@ public class AuthMeEntityListener implements Listener { return; } - // TODO: npc status can be used to bypass security!!! if (Utils.isNPC((Player) entity)) { return; } @@ -177,7 +173,6 @@ public class AuthMeEntityListener implements Listener { return; } - // TODO: npc status can be used to bypass security!!! if (Utils.isNPC((Player) entity)) { return; } @@ -201,7 +196,6 @@ public class AuthMeEntityListener implements Listener { return; } - // TODO: npc status can be used to bypass security!!! if (Utils.isNPC((Player) entity)) { return; } @@ -210,7 +204,6 @@ public class AuthMeEntityListener implements Listener { } // TODO: Need to check this, player can't throw snowball but the item is taken. - /** * Method onProjectileLaunch. * @@ -245,7 +238,6 @@ public class AuthMeEntityListener implements Listener { return; } - // TODO: npc status can be used to bypass security!!! if (Utils.isNPC(player)) { return; } @@ -270,7 +262,6 @@ public class AuthMeEntityListener implements Listener { return; } - // TODO: npc status can be used to bypass security!!! if (Utils.isNPC(player)) { return; } diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index e49215b3..337e13ec 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -229,7 +229,7 @@ public class AuthMePlayerListener implements Listener { if (auth != null && !auth.getRealName().equals("Player") && !auth.getRealName().equals(event.getName())) { event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER); event.setKickMessage("You should join using username: " + ChatColor.AQUA + auth.getRealName() + - ChatColor.RESET + "\nnot :" + ChatColor.RED + event.getName()); // TODO: write a better message + ChatColor.RESET + "\nnot: " + ChatColor.RED + event.getName()); // TODO: write a better message return; } @@ -288,7 +288,7 @@ public class AuthMePlayerListener implements Listener { pl.kickPlayer(m.retrieveSingle(MessageKey.KICK_FOR_VIP)); event.allow(); } else { - ConsoleLogger.info("The player " + event.getPlayer().getName() + " tryed to join, but the server was full"); + ConsoleLogger.info("The player " + event.getPlayer().getName() + " tried to join, but the server was full"); event.setKickMessage(m.retrieveSingle(MessageKey.KICK_FULL_SERVER)); event.setResult(PlayerLoginEvent.Result.KICK_FULL); } diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener16.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener16.java index 0975b18a..2c3c5d3c 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener16.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener16.java @@ -22,6 +22,7 @@ public class AuthMePlayerListener16 implements Listener { this.plugin = plugin; } + // TODO: npc status can be used to bypass security!!! /** * Method onPlayerEditBook. * @@ -33,7 +34,6 @@ public class AuthMePlayerListener16 implements Listener { return; } - // TODO: npc status can be used to bypass security!!! if (Utils.isNPC(event.getPlayer())) { return; } diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener18.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener18.java index dbcb1c71..f3d01028 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener18.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener18.java @@ -22,6 +22,7 @@ public class AuthMePlayerListener18 implements Listener { this.plugin = plugin; } + // TODO: npc status can be used to bypass security!!! /** * Method onPlayerInteractAtEntity. * @@ -33,7 +34,6 @@ public class AuthMePlayerListener18 implements Listener { return; } - // TODO: npc status can be used to bypass security!!! if (Utils.isNPC(event.getPlayer())) { return; } diff --git a/src/main/java/fr/xephi/authme/output/MessageKey.java b/src/main/java/fr/xephi/authme/output/MessageKey.java index bc024abf..b93f956b 100644 --- a/src/main/java/fr/xephi/authme/output/MessageKey.java +++ b/src/main/java/fr/xephi/authme/output/MessageKey.java @@ -79,7 +79,7 @@ public enum MessageKey { INVALID_NAME_LENGTH("name_len"), - INVALID_NAME_CHARACTERS("regex"), + INVALID_NAME_CHARACTERS("regex", "REG_EX"), ADD_EMAIL_MESSAGE("add_email"), @@ -87,7 +87,7 @@ public enum MessageKey { USAGE_CAPTCHA("usage_captcha"), - CAPTCHA_WRONG_ERROR("wrong_captcha"), + CAPTCHA_WRONG_ERROR("wrong_captcha", "THE_CAPTCHA"), CAPTCHA_SUCCESS("valid_captcha"), @@ -119,16 +119,32 @@ public enum MessageKey { ANTIBOT_AUTO_ENABLED_MESSAGE("antibot_auto_enabled"), - ANTIBOT_AUTO_DISABLED_MESSAGE("antibot_auto_disabled"); + ANTIBOT_AUTO_DISABLED_MESSAGE("antibot_auto_disabled", "%m"); private String key; + private String[] tags; - MessageKey(String key) { + MessageKey(String key, String... tags) { this.key = key; + this.tags = tags; } + /** + * Return the key used in the messages file. + * + * @return The key + */ public String getKey() { return key; } + + /** + * Return a list of tags (texts) that are replaced with actual content in AuthMe. + * + * @return List of tags + */ + public String[] getTags() { + return tags; + } } diff --git a/src/main/java/fr/xephi/authme/output/Messages.java b/src/main/java/fr/xephi/authme/output/Messages.java index ad586fd1..e27e9061 100644 --- a/src/main/java/fr/xephi/authme/output/Messages.java +++ b/src/main/java/fr/xephi/authme/output/Messages.java @@ -47,6 +47,31 @@ public class Messages { } } + /** + * Send the given message code to the player with the given tag replacements. Note that this method + * issues an exception if the number of supplied replacements doesn't correspond to the number of tags + * the message key contains. + * + * @param sender The entity to send the message to + * @param key The key of the message to send + * @param replacements The replacements to apply for the tags + */ + public void send(CommandSender sender, MessageKey key, String... replacements) { + String message = retrieveSingle(key); + String[] tags = key.getTags(); + if (replacements.length != tags.length) { + throw new RuntimeException("Given replacement size does not match the tags in message key '" + key + "'"); + } + + for (int i = 0; i < tags.length; ++i) { + message = message.replace(tags[i], replacements[i]); + } + + for (String line : message.split("\n")) { + sender.sendMessage(line); + } + } + /** * Retrieve the message from the text file and return it split by new line as an array. * diff --git a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java index 8a4bd654..dd1eb4b2 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java @@ -10,9 +10,9 @@ import fr.xephi.authme.events.FirstSpawnTeleportEvent; import fr.xephi.authme.events.ProtectInventoryEvent; import fr.xephi.authme.events.SpawnTeleportEvent; import fr.xephi.authme.listener.AuthMePlayerListener; -import fr.xephi.authme.permission.PlayerPermission; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.Messages; +import fr.xephi.authme.permission.PlayerPermission; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Spawn; import fr.xephi.authme.task.MessageTask; @@ -78,9 +78,9 @@ public class AsynchronousJoin { return; } if (Settings.getMaxJoinPerIp > 0 - && !plugin.getPermissionsManager().hasPermission(player, PlayerPermission.ALLOW_MULTIPLE_ACCOUNTS) - && !ip.equalsIgnoreCase("127.0.0.1") - && !ip.equalsIgnoreCase("localhost")) { + && !plugin.getPermissionsManager().hasPermission(player, PlayerPermission.ALLOW_MULTIPLE_ACCOUNTS) + && !ip.equalsIgnoreCase("127.0.0.1") + && !ip.equalsIgnoreCase("localhost")) { if (plugin.hasJoinedIp(player.getName(), ip)) { sched.scheduleSyncDelayedTask(plugin, new Runnable() { @@ -203,10 +203,6 @@ public class AsynchronousJoin { if (Settings.applyBlindEffect) { player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeOut, 2)); } - if (!Settings.isMovementAllowed && Settings.isRemoveSpeedEnabled) { - player.setWalkSpeed(0.0f); - player.setFlySpeed(0.0f); - } } }); @@ -236,8 +232,7 @@ public class AsynchronousJoin { ? m.retrieve(MessageKey.REGISTER_EMAIL_MESSAGE) : m.retrieve(MessageKey.REGISTER_MESSAGE); } - if (LimboCache.getInstance().getLimboPlayer(name) != null) - { + if (LimboCache.getInstance().getLimboPlayer(name) != null) { BukkitTask msgTask = sched.runTaskAsynchronously(plugin, new MessageTask(plugin, name, msg, msgInterval)); LimboCache.getInstance().getLimboPlayer(name).setMessageTaskId(msgTask); } diff --git a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java b/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java index 025defb2..b588361c 100644 --- a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java @@ -57,20 +57,10 @@ public class AsynchronousLogin { this.database = data; } - /** - * Method getIP. - * - * @return String - */ protected String getIP() { return plugin.getIP(player); } - /** - * Method needsCaptcha. - * - * @return boolean - */ protected boolean needsCaptcha() { if (Settings.useCaptcha) { if (!plugin.captcha.containsKey(name)) { @@ -82,9 +72,7 @@ public class AsynchronousLogin { } if (plugin.captcha.containsKey(name) && plugin.captcha.get(name) > Settings.maxLoginTry) { plugin.cap.putIfAbsent(name, rdm.nextString()); - for (String s : m.retrieve(MessageKey.USAGE_CAPTCHA)) { - player.sendMessage(s.replace("THE_CAPTCHA", plugin.cap.get(name)).replace("", plugin.cap.get(name))); - } + m.send(player, MessageKey.USAGE_CAPTCHA, plugin.cap.get(name)); return true; } } @@ -230,12 +218,6 @@ public class AsynchronousLogin { } } - /** - * Method displayOtherAccounts. - * - * @param auth PlayerAuth - * @param p Player - */ public void displayOtherAccounts(PlayerAuth auth, Player p) { if (!Settings.displayOtherAccounts) { return; diff --git a/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java b/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java index f64b2274..8c828074 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java @@ -189,11 +189,6 @@ public class ProcessSyncronousPlayerLogin implements Runnable { player.removePotionEffect(PotionEffectType.BLINDNESS); } - if (!Settings.isMovementAllowed && Settings.isRemoveSpeedEnabled) { - player.setWalkSpeed(0.2f); - player.setFlySpeed(0.1f); - } - // The Login event now fires (as intended) after everything is processed Bukkit.getServer().getPluginManager().callEvent(new LoginEvent(player, true)); player.saveData(); diff --git a/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java b/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java index 8f34c363..4fd6a9ca 100644 --- a/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java +++ b/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java @@ -80,10 +80,6 @@ public class ProcessSyncronousPlayerLogout implements Runnable { if (!Settings.isMovementAllowed) { player.setAllowFlight(true); player.setFlying(true); - if (!Settings.isMovementAllowed && Settings.isRemoveSpeedEnabled) { - player.setFlySpeed(0.0f); - player.setWalkSpeed(0.0f); - } } // Player is now logout... Time to fire event ! Bukkit.getServer().getPluginManager().callEvent(new LogoutEvent(player)); diff --git a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java index 668c0e3d..fb102ec9 100644 --- a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java @@ -141,8 +141,10 @@ public class AsyncRegister { return; } if (!Settings.forceRegLogin) { - PlayerCache.getInstance().addPlayer(auth); - database.setLogged(name); + //PlayerCache.getInstance().addPlayer(auth); + //database.setLogged(name); + // TODO: check this... + plugin.getManagement().performLogin(player, "dontneed", true); } plugin.otherAccounts.addPlayer(player.getUniqueId()); ProcessSyncPasswordRegister sync = new ProcessSyncPasswordRegister(player, plugin); diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java index 4c9136de..17916167 100644 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java @@ -128,11 +128,6 @@ public class ProcessSyncPasswordRegister implements Runnable { player.removePotionEffect(PotionEffectType.BLINDNESS); } - if (!Settings.isMovementAllowed && Settings.isRemoveSpeedEnabled) { - player.setWalkSpeed(0.0f); - player.setFlySpeed(0.0f); - } - // The LoginEvent now fires (as intended) after everything is processed plugin.getServer().getPluginManager().callEvent(new LoginEvent(player, true)); player.saveData(); diff --git a/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java b/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java index da5d19f9..53c54b3e 100644 --- a/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java +++ b/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java @@ -104,10 +104,6 @@ public class AsynchronousUnregister { if (Settings.applyBlindEffect) { player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeOut, 2)); } - if (!Settings.isMovementAllowed && Settings.isRemoveSpeedEnabled) { - player.setWalkSpeed(0.0f); - player.setFlySpeed(0.0f); - } m.send(player, MessageKey.UNREGISTERED_SUCCESS); ConsoleLogger.info(player.getDisplayName() + " unregistered himself"); Utils.teleportToSpawn(player); diff --git a/src/main/java/fr/xephi/authme/util/Utils.java b/src/main/java/fr/xephi/authme/util/Utils.java index e45b04a8..c96f47c6 100644 --- a/src/main/java/fr/xephi/authme/util/Utils.java +++ b/src/main/java/fr/xephi/authme/util/Utils.java @@ -15,7 +15,6 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.Player; -import java.io.File; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; @@ -207,27 +206,6 @@ public final class Utils { } } - /** - * Delete a given directory and all his content. - * - * @param directory File - */ - public static void purgeDirectory(File directory) { - if (!directory.isDirectory()) { - return; - } - File[] files = directory.listFiles(); - if (files == null) { - return; - } - for (File target : files) { - if (target.isDirectory()) { - purgeDirectory(target); - } - target.delete(); - } - } - /** * Safe way to retrieve the list of online players from the server. Depending on the * implementation of the server, either an array of {@link Player} instances is being returned, diff --git a/src/main/resources/messages/messages_cz.yml b/src/main/resources/messages/messages_cz.yml index 591e4e75..4108ea5a 100644 --- a/src/main/resources/messages/messages_cz.yml +++ b/src/main/resources/messages/messages_cz.yml @@ -38,7 +38,7 @@ regex: '&cTvuj nick obsahuje nepovolene znaky. Pripustne znaky jsou: REG_EX' add_email: '&cPridej prosim svuj email pomoci : /email add TvujEmail TvujEmail' recovery_email: '&cZapomel jsi heslo? Zadej: /email recovery ' usage_captcha: '&cPouzij: /captcha ' -wrong_captcha: '&cSpatne opsana Captcha, pouzij prosim: /captcha CAPTCHA_TEXT' +wrong_captcha: '&cSpatne opsana Captcha, pouzij prosim: /captcha THE_CAPTCHA' valid_captcha: '&cZadana captcha je v poradku!' kick_forvip: '&cVIP Hrac se pripojil na plny server!' kick_fullserver: '&cServer je plne obsazen, zkus to pozdeji prosim!' diff --git a/src/main/resources/messages/messages_en.yml b/src/main/resources/messages/messages_en.yml index fdb361a3..2d26cb1f 100644 --- a/src/main/resources/messages/messages_en.yml +++ b/src/main/resources/messages/messages_en.yml @@ -14,7 +14,7 @@ user_regged: '&cYou already have registered this username!' usage_reg: '&cUsage: /register ' max_reg: '&cYou have exceeded the maximum number of registrations for your connection!' no_perm: '&4You don''t have the permission to perform this action!' -error: '&4An unexpected error occurred, please contact an Administrator!' +error: '&4An unexpected error occurred, please contact an administrator!' login_msg: '&cPlease, login with the command "/login "' reg_msg: '&3Please, register to the server with the command "/register "' reg_email_msg: '&3Please, register to the server with the command "/register "' @@ -39,20 +39,20 @@ regex: '&4Your username contains illegal characters. Allowed chars: REG_EX' add_email: '&3Please add your email to your account with the command "/email add "' recovery_email: '&3Forgot your password? Please use the command "/email recovery "' usage_captcha: '&3To login you have to solve a captcha code, please use the command "/captcha "' -wrong_captcha: '&cWrong Captcha, please type "/captcha THE_CAPTCHA" into the chat!' +wrong_captcha: '&cWrong captcha, please type "/captcha THE_CAPTCHA" into the chat!' valid_captcha: '&2Captcha code solved correctly!' -kick_forvip: '&3A VIP Player has joined the server when it was full!' +kick_forvip: '&3A VIP player has joined the server when it was full!' kick_fullserver: '&4The server is full, try again later!' usage_email_add: '&cUsage: /email add ' usage_email_change: '&cUsage: /email change ' usage_email_recovery: '&cUsage: /email recovery ' -new_email_invalid: '&cInvalid New Email, try again!' -old_email_invalid: '&cInvalid Old Email, try again!' -email_invalid: '&cInvalid Email address, try again!' +new_email_invalid: '&cInvalid new email, try again!' +old_email_invalid: '&cInvalid old email, try again!' +email_invalid: '&cInvalid email address, try again!' email_added: '&2Email address successfully added to your account!' email_confirm: '&cPlease confirm your email address!' email_changed: '&2Email address changed correctly!' -email_send: '&2Recovery email sent correctly! Check your email inbox!' +email_send: '&2Recovery email sent successfully! Please check your email inbox!' email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:' country_banned: '&4Your country is banned from this server!' antibot_auto_enabled: '&4[AntiBotService] AntiBot enabled due to the huge number of connections!' diff --git a/src/main/resources/messages/messages_es.yml b/src/main/resources/messages/messages_es.yml index 850d750a..a7066330 100644 --- a/src/main/resources/messages/messages_es.yml +++ b/src/main/resources/messages/messages_es.yml @@ -39,7 +39,7 @@ regex: '&cTu usuario tiene carácteres no admitidos, los cuales son: REG_EX' add_email: '&cPor favor agrega tu e-mail con: /email add tuEmail confirmarEmail' recovery_email: '&c¿Olvidaste tu contraseña? Por favor usa /email recovery ' usage_captcha: '&cUso: /captcha ' -wrong_captcha: '&cCaptcha incorrecto, please use : /captcha EL_CAPTCHA' +wrong_captcha: '&cCaptcha incorrecto, please use : /captcha THE_CAPTCHA' valid_captcha: '&c¡ Captcha ingresado correctamente !' kick_forvip: '&cUn jugador VIP ha ingresado al servidor lleno!' kick_fullserver: '&cEl servidor está lleno, lo sentimos!' diff --git a/src/main/resources/messages/messages_hu.yml b/src/main/resources/messages/messages_hu.yml index 3245ce1a..f52e4f2b 100644 --- a/src/main/resources/messages/messages_hu.yml +++ b/src/main/resources/messages/messages_hu.yml @@ -1,4 +1,4 @@ -reg_only: Csak regisztrált játékosoknak! Jelentkezni a yndicraft@freemail.hu e-mail címen lehet +reg_only: Csak regisztrált játékosoknak! Jelentkezni a mail@email.com e-mail címen lehet usage_unreg: '&cHasználat: /unregister jelszó' registered: '&aSikeres regisztráció. Üdvözöllek!' user_regged: '&cJátékosnév már regisztrálva' diff --git a/src/test/java/fr/xephi/authme/command/CommandInitializerTest.java b/src/test/java/fr/xephi/authme/command/CommandInitializerTest.java index 66e77450..3df6cd13 100644 --- a/src/test/java/fr/xephi/authme/command/CommandInitializerTest.java +++ b/src/test/java/fr/xephi/authme/command/CommandInitializerTest.java @@ -5,6 +5,7 @@ import fr.xephi.authme.permission.PermissionNode; import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.WrapperMock; import org.junit.BeforeClass; +import org.junit.Ignore; import org.junit.Test; import java.util.ArrayList; @@ -269,6 +270,42 @@ public class CommandInitializerTest { walkThroughCommands(commands, adminPermissionChecker); } + /** + * Tests that multiple CommandDescription instances pointing to the same ExecutableCommand use the same + * count of arguments. + */ + @Test + @Ignore // TODO #306 ljacqu 20151214: Un-ignore this test and fix the offending command + public void shouldPointToSameExecutableCommandWithConsistentArgumentCount() { + // given + final Map, Integer> mandatoryArguments = new HashMap<>(); + final Map, Integer> totalArguments = new HashMap<>(); + + BiConsumer argChecker = new BiConsumer() { + @Override + public void accept(CommandDescription command, int depth) { + testCollectionForCommand(command, CommandUtils.getMinNumberOfArguments(command), mandatoryArguments); + testCollectionForCommand(command, CommandUtils.getMaxNumberOfArguments(command), totalArguments); + } + private void testCollectionForCommand(CommandDescription command, int argCount, + Map, Integer> collection) { + final Class clazz = command.getExecutableCommand().getClass(); + Integer existingCount = collection.get(clazz); + if (existingCount != null) { + String commandDescription = "Command with label '" + command.getLabels().get(0) + "' and parent '" + + (command.getParent() != null ? command.getLabels().get(0) : "null") + "' "; + assertThat(commandDescription + "should point to " + clazz + " with arguments consistent to others", + argCount, equalTo(existingCount)); + } else { + collection.put(clazz, argCount); + } + } + }; + + // when / then + walkThroughCommands(commands, argChecker); + } + // ------------ // Helper methods diff --git a/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java b/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java index aa7367e2..343a5687 100644 --- a/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java @@ -2,9 +2,11 @@ package fr.xephi.authme.output; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.util.WrapperMock; +import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.junit.Before; import org.junit.Test; +import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import java.io.File; @@ -14,6 +16,8 @@ import static org.hamcrest.Matchers.arrayWithSize; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.startsWith; import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; /** @@ -137,4 +141,58 @@ public class MessagesIntegrationTest { verify(player).sendMessage(line); } } + + @Test + public void shouldSendMessageToPlayerWithTagReplacement() { + // given + MessageKey key = MessageKey.CAPTCHA_WRONG_ERROR; + CommandSender sender = Mockito.mock(CommandSender.class); + + // when + messages.send(sender, key, "1234"); + + // then + ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); + verify(sender, times(1)).sendMessage(captor.capture()); + String message = captor.getValue(); + assertThat(message, equalTo("Use /captcha 1234 to solve the captcha")); + } + + @Test + public void shouldNotThrowForKeyWithNoTagReplacements() { + // given + MessageKey key = MessageKey.CAPTCHA_WRONG_ERROR; + CommandSender sender = mock(CommandSender.class); + + // when + messages.send(sender, key); + + // then + ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); + verify(sender, times(1)).sendMessage(captor.capture()); + String message = captor.getValue(); + assertThat(message, equalTo("Use /captcha THE_CAPTCHA to solve the captcha")); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowForInvalidReplacementCount() { + // given + MessageKey key = MessageKey.CAPTCHA_WRONG_ERROR; + + // when + messages.send(mock(CommandSender.class), key, "rep", "rep2"); + + // then - expect exception + } + + @Test(expected = RuntimeException.class) + public void shouldThrowForReplacementsOnKeyWithNoTags() { + // given + MessageKey key = MessageKey.UNKNOWN_USER; + + // when + messages.send(mock(CommandSender.class), key, "Replacement"); + + // then - expect exception + } } diff --git a/src/test/java/fr/xephi/authme/permission/AdminPermissionTest.java b/src/test/java/fr/xephi/authme/permission/AdminPermissionTest.java index 9a8625ac..0c2c2b16 100644 --- a/src/test/java/fr/xephi/authme/permission/AdminPermissionTest.java +++ b/src/test/java/fr/xephi/authme/permission/AdminPermissionTest.java @@ -13,9 +13,9 @@ import static org.junit.Assert.fail; public class AdminPermissionTest { @Test - public void shouldStartWithAuthMePrefix() { + public void shouldStartWithAuthMeAdminPrefix() { // given - String requiredPrefix = "authme."; + String requiredPrefix = "authme.admin."; // when/then for (AdminPermission permission : AdminPermission.values()) { @@ -26,20 +26,6 @@ public class AdminPermissionTest { } } - @Test - public void shouldContainAdminBranch() { - // given - String requiredBranch = ".admin."; - - // when/then - for (AdminPermission permission : AdminPermission.values()) { - if (!permission.getNode().contains(requiredBranch)) { - fail("The permission '" + permission + "' does not contain with the required branch '" - + requiredBranch + "'"); - } - } - } - @Test public void shouldHaveUniqueNodes() { // given diff --git a/src/test/java/fr/xephi/authme/permission/PlayerPermissionTest.java b/src/test/java/fr/xephi/authme/permission/PlayerPermissionTest.java index 6afc0ac0..632a2cf3 100644 --- a/src/test/java/fr/xephi/authme/permission/PlayerPermissionTest.java +++ b/src/test/java/fr/xephi/authme/permission/PlayerPermissionTest.java @@ -13,32 +13,13 @@ import static org.junit.Assert.fail; public class PlayerPermissionTest { @Test - public void shouldStartWithAuthMePrefix() { + public void shouldStartWithPlayerPrefix() { // given - String requiredPrefix = "authme."; + String playerBranch = "authme.player."; // when/then for (PlayerPermission permission : PlayerPermission.values()) { - if (!permission.getNode().startsWith(requiredPrefix)) { - fail("The permission '" + permission + "' does not start with the required prefix '" + requiredPrefix - + "'"); - } - } - } - - @Test - public void shouldContainPlayerBranch() { - // given - String playerBranch = ".player."; - String adminBranch = ".admin."; - - // when/then - for (PlayerPermission permission : PlayerPermission.values()) { - if (permission.getNode().contains(adminBranch)) { - fail("The permission '" + permission + "' should not use a node with the admin-specific branch '" - + adminBranch + "'"); - - } else if (!permission.getNode().contains(playerBranch)) { + if (!permission.getNode().startsWith(playerBranch)) { fail("The permission '" + permission + "' should use a node with the player-specific branch '" + playerBranch + "'"); } diff --git a/src/test/resources/messages_test.yml b/src/test/resources/messages_test.yml index 23dd12bd..73aea93e 100644 --- a/src/test/resources/messages_test.yml +++ b/src/test/resources/messages_test.yml @@ -4,3 +4,4 @@ not_logged_in: 'Apostrophes '' should be loaded correctly, don''t you think?' reg_voluntarily: 'You can register yourself to the server with the command "/register "' usage_log: '&cUsage: /login ' wrong_pwd: '&cWrong password!' +wrong_captcha: 'Use /captcha THE_CAPTCHA to solve the captcha' diff --git a/src/tools/commands/CommandPageCreater.java b/src/tools/commands/CommandPageCreater.java new file mode 100644 index 00000000..4d74dfba --- /dev/null +++ b/src/tools/commands/CommandPageCreater.java @@ -0,0 +1,70 @@ +package commands; + +import fr.xephi.authme.command.CommandArgumentDescription; +import fr.xephi.authme.command.CommandDescription; +import fr.xephi.authme.command.CommandInitializer; +import fr.xephi.authme.command.CommandPermissions; +import fr.xephi.authme.command.CommandUtils; +import fr.xephi.authme.permission.PermissionNode; +import utils.ANewMap; +import utils.FileUtils; +import utils.TagReplacer; +import utils.ToolTask; +import utils.ToolsConstants; + +import java.util.Map; +import java.util.Scanner; +import java.util.Set; + +public class CommandPageCreater implements ToolTask { + + @Override + public String getTaskName() { + return "createCommandPage"; + } + + @Override + public void execute(Scanner scanner) { + final Set baseCommands = CommandInitializer.getBaseCommands(); + final String template = FileUtils.readFromFile(ToolsConstants.TOOLS_SOURCE_ROOT + + "commands/command_entry.tpl.md"); + + StringBuilder commandsResult = new StringBuilder(); + for (CommandDescription command : baseCommands) { + Map tags = ANewMap + .with("command", CommandUtils.constructCommandPath(command)) + .and("description", command.getDetailedDescription()) + .and("arguments", formatArguments(command.getArguments())) + .and("permissions", formatPermissions(command.getCommandPermissions())) + .build(); + commandsResult.append(TagReplacer.applyReplacements(template, tags)); + } + + FileUtils.generateFileFromTemplate( + ToolsConstants.TOOLS_SOURCE_ROOT + "commands/commands.tpl.md", + ToolsConstants.DOCS_FOLDER + "commands.md", + ANewMap.with("commands", commandsResult.toString()).build()); + } + + private static String formatPermissions(CommandPermissions permissions) { + if (permissions == null) { + return ""; + } + String result = ""; + for (PermissionNode node : permissions.getPermissionNodes()) { + result += node.getNode() + " "; + } + return result; + } + + private static String formatArguments(Iterable arguments) { + StringBuilder result = new StringBuilder(); + for (CommandArgumentDescription argument : arguments) { + String argumentName = argument.isOptional() + ? "[" + argument.getDescription() + "]" + : "<" + argument.getDescription() + ">"; + result.append(argumentName).append(" "); + } + return result.toString(); + } +} diff --git a/src/tools/commands/command_entry.tpl.md b/src/tools/commands/command_entry.tpl.md new file mode 100644 index 00000000..c39b1deb --- /dev/null +++ b/src/tools/commands/command_entry.tpl.md @@ -0,0 +1,2 @@ +{command}: {description} _{arguments}_ +[permissions]Permission: {permissions}[/permissions] diff --git a/src/tools/commands/commands.tpl.md b/src/tools/commands/commands.tpl.md new file mode 100644 index 00000000..f2334c1b --- /dev/null +++ b/src/tools/commands/commands.tpl.md @@ -0,0 +1,4 @@ +## AuthMe commands +You can use the following commands to use the functions of AuthMe: + +{commands} diff --git a/src/tools/messages/MessageFileVerifier.java b/src/tools/messages/MessageFileVerifier.java index 75e9927e..904ea1af 100644 --- a/src/tools/messages/MessageFileVerifier.java +++ b/src/tools/messages/MessageFileVerifier.java @@ -1,11 +1,15 @@ package messages; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; import fr.xephi.authme.output.MessageKey; import utils.FileUtils; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -22,6 +26,7 @@ public class MessageFileVerifier { private final Set unknownKeys = new HashSet<>(); // Map with the missing key and a boolean indicating whether or not it was added to the file by this object private final Map missingKeys = new HashMap<>(); + private final Multimap missingTags = HashMultimap.create(); /** * Create a verifier that verifies the given messages file. @@ -53,8 +58,17 @@ public class MessageFileVerifier { return missingKeys; } + /** + * Return the collection of tags the message key defines that aren't present in the read line. + * + * @return Collection of missing tags per message key. Key = message key, value = missing tag. + */ + public Multimap getMissingTags() { + return missingTags; + } + private void verifyKeys() { - Set messageKeys = getAllMessageKeys(); + List messageKeys = getAllMessageKeys(); List fileLines = FileUtils.readLinesFromFile(messagesFile); for (String line : fileLines) { // Skip comments and empty lines @@ -64,22 +78,38 @@ public class MessageFileVerifier { } // All keys that remain are keys that are absent in the file - for (String missingKey : messageKeys) { - missingKeys.put(missingKey, false); + for (MessageKey missingKey : messageKeys) { + missingKeys.put(missingKey.getKey(), false); } } - private void processKeyInFile(String line, Set messageKeys) { + private void processKeyInFile(String line, List messageKeys) { if (line.indexOf(':') == -1) { System.out.println("Skipping line in unknown format: '" + line + "'"); return; } - final String key = line.substring(0, line.indexOf(':')); - if (messageKeys.contains(key)) { - messageKeys.remove(key); - } else { - unknownKeys.add(key); + final String readKey = line.substring(0, line.indexOf(':')); + boolean foundKey = false; + for (Iterator it = messageKeys.iterator(); it.hasNext(); ) { + MessageKey messageKey = it.next(); + if (messageKey.getKey().equals(readKey)) { + checkTagsInMessage(readKey, line.substring(line.indexOf(':')), messageKey.getTags()); + it.remove(); + foundKey = true; + break; + } + } + if (!foundKey) { + unknownKeys.add(readKey); + } + } + + private void checkTagsInMessage(String key, String message, String[] tags) { + for (String tag : tags) { + if (!message.contains(tag)) { + missingTags.put(key, tag); + } } } @@ -105,11 +135,7 @@ public class MessageFileVerifier { FileUtils.appendToFile(messagesFile, sb.toString()); } - private static Set getAllMessageKeys() { - Set messageKeys = new HashSet<>(MessageKey.values().length); - for (MessageKey key : MessageKey.values()) { - messageKeys.add(key.getKey()); - } - return messageKeys; + private static List getAllMessageKeys() { + return new ArrayList<>(Arrays.asList(MessageKey.values())); } } diff --git a/src/tools/messages/VerifyMessagesTask.java b/src/tools/messages/VerifyMessagesTask.java index 2a371216..19eacf24 100644 --- a/src/tools/messages/VerifyMessagesTask.java +++ b/src/tools/messages/VerifyMessagesTask.java @@ -1,5 +1,6 @@ package messages; +import com.google.common.collect.Multimap; import fr.xephi.authme.util.StringUtils; import utils.FileUtils; import utils.ToolTask; @@ -84,6 +85,11 @@ public final class VerifyMessagesTask implements ToolTask { if (!unknownKeys.isEmpty()) { System.out.println(" Unknown keys: " + unknownKeys); } + + Multimap missingTags = verifier.getMissingTags(); + for (Map.Entry entry : missingTags.entries()) { + System.out.println(" Missing tag '" + entry.getValue() + "' in entry with key '" + entry.getKey() + "'"); + } } private static void verifyFileAndAddKeys(MessageFileVerifier verifier, Map defaultMessages) { @@ -106,6 +112,11 @@ public final class VerifyMessagesTask implements ToolTask { if (!unknownKeys.isEmpty()) { System.out.println(" Unknown keys: " + unknownKeys); } + + Multimap missingTags = verifier.getMissingTags(); + for (Map.Entry entry : missingTags.entries()) { + System.out.println(" Missing tag '" + entry.getValue() + "' in entry with key '" + entry.getKey() + "'"); + } } private static Map constructDefaultMessages() { diff --git a/src/tools/permissions/PermissionsListWriter.java b/src/tools/permissions/PermissionsListWriter.java index 1d06b8ce..5958e077 100644 --- a/src/tools/permissions/PermissionsListWriter.java +++ b/src/tools/permissions/PermissionsListWriter.java @@ -47,7 +47,7 @@ public class PermissionsListWriter implements ToolTask { private static void generateAndWriteFile() { final String permissionsTagValue = generatePermissionsList(); - Map tags = ANewMap.with("permissions", permissionsTagValue).build(); + Map tags = ANewMap.with("permissions", permissionsTagValue).build(); FileUtils.generateFileFromTemplate( ToolsConstants.TOOLS_SOURCE_ROOT + "permissions/permission_nodes.tpl.md", PERMISSIONS_OUTPUT_FILE, tags); System.out.println("Wrote to '" + PERMISSIONS_OUTPUT_FILE + "'"); @@ -62,8 +62,8 @@ public class PermissionsListWriter implements ToolTask { StringBuilder sb = new StringBuilder(); for (Map.Entry entry : permissions.entrySet()) { - Map tags = ANewMap. - with("node", entry.getKey()) + Map tags = ANewMap + .with("node", entry.getKey()) .and("description", entry.getValue()) .build(); sb.append(TagReplacer.applyReplacements(template, tags)); diff --git a/src/tools/utils/FileUtils.java b/src/tools/utils/FileUtils.java index 5ad5ab25..49bcab9f 100644 --- a/src/tools/utils/FileUtils.java +++ b/src/tools/utils/FileUtils.java @@ -18,10 +18,9 @@ public final class FileUtils { private FileUtils() { } - public static void generateFileFromTemplate(String templateFile, String destinationFile, Map tags) { + public static void generateFileFromTemplate(String templateFile, String destinationFile, Map tags) { String template = readFromFile(templateFile); String result = TagReplacer.applyReplacements(template, tags); - writeToFile(destinationFile, result); } diff --git a/src/tools/utils/TagReplacer.java b/src/tools/utils/TagReplacer.java index 404857b7..29a9b91c 100644 --- a/src/tools/utils/TagReplacer.java +++ b/src/tools/utils/TagReplacer.java @@ -1,5 +1,7 @@ package utils; +import fr.xephi.authme.util.StringUtils; + import java.util.Date; import java.util.Map; @@ -21,10 +23,15 @@ public class TagReplacer { * any occurrences of "{foo}" to "bar". * @return The filled template */ - public static String applyReplacements(String template, Map tags) { + public static String applyReplacements(String template, Map tags) { String result = template; - for (Map.Entry tagRule : tags.entrySet()) { - result = result.replace("{" + tagRule.getKey() + "}", tagRule.getValue().toString()); + for (Map.Entry tagRule : tags.entrySet()) { + final String name = tagRule.getKey(); + final String value = tagRule.getValue(); + + String replacement = StringUtils.isEmpty(value) ? "" : "\\1"; + result = result.replaceAll("\\[" + name + "\\](.*?)\\[/" + name + "\\]", replacement); + result = result.replace("{" + tagRule.getKey() + "}", tagRule.getValue()); } return applyReplacements(result);