diff --git a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java index bd06dd6b3..299fc5846 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java @@ -107,9 +107,9 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess { // Login is now finished; we can force all commands if (isFirstLogin) { - commandManager.runCommandsOnFirstLogin(player); + commandManager.runCommandsOnFirstLogin(player, authsWithSameIp); } - commandManager.runCommandsOnLogin(player); + commandManager.runCommandsOnLogin(player, authsWithSameIp); // Send Bungee stuff. The service will check if it is enabled or not. bungeeSender.connectPlayerOnLogin(player); diff --git a/src/main/java/fr/xephi/authme/settings/commandconfig/CommandConfig.java b/src/main/java/fr/xephi/authme/settings/commandconfig/CommandConfig.java index e210f597c..29484ccdd 100644 --- a/src/main/java/fr/xephi/authme/settings/commandconfig/CommandConfig.java +++ b/src/main/java/fr/xephi/authme/settings/commandconfig/CommandConfig.java @@ -11,9 +11,9 @@ import java.util.Map; public class CommandConfig { private Map onJoin = new LinkedHashMap<>(); - private Map onLogin = new LinkedHashMap<>(); + private Map onLogin = new LinkedHashMap<>(); private Map onSessionLogin = new LinkedHashMap<>(); - private Map onFirstLogin = new LinkedHashMap<>(); + private Map onFirstLogin = new LinkedHashMap<>(); private Map onRegister = new LinkedHashMap<>(); private Map onUnregister = new LinkedHashMap<>(); private Map onLogout = new LinkedHashMap<>(); @@ -26,11 +26,11 @@ public class CommandConfig { this.onJoin = onJoin; } - public Map getOnLogin() { + public Map getOnLogin() { return onLogin; } - public void setOnLogin(Map onLogin) { + public void setOnLogin(Map onLogin) { this.onLogin = onLogin; } @@ -42,11 +42,11 @@ public class CommandConfig { this.onSessionLogin = onSessionLogin; } - public Map getOnFirstLogin() { + public Map getOnFirstLogin() { return onFirstLogin; } - public void setOnFirstLogin(Map onFirstLogin) { + public void setOnFirstLogin(Map onFirstLogin) { this.onFirstLogin = onFirstLogin; } diff --git a/src/main/java/fr/xephi/authme/settings/commandconfig/CommandManager.java b/src/main/java/fr/xephi/authme/settings/commandconfig/CommandManager.java index 6fdb5fdee..ab096fc60 100644 --- a/src/main/java/fr/xephi/authme/settings/commandconfig/CommandManager.java +++ b/src/main/java/fr/xephi/authme/settings/commandconfig/CommandManager.java @@ -17,6 +17,7 @@ import java.io.File; import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.function.Predicate; import static fr.xephi.authme.util.lazytags.TagBuilder.createTag; @@ -32,9 +33,9 @@ public class CommandManager implements Reloadable { private final List> availableTags = buildAvailableTags(); private WrappedTagReplacer onJoinCommands; - private WrappedTagReplacer onLoginCommands; + private WrappedTagReplacer onLoginCommands; private WrappedTagReplacer onSessionLoginCommands; - private WrappedTagReplacer onFirstLoginCommands; + private WrappedTagReplacer onFirstLoginCommands; private WrappedTagReplacer onRegisterCommands; private WrappedTagReplacer onUnregisterCommands; private WrappedTagReplacer onLogoutCommands; @@ -72,8 +73,10 @@ public class CommandManager implements Reloadable { * * @param player the player that logged in */ - public void runCommandsOnLogin(Player player) { - executeCommands(player, onLoginCommands.getAdaptedItems(player)); + public void runCommandsOnLogin(Player player, List otherAccounts) { + final int numberOfOtherAccounts = otherAccounts.size(); + executeCommands(player, onLoginCommands.getAdaptedItems(player), + cmd -> shouldCommandBeRun(cmd, numberOfOtherAccounts)); } /** @@ -90,8 +93,10 @@ public class CommandManager implements Reloadable { * * @param player the player that has logged in for the first time */ - public void runCommandsOnFirstLogin(Player player) { - executeCommands(player, onFirstLoginCommands.getAdaptedItems(player)); + public void runCommandsOnFirstLogin(Player player, List otherAccounts) { + final int numberOfOtherAccounts = otherAccounts.size(); + executeCommands(player, onFirstLoginCommands.getAdaptedItems(player), + cmd -> shouldCommandBeRun(cmd, numberOfOtherAccounts)); } /** @@ -113,16 +118,29 @@ public class CommandManager implements Reloadable { } private void executeCommands(Player player, List commands) { - for (Command command : commands) { - final String execution = command.getCommand(); - if (Executor.CONSOLE.equals(command.getExecutor())) { - bukkitService.dispatchConsoleCommand(execution); - } else { - bukkitService.dispatchCommand(player, execution); + executeCommands(player, commands, c -> true); + } + + private void executeCommands(Player player, List commands, Predicate predicate) { + for (T command : commands) { + if (predicate.test(command)) { + final String execution = command.getCommand(); + if (Executor.CONSOLE.equals(command.getExecutor())) { + bukkitService.dispatchConsoleCommand(execution); + } else { + bukkitService.dispatchCommand(player, execution); + } } } } + private static boolean shouldCommandBeRun(OnLoginCommand command, int numberOfOtherAccounts) { + return (!command.getNumberOfOtherAccountsAtLeast().isPresent() + || command.getNumberOfOtherAccountsAtLeast().get() >= numberOfOtherAccounts) + && (!command.getNumberOfOtherAccountsLessThan().isPresent() + || command.getNumberOfOtherAccountsLessThan().get() <= numberOfOtherAccounts); + } + @Override public void reload() { File file = new File(dataFolder, "commands.yml"); @@ -132,8 +150,8 @@ public class CommandManager implements Reloadable { new YamlFileResource(file), commandMigrationService, CommandSettingsHolder.class); CommandConfig commandConfig = settingsManager.getProperty(CommandSettingsHolder.COMMANDS); onJoinCommands = newReplacer(commandConfig.getOnJoin()); - onLoginCommands = newReplacer(commandConfig.getOnLogin()); - onFirstLoginCommands = newReplacer(commandConfig.getOnFirstLogin()); + onLoginCommands = newOnLoginCmdReplacer(commandConfig.getOnLogin()); + onFirstLoginCommands = newOnLoginCmdReplacer(commandConfig.getOnFirstLogin()); onSessionLoginCommands = newReplacer(commandConfig.getOnSessionLogin()); onRegisterCommands = newReplacer(commandConfig.getOnRegister()); onUnregisterCommands = newReplacer(commandConfig.getOnUnregister()); @@ -145,6 +163,13 @@ public class CommandManager implements Reloadable { (cmd, text) -> new Command(text, cmd.getExecutor())); } + private WrappedTagReplacer newOnLoginCmdReplacer( + Map commands) { + + return new WrappedTagReplacer<>(availableTags, commands.values(), Command::getCommand, + (cmd, text) -> new OnLoginCommand(text, cmd.getExecutor())); + } + private List> buildAvailableTags() { return Arrays.asList( createTag("%p", pl -> pl.getName()), diff --git a/src/main/java/fr/xephi/authme/settings/commandconfig/CommandMigrationService.java b/src/main/java/fr/xephi/authme/settings/commandconfig/CommandMigrationService.java index acd39cc64..0b631fcad 100644 --- a/src/main/java/fr/xephi/authme/settings/commandconfig/CommandMigrationService.java +++ b/src/main/java/fr/xephi/authme/settings/commandconfig/CommandMigrationService.java @@ -12,6 +12,7 @@ import fr.xephi.authme.util.RandomStringUtils; import javax.inject.Inject; import java.util.List; import java.util.Map; +import java.util.function.BiFunction; import java.util.function.Function; import java.util.stream.Collectors; @@ -70,12 +71,14 @@ class CommandMigrationService implements MigrationService { ON_JOIN( SettingsMigrationService::getOnLoginCommands, Executor.PLAYER, - CommandConfig::getOnLogin), + CommandConfig::getOnLogin, + OnLoginCommand::new), ON_JOIN_CONSOLE( SettingsMigrationService::getOnLoginConsoleCommands, Executor.CONSOLE, - CommandConfig::getOnLogin), + CommandConfig::getOnLogin, + OnLoginCommand::new), ON_REGISTER( SettingsMigrationService::getOnRegisterCommands, @@ -90,6 +93,7 @@ class CommandMigrationService implements MigrationService { private final Function> legacyCommandsGetter; private final Executor executor; private final Function> commandMapGetter; + private final BiFunction commandConstructor; /** * Constructor. @@ -102,9 +106,29 @@ class CommandMigrationService implements MigrationService { MigratableCommandSection(Function> legacyCommandsGetter, Executor executor, Function> commandMapGetter) { + this(legacyCommandsGetter, executor, commandMapGetter, Command::new); + } + + /** + * Constructor. + * + * @param legacyCommandsGetter getter on MigrationService to get the deprecated command entries + * @param executor the executor of the commands + * @param commandMapGetter the getter for the commands map in the new settings structure to add the old + * settings to after conversion + * @param commandConstructor constructor for creating a command object + */ + MigratableCommandSection( + Function> legacyCommandsGetter, + Executor executor, + Function> commandMapGetter, + BiFunction commandConstructor) { + this.legacyCommandsGetter = legacyCommandsGetter; this.executor = executor; - this.commandMapGetter = commandMapGetter; + // This is horrible to be doing but this way we don't need to cast in convertCommands() + this.commandMapGetter = (Function) commandMapGetter; + this.commandConstructor = (BiFunction) commandConstructor; } /** @@ -117,7 +141,7 @@ class CommandMigrationService implements MigrationService { */ boolean convertCommands(SettingsMigrationService settingsMigrationService, CommandConfig commandConfig) { List commands = legacyCommandsGetter.apply(settingsMigrationService).stream() - .map(cmd -> new Command(cmd, executor)).collect(Collectors.toList()); + .map(cmd -> commandConstructor.apply(cmd, executor)).collect(Collectors.toList()); if (commands.isEmpty()) { return false; diff --git a/src/main/java/fr/xephi/authme/settings/commandconfig/OnLoginCommand.java b/src/main/java/fr/xephi/authme/settings/commandconfig/OnLoginCommand.java new file mode 100644 index 000000000..9a3a25bc4 --- /dev/null +++ b/src/main/java/fr/xephi/authme/settings/commandconfig/OnLoginCommand.java @@ -0,0 +1,44 @@ +package fr.xephi.authme.settings.commandconfig; + +import java.util.Optional; + +/** + * Configurable command for when a player logs in. + */ +public class OnLoginCommand extends Command { + + private Optional numberOfOtherAccountsAtLeast; + private Optional numberOfOtherAccountsLessThan; + + /** + * Default constructor (for bean mapping). + */ + public OnLoginCommand() { + } + + /** + * Constructor. + * + * @param command the command to execute + * @param executor the executor of the command + */ + public OnLoginCommand(String command, Executor executor) { + super(command, executor); + } + + public Optional getNumberOfOtherAccountsAtLeast() { + return numberOfOtherAccountsAtLeast; + } + + public void setNumberOfOtherAccountsAtLeast(Optional numberOfOtherAccountsAtLeast) { + this.numberOfOtherAccountsAtLeast = numberOfOtherAccountsAtLeast; + } + + public Optional getNumberOfOtherAccountsLessThan() { + return numberOfOtherAccountsLessThan; + } + + public void setNumberOfOtherAccountsLessThan(Optional numberOfOtherAccountsLessThan) { + this.numberOfOtherAccountsLessThan = numberOfOtherAccountsLessThan; + } +} diff --git a/src/test/java/fr/xephi/authme/settings/commandconfig/CommandManagerTest.java b/src/test/java/fr/xephi/authme/settings/commandconfig/CommandManagerTest.java index b4183d700..4b6b1361b 100644 --- a/src/test/java/fr/xephi/authme/settings/commandconfig/CommandManagerTest.java +++ b/src/test/java/fr/xephi/authme/settings/commandconfig/CommandManagerTest.java @@ -17,6 +17,7 @@ import org.mockito.junit.MockitoJUnitRunner; import java.io.File; import java.io.IOException; +import java.util.Collections; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -30,6 +31,7 @@ import static org.mockito.Mockito.verifyZeroInteractions; /** * Test for {@link CommandManager}. */ +// TODO #1035: Tests currently fail because ConfigMe can't handle Optional fields @RunWith(MockitoJUnitRunner.class) public class CommandManagerTest { @@ -66,7 +68,7 @@ public class CommandManagerTest { initManager(); // when - manager.runCommandsOnLogin(player); + manager.runCommandsOnLogin(player, Collections.emptyList()); // then verify(bukkitService).dispatchConsoleCommand("msg Bobby Welcome back"); @@ -83,7 +85,7 @@ public class CommandManagerTest { initManager(); // when - manager.runCommandsOnLogin(player); + manager.runCommandsOnLogin(player, Collections.emptyList()); // then verify(bukkitService).dispatchConsoleCommand("msg Bobby Welcome back, bob"); @@ -114,7 +116,7 @@ public class CommandManagerTest { initManager(); // when - manager.runCommandsOnFirstLogin(player); + manager.runCommandsOnFirstLogin(player, Collections.emptyList()); // then verify(bukkitService).dispatchConsoleCommand("pay Bobby 30"); diff --git a/src/test/java/fr/xephi/authme/settings/commandconfig/CommandMigrationServiceTest.java b/src/test/java/fr/xephi/authme/settings/commandconfig/CommandMigrationServiceTest.java index 21f4d0479..87f4b0015 100644 --- a/src/test/java/fr/xephi/authme/settings/commandconfig/CommandMigrationServiceTest.java +++ b/src/test/java/fr/xephi/authme/settings/commandconfig/CommandMigrationServiceTest.java @@ -21,6 +21,7 @@ import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import static fr.xephi.authme.settings.commandconfig.CommandConfigTestHelper.isCommand; import static java.util.Collections.emptyList; @@ -85,8 +86,10 @@ public class CommandMigrationServiceTest { List onRegisterConsole = Arrays.asList("log %p registered", "whois %p"); given(settingsMigrationService.getOnRegisterConsoleCommands()).willReturn(onRegisterConsole); - Map onLoginCommands = new LinkedHashMap<>(); - onLoginCommands.put("bcast", new Command("bcast %p returned", Executor.CONSOLE)); + Map onLoginCommands = new LinkedHashMap<>(); + OnLoginCommand existingCommand = new OnLoginCommand("helpop %p has many alts", Executor.CONSOLE); + existingCommand.setNumberOfOtherAccountsAtLeast(Optional.of(2)); + onLoginCommands.put("alert_on_alts", existingCommand); commandConfig.setOnLogin(onLoginCommands); Map onRegisterCommands = new LinkedHashMap<>(); onRegisterCommands.put("ex_cmd", new Command("existing", Executor.CONSOLE)); @@ -99,9 +102,9 @@ public class CommandMigrationServiceTest { // then assertThat(result, equalTo(true)); assertThat(commandConfig.getOnLogin(), sameInstance(onLoginCommands)); - Collection loginCmdList = onLoginCommands.values(); + Collection loginCmdList = onLoginCommands.values(); assertThat(loginCmdList, contains( - equalTo(onLoginCommands.get("bcast")), + equalTo(existingCommand), isCommand("on login command", Executor.PLAYER), isCommand("cmd1", Executor.CONSOLE), isCommand("cmd2 %p", Executor.CONSOLE), diff --git a/src/test/resources/fr/xephi/authme/settings/commandconfig/commands.complete.yml b/src/test/resources/fr/xephi/authme/settings/commandconfig/commands.complete.yml index 7bcf0b770..2e880256f 100644 --- a/src/test/resources/fr/xephi/authme/settings/commandconfig/commands.complete.yml +++ b/src/test/resources/fr/xephi/authme/settings/commandconfig/commands.complete.yml @@ -21,6 +21,10 @@ onLogin: display_list: command: 'list' executor: PLAYER + warn_for_alts: + command: 'helpop Player %p has more than 1 account' + exeuctor: CONSOLE + numberOfOtherAccountsAtLeast: 2 onSessionLogin: welcome: command: 'msg %p Session login!'