From 86a07771d7e28a6f137de6cc1f8e3f7988b5d431 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 25 Nov 2017 14:41:23 +0100 Subject: [PATCH 1/8] Open 5.5 development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6f89359b..490dbc7e 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ fr.xephi authme - 5.4.0-RC1 + 5.5-SNAPSHOT AuthMeReloaded The first authentication plugin for the Bukkit API! From 7932c1bf90d5f824dfde72f58cfc18eac2e09a32 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 25 Nov 2017 21:27:18 +0100 Subject: [PATCH 2/8] Update to injector 1.0 - Includes Factory and SingletonStore so our custom implementation is removed --- pom.xml | 2 +- src/main/java/fr/xephi/authme/AuthMe.java | 3 - .../xephi/authme/command/CommandHandler.java | 2 +- .../executable/authme/ConverterCommand.java | 2 +- .../executable/authme/ReloadCommand.java | 2 +- .../authme/debug/DataStatistics.java | 2 +- .../executable/authme/debug/DebugCommand.java | 2 +- .../limbo/persistence/LimboPersistence.java | 2 +- .../initialization/factory/Factory.java | 19 ------ .../factory/FactoryDependencyHandler.java | 46 -------------- .../factory/SingletonStore.java | 37 ----------- .../SingletonStoreDependencyHandler.java | 61 ------------------- .../process/register/AsyncRegister.java | 2 +- .../authme/security/PasswordSecurity.java | 2 +- .../fr/xephi/authme/task/CleanupTask.java | 2 +- .../authme/AuthMeInitializationTest.java | 3 - .../authme/command/CommandHandlerTest.java | 2 +- .../authme/ConverterCommandTest.java | 2 +- .../executable/authme/ReloadCommandTest.java | 2 +- .../authme/debug/DataStatisticsTest.java | 2 +- .../authme/debug/DebugCommandTest.java | 2 +- .../persistence/LimboPersistenceTest.java | 2 +- .../process/register/AsyncRegisterTest.java | 2 +- .../authme/security/PasswordSecurityTest.java | 2 +- .../fr/xephi/authme/task/CleanupTaskTest.java | 2 +- .../tools/dependencygraph/DrawDependency.java | 32 +++++----- src/test/java/tools/utils/InjectorUtils.java | 34 +++++++++-- 27 files changed, 64 insertions(+), 209 deletions(-) delete mode 100644 src/main/java/fr/xephi/authme/initialization/factory/Factory.java delete mode 100644 src/main/java/fr/xephi/authme/initialization/factory/FactoryDependencyHandler.java delete mode 100644 src/main/java/fr/xephi/authme/initialization/factory/SingletonStore.java delete mode 100644 src/main/java/fr/xephi/authme/initialization/factory/SingletonStoreDependencyHandler.java diff --git a/pom.xml b/pom.xml index 490dbc7e..e0828671 100644 --- a/pom.xml +++ b/pom.xml @@ -302,7 +302,7 @@ ch.jalu injector - 0.4.1 + 1.0 compile true diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 9a569b1a..15a37ab4 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -12,8 +12,6 @@ import fr.xephi.authme.initialization.OnShutdownPlayerSaver; import fr.xephi.authme.initialization.OnStartupTasks; import fr.xephi.authme.initialization.SettingsProvider; import fr.xephi.authme.initialization.TaskCloser; -import fr.xephi.authme.initialization.factory.FactoryDependencyHandler; -import fr.xephi.authme.initialization.factory.SingletonStoreDependencyHandler; import fr.xephi.authme.listener.BlockListener; import fr.xephi.authme.listener.EntityListener; import fr.xephi.authme.listener.PlayerListener; @@ -201,7 +199,6 @@ public class AuthMe extends JavaPlugin { // Create injector, provide elements from the Bukkit environment and register providers injector = new InjectorBuilder() - .addHandlers(new FactoryDependencyHandler(), new SingletonStoreDependencyHandler()) .addDefaultHandlers("fr.xephi.authme") .create(); injector.register(AuthMe.class, this); diff --git a/src/main/java/fr/xephi/authme/command/CommandHandler.java b/src/main/java/fr/xephi/authme/command/CommandHandler.java index acbb4757..27445e02 100644 --- a/src/main/java/fr/xephi/authme/command/CommandHandler.java +++ b/src/main/java/fr/xephi/authme/command/CommandHandler.java @@ -1,8 +1,8 @@ package fr.xephi.authme.command; +import ch.jalu.injector.factory.Factory; import fr.xephi.authme.AuthMe; import fr.xephi.authme.command.help.HelpProvider; -import fr.xephi.authme.initialization.factory.Factory; import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.Messages; import fr.xephi.authme.permission.PermissionsManager; diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/ConverterCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/ConverterCommand.java index b0d1c7fa..2973ba2d 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/ConverterCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/ConverterCommand.java @@ -1,5 +1,6 @@ package fr.xephi.authme.command.executable.authme; +import ch.jalu.injector.factory.Factory; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableSortedMap; import fr.xephi.authme.ConsoleLogger; @@ -13,7 +14,6 @@ import fr.xephi.authme.datasource.converter.RoyalAuthConverter; import fr.xephi.authme.datasource.converter.SqliteToSql; import fr.xephi.authme.datasource.converter.VAuthConverter; import fr.xephi.authme.datasource.converter.XAuthConverter; -import fr.xephi.authme.initialization.factory.Factory; import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.service.BukkitService; import fr.xephi.authme.service.CommonService; diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java index ce288c14..164b5913 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java @@ -1,12 +1,12 @@ package fr.xephi.authme.command.executable.authme; +import ch.jalu.injector.factory.SingletonStore; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.initialization.Reloadable; import fr.xephi.authme.initialization.SettingsDependent; -import fr.xephi.authme.initialization.factory.SingletonStore; import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.service.CommonService; import fr.xephi.authme.settings.Settings; diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/debug/DataStatistics.java b/src/main/java/fr/xephi/authme/command/executable/authme/debug/DataStatistics.java index 75a17869..f90883b8 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/debug/DataStatistics.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/debug/DataStatistics.java @@ -1,5 +1,6 @@ package fr.xephi.authme.command.executable.authme.debug; +import ch.jalu.injector.factory.SingletonStore; import fr.xephi.authme.data.auth.PlayerCache; import fr.xephi.authme.data.limbo.LimboService; import fr.xephi.authme.datasource.CacheDataSource; @@ -7,7 +8,6 @@ import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.initialization.HasCleanup; import fr.xephi.authme.initialization.Reloadable; import fr.xephi.authme.initialization.SettingsDependent; -import fr.xephi.authme.initialization.factory.SingletonStore; import fr.xephi.authme.permission.DebugSectionPermissions; import fr.xephi.authme.permission.PermissionNode; import org.bukkit.ChatColor; diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/debug/DebugCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/debug/DebugCommand.java index 53ee747e..c7b0d8fc 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/debug/DebugCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/debug/DebugCommand.java @@ -1,8 +1,8 @@ package fr.xephi.authme.command.executable.authme.debug; +import ch.jalu.injector.factory.Factory; import com.google.common.collect.ImmutableSet; import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.initialization.factory.Factory; import fr.xephi.authme.permission.PermissionsManager; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; diff --git a/src/main/java/fr/xephi/authme/data/limbo/persistence/LimboPersistence.java b/src/main/java/fr/xephi/authme/data/limbo/persistence/LimboPersistence.java index f07e82cd..391878da 100644 --- a/src/main/java/fr/xephi/authme/data/limbo/persistence/LimboPersistence.java +++ b/src/main/java/fr/xephi/authme/data/limbo/persistence/LimboPersistence.java @@ -1,9 +1,9 @@ package fr.xephi.authme.data.limbo.persistence; +import ch.jalu.injector.factory.Factory; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.data.limbo.LimboPlayer; import fr.xephi.authme.initialization.SettingsDependent; -import fr.xephi.authme.initialization.factory.Factory; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.properties.LimboSettings; import org.bukkit.entity.Player; diff --git a/src/main/java/fr/xephi/authme/initialization/factory/Factory.java b/src/main/java/fr/xephi/authme/initialization/factory/Factory.java deleted file mode 100644 index 0f4ae62a..00000000 --- a/src/main/java/fr/xephi/authme/initialization/factory/Factory.java +++ /dev/null @@ -1,19 +0,0 @@ -package fr.xephi.authme.initialization.factory; - -/** - * Injectable factory that creates new instances of a certain type. - * - * @param

the parent type to which the factory is limited to - */ -public interface Factory

{ - - /** - * Creates an instance of the given class. - * - * @param clazz the class to instantiate - * @param the class type - * @return new instance of the class - */ - C newInstance(Class clazz); - -} diff --git a/src/main/java/fr/xephi/authme/initialization/factory/FactoryDependencyHandler.java b/src/main/java/fr/xephi/authme/initialization/factory/FactoryDependencyHandler.java deleted file mode 100644 index e063d149..00000000 --- a/src/main/java/fr/xephi/authme/initialization/factory/FactoryDependencyHandler.java +++ /dev/null @@ -1,46 +0,0 @@ -package fr.xephi.authme.initialization.factory; - -import ch.jalu.injector.Injector; -import ch.jalu.injector.context.ResolvedInstantiationContext; -import ch.jalu.injector.handlers.dependency.DependencyHandler; -import ch.jalu.injector.handlers.instantiation.DependencyDescription; -import ch.jalu.injector.utils.ReflectionUtils; - -/** - * Dependency handler that builds {@link Factory} objects. - */ -public class FactoryDependencyHandler implements DependencyHandler { - - @Override - public Object resolveValue(ResolvedInstantiationContext context, DependencyDescription dependencyDescription) { - if (dependencyDescription.getType() == Factory.class) { - Class genericType = ReflectionUtils.getGenericType(dependencyDescription.getGenericType()); - if (genericType == null) { - throw new IllegalStateException("Factory fields must have concrete generic type. " - + "Cannot get generic type for field in '" + context.getMappedClass() + "'"); - } - - return new FactoryImpl<>(genericType, context.getInjector()); - } - return null; - } - - private static final class FactoryImpl

implements Factory

{ - - private final Injector injector; - private final Class

parentClass; - - FactoryImpl(Class

parentClass, Injector injector) { - this.parentClass = parentClass; - this.injector = injector; - } - - @Override - public C newInstance(Class clazz) { - if (parentClass.isAssignableFrom(clazz)) { - return injector.newInstance(clazz); - } - throw new IllegalArgumentException(clazz + " not child of " + parentClass); - } - } -} diff --git a/src/main/java/fr/xephi/authme/initialization/factory/SingletonStore.java b/src/main/java/fr/xephi/authme/initialization/factory/SingletonStore.java deleted file mode 100644 index 13a5cbb5..00000000 --- a/src/main/java/fr/xephi/authme/initialization/factory/SingletonStore.java +++ /dev/null @@ -1,37 +0,0 @@ -package fr.xephi.authme.initialization.factory; - -import java.util.Collection; - -/** - * Injectable object to retrieve and create singletons of a common parent. - * - * @param

the parent class to which this store is limited to - */ -public interface SingletonStore

{ - - /** - * Returns the singleton of the given type, creating it if it hasn't been yet created. - * - * @param clazz the class to get the singleton for - * @param type of the singleton - * @return the singleton of type {@code C} - */ - C getSingleton(Class clazz); - - /** - * Returns all existing singletons of this store's type. - * - * @return all registered singletons of type {@code P} - */ - Collection

retrieveAllOfType(); - - /** - * Returns all existing singletons of the given type. - * - * @param clazz the type to get singletons for - * @param class type - * @return all registered singletons of type {@code C} - */ - Collection retrieveAllOfType(Class clazz); - -} diff --git a/src/main/java/fr/xephi/authme/initialization/factory/SingletonStoreDependencyHandler.java b/src/main/java/fr/xephi/authme/initialization/factory/SingletonStoreDependencyHandler.java deleted file mode 100644 index 09a198c7..00000000 --- a/src/main/java/fr/xephi/authme/initialization/factory/SingletonStoreDependencyHandler.java +++ /dev/null @@ -1,61 +0,0 @@ -package fr.xephi.authme.initialization.factory; - -import ch.jalu.injector.Injector; -import ch.jalu.injector.context.ResolvedInstantiationContext; -import ch.jalu.injector.handlers.dependency.DependencyHandler; -import ch.jalu.injector.handlers.instantiation.DependencyDescription; -import ch.jalu.injector.utils.ReflectionUtils; - -import java.util.Collection; - -/** - * Dependency handler that builds {@link SingletonStore} objects. - */ -public class SingletonStoreDependencyHandler implements DependencyHandler { - - @Override - public Object resolveValue(ResolvedInstantiationContext context, DependencyDescription dependencyDescription) { - if (dependencyDescription.getType() == SingletonStore.class) { - Class genericType = ReflectionUtils.getGenericType(dependencyDescription.getGenericType()); - if (genericType == null) { - throw new IllegalStateException("Singleton store fields must have concrete generic type. " - + "Cannot get generic type for field in '" + context.getMappedClass() + "'"); - } - - return new SingletonStoreImpl<>(genericType, context.getInjector()); - } - return null; - } - - private static final class SingletonStoreImpl

implements SingletonStore

{ - - private final Injector injector; - private final Class

parentClass; - - SingletonStoreImpl(Class

parentClass, Injector injector) { - this.parentClass = parentClass; - this.injector = injector; - } - - @Override - public C getSingleton(Class clazz) { - if (parentClass.isAssignableFrom(clazz)) { - return injector.getSingleton(clazz); - } - throw new IllegalArgumentException(clazz + " not child of " + parentClass); - } - - @Override - public Collection

retrieveAllOfType() { - return retrieveAllOfType(parentClass); - } - - @Override - public Collection retrieveAllOfType(Class clazz) { - if (parentClass.isAssignableFrom(clazz)) { - return injector.retrieveAllOfType(clazz); - } - throw new IllegalArgumentException(clazz + " not child of " + parentClass); - } - } -} 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 11f6354c..a370b1a9 100644 --- a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java @@ -1,9 +1,9 @@ package fr.xephi.authme.process.register; +import ch.jalu.injector.factory.SingletonStore; import fr.xephi.authme.data.auth.PlayerAuth; import fr.xephi.authme.data.auth.PlayerCache; import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.initialization.factory.SingletonStore; import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.process.AsynchronousProcess; diff --git a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java b/src/main/java/fr/xephi/authme/security/PasswordSecurity.java index ebccb63d..d6cb6e71 100644 --- a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java +++ b/src/main/java/fr/xephi/authme/security/PasswordSecurity.java @@ -1,9 +1,9 @@ package fr.xephi.authme.security; +import ch.jalu.injector.factory.Factory; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.events.PasswordEncryptionEvent; import fr.xephi.authme.initialization.Reloadable; -import fr.xephi.authme.initialization.factory.Factory; import fr.xephi.authme.security.crypts.EncryptionMethod; import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.settings.Settings; diff --git a/src/main/java/fr/xephi/authme/task/CleanupTask.java b/src/main/java/fr/xephi/authme/task/CleanupTask.java index f373c3e5..48d989f1 100644 --- a/src/main/java/fr/xephi/authme/task/CleanupTask.java +++ b/src/main/java/fr/xephi/authme/task/CleanupTask.java @@ -1,7 +1,7 @@ package fr.xephi.authme.task; +import ch.jalu.injector.factory.SingletonStore; import fr.xephi.authme.initialization.HasCleanup; -import fr.xephi.authme.initialization.factory.SingletonStore; import org.bukkit.scheduler.BukkitRunnable; import javax.inject.Inject; diff --git a/src/test/java/fr/xephi/authme/AuthMeInitializationTest.java b/src/test/java/fr/xephi/authme/AuthMeInitializationTest.java index d0f3c1b3..e64d0f7e 100644 --- a/src/test/java/fr/xephi/authme/AuthMeInitializationTest.java +++ b/src/test/java/fr/xephi/authme/AuthMeInitializationTest.java @@ -8,8 +8,6 @@ import fr.xephi.authme.api.v3.AuthMeApi; import fr.xephi.authme.command.CommandHandler; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.initialization.DataFolder; -import fr.xephi.authme.initialization.factory.FactoryDependencyHandler; -import fr.xephi.authme.initialization.factory.SingletonStoreDependencyHandler; import fr.xephi.authme.listener.BlockListener; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.process.Management; @@ -96,7 +94,6 @@ public class AuthMeInitializationTest { new Settings(dataFolder, mock(PropertyResource.class), null, buildConfigurationData()); Injector injector = new InjectorBuilder() - .addHandlers(new FactoryDependencyHandler(), new SingletonStoreDependencyHandler()) .addDefaultHandlers("fr.xephi.authme") .create(); injector.provide(DataFolder.class, dataFolder); diff --git a/src/test/java/fr/xephi/authme/command/CommandHandlerTest.java b/src/test/java/fr/xephi/authme/command/CommandHandlerTest.java index e343199f..d80d8f8a 100644 --- a/src/test/java/fr/xephi/authme/command/CommandHandlerTest.java +++ b/src/test/java/fr/xephi/authme/command/CommandHandlerTest.java @@ -1,12 +1,12 @@ package fr.xephi.authme.command; import ch.jalu.injector.Injector; +import ch.jalu.injector.factory.Factory; import com.google.common.collect.Sets; import fr.xephi.authme.command.TestCommandsUtil.TestLoginCommand; import fr.xephi.authme.command.TestCommandsUtil.TestRegisterCommand; import fr.xephi.authme.command.TestCommandsUtil.TestUnregisterCommand; import fr.xephi.authme.command.help.HelpProvider; -import fr.xephi.authme.initialization.factory.Factory; import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.Messages; import fr.xephi.authme.permission.PermissionsManager; diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/ConverterCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/ConverterCommandTest.java index 02ecd7e2..626e9c90 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/ConverterCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/ConverterCommandTest.java @@ -1,8 +1,8 @@ package fr.xephi.authme.command.executable.authme; +import ch.jalu.injector.factory.Factory; import fr.xephi.authme.TestHelper; import fr.xephi.authme.datasource.converter.Converter; -import fr.xephi.authme.initialization.factory.Factory; import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.service.BukkitService; import fr.xephi.authme.service.CommonService; diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/ReloadCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/ReloadCommandTest.java index 52e342db..8b10de64 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/ReloadCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/ReloadCommandTest.java @@ -1,12 +1,12 @@ package fr.xephi.authme.command.executable.authme; +import ch.jalu.injector.factory.SingletonStore; import fr.xephi.authme.AuthMe; import fr.xephi.authme.TestHelper; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSourceType; import fr.xephi.authme.initialization.Reloadable; import fr.xephi.authme.initialization.SettingsDependent; -import fr.xephi.authme.initialization.factory.SingletonStore; import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.output.LogLevel; import fr.xephi.authme.service.CommonService; diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/debug/DataStatisticsTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/debug/DataStatisticsTest.java index e28c110f..52b13b0e 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/debug/DataStatisticsTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/debug/DataStatisticsTest.java @@ -1,5 +1,6 @@ package fr.xephi.authme.command.executable.authme.debug; +import ch.jalu.injector.factory.SingletonStore; import com.google.common.cache.LoadingCache; import fr.xephi.authme.ReflectionTestUtils; import fr.xephi.authme.data.auth.PlayerAuth; @@ -11,7 +12,6 @@ import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.initialization.HasCleanup; import fr.xephi.authme.initialization.Reloadable; import fr.xephi.authme.initialization.SettingsDependent; -import fr.xephi.authme.initialization.factory.SingletonStore; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import org.junit.Before; diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/debug/DebugCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/debug/DebugCommandTest.java index 3174926a..e2c63a60 100644 --- a/src/test/java/fr/xephi/authme/command/executable/authme/debug/DebugCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/authme/debug/DebugCommandTest.java @@ -1,6 +1,6 @@ package fr.xephi.authme.command.executable.authme.debug; -import fr.xephi.authme.initialization.factory.Factory; +import ch.jalu.injector.factory.Factory; import fr.xephi.authme.permission.DebugSectionPermissions; import fr.xephi.authme.permission.PermissionNode; import fr.xephi.authme.permission.PermissionsManager; diff --git a/src/test/java/fr/xephi/authme/data/limbo/persistence/LimboPersistenceTest.java b/src/test/java/fr/xephi/authme/data/limbo/persistence/LimboPersistenceTest.java index d253869f..2b1e311c 100644 --- a/src/test/java/fr/xephi/authme/data/limbo/persistence/LimboPersistenceTest.java +++ b/src/test/java/fr/xephi/authme/data/limbo/persistence/LimboPersistenceTest.java @@ -1,12 +1,12 @@ package fr.xephi.authme.data.limbo.persistence; +import ch.jalu.injector.factory.Factory; import ch.jalu.injector.testing.BeforeInjecting; import ch.jalu.injector.testing.DelayedInjectionRunner; import ch.jalu.injector.testing.InjectDelayed; import fr.xephi.authme.ReflectionTestUtils; import fr.xephi.authme.TestHelper; import fr.xephi.authme.data.limbo.LimboPlayer; -import fr.xephi.authme.initialization.factory.Factory; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.properties.LimboSettings; import org.bukkit.entity.Player; diff --git a/src/test/java/fr/xephi/authme/process/register/AsyncRegisterTest.java b/src/test/java/fr/xephi/authme/process/register/AsyncRegisterTest.java index dee3dc64..e044a754 100644 --- a/src/test/java/fr/xephi/authme/process/register/AsyncRegisterTest.java +++ b/src/test/java/fr/xephi/authme/process/register/AsyncRegisterTest.java @@ -1,9 +1,9 @@ package fr.xephi.authme.process.register; +import ch.jalu.injector.factory.SingletonStore; import fr.xephi.authme.TestHelper; import fr.xephi.authme.data.auth.PlayerCache; import fr.xephi.authme.datasource.DataSource; -import fr.xephi.authme.initialization.factory.SingletonStore; import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.process.register.executors.PasswordRegisterParams; diff --git a/src/test/java/fr/xephi/authme/security/PasswordSecurityTest.java b/src/test/java/fr/xephi/authme/security/PasswordSecurityTest.java index 44118076..520ae8dd 100644 --- a/src/test/java/fr/xephi/authme/security/PasswordSecurityTest.java +++ b/src/test/java/fr/xephi/authme/security/PasswordSecurityTest.java @@ -2,6 +2,7 @@ package fr.xephi.authme.security; import ch.jalu.injector.Injector; import ch.jalu.injector.InjectorBuilder; +import ch.jalu.injector.factory.Factory; import ch.jalu.injector.testing.BeforeInjecting; import ch.jalu.injector.testing.DelayedInjectionRunner; import ch.jalu.injector.testing.InjectDelayed; @@ -9,7 +10,6 @@ import fr.xephi.authme.ReflectionTestUtils; import fr.xephi.authme.TestHelper; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.events.PasswordEncryptionEvent; -import fr.xephi.authme.initialization.factory.Factory; import fr.xephi.authme.security.crypts.EncryptionMethod; import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.security.crypts.Joomla; diff --git a/src/test/java/fr/xephi/authme/task/CleanupTaskTest.java b/src/test/java/fr/xephi/authme/task/CleanupTaskTest.java index 33cd360b..4269f9bd 100644 --- a/src/test/java/fr/xephi/authme/task/CleanupTaskTest.java +++ b/src/test/java/fr/xephi/authme/task/CleanupTaskTest.java @@ -1,7 +1,7 @@ package fr.xephi.authme.task; +import ch.jalu.injector.factory.SingletonStore; import fr.xephi.authme.initialization.HasCleanup; -import fr.xephi.authme.initialization.factory.SingletonStore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; diff --git a/src/test/java/tools/dependencygraph/DrawDependency.java b/src/test/java/tools/dependencygraph/DrawDependency.java index 98de28be..3f34197c 100644 --- a/src/test/java/tools/dependencygraph/DrawDependency.java +++ b/src/test/java/tools/dependencygraph/DrawDependency.java @@ -1,7 +1,9 @@ package tools.dependencygraph; -import ch.jalu.injector.handlers.instantiation.DependencyDescription; -import ch.jalu.injector.handlers.instantiation.Instantiation; +import ch.jalu.injector.context.ObjectIdentifier; +import ch.jalu.injector.factory.Factory; +import ch.jalu.injector.factory.SingletonStore; +import ch.jalu.injector.handlers.instantiation.Resolution; import ch.jalu.injector.handlers.instantiation.StandardInjectionProvider; import ch.jalu.injector.utils.ReflectionUtils; import com.google.common.collect.HashMultimap; @@ -14,13 +16,12 @@ import fr.xephi.authme.command.executable.authme.debug.DebugCommand; import fr.xephi.authme.data.limbo.persistence.LimboPersistence; import fr.xephi.authme.datasource.converter.Converter; import fr.xephi.authme.initialization.DataFolder; -import fr.xephi.authme.initialization.factory.Factory; -import fr.xephi.authme.initialization.factory.SingletonStore; import fr.xephi.authme.process.AsynchronousProcess; import fr.xephi.authme.process.SynchronousProcess; import fr.xephi.authme.process.register.executors.RegistrationExecutor; import fr.xephi.authme.security.crypts.EncryptionMethod; import org.bukkit.event.Listener; +import tools.utils.InjectorUtils; import tools.utils.ToolTask; import tools.utils.ToolsConstants; @@ -124,21 +125,20 @@ public class DrawDependency implements ToolTask { * This is interesting so that a dependency in a class to {@code Factory} is * rendered as a dependency to {@code Foo}, not to {@code Factory}. * - * @param clazz class of the dependency * @param genericType generic type of the dependency * @return the class to use to render the dependency */ - private Class unwrapGenericClass(Class clazz, Type genericType) { - if (clazz == Factory.class || clazz == SingletonStore.class) { + private Class unwrapGenericClass(Type genericType) { + if (genericType == Factory.class || genericType == SingletonStore.class) { Class parameterType = ReflectionUtils.getGenericType(genericType); - Objects.requireNonNull(parameterType, "Parameter type for '" + clazz + "' should be a concrete class"); + Objects.requireNonNull(parameterType, "Parameter type for '" + genericType + "' should be a concrete class"); return parameterType; } - return clazz; + return InjectorUtils.convertToClass(genericType); } private List getDependencies(Class clazz) { - Instantiation instantiation = new StandardInjectionProvider().safeGet(clazz); + Resolution instantiation = new StandardInjectionProvider().safeGet(clazz); return instantiation == null ? null : formatInjectionDependencies(instantiation); } @@ -150,22 +150,22 @@ public class DrawDependency implements ToolTask { * @param injection the injection whose dependencies should be formatted * @return list of dependencies in a friendly format */ - private List formatInjectionDependencies(Instantiation injection) { - List descriptions = injection.getDependencies(); - List result = new ArrayList<>(descriptions.size()); - for (DependencyDescription dependency : descriptions) { + private List formatInjectionDependencies(Resolution injection) { + List dependencies = injection.getDependencies(); + List result = new ArrayList<>(dependencies.size()); + for (ObjectIdentifier dependency : dependencies) { Class annotation = getRelevantAnnotationClass(dependency.getAnnotations()); if (annotation != null) { result.add("@" + annotation.getSimpleName()); } else { - Class clazz = unwrapGenericClass(dependency.getType(), dependency.getGenericType()); + Class clazz = unwrapGenericClass(dependency.getType()); result.add(mapToSuper(clazz).getSimpleName()); } } return result; } - private static Class getRelevantAnnotationClass(Annotation[] annotations) { + private static Class getRelevantAnnotationClass(List annotations) { for (Annotation annotation : annotations) { if (ANNOTATION_TYPES.contains(annotation.annotationType())) { return annotation.annotationType(); diff --git a/src/test/java/tools/utils/InjectorUtils.java b/src/test/java/tools/utils/InjectorUtils.java index 6b5d510e..27150125 100644 --- a/src/test/java/tools/utils/InjectorUtils.java +++ b/src/test/java/tools/utils/InjectorUtils.java @@ -1,9 +1,11 @@ package tools.utils; -import ch.jalu.injector.handlers.instantiation.DependencyDescription; -import ch.jalu.injector.handlers.instantiation.Instantiation; +import ch.jalu.injector.context.ObjectIdentifier; +import ch.jalu.injector.handlers.instantiation.Resolution; import ch.jalu.injector.handlers.instantiation.StandardInjectionProvider; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.util.HashSet; import java.util.Set; @@ -22,15 +24,37 @@ public final class InjectorUtils { * @return the class' dependencies, or null if no instantiation method found */ public static Set> getDependencies(Class clazz) { - Instantiation instantiation = new StandardInjectionProvider().safeGet(clazz); + Resolution instantiation = new StandardInjectionProvider().safeGet(clazz); if (instantiation == null) { return null; } Set> dependencies = new HashSet<>(); - for (DependencyDescription description : instantiation.getDependencies()) { - dependencies.add(description.getType()); + for (ObjectIdentifier description : instantiation.getDependencies()) { + dependencies.add(convertToClass(description.getType())); } return dependencies; } + /** + * Returns the given type as a {@link Class}. + * + * @param type the type to convert + * @return class corresponding to the provided type + */ + public static Class convertToClass(Type type) { + if (type instanceof Class) { + return (Class) type; + } else if (type instanceof ParameterizedType) { + Type rawType = ((ParameterizedType) type).getRawType(); + if (rawType instanceof Class) { + return (Class) rawType; + } else { + throw new IllegalStateException("Got raw type '" + rawType + "' of type '" + + rawType.getClass() + "' for genericType '" + type + "'"); + } + } + Class typeClass = type == null ? null : type.getClass(); + throw new IllegalStateException("Unknown type implementation '" + typeClass + "' for '" + type + "'"); + } + } From c7c8e673f01643bf87a86fb2ed37c47a3a68d91c Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Tue, 28 Nov 2017 12:57:39 +0100 Subject: [PATCH 3/8] #1423 Implement CMI spawn integration --- docs/config.md | 24 +++---- .../xephi/authme/listener/ServerListener.java | 7 ++ .../authme/service/PluginHookService.java | 45 +++++++++++- .../fr/xephi/authme/settings/SpawnLoader.java | 72 +++++++++++++++++++ .../properties/RestrictionSettings.java | 4 +- .../authme/listener/ServerListenerTest.java | 9 +++ 6 files changed, 145 insertions(+), 16 deletions(-) diff --git a/docs/config.md b/docs/config.md index 0e4435c9..2483ed4f 100644 --- a/docs/config.md +++ b/docs/config.md @@ -1,8 +1,8 @@ - + ## AuthMe Configuration -The first time you run AuthMe it will create a config.yml file in the plugins/AuthMe folder, +The first time you run AuthMe it will create a config.yml file in the plugins/AuthMe folder, with which you can configure various settings. This following is the initial contents of the generated config.yml file. @@ -131,7 +131,7 @@ settings: # Hide the chat log from players who are not authenticated? hideChat: false # Allowed commands for unauthenticated players - allowCommands: + allowCommands: - '/login' - '/register' - '/l' @@ -158,7 +158,7 @@ settings: enabled: false # WorldNames where we need to force the spawn location # Case-sensitive! - worlds: + worlds: - 'world' - 'world_nether' - 'world_the_end' @@ -202,8 +202,8 @@ settings: # Should we display all other accounts from a player when he joins? # permission: /authme.admin.accounts displayOtherAccounts: true - # Spawn priority; values: authme, essentials, multiverse, default - spawnPriority: 'authme,essentials,multiverse,default' + # Spawn priority; values: authme, essentials, cmi, multiverse, default + spawnPriority: 'authme,essentials,cmi,multiverse,default' # Maximum Login authorized by IP maxLoginPerIp: 0 # Maximum Join authorized by IP @@ -258,7 +258,7 @@ settings: # - '123456' # - 'password' # - 'help' - unsafePasswords: + unsafePasswords: - '123456' - 'password' - 'qwerty' @@ -364,7 +364,7 @@ Email: # Delay in minute for the recall scheduler delayRecall: 5 # Blacklist these domains for emails - emailBlacklisted: + emailBlacklisted: - '10minutemail.com' # Whitelist ONLY these domains for emails emailWhitelisted: [] @@ -391,12 +391,12 @@ Protection: # Countries allowed to join the server and register. For country codes, see # http://dev.maxmind.com/geoip/legacy/codes/iso3166/ # PLEASE USE QUOTES! - countries: + countries: - 'US' - 'GB' # Countries not allowed to join the server and register # PLEASE USE QUOTES! - countriesBlacklist: + countriesBlacklist: - 'A1' # Do we need to enable automatic antibot system? enableAntiBot: true @@ -555,9 +555,9 @@ Converter: password: '' ``` -To change settings on a running server, save your changes to config.yml and use +To change settings on a running server, save your changes to config.yml and use `/authme reload`. --- -This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Tue Oct 31 15:56:59 CET 2017 +This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Tue Nov 28 12:49:57 CET 2017 diff --git a/src/main/java/fr/xephi/authme/listener/ServerListener.java b/src/main/java/fr/xephi/authme/listener/ServerListener.java index 055e72af..f424fc37 100644 --- a/src/main/java/fr/xephi/authme/listener/ServerListener.java +++ b/src/main/java/fr/xephi/authme/listener/ServerListener.java @@ -40,6 +40,10 @@ public class ServerListener implements Listener { if ("Essentials".equalsIgnoreCase(pluginName)) { pluginHookService.unhookEssentials(); ConsoleLogger.info("Essentials has been disabled: unhooking"); + } else if ("CMI".equalsIgnoreCase(pluginName)) { + pluginHookService.unhookCMI(); + spawnLoader.unloadCMISpawn(); + ConsoleLogger.info("CMI has been disabled: unhooking"); } else if ("Multiverse-Core".equalsIgnoreCase(pluginName)) { pluginHookService.unhookMultiverse(); ConsoleLogger.info("Multiverse-Core has been disabled: unhooking"); @@ -70,6 +74,9 @@ public class ServerListener implements Listener { pluginHookService.tryHookToMultiverse(); } else if ("EssentialsSpawn".equalsIgnoreCase(pluginName)) { spawnLoader.loadEssentialsSpawn(); + } else if ("CMI".equalsIgnoreCase(pluginName)) { + pluginHookService.tryHookToCMI(); + spawnLoader.loadCMISpawn(); } else if ("ProtocolLib".equalsIgnoreCase(pluginName)) { protocolLibService.setup(); } diff --git a/src/main/java/fr/xephi/authme/service/PluginHookService.java b/src/main/java/fr/xephi/authme/service/PluginHookService.java index af86b8a3..0ae10a7c 100644 --- a/src/main/java/fr/xephi/authme/service/PluginHookService.java +++ b/src/main/java/fr/xephi/authme/service/PluginHookService.java @@ -22,6 +22,7 @@ public class PluginHookService { private final PluginManager pluginManager; private Essentials essentials; + private Plugin cmi; private MultiverseCore multiverse; /** @@ -33,6 +34,7 @@ public class PluginHookService { public PluginHookService(PluginManager pluginManager) { this.pluginManager = pluginManager; tryHookToEssentials(); + tryHookToCMI(); tryHookToMultiverse(); } @@ -60,6 +62,19 @@ public class PluginHookService { return null; } + /** + * If CMI is hooked into, return CMI' data folder. + * + * @return The CMI data folder, or null if unavailable + */ + public File getCMIDataFolder() { + Plugin plugin = pluginManager.getPlugin("CMI"); + if(plugin == null) { + return null; + } + return plugin.getDataFolder(); + } + /** * Return the spawn of the given world as defined by Multiverse (if available). * @@ -76,10 +91,10 @@ public class PluginHookService { return null; } - // ------ // "Is plugin available" methods // ------ + /** * @return true if we have a hook to Essentials, false otherwise */ @@ -87,6 +102,13 @@ public class PluginHookService { return essentials != null; } + /** + * @return true if we have a hook to CMI, false otherwise + */ + public boolean isCMIAvailable() { + return cmi != null; + } + /** * @return true if we have a hook to Multiverse, false otherwise */ @@ -109,6 +131,17 @@ public class PluginHookService { } } + /** + * Attempts to create a hook into CMI. + */ + public void tryHookToCMI() { + try { + cmi = getPlugin(pluginManager, "CMI", Plugin.class); + } catch (Exception | NoClassDefFoundError ignored) { + cmi = null; + } + } + /** * Attempts to create a hook into Multiverse. */ @@ -123,6 +156,7 @@ public class PluginHookService { // ------ // Unhook methods // ------ + /** * Unhooks from Essentials. */ @@ -130,6 +164,13 @@ public class PluginHookService { essentials = null; } + /** + * Unhooks from CMI. + */ + public void unhookCMI() { + cmi = null; + } + /** * Unhooks from Multiverse. */ @@ -140,6 +181,7 @@ public class PluginHookService { // ------ // Helpers // ------ + private static T getPlugin(PluginManager pluginManager, String name, Class clazz) throws Exception, NoClassDefFoundError { if (pluginManager.isPluginEnabled(name)) { @@ -150,5 +192,4 @@ public class PluginHookService { return null; } - } diff --git a/src/main/java/fr/xephi/authme/settings/SpawnLoader.java b/src/main/java/fr/xephi/authme/settings/SpawnLoader.java index 09442ed4..f64c6848 100644 --- a/src/main/java/fr/xephi/authme/settings/SpawnLoader.java +++ b/src/main/java/fr/xephi/authme/settings/SpawnLoader.java @@ -35,6 +35,7 @@ public class SpawnLoader implements Reloadable { private FileConfiguration authMeConfiguration; private String[] spawnPriority; private Location essentialsSpawn; + private Location cmiSpawn; /** * Constructor. @@ -130,6 +131,32 @@ public class SpawnLoader implements Reloadable { essentialsSpawn = null; } + /** + * Load the spawn point defined in CMI. + */ + public void loadCMISpawn() { + File cmiFolder = pluginHookService.getCMIDataFolder(); + if (cmiFolder == null) { + return; + } + + File cmiConfig = new File(cmiFolder, "config.yml"); + if (cmiConfig.exists()) { + cmiSpawn = getLocationFromConfigurationUpper( + YamlConfiguration.loadConfiguration(cmiConfig), "Spawn.Main"); + } else { + cmiSpawn = null; + ConsoleLogger.info("CMI config file not found: '" + cmiConfig.getAbsolutePath() + "'"); + } + } + + /** + * Unset the spawn point defined in CMI. + */ + public void unloadCMISpawn() { + cmiSpawn = null; + } + /** * Return the spawn location for the given player. The source of the spawn location varies * depending on the spawn priority setting. @@ -162,6 +189,9 @@ public class SpawnLoader implements Reloadable { case "essentials": spawnLoc = essentialsSpawn; break; + case "cmi": + spawnLoc = cmiSpawn; + break; case "authme": spawnLoc = getSpawn(); break; @@ -242,6 +272,28 @@ public class SpawnLoader implements Reloadable { return null; } + /** + * Build a {@link Location} object from the given path in the file configuration. + * + * @param configuration The file configuration to read from + * @param pathPrefix The path to get the spawn point from + * + * @return Location corresponding to the values in the path + */ + private static Location getLocationFromConfigurationUpper(FileConfiguration configuration, String pathPrefix) { + if (containsAllSpawnFieldsUpper(configuration, pathPrefix)) { + String prefix = pathPrefix + "."; + String worldName = configuration.getString(prefix + "World"); + World world = Bukkit.getWorld(worldName); + if (!StringUtils.isEmpty(worldName) && world != null) { + return new Location(world, configuration.getDouble(prefix + "X"), + configuration.getDouble(prefix + "Y"), configuration.getDouble(prefix + "Z"), + getFloat(configuration, prefix + "Yaw"), getFloat(configuration, prefix + "Pitch")); + } + } + return null; + } + /** * Return whether the file configuration contains all fields necessary to define a spawn * under the given path. @@ -261,6 +313,25 @@ public class SpawnLoader implements Reloadable { return true; } + /** + * Return whether the file configuration contains all fields necessary to define a spawn + * under the given path. + * + * @param configuration The file configuration to use + * @param pathPrefix The path to verify + * + * @return True if all spawn fields are present, false otherwise + */ + private static boolean containsAllSpawnFieldsUpper(FileConfiguration configuration, String pathPrefix) { + String[] fields = {"World", "X", "Y", "Z", "Yaw", "Pitch"}; + for (String field : fields) { + if (!configuration.contains(pathPrefix + "." + field)) { + return false; + } + } + return true; + } + /** * Retrieve a property as a float from the given file configuration. * @@ -274,4 +345,5 @@ public class SpawnLoader implements Reloadable { // This behavior is consistent with FileConfiguration#getDouble return (value instanceof Number) ? ((Number) value).floatValue() : 0; } + } diff --git a/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java b/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java index ab202d2f..a53eaa76 100644 --- a/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java @@ -140,9 +140,9 @@ public final class RestrictionSettings implements SettingsHolder { public static final Property DISPLAY_OTHER_ACCOUNTS = newProperty("settings.restrictions.displayOtherAccounts", true); - @Comment("Spawn priority; values: authme, essentials, multiverse, default") + @Comment("Spawn priority; values: authme, essentials, cmi, multiverse, default") public static final Property SPAWN_PRIORITY = - newProperty("settings.restrictions.spawnPriority", "authme,essentials,multiverse,default"); + newProperty("settings.restrictions.spawnPriority", "authme,essentials,cmi,multiverse,default"); @Comment("Maximum Login authorized by IP") public static final Property MAX_LOGIN_PER_IP = diff --git a/src/test/java/fr/xephi/authme/listener/ServerListenerTest.java b/src/test/java/fr/xephi/authme/listener/ServerListenerTest.java index 2ffe57f5..29b484ad 100644 --- a/src/test/java/fr/xephi/authme/listener/ServerListenerTest.java +++ b/src/test/java/fr/xephi/authme/listener/ServerListenerTest.java @@ -31,6 +31,7 @@ public class ServerListenerTest { private static final String ESSENTIALS = "Essentials"; private static final String ESSENTIALS_SPAWN = "EssentialsSpawn"; + private static final String CMI = "CMI"; private static final String MULTIVERSE = "Multiverse-Core"; private static final String PROTOCOL_LIB = "ProtocolLib"; @@ -58,6 +59,10 @@ public class ServerListenerTest { public void shouldForwardPluginNameOnEnable() { checkEnableHandling(ESSENTIALS, () -> verify(pluginHookService).tryHookToEssentials()); checkEnableHandling(ESSENTIALS_SPAWN, () -> verify(spawnLoader).loadEssentialsSpawn()); + checkEnableHandling(CMI, () -> { + verify(pluginHookService).tryHookToCMI(); + verify(spawnLoader).loadCMISpawn(); + }); checkEnableHandling(MULTIVERSE, () -> verify(pluginHookService).tryHookToMultiverse()); checkEnableHandling(PROTOCOL_LIB, () -> verify(protocolLibService).setup()); checkEnableHandling("UnknownPlugin", () -> verifyZeroInteractions(pluginHookService, spawnLoader)); @@ -67,6 +72,10 @@ public class ServerListenerTest { public void shouldForwardPluginNameOnDisable() { checkDisableHandling(ESSENTIALS, () -> verify(pluginHookService).unhookEssentials()); checkDisableHandling(ESSENTIALS_SPAWN, () -> verify(spawnLoader).unloadEssentialsSpawn()); + checkDisableHandling(CMI, () -> { + verify(pluginHookService).unhookCMI(); + verify(spawnLoader).unloadCMISpawn(); + }); checkDisableHandling(MULTIVERSE, () -> verify(pluginHookService).unhookMultiverse()); checkDisableHandling(PROTOCOL_LIB, () -> verify(protocolLibService).disable()); checkDisableHandling("UnknownPlugin", () -> verifyZeroInteractions(pluginHookService, spawnLoader)); From 50dbbb8d87297b3c698d2f430b73ff775aef63ba Mon Sep 17 00:00:00 2001 From: ljacqu Date: Tue, 28 Nov 2017 21:07:10 +0100 Subject: [PATCH 4/8] #1254 Create command to see recently logged in players - Create datasource method to fetch most recent players by last login date - Add command to view last logged in players --- .../authme/command/CommandInitializer.java | 10 +++ .../authme/RecentPlayersCommand.java | 50 +++++++++++++++ .../authme/datasource/CacheDataSource.java | 5 ++ .../xephi/authme/datasource/DataSource.java | 7 +++ .../fr/xephi/authme/datasource/FlatFile.java | 5 ++ .../fr/xephi/authme/datasource/MySQL.java | 16 +++++ .../fr/xephi/authme/datasource/SQLite.java | 14 +++++ .../authme/permission/AdminPermission.java | 5 ++ src/main/resources/plugin.yml | 6 +- .../authme/RecentPlayersCommandTest.java | 61 +++++++++++++++++++ .../AbstractDataSourceIntegrationTest.java | 27 ++++++++ 11 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 src/main/java/fr/xephi/authme/command/executable/authme/RecentPlayersCommand.java create mode 100644 src/test/java/fr/xephi/authme/command/executable/authme/RecentPlayersCommandTest.java diff --git a/src/main/java/fr/xephi/authme/command/CommandInitializer.java b/src/main/java/fr/xephi/authme/command/CommandInitializer.java index dbce8733..2cd0fc60 100644 --- a/src/main/java/fr/xephi/authme/command/CommandInitializer.java +++ b/src/main/java/fr/xephi/authme/command/CommandInitializer.java @@ -17,6 +17,7 @@ import fr.xephi.authme.command.executable.authme.PurgeBannedPlayersCommand; import fr.xephi.authme.command.executable.authme.PurgeCommand; import fr.xephi.authme.command.executable.authme.PurgeLastPositionCommand; import fr.xephi.authme.command.executable.authme.PurgePlayerCommand; +import fr.xephi.authme.command.executable.authme.RecentPlayersCommand; import fr.xephi.authme.command.executable.authme.RegisterAdminCommand; import fr.xephi.authme.command.executable.authme.ReloadCommand; import fr.xephi.authme.command.executable.authme.SetEmailCommand; @@ -433,6 +434,15 @@ public class CommandInitializer { .executableCommand(MessagesCommand.class) .register(); + CommandDescription.builder() + .parent(authmeBase) + .labels("recent") + .description("See players who have recently logged in") + .detailedDescription("Shows the last players that have logged in.") + .permission(AdminPermission.SEE_RECENT_PLAYERS) + .executableCommand(RecentPlayersCommand.class) + .register(); + CommandDescription.builder() .parent(authmeBase) .labels("debug", "dbg") diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/RecentPlayersCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/RecentPlayersCommand.java new file mode 100644 index 00000000..1666acb1 --- /dev/null +++ b/src/main/java/fr/xephi/authme/command/executable/authme/RecentPlayersCommand.java @@ -0,0 +1,50 @@ +package fr.xephi.authme.command.executable.authme; + +import com.google.common.annotations.VisibleForTesting; +import fr.xephi.authme.command.ExecutableCommand; +import fr.xephi.authme.data.auth.PlayerAuth; +import fr.xephi.authme.datasource.DataSource; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; + +import javax.inject.Inject; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.List; + +import static java.time.Instant.ofEpochMilli; + +/** + * Command showing the most recent logged in players. + */ +public class RecentPlayersCommand implements ExecutableCommand { + + /** DateTime formatter, producing Strings such as "10:42 AM, 11 Jul". */ + private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("hh:mm a, dd MMM"); + + @Inject + private DataSource dataSource; + + @Override + public void executeCommand(CommandSender sender, List arguments) { + List recentPlayers = dataSource.getRecentlyLoggedInPlayers(); + + sender.sendMessage(ChatColor.BLUE + "[AuthMe] Recently logged in players"); + for (PlayerAuth auth : recentPlayers) { + sender.sendMessage(formatPlayerMessage(auth)); + } + } + + @VisibleForTesting + ZoneId getZoneId() { + return ZoneId.systemDefault(); + } + + private String formatPlayerMessage(PlayerAuth auth) { + LocalDateTime lastLogin = LocalDateTime.ofInstant(ofEpochMilli(auth.getLastLogin()), getZoneId()); + String lastLoginText = DATE_FORMAT.format(lastLogin); + + return "- " + auth.getRealName() + " (" + lastLoginText + " with IP " + auth.getLastIp() + ")"; + } +} diff --git a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java index ac2eaf12..39f04a53 100644 --- a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java @@ -263,6 +263,11 @@ public class CacheDataSource implements DataSource { .collect(Collectors.toList()); } + @Override + public List getRecentlyLoggedInPlayers() { + return source.getRecentlyLoggedInPlayers(); + } + @Override public void invalidateCache(String playerName) { cachedAuths.invalidate(playerName); diff --git a/src/main/java/fr/xephi/authme/datasource/DataSource.java b/src/main/java/fr/xephi/authme/datasource/DataSource.java index 715cb059..6f97951d 100644 --- a/src/main/java/fr/xephi/authme/datasource/DataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/DataSource.java @@ -225,6 +225,13 @@ public interface DataSource extends Reloadable { */ List getAllAuths(); + /** + * Returns the last ten players who have recently logged in (first ten players with highest last login date). + * + * @return the 10 last players who last logged in + */ + List getRecentlyLoggedInPlayers(); + /** * Reload the data source. */ diff --git a/src/main/java/fr/xephi/authme/datasource/FlatFile.java b/src/main/java/fr/xephi/authme/datasource/FlatFile.java index 0ace15b1..d234da55 100644 --- a/src/main/java/fr/xephi/authme/datasource/FlatFile.java +++ b/src/main/java/fr/xephi/authme/datasource/FlatFile.java @@ -393,6 +393,11 @@ public class FlatFile implements DataSource { throw new UnsupportedOperationException("Flat file no longer supported"); } + @Override + public List getRecentlyLoggedInPlayers() { + throw new UnsupportedOperationException("Flat file no longer supported"); + } + /** * Creates a PlayerAuth object from the read data. * diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index 98bbaa68..eb6019ca 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -716,6 +716,22 @@ public class MySQL implements DataSource { return players; } + @Override + public List getRecentlyLoggedInPlayers() { + List players = new ArrayList<>(); + String sql = "SELECT * FROM " + tableName + " ORDER BY " + col.LAST_LOGIN + " DESC LIMIT 10;"; + try (Connection con = getConnection(); + Statement st = con.createStatement(); + ResultSet rs = st.executeQuery(sql)) { + while (rs.next()) { + players.add(buildAuthFromResultSet(rs)); + } + } catch (SQLException e) { + logSqlException(e); + } + return players; + } + private PlayerAuth buildAuthFromResultSet(ResultSet row) throws SQLException { String salt = col.SALT.isEmpty() ? null : row.getString(col.SALT); int group = col.GROUP.isEmpty() ? -1 : row.getInt(col.GROUP); diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite.java b/src/main/java/fr/xephi/authme/datasource/SQLite.java index 8df1a033..4924e0cc 100644 --- a/src/main/java/fr/xephi/authme/datasource/SQLite.java +++ b/src/main/java/fr/xephi/authme/datasource/SQLite.java @@ -639,6 +639,20 @@ public class SQLite implements DataSource { return players; } + @Override + public List getRecentlyLoggedInPlayers() { + List players = new ArrayList<>(); + String sql = "SELECT * FROM " + tableName + " ORDER BY " + col.LAST_LOGIN + " DESC LIMIT 10;"; + try (Statement st = con.createStatement(); ResultSet rs = st.executeQuery(sql)) { + while (rs.next()) { + players.add(buildAuthFromResultSet(rs)); + } + } catch (SQLException e) { + logSqlException(e); + } + return players; + } + private PlayerAuth buildAuthFromResultSet(ResultSet row) throws SQLException { String salt = !col.SALT.isEmpty() ? row.getString(col.SALT) : null; diff --git a/src/main/java/fr/xephi/authme/permission/AdminPermission.java b/src/main/java/fr/xephi/authme/permission/AdminPermission.java index 14baf3ae..7664e143 100644 --- a/src/main/java/fr/xephi/authme/permission/AdminPermission.java +++ b/src/main/java/fr/xephi/authme/permission/AdminPermission.java @@ -50,6 +50,11 @@ public enum AdminPermission implements PermissionNode { */ GET_IP("authme.admin.getip"), + /** + * Administrator command to see the last recently logged in players. + */ + SEE_RECENT_PLAYERS("authme.admin.seerecent"), + /** * Administrator command to teleport to the AuthMe spawn. */ diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 9014476f..0f74a3ac 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -17,7 +17,7 @@ softdepend: commands: authme: description: AuthMe op commands - usage: /authme register|unregister|forcelogin|password|lastlogin|accounts|email|setemail|getip|spawn|setspawn|firstspawn|setfirstspawn|purge|purgeplayer|backup|resetpos|purgebannedplayers|switchantibot|reload|version|converter|messages|debug + usage: /authme register|unregister|forcelogin|password|lastlogin|accounts|email|setemail|getip|spawn|setspawn|firstspawn|setfirstspawn|purge|purgeplayer|backup|resetpos|purgebannedplayers|switchantibot|reload|version|converter|messages|recent|debug email: description: Add email or recover password usage: /email show|add|change|recover|code|setpassword @@ -74,6 +74,7 @@ permissions: authme.admin.register: true authme.admin.reload: true authme.admin.seeotheraccounts: true + authme.admin.seerecent: true authme.admin.setfirstspawn: true authme.admin.setspawn: true authme.admin.spawn: true @@ -134,6 +135,9 @@ permissions: authme.admin.seeotheraccounts: description: Permission to see the other accounts of the players that log in. default: op + authme.admin.seerecent: + description: Administrator command to see the last recently logged in players. + default: op authme.admin.setfirstspawn: description: Administrator command to set the first AuthMe spawn. default: op diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/RecentPlayersCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/RecentPlayersCommandTest.java new file mode 100644 index 00000000..eac5f8fb --- /dev/null +++ b/src/test/java/fr/xephi/authme/command/executable/authme/RecentPlayersCommandTest.java @@ -0,0 +1,61 @@ +package fr.xephi.authme.command.executable.authme; + +import fr.xephi.authme.data.auth.PlayerAuth; +import fr.xephi.authme.datasource.DataSource; +import org.bukkit.command.CommandSender; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnitRunner; + +import java.time.ZoneId; +import java.util.Arrays; +import java.util.Collections; + +import static org.hamcrest.Matchers.containsString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.hamcrest.MockitoHamcrest.argThat; + +/** + * Test for {@link RecentPlayersCommand}. + */ +@RunWith(MockitoJUnitRunner.class) +public class RecentPlayersCommandTest { + + @InjectMocks + @Spy + private RecentPlayersCommand command; + + @Mock + private DataSource dataSource; + + @Test + public void shouldShowRecentPlayers() { + // given + PlayerAuth auth1 = PlayerAuth.builder() + .name("hannah").realName("Hannah").lastIp("11.11.11.11") + .lastLogin(1510387755000L) // 11/11/2017 @ 8:09am + .build(); + PlayerAuth auth2 = PlayerAuth.builder() + .name("matt").realName("MATT").lastIp("22.11.22.33") + .lastLogin(1510269301000L) // 11/09/2017 @ 11:15pm + .build(); + doReturn(ZoneId.of("UTC")).when(command).getZoneId(); + given(dataSource.getRecentlyLoggedInPlayers()).willReturn(Arrays.asList(auth1, auth2)); + + CommandSender sender = mock(CommandSender.class); + + // when + command.executeCommand(sender, Collections.emptyList()); + + // then + verify(sender).sendMessage(argThat(containsString("Recently logged in players"))); + verify(sender).sendMessage("- Hannah (08:09 AM, 11 Nov with IP 11.11.11.11)"); + verify(sender).sendMessage("- MATT (11:15 PM, 09 Nov with IP 22.11.22.33)"); + } +} diff --git a/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java b/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java index f72c92ae..530ab56b 100644 --- a/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java @@ -1,5 +1,6 @@ package fr.xephi.authme.datasource; +import com.google.common.collect.Lists; import fr.xephi.authme.data.auth.PlayerAuth; import fr.xephi.authme.security.crypts.HashedPassword; import org.junit.Test; @@ -467,4 +468,30 @@ public abstract class AbstractDataSourceIntegrationTest { assertThat(dataSource.hasSession("user"), equalTo(true)); assertThat(dataSource.hasSession("nonExistentName"), equalTo(false)); } + + @Test + public void shouldGetRecentlyLoggedInPlayers() { + // given + DataSource dataSource = getDataSource(); + String[] names = {"user3", "user8", "user2", "user4", "user7", + "user11", "user14", "user12", "user18", "user16", + "user28", "user29", "user22", "user20", "user24"}; + long timestamp = 1461024000; // 2016-04-19 00:00:00 + for (int i = 0; i < names.length; ++i) { + PlayerAuth auth = PlayerAuth.builder().name(names[i]) + .registrationDate(1234567) + .lastLogin(timestamp + i * 3600) + .build(); + dataSource.saveAuth(auth); + dataSource.updateSession(auth); + } + + // when + List recentPlayers = dataSource.getRecentlyLoggedInPlayers(); + + // then + assertThat(Lists.transform(recentPlayers, PlayerAuth::getNickname), + contains("user24", "user20", "user22", "user29", "user28", + "user16", "user18", "user12", "user14", "user11")); + } } From f1c1848985cd8842cfe4ea7358c1aad5c01cf047 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Tue, 28 Nov 2017 21:41:30 +0100 Subject: [PATCH 5/8] #1046 Add onFirstLogin to commands.yml - Allow to configure commands run on player's first login (login of player with a previously null lastlogin date) --- .../xephi/authme/process/SyncProcessManager.java | 4 ++-- .../authme/process/login/AsynchronousLogin.java | 4 +++- .../process/login/ProcessSyncPlayerLogin.java | 11 ++++++++++- .../settings/commandconfig/CommandConfig.java | 9 +++++++++ .../settings/commandconfig/CommandManager.java | 12 +++++++++++- .../commandconfig/CommandMigrationService.java | 2 +- .../commandconfig/CommandSettingsHolder.java | 10 +++++++--- src/main/resources/commands.yml | 4 +++- .../commandconfig/CommandManagerTest.java | 15 +++++++++++++++ .../settings/commandconfig/commands.complete.yml | 4 ++++ 10 files changed, 65 insertions(+), 10 deletions(-) diff --git a/src/main/java/fr/xephi/authme/process/SyncProcessManager.java b/src/main/java/fr/xephi/authme/process/SyncProcessManager.java index e634302f..136c6b35 100644 --- a/src/main/java/fr/xephi/authme/process/SyncProcessManager.java +++ b/src/main/java/fr/xephi/authme/process/SyncProcessManager.java @@ -47,8 +47,8 @@ public class SyncProcessManager { runTask(() -> processSyncPlayerLogout.processSyncLogout(player)); } - public void processSyncPlayerLogin(Player player) { - runTask(() -> processSyncPlayerLogin.processPlayerLogin(player)); + public void processSyncPlayerLogin(Player player, boolean isFirstLogin) { + runTask(() -> processSyncPlayerLogin.processPlayerLogin(player, isFirstLogin)); } public void processSyncPlayerQuit(Player player, boolean wasLoggedIn) { 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 e76fea78..75219b45 100644 --- a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java @@ -220,6 +220,8 @@ public class AsynchronousLogin implements AsynchronousProcess { */ private void performLogin(Player player, PlayerAuth auth) { if (player.isOnline()) { + final boolean isFirstLogin = (auth.getLastLogin() == null); + // Update auth to reflect this new login final String ip = PlayerUtils.getPlayerIp(player); auth.setRealName(player.getName()); @@ -258,7 +260,7 @@ public class AsynchronousLogin implements AsynchronousProcess { // task, we schedule it in the end // so that we can be sure, and have not to care if it might be // processed in other order. - syncProcessManager.processSyncPlayerLogin(player); + syncProcessManager.processSyncPlayerLogin(player, isFirstLogin); } else { ConsoleLogger.warning("Player '" + player.getName() + "' wasn't online during login process, aborted..."); } 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 359aca03..f47ccdbf 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java @@ -62,7 +62,13 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess { } } - public void processPlayerLogin(Player player) { + /** + * Performs operations in sync mode for a player that has just logged in. + * + * @param player the player that was logged in + * @param isFirstLogin true if this is the first time the player logged in + */ + public void processPlayerLogin(Player player, boolean isFirstLogin) { final String name = player.getName().toLowerCase(); final LimboPlayer limbo = limboService.getLimboPlayer(name); @@ -93,6 +99,9 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess { welcomeMessageConfiguration.sendWelcomeMessage(player); // Login is now finished; we can force all commands + if (isFirstLogin) { + commandManager.runCommandsOnFirstLogin(player); + } commandManager.runCommandsOnLogin(player); // Send Bungee stuff. The service will check if it is enabled or not. 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 f7023020..e210f597 100644 --- a/src/main/java/fr/xephi/authme/settings/commandconfig/CommandConfig.java +++ b/src/main/java/fr/xephi/authme/settings/commandconfig/CommandConfig.java @@ -13,6 +13,7 @@ public class CommandConfig { private Map onJoin = new LinkedHashMap<>(); private Map onLogin = new LinkedHashMap<>(); private Map onSessionLogin = new LinkedHashMap<>(); + private Map onFirstLogin = new LinkedHashMap<>(); private Map onRegister = new LinkedHashMap<>(); private Map onUnregister = new LinkedHashMap<>(); private Map onLogout = new LinkedHashMap<>(); @@ -41,6 +42,14 @@ public class CommandConfig { this.onSessionLogin = onSessionLogin; } + public Map getOnFirstLogin() { + return onFirstLogin; + } + + public void setOnFirstLogin(Map onFirstLogin) { + this.onFirstLogin = onFirstLogin; + } + public Map getOnRegister() { return onRegister; } 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 f6fbd4c7..6fdb5fde 100644 --- a/src/main/java/fr/xephi/authme/settings/commandconfig/CommandManager.java +++ b/src/main/java/fr/xephi/authme/settings/commandconfig/CommandManager.java @@ -34,6 +34,7 @@ public class CommandManager implements Reloadable { private WrappedTagReplacer onJoinCommands; private WrappedTagReplacer onLoginCommands; private WrappedTagReplacer onSessionLoginCommands; + private WrappedTagReplacer onFirstLoginCommands; private WrappedTagReplacer onRegisterCommands; private WrappedTagReplacer onUnregisterCommands; private WrappedTagReplacer onLogoutCommands; @@ -75,7 +76,6 @@ public class CommandManager implements Reloadable { executeCommands(player, onLoginCommands.getAdaptedItems(player)); } - /** * Runs the configured commands for when a player has logged in successfully due to session. * @@ -85,6 +85,15 @@ public class CommandManager implements Reloadable { executeCommands(player, onSessionLoginCommands.getAdaptedItems(player)); } + /** + * Runs the configured commands for when a player logs in the first time. + * + * @param player the player that has logged in for the first time + */ + public void runCommandsOnFirstLogin(Player player) { + executeCommands(player, onFirstLoginCommands.getAdaptedItems(player)); + } + /** * Runs the configured commands for when a player has been unregistered. * @@ -124,6 +133,7 @@ public class CommandManager implements Reloadable { CommandConfig commandConfig = settingsManager.getProperty(CommandSettingsHolder.COMMANDS); onJoinCommands = newReplacer(commandConfig.getOnJoin()); onLoginCommands = newReplacer(commandConfig.getOnLogin()); + onFirstLoginCommands = newReplacer(commandConfig.getOnFirstLogin()); onSessionLoginCommands = newReplacer(commandConfig.getOnSessionLogin()); onRegisterCommands = newReplacer(commandConfig.getOnRegister()); onUnregisterCommands = newReplacer(commandConfig.getOnUnregister()); 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 e1d1085a..acd39cc6 100644 --- a/src/main/java/fr/xephi/authme/settings/commandconfig/CommandMigrationService.java +++ b/src/main/java/fr/xephi/authme/settings/commandconfig/CommandMigrationService.java @@ -23,7 +23,7 @@ class CommandMigrationService implements MigrationService { /** List of all properties in {@link CommandConfig}. */ @VisibleForTesting static final List COMMAND_CONFIG_PROPERTIES = ImmutableList.of( - "onJoin", "onLogin", "onSessionLogin", "onRegister", "onUnregister", "onLogout"); + "onJoin", "onLogin", "onSessionLogin", "onFirstLogin", "onRegister", "onUnregister", "onLogout"); @Inject private SettingsMigrationService settingsMigrationService; diff --git a/src/main/java/fr/xephi/authme/settings/commandconfig/CommandSettingsHolder.java b/src/main/java/fr/xephi/authme/settings/commandconfig/CommandSettingsHolder.java index 29e9b0c9..87530d22 100644 --- a/src/main/java/fr/xephi/authme/settings/commandconfig/CommandSettingsHolder.java +++ b/src/main/java/fr/xephi/authme/settings/commandconfig/CommandSettingsHolder.java @@ -22,7 +22,7 @@ public final class CommandSettingsHolder implements SettingsHolder { @SectionComments public static Map sectionComments() { - String[] comments = { + String[] rootComments = { "This configuration file allows you to execute commands on various events.", "Supported placeholders in commands:", " %p is replaced with the player name.", @@ -48,10 +48,14 @@ public final class CommandSettingsHolder implements SettingsHolder { " command: 'broadcast %p has joined, welcome back!'", " executor: CONSOLE", "", - "Supported command events: onLogin, onSessionLogin, onJoin, onLogout, onRegister, onUnregister" + "Supported command events: onLogin, onSessionLogin, onFirstLogin, onJoin, onLogout, onRegister, " + + "onUnregister" }; Map commentMap = new HashMap<>(); - commentMap.put("", comments); + commentMap.put("", rootComments); + commentMap.put("onFirstLogin", new String[]{ + "Commands to run for players logging in whose 'last login date' was empty" + }); commentMap.put("onUnregister", new String[]{ "Commands to run whenever a player is unregistered (by himself, or by an admin)" }); diff --git a/src/main/resources/commands.yml b/src/main/resources/commands.yml index fecccd59..5e7717ac 100644 --- a/src/main/resources/commands.yml +++ b/src/main/resources/commands.yml @@ -24,7 +24,9 @@ # command: 'broadcast %p has joined, welcome back!' # executor: CONSOLE # -# Supported command events: onLogin, onSessionLogin, onJoin, onLogout, onRegister, onUnregister +# Supported command events: onLogin, onSessionLogin, onFirstLogin, onJoin, onLogout, onRegister, onUnregister +# Commands to run for players logging in whose 'last login date' was empty +onFirstLogin: {} onJoin: {} onLogin: {} # These commands are called whenever a logged in player uses /logout or quits. 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 ebf92726..b4183d70 100644 --- a/src/test/java/fr/xephi/authme/settings/commandconfig/CommandManagerTest.java +++ b/src/test/java/fr/xephi/authme/settings/commandconfig/CommandManagerTest.java @@ -107,6 +107,21 @@ public class CommandManagerTest { verifyZeroInteractions(geoIpService); } + @Test + public void shouldExecuteCommandsOnFirstLogin() { + // given + copyJarFileAsCommandsYml(TEST_FILES_FOLDER + "commands.complete.yml"); + initManager(); + + // when + manager.runCommandsOnFirstLogin(player); + + // then + verify(bukkitService).dispatchConsoleCommand("pay Bobby 30"); + verifyNoMoreInteractions(bukkitService); + verifyZeroInteractions(geoIpService); + } + @Test public void shouldExecuteCommandsOnJoin() { // given 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 57154c7f..7bcf0b77 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 @@ -25,6 +25,10 @@ onSessionLogin: welcome: command: 'msg %p Session login!' executor: CONSOLE +onFirstLogin: + give_money: + command: 'pay %p 30' + executor: CONSOLE onUnregister: {} onLogout: announce: From 610fed3c7b208dd913b442811af34d985e42b417 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Wed, 29 Nov 2017 08:38:34 +0100 Subject: [PATCH 6/8] Fix codestyle, add test --- .../fr/xephi/authme/listener/ServerListener.java | 4 ++-- .../xephi/authme/service/PluginHookService.java | 10 +++++----- .../fr/xephi/authme/settings/SpawnLoader.java | 2 +- .../authme/listener/ServerListenerTest.java | 4 ++-- .../authme/service/PluginHookServiceTest.java | 16 ++++++++++++++++ 5 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/main/java/fr/xephi/authme/listener/ServerListener.java b/src/main/java/fr/xephi/authme/listener/ServerListener.java index f424fc37..83898bdc 100644 --- a/src/main/java/fr/xephi/authme/listener/ServerListener.java +++ b/src/main/java/fr/xephi/authme/listener/ServerListener.java @@ -41,7 +41,7 @@ public class ServerListener implements Listener { pluginHookService.unhookEssentials(); ConsoleLogger.info("Essentials has been disabled: unhooking"); } else if ("CMI".equalsIgnoreCase(pluginName)) { - pluginHookService.unhookCMI(); + pluginHookService.unhookCmi(); spawnLoader.unloadCMISpawn(); ConsoleLogger.info("CMI has been disabled: unhooking"); } else if ("Multiverse-Core".equalsIgnoreCase(pluginName)) { @@ -75,7 +75,7 @@ public class ServerListener implements Listener { } else if ("EssentialsSpawn".equalsIgnoreCase(pluginName)) { spawnLoader.loadEssentialsSpawn(); } else if ("CMI".equalsIgnoreCase(pluginName)) { - pluginHookService.tryHookToCMI(); + pluginHookService.tryHookToCmi(); spawnLoader.loadCMISpawn(); } else if ("ProtocolLib".equalsIgnoreCase(pluginName)) { protocolLibService.setup(); diff --git a/src/main/java/fr/xephi/authme/service/PluginHookService.java b/src/main/java/fr/xephi/authme/service/PluginHookService.java index 0ae10a7c..0a204aa0 100644 --- a/src/main/java/fr/xephi/authme/service/PluginHookService.java +++ b/src/main/java/fr/xephi/authme/service/PluginHookService.java @@ -34,7 +34,7 @@ public class PluginHookService { public PluginHookService(PluginManager pluginManager) { this.pluginManager = pluginManager; tryHookToEssentials(); - tryHookToCMI(); + tryHookToCmi(); tryHookToMultiverse(); } @@ -67,7 +67,7 @@ public class PluginHookService { * * @return The CMI data folder, or null if unavailable */ - public File getCMIDataFolder() { + public File getCmiDataFolder() { Plugin plugin = pluginManager.getPlugin("CMI"); if(plugin == null) { return null; @@ -105,7 +105,7 @@ public class PluginHookService { /** * @return true if we have a hook to CMI, false otherwise */ - public boolean isCMIAvailable() { + public boolean isCmiAvailable() { return cmi != null; } @@ -134,7 +134,7 @@ public class PluginHookService { /** * Attempts to create a hook into CMI. */ - public void tryHookToCMI() { + public void tryHookToCmi() { try { cmi = getPlugin(pluginManager, "CMI", Plugin.class); } catch (Exception | NoClassDefFoundError ignored) { @@ -167,7 +167,7 @@ public class PluginHookService { /** * Unhooks from CMI. */ - public void unhookCMI() { + public void unhookCmi() { cmi = null; } diff --git a/src/main/java/fr/xephi/authme/settings/SpawnLoader.java b/src/main/java/fr/xephi/authme/settings/SpawnLoader.java index f64c6848..93d1f57f 100644 --- a/src/main/java/fr/xephi/authme/settings/SpawnLoader.java +++ b/src/main/java/fr/xephi/authme/settings/SpawnLoader.java @@ -135,7 +135,7 @@ public class SpawnLoader implements Reloadable { * Load the spawn point defined in CMI. */ public void loadCMISpawn() { - File cmiFolder = pluginHookService.getCMIDataFolder(); + File cmiFolder = pluginHookService.getCmiDataFolder(); if (cmiFolder == null) { return; } diff --git a/src/test/java/fr/xephi/authme/listener/ServerListenerTest.java b/src/test/java/fr/xephi/authme/listener/ServerListenerTest.java index 29b484ad..8cfdf03e 100644 --- a/src/test/java/fr/xephi/authme/listener/ServerListenerTest.java +++ b/src/test/java/fr/xephi/authme/listener/ServerListenerTest.java @@ -60,7 +60,7 @@ public class ServerListenerTest { checkEnableHandling(ESSENTIALS, () -> verify(pluginHookService).tryHookToEssentials()); checkEnableHandling(ESSENTIALS_SPAWN, () -> verify(spawnLoader).loadEssentialsSpawn()); checkEnableHandling(CMI, () -> { - verify(pluginHookService).tryHookToCMI(); + verify(pluginHookService).tryHookToCmi(); verify(spawnLoader).loadCMISpawn(); }); checkEnableHandling(MULTIVERSE, () -> verify(pluginHookService).tryHookToMultiverse()); @@ -73,7 +73,7 @@ public class ServerListenerTest { checkDisableHandling(ESSENTIALS, () -> verify(pluginHookService).unhookEssentials()); checkDisableHandling(ESSENTIALS_SPAWN, () -> verify(spawnLoader).unloadEssentialsSpawn()); checkDisableHandling(CMI, () -> { - verify(pluginHookService).unhookCMI(); + verify(pluginHookService).unhookCmi(); verify(spawnLoader).unloadCMISpawn(); }); checkDisableHandling(MULTIVERSE, () -> verify(pluginHookService).unhookMultiverse()); diff --git a/src/test/java/fr/xephi/authme/service/PluginHookServiceTest.java b/src/test/java/fr/xephi/authme/service/PluginHookServiceTest.java index 763e6b31..d949db7d 100644 --- a/src/test/java/fr/xephi/authme/service/PluginHookServiceTest.java +++ b/src/test/java/fr/xephi/authme/service/PluginHookServiceTest.java @@ -35,6 +35,8 @@ public class PluginHookServiceTest { /** The plugin name of Essentials. */ private static final String ESSENTIALS = "Essentials"; + /** The plugin name of CMI. */ + private static final String CMI = "CMI"; /** The plugin name of Multiverse-Core. */ private static final String MULTIVERSE = "Multiverse-Core"; @@ -71,6 +73,19 @@ public class PluginHookServiceTest { assertThat(pluginHookService.isEssentialsAvailable(), equalTo(true)); } + @Test + public void shouldHookIntoCmiAtInitialization() { + // given + PluginManager pluginManager = mock(PluginManager.class); + setPluginAvailable(pluginManager, CMI, Plugin.class); + + // when + PluginHookService pluginHookService = new PluginHookService(pluginManager); + + // then + assertThat(pluginHookService.isCmiAvailable(), equalTo(true)); + } + @Test public void shouldHookIntoMultiverseAtInitialization() { // given @@ -175,6 +190,7 @@ public class PluginHookServiceTest { // then assertThat(pluginHookService.isEssentialsAvailable(), equalTo(false)); + assertThat(pluginHookService.isCmiAvailable(), equalTo(false)); assertThat(pluginHookService.isMultiverseAvailable(), equalTo(false)); } From 17eb7acf4d8bd8f99e67d6135783362895be28d6 Mon Sep 17 00:00:00 2001 From: Gabriele C Date: Wed, 29 Nov 2017 09:17:37 +0100 Subject: [PATCH 7/8] Change version format --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e0828671..1e785bf0 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ fr.xephi authme - 5.5-SNAPSHOT + 5.5.0-SNAPSHOT AuthMeReloaded The first authentication plugin for the Bukkit API! From c784fc7f2e126769ea174088053ae5546d4b8dff Mon Sep 17 00:00:00 2001 From: ljacqu Date: Wed, 29 Nov 2017 19:43:35 +0100 Subject: [PATCH 8/8] #1423 Fix ignored review remarks --- .../xephi/authme/listener/ServerListener.java | 4 +-- .../fr/xephi/authme/settings/SpawnLoader.java | 28 +++++++++---------- .../authme/listener/ServerListenerTest.java | 4 +-- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/main/java/fr/xephi/authme/listener/ServerListener.java b/src/main/java/fr/xephi/authme/listener/ServerListener.java index 83898bdc..4aceaf6f 100644 --- a/src/main/java/fr/xephi/authme/listener/ServerListener.java +++ b/src/main/java/fr/xephi/authme/listener/ServerListener.java @@ -42,7 +42,7 @@ public class ServerListener implements Listener { ConsoleLogger.info("Essentials has been disabled: unhooking"); } else if ("CMI".equalsIgnoreCase(pluginName)) { pluginHookService.unhookCmi(); - spawnLoader.unloadCMISpawn(); + spawnLoader.unloadCmiSpawn(); ConsoleLogger.info("CMI has been disabled: unhooking"); } else if ("Multiverse-Core".equalsIgnoreCase(pluginName)) { pluginHookService.unhookMultiverse(); @@ -76,7 +76,7 @@ public class ServerListener implements Listener { spawnLoader.loadEssentialsSpawn(); } else if ("CMI".equalsIgnoreCase(pluginName)) { pluginHookService.tryHookToCmi(); - spawnLoader.loadCMISpawn(); + spawnLoader.loadCmiSpawn(); } else if ("ProtocolLib".equalsIgnoreCase(pluginName)) { protocolLibService.setup(); } diff --git a/src/main/java/fr/xephi/authme/settings/SpawnLoader.java b/src/main/java/fr/xephi/authme/settings/SpawnLoader.java index 93d1f57f..ea235b3c 100644 --- a/src/main/java/fr/xephi/authme/settings/SpawnLoader.java +++ b/src/main/java/fr/xephi/authme/settings/SpawnLoader.java @@ -134,7 +134,7 @@ public class SpawnLoader implements Reloadable { /** * Load the spawn point defined in CMI. */ - public void loadCMISpawn() { + public void loadCmiSpawn() { File cmiFolder = pluginHookService.getCmiDataFolder(); if (cmiFolder == null) { return; @@ -142,8 +142,7 @@ public class SpawnLoader implements Reloadable { File cmiConfig = new File(cmiFolder, "config.yml"); if (cmiConfig.exists()) { - cmiSpawn = getLocationFromConfigurationUpper( - YamlConfiguration.loadConfiguration(cmiConfig), "Spawn.Main"); + cmiSpawn = getLocationFromCmiConfiguration(YamlConfiguration.loadConfiguration(cmiConfig)); } else { cmiSpawn = null; ConsoleLogger.info("CMI config file not found: '" + cmiConfig.getAbsolutePath() + "'"); @@ -153,7 +152,7 @@ public class SpawnLoader implements Reloadable { /** * Unset the spawn point defined in CMI. */ - public void unloadCMISpawn() { + public void unloadCmiSpawn() { cmiSpawn = null; } @@ -273,15 +272,15 @@ public class SpawnLoader implements Reloadable { } /** - * Build a {@link Location} object from the given path in the file configuration. + * Build a {@link Location} object based on the CMI configuration. * - * @param configuration The file configuration to read from - * @param pathPrefix The path to get the spawn point from + * @param configuration The CMI file configuration to read from * * @return Location corresponding to the values in the path */ - private static Location getLocationFromConfigurationUpper(FileConfiguration configuration, String pathPrefix) { - if (containsAllSpawnFieldsUpper(configuration, pathPrefix)) { + private static Location getLocationFromCmiConfiguration(FileConfiguration configuration) { + final String pathPrefix = "Spawn.Main"; + if (isLocationCompleteInCmiConfig(configuration, pathPrefix)) { String prefix = pathPrefix + "."; String worldName = configuration.getString(prefix + "World"); World world = Bukkit.getWorld(worldName); @@ -314,18 +313,17 @@ public class SpawnLoader implements Reloadable { } /** - * Return whether the file configuration contains all fields necessary to define a spawn - * under the given path. + * Return whether the CMI file configuration contains all spawn fields under the given path. * - * @param configuration The file configuration to use - * @param pathPrefix The path to verify + * @param cmiConfiguration The file configuration from CMI + * @param pathPrefix The path to verify * * @return True if all spawn fields are present, false otherwise */ - private static boolean containsAllSpawnFieldsUpper(FileConfiguration configuration, String pathPrefix) { + private static boolean isLocationCompleteInCmiConfig(FileConfiguration cmiConfiguration, String pathPrefix) { String[] fields = {"World", "X", "Y", "Z", "Yaw", "Pitch"}; for (String field : fields) { - if (!configuration.contains(pathPrefix + "." + field)) { + if (!cmiConfiguration.contains(pathPrefix + "." + field)) { return false; } } diff --git a/src/test/java/fr/xephi/authme/listener/ServerListenerTest.java b/src/test/java/fr/xephi/authme/listener/ServerListenerTest.java index 8cfdf03e..b015c2eb 100644 --- a/src/test/java/fr/xephi/authme/listener/ServerListenerTest.java +++ b/src/test/java/fr/xephi/authme/listener/ServerListenerTest.java @@ -61,7 +61,7 @@ public class ServerListenerTest { checkEnableHandling(ESSENTIALS_SPAWN, () -> verify(spawnLoader).loadEssentialsSpawn()); checkEnableHandling(CMI, () -> { verify(pluginHookService).tryHookToCmi(); - verify(spawnLoader).loadCMISpawn(); + verify(spawnLoader).loadCmiSpawn(); }); checkEnableHandling(MULTIVERSE, () -> verify(pluginHookService).tryHookToMultiverse()); checkEnableHandling(PROTOCOL_LIB, () -> verify(protocolLibService).setup()); @@ -74,7 +74,7 @@ public class ServerListenerTest { checkDisableHandling(ESSENTIALS_SPAWN, () -> verify(spawnLoader).unloadEssentialsSpawn()); checkDisableHandling(CMI, () -> { verify(pluginHookService).unhookCmi(); - verify(spawnLoader).unloadCMISpawn(); + verify(spawnLoader).unloadCmiSpawn(); }); checkDisableHandling(MULTIVERSE, () -> verify(pluginHookService).unhookMultiverse()); checkDisableHandling(PROTOCOL_LIB, () -> verify(protocolLibService).disable());