#1035 Add optional constraints to onLogin and onFirstLogin commands for number of alt accounts

- Extend Command to add specific constraints
- Currently doesn't work because of missing ConfigMe support
This commit is contained in:
ljacqu 2018-01-14 12:23:04 +01:00
parent 1cd5a6acce
commit 8dbba1dc93
8 changed files with 135 additions and 33 deletions

View File

@ -107,9 +107,9 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
// Login is now finished; we can force all commands // Login is now finished; we can force all commands
if (isFirstLogin) { 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. // Send Bungee stuff. The service will check if it is enabled or not.
bungeeSender.connectPlayerOnLogin(player); bungeeSender.connectPlayerOnLogin(player);

View File

@ -11,9 +11,9 @@ import java.util.Map;
public class CommandConfig { public class CommandConfig {
private Map<String, Command> onJoin = new LinkedHashMap<>(); private Map<String, Command> onJoin = new LinkedHashMap<>();
private Map<String, Command> onLogin = new LinkedHashMap<>(); private Map<String, OnLoginCommand> onLogin = new LinkedHashMap<>();
private Map<String, Command> onSessionLogin = new LinkedHashMap<>(); private Map<String, Command> onSessionLogin = new LinkedHashMap<>();
private Map<String, Command> onFirstLogin = new LinkedHashMap<>(); private Map<String, OnLoginCommand> onFirstLogin = new LinkedHashMap<>();
private Map<String, Command> onRegister = new LinkedHashMap<>(); private Map<String, Command> onRegister = new LinkedHashMap<>();
private Map<String, Command> onUnregister = new LinkedHashMap<>(); private Map<String, Command> onUnregister = new LinkedHashMap<>();
private Map<String, Command> onLogout = new LinkedHashMap<>(); private Map<String, Command> onLogout = new LinkedHashMap<>();
@ -26,11 +26,11 @@ public class CommandConfig {
this.onJoin = onJoin; this.onJoin = onJoin;
} }
public Map<String, Command> getOnLogin() { public Map<String, OnLoginCommand> getOnLogin() {
return onLogin; return onLogin;
} }
public void setOnLogin(Map<String, Command> onLogin) { public void setOnLogin(Map<String, OnLoginCommand> onLogin) {
this.onLogin = onLogin; this.onLogin = onLogin;
} }
@ -42,11 +42,11 @@ public class CommandConfig {
this.onSessionLogin = onSessionLogin; this.onSessionLogin = onSessionLogin;
} }
public Map<String, Command> getOnFirstLogin() { public Map<String, OnLoginCommand> getOnFirstLogin() {
return onFirstLogin; return onFirstLogin;
} }
public void setOnFirstLogin(Map<String, Command> onFirstLogin) { public void setOnFirstLogin(Map<String, OnLoginCommand> onFirstLogin) {
this.onFirstLogin = onFirstLogin; this.onFirstLogin = onFirstLogin;
} }

View File

@ -17,6 +17,7 @@ import java.io.File;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Predicate;
import static fr.xephi.authme.util.lazytags.TagBuilder.createTag; import static fr.xephi.authme.util.lazytags.TagBuilder.createTag;
@ -32,9 +33,9 @@ public class CommandManager implements Reloadable {
private final List<Tag<Player>> availableTags = buildAvailableTags(); private final List<Tag<Player>> availableTags = buildAvailableTags();
private WrappedTagReplacer<Command, Player> onJoinCommands; private WrappedTagReplacer<Command, Player> onJoinCommands;
private WrappedTagReplacer<Command, Player> onLoginCommands; private WrappedTagReplacer<OnLoginCommand, Player> onLoginCommands;
private WrappedTagReplacer<Command, Player> onSessionLoginCommands; private WrappedTagReplacer<Command, Player> onSessionLoginCommands;
private WrappedTagReplacer<Command, Player> onFirstLoginCommands; private WrappedTagReplacer<OnLoginCommand, Player> onFirstLoginCommands;
private WrappedTagReplacer<Command, Player> onRegisterCommands; private WrappedTagReplacer<Command, Player> onRegisterCommands;
private WrappedTagReplacer<Command, Player> onUnregisterCommands; private WrappedTagReplacer<Command, Player> onUnregisterCommands;
private WrappedTagReplacer<Command, Player> onLogoutCommands; private WrappedTagReplacer<Command, Player> onLogoutCommands;
@ -72,8 +73,10 @@ public class CommandManager implements Reloadable {
* *
* @param player the player that logged in * @param player the player that logged in
*/ */
public void runCommandsOnLogin(Player player) { public void runCommandsOnLogin(Player player, List<String> otherAccounts) {
executeCommands(player, onLoginCommands.getAdaptedItems(player)); 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 * @param player the player that has logged in for the first time
*/ */
public void runCommandsOnFirstLogin(Player player) { public void runCommandsOnFirstLogin(Player player, List<String> otherAccounts) {
executeCommands(player, onFirstLoginCommands.getAdaptedItems(player)); 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<Command> commands) { private void executeCommands(Player player, List<Command> commands) {
for (Command command : commands) { executeCommands(player, commands, c -> true);
final String execution = command.getCommand(); }
if (Executor.CONSOLE.equals(command.getExecutor())) {
bukkitService.dispatchConsoleCommand(execution); private <T extends Command> void executeCommands(Player player, List<T> commands, Predicate<T> predicate) {
} else { for (T command : commands) {
bukkitService.dispatchCommand(player, execution); 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 @Override
public void reload() { public void reload() {
File file = new File(dataFolder, "commands.yml"); File file = new File(dataFolder, "commands.yml");
@ -132,8 +150,8 @@ public class CommandManager implements Reloadable {
new YamlFileResource(file), commandMigrationService, CommandSettingsHolder.class); new YamlFileResource(file), commandMigrationService, CommandSettingsHolder.class);
CommandConfig commandConfig = settingsManager.getProperty(CommandSettingsHolder.COMMANDS); CommandConfig commandConfig = settingsManager.getProperty(CommandSettingsHolder.COMMANDS);
onJoinCommands = newReplacer(commandConfig.getOnJoin()); onJoinCommands = newReplacer(commandConfig.getOnJoin());
onLoginCommands = newReplacer(commandConfig.getOnLogin()); onLoginCommands = newOnLoginCmdReplacer(commandConfig.getOnLogin());
onFirstLoginCommands = newReplacer(commandConfig.getOnFirstLogin()); onFirstLoginCommands = newOnLoginCmdReplacer(commandConfig.getOnFirstLogin());
onSessionLoginCommands = newReplacer(commandConfig.getOnSessionLogin()); onSessionLoginCommands = newReplacer(commandConfig.getOnSessionLogin());
onRegisterCommands = newReplacer(commandConfig.getOnRegister()); onRegisterCommands = newReplacer(commandConfig.getOnRegister());
onUnregisterCommands = newReplacer(commandConfig.getOnUnregister()); onUnregisterCommands = newReplacer(commandConfig.getOnUnregister());
@ -145,6 +163,13 @@ public class CommandManager implements Reloadable {
(cmd, text) -> new Command(text, cmd.getExecutor())); (cmd, text) -> new Command(text, cmd.getExecutor()));
} }
private WrappedTagReplacer<OnLoginCommand, Player> newOnLoginCmdReplacer(
Map<String, OnLoginCommand> commands) {
return new WrappedTagReplacer<>(availableTags, commands.values(), Command::getCommand,
(cmd, text) -> new OnLoginCommand(text, cmd.getExecutor()));
}
private List<Tag<Player>> buildAvailableTags() { private List<Tag<Player>> buildAvailableTags() {
return Arrays.asList( return Arrays.asList(
createTag("%p", pl -> pl.getName()), createTag("%p", pl -> pl.getName()),

View File

@ -12,6 +12,7 @@ import fr.xephi.authme.util.RandomStringUtils;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -70,12 +71,14 @@ class CommandMigrationService implements MigrationService {
ON_JOIN( ON_JOIN(
SettingsMigrationService::getOnLoginCommands, SettingsMigrationService::getOnLoginCommands,
Executor.PLAYER, Executor.PLAYER,
CommandConfig::getOnLogin), CommandConfig::getOnLogin,
OnLoginCommand::new),
ON_JOIN_CONSOLE( ON_JOIN_CONSOLE(
SettingsMigrationService::getOnLoginConsoleCommands, SettingsMigrationService::getOnLoginConsoleCommands,
Executor.CONSOLE, Executor.CONSOLE,
CommandConfig::getOnLogin), CommandConfig::getOnLogin,
OnLoginCommand::new),
ON_REGISTER( ON_REGISTER(
SettingsMigrationService::getOnRegisterCommands, SettingsMigrationService::getOnRegisterCommands,
@ -90,6 +93,7 @@ class CommandMigrationService implements MigrationService {
private final Function<SettingsMigrationService, List<String>> legacyCommandsGetter; private final Function<SettingsMigrationService, List<String>> legacyCommandsGetter;
private final Executor executor; private final Executor executor;
private final Function<CommandConfig, Map<String, Command>> commandMapGetter; private final Function<CommandConfig, Map<String, Command>> commandMapGetter;
private final BiFunction<String, Executor, Command> commandConstructor;
/** /**
* Constructor. * Constructor.
@ -102,9 +106,29 @@ class CommandMigrationService implements MigrationService {
MigratableCommandSection(Function<SettingsMigrationService, List<String>> legacyCommandsGetter, MigratableCommandSection(Function<SettingsMigrationService, List<String>> legacyCommandsGetter,
Executor executor, Executor executor,
Function<CommandConfig, Map<String, Command>> commandMapGetter) { Function<CommandConfig, Map<String, Command>> 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
*/
<T extends Command> MigratableCommandSection(
Function<SettingsMigrationService, List<String>> legacyCommandsGetter,
Executor executor,
Function<CommandConfig, Map<String, T>> commandMapGetter,
BiFunction<String, Executor, T> commandConstructor) {
this.legacyCommandsGetter = legacyCommandsGetter; this.legacyCommandsGetter = legacyCommandsGetter;
this.executor = executor; 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) { boolean convertCommands(SettingsMigrationService settingsMigrationService, CommandConfig commandConfig) {
List<Command> commands = legacyCommandsGetter.apply(settingsMigrationService).stream() List<Command> 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()) { if (commands.isEmpty()) {
return false; return false;

View File

@ -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<Integer> numberOfOtherAccountsAtLeast;
private Optional<Integer> 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<Integer> getNumberOfOtherAccountsAtLeast() {
return numberOfOtherAccountsAtLeast;
}
public void setNumberOfOtherAccountsAtLeast(Optional<Integer> numberOfOtherAccountsAtLeast) {
this.numberOfOtherAccountsAtLeast = numberOfOtherAccountsAtLeast;
}
public Optional<Integer> getNumberOfOtherAccountsLessThan() {
return numberOfOtherAccountsLessThan;
}
public void setNumberOfOtherAccountsLessThan(Optional<Integer> numberOfOtherAccountsLessThan) {
this.numberOfOtherAccountsLessThan = numberOfOtherAccountsLessThan;
}
}

View File

@ -17,6 +17,7 @@ import org.mockito.junit.MockitoJUnitRunner;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Collections;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
@ -30,6 +31,7 @@ import static org.mockito.Mockito.verifyZeroInteractions;
/** /**
* Test for {@link CommandManager}. * Test for {@link CommandManager}.
*/ */
// TODO #1035: Tests currently fail because ConfigMe can't handle Optional fields
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
public class CommandManagerTest { public class CommandManagerTest {
@ -66,7 +68,7 @@ public class CommandManagerTest {
initManager(); initManager();
// when // when
manager.runCommandsOnLogin(player); manager.runCommandsOnLogin(player, Collections.emptyList());
// then // then
verify(bukkitService).dispatchConsoleCommand("msg Bobby Welcome back"); verify(bukkitService).dispatchConsoleCommand("msg Bobby Welcome back");
@ -83,7 +85,7 @@ public class CommandManagerTest {
initManager(); initManager();
// when // when
manager.runCommandsOnLogin(player); manager.runCommandsOnLogin(player, Collections.emptyList());
// then // then
verify(bukkitService).dispatchConsoleCommand("msg Bobby Welcome back, bob"); verify(bukkitService).dispatchConsoleCommand("msg Bobby Welcome back, bob");
@ -114,7 +116,7 @@ public class CommandManagerTest {
initManager(); initManager();
// when // when
manager.runCommandsOnFirstLogin(player); manager.runCommandsOnFirstLogin(player, Collections.emptyList());
// then // then
verify(bukkitService).dispatchConsoleCommand("pay Bobby 30"); verify(bukkitService).dispatchConsoleCommand("pay Bobby 30");

View File

@ -21,6 +21,7 @@ import java.util.Collections;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import static fr.xephi.authme.settings.commandconfig.CommandConfigTestHelper.isCommand; import static fr.xephi.authme.settings.commandconfig.CommandConfigTestHelper.isCommand;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
@ -85,8 +86,10 @@ public class CommandMigrationServiceTest {
List<String> onRegisterConsole = Arrays.asList("log %p registered", "whois %p"); List<String> onRegisterConsole = Arrays.asList("log %p registered", "whois %p");
given(settingsMigrationService.getOnRegisterConsoleCommands()).willReturn(onRegisterConsole); given(settingsMigrationService.getOnRegisterConsoleCommands()).willReturn(onRegisterConsole);
Map<String, Command> onLoginCommands = new LinkedHashMap<>(); Map<String, OnLoginCommand> onLoginCommands = new LinkedHashMap<>();
onLoginCommands.put("bcast", new Command("bcast %p returned", Executor.CONSOLE)); 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); commandConfig.setOnLogin(onLoginCommands);
Map<String, Command> onRegisterCommands = new LinkedHashMap<>(); Map<String, Command> onRegisterCommands = new LinkedHashMap<>();
onRegisterCommands.put("ex_cmd", new Command("existing", Executor.CONSOLE)); onRegisterCommands.put("ex_cmd", new Command("existing", Executor.CONSOLE));
@ -99,9 +102,9 @@ public class CommandMigrationServiceTest {
// then // then
assertThat(result, equalTo(true)); assertThat(result, equalTo(true));
assertThat(commandConfig.getOnLogin(), sameInstance(onLoginCommands)); assertThat(commandConfig.getOnLogin(), sameInstance(onLoginCommands));
Collection<Command> loginCmdList = onLoginCommands.values(); Collection<OnLoginCommand> loginCmdList = onLoginCommands.values();
assertThat(loginCmdList, contains( assertThat(loginCmdList, contains(
equalTo(onLoginCommands.get("bcast")), equalTo(existingCommand),
isCommand("on login command", Executor.PLAYER), isCommand("on login command", Executor.PLAYER),
isCommand("cmd1", Executor.CONSOLE), isCommand("cmd1", Executor.CONSOLE),
isCommand("cmd2 %p", Executor.CONSOLE), isCommand("cmd2 %p", Executor.CONSOLE),

View File

@ -21,6 +21,10 @@ onLogin:
display_list: display_list:
command: 'list' command: 'list'
executor: PLAYER executor: PLAYER
warn_for_alts:
command: 'helpop Player %p has more than 1 account'
exeuctor: CONSOLE
numberOfOtherAccountsAtLeast: 2
onSessionLogin: onSessionLogin:
welcome: welcome:
command: 'msg %p Session login!' command: 'msg %p Session login!'