doubleEmailCheck: false
- # Do we force kicking player after a successful registration?
+ # Do we force kick a player after a successful registration?
# Do not use with login feature below
forceKickAfterRegister: false
# Does AuthMe need to enforce a /login after a successful registration?
forceLoginAfterRegister: false
- unrestrictions:
- # below you can list all account names that
- # AuthMe will ignore for registration or login, configure it
- # at your own risk!! Remember that if you are going to add
- # nickname with [], you have to delimit name with ' '.
- # this option add compatibility with BuildCraft and some
- # other mods.
- # It is CaseSensitive!
- UnrestrictedName: []
- # Message language, available : en, de, br, cz, pl, fr, ru, hu, sk, es, zhtw, fi, zhcn, lt, it, ko, pt
- messagesLanguage: en
- # Force these commands after /login, without any '/', use %p for replace with player name
+ # Force these commands after /login, without any '/', use %p to replace with player name
forceCommands: []
- # Force these commands after /login as a server console, without any '/', use %p for replace with player name
+ # Force these commands after /login as service console, without any '/'.
+ # Use %p to replace with player name
forceCommandsAsConsole: []
- # Force these commands after /register, without any '/', use %p for replace with player name
+ # Force these commands after /register, without any '/', use %p to replace with player name
forceRegisterCommands: []
- # Force these commands after /register as a server console, without any '/', use %p for replace with player name
+ # Force these commands after /register as a server console, without any '/'.
+ # Use %p to replace with player name
forceRegisterCommandsAsConsole: []
- # Do we need to display the welcome message (welcome.txt) after a login?
+ # Enable to display the welcome message (welcome.txt) after a login
# You can use colors in this welcome.txt + some replaced strings:
- # {PLAYER}: player name, {ONLINE}: display number of online players, {MAXPLAYERS}: display server slots,
- # {IP}: player ip, {LOGINS}: number of players logged, {WORLD}: player current world, {SERVER}: server name
+ # {PLAYER}: player name, {ONLINE}: display number of online players,
+ # {MAXPLAYERS}: display server slots, {IP}: player ip, {LOGINS}: number of players logged,
+ # {WORLD}: player current world, {SERVER}: server name
# {VERSION}: get current bukkit version, {COUNTRY}: player country
useWelcomeMessage: true
- # Do we need to broadcast the welcome message to all server or only to the player? set true for server or false for player
+ # Broadcast the welcome message to the server or only to the player?
+ # set true for server or false for player
broadcastWelcomeMessage: false
# Should we delay the join message and display it once the player has logged in?
delayJoinMessage: false
@@ -260,64 +304,115 @@ settings:
removeJoinMessage: false
# Should we remove leave messages altogether?
removeLeaveMessage: false
- # Do we need to add potion effect Blinding before login/register?
+ # Do we need to add potion effect Blinding before login/reigster?
applyBlindEffect: false
# Do we need to prevent people to login with another case?
# If Xephi is registered, then Xephi can login, but not XEPHI/xephi/XePhI
preventOtherCase: false
- # Log level: INFO, FINE, DEBUG. Use INFO for general messages,
- # FINE for some additional detailed ones (like password failed),
- # and DEBUG for debug messages
- logLevel: 'FINE'
- # By default we schedule async tasks when talking to the database
- # If you want typical communication with the database to happen synchronously, set this to false
- useAsyncTasks: true
-ExternalBoardOptions:
- # MySQL column for the salt, needed for some forum/cms support
- mySQLColumnSalt: ''
- # MySQL column for the group, needed for some forum/cms support
- mySQLColumnGroup: ''
- # -1 mean disabled. If u want that only
- # activated player can login in your server
- # u can put in this options the group number
- # of unactivated user, needed for some forum/cms support
- nonActivedUserGroup: -1
- # Other MySQL columns where we need to put the Username (case sensitive)
- mySQLOtherUsernameColumns: []
- # How much Log to Round needed in BCrypt(do not change it if you do not know what's your doing)
- bCryptLog2Round: 10
- # phpBB prefix defined during phpbb installation process
- phpbbTablePrefix: 'phpbb_'
- # phpBB activated group id, 2 is default registered group defined by phpbb
- phpbbActivatedGroupId: 2
- # WordPress prefix defined during WordPress installation process
- wordpressTablePrefix: 'wp_'
permission:
- # Take care with this options, if you dont want
- # to use Vault and Group Switching of
- # AuthMe for unloggedIn players put true
- # below, default is false.
+ # Take care with this option; if you want
+ # to use group switching of AuthMe
+ # for unloggedIn players, set this setting to true.
+ # Default is false.
EnablePermissionCheck: false
-BackupSystem:
- # Enable or Disable Automatic Backup
- ActivateBackup: false
- # set Backup at every start of Server
- OnServerStart: false
- # set Backup at every stop of Server
- OnServerStop: true
- # Windows only mysql installation Path
- MysqlWindowsPath: 'C:\Program Files\MySQL\MySQL Server 5.1\'
+Email:
+ # Email SMTP server host
+ mailSMTP: 'smtp.gmail.com'
+ # Email SMTP server port
+ mailPort: 465
+ # Email account which sends the mails
+ mailAccount: ''
+ # Email account password
+ mailPassword: ''
+ # Custom sender name, replacing the mailAccount name in the email
+ mailSenderName: ''
+ # Recovery password length
+ RecoveryPasswordLength: 8
+ # Mail Subject
+ mailSubject: 'Your new AuthMe password'
+ # Like maxRegPerIP but with email
+ maxRegPerEmail: 1
+ # Recall players to add an email?
+ recallPlayers: false
+ # Delay in minute for the recall scheduler
+ delayRecall: 5
+ # Blacklist these domains for emails
+ emailBlacklisted:
+ - '10minutemail.com'
+ # Whitelist ONLY these domains for emails
+ emailWhitelisted: []
+ # Send the new password drawn in an image?
+ generateImage: false
+ # The OAuth2 token
+ emailOauth2Token: ''
+Hooks:
+ # Do we need to hook with multiverse for spawn checking?
+ multiverse: true
+ # Do we need to hook with BungeeCord?
+ bungeecord: false
+ # Send player to this BungeeCord server after register/login
+ sendPlayerTo: ''
+ # Do we need to disable Essentials SocialSpy on join?
+ disableSocialSpy: true
+ # Do we need to force /motd Essentials command on join?
+ useEssentialsMotd: false
+GroupOptions:
+ # Unregistered permission group
+ UnregisteredPlayerGroup: ''
+ # Registered permission group
+ RegisteredPlayerGroup: ''
+Protection:
+ # Enable some servers protection (country based login, antibot)
+ enableProtection: false
+ # Apply the protection also to registered usernames
+ enableProtectionRegistered: true
+ # Countries allowed to join the server and register. For country codes, see
+ # http://dev.bukkit.org/bukkit-plugins/authme-reloaded/pages/countries-codes/
+ # PLEASE USE QUOTES!
+ countries:
+ - 'US'
+ - 'GB'
+ # Countries not allowed to join the server and register
+ # PLEASE USE QUOTES!
+ countriesBlacklist:
+ - 'A1'
+ # Do we need to enable automatic antibot system?
+ enableAntiBot: true
+ # Max number of players allowed to login in 5 secs
+ # before the AntiBot system is enabled automatically
+ antiBotSensibility: 10
+ # Duration in minutes of the antibot automatic system
+ antiBotDuration: 10
+ # Delay in seconds before the antibot activation
+ antiBotDelay: 60
+Purge:
+ # If enabled, AuthMe automatically purges old, unused accounts
+ useAutoPurge: false
+ # Number of days after which an account should be purged
+ daysBeforeRemovePlayer: 60
+ # Do we need to remove the player.dat file during purge process?
+ removePlayerDat: false
+ # Do we need to remove the Essentials/userdata/player.yml file during purge process?
+ removeEssentialsFile: false
+ # World where are players.dat stores
+ defaultWorld: 'world'
+ # Remove LimitedCreative/inventories/player.yml, player_creative.yml files during purge?
+ removeLimitedCreativesInventories: false
+ # Do we need to remove the AntiXRayData/PlayerData/player file during purge process?
+ removeAntiXRayFile: false
+ # Do we need to remove permissions?
+ removePermissions: false
Security:
SQLProblem:
# Stop the server if we can't contact the sql database
- # Take care with this, if you set that to false,
- # AuthMe automatically disable and the server is not protected!
+ # Take care with this, if you set this to false,
+ # AuthMe will automatically disable and the server won't be protected!
stopServer: true
ReloadCommand:
# /reload support
useReloadCommandSupport: true
console:
- # Replace passwords in the console when player type a command like /login
+ # Remove passwords from console?
removePassword: true
# Copy AuthMe log output in a separate file as well?
logConsole: true
@@ -344,99 +439,20 @@ Security:
length: 8
# How many hours is a recovery code valid for?
validForHours: 4
-Converter:
- Rakamak:
- # Rakamak file name
- fileName: users.rak
- # Rakamak use ip ?
- useIP: false
- # IP file name for rakamak
- ipFileName: UsersIp.rak
- CrazyLogin:
- # CrazyLogin database file
- fileName: accounts.db
-Email:
- # Email SMTP server host
- mailSMTP: smtp.gmail.com
- # Email SMTP server port
- mailPort: 465
- # Email account that send the mail
- mailAccount: ''
- # Email account password
- mailPassword: ''
- # Custom SenderName, that replace the mailAccount name in the email
- mailSenderName: ''
- # Random password length
- RecoveryPasswordLength: 8
- # Email subject of password get
- mailSubject: 'Your new AuthMe password'
- # Like maxRegPerIp but with email
- maxRegPerEmail: 1
- # Recall players to add an email?
- recallPlayers: false
- # Delay in minute for the recall scheduler
- delayRecall: 5
- # Blacklist these domains for emails
- emailBlacklisted:
- - 10minutemail.com
- # WhiteList only these domains for emails
- emailWhitelisted: []
- # Do we need to send new password draw in an image?
- generateImage: false
- # The email OAuth 2 token (leave empty if not used)
- emailOauth2Token: ''
-Hooks:
- # Do we need to hook with multiverse for spawn checking?
- multiverse: true
- # Do we need to hook with BungeeCord ?
- bungeecord: false
- # Send player to this BungeeCord server after register/login
- sendPlayerTo: ''
- # Do we need to disable Essentials SocialSpy on join?
- disableSocialSpy: true
- # Do we need to force /motd Essentials command on join?
- useEssentialsMotd: false
-Purge:
- # If enabled, AuthMe automatically purges old, unused accounts
- useAutoPurge: false
- # Number of Days an account become Unused
- daysBeforeRemovePlayer: 60
- # Do we need to remove the player.dat file during purge process?
- removePlayerDat: false
- # Do we need to remove the Essentials/userdata/player.yml file during purge process?
- removeEssentialsFile: false
- # World where are players.dat stores
- defaultWorld: 'world'
- # Do we need to remove LimitedCreative/inventories/player.yml, player_creative.yml files during purge process ?
- removeLimitedCreativesInventories: false
- # Do we need to remove the AntiXRayData/PlayerData/player file during purge process?
- removeAntiXRayFile: false
- # Do we need to remove permissions?
- removePermissions: false
-Protection:
- # Enable some servers protection ( country based login, antibot )
- enableProtection: false
- # Apply the protection also to registered usernames
- enableProtectionRegistered: true
- # Countries allowed to join the server and register, see http://dev.bukkit.org/bukkit-plugins/authme-reloaded/pages/countries-codes/ for countries' codes
- # PLEASE USE QUOTES!
- countries:
- - 'US'
- - 'GB'
- # Countries blacklisted automatically (without any needed to enable protection)
- # PLEASE USE QUOTES!
- countriesBlacklist:
- - 'A1'
- # Do we need to enable automatic antibot system?
- enableAntiBot: true
- # Max number of player allowed to login in 5 secs before enable AntiBot system automatically
- antiBotSensibility: 10
- # Duration in minutes of the antibot automatic system
- antiBotDuration: 10
- # Delay in seconds before the antibot activation
- antiBotDelay: 60
-GroupOptions:
- # Registered permission group
- RegisteredPlayerGroup: ''
- # Unregistered permission group
- UnregisteredPlayerGroup: ''
+BackupSystem:
+ # Enable or disable automatic backup
+ ActivateBackup: false
+ # Set backup at every start of server
+ OnServerStart: false
+ # Set backup at every stop of server
+ OnServerStop: true
+ # Windows only mysql installation Path
+ MysqlWindowsPath: 'C:\Program Files\MySQL\MySQL Server 5.1\'
+```
+
+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 Sun Oct 23 21:08:57 CEST 2016
diff --git a/docs/permission_nodes.md b/docs/permission_nodes.md
index 61f61c3e1..fb6408206 100644
--- a/docs/permission_nodes.md
+++ b/docs/permission_nodes.md
@@ -1,5 +1,5 @@
-
+
## AuthMe Permission Nodes
The following are the permission nodes that are currently supported by the latest dev builds.
@@ -26,25 +26,27 @@ The following are the permission nodes that are currently supported by the lates
- **authme.admin.spawn** – Administrator command to teleport to the AuthMe spawn.
- **authme.admin.switchantibot** – Administrator command to toggle the AntiBot protection status.
- **authme.admin.unregister** – Administrator command to unregister an existing user.
+- **authme.admin.updatemessages** – Permission to use the update messages command.
- **authme.allowmultipleaccounts** – Permission to be able to register multiple accounts.
- **authme.bypassantibot** – Permission node to bypass AntiBot protection.
- **authme.bypassforcesurvival** – Permission for users to bypass force-survival mode.
-- **authme.bypasspurge** – Permission to bypass the purging process
+- **authme.bypasspurge** – Permission to bypass the purging process.
- **authme.player.*** – Permission to use all player (non-admin) commands.
- **authme.player.canbeforced** – Permission for users a login can be forced to.
- **authme.player.captcha** – Command permission to use captcha.
- **authme.player.changepassword** – Command permission to change the password.
+- **authme.player.email** – Grants all email permissions.
- **authme.player.email.add** – Command permission to add an email address.
- **authme.player.email.change** – Command permission to change the email address.
-- **authme.player.email.recover** – Command permission to recover an account using it's email address.
+- **authme.player.email.recover** – Command permission to recover an account using its email address.
- **authme.player.login** – Command permission to login.
- **authme.player.logout** – Command permission to logout.
- **authme.player.register** – Command permission to register.
- **authme.player.seeownaccounts** – Permission to use to see own other accounts.
- **authme.player.unregister** – Command permission to unregister.
-- **authme.vip** – Permission node to identify VIP users.
+- **authme.vip** – When the server is full and someone with this permission joins the server, someone will be kicked.
---
-This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Oct 02 10:47:16 CEST 2016
+This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Oct 23 15:38:58 CEST 2016
diff --git a/docs/translations.md b/docs/translations.md
index c261bb8f6..c4288f152 100644
--- a/docs/translations.md
+++ b/docs/translations.md
@@ -1,5 +1,5 @@
-
+
# AuthMe Translations
The following translations are available in AuthMe. Set `messagesLanguage` to the language code
@@ -8,32 +8,32 @@ in your config.yml to use the language, or use another language code to start a
Code | Language | Translated |
---- | -------- | ---------: | ------
[en](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_en.yml) | English | 100% |
-[bg](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_bg.yml) | Bulgarian | 73% |
-[br](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_br.yml) | Brazilian | 100% |
-[cz](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_cz.yml) | Czech | 91% |
-[de](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_de.yml) | German | 97% |
-[es](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_es.yml) | Spanish | 100% |
-[eu](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_eu.yml) | Basque | 66% |
-[fi](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_fi.yml) | Finnish | 70% |
-[fr](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_fr.yml) | French | 97% |
-[gl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_gl.yml) | Galician | 74% |
-[hu](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_hu.yml) | Hungarian | 100% |
-[id](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_id.yml) | Indonesian | 74% |
+[bg](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_bg.yml) | Bulgarian | 71% |
+[br](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_br.yml) | Brazilian | 97% |
+[cz](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_cz.yml) | Czech | 88% |
+[de](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_de.yml) | German | 95% |
+[es](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_es.yml) | Spanish | 97% |
+[eu](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_eu.yml) | Basque | 64% |
+[fi](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_fi.yml) | Finnish | 68% |
+[fr](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_fr.yml) | French | 95% |
+[gl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_gl.yml) | Galician | 72% |
+[hu](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_hu.yml) | Hungarian | 97% |
+[id](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_id.yml) | Indonesian | 72% |
[it](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_it.yml) | Italian | 100% |
-[ko](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ko.yml) | Korean | 76% |
-[lt](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_lt.yml) | Latvian | 57% |
-[nl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_nl.yml) | Dutch | 80% |
-[pl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_pl.yml) | Polish | 95% |
-[pt](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_pt.yml) | Portuguese | 91% |
-[ru](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ru.yml) | Russian | 97% |
-[sk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_sk.yml) | Slovakian | 50% |
-[tr](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_tr.yml) | Turkish | 85% |
-[uk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_uk.yml) | Ukrainian | 97% |
-[vn](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_vn.yml) | Vietnamese | 85% |
-[zhcn](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhcn.yml) | Chinese (China) | 85% |
-[zhhk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhhk.yml) | Chinese (Hong Kong) | 85% |
-[zhtw](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhtw.yml) | Chinese (Taiwan) | 85% |
+[ko](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ko.yml) | Korean | 74% |
+[lt](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_lt.yml) | Latvian | 55% |
+[nl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_nl.yml) | Dutch | 78% |
+[pl](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_pl.yml) | Polish | 92% |
+[pt](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_pt.yml) | Portuguese | 88% |
+[ru](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_ru.yml) | Russian | 95% |
+[sk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_sk.yml) | Slovakian | 49% |
+[tr](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_tr.yml) | Turkish | 83% |
+[uk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_uk.yml) | Ukrainian | 95% |
+[vn](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_vn.yml) | Vietnamese | 83% |
+[zhcn](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhcn.yml) | Chinese (China) | 83% |
+[zhhk](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhhk.yml) | Chinese (Hong Kong) | 83% |
+[zhtw](https://github.com/AuthMe/AuthMeReloaded/blob/master/src/main/resources/messages/messages_zhtw.yml) | Chinese (Taiwan) | 83% |
---
-This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Oct 09 09:42:48 CEST 2016
+This page was automatically generated on the [AuthMe/AuthMeReloaded repository](https://github.com/AuthMe/AuthMeReloaded/tree/master/docs/) on Sun Oct 23 18:25:14 CEST 2016
diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java
index 8e9818bf2..b52caf32e 100644
--- a/src/main/java/fr/xephi/authme/AuthMe.java
+++ b/src/main/java/fr/xephi/authme/AuthMe.java
@@ -199,6 +199,9 @@ public class AuthMe extends JavaPlugin {
ConsoleLogger.setLogger(getLogger());
ConsoleLogger.setLogFile(new File(getDataFolder(), LOG_FILENAME));
+ // Create plugin folder
+ getDataFolder().mkdir();
+
// Load settings and set up the console and console filter
settings = Initializer.createSettings(this);
bukkitService = new BukkitService(this, settings);
diff --git a/src/main/java/fr/xephi/authme/command/CommandDescription.java b/src/main/java/fr/xephi/authme/command/CommandDescription.java
index 36ad6da6e..b6c006f9b 100644
--- a/src/main/java/fr/xephi/authme/command/CommandDescription.java
+++ b/src/main/java/fr/xephi/authme/command/CommandDescription.java
@@ -56,16 +56,10 @@ public class CommandDescription {
private PermissionNode permission;
/**
- * Private constructor. Use {@link CommandDescription#builder()} to create instances of this class.
+ * Private constructor.
*
- * Note for developers: Instances should be created with {@link CommandDescription#createInstance} to be properly
+ * Note for developers: Instances should be created with {@link CommandBuilder#register()} to be properly
* registered in the command tree.
- */
- private CommandDescription() {
- }
-
- /**
- * Create an instance.
*
* @param labels command labels
* @param description description of the command
@@ -74,30 +68,17 @@ public class CommandDescription {
* @param parent parent command
* @param arguments command arguments
* @param permission permission node required to execute this command
- *
- * @return the created instance
- * @see CommandDescription#builder()
*/
- private static CommandDescription createInstance(List labels, String description,
- String detailedDescription, Class extends ExecutableCommand> executableCommand, CommandDescription parent,
- List arguments, PermissionNode permission) {
- CommandDescription instance = new CommandDescription();
- instance.labels = labels;
- instance.description = description;
- instance.detailedDescription = detailedDescription;
- instance.executableCommand = executableCommand;
- instance.parent = parent;
- instance.arguments = arguments;
- instance.permission = permission;
-
- if (parent != null) {
- parent.addChild(instance);
- }
- return instance;
- }
-
- private void addChild(CommandDescription command) {
- children.add(command);
+ private CommandDescription(List labels, String description, String detailedDescription,
+ Class extends ExecutableCommand> executableCommand, CommandDescription parent,
+ List arguments, PermissionNode permission) {
+ this.labels = labels;
+ this.description = description;
+ this.detailedDescription = detailedDescription;
+ this.executableCommand = executableCommand;
+ this.parent = parent;
+ this.arguments = arguments;
+ this.permission = permission;
}
/**
@@ -224,8 +205,21 @@ public class CommandDescription {
private PermissionNode permission;
/**
- * Build a CommandDescription from the builder or throw an exception if a mandatory
- * field has not been set.
+ * Build a CommandDescription and register it onto the parent if available.
+ *
+ * @return The generated CommandDescription object
+ */
+ public CommandDescription register() {
+ CommandDescription command = build();
+
+ if (command.parent != null) {
+ command.parent.children.add(command);
+ }
+ return command;
+ }
+
+ /**
+ * Build a CommandDescription (without registering it on the parent).
*
* @return The generated CommandDescription object
*/
@@ -236,8 +230,8 @@ public class CommandDescription {
checkArgument(executableCommand != null, "Executable command must be set");
// parents and permissions may be null; arguments may be empty
- return createInstance(labels, description, detailedDescription, executableCommand,
- parent, arguments, permission);
+ return new CommandDescription(labels, description, detailedDescription, executableCommand,
+ parent, arguments, permission);
}
public CommandBuilder labels(List labels) {
diff --git a/src/main/java/fr/xephi/authme/command/CommandInitializer.java b/src/main/java/fr/xephi/authme/command/CommandInitializer.java
index a6d7b7674..7e01e0e30 100644
--- a/src/main/java/fr/xephi/authme/command/CommandInitializer.java
+++ b/src/main/java/fr/xephi/authme/command/CommandInitializer.java
@@ -1,6 +1,6 @@
package fr.xephi.authme.command;
-import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableList;
import fr.xephi.authme.command.executable.HelpCommand;
import fr.xephi.authme.command.executable.authme.AccountsCommand;
import fr.xephi.authme.command.executable.authme.AuthMeCommand;
@@ -11,6 +11,7 @@ import fr.xephi.authme.command.executable.authme.ForceLoginCommand;
import fr.xephi.authme.command.executable.authme.GetEmailCommand;
import fr.xephi.authme.command.executable.authme.GetIpCommand;
import fr.xephi.authme.command.executable.authme.LastLoginCommand;
+import fr.xephi.authme.command.executable.authme.MessagesCommand;
import fr.xephi.authme.command.executable.authme.PurgeBannedPlayersCommand;
import fr.xephi.authme.command.executable.authme.PurgeCommand;
import fr.xephi.authme.command.executable.authme.PurgeLastPositionCommand;
@@ -40,14 +41,13 @@ import fr.xephi.authme.permission.PlayerPermission;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
-import java.util.Set;
/**
* Initializes all available AuthMe commands.
*/
public class CommandInitializer {
- private Set commands;
+ private List commands;
public CommandInitializer() {
buildCommands();
@@ -58,7 +58,7 @@ public class CommandInitializer {
*
* @return the command descriptions
*/
- public Set getCommands() {
+ public List getCommands() {
return commands;
}
@@ -66,10 +66,10 @@ public class CommandInitializer {
// Register the base AuthMe Reloaded command
final CommandDescription AUTHME_BASE = CommandDescription.builder()
.labels("authme")
- .description("Main command")
+ .description("AuthMe op commands")
.detailedDescription("The main AuthMeReloaded command. The root for all admin commands.")
.executableCommand(AuthMeCommand.class)
- .build();
+ .register();
// Register the register command
CommandDescription.builder()
@@ -81,7 +81,7 @@ public class CommandInitializer {
.withArgument("password", "Password", false)
.permission(AdminPermission.REGISTER)
.executableCommand(RegisterAdminCommand.class)
- .build();
+ .register();
// Register the unregister command
CommandDescription.builder()
@@ -92,7 +92,7 @@ public class CommandInitializer {
.withArgument("player", "Player name", false)
.permission(AdminPermission.UNREGISTER)
.executableCommand(UnregisterAdminCommand.class)
- .build();
+ .register();
// Register the forcelogin command
CommandDescription.builder()
@@ -103,7 +103,7 @@ public class CommandInitializer {
.withArgument("player", "Online player name", true)
.permission(AdminPermission.FORCE_LOGIN)
.executableCommand(ForceLoginCommand.class)
- .build();
+ .register();
// Register the changepassword command
CommandDescription.builder()
@@ -115,7 +115,7 @@ public class CommandInitializer {
.withArgument("pwd", "New password", false)
.permission(AdminPermission.CHANGE_PASSWORD)
.executableCommand(ChangePasswordAdminCommand.class)
- .build();
+ .register();
// Register the last login command
CommandDescription.builder()
@@ -126,7 +126,7 @@ public class CommandInitializer {
.withArgument("player", "Player name", true)
.permission(AdminPermission.LAST_LOGIN)
.executableCommand(LastLoginCommand.class)
- .build();
+ .register();
// Register the accounts command
CommandDescription.builder()
@@ -137,7 +137,7 @@ public class CommandInitializer {
.withArgument("player", "Player name or IP", true)
.permission(AdminPermission.ACCOUNTS)
.executableCommand(AccountsCommand.class)
- .build();
+ .register();
// Register the getemail command
CommandDescription.builder()
@@ -148,7 +148,7 @@ public class CommandInitializer {
.withArgument("player", "Player name", true)
.permission(AdminPermission.GET_EMAIL)
.executableCommand(GetEmailCommand.class)
- .build();
+ .register();
// Register the setemail command
CommandDescription.builder()
@@ -160,7 +160,7 @@ public class CommandInitializer {
.withArgument("email", "Player email", false)
.permission(AdminPermission.CHANGE_EMAIL)
.executableCommand(SetEmailCommand.class)
- .build();
+ .register();
// Register the getip command
CommandDescription.builder()
@@ -171,7 +171,7 @@ public class CommandInitializer {
.withArgument("player", "Player name", false)
.permission(AdminPermission.GET_IP)
.executableCommand(GetIpCommand.class)
- .build();
+ .register();
// Register the spawn command
CommandDescription.builder()
@@ -181,7 +181,7 @@ public class CommandInitializer {
.detailedDescription("Teleport to the spawn.")
.permission(AdminPermission.SPAWN)
.executableCommand(SpawnCommand.class)
- .build();
+ .register();
// Register the setspawn command
CommandDescription.builder()
@@ -191,7 +191,7 @@ public class CommandInitializer {
.detailedDescription("Change the player's spawn to your current position.")
.permission(AdminPermission.SET_SPAWN)
.executableCommand(SetSpawnCommand.class)
- .build();
+ .register();
// Register the firstspawn command
CommandDescription.builder()
@@ -201,7 +201,7 @@ public class CommandInitializer {
.detailedDescription("Teleport to the first spawn.")
.permission(AdminPermission.FIRST_SPAWN)
.executableCommand(FirstSpawnCommand.class)
- .build();
+ .register();
// Register the setfirstspawn command
CommandDescription.builder()
@@ -211,7 +211,7 @@ public class CommandInitializer {
.detailedDescription("Change the first player's spawn to your current position.")
.permission(AdminPermission.SET_FIRST_SPAWN)
.executableCommand(SetFirstSpawnCommand.class)
- .build();
+ .register();
// Register the purge command
CommandDescription.builder()
@@ -223,7 +223,7 @@ public class CommandInitializer {
.withArgument("all", "Add 'all' at the end to also purge players with lastlogin = 0", true)
.permission(AdminPermission.PURGE)
.executableCommand(PurgeCommand.class)
- .build();
+ .register();
// Register the purgelastposition command
CommandDescription.builder()
@@ -235,7 +235,7 @@ public class CommandInitializer {
.withArgument("player/*", "Player name or * for all players", false)
.permission(AdminPermission.PURGE_LAST_POSITION)
.executableCommand(PurgeLastPositionCommand.class)
- .build();
+ .register();
// Register the purgebannedplayers command
CommandDescription.builder()
@@ -245,7 +245,7 @@ public class CommandInitializer {
.detailedDescription("Purge all AuthMeReloaded data for banned players.")
.permission(AdminPermission.PURGE_BANNED_PLAYERS)
.executableCommand(PurgeBannedPlayersCommand.class)
- .build();
+ .register();
// Register the switchantibot command
CommandDescription.builder()
@@ -256,7 +256,7 @@ public class CommandInitializer {
.withArgument("mode", "ON / OFF", true)
.permission(AdminPermission.SWITCH_ANTIBOT)
.executableCommand(SwitchAntiBotCommand.class)
- .build();
+ .register();
// Register the reload command
CommandDescription.builder()
@@ -266,7 +266,7 @@ public class CommandInitializer {
.detailedDescription("Reload the AuthMeReloaded plugin.")
.permission(AdminPermission.RELOAD)
.executableCommand(ReloadCommand.class)
- .build();
+ .register();
// Register the version command
CommandDescription.builder()
@@ -276,7 +276,7 @@ public class CommandInitializer {
.detailedDescription("Show detailed information about the installed AuthMeReloaded version, the "
+ "developers, contributors, and license.")
.executableCommand(VersionCommand.class)
- .build();
+ .register();
CommandDescription.builder()
.parent(AUTHME_BASE)
@@ -287,7 +287,16 @@ public class CommandInitializer {
"royalauth / vauth / sqliteToSql / mysqlToSqlite", false)
.permission(AdminPermission.CONVERTER)
.executableCommand(ConverterCommand.class)
- .build();
+ .register();
+
+ CommandDescription.builder()
+ .parent(AUTHME_BASE)
+ .labels("messages", "msg")
+ .description("Add missing messages")
+ .detailedDescription("Adds missing messages to the current messages file.")
+ .permission(AdminPermission.UPDATE_MESSAGES)
+ .executableCommand(MessagesCommand.class)
+ .register();
// Register the base login command
final CommandDescription LOGIN_BASE = CommandDescription.builder()
@@ -298,7 +307,7 @@ public class CommandInitializer {
.withArgument("password", "Login password", false)
.permission(PlayerPermission.LOGIN)
.executableCommand(LoginCommand.class)
- .build();
+ .register();
// Register the base logout command
CommandDescription LOGOUT_BASE = CommandDescription.builder()
@@ -308,51 +317,51 @@ public class CommandInitializer {
.detailedDescription("Command to logout using AuthMeReloaded.")
.permission(PlayerPermission.LOGOUT)
.executableCommand(LogoutCommand.class)
- .build();
+ .register();
// Register the base register command
final CommandDescription REGISTER_BASE = CommandDescription.builder()
.parent(null)
.labels("register", "reg")
- .description("Registration command")
+ .description("Register an account")
.detailedDescription("Command to register using AuthMeReloaded.")
.withArgument("password", "Password", true)
.withArgument("verifyPassword", "Verify password", true)
.permission(PlayerPermission.REGISTER)
.executableCommand(RegisterCommand.class)
- .build();
+ .register();
// Register the base unregister command
CommandDescription UNREGISTER_BASE = CommandDescription.builder()
.parent(null)
.labels("unregister", "unreg")
- .description("Unregistration Command")
+ .description("Unregister an account")
.detailedDescription("Command to unregister using AuthMeReloaded.")
.withArgument("password", "Password", false)
.permission(PlayerPermission.UNREGISTER)
.executableCommand(UnregisterCommand.class)
- .build();
+ .register();
// Register the base changepassword command
final CommandDescription CHANGE_PASSWORD_BASE = CommandDescription.builder()
.parent(null)
.labels("changepassword", "changepass", "cp")
- .description("Change password Command")
+ .description("Change password of an account")
.detailedDescription("Command to change your password using AuthMeReloaded.")
- .withArgument("oldPassword", "Old Password", false)
- .withArgument("newPassword", "New Password.", false)
+ .withArgument("oldPassword", "Old password", false)
+ .withArgument("newPassword", "New password", false)
.permission(PlayerPermission.CHANGE_PASSWORD)
.executableCommand(ChangePasswordCommand.class)
- .build();
+ .register();
// Register the base Email command
CommandDescription EMAIL_BASE = CommandDescription.builder()
.parent(null)
.labels("email")
- .description("Email command")
- .detailedDescription("The AuthMeReloaded Email command base.")
+ .description("Add email or recover password")
+ .detailedDescription("The AuthMeReloaded email command base.")
.executableCommand(EmailBaseCommand.class)
- .build();
+ .register();
// Register the show command
CommandDescription.builder()
@@ -361,7 +370,7 @@ public class CommandInitializer {
.description("Show Email")
.detailedDescription("Show your current email address.")
.executableCommand(ShowEmailCommand.class)
- .build();
+ .register();
// Register the add command
CommandDescription.builder()
@@ -373,7 +382,7 @@ public class CommandInitializer {
.withArgument("verifyEmail", "Email address verification", false)
.permission(PlayerPermission.ADD_EMAIL)
.executableCommand(AddEmailCommand.class)
- .build();
+ .register();
// Register the change command
CommandDescription.builder()
@@ -385,20 +394,20 @@ public class CommandInitializer {
.withArgument("newEmail", "New email address", false)
.permission(PlayerPermission.CHANGE_EMAIL)
.executableCommand(ChangeEmailCommand.class)
- .build();
+ .register();
// Register the recover command
CommandDescription.builder()
.parent(EMAIL_BASE)
.labels("recover", "recovery", "recoveremail", "recovermail")
- .description("Recover password using Email")
+ .description("Recover password using email")
.detailedDescription("Recover your account using an Email address by sending a mail containing " +
"a new password.")
.withArgument("email", "Email address", false)
.withArgument("code", "Recovery code", true)
.permission(PlayerPermission.RECOVER_EMAIL)
.executableCommand(RecoverEmailCommand.class)
- .build();
+ .register();
// Register the base captcha command
CommandDescription CAPTCHA_BASE = CommandDescription.builder()
@@ -409,9 +418,9 @@ public class CommandInitializer {
.withArgument("captcha", "The Captcha", false)
.permission(PlayerPermission.CAPTCHA)
.executableCommand(CaptchaCommand.class)
- .build();
+ .register();
- Set baseCommands = ImmutableSet.of(
+ List baseCommands = ImmutableList.of(
AUTHME_BASE,
LOGIN_BASE,
LOGOUT_BASE,
@@ -441,7 +450,7 @@ public class CommandInitializer {
.detailedDescription("View detailed help for /" + base.getLabels().get(0) + " commands.")
.withArgument("query", "The command or query to view help for.", true)
.executableCommand(HelpCommand.class)
- .build();
+ .register();
}
}
}
diff --git a/src/main/java/fr/xephi/authme/command/CommandMapper.java b/src/main/java/fr/xephi/authme/command/CommandMapper.java
index 44d5b5833..e36664929 100644
--- a/src/main/java/fr/xephi/authme/command/CommandMapper.java
+++ b/src/main/java/fr/xephi/authme/command/CommandMapper.java
@@ -8,6 +8,7 @@ import org.bukkit.command.CommandSender;
import javax.inject.Inject;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -26,7 +27,7 @@ public class CommandMapper {
*/
private static final Class extends ExecutableCommand> HELP_COMMAND_CLASS = HelpCommand.class;
- private final Set baseCommands;
+ private final Collection baseCommands;
private final PermissionsManager permissionsManager;
@Inject
diff --git a/src/main/java/fr/xephi/authme/command/CommandUtils.java b/src/main/java/fr/xephi/authme/command/CommandUtils.java
index 9ea1f5c55..699e4f37e 100644
--- a/src/main/java/fr/xephi/authme/command/CommandUtils.java
+++ b/src/main/java/fr/xephi/authme/command/CommandUtils.java
@@ -1,9 +1,11 @@
package fr.xephi.authme.command;
import com.google.common.collect.Lists;
+import org.bukkit.ChatColor;
import java.util.ArrayList;
import java.util.List;
+import java.util.stream.Collectors;
public final class CommandUtils {
@@ -34,6 +36,14 @@ public final class CommandUtils {
return sb.toString();
}
+ /**
+ * Constructs a hierarchical list of commands for the given command. The commands are in order:
+ * the parents of the given command precede the provided command. For example, given the command
+ * for {@code /authme register}, a list with {@code [{authme}, {authme register}]} is returned.
+ *
+ * @param command the command to build a parent list for
+ * @return the parent list
+ */
public static List constructParentList(CommandDescription command) {
List commands = new ArrayList<>();
CommandDescription currentCommand = command;
@@ -43,4 +53,35 @@ public final class CommandUtils {
}
return Lists.reverse(commands);
}
+
+ public static String buildSyntax(CommandDescription command) {
+ String arguments = command.getArguments().stream()
+ .map(arg -> formatArgument(arg))
+ .collect(Collectors.joining(" "));
+ return (constructCommandPath(command) + " " + arguments).trim();
+ }
+
+ public static String buildSyntax(CommandDescription command, List correctLabels) {
+ String commandSyntax = ChatColor.WHITE + "/" + correctLabels.get(0) + ChatColor.YELLOW;
+ for (int i = 1; i < correctLabels.size(); ++i) {
+ commandSyntax += " " + correctLabels.get(i);
+ }
+ for (CommandArgumentDescription argument : command.getArguments()) {
+ commandSyntax += " " + formatArgument(argument);
+ }
+ return commandSyntax;
+ }
+
+ /**
+ * Format a command argument with the proper type of brackets.
+ *
+ * @param argument the argument to format
+ * @return the formatted argument
+ */
+ public static String formatArgument(CommandArgumentDescription argument) {
+ if (argument.isOptional()) {
+ return "[" + argument.getName() + "]";
+ }
+ return "<" + argument.getName() + ">";
+ }
}
diff --git a/src/main/java/fr/xephi/authme/command/executable/HelpCommand.java b/src/main/java/fr/xephi/authme/command/executable/HelpCommand.java
index 2076bcbce..0f7d90d20 100644
--- a/src/main/java/fr/xephi/authme/command/executable/HelpCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/HelpCommand.java
@@ -14,6 +14,11 @@ import java.util.List;
import static fr.xephi.authme.command.FoundResultStatus.MISSING_BASE_COMMAND;
import static fr.xephi.authme.command.FoundResultStatus.UNKNOWN_LABEL;
+import static fr.xephi.authme.command.help.HelpProvider.ALL_OPTIONS;
+import static fr.xephi.authme.command.help.HelpProvider.SHOW_ALTERNATIVES;
+import static fr.xephi.authme.command.help.HelpProvider.SHOW_CHILDREN;
+import static fr.xephi.authme.command.help.HelpProvider.SHOW_COMMAND;
+import static fr.xephi.authme.command.help.HelpProvider.SHOW_DESCRIPTION;
public class HelpCommand implements ExecutableCommand {
@@ -46,9 +51,9 @@ public class HelpCommand implements ExecutableCommand {
int mappedCommandLevel = result.getCommandDescription().getLabelCount();
if (mappedCommandLevel == 1) {
- helpProvider.outputHelp(sender, result, HelpProvider.SHOW_CHILDREN);
+ helpProvider.outputHelp(sender, result, SHOW_COMMAND | SHOW_DESCRIPTION | SHOW_CHILDREN | SHOW_ALTERNATIVES);
} else {
- helpProvider.outputHelp(sender, result, HelpProvider.ALL_OPTIONS);
+ helpProvider.outputHelp(sender, result, ALL_OPTIONS);
}
}
diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/MessagesCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/MessagesCommand.java
new file mode 100644
index 000000000..a7d38d5ac
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/command/executable/authme/MessagesCommand.java
@@ -0,0 +1,54 @@
+package fr.xephi.authme.command.executable.authme;
+
+import fr.xephi.authme.ConsoleLogger;
+import fr.xephi.authme.command.ExecutableCommand;
+import fr.xephi.authme.initialization.DataFolder;
+import fr.xephi.authme.message.Messages;
+import fr.xephi.authme.service.MessageUpdater;
+import fr.xephi.authme.settings.Settings;
+import fr.xephi.authme.settings.properties.PluginSettings;
+import org.bukkit.command.CommandSender;
+
+import javax.inject.Inject;
+import java.io.File;
+import java.util.List;
+
+/**
+ * Messages command, updates the user's messages file with any missing files
+ * from the provided file in the JAR.
+ */
+public class MessagesCommand implements ExecutableCommand {
+
+ private static final String DEFAULT_LANGUAGE = "en";
+
+ @Inject
+ private Settings settings;
+ @Inject
+ @DataFolder
+ private File dataFolder;
+ @Inject
+ private Messages messages;
+
+ @Override
+ public void executeCommand(CommandSender sender, List arguments) {
+ final String language = settings.getProperty(PluginSettings.MESSAGES_LANGUAGE);
+
+ try {
+ boolean isFileUpdated = new MessageUpdater(
+ new File(dataFolder, getMessagePath(language)),
+ getMessagePath(language),
+ getMessagePath(DEFAULT_LANGUAGE))
+ .executeCopy(sender);
+ if (isFileUpdated) {
+ messages.reload();
+ }
+ } catch (Exception e) {
+ sender.sendMessage("Could not update messages: " + e.getMessage());
+ ConsoleLogger.logException("Could not update messages:", e);
+ }
+ }
+
+ private static String getMessagePath(String code) {
+ return "messages/messages_" + code + ".yml";
+ }
+}
diff --git a/src/main/java/fr/xephi/authme/command/help/CommandSyntaxHelper.java b/src/main/java/fr/xephi/authme/command/help/CommandSyntaxHelper.java
deleted file mode 100644
index 86ffb5427..000000000
--- a/src/main/java/fr/xephi/authme/command/help/CommandSyntaxHelper.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package fr.xephi.authme.command.help;
-
-import fr.xephi.authme.command.CommandArgumentDescription;
-import fr.xephi.authme.command.CommandDescription;
-import org.bukkit.ChatColor;
-
-import java.util.List;
-
-/**
- * Helper class for displaying the syntax of a command properly to a user.
- */
-final class CommandSyntaxHelper {
-
- private CommandSyntaxHelper() {
- }
-
- public static String getSyntax(CommandDescription command, List correctLabels) {
- String commandSyntax = ChatColor.WHITE + "/" + correctLabels.get(0) + ChatColor.YELLOW;
- for (int i = 1; i < correctLabels.size(); ++i) {
- commandSyntax += " " + correctLabels.get(i);
- }
- for (CommandArgumentDescription argument : command.getArguments()) {
- commandSyntax += " " + formatArgument(argument);
- }
- return commandSyntax;
- }
-
- /** Format a command argument with the proper type of brackets. */
- private static String formatArgument(CommandArgumentDescription argument) {
- if (argument.isOptional()) {
- return "[" + argument.getName() + "]";
- }
- return "<" + argument.getName() + ">";
- }
-
-}
diff --git a/src/main/java/fr/xephi/authme/command/help/HelpMessagesService.java b/src/main/java/fr/xephi/authme/command/help/HelpMessagesService.java
index b500e4310..c2cbaff99 100644
--- a/src/main/java/fr/xephi/authme/command/help/HelpMessagesService.java
+++ b/src/main/java/fr/xephi/authme/command/help/HelpMessagesService.java
@@ -67,6 +67,10 @@ public class HelpMessagesService implements Reloadable {
return localCommand;
}
+ public String getDescription(CommandDescription command) {
+ return getText(getCommandPath(command) + DESCRIPTION_SUFFIX, command::getDescription);
+ }
+
public String getMessage(HelpMessage message) {
return messageFileHandler.getMessage(message.getKey());
}
diff --git a/src/main/java/fr/xephi/authme/command/help/HelpProvider.java b/src/main/java/fr/xephi/authme/command/help/HelpProvider.java
index 8fc941617..23e87cab6 100644
--- a/src/main/java/fr/xephi/authme/command/help/HelpProvider.java
+++ b/src/main/java/fr/xephi/authme/command/help/HelpProvider.java
@@ -15,11 +15,12 @@ import org.bukkit.command.CommandSender;
import javax.inject.Inject;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
+import java.util.function.Function;
import static fr.xephi.authme.command.help.HelpSection.DETAILED_DESCRIPTION;
import static fr.xephi.authme.command.help.HelpSection.SHORT_DESCRIPTION;
-import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
/**
@@ -79,7 +80,7 @@ public class HelpProvider implements Reloadable {
if (hasFlag(SHOW_COMMAND, options)) {
lines.add(ChatColor.GOLD + helpMessagesService.getMessage(HelpSection.COMMAND) + ": "
- + CommandSyntaxHelper.getSyntax(command, correctLabels));
+ + CommandUtils.buildSyntax(command, correctLabels));
}
if (hasFlag(SHOW_DESCRIPTION, options)) {
lines.add(ChatColor.GOLD + helpMessagesService.getMessage(SHORT_DESCRIPTION) + ": "
@@ -171,19 +172,29 @@ public class HelpProvider implements Reloadable {
}
private void printAlternatives(CommandDescription command, List correctLabels, List lines) {
- if (command.getLabels().size() <= 1 || correctLabels.size() <= 1) {
+ if (command.getLabels().size() <= 1) {
return;
}
lines.add(ChatColor.GOLD + helpMessagesService.getMessage(HelpSection.ALTERNATIVES) + ":");
- // Get the label used
- final String parentLabel = correctLabels.get(0);
- final String childLabel = correctLabels.get(1);
+
+ // Label with which the command was called -> don't show it as an alternative
+ final String usedLabel;
+ // Takes alternative label and constructs list of labels, e.g. "reg" -> [authme, reg]
+ final Function> commandLabelsFn;
+
+ if (correctLabels.size() == 1) {
+ usedLabel = correctLabels.get(0);
+ commandLabelsFn = label -> singletonList(label);
+ } else {
+ usedLabel = correctLabels.get(1);
+ commandLabelsFn = label -> Arrays.asList(correctLabels.get(0), label);
+ }
// Create a list of alternatives
- for (String entry : command.getLabels()) {
- if (!entry.equalsIgnoreCase(childLabel)) {
- lines.add(" " + CommandSyntaxHelper.getSyntax(command, asList(parentLabel, entry)));
+ for (String label : command.getLabels()) {
+ if (!label.equalsIgnoreCase(usedLabel)) {
+ lines.add(" " + CommandUtils.buildSyntax(command, commandLabelsFn.apply(label)));
}
}
}
@@ -238,7 +249,7 @@ public class HelpProvider implements Reloadable {
String parentCommandPath = String.join(" ", parentLabels);
for (CommandDescription child : command.getChildren()) {
lines.add(" /" + parentCommandPath + " " + child.getLabels().get(0)
- + ChatColor.GRAY + ChatColor.ITALIC + ": " + child.getDescription());
+ + ChatColor.GRAY + ChatColor.ITALIC + ": " + helpMessagesService.getDescription(child));
}
}
diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java
index 9c613ec35..9da225b94 100644
--- a/src/main/java/fr/xephi/authme/datasource/MySQL.java
+++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java
@@ -40,6 +40,7 @@ public class MySQL implements DataSource {
private String password;
private String database;
private String tableName;
+ private int poolSize;
private List columnOthers;
private Columns col;
private HashAlgorithm hashAlgorithm;
@@ -98,6 +99,10 @@ public class MySQL implements DataSource {
this.phpBbPrefix = settings.getProperty(HooksSettings.PHPBB_TABLE_PREFIX);
this.phpBbGroup = settings.getProperty(HooksSettings.PHPBB_ACTIVATED_GROUP_ID);
this.wordpressPrefix = settings.getProperty(HooksSettings.WORDPRESS_TABLE_PREFIX);
+ this.poolSize = settings.getProperty(DatabaseSettings.MYSQL_POOL_SIZE);
+ if(poolSize == -1) {
+ poolSize = RuntimeUtils.getCoreCount();
+ }
}
private void setConnectionArguments() throws RuntimeException {
@@ -105,7 +110,7 @@ public class MySQL implements DataSource {
ds.setPoolName("AuthMeMYSQLPool");
// Pool size
- ds.setMaximumPoolSize(RuntimeUtils.getCoreCount());
+ ds.setMaximumPoolSize(poolSize);
// Database URL
ds.setJdbcUrl("jdbc:mysql://" + this.host + ":" + this.port + "/" + this.database);
diff --git a/src/main/java/fr/xephi/authme/initialization/Initializer.java b/src/main/java/fr/xephi/authme/initialization/Initializer.java
index eaac2abc9..525334c27 100644
--- a/src/main/java/fr/xephi/authme/initialization/Initializer.java
+++ b/src/main/java/fr/xephi/authme/initialization/Initializer.java
@@ -62,13 +62,13 @@ public class Initializer {
*/
public static Settings createSettings(AuthMe authMe) throws Exception {
File configFile = new File(authMe.getDataFolder(), "config.yml");
- if (FileUtils.copyFileFromResource(configFile, "config.yml")) {
- PropertyResource resource = new YamlFileResource(configFile);
- SettingsMigrationService migrationService = new SettingsMigrationService(authMe.getDataFolder());
- ConfigurationData configurationData = AuthMeSettingsRetriever.buildConfigurationData();
- return new Settings(authMe.getDataFolder(), resource, migrationService, configurationData);
+ if(!configFile.exists()) {
+ configFile.createNewFile();
}
- throw new Exception("Could not copy config.yml from JAR to plugin folder");
+ PropertyResource resource = new YamlFileResource(configFile);
+ SettingsMigrationService migrationService = new SettingsMigrationService(authMe.getDataFolder());
+ ConfigurationData configurationData = AuthMeSettingsRetriever.buildConfigurationData();
+ return new Settings(authMe.getDataFolder(), resource, migrationService, configurationData);
}
/**
diff --git a/src/main/java/fr/xephi/authme/permission/AdminPermission.java b/src/main/java/fr/xephi/authme/permission/AdminPermission.java
index ed5ab9f4c..46d58072a 100644
--- a/src/main/java/fr/xephi/authme/permission/AdminPermission.java
+++ b/src/main/java/fr/xephi/authme/permission/AdminPermission.java
@@ -8,126 +8,125 @@ public enum AdminPermission implements PermissionNode {
/**
* Administrator command to register a new user.
*/
- REGISTER("authme.admin.register", DefaultPermission.OP_ONLY),
+ REGISTER("authme.admin.register"),
/**
* Administrator command to unregister an existing user.
*/
- UNREGISTER("authme.admin.unregister", DefaultPermission.OP_ONLY),
+ UNREGISTER("authme.admin.unregister"),
/**
* Administrator command to force-login an existing user.
*/
- FORCE_LOGIN("authme.admin.forcelogin", DefaultPermission.OP_ONLY),
+ FORCE_LOGIN("authme.admin.forcelogin"),
/**
* Administrator command to change the password of a user.
*/
- CHANGE_PASSWORD("authme.admin.changepassword", DefaultPermission.OP_ONLY),
+ CHANGE_PASSWORD("authme.admin.changepassword"),
/**
* Administrator command to see the last login date and time of a user.
*/
- LAST_LOGIN("authme.admin.lastlogin", DefaultPermission.OP_ONLY),
+ LAST_LOGIN("authme.admin.lastlogin"),
/**
* Administrator command to see all accounts associated with a user.
*/
- ACCOUNTS("authme.admin.accounts", DefaultPermission.OP_ONLY),
+ ACCOUNTS("authme.admin.accounts"),
/**
* Administrator command to get the email address of a user, if set.
*/
- GET_EMAIL("authme.admin.getemail", DefaultPermission.OP_ONLY),
+ GET_EMAIL("authme.admin.getemail"),
/**
* Administrator command to set or change the email address of a user.
*/
- CHANGE_EMAIL("authme.admin.changemail", DefaultPermission.OP_ONLY),
+ CHANGE_EMAIL("authme.admin.changemail"),
/**
* Administrator command to get the last known IP of a user.
*/
- GET_IP("authme.admin.getip", DefaultPermission.OP_ONLY),
+ GET_IP("authme.admin.getip"),
/**
* Administrator command to teleport to the AuthMe spawn.
*/
- SPAWN("authme.admin.spawn", DefaultPermission.OP_ONLY),
+ SPAWN("authme.admin.spawn"),
/**
* Administrator command to set the AuthMe spawn.
*/
- SET_SPAWN("authme.admin.setspawn", DefaultPermission.OP_ONLY),
+ SET_SPAWN("authme.admin.setspawn"),
/**
* Administrator command to teleport to the first AuthMe spawn.
*/
- FIRST_SPAWN("authme.admin.firstspawn", DefaultPermission.OP_ONLY),
+ FIRST_SPAWN("authme.admin.firstspawn"),
/**
* Administrator command to set the first AuthMe spawn.
*/
- SET_FIRST_SPAWN("authme.admin.setfirstspawn", DefaultPermission.OP_ONLY),
+ SET_FIRST_SPAWN("authme.admin.setfirstspawn"),
/**
* Administrator command to purge old user data.
*/
- PURGE("authme.admin.purge", DefaultPermission.OP_ONLY),
+ PURGE("authme.admin.purge"),
/**
* Administrator command to purge the last position of a user.
*/
- PURGE_LAST_POSITION("authme.admin.purgelastpos", DefaultPermission.OP_ONLY),
+ PURGE_LAST_POSITION("authme.admin.purgelastpos"),
/**
* Administrator command to purge all data associated with banned players.
*/
- PURGE_BANNED_PLAYERS("authme.admin.purgebannedplayers", DefaultPermission.OP_ONLY),
+ PURGE_BANNED_PLAYERS("authme.admin.purgebannedplayers"),
/**
* Administrator command to toggle the AntiBot protection status.
*/
- SWITCH_ANTIBOT("authme.admin.switchantibot", DefaultPermission.OP_ONLY),
+ SWITCH_ANTIBOT("authme.admin.switchantibot"),
/**
* Administrator command to convert old or other data to AuthMe data.
*/
- CONVERTER("authme.admin.converter", DefaultPermission.OP_ONLY),
+ CONVERTER("authme.admin.converter"),
/**
* Administrator command to reload the plugin configuration.
*/
- RELOAD("authme.admin.reload", DefaultPermission.OP_ONLY),
+ RELOAD("authme.admin.reload"),
/**
* Permission to see Antibot messages.
*/
- ANTIBOT_MESSAGES("authme.admin.antibotmessages", DefaultPermission.OP_ONLY),
+ ANTIBOT_MESSAGES("authme.admin.antibotmessages"),
+
+ /**
+ * Permission to use the update messages command.
+ */
+ UPDATE_MESSAGES("authme.admin.updatemessages"),
/**
* Permission to see the other accounts of the players that log in.
*/
- SEE_OTHER_ACCOUNTS("authme.admin.seeotheraccounts", DefaultPermission.OP_ONLY);
+ SEE_OTHER_ACCOUNTS("authme.admin.seeotheraccounts");
/**
* The permission node.
*/
private String node;
- /**
- * The default permission level
- */
- private DefaultPermission defaultPermission;
-
/**
* Constructor.
*
* @param node Permission node.
*/
- AdminPermission(String node, DefaultPermission defaultPermission) {
+ AdminPermission(String node) {
this.node = node;
- this.defaultPermission = defaultPermission;
}
@Override
@@ -137,6 +136,6 @@ public enum AdminPermission implements PermissionNode {
@Override
public DefaultPermission getDefaultPermission() {
- return defaultPermission;
+ return DefaultPermission.OP_ONLY;
}
}
diff --git a/src/main/java/fr/xephi/authme/permission/PlayerPermission.java b/src/main/java/fr/xephi/authme/permission/PlayerPermission.java
index e2932e932..a42c9c9c8 100644
--- a/src/main/java/fr/xephi/authme/permission/PlayerPermission.java
+++ b/src/main/java/fr/xephi/authme/permission/PlayerPermission.java
@@ -8,76 +8,70 @@ public enum PlayerPermission implements PermissionNode {
/**
* Command permission to login.
*/
- LOGIN("authme.player.login", DefaultPermission.ALLOWED),
+ LOGIN("authme.player.login"),
/**
* Command permission to logout.
*/
- LOGOUT("authme.player.logout", DefaultPermission.ALLOWED),
+ LOGOUT("authme.player.logout"),
/**
* Command permission to register.
*/
- REGISTER("authme.player.register", DefaultPermission.ALLOWED),
+ REGISTER("authme.player.register"),
/**
* Command permission to unregister.
*/
- UNREGISTER("authme.player.unregister", DefaultPermission.ALLOWED),
+ UNREGISTER("authme.player.unregister"),
/**
* Command permission to change the password.
*/
- CHANGE_PASSWORD("authme.player.changepassword", DefaultPermission.ALLOWED),
+ CHANGE_PASSWORD("authme.player.changepassword"),
/**
* Command permission to add an email address.
*/
- ADD_EMAIL("authme.player.email.add", DefaultPermission.ALLOWED),
+ ADD_EMAIL("authme.player.email.add"),
/**
* Command permission to change the email address.
*/
- CHANGE_EMAIL("authme.player.email.change", DefaultPermission.ALLOWED),
+ CHANGE_EMAIL("authme.player.email.change"),
/**
- * Command permission to recover an account using it's email address.
+ * Command permission to recover an account using its email address.
*/
- RECOVER_EMAIL("authme.player.email.recover", DefaultPermission.ALLOWED),
+ RECOVER_EMAIL("authme.player.email.recover"),
/**
* Command permission to use captcha.
*/
- CAPTCHA("authme.player.captcha", DefaultPermission.ALLOWED),
+ CAPTCHA("authme.player.captcha"),
/**
* Permission for users a login can be forced to.
*/
- CAN_LOGIN_BE_FORCED("authme.player.canbeforced", DefaultPermission.ALLOWED),
+ CAN_LOGIN_BE_FORCED("authme.player.canbeforced"),
/**
* Permission to use to see own other accounts.
*/
- SEE_OWN_ACCOUNTS("authme.player.seeownaccounts", DefaultPermission.ALLOWED);
+ SEE_OWN_ACCOUNTS("authme.player.seeownaccounts");
/**
* The permission node.
*/
private String node;
- /**
- * The default permission level
- */
- private DefaultPermission defaultPermission;
-
/**
* Constructor.
*
* @param node Permission node.
*/
- PlayerPermission(String node, DefaultPermission defaultPermission) {
+ PlayerPermission(String node) {
this.node = node;
- this.defaultPermission = defaultPermission;
}
@Override
@@ -87,7 +81,7 @@ public enum PlayerPermission implements PermissionNode {
@Override
public DefaultPermission getDefaultPermission() {
- return defaultPermission;
+ return DefaultPermission.ALLOWED;
}
}
diff --git a/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java b/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java
index d733814eb..aaeb0eea3 100644
--- a/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java
+++ b/src/main/java/fr/xephi/authme/permission/PlayerStatePermission.java
@@ -17,7 +17,7 @@ public enum PlayerStatePermission implements PermissionNode {
BYPASS_FORCE_SURVIVAL("authme.bypassforcesurvival", DefaultPermission.OP_ONLY),
/**
- * Permission node to identify VIP users.
+ * When the server is full and someone with this permission joins the server, someone will be kicked.
*/
IS_VIP("authme.vip", DefaultPermission.OP_ONLY),
@@ -27,7 +27,7 @@ public enum PlayerStatePermission implements PermissionNode {
ALLOW_MULTIPLE_ACCOUNTS("authme.allowmultipleaccounts", DefaultPermission.OP_ONLY),
/**
- * Permission to bypass the purging process
+ * Permission to bypass the purging process.
*/
BYPASS_PURGE("authme.bypasspurge", DefaultPermission.NOT_ALLOWED);
@@ -44,7 +44,8 @@ public enum PlayerStatePermission implements PermissionNode {
/**
* Constructor.
*
- * @param node Permission node.
+ * @param node Permission node
+ * @param defaultPermission The default permission
*/
PlayerStatePermission(String node, DefaultPermission defaultPermission) {
this.node = node;
diff --git a/src/main/java/fr/xephi/authme/service/MessageUpdater.java b/src/main/java/fr/xephi/authme/service/MessageUpdater.java
new file mode 100644
index 000000000..129a47b81
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/service/MessageUpdater.java
@@ -0,0 +1,139 @@
+package fr.xephi.authme.service;
+
+import com.github.authme.configme.SettingsManager;
+import com.github.authme.configme.knownproperties.ConfigurationData;
+import com.github.authme.configme.properties.Property;
+import com.github.authme.configme.properties.StringProperty;
+import com.github.authme.configme.resource.YamlFileResource;
+import fr.xephi.authme.ConsoleLogger;
+import fr.xephi.authme.message.MessageKey;
+import fr.xephi.authme.util.FileUtils;
+import fr.xephi.authme.util.StringUtils;
+import org.bukkit.command.CommandSender;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.configuration.file.YamlConfiguration;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Updates a user's messages file with messages from the JAR files.
+ */
+public class MessageUpdater {
+
+ private final FileConfiguration userConfiguration;
+ private final FileConfiguration localJarConfiguration;
+ private final FileConfiguration defaultJarConfiguration;
+
+ private final List> properties;
+ private final SettingsManager settingsManager;
+ private boolean hasMissingMessages = false;
+
+ /**
+ * Constructor.
+ *
+ * @param userFile messages file in the data folder
+ * @param localJarFile path to messages file in JAR in local language
+ * @param defaultJarFile path to messages file in JAR for default language
+ * @throws Exception if userFile does not exist or no JAR messages file can be loaded
+ */
+ public MessageUpdater(File userFile, String localJarFile, String defaultJarFile) throws Exception {
+ if (!userFile.exists()) {
+ throw new Exception("Local messages file does not exist");
+ }
+
+ userConfiguration = YamlConfiguration.loadConfiguration(userFile);
+ localJarConfiguration = loadJarFileOrSendError(localJarFile);
+ defaultJarConfiguration = localJarFile.equals(defaultJarFile) ? null : loadJarFileOrSendError(defaultJarFile);
+ if (localJarConfiguration == null && defaultJarConfiguration == null) {
+ throw new Exception("Could not load any JAR messages file to copy from");
+ }
+
+ properties = buildPropertyEntriesForMessageKeys();
+ settingsManager = new SettingsManager(
+ new YamlFileResource(userFile), (r, p) -> true, new ConfigurationData((List) properties));
+ }
+
+ /**
+ * Copies missing messages to the messages file.
+ *
+ * @param sender sender starting the copy process
+ * @return true if the messages file was updated, false otherwise
+ * @throws Exception if an error occurs during saving
+ */
+ public boolean executeCopy(CommandSender sender) throws Exception {
+ copyMissingMessages();
+
+ if (!hasMissingMessages) {
+ sender.sendMessage("No new messages to add");
+ return false;
+ }
+
+ // Save user configuration file
+ try {
+ settingsManager.save();
+ sender.sendMessage("Message file updated with new messages");
+ return true;
+ } catch (Exception e) {
+ throw new Exception("Could not save to messages file: " + StringUtils.formatException(e));
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void copyMissingMessages() {
+ for (Property property : properties) {
+ String message = userConfiguration.getString(property.getPath());
+ if (message == null) {
+ hasMissingMessages = true;
+ message = getMessageFromJar(property.getPath());
+ }
+ settingsManager.setProperty(property, message);
+ }
+ }
+
+ private String getMessageFromJar(String key) {
+ String message = (localJarConfiguration == null ? null : localJarConfiguration.getString(key));
+ if (message != null) {
+ return message;
+ }
+ return (defaultJarConfiguration == null) ? null : defaultJarConfiguration.getString(key);
+ }
+
+ private static FileConfiguration loadJarFileOrSendError(String jarPath) {
+ try (InputStream stream = FileUtils.getResourceFromJar(jarPath)) {
+ if (stream == null) {
+ ConsoleLogger.info("Could not load '" + jarPath + "' from JAR");
+ return null;
+ }
+ InputStreamReader isr = new InputStreamReader(stream);
+ FileConfiguration configuration = YamlConfiguration.loadConfiguration(isr);
+ close(isr);
+ return configuration;
+ } catch (IOException e) {
+ ConsoleLogger.logException("Exception while handling JAR path '" + jarPath + "'", e);
+ }
+ return null;
+ }
+
+ private static List> buildPropertyEntriesForMessageKeys() {
+ return Arrays.stream(MessageKey.values())
+ .map(key -> new StringProperty(key.getKey(), ""))
+ .collect(Collectors.toList());
+ }
+
+ private static void close(Closeable closeable) {
+ if (closeable != null) {
+ try {
+ closeable.close();
+ } catch (IOException e) {
+ ConsoleLogger.info("Cannot close '" + closeable + "': " + StringUtils.formatException(e));
+ }
+ }
+ }
+}
diff --git a/src/main/java/fr/xephi/authme/settings/properties/DatabaseSettings.java b/src/main/java/fr/xephi/authme/settings/properties/DatabaseSettings.java
index 2dc769ec6..c82a7a81d 100644
--- a/src/main/java/fr/xephi/authme/settings/properties/DatabaseSettings.java
+++ b/src/main/java/fr/xephi/authme/settings/properties/DatabaseSettings.java
@@ -98,6 +98,10 @@ public class DatabaseSettings implements SettingsHolder {
public static final Property MYSQL_COL_GROUP =
newProperty("ExternalBoardOptions.mySQLColumnGroup", "");
+ @Comment("Overrides the size of the DB Connection Pool, -1 = Auto")
+ public static final Property MYSQL_POOL_SIZE =
+ newProperty("DataSource.poolSize", -1);
+
private DatabaseSettings() {
}
diff --git a/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java b/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java
index bfb565337..094a3d5b9 100644
--- a/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java
+++ b/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java
@@ -36,7 +36,10 @@ public class PluginSettings implements SettingsHolder {
public static final Property SESSIONS_EXPIRE_ON_IP_CHANGE =
newProperty("settings.sessions.sessionExpireOnIpChange", true);
- @Comment("Message language, available: en, de, br, cz, pl, fr, ru, hu, sk, es, zhtw, fi, zhcn, lt, it, ko, pt")
+ @Comment({
+ "Message language, available languages:",
+ "https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/translations.md"
+ })
public static final Property MESSAGES_LANGUAGE =
newProperty("settings.messagesLanguage", "en");
@@ -65,8 +68,8 @@ public class PluginSettings implements SettingsHolder {
newProperty(LogLevel.class, "settings.logLevel", LogLevel.FINE);
@Comment({
- "By default we schedule async tasks when talking to the database",
- "If you want typical communication with the database to happen synchronously, set this to false"
+ "By default we schedule async tasks when talking to the database. If you want",
+ "typical communication with the database to happen synchronously, set this to false"
})
public static final Property USE_ASYNC_TASKS =
newProperty("settings.useAsyncTasks", true);
diff --git a/src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java b/src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java
index cdd760bd2..b725172f0 100644
--- a/src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java
+++ b/src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java
@@ -20,13 +20,16 @@ public class ProtectionSettings implements SettingsHolder {
public static final Property ENABLE_PROTECTION_REGISTERED =
newProperty("Protection.enableProtectionRegistered", true);
- @Comment({"Countries allowed to join the server and register, see http://dev.bukkit.org/bukkit-plugins/authme-reloaded/pages/countries-codes/ for countries' codes",
- "PLEASE USE QUOTES!"})
+ @Comment({
+ "Countries allowed to join the server and register. For country codes, see",
+ "http://dev.bukkit.org/bukkit-plugins/authme-reloaded/pages/countries-codes/",
+ "PLEASE USE QUOTES!"})
public static final Property> COUNTRIES_WHITELIST =
newListProperty("Protection.countries", "US", "GB");
- @Comment({"Countries not allowed to join the server and register",
- "PLEASE USE QUOTES!"})
+ @Comment({
+ "Countries not allowed to join the server and register",
+ "PLEASE USE QUOTES!"})
public static final Property> COUNTRIES_BLACKLIST =
newListProperty("Protection.countriesBlacklist", "A1");
@@ -34,7 +37,13 @@ public class ProtectionSettings implements SettingsHolder {
public static final Property ENABLE_ANTIBOT =
newProperty("Protection.enableAntiBot", true);
- @Comment("Max number of players allowed to login in 5 secs before the AntiBot system is enabled automatically")
+ @Comment("The interval in seconds")
+ public static final Property ANTIBOT_INTERVAL =
+ newProperty("Protection.antiBotInterval", 5);
+
+ @Comment({
+ "Max number of players allowed to login in the interval",
+ "before the AntiBot system is enabled automatically"})
public static final Property ANTIBOT_SENSIBILITY =
newProperty("Protection.antiBotSensibility", 10);
diff --git a/src/main/java/fr/xephi/authme/settings/properties/PurgeSettings.java b/src/main/java/fr/xephi/authme/settings/properties/PurgeSettings.java
index f23a3eb12..b3733b5ac 100644
--- a/src/main/java/fr/xephi/authme/settings/properties/PurgeSettings.java
+++ b/src/main/java/fr/xephi/authme/settings/properties/PurgeSettings.java
@@ -12,7 +12,7 @@ public class PurgeSettings implements SettingsHolder {
public static final Property USE_AUTO_PURGE =
newProperty("Purge.useAutoPurge", false);
- @Comment("Number of Days an account become Unused")
+ @Comment("Number of days after which an account should be purged")
public static final Property DAYS_BEFORE_REMOVE_PLAYER =
newProperty("Purge.daysBeforeRemovePlayer", 60);
@@ -28,7 +28,7 @@ public class PurgeSettings implements SettingsHolder {
public static final Property DEFAULT_WORLD =
newProperty("Purge.defaultWorld", "world");
- @Comment("Do we need to remove LimitedCreative/inventories/player.yml, player_creative.yml files during purge process ?")
+ @Comment("Remove LimitedCreative/inventories/player.yml, player_creative.yml files during purge?")
public static final Property REMOVE_LIMITED_CREATIVE_INVENTORIES =
newProperty("Purge.removeLimitedCreativesInventories", false);
diff --git a/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java b/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java
index b593869a3..487039ba7 100644
--- a/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java
+++ b/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java
@@ -52,8 +52,9 @@ public class RegistrationSettings implements SettingsHolder {
public static final Property> FORCE_COMMANDS =
newListProperty("settings.forceCommands");
- @Comment("Force these commands after /login as service console, without any '/'. "
- + "Use %p to replace with player name")
+ @Comment({
+ "Force these commands after /login as service console, without any '/'.",
+ "Use %p to replace with player name"})
public static final Property> FORCE_COMMANDS_AS_CONSOLE =
newListProperty("settings.forceCommandsAsConsole");
@@ -61,22 +62,25 @@ public class RegistrationSettings implements SettingsHolder {
public static final Property> FORCE_REGISTER_COMMANDS =
newListProperty("settings.forceRegisterCommands");
- @Comment("Force these commands after /register as a server console, without any '/'. "
- + "Use %p to replace with player name")
+ @Comment({
+ "Force these commands after /register as a server console, without any '/'.",
+ "Use %p to replace with player name"})
public static final Property> FORCE_REGISTER_COMMANDS_AS_CONSOLE =
newListProperty("settings.forceRegisterCommandsAsConsole");
@Comment({
"Enable to display the welcome message (welcome.txt) after a login",
"You can use colors in this welcome.txt + some replaced strings:",
- "{PLAYER}: player name, {ONLINE}: display number of online players, {MAXPLAYERS}: display server slots,",
- "{IP}: player ip, {LOGINS}: number of players logged, {WORLD}: player current world, {SERVER}: server name",
+ "{PLAYER}: player name, {ONLINE}: display number of online players,",
+ "{MAXPLAYERS}: display server slots, {IP}: player ip, {LOGINS}: number of players logged,",
+ "{WORLD}: player current world, {SERVER}: server name",
"{VERSION}: get current bukkit version, {COUNTRY}: player country"})
public static final Property USE_WELCOME_MESSAGE =
newProperty("settings.useWelcomeMessage", true);
- @Comment("Do we need to broadcast the welcome message to all server or only to the player? set true for "
- + "server or false for player")
+ @Comment({
+ "Broadcast the welcome message to the server or only to the player?",
+ "set true for server or false for player"})
public static final Property BROADCAST_WELCOME_MESSAGE =
newProperty("settings.broadcastWelcomeMessage", false);
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 9e16714dd..c05efa4b5 100644
--- a/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java
+++ b/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java
@@ -36,7 +36,7 @@ public class RestrictionSettings implements SettingsHolder {
@Comment("Minimum allowed username length")
public static final Property MIN_NICKNAME_LENGTH =
- newProperty("settings.restrictions.minNicknameLength", 4);
+ newProperty("settings.restrictions.minNicknameLength", 3);
@Comment("Maximum allowed username length")
public static final Property MAX_NICKNAME_LENGTH =
@@ -50,9 +50,9 @@ public class RestrictionSettings implements SettingsHolder {
newProperty("settings.restrictions.ForceSingleSession", true);
@Comment({
- "If enabled, every player that spawn in one of the world listed in \"ForceSpawnLocOnJoin.worlds\"",
- "will be teleported to the spawnpoint after successful authentication.",
- "The quit location of the player will be overwritten.",
+ "If enabled, every player that spawn in one of the world listed in",
+ "\"ForceSpawnLocOnJoin.worlds\" will be teleported to the spawnpoint after successful",
+ "authentication. The quit location of the player will be overwritten.",
"This is different from \"teleportUnAuthedToSpawn\" that teleport player",
"to the spawnpoint on join."})
public static final Property FORCE_SPAWN_LOCATION_AFTER_LOGIN =
diff --git a/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java b/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java
index 7d91f8183..92ce2e5ec 100644
--- a/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java
+++ b/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java
@@ -18,10 +18,6 @@ public class SecuritySettings implements SettingsHolder {
public static final Property STOP_SERVER_ON_PROBLEM =
newProperty("Security.SQLProblem.stopServer", true);
- @Comment("/reload support")
- public static final Property USE_RELOAD_COMMAND_SUPPORT =
- newProperty("Security.ReloadCommand.useReloadCommandSupport", true);
-
@Comment("Remove passwords from console?")
public static final Property REMOVE_PASSWORD_FROM_CONSOLE =
newProperty("Security.console.removePassword", true);
@@ -85,11 +81,13 @@ public class SecuritySettings implements SettingsHolder {
newProperty("settings.security.supportOldPasswordHash", false);
@Comment({"Prevent unsafe passwords from being used; put them in lowercase!",
+ "You should always set 'help' as unsafePassword due to possible conflicts.",
"unsafePasswords:",
"- '123456'",
- "- 'password'"})
+ "- 'password'",
+ "- 'help'"})
public static final Property> UNSAFE_PASSWORDS =
- newLowercaseListProperty("settings.security.unsafePasswords", "123456", "password", "qwerty", "12345", "54321", "123456789");
+ newLowercaseListProperty("settings.security.unsafePasswords", "123456", "password", "qwerty", "12345", "54321", "123456789", "help");
@Comment("Tempban a user's IP address if they enter the wrong password too many times")
public static final Property TEMPBAN_ON_MAX_LOGINS =
diff --git a/src/main/java/fr/xephi/authme/util/FileUtils.java b/src/main/java/fr/xephi/authme/util/FileUtils.java
index 831beafd6..86c8cae46 100644
--- a/src/main/java/fr/xephi/authme/util/FileUtils.java
+++ b/src/main/java/fr/xephi/authme/util/FileUtils.java
@@ -23,7 +23,7 @@ public final class FileUtils {
* Copy a resource file (from the JAR) to the given file if it doesn't exist.
*
* @param destinationFile The file to check and copy to (outside of JAR)
- * @param resourcePath Absolute path to the resource file (path to file within JAR)
+ * @param resourcePath Local path to the resource file (path to file within JAR)
*
* @return False if the file does not exist and could not be copied, true otherwise
*/
@@ -35,9 +35,7 @@ public final class FileUtils {
return false;
}
- // ClassLoader#getResourceAsStream does not deal with the '\' path separator: replace to '/'
- final String normalizedPath = resourcePath.replace("\\", "/");
- try (InputStream is = AuthMe.class.getClassLoader().getResourceAsStream(normalizedPath)) {
+ try (InputStream is = getResourceFromJar(resourcePath)) {
if (is == null) {
ConsoleLogger.warning(format("Cannot copy resource '%s' to file '%s': cannot load resource",
resourcePath, destinationFile.getPath()));
@@ -52,6 +50,18 @@ public final class FileUtils {
return false;
}
+ /**
+ * Returns a JAR file as stream. Returns null if it doesn't exist.
+ *
+ * @param path the local path (starting from resources project, e.g. "config.yml" for 'resources/config.yml')
+ * @return the stream if the file exists, or false otherwise
+ */
+ public static InputStream getResourceFromJar(String path) {
+ // ClassLoader#getResourceAsStream does not deal with the '\' path separator: replace to '/'
+ final String normalizedPath = path.replace("\\", "/");
+ return AuthMe.class.getClassLoader().getResourceAsStream(normalizedPath);
+ }
+
/**
* Delete a given directory and all its content.
*
diff --git a/src/main/resources/messages/help_br.yml b/src/main/resources/messages/help_br.yml
new file mode 100644
index 000000000..90fc6cc04
--- /dev/null
+++ b/src/main/resources/messages/help_br.yml
@@ -0,0 +1,44 @@
+# Translation config for the AuthMe help, e.g. when /authme help or /authme help register is called
+
+# -------------------------------------------------------
+# List of texts used in the help section
+common:
+ optional: 'Opcional'
+ hasPermission: 'Você tem permissão'
+ noPermission: 'Sem Permissão'
+ default: 'Default'
+ result: 'Resultado'
+ defaultPermissions:
+ notAllowed: 'Sem Permissão'
+ opOnly: 'OP''s only'
+ allowed: 'Todos podem'
+
+# -------------------------------------------------------
+# Titles of the individual help sections
+# Set the translation text to empty text to disable the section, e.g. to hide alternatives:
+# alternatives: ''
+section:
+ command: 'Comando'
+ description: 'Pequena descrição'
+ detailedDescription: 'Descrição detalhada'
+ arguments: 'Argumentos'
+ permissions: 'Permissões'
+ alternatives: 'Alternativas'
+ children: 'Comandos'
+
+# -------------------------------------------------------
+# You can translate the data for all commands using the below pattern.
+# For example to translate /authme reload, create a section "authme.reload", or "login" for /login
+# If the command has arguments, you can use arg1 as below to translate the first argument, and so forth
+# Translations don't need to be complete; any missing section will be taken from the default silently
+# Important: Put main commands like "authme" before their children (e.g. "authme.reload")
+commands:
+ authme.register:
+ description: 'Registra um jogador'
+ detailedDescription: 'Registra um esprecifico jogador com uma senha especifica.'
+ arg1:
+ label: 'player'
+ description: 'Nome do player'
+ arg2:
+ label: 'password'
+ description: 'Senha'
diff --git a/src/main/resources/messages/help_it.yml b/src/main/resources/messages/help_it.yml
new file mode 100644
index 000000000..b69f85153
--- /dev/null
+++ b/src/main/resources/messages/help_it.yml
@@ -0,0 +1,154 @@
+# Lingua Italiana creata da Maxetto e sgdc3.
+# Translation config for the AuthMe help, e.g. when /authme help or /authme help register is called
+
+# -------------------------------------------------------
+# List of texts used in the help section
+common:
+ header: '==========[ Assistenza AuthMeReloaded ]=========='
+ optional: 'Opzionale'
+ hasPermission: 'Hai il permesso'
+ noPermission: 'Non hai il permesso'
+ default: 'Configurazione base'
+ result: 'Risultato'
+ defaultPermissions:
+ notAllowed: 'Nessuno autorizzato'
+ opOnly: 'Solo per OP'
+ allowed: 'Tutti autorizzati'
+
+# -------------------------------------------------------
+# Titles of the individual help sections
+# Set the translation text to empty text to disable the section, e.g. to hide alternatives:
+# alternatives: ''
+section:
+ command: 'Comando'
+ description: 'Descrizione breve'
+ detailedDescription: 'Descrizione dettagliata'
+ arguments: 'Parametri'
+ permissions: 'Permessi'
+ alternatives: 'Alternative'
+ children: 'Comandi'
+
+# -------------------------------------------------------
+# You can translate the data for all commands using the below pattern.
+# For example to translate /authme reload, create a section "authme.reload", or "login" for /login
+# If the command has arguments, you can use arg1 as below to translate the first argument, and so forth
+# Translations don't need to be complete; any missing section will be taken from the default silently
+# Important: Put main commands like "authme" before their children (e.g. "authme.reload")
+commands:
+ authme.register:
+ description: 'Registra un giocatore'
+ detailedDescription: 'Registra il giocatore indicato con la password inserita.'
+ arg1:
+ label: 'giocatore'
+ description: 'Nome del giocatore'
+ arg2:
+ label: 'password'
+ description: 'Password'
+ authme.unregister:
+ description: 'Rimuovi un giocatore'
+ detailedDescription: 'Rimuovi il giocatore indicato dal Database.'
+ arg1:
+ label: 'giocatore'
+ description: 'Nome del giocatore'
+ authme.forcelogin:
+ description: 'Forza l''autenticazione ad un giocatore'
+ detailedDescription: 'Autentica il giocatore indicato.'
+ arg1:
+ label: 'giocatore'
+ description: 'Nome del giocatore connesso'
+ authme.password:
+ description: 'Cambia la password di un giocatore'
+ detailedDescription: 'Cambia la password del giocatore indicato.'
+ arg1:
+ label: 'giocatore'
+ description: 'Nome del giocatore'
+ arg2:
+ label: 'password'
+ description: 'Nuova Password'
+ authme.lastlogin:
+ description: 'Ultima autenticazione di un giocatore'
+ detailedDescription: 'Visualizza l''ultima data di autenticazione del giocatore indicato.'
+ arg1:
+ label: 'giocatore'
+ description: 'Nome del giocatore'
+ authme.accounts:
+ description: 'Mostra i profili di un giocatore'
+ detailedDescription: 'Mostra tutti i profili di un giocatore attraverso il nome o l''indirizzo IP.'
+ arg1:
+ label: 'giocatore'
+ description: 'Nome o indirizzo IP del giocatore'
+ authme.email:
+ description: 'Mostra l''indirizzo email di un giocatore'
+ detailedDescription: 'Mostra l''indirizzo email del giocatore indicato se impostato.'
+ arg1:
+ label: 'giocatore'
+ description: 'Nome del giocatore'
+ authme.setemail:
+ description: 'Cambia l''indirizzo email di un giocatore'
+ detailedDescription: 'Cambia l''indirizzo email del giocatore indicato.'
+ arg1:
+ label: 'giocatore'
+ description: 'Nome del giocatore'
+ arg2:
+ label: 'email'
+ description: 'Indirizzo email del giocatore'
+ authme.getip:
+ description: 'Mostra l''indirizzo IP di un giocatore'
+ detailedDescription: 'Mostra l''indirizzo IP del giocatore indicato.'
+ arg1:
+ label: 'giocatore'
+ description: 'Nome del giocatore connesso'
+ authme.spawn:
+ description: 'Teletrasportati al punto di rigenerazione'
+ detailedDescription: 'Teletrasportati al punto di rigenerazione.'
+ authme.setspawn:
+ description: 'Cambia il punto di rigenerazione'
+ detailedDescription: 'Cambia il punto di rigenerazione dei giocatori alla tua posizione.'
+ authme.firstspawn:
+ description: 'Teletrasportati al punto di rigenerazione iniziale'
+ detailedDescription: 'Teletrasportati al punto di rigenerazione iniziale.'
+ authme.setfirstspawn:
+ description: 'Cambia il punto di rigenerazione iniziale'
+ detailedDescription: 'Cambia il punto di rigenerazione iniziale dei giocatori alla tua posizione.'
+ authme.purge:
+ description: 'Elimina i vecchi dati'
+ detailedDescription: 'Elimina i dati di AuthMeReloaded più vecchi dei giorni indicati.'
+ arg1:
+ label: 'giorni'
+ description: 'Numero di giorni'
+ arg2:
+ label: 'all'
+ description: 'Aggiungi ''all'' alla fine per eliminare anche i giocatori con l''ultima autenticazione pari a 0'
+ authme.resetpos:
+ description: 'Elimina l''ultima posizione di un giocatore'
+ detailedDescription: 'Elimina l''ultima posizione conosciuta del giocatore indicato o di tutti i giocatori.'
+ arg1:
+ label: 'giocatore/*'
+ description: 'Nome del giocatore o ''*'' per tutti i giocatori'
+ authme.purgebannedplayers:
+ description: 'Elimina i dati dei giocatori banditi'
+ detailedDescription: 'Elimina tutti i dati di AuthMeReloaded dei giocatori banditi.'
+ authme.switchantibot:
+ description: 'Cambia lo stato del servizio di AntiBot'
+ detailedDescription: 'Cambia lo stato del servizio di AntiBot allo stato indicato.'
+ arg1:
+ label: 'stato'
+ description: 'ON / OFF'
+ authme.reload:
+ description: 'Ricarica il plugin'
+ detailedDescription: 'Ricarica il plugin AuthMeReloaded.'
+ authme.version:
+ description: 'Informazioni sulla versione'
+ detailedDescription: 'Mostra informazioni dettagliate riguardo la versione di AuthMeReloaded in uso, gli sviluppatori, i collaboratori e la licenza.'
+ authme.converter:
+ description: 'Comando per il convertitore'
+ detailedDescription: 'Comando per il convertitore di AuthMeReloaded.'
+ arg1:
+ label: 'incarico'
+ description: 'Incarico di conversione: xauth / crazylogin / rakamak / royalauth / vauth / sqliteToSql / mysqlToSqlite'
+ authme.help:
+ description: 'Visualizza l''assistenza'
+ detailedDescription: 'Visualizza informazioni dettagliate per i comandi ''/authme''.'
+ arg1:
+ label: 'comando'
+ description: 'Il comando di cui vuoi ricevere assistenza'
diff --git a/src/main/resources/messages/messages_br.yml b/src/main/resources/messages/messages_br.yml
index 8002a7a1a..8181658cd 100644
--- a/src/main/resources/messages/messages_br.yml
+++ b/src/main/resources/messages/messages_br.yml
@@ -61,6 +61,8 @@ email_confirm: '&cPor favor confirme seu endereço de email!'
email_changed: '&2Troca de email com sucesso.!'
email_send: '&2Recuperação de email enviada com sucesso! Por favor, verifique sua caixa de entrada de e-mail!'
email_exists: '&cUm e-mail de recuperação já foi enviado! Você pode descartá-lo e enviar um novo usando o comando abaixo:'
+email_show: '&2O seu endereço de e-mail atual é: &f%email'
+show_no_email: '&2Você atualmente não têm endereço de e-mail associado a esta conta.'
country_banned: '&4O seu país está banido neste servidor!'
antibot_auto_enabled: '&4[AntiBotService] habilitado devido ao enorme número de conexões!'
antibot_auto_disabled: '&2[AntiBotService] AntiBot desativada após %m minutos!'
@@ -75,5 +77,3 @@ kicked_admin_registered: 'Um administrador registrou você; por favor faça logi
incomplete_email_settings: 'Erro: Nem todas as configurações necessárias estão definidas para o envio de e-mails. Entre em contato com um administrador.'
recovery_code_sent: 'Um código de recuperação para redefinir sua senha foi enviada para o seu e-mail.'
recovery_code_incorrect: 'O código de recuperação esta incorreto! Use /email recovery [email] para gerar um novo!'
-# TODO email_show: '&2Your current email address is: &f%email'
-# TODO show_no_email: '&2You currently don''t have email address associated with this account.'
\ No newline at end of file
diff --git a/src/main/resources/messages/messages_hu.yml b/src/main/resources/messages/messages_hu.yml
index 88142bbce..daabe5734 100644
--- a/src/main/resources/messages/messages_hu.yml
+++ b/src/main/resources/messages/messages_hu.yml
@@ -72,5 +72,5 @@ kicked_admin_registered: 'Adminisztrátor által regisztrálva lettél; kérlek
accounts_owned_self: '%count db regisztrációd van:'
recovery_code_incorrect: 'A visszaállító kód helytelen volt! Használd a következő parancsot: /email recovery [email címed] egy új generálásához'
recovery_code_sent: 'A jelszavad visszaállításához szükséges kódot sikeresen kiküldtük az email címedre!'
-# TODO email_show: '&2Your current email address is: &f%email'
-# TODO show_no_email: '&2You currently don''t have email address associated with this account.'
\ No newline at end of file
+email_show: '&2A jelenlegi email-ed a következő: &f%email'
+show_no_email: '&2Ehhez a felhasználóhoz jelenleg még nincs email hozzárendelve.'
diff --git a/src/main/resources/messages/messages_it.yml b/src/main/resources/messages/messages_it.yml
index 3c0aaed2a..d257c7465 100644
--- a/src/main/resources/messages/messages_it.yml
+++ b/src/main/resources/messages/messages_it.yml
@@ -69,9 +69,9 @@ invalid_name_case: 'Dovresti entrare con questo nome utente: "%valid", al posto
tempban_max_logins: '&cSei stato temporaneamente bandito per aver fallito l''autenticazione troppe volte.'
accounts_owned_self: 'Possiedi %count account:'
accounts_owned_other: 'Il giocatore %name possiede %count account:'
-kicked_admin_registered: 'Un amministratore ti ha appena registrato; per favore rientra nel server'
+kicked_admin_registered: 'Un amministratore ti ha appena registrato, per favore rientra nel server'
incomplete_email_settings: 'Errore: non tutte le impostazioni richieste per inviare le email sono state impostate. Per favore contatta un amministratore.'
recovery_code_incorrect: 'Il codice di recupero inserito non è corretto! Scrivi /email recovery per generarne uno nuovo'
recovery_code_sent: 'Una email contenente il codice di recupero per reimpostare la tua password è stata appena inviata al tuo indirizzo email.'
-# TODO email_show: '&2Your current email address is: &f%email'
-# TODO show_no_email: '&2You currently don''t have email address associated with this account.'
\ No newline at end of file
+email_show: '&2Il tuo indirizzo email al momento è: &f%email'
+show_no_email: '&2Al momento non hai nessun indirizzo email associato al tuo account.'
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index 2b950e3a7..9ca68c314 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -15,186 +15,197 @@ softdepend:
- EssentialsSpawn
- ProtocolLib
commands:
- authme:
- description: AuthMe op commands
- usage: '/authme reload|register playername password|changepassword playername password|unregister playername|version|converter'
- register:
- description: Register an account
- usage: /register
- aliases: [reg]
- login:
- description: Login command
- usage: /login
- aliases: [l,log]
- changepassword:
- description: Change password of an account
- usage: /changepassword
- aliases: [cp,changepass]
- logout:
- description: Logout
- usage: /logout
- unregister:
- description: Unregister your account
- usage: /unregister
- aliases: [unreg]
- email:
- description: Add Email or recover password
- usage: '/email add your@email.com your@email.com|change oldEmail newEmail|recovery your@email.com'
- captcha:
- description: Captcha command
- usage: /captcha
+ authme:
+ description: AuthMe op commands
+ usage: /authme register|unregister|forcelogin|password|lastlogin|accounts|email|setemail|getip|spawn|setspawn|firstspawn|setfirstspawn|purge|resetpos|purgebannedplayers|switchantibot|reload|version|converter|messages
+ login:
+ description: Login command
+ usage: /login
+ aliases:
+ - l
+ - log
+ logout:
+ description: Logout command
+ usage: /logout
+ register:
+ description: Register an account
+ usage: /register [password] [verifyPassword]
+ aliases:
+ - reg
+ unregister:
+ description: Unregister an account
+ usage: /unregister
+ aliases:
+ - unreg
+ changepassword:
+ description: Change password of an account
+ usage: /changepassword
+ aliases:
+ - changepass
+ - cp
+ email:
+ description: Add email or recover password
+ usage: /email show|add|change|recover
+ captcha:
+ description: Captcha Command
+ usage: /captcha
permissions:
- authme.admin.*:
- description: Give access to all admin commands.
- children:
- authme.admin.accounts: true
- authme.admin.changemail: true
- authme.admin.changepassword: true
- authme.admin.converter: true
- authme.admin.firstspawn: true
- authme.admin.forcelogin: true
- authme.admin.getemail: true
- authme.admin.getip: true
- authme.admin.lastlogin: true
- authme.admin.purge: true
- authme.admin.purgebannedplayers: true
- authme.admin.purgelastpos: true
- authme.admin.register: true
- authme.admin.reload: true
- authme.admin.setfirstspawn: true
- authme.admin.setspawn: true
- authme.admin.spawn: true
- authme.admin.switchantibot: true
- authme.admin.unregister: true
- authme.admin.register:
- description: Administrator command to register a new user.
- default: op
- authme.admin.unregister:
- description: Administrator command to unregister an existing user.
- default: op
- authme.admin.forcelogin:
- description: Administrator command to force-login an existing user.
- default: op
- authme.admin.changepassword:
- description: Administrator command to change the password of a user.
- default: op
- authme.admin.lastlogin:
- description: Administrator command to see the last login date and time of a user.
- default: op
- authme.admin.accounts:
- description: Administrator command to see all accounts associated with a user.
- default: op
- authme.admin.getemail:
- description: Administrator command to get the email address of a user, if set.
- default: op
- authme.admin.changemail:
- description: Administrator command to set or change the email address of a user.
- default: op
- authme.admin.getip:
- description: Administrator command to get the last known IP of a user.
- default: op
- authme.admin.spawn:
- description: Administrator command to teleport to the AuthMe spawn.
- default: op
- authme.admin.setspawn:
- description: Administrator command to set the AuthMe spawn.
- default: op
- authme.admin.firstspawn:
- description: Administrator command to teleport to the first AuthMe spawn.
- default: op
- authme.admin.setfirstspawn:
- description: Administrator command to set the first AuthMe spawn.
- default: op
- authme.admin.purge:
- description: Administrator command to purge old user data.
- default: op
- authme.admin.purgelastpos:
- description: Administrator command to purge the last position of a user.
- default: op
- authme.admin.purgebannedplayers:
- description: Administrator command to purge all data associated with banned players.
- default: op
- authme.admin.seeotheraccounts:
- description: Permission for user to see other accounts.
- default: op
- authme.admin.switchantibot:
- description: Administrator command to toggle the AntiBot protection status.
- default: op
- authme.admin.converter:
- description: Administrator command to convert old or other data to AuthMe data.
- default: op
- authme.admin.reload:
- description: Administrator command to reload the plugin configuration.
- default: op
- authme.admin.antibotmessages:
- description: Permission to see Antibot messages
- default: op
- authme.player.*:
- description: Permission to use all player (non-admin) commands.
- children:
- authme.player.canbeforced: true
- authme.player.captcha: true
- authme.player.changepassword: true
- authme.player.email.add: true
- authme.player.email.change: true
- authme.player.email.recover: true
- authme.player.login: true
- authme.player.logout: true
- authme.player.register: true
- authme.player.unregister: true
- authme.player.seeownaccounts: true
- authme.player.email:
- description: Gives access to player email commands
- default: false
- children:
- authme.player.email.add: true
- authme.player.email.change: true
- authme.player.email.recover: true
- authme.player.login:
- description: Command permission to login.
- default: true
- authme.player.logout:
- description: Command permission to logout.
- default: true
- authme.player.register:
- description: Command permission to register.
- default: true
- authme.player.unregister:
- description: Command permission to unregister.
- default: true
- authme.player.changepassword:
- description: Command permission to change the password.
- default: true
- authme.player.email.add:
- description: Command permission to add an email address.
- default: true
- authme.player.email.change:
- description: Command permission to change the email address.
- default: true
- authme.player.email.recover:
- description: Command permission to recover an account using its email address.
- default: true
- authme.player.captcha:
- description: Command permission to use captcha.
- default: true
- authme.player.canbeforced:
- description: Permission for users a login can be forced to.
- default: true
- authme.player.seeownaccounts:
- description: Permission to use to see own other accounts.
- default: true
- authme.vip:
- description: Allow vip slot when the server is full
- default: op
- authme.bypassantibot:
- description: Bypass the AntiBot check
- default: op
- authme.allowmultipleaccounts:
- description: Allow more accounts for same ip
- default: op
- authme.bypassforcesurvival:
- description: Bypass all ForceSurvival features
- default: op
- authme.bypasspurge:
- description: Permission to bypass the purging process
- default: false
+ authme.admin.*:
+ description: Gives access to all admin commands
+ children:
+ authme.admin.accounts: true
+ authme.admin.antibotmessages: true
+ authme.admin.changemail: true
+ authme.admin.changepassword: true
+ authme.admin.converter: true
+ authme.admin.firstspawn: true
+ authme.admin.forcelogin: true
+ authme.admin.getemail: true
+ authme.admin.getip: true
+ authme.admin.lastlogin: true
+ authme.admin.purge: true
+ authme.admin.purgebannedplayers: true
+ authme.admin.purgelastpos: true
+ authme.admin.register: true
+ authme.admin.reload: true
+ authme.admin.seeotheraccounts: true
+ authme.admin.setfirstspawn: true
+ authme.admin.setspawn: true
+ authme.admin.spawn: true
+ authme.admin.switchantibot: true
+ authme.admin.unregister: true
+ authme.admin.updatemessages: true
+ authme.admin.accounts:
+ description: Administrator command to see all accounts associated with a user.
+ default: op
+ authme.admin.antibotmessages:
+ description: Permission to see Antibot messages.
+ default: op
+ authme.admin.changemail:
+ description: Administrator command to set or change the email address of a user.
+ default: op
+ authme.admin.changepassword:
+ description: Administrator command to change the password of a user.
+ default: op
+ authme.admin.converter:
+ description: Administrator command to convert old or other data to AuthMe data.
+ default: op
+ authme.admin.firstspawn:
+ description: Administrator command to teleport to the first AuthMe spawn.
+ default: op
+ authme.admin.forcelogin:
+ description: Administrator command to force-login an existing user.
+ default: op
+ authme.admin.getemail:
+ description: Administrator command to get the email address of a user, if set.
+ default: op
+ authme.admin.getip:
+ description: Administrator command to get the last known IP of a user.
+ default: op
+ authme.admin.lastlogin:
+ description: Administrator command to see the last login date and time of a user.
+ default: op
+ authme.admin.purge:
+ description: Administrator command to purge old user data.
+ default: op
+ authme.admin.purgebannedplayers:
+ description: Administrator command to purge all data associated with banned players.
+ default: op
+ authme.admin.purgelastpos:
+ description: Administrator command to purge the last position of a user.
+ default: op
+ authme.admin.register:
+ description: Administrator command to register a new user.
+ default: op
+ authme.admin.reload:
+ description: Administrator command to reload the plugin configuration.
+ default: op
+ authme.admin.seeotheraccounts:
+ description: Permission to see the other accounts of the players that log in.
+ default: op
+ authme.admin.setfirstspawn:
+ description: Administrator command to set the first AuthMe spawn.
+ default: op
+ authme.admin.setspawn:
+ description: Administrator command to set the AuthMe spawn.
+ default: op
+ authme.admin.spawn:
+ description: Administrator command to teleport to the AuthMe spawn.
+ default: op
+ authme.admin.switchantibot:
+ description: Administrator command to toggle the AntiBot protection status.
+ default: op
+ authme.admin.unregister:
+ description: Administrator command to unregister an existing user.
+ default: op
+ authme.admin.updatemessages:
+ description: Permission to use the update messages command.
+ default: op
+ authme.allowmultipleaccounts:
+ description: Permission to be able to register multiple accounts.
+ default: op
+ authme.bypassantibot:
+ description: Permission node to bypass AntiBot protection.
+ default: op
+ authme.bypassforcesurvival:
+ description: Permission for users to bypass force-survival mode.
+ default: op
+ authme.bypasspurge:
+ description: Permission to bypass the purging process.
+ default: false
+ authme.player.*:
+ description: Gives access to all player commands
+ children:
+ authme.player.canbeforced: true
+ authme.player.captcha: true
+ authme.player.changepassword: true
+ authme.player.email.add: true
+ authme.player.email.change: true
+ authme.player.email.recover: true
+ authme.player.login: true
+ authme.player.logout: true
+ authme.player.register: true
+ authme.player.seeownaccounts: true
+ authme.player.unregister: true
+ authme.player.canbeforced:
+ description: Permission for users a login can be forced to.
+ default: true
+ authme.player.captcha:
+ description: Command permission to use captcha.
+ default: true
+ authme.player.changepassword:
+ description: Command permission to change the password.
+ default: true
+ authme.player.email:
+ description: Gives access to all email commands
+ children:
+ authme.player.email.add: true
+ authme.player.email.change: true
+ authme.player.email.recover: true
+ authme.player.email.add:
+ description: Command permission to add an email address.
+ default: true
+ authme.player.email.change:
+ description: Command permission to change the email address.
+ default: true
+ authme.player.email.recover:
+ description: Command permission to recover an account using its email address.
+ default: true
+ authme.player.login:
+ description: Command permission to login.
+ default: true
+ authme.player.logout:
+ description: Command permission to logout.
+ default: true
+ authme.player.register:
+ description: Command permission to register.
+ default: true
+ authme.player.seeownaccounts:
+ description: Permission to use to see own other accounts.
+ default: true
+ authme.player.unregister:
+ description: Command permission to unregister.
+ default: true
+ authme.vip:
+ description: Permission node to identify VIP users.
+ default: op
diff --git a/src/test/java/fr/xephi/authme/command/CommandInitializerTest.java b/src/test/java/fr/xephi/authme/command/CommandInitializerTest.java
index 944424f52..a4e51e28c 100644
--- a/src/test/java/fr/xephi/authme/command/CommandInitializerTest.java
+++ b/src/test/java/fr/xephi/authme/command/CommandInitializerTest.java
@@ -18,6 +18,7 @@ import java.util.regex.Pattern;
import static fr.xephi.authme.permission.DefaultPermission.OP_ONLY;
import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasSize;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
@@ -32,7 +33,7 @@ public class CommandInitializerTest {
*/
private static int MAX_ALLOWED_DEPTH = 1;
- private static Set commands;
+ private static Collection commands;
@BeforeClass
public static void initializeCommandCollection() {
@@ -46,7 +47,7 @@ public class CommandInitializerTest {
// It obviously doesn't make sense to test much of the concrete data
// that is being initialized; we just want to guarantee with this test
// that data is indeed being initialized and we take a few "probes"
- assertThat(commands.size(), equalTo(8));
+ assertThat(commands, hasSize(8));
assertThat(commandsIncludeLabel(commands, "authme"), equalTo(true));
assertThat(commandsIncludeLabel(commands, "register"), equalTo(true));
assertThat(commandsIncludeLabel(commands, "help"), equalTo(false));
diff --git a/src/test/java/fr/xephi/authme/command/CommandMapperTest.java b/src/test/java/fr/xephi/authme/command/CommandMapperTest.java
index 3fd023a4e..46efdaec4 100644
--- a/src/test/java/fr/xephi/authme/command/CommandMapperTest.java
+++ b/src/test/java/fr/xephi/authme/command/CommandMapperTest.java
@@ -39,7 +39,7 @@ import static org.mockito.Mockito.mock;
@RunWith(DelayedInjectionRunner.class)
public class CommandMapperTest {
- private static Set commands;
+ private static List commands;
@InjectDelayed
private CommandMapper mapper;
diff --git a/src/test/java/fr/xephi/authme/command/CommandUtilsTest.java b/src/test/java/fr/xephi/authme/command/CommandUtilsTest.java
index 2d73549d8..c0b4771cd 100644
--- a/src/test/java/fr/xephi/authme/command/CommandUtilsTest.java
+++ b/src/test/java/fr/xephi/authme/command/CommandUtilsTest.java
@@ -1,8 +1,15 @@
package fr.xephi.authme.command;
import fr.xephi.authme.TestHelper;
+import org.bukkit.ChatColor;
+import org.junit.BeforeClass;
import org.junit.Test;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
@@ -11,6 +18,13 @@ import static org.junit.Assert.assertThat;
*/
public class CommandUtilsTest {
+ private static Collection commands;
+
+ @BeforeClass
+ public static void setUpTestCommands() {
+ commands = TestCommandsUtil.generateCommands();
+ }
+
@Test
public void shouldReturnCommandPath() {
// given
@@ -19,14 +33,14 @@ public class CommandUtilsTest {
.description("Base")
.detailedDescription("Test base command.")
.executableCommand(ExecutableCommand.class)
- .build();
+ .register();
CommandDescription command = CommandDescription.builder()
.parent(base)
.labels("help", "h", "?")
.description("Child")
.detailedDescription("Test child command.")
.executableCommand(ExecutableCommand.class)
- .build();
+ .register();
// when
String commandPath = CommandUtils.constructCommandPath(command);
@@ -42,7 +56,7 @@ public class CommandUtilsTest {
@Test
public void shouldComputeMinAndMaxOnEmptyCommand() {
// given
- CommandDescription command = getBuilderForArgsTest().build();
+ CommandDescription command = getBuilderForArgsTest().register();
// when / then
checkArgumentCount(command, 0, 0);
@@ -54,7 +68,7 @@ public class CommandUtilsTest {
CommandDescription command = getBuilderForArgsTest()
.withArgument("Test", "Arg description", false)
.withArgument("Test22", "Arg description 2", false)
- .build();
+ .register();
// when / then
checkArgumentCount(command, 2, 2);
@@ -67,7 +81,7 @@ public class CommandUtilsTest {
.withArgument("arg1", "Arg description", false)
.withArgument("arg2", "Arg description 2", true)
.withArgument("arg3", "Arg description 3", true)
- .build();
+ .register();
// when / then
checkArgumentCount(command, 1, 3);
@@ -79,6 +93,46 @@ public class CommandUtilsTest {
TestHelper.validateHasOnlyPrivateEmptyConstructor(CommandUtils.class);
}
+ @Test
+ public void shouldFormatSimpleArgument() {
+ // given
+ CommandDescription command = TestCommandsUtil.getCommandWithLabel(commands, "authme");
+ List labels = Collections.singletonList("authme");
+
+ // when
+ String result = CommandUtils.buildSyntax(command, labels);
+
+ // then
+ assertThat(result, equalTo(ChatColor.WHITE + "/authme" + ChatColor.YELLOW));
+ }
+
+ @Test
+ public void shouldFormatCommandWithMultipleArguments() {
+ // given
+ CommandDescription command = TestCommandsUtil.getCommandWithLabel(commands, "authme", "register");
+ List labels = Arrays.asList("authme", "reg");
+
+ // when
+ String result = CommandUtils.buildSyntax(command, labels);
+
+ // then
+ assertThat(result, equalTo(ChatColor.WHITE + "/authme" + ChatColor.YELLOW + " reg "));
+ }
+
+
+ @Test
+ public void shouldFormatCommandWithOptionalArgument() {
+ // given
+ CommandDescription command = TestCommandsUtil.getCommandWithLabel(commands, "email");
+ List labels = Collections.singletonList("email");
+
+ // when
+ String result = CommandUtils.buildSyntax(command, labels);
+
+ // then
+ assertThat(result, equalTo(ChatColor.WHITE + "/email" + ChatColor.YELLOW + " [player]"));
+ }
+
private static void checkArgumentCount(CommandDescription command, int expectedMin, int expectedMax) {
assertThat(CommandUtils.getMinNumberOfArguments(command), equalTo(expectedMin));
diff --git a/src/test/java/fr/xephi/authme/command/TestCommandsUtil.java b/src/test/java/fr/xephi/authme/command/TestCommandsUtil.java
index 285369973..9f9b02ca2 100644
--- a/src/test/java/fr/xephi/authme/command/TestCommandsUtil.java
+++ b/src/test/java/fr/xephi/authme/command/TestCommandsUtil.java
@@ -1,5 +1,6 @@
package fr.xephi.authme.command;
+import com.google.common.collect.ImmutableList;
import fr.xephi.authme.command.executable.HelpCommand;
import fr.xephi.authme.permission.AdminPermission;
import fr.xephi.authme.permission.PermissionNode;
@@ -8,9 +9,7 @@ import org.bukkit.command.CommandSender;
import java.util.Collection;
import java.util.List;
-import java.util.Set;
-import static com.google.common.collect.Sets.newHashSet;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
@@ -27,7 +26,7 @@ public final class TestCommandsUtil {
*
* @return The generated commands
*/
- public static Set generateCommands() {
+ public static List generateCommands() {
// Register /authme
CommandDescription authMeBase = createCommand(null, null, singletonList("authme"), ExecutableCommand.class);
// Register /authme login
@@ -42,13 +41,13 @@ public final class TestCommandsUtil {
newArgument("player", true));
// Register /email helptest -- use only to test for help command arguments special case
CommandDescription.builder().parent(emailBase).labels("helptest").executableCommand(HelpCommand.class)
- .description("test").detailedDescription("Test.").withArgument("Query", "", false).build();
+ .description("test").detailedDescription("Test.").withArgument("Query", "", false).register();
// Register /unregister , alias: /unreg
CommandDescription unregisterBase = createCommand(AdminPermission.UNREGISTER, null,
asList("unregister", "unreg"), TestUnregisterCommand.class, newArgument("player", false));
- return newHashSet(authMeBase, emailBase, unregisterBase);
+ return ImmutableList.of(authMeBase, emailBase, unregisterBase);
}
/**
@@ -101,7 +100,7 @@ public final class TestCommandsUtil {
}
}
- return command.build();
+ return command.register();
}
/** Shortcut command to initialize a new argument description. */
diff --git a/src/test/java/fr/xephi/authme/command/executable/HelpCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/HelpCommandTest.java
index 143ae26b8..3c57e2148 100644
--- a/src/test/java/fr/xephi/authme/command/executable/HelpCommandTest.java
+++ b/src/test/java/fr/xephi/authme/command/executable/HelpCommandTest.java
@@ -20,6 +20,10 @@ import static fr.xephi.authme.command.FoundResultStatus.INCORRECT_ARGUMENTS;
import static fr.xephi.authme.command.FoundResultStatus.MISSING_BASE_COMMAND;
import static fr.xephi.authme.command.FoundResultStatus.SUCCESS;
import static fr.xephi.authme.command.FoundResultStatus.UNKNOWN_LABEL;
+import static fr.xephi.authme.command.help.HelpProvider.SHOW_ALTERNATIVES;
+import static fr.xephi.authme.command.help.HelpProvider.SHOW_CHILDREN;
+import static fr.xephi.authme.command.help.HelpProvider.SHOW_COMMAND;
+import static fr.xephi.authme.command.help.HelpProvider.SHOW_DESCRIPTION;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.hamcrest.CoreMatchers.containsString;
@@ -108,7 +112,7 @@ public class HelpCommandTest {
CommandDescription commandDescription = mock(CommandDescription.class);
given(commandDescription.getLabelCount()).willReturn(1);
FoundCommandResult foundCommandResult = new FoundCommandResult(commandDescription, singletonList("authme"),
- Collections.emptyList(), 0.0, SUCCESS);
+ Collections.emptyList(), 0.0, SUCCESS);
given(commandMapper.mapPartsToCommand(sender, arguments)).willReturn(foundCommandResult);
// when
@@ -116,7 +120,8 @@ public class HelpCommandTest {
// then
verify(sender, never()).sendMessage(anyString());
- verify(helpProvider).outputHelp(sender, foundCommandResult, HelpProvider.SHOW_CHILDREN);
+ verify(helpProvider).outputHelp(sender, foundCommandResult,
+ SHOW_DESCRIPTION | SHOW_COMMAND | SHOW_CHILDREN | SHOW_ALTERNATIVES);
}
@Test
@@ -126,7 +131,7 @@ public class HelpCommandTest {
CommandDescription commandDescription = mock(CommandDescription.class);
given(commandDescription.getLabelCount()).willReturn(2);
FoundCommandResult foundCommandResult = new FoundCommandResult(commandDescription, asList("authme", "getpos"),
- Collections.emptyList(), 0.0, INCORRECT_ARGUMENTS);
+ Collections.emptyList(), 0.0, INCORRECT_ARGUMENTS);
given(commandMapper.mapPartsToCommand(sender, arguments)).willReturn(foundCommandResult);
// when
diff --git a/src/test/java/fr/xephi/authme/command/help/CommandSyntaxHelperTest.java b/src/test/java/fr/xephi/authme/command/help/CommandSyntaxHelperTest.java
deleted file mode 100644
index 77320d151..000000000
--- a/src/test/java/fr/xephi/authme/command/help/CommandSyntaxHelperTest.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package fr.xephi.authme.command.help;
-
-import fr.xephi.authme.TestHelper;
-import fr.xephi.authme.command.CommandDescription;
-import fr.xephi.authme.command.TestCommandsUtil;
-import org.bukkit.ChatColor;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-
-import static org.hamcrest.Matchers.equalTo;
-import static org.junit.Assert.assertThat;
-
-/**
- * Test for {@link CommandSyntaxHelper}.
- */
-public class CommandSyntaxHelperTest {
-
- private static Set commands;
-
- @BeforeClass
- public static void setUpTestCommands() {
- commands = TestCommandsUtil.generateCommands();
- }
-
- @Test
- public void shouldFormatSimpleArgument() {
- // given
- CommandDescription command = TestCommandsUtil.getCommandWithLabel(commands, "authme");
- List labels = Collections.singletonList("authme");
-
- // when
- String result = CommandSyntaxHelper.getSyntax(command, labels);
-
- // then
- assertThat(result, equalTo(ChatColor.WHITE + "/authme" + ChatColor.YELLOW));
- }
-
- @Test
- public void shouldFormatCommandWithMultipleArguments() {
- // given
- CommandDescription command = TestCommandsUtil.getCommandWithLabel(commands, "authme", "register");
- List labels = Arrays.asList("authme", "reg");
-
- // when
- String result = CommandSyntaxHelper.getSyntax(command, labels);
-
- // then
- assertThat(result, equalTo(ChatColor.WHITE + "/authme" + ChatColor.YELLOW + " reg "));
- }
-
-
- @Test
- public void shouldFormatCommandWithOptionalArgument() {
- // given
- CommandDescription command = TestCommandsUtil.getCommandWithLabel(commands, "email");
- List labels = Collections.singletonList("email");
-
- // when
- String result = CommandSyntaxHelper.getSyntax(command, labels);
-
- // then
- assertThat(result, equalTo(ChatColor.WHITE + "/email" + ChatColor.YELLOW + " [player]"));
- }
-
- @Test
- public void shouldHaveHiddenConstructor() {
- // given / when / then
- TestHelper.validateHasOnlyPrivateEmptyConstructor(CommandSyntaxHelper.class);
- }
-
-}
diff --git a/src/test/java/fr/xephi/authme/command/help/HelpMessagesConsistencyTest.java b/src/test/java/fr/xephi/authme/command/help/HelpMessagesConsistencyTest.java
index 7c50829f8..5e79ef993 100644
--- a/src/test/java/fr/xephi/authme/command/help/HelpMessagesConsistencyTest.java
+++ b/src/test/java/fr/xephi/authme/command/help/HelpMessagesConsistencyTest.java
@@ -9,8 +9,8 @@ import org.bukkit.configuration.file.YamlConfiguration;
import org.junit.Test;
import java.io.File;
+import java.util.Collection;
import java.util.List;
-import java.util.Set;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.equalTo;
@@ -78,7 +78,7 @@ public class HelpMessagesConsistencyTest {
* @return the CommandDescription object for the {@code /authme register} command.
*/
private static CommandDescription getAuthMeRegisterDescription() {
- Set commands = new CommandInitializer().getCommands();
+ Collection commands = new CommandInitializer().getCommands();
List children = commands.stream()
.filter(command -> command.getLabels().contains("authme"))
diff --git a/src/test/java/fr/xephi/authme/command/help/HelpMessagesServiceTest.java b/src/test/java/fr/xephi/authme/command/help/HelpMessagesServiceTest.java
index a451ff4d2..150bb42f5 100644
--- a/src/test/java/fr/xephi/authme/command/help/HelpMessagesServiceTest.java
+++ b/src/test/java/fr/xephi/authme/command/help/HelpMessagesServiceTest.java
@@ -12,10 +12,11 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import java.util.Set;
+import java.util.Collection;
import java.util.function.Function;
import static fr.xephi.authme.TestHelper.getJarFile;
+import static fr.xephi.authme.command.TestCommandsUtil.getCommandWithLabel;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.sameInstance;
@@ -30,7 +31,7 @@ import static org.mockito.Matchers.any;
public class HelpMessagesServiceTest {
private static final String TEST_FILE = "/fr/xephi/authme/command/help/help_test.yml";
- private static final Set COMMANDS = TestCommandsUtil.generateCommands();
+ private static final Collection COMMANDS = TestCommandsUtil.generateCommands();
@InjectDelayed
private HelpMessagesService helpMessagesService;
@@ -48,7 +49,7 @@ public class HelpMessagesServiceTest {
@Test
public void shouldReturnLocalizedCommand() {
// given
- CommandDescription command = TestCommandsUtil.getCommandWithLabel(COMMANDS, "authme", "register");
+ CommandDescription command = getCommandWithLabel(COMMANDS, "authme", "register");
// when
CommandDescription localCommand = helpMessagesService.buildLocalizedDescription(command);
@@ -68,7 +69,7 @@ public class HelpMessagesServiceTest {
@Test
public void shouldReturnLocalizedCommandWithDefaults() {
// given
- CommandDescription command = TestCommandsUtil.getCommandWithLabel(COMMANDS, "authme", "login");
+ CommandDescription command = getCommandWithLabel(COMMANDS, "authme", "login");
// when
CommandDescription localCommand = helpMessagesService.buildLocalizedDescription(command);
@@ -84,7 +85,7 @@ public class HelpMessagesServiceTest {
@Test
public void shouldReturnSameCommandForNoLocalization() {
// given
- CommandDescription command = TestCommandsUtil.getCommandWithLabel(COMMANDS, "email");
+ CommandDescription command = getCommandWithLabel(COMMANDS, "email");
// when
CommandDescription localCommand = helpMessagesService.buildLocalizedDescription(command);
@@ -96,7 +97,7 @@ public class HelpMessagesServiceTest {
@Test
public void shouldKeepChildrenInLocalCommand() {
// given
- CommandDescription command = TestCommandsUtil.getCommandWithLabel(COMMANDS, "authme");
+ CommandDescription command = getCommandWithLabel(COMMANDS, "authme");
// when
CommandDescription localCommand = helpMessagesService.buildLocalizedDescription(command);
@@ -114,4 +115,28 @@ public class HelpMessagesServiceTest {
assertThat(helpMessagesService.getMessage(HelpMessage.RESULT), equalTo("res."));
assertThat(helpMessagesService.getMessage(HelpSection.ARGUMENTS), equalTo("arg."));
}
+
+ @Test
+ public void shouldGetLocalCommandDescription() {
+ // given
+ CommandDescription command = getCommandWithLabel(COMMANDS, "authme", "register");
+
+ // when
+ String description = helpMessagesService.getDescription(command);
+
+ // then
+ assertThat(description, equalTo("Registration"));
+ }
+
+ @Test
+ public void shouldFallbackToDescriptionOnCommandObject() {
+ // given
+ CommandDescription command = getCommandWithLabel(COMMANDS, "unregister");
+
+ // when
+ String description = helpMessagesService.getDescription(command);
+
+ // then
+ assertThat(description, equalTo(command.getDescription()));
+ }
}
diff --git a/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java b/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java
index 5a0f06f29..e90a76120 100644
--- a/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java
+++ b/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java
@@ -20,9 +20,9 @@ import org.mockito.Mock;
import org.mockito.internal.stubbing.answers.ReturnsArgumentAt;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.Set;
import java.util.stream.Collectors;
import static fr.xephi.authme.command.TestCommandsUtil.getCommandWithLabel;
@@ -53,7 +53,7 @@ import static org.mockito.Mockito.verify;
@RunWith(DelayedInjectionRunner.class)
public class HelpProviderTest {
- private static Set commands;
+ private static Collection commands;
@InjectDelayed
private HelpProvider helpProvider;
@@ -251,6 +251,10 @@ public class HelpProviderTest {
// given
CommandDescription command = getCommandWithLabel(commands, "authme");
FoundCommandResult result = newFoundResult(command, Collections.singletonList("authme"));
+ given(helpMessagesService.getDescription(getCommandWithLabel(commands, "authme", "login")))
+ .willReturn("Command for login [localized]");
+ given(helpMessagesService.getDescription(getCommandWithLabel(commands, "authme", "register")))
+ .willReturn("Registration command [localized]");
// when
helpProvider.outputHelp(sender, result, SHOW_CHILDREN);
@@ -258,9 +262,9 @@ public class HelpProviderTest {
// then
List lines = getLines(sender);
assertThat(lines, hasSize(4));
- assertThat(lines.get(1), containsString("Children:"));
- assertThat(lines.get(2), containsString("/authme login: login cmd"));
- assertThat(lines.get(3), containsString("/authme register: register cmd"));
+ assertThat(lines.get(1), equalTo("Children:"));
+ assertThat(lines.get(2), equalTo(" /authme login: Command for login [localized]"));
+ assertThat(lines.get(3), equalTo(" /authme register: Registration command [localized]"));
}
@Test
@@ -395,6 +399,24 @@ public class HelpProviderTest {
assertThat(lines.get(0), equalTo("Command: /authme register "));
}
+ @Test
+ public void shouldShowAlternativesForRootCommand() {
+ // given
+ CommandDescription command = getCommandWithLabel(commands, "unregister");
+ FoundCommandResult result = newFoundResult(command, Collections.singletonList("unreg"));
+
+ // when
+ helpProvider.outputHelp(sender, result, SHOW_COMMAND | SHOW_ALTERNATIVES);
+
+ // then
+ List lines = getLines(sender);
+ assertThat(lines, hasSize(4));
+ assertThat(lines.get(0), equalTo("Header"));
+ assertThat(lines.get(1), equalTo("Command: /unreg "));
+ assertThat(lines.get(2), equalTo("Alternatives:"));
+ assertThat(lines.get(3), equalTo(" /unregister "));
+ }
+
/**
* Generate an instance of {@link FoundCommandResult} with the given command and labels. All other fields aren't
* retrieved by {@link HelpProvider} and so are initialized to default values for the tests.
diff --git a/src/test/java/fr/xephi/authme/message/MessagesFileYamlCheckerTest.java b/src/test/java/fr/xephi/authme/message/MessagesFileYamlCheckerTest.java
deleted file mode 100644
index ebb04fc2d..000000000
--- a/src/test/java/fr/xephi/authme/message/MessagesFileYamlCheckerTest.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package fr.xephi.authme.message;
-
-import fr.xephi.authme.TestHelper;
-import fr.xephi.authme.util.StringUtils;
-import org.bukkit.configuration.file.YamlConfiguration;
-import org.junit.Test;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Pattern;
-
-import static org.junit.Assert.fail;
-
-/**
- * Tests that all YML message files can be loaded.
- */
-public class MessagesFileYamlCheckerTest {
-
- /** Path in the resources folder where the message files are located. */
- private static final String MESSAGES_FOLDER = "/messages/";
- /** Pattern of the message file names. */
- private static final Pattern MESSAGE_FILE_PATTERN = Pattern.compile("messages_\\w+\\.yml");
- /** Message key that is present in all files. Used to make sure that text is returned. */
- private static final MessageKey MESSAGE_KEY = MessageKey.LOGIN_MESSAGE;
-
- @Test
- public void shouldAllBeValidYaml() {
- // given
- List messageFiles = getMessageFiles();
-
- // when
- List errors = new ArrayList<>();
- for (File file : messageFiles) {
- String error = null;
- try {
- YamlConfiguration configuration = YamlConfiguration.loadConfiguration(file);
- if (StringUtils.isEmpty(configuration.getString(MESSAGE_KEY.getKey()))) {
- error = "Message for '" + MESSAGE_KEY + "' is empty";
- }
- } catch (Exception e) {
- error = "Could not load file: " + StringUtils.formatException(e);
- }
- if (!StringUtils.isEmpty(error)) {
- errors.add(file.getName() + ": " + error);
- }
- }
-
- // then
- if (!errors.isEmpty()) {
- fail("Errors during verification of message files:\n-" + String.join("\n-", errors));
- }
- }
-
-
- private List getMessageFiles() {
- File folder = TestHelper.getJarFile(MESSAGES_FOLDER);
- File[] files = folder.listFiles();
- if (files == null) {
- throw new IllegalStateException("Could not read folder '" + folder.getName() + "'");
- }
-
- List messageFiles = new ArrayList<>();
- for (File file : files) {
- if (MESSAGE_FILE_PATTERN.matcher(file.getName()).matches()) {
- messageFiles.add(file);
- }
- }
- if (messageFiles.isEmpty()) {
- throw new IllegalStateException("Error getting message files: list of files is empty");
- }
- return messageFiles;
- }
-
-}
diff --git a/src/test/java/fr/xephi/authme/message/YamlTextFileCheckerTest.java b/src/test/java/fr/xephi/authme/message/YamlTextFileCheckerTest.java
new file mode 100644
index 000000000..7fa6fecba
--- /dev/null
+++ b/src/test/java/fr/xephi/authme/message/YamlTextFileCheckerTest.java
@@ -0,0 +1,98 @@
+package fr.xephi.authme.message;
+
+import fr.xephi.authme.TestHelper;
+import fr.xephi.authme.command.help.HelpSection;
+import fr.xephi.authme.util.StringUtils;
+import org.bukkit.configuration.file.YamlConfiguration;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import static org.junit.Assert.fail;
+
+/**
+ * Tests that all YML text files can be loaded.
+ */
+public class YamlTextFileCheckerTest {
+
+ /** Path in the resources folder where the message files are located. */
+ private static final String MESSAGES_FOLDER = "/messages/";
+ /** Contains all files of the MESSAGES_FOLDER. */
+ private static List messageFiles;
+
+ @BeforeClass
+ public static void loadMessagesFiles() {
+ File folder = TestHelper.getJarFile(MESSAGES_FOLDER);
+ File[] files = folder.listFiles();
+ if (files == null || files.length == 0) {
+ throw new IllegalStateException("Could not read folder '" + folder.getName() + "'");
+ }
+ messageFiles = Arrays.asList(files);
+ }
+
+ @Test
+ public void testAllMessagesYmlFiles() {
+ checkFiles(
+ Pattern.compile("messages_\\w+\\.yml"),
+ MessageKey.LOGIN_MESSAGE.getKey());
+ }
+
+ @Test
+ public void testAllHelpYmlFiles() {
+ checkFiles(
+ Pattern.compile("help_\\w+\\.yml"),
+ HelpSection.ALTERNATIVES.getKey());
+ }
+
+ /**
+ * Checks all files in the messages folder that match the given pattern.
+ *
+ * @param pattern the pattern the file name needs to match
+ * @param mandatoryKey key present in all matched files
+ */
+ private void checkFiles(Pattern pattern, String mandatoryKey) {
+ List errors = new ArrayList<>();
+
+ boolean hasMatch = false;
+ for (File file : messageFiles) {
+ if (pattern.matcher(file.getName()).matches()) {
+ checkFile(file, mandatoryKey, errors);
+ hasMatch = true;
+ }
+ }
+
+ if (!errors.isEmpty()) {
+ fail("Errors while checking files matching '" + pattern + "':\n-" + String.join("\n-", errors));
+ } else if (!hasMatch) {
+ fail("Could not find any files satisfying pattern '" + pattern + "'");
+ }
+ }
+
+ /**
+ * Checks that the provided YAML file can be loaded and that it contains a non-empty text
+ * for the provided mandatory key.
+ *
+ * @param file the file to check
+ * @param mandatoryKey the key for which text must be present
+ * @param errors collection of errors to add to if the verification fails
+ */
+ private void checkFile(File file, String mandatoryKey, List errors) {
+ String error = null;
+ try {
+ YamlConfiguration configuration = YamlConfiguration.loadConfiguration(file);
+ if (StringUtils.isEmpty(configuration.getString(mandatoryKey))) {
+ error = "Message for '" + mandatoryKey + "' is empty";
+ }
+ } catch (Exception e) {
+ error = "Could not load file: " + StringUtils.formatException(e);
+ }
+ if (!StringUtils.isEmpty(error)) {
+ errors.add(file.getName() + ": " + error);
+ }
+ }
+}
diff --git a/src/test/java/fr/xephi/authme/permission/PermissionConsistencyTest.java b/src/test/java/fr/xephi/authme/permission/PermissionConsistencyTest.java
index bd18df8ad..f44ef2220 100644
--- a/src/test/java/fr/xephi/authme/permission/PermissionConsistencyTest.java
+++ b/src/test/java/fr/xephi/authme/permission/PermissionConsistencyTest.java
@@ -26,7 +26,7 @@ public class PermissionConsistencyTest {
/** All classes defining permission nodes. */
private static final Set> PERMISSION_CLASSES = ImmutableSet
- .>of(PlayerPermission.class, AdminPermission.class, PlayerStatePermission.class);
+ .of(PlayerPermission.class, AdminPermission.class, PlayerStatePermission.class);
/** Wildcard permissions (present in plugin.yml but not in the codebase). */
private static final Set PLUGIN_YML_PERMISSIONS_WILDCARDS =
diff --git a/src/test/java/fr/xephi/authme/service/AntiBotServiceTest.java b/src/test/java/fr/xephi/authme/service/AntiBotServiceTest.java
index a39c7a6e2..7dfa0b0d3 100644
--- a/src/test/java/fr/xephi/authme/service/AntiBotServiceTest.java
+++ b/src/test/java/fr/xephi/authme/service/AntiBotServiceTest.java
@@ -51,6 +51,7 @@ public class AntiBotServiceTest {
@BeforeInjecting
public void initSettings() {
given(settings.getProperty(ProtectionSettings.ANTIBOT_DURATION)).willReturn(10);
+ given(settings.getProperty(ProtectionSettings.ANTIBOT_INTERVAL)).willReturn(5);
given(settings.getProperty(ProtectionSettings.ANTIBOT_SENSIBILITY)).willReturn(5);
given(settings.getProperty(ProtectionSettings.ENABLE_ANTIBOT)).willReturn(true);
given(settings.getProperty(ProtectionSettings.ANTIBOT_DELAY)).willReturn(8);
diff --git a/src/test/java/fr/xephi/authme/settings/ConfigFileConsistencyTest.java b/src/test/java/fr/xephi/authme/settings/ConfigFileConsistencyTest.java
deleted file mode 100644
index ab4031e25..000000000
--- a/src/test/java/fr/xephi/authme/settings/ConfigFileConsistencyTest.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package fr.xephi.authme.settings;
-
-import com.github.authme.configme.knownproperties.ConfigurationData;
-import com.github.authme.configme.migration.MigrationService;
-import com.github.authme.configme.migration.PlainMigrationService;
-import com.github.authme.configme.properties.Property;
-import com.github.authme.configme.resource.PropertyResource;
-import com.github.authme.configme.resource.YamlFileResource;
-import fr.xephi.authme.TestHelper;
-import fr.xephi.authme.settings.properties.AuthMeSettingsRetriever;
-import org.bukkit.configuration.MemorySection;
-import org.bukkit.configuration.file.FileConfiguration;
-import org.bukkit.configuration.file.YamlConfiguration;
-import org.junit.Test;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import static org.hamcrest.Matchers.equalTo;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.fail;
-
-/**
- * Test for {@link Settings} and the project's config.yml,
- * verifying that no settings are missing from the file.
- */
-public class ConfigFileConsistencyTest {
-
- /** The file name of the project's sample config file. */
- private static final String CONFIG_FILE = "/config.yml";
-
- @Test
- public void shouldHaveAllConfigs() throws IOException {
- // given
- File configFile = TestHelper.getJarFile(CONFIG_FILE);
- PropertyResource resource = new YamlFileResource(configFile);
- MigrationService migration = new PlainMigrationService();
-
- // when
- boolean result = migration.checkAndMigrate(
- resource, AuthMeSettingsRetriever.buildConfigurationData().getProperties());
-
- // then
- if (result) {
- Set knownProperties = getAllKnownPropertyPaths();
- List missingProperties = new ArrayList<>();
- for (String path : knownProperties) {
- if (!resource.contains(path)) {
- missingProperties.add(path);
- }
- }
- fail("Found missing properties!\n-" + String.join("\n-", missingProperties));
- }
- }
-
- @Test
- public void shouldNotHaveUnknownConfigs() {
- // given
- File configFile = TestHelper.getJarFile(CONFIG_FILE);
- FileConfiguration configuration = YamlConfiguration.loadConfiguration(configFile);
- Map allReadProperties = configuration.getValues(true);
- Set knownKeys = getAllKnownPropertyPaths();
-
- // when
- List unknownPaths = new ArrayList<>();
- for (Map.Entry entry : allReadProperties.entrySet()) {
- // The value being a MemorySection means it's a parent node
- if (!(entry.getValue() instanceof MemorySection) && !knownKeys.contains(entry.getKey())) {
- unknownPaths.add(entry.getKey());
- }
- }
-
- // then
- if (!unknownPaths.isEmpty()) {
- fail("Found " + unknownPaths.size() + " unknown property paths in the project's config.yml: \n- "
- + String.join("\n- ", unknownPaths));
- }
- }
-
- @Test
- public void shouldHaveValueCorrespondingToPropertyDefault() {
- // given
- File configFile = TestHelper.getJarFile(CONFIG_FILE);
- PropertyResource resource = new YamlFileResource(configFile);
- ConfigurationData configurationData = AuthMeSettingsRetriever.buildConfigurationData();
-
- // when / then
- for (Property> property : configurationData.getProperties()) {
- assertThat("Default value of '" + property.getPath() + "' in config.yml should be the same as in Property",
- property.getValue(resource).equals(property.getDefaultValue()), equalTo(true));
- }
- }
-
- private static Set getAllKnownPropertyPaths() {
- return AuthMeSettingsRetriever.buildConfigurationData()
- .getProperties().stream()
- .map(Property::getPath)
- .collect(Collectors.toSet());
- }
-}
diff --git a/src/test/java/fr/xephi/authme/settings/SettingsConsistencyTest.java b/src/test/java/fr/xephi/authme/settings/SettingsConsistencyTest.java
new file mode 100644
index 000000000..7123ac26b
--- /dev/null
+++ b/src/test/java/fr/xephi/authme/settings/SettingsConsistencyTest.java
@@ -0,0 +1,69 @@
+package fr.xephi.authme.settings;
+
+import com.github.authme.configme.knownproperties.ConfigurationData;
+import com.github.authme.configme.properties.Property;
+import fr.xephi.authme.settings.properties.AuthMeSettingsRetriever;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.junit.Assert.fail;
+
+/**
+ * Tests the consistency of the settings configuration.
+ */
+public class SettingsConsistencyTest {
+
+ /**
+ * Maximum characters one comment line may have (prevents horizontal scrolling).
+ */
+ private static final int MAX_COMMENT_LENGTH = 90;
+
+ private static ConfigurationData configurationData;
+
+ @BeforeClass
+ public static void buildConfigurationData() {
+ configurationData = AuthMeSettingsRetriever.buildConfigurationData();
+ }
+
+ @Test
+ public void shouldHaveCommentOnEachProperty() {
+ // given
+ List> properties = configurationData.getProperties();
+
+ // when / then
+ for (Property> property : properties) {
+ if (configurationData.getCommentsForSection(property.getPath()).length == 0) {
+ fail("No comment defined for '" + property + "'");
+ }
+ }
+ }
+
+ @Test
+ public void shouldNotHaveVeryLongCommentLines() {
+ // given
+ List> properties = configurationData.getProperties();
+ List> badProperties = new ArrayList<>();
+
+ // when
+ for (Property> property : properties) {
+ for (String comment : configurationData.getCommentsForSection(property.getPath())) {
+ if (comment.length() > MAX_COMMENT_LENGTH) {
+ badProperties.add(property);
+ break;
+ }
+ }
+ }
+
+ // then
+ if (!badProperties.isEmpty()) {
+ fail("Comment lines should not be longer than " + MAX_COMMENT_LENGTH + " chars, "
+ + "but found too long comments for:\n- "
+ + badProperties.stream().map(Property::getPath).collect(Collectors.joining("\n- ")));
+ }
+ }
+
+}
diff --git a/src/test/java/fr/xephi/authme/settings/SettingsMigrationServiceTest.java b/src/test/java/fr/xephi/authme/settings/SettingsMigrationServiceTest.java
deleted file mode 100644
index 93325110a..000000000
--- a/src/test/java/fr/xephi/authme/settings/SettingsMigrationServiceTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package fr.xephi.authme.settings;
-
-import com.github.authme.configme.knownproperties.ConfigurationData;
-import com.github.authme.configme.resource.PropertyResource;
-import com.github.authme.configme.resource.YamlFileResource;
-import com.google.common.io.Files;
-import fr.xephi.authme.TestHelper;
-import fr.xephi.authme.settings.properties.AuthMeSettingsRetriever;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-
-import java.io.File;
-import java.io.IOException;
-
-import static org.hamcrest.Matchers.arrayWithSize;
-import static org.hamcrest.Matchers.equalTo;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assume.assumeThat;
-
-/**
- * Test for {@link SettingsMigrationService}.
- */
-public class SettingsMigrationServiceTest {
-
- @Rule
- public TemporaryFolder testFolderHandler = new TemporaryFolder();
-
- private File testFolder;
- private File configTestFile;
-
- /**
- * Ensure that AuthMe regards the JAR's own config.yml as complete.
- * If something legitimately needs migrating, a test from {@link ConfigFileConsistencyTest} should fail.
- * If none fails in that class, it means something is wrong with the migration service
- * as it wants to perform a migration on our up-to-date config.yml.
- */
- @Test
- public void shouldNotRewriteJarConfig() throws IOException {
- // given
- copyConfigToTestFolder();
- PropertyResource resource = new YamlFileResource(configTestFile);
- ConfigurationData configurationData = AuthMeSettingsRetriever.buildConfigurationData();
- assumeThat(testFolder.listFiles(), arrayWithSize(1));
- SettingsMigrationService migrationService = new SettingsMigrationService(testFolder);
-
- // when
- boolean result = migrationService.checkAndMigrate(resource, configurationData.getProperties());
-
- // then
- assertThat(result, equalTo(false));
- assertThat(testFolder.listFiles(), arrayWithSize(1));
- }
-
- private void copyConfigToTestFolder() throws IOException {
- testFolder = testFolderHandler.newFolder("migrationtest");
-
- final File testConfig = testFolderHandler.newFile("migrationtest/config.yml");
- final File realConfig = TestHelper.getJarFile("/config.yml");
-
- Files.copy(realConfig, testConfig);
- if (!testConfig.exists()) {
- throw new IOException("Could not copy project's config.yml to test folder");
- }
- configTestFile = testConfig;
- }
-}
diff --git a/src/test/java/fr/xephi/authme/util/FileUtilsTest.java b/src/test/java/fr/xephi/authme/util/FileUtilsTest.java
index f36acf755..fa8ee9c6d 100644
--- a/src/test/java/fr/xephi/authme/util/FileUtilsTest.java
+++ b/src/test/java/fr/xephi/authme/util/FileUtilsTest.java
@@ -11,6 +11,8 @@ import java.io.File;
import java.io.IOException;
import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertThat;
/**
@@ -47,15 +49,15 @@ public class FileUtilsTest {
public void shouldCopyFileFromJar() throws IOException {
// given
File folder = temporaryFolder.newFolder();
- File file = new File(folder, "some/folders/config.yml");
+ File file = new File(folder, "some/folders/welcome.txt");
// when
- boolean result = FileUtils.copyFileFromResource(file, "config.yml");
+ boolean result = FileUtils.copyFileFromResource(file, "welcome.txt");
// then
assertThat(result, equalTo(true));
assertThat(file.exists(), equalTo(true));
- File configJarFile = TestHelper.getJarFile("/config.yml");
+ File configJarFile = TestHelper.getJarFile("/welcome.txt");
assertThat(file.length(), equalTo(configJarFile.length()));
}
@@ -119,6 +121,13 @@ public class FileUtilsTest {
// Nothing happens
}
+ @Test
+ public void shouldGetResourceFromJar() {
+ // given / when / then
+ assertThat(FileUtils.getResourceFromJar("config.yml"), not(nullValue()));
+ assertThat(FileUtils.getResourceFromJar("does-not-exist"), nullValue());
+ }
+
@Test
public void shouldConstructPath() {
// given/when
diff --git a/src/test/java/tools/checktestmocks/CheckTestMocks.java b/src/test/java/tools/checktestmocks/CheckTestMocks.java
index def4e822f..9af3ae040 100644
--- a/src/test/java/tools/checktestmocks/CheckTestMocks.java
+++ b/src/test/java/tools/checktestmocks/CheckTestMocks.java
@@ -12,7 +12,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
-import java.util.Scanner;
import java.util.Set;
import java.util.stream.Collectors;
@@ -29,11 +28,6 @@ public class CheckTestMocks implements AutoToolTask {
return "checkTestMocks";
}
- @Override
- public void execute(Scanner scanner) {
- executeDefault();
- }
-
@Override
public void executeDefault() {
ClassCollector collector = new ClassCollector(TestHelper.TEST_SOURCES_FOLDER, TestHelper.PROJECT_ROOT);
diff --git a/src/test/java/tools/docs/UpdateDocsTask.java b/src/test/java/tools/docs/UpdateDocsTask.java
index cfdb69ef9..84f723c64 100644
--- a/src/test/java/tools/docs/UpdateDocsTask.java
+++ b/src/test/java/tools/docs/UpdateDocsTask.java
@@ -1,26 +1,20 @@
package tools.docs;
-import com.google.common.collect.ImmutableSet;
-import tools.docs.commands.CommandPageCreater;
-import tools.docs.hashmethods.HashAlgorithmsDescriptionTask;
-import tools.docs.permissions.PermissionsListWriter;
-import tools.docs.translations.TranslationPageGenerator;
+import fr.xephi.authme.ClassCollector;
+import fr.xephi.authme.TestHelper;
import tools.utils.AutoToolTask;
import tools.utils.ToolTask;
+import java.util.List;
import java.util.Scanner;
-import java.util.Set;
import java.util.function.Consumer;
+import java.util.stream.Collectors;
/**
* Task that runs all tasks which update files in the docs folder.
*/
public class UpdateDocsTask implements AutoToolTask {
- private static final Set> TASKS = ImmutableSet
- .of(CommandPageCreater.class, HashAlgorithmsDescriptionTask.class,
- PermissionsListWriter.class, TranslationPageGenerator.class);
-
@Override
public String getTaskName() {
return "updateDocs";
@@ -40,19 +34,18 @@ public class UpdateDocsTask implements AutoToolTask {
});
}
- private static ToolTask instantiateTask(Class extends ToolTask> clazz) {
- try {
- return clazz.newInstance();
- } catch (IllegalAccessException | InstantiationException e) {
- throw new UnsupportedOperationException("Could not instantiate task class '" + clazz + "'", e);
- }
- }
-
- private static void executeTasks(Consumer taskRunner) {
- for (Class extends ToolTask> taskClass : TASKS) {
- ToolTask task = instantiateTask(taskClass);
+ private void executeTasks(Consumer taskRunner) {
+ for (ToolTask task : getDocTasks()) {
System.out.println("\nRunning " + task.getTaskName() + "\n-------------------");
taskRunner.accept(task);
}
}
+
+ private List getDocTasks() {
+ ClassCollector classCollector =
+ new ClassCollector(TestHelper.TEST_SOURCES_FOLDER, "tools/docs");
+ return classCollector.getInstancesOfType(ToolTask.class).stream()
+ .filter(task -> task.getClass() != getClass())
+ .collect(Collectors.toList());
+ }
}
diff --git a/src/test/java/tools/docs/commands/CommandPageCreater.java b/src/test/java/tools/docs/commands/CommandPageCreater.java
index 6a2f5edfe..ff1500a77 100644
--- a/src/test/java/tools/docs/commands/CommandPageCreater.java
+++ b/src/test/java/tools/docs/commands/CommandPageCreater.java
@@ -6,14 +6,12 @@ import fr.xephi.authme.command.CommandInitializer;
import fr.xephi.authme.command.CommandUtils;
import fr.xephi.authme.permission.PermissionNode;
import tools.utils.AutoToolTask;
-import tools.utils.FileUtils;
+import tools.utils.FileIoUtils;
import tools.utils.TagValue.NestedTagValue;
import tools.utils.TagValueHolder;
import tools.utils.ToolsConstants;
import java.util.Collection;
-import java.util.Scanner;
-import java.util.Set;
public class CommandPageCreater implements AutoToolTask {
@@ -24,19 +22,14 @@ public class CommandPageCreater implements AutoToolTask {
return "createCommandPage";
}
- @Override
- public void execute(Scanner scanner) {
- executeDefault();
- }
-
@Override
public void executeDefault() {
CommandInitializer commandInitializer = new CommandInitializer();
- final Set baseCommands = commandInitializer.getCommands();
+ final Collection baseCommands = commandInitializer.getCommands();
NestedTagValue commandTags = new NestedTagValue();
addCommandsInfo(commandTags, baseCommands);
- FileUtils.generateFileFromTemplate(
+ FileIoUtils.generateFileFromTemplate(
ToolsConstants.TOOLS_SOURCE_ROOT + "docs/commands/commands.tpl.md",
OUTPUT_FILE,
TagValueHolder.create().put("commands", commandTags));
diff --git a/src/test/java/tools/docs/commands/commands.tpl.md b/src/test/java/tools/docs/commands/commands.tpl.md
index c0f4da120..61018634c 100644
--- a/src/test/java/tools/docs/commands/commands.tpl.md
+++ b/src/test/java/tools/docs/commands/commands.tpl.md
@@ -1,5 +1,5 @@
-
+
## AuthMe Commands
You can use the following commands to use the features of AuthMe. Mandatory arguments are marked with `< >`
diff --git a/src/test/java/tools/docs/config/UpdateConfigPageTask.java b/src/test/java/tools/docs/config/UpdateConfigPageTask.java
new file mode 100644
index 000000000..f9a249a70
--- /dev/null
+++ b/src/test/java/tools/docs/config/UpdateConfigPageTask.java
@@ -0,0 +1,49 @@
+package tools.docs.config;
+
+import com.github.authme.configme.SettingsManager;
+import com.github.authme.configme.resource.YamlFileResource;
+import fr.xephi.authme.settings.properties.AuthMeSettingsRetriever;
+import fr.xephi.authme.util.FileUtils;
+import tools.utils.AutoToolTask;
+import tools.utils.FileIoUtils;
+import tools.utils.TagValueHolder;
+import tools.utils.ToolsConstants;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Task for updating the config docs page.
+ */
+public class UpdateConfigPageTask implements AutoToolTask {
+
+ private static final String TEMPLATE_FILE = ToolsConstants.TOOLS_SOURCE_ROOT + "docs/config/config.tpl.md";
+ private static final String OUTPUT_FILE = ToolsConstants.DOCS_FOLDER + "config.md";
+
+ @Override
+ public String getTaskName() {
+ return "updateConfigPage";
+ }
+
+ @Override
+ public void executeDefault() {
+ File config = null;
+ try {
+ // Create empty temporary .yml file and save the config to it
+ config = File.createTempFile("authme-config-", ".yml");
+ SettingsManager settingsManager = new SettingsManager(
+ new YamlFileResource(config), null, AuthMeSettingsRetriever.buildConfigurationData());
+ settingsManager.save();
+
+ // Get the contents and generate template file
+ TagValueHolder tagValueHolder = TagValueHolder.create()
+ .put("config", FileIoUtils.readFromFile(config.toPath()));
+ FileIoUtils.generateFileFromTemplate(TEMPLATE_FILE, OUTPUT_FILE, tagValueHolder);
+ System.out.println("Wrote to '" + OUTPUT_FILE + "'");
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ } finally {
+ FileUtils.delete(config);
+ }
+ }
+}
diff --git a/src/test/java/tools/docs/config/config.tpl.md b/src/test/java/tools/docs/config/config.tpl.md
new file mode 100644
index 000000000..25cf8c2c0
--- /dev/null
+++ b/src/test/java/tools/docs/config/config.tpl.md
@@ -0,0 +1,16 @@
+
+
+
+## AuthMe Configuration
+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.
+
+```yml
+{config}
+```
+
+To change settings on a running server, save your changes to config.yml and use
+`/authme reload`.
+
+{gen_footer}
diff --git a/src/test/java/tools/docs/hashmethods/HashAlgorithmsDescriptionTask.java b/src/test/java/tools/docs/hashmethods/HashAlgorithmsDescriptionTask.java
index 95da44d53..b21d7fda3 100644
--- a/src/test/java/tools/docs/hashmethods/HashAlgorithmsDescriptionTask.java
+++ b/src/test/java/tools/docs/hashmethods/HashAlgorithmsDescriptionTask.java
@@ -2,13 +2,12 @@ package tools.docs.hashmethods;
import fr.xephi.authme.security.HashAlgorithm;
import tools.utils.AutoToolTask;
-import tools.utils.FileUtils;
+import tools.utils.FileIoUtils;
import tools.utils.TagValue.NestedTagValue;
import tools.utils.TagValueHolder;
import tools.utils.ToolsConstants;
import java.util.Map;
-import java.util.Scanner;
/**
* Task for generating the markdown page describing the AuthMe hash algorithms.
@@ -20,11 +19,6 @@ public class HashAlgorithmsDescriptionTask implements AutoToolTask {
private static final String CUR_FOLDER = ToolsConstants.TOOLS_SOURCE_ROOT + "docs/hashmethods/";
private static final String OUTPUT_FILE = ToolsConstants.DOCS_FOLDER + "hash_algorithms.md";
- @Override
- public void execute(Scanner scanner) {
- executeDefault();
- }
-
@Override
public void executeDefault() {
// Gather info and construct a row for each method
@@ -34,7 +28,8 @@ public class HashAlgorithmsDescriptionTask implements AutoToolTask {
// Write to the docs file
TagValueHolder tags = TagValueHolder.create().put("algorithms", methodRows);
- FileUtils.generateFileFromTemplate(CUR_FOLDER + "hash_algorithms.tpl.md", OUTPUT_FILE, tags);
+ FileIoUtils.generateFileFromTemplate(CUR_FOLDER + "hash_algorithms.tpl.md", OUTPUT_FILE, tags);
+ System.out.println("Wrote to '" + OUTPUT_FILE + "'");
}
private static NestedTagValue constructMethodRows(Map descriptions) {
diff --git a/src/test/java/tools/docs/hashmethods/hash_algorithms.tpl.md b/src/test/java/tools/docs/hashmethods/hash_algorithms.tpl.md
index 17431eb5b..2f542b50f 100644
--- a/src/test/java/tools/docs/hashmethods/hash_algorithms.tpl.md
+++ b/src/test/java/tools/docs/hashmethods/hash_algorithms.tpl.md
@@ -1,5 +1,5 @@
-
+
## Hash Algorithms
AuthMe supports the following hash algorithms for storing your passwords safely.
diff --git a/src/test/java/tools/docs/permissions/PermissionNodesGatherer.java b/src/test/java/tools/docs/permissions/PermissionNodesGatherer.java
index f6221ac5f..e36355121 100644
--- a/src/test/java/tools/docs/permissions/PermissionNodesGatherer.java
+++ b/src/test/java/tools/docs/permissions/PermissionNodesGatherer.java
@@ -2,15 +2,17 @@ package tools.docs.permissions;
import fr.xephi.authme.ClassCollector;
import fr.xephi.authme.permission.PermissionNode;
-import tools.utils.FileUtils;
+import tools.utils.FileIoUtils;
import tools.utils.ToolsConstants;
import java.util.EnumSet;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
/**
* Gatherer to generate up-to-date lists of the AuthMe permission nodes.
@@ -27,6 +29,11 @@ public class PermissionNodesGatherer {
+ "(.*?)\\s+\\*/" // Capture everything until we encounter '*/'
+ "\\s+([A-Z_]+)\\("); // Match the enum name (e.g. 'LOGIN'), until before the first '('
+ /**
+ * List of all enum classes that implement the {@link PermissionNode} interface.
+ */
+ private List> permissionClasses;
+
/**
* Return a sorted collection of all permission nodes, including its JavaDoc description.
*
@@ -39,14 +46,27 @@ public class PermissionNodesGatherer {
result.put("authme.player.*", "Permission to use all player (non-admin) commands.");
result.put("authme.player.email", "Grants all email permissions.");
- new ClassCollector(ToolsConstants.MAIN_SOURCE_ROOT, "")
- .collectClasses(PermissionNode.class)
- .stream()
- .filter(Class::isEnum)
- .forEach(clz -> addDescriptionsForClass((Class) clz, result));
+ getPermissionClasses().forEach(clz -> addDescriptionsForClass((Class) clz, result));
return result;
}
+ /**
+ * Return all enum classes implementing the PermissionNode interface.
+ *
+ * @return all permission node enums
+ */
+ public List> getPermissionClasses() {
+ if (permissionClasses == null) {
+ ClassCollector classCollector = new ClassCollector(ToolsConstants.MAIN_SOURCE_ROOT, "");
+ permissionClasses = classCollector
+ .collectClasses(PermissionNode.class)
+ .stream()
+ .filter(Class::isEnum)
+ .collect(Collectors.toList());
+ }
+ return permissionClasses;
+ }
+
private & PermissionNode> void addDescriptionsForClass(Class clazz,
Map descriptions) {
String classSource = getSourceForClass(clazz);
@@ -83,7 +103,7 @@ public class PermissionNodesGatherer {
*/
private static & PermissionNode> String getSourceForClass(Class clazz) {
String classFile = ToolsConstants.MAIN_SOURCE_ROOT + clazz.getName().replace(".", "/") + ".java";
- return FileUtils.readFromFile(classFile);
+ return FileIoUtils.readFromFile(classFile);
}
}
diff --git a/src/test/java/tools/docs/permissions/PermissionsListWriter.java b/src/test/java/tools/docs/permissions/PermissionsListWriter.java
index 6d1b48d74..797e26e79 100644
--- a/src/test/java/tools/docs/permissions/PermissionsListWriter.java
+++ b/src/test/java/tools/docs/permissions/PermissionsListWriter.java
@@ -1,13 +1,12 @@
package tools.docs.permissions;
import tools.utils.AutoToolTask;
-import tools.utils.FileUtils;
+import tools.utils.FileIoUtils;
import tools.utils.TagValue.NestedTagValue;
import tools.utils.TagValueHolder;
import tools.utils.ToolsConstants;
import java.util.Map;
-import java.util.Scanner;
/**
* Task responsible for formatting a permissions node list and
@@ -23,23 +22,13 @@ public class PermissionsListWriter implements AutoToolTask {
return "writePermissionsList";
}
- @Override
- public void execute(Scanner scanner) {
- generateAndWriteFile();
- }
-
@Override
public void executeDefault() {
- generateAndWriteFile();
- }
-
- private static void generateAndWriteFile() {
final NestedTagValue permissionsTagValue = generatePermissionsList();
TagValueHolder tags = TagValueHolder.create().put("nodes", permissionsTagValue);
- FileUtils.generateFileFromTemplate(TEMPLATE_FILE, PERMISSIONS_OUTPUT_FILE, tags);
+ FileIoUtils.generateFileFromTemplate(TEMPLATE_FILE, PERMISSIONS_OUTPUT_FILE, tags);
System.out.println("Wrote to '" + PERMISSIONS_OUTPUT_FILE + "'");
- System.out.println("Before committing, please verify the output!");
}
private static NestedTagValue generatePermissionsList() {
diff --git a/src/test/java/tools/docs/permissions/permission_nodes.tpl.md b/src/test/java/tools/docs/permissions/permission_nodes.tpl.md
index 8d2a2b4f4..8987f08bb 100644
--- a/src/test/java/tools/docs/permissions/permission_nodes.tpl.md
+++ b/src/test/java/tools/docs/permissions/permission_nodes.tpl.md
@@ -1,5 +1,5 @@
-
+
## AuthMe Permission Nodes
The following are the permission nodes that are currently supported by the latest dev builds.
diff --git a/src/test/java/tools/docs/translations/TranslationPageGenerator.java b/src/test/java/tools/docs/translations/TranslationPageGenerator.java
index e7785bd7a..240e7a640 100644
--- a/src/test/java/tools/docs/translations/TranslationPageGenerator.java
+++ b/src/test/java/tools/docs/translations/TranslationPageGenerator.java
@@ -3,14 +3,13 @@ package tools.docs.translations;
import com.google.common.collect.ImmutableMap;
import tools.docs.translations.TranslationsGatherer.TranslationInfo;
import tools.utils.AutoToolTask;
-import tools.utils.FileUtils;
+import tools.utils.FileIoUtils;
import tools.utils.TagValue.NestedTagValue;
import tools.utils.TagValueHolder;
import tools.utils.ToolsConstants;
import java.util.Arrays;
import java.util.Map;
-import java.util.Scanner;
import java.util.stream.Collectors;
import static com.google.common.base.Objects.firstNonNull;
@@ -42,11 +41,6 @@ public class TranslationPageGenerator implements AutoToolTask {
return "updateTranslations";
}
- @Override
- public void execute(Scanner scanner) {
- executeDefault();
- }
-
@Override
public void executeDefault() {
NestedTagValue translationValuesHolder = new NestedTagValue();
@@ -63,7 +57,8 @@ public class TranslationPageGenerator implements AutoToolTask {
}
TagValueHolder tags = TagValueHolder.create().put("languages", translationValuesHolder);
- FileUtils.generateFileFromTemplate(TEMPLATE_FILE, DOCS_PAGE, tags);
+ FileIoUtils.generateFileFromTemplate(TEMPLATE_FILE, DOCS_PAGE, tags);
+ System.out.println("Wrote to '" + DOCS_PAGE + "'");
}
/**
diff --git a/src/test/java/tools/docs/translations/translations.tpl.md b/src/test/java/tools/docs/translations/translations.tpl.md
index 199d4029c..5308b6554 100644
--- a/src/test/java/tools/docs/translations/translations.tpl.md
+++ b/src/test/java/tools/docs/translations/translations.tpl.md
@@ -1,5 +1,5 @@
-
+
# AuthMe Translations
The following translations are available in AuthMe. Set `messagesLanguage` to the language code
diff --git a/src/test/java/tools/filegeneration/GeneratePluginYml.java b/src/test/java/tools/filegeneration/GeneratePluginYml.java
new file mode 100644
index 000000000..b4a017c62
--- /dev/null
+++ b/src/test/java/tools/filegeneration/GeneratePluginYml.java
@@ -0,0 +1,176 @@
+package tools.filegeneration;
+
+import com.google.common.collect.ImmutableMap;
+import fr.xephi.authme.command.CommandDescription;
+import fr.xephi.authme.command.CommandInitializer;
+import fr.xephi.authme.command.CommandUtils;
+import fr.xephi.authme.permission.DefaultPermission;
+import fr.xephi.authme.permission.PermissionNode;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.configuration.file.YamlConfiguration;
+import tools.docs.permissions.PermissionNodesGatherer;
+import tools.utils.AutoToolTask;
+import tools.utils.FileIoUtils;
+import tools.utils.ToolsConstants;
+
+import java.io.StringReader;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+
+/**
+ * Generates the command and permission section of plugin.yml.
+ */
+public class GeneratePluginYml implements AutoToolTask {
+
+ private static final String PLUGIN_YML_FILE = ToolsConstants.MAIN_RESOURCES_ROOT + "plugin.yml";
+
+ private static final Map WILDCARD_PERMISSIONS = ImmutableMap.of(
+ "authme.player.*", "Gives access to all player commands",
+ "authme.admin.*", "Gives access to all admin commands",
+ "authme.player.email", "Gives access to all email commands");
+
+ private List permissionNodes;
+
+ private String pluginYmlStart;
+
+ @Override
+ public void executeDefault() {
+ FileConfiguration configuration = loadPartialPluginYmlFile();
+
+ configuration.set("commands", generateCommands());
+ configuration.set("permissions", generatePermissions());
+
+ FileIoUtils.writeToFile(PLUGIN_YML_FILE,
+ pluginYmlStart + "\n" + configuration.saveToString());
+ }
+
+ @Override
+ public String getTaskName() {
+ return "generatePluginYml";
+ }
+
+ /**
+ * Because some parts above the commands section have placeholders that aren't valid YAML, we need
+ * to split the contents into an upper part that we ignore and a lower part we load as YAML. When
+ * saving we prepend the YAML export with the stripped off part of the file again.
+ *
+ * @return file configuration with the lower part of the plugin.yml file
+ */
+ private FileConfiguration loadPartialPluginYmlFile() {
+ List pluginYmlLines = FileIoUtils.readLinesFromFile(Paths.get(PLUGIN_YML_FILE));
+ int lineNr = 0;
+ for (String line : pluginYmlLines) {
+ if (line.equals("commands:")) {
+ break;
+ }
+ ++lineNr;
+ }
+ if (lineNr == pluginYmlLines.size()) {
+ throw new IllegalStateException("Could not find line starting 'commands:' section");
+ }
+ pluginYmlStart = String.join("\n", pluginYmlLines.subList(0, lineNr));
+ String yamlContents = String.join("\n", pluginYmlLines.subList(lineNr, pluginYmlLines.size()));
+ return YamlConfiguration.loadConfiguration(new StringReader(yamlContents));
+ }
+
+ private static Map generateCommands() {
+ Collection commands = new CommandInitializer().getCommands();
+ Map entries = new LinkedHashMap<>();
+ for (CommandDescription command : commands) {
+ entries.put(command.getLabels().get(0), buildCommandEntry(command));
+ }
+ return entries;
+ }
+
+ private Map generatePermissions() {
+ PermissionNodesGatherer gatherer = new PermissionNodesGatherer();
+ Map permissionDescriptions = gatherer.gatherNodesWithJavaDoc();
+
+ permissionNodes = gatherer.getPermissionClasses().stream()
+ // Note ljacqu 20161023: The compiler fails if we use method references below
+ .map(clz -> clz.getEnumConstants())
+ .flatMap((PermissionNode[] nodes) -> Arrays.stream(nodes))
+ .collect(Collectors.toList());
+
+ Map descriptions = new TreeMap<>();
+ for (PermissionNode node : permissionNodes) {
+ descriptions.put(node.getNode(), buildPermissionEntry(node, permissionDescriptions.get(node.getNode())));
+ }
+ addWildcardPermissions(descriptions);
+ return descriptions;
+ }
+
+ private void addWildcardPermissions(Map permissions) {
+ for (Map.Entry entry : WILDCARD_PERMISSIONS.entrySet()) {
+ permissions.put(entry.getKey(),
+ buildWildcardPermissionEntry(entry.getValue(), gatherChildren(entry.getKey())));
+ }
+ }
+
+ private Map gatherChildren(String parentNode) {
+ String parentPath = parentNode.replaceAll("\\.\\*$", "");
+
+ Map children = new TreeMap<>();
+ for (PermissionNode node : permissionNodes) {
+ if (node.getNode().startsWith(parentPath)) {
+ children.put(node.getNode(), Boolean.TRUE);
+ }
+ }
+ return children;
+ }
+
+ private static Map buildCommandEntry(CommandDescription command) {
+ if (command.getLabels().size() > 1) {
+ return ImmutableMap.of(
+ "description", command.getDescription(),
+ "usage", buildUsage(command),
+ "aliases", command.getLabels().subList(1, command.getLabels().size()));
+ } else {
+ return ImmutableMap.of(
+ "description", command.getDescription(),
+ "usage", buildUsage(command));
+ }
+ }
+
+ private static String buildUsage(CommandDescription command) {
+ if (!command.getArguments().isEmpty()) {
+ return CommandUtils.buildSyntax(command);
+ }
+ final String commandStart = "/" + command.getLabels().get(0);
+ String usage = commandStart + " " + command.getChildren()
+ .stream()
+ .filter(cmd -> !cmd.getLabels().contains("help"))
+ .map(cmd -> cmd.getLabels().get(0))
+ .collect(Collectors.joining("|"));
+ return usage.trim();
+ }
+
+ private static Map buildPermissionEntry(PermissionNode permissionNode, String description) {
+ return ImmutableMap.of(
+ "description", description,
+ "default", convertDefaultPermission(permissionNode.getDefaultPermission()));
+ }
+
+ private static Map buildWildcardPermissionEntry(String description, Map children) {
+ return ImmutableMap.of(
+ "description", description,
+ "children", children);
+ }
+
+ private static Object convertDefaultPermission(DefaultPermission defaultPermission) {
+ switch (defaultPermission) {
+ // Returning true/false as booleans will make SnakeYAML avoid using quotes
+ case ALLOWED: return true;
+ case NOT_ALLOWED: return false;
+ case OP_ONLY: return "op";
+ default:
+ throw new IllegalArgumentException("Unknown default permission '" + defaultPermission + "'");
+ }
+ }
+}
diff --git a/src/test/java/tools/helptranslation/HelpTranslationVerifier.java b/src/test/java/tools/helptranslation/HelpTranslationVerifier.java
new file mode 100644
index 000000000..9cbf12b5c
--- /dev/null
+++ b/src/test/java/tools/helptranslation/HelpTranslationVerifier.java
@@ -0,0 +1,171 @@
+package tools.helptranslation;
+
+import com.google.common.collect.Sets;
+import de.bananaco.bpermissions.imp.YamlConfiguration;
+import fr.xephi.authme.command.CommandDescription;
+import fr.xephi.authme.command.CommandInitializer;
+import fr.xephi.authme.command.CommandUtils;
+import fr.xephi.authme.command.help.HelpMessage;
+import fr.xephi.authme.command.help.HelpSection;
+import org.bukkit.configuration.MemorySection;
+import org.bukkit.configuration.file.FileConfiguration;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+/**
+ * Verifies a help messages translation.
+ */
+public class HelpTranslationVerifier {
+
+ private final FileConfiguration configuration;
+
+ // missing and unknown HelpSection and HelpMessage entries
+ private final List missingSections = new ArrayList<>();
+ private final List unknownSections = new ArrayList<>();
+ // missing and unknown command entries
+ private final List missingCommands = new ArrayList<>();
+ private final List unknownCommands = new ArrayList<>();
+
+ public HelpTranslationVerifier(File translation) {
+ this.configuration = YamlConfiguration.loadConfiguration(translation);
+ checkFile();
+ }
+
+ private void checkFile() {
+ checkHelpSections();
+ checkCommands();
+ }
+
+ public List getMissingSections() {
+ return missingSections;
+ }
+
+ public List getUnknownSections() {
+ return unknownSections;
+ }
+
+ public List getMissingCommands() {
+ // All entries start with "command.", so remove that
+ return missingCommands.stream()
+ .map(s -> s.substring(9)).collect(Collectors.toList());
+ }
+
+ public List getUnknownCommands() {
+ // All entries start with "command.", so remove that
+ return unknownCommands.stream()
+ .map(s -> s.substring(9)).collect(Collectors.toList());
+ }
+
+ /**
+ * Verifies that the file has the expected entries for {@link HelpSection} and {@link HelpMessage}.
+ */
+ private void checkHelpSections() {
+ Set knownSections = Arrays.stream(HelpSection.values())
+ .map(HelpSection::getKey).collect(Collectors.toSet());
+ knownSections.addAll(Arrays.stream(HelpMessage.values()).map(HelpMessage::getKey).collect(Collectors.toSet()));
+ knownSections.addAll(Arrays.asList("common.defaultPermissions.notAllowed",
+ "common.defaultPermissions.opOnly", "common.defaultPermissions.allowed"));
+ Set sectionKeys = getLeafKeys("section");
+ sectionKeys.addAll(getLeafKeys("common"));
+
+ if (sectionKeys.isEmpty()) {
+ missingSections.addAll(knownSections);
+ } else {
+ missingSections.addAll(Sets.difference(knownSections, sectionKeys));
+ unknownSections.addAll(Sets.difference(sectionKeys, knownSections));
+ }
+ }
+
+ /**
+ * Verifies that the file has the expected entries for AuthMe commands.
+ */
+ private void checkCommands() {
+ Set commandPaths = buildCommandPaths();
+ Set existingKeys = getLeafKeys("commands");
+ if (existingKeys.isEmpty()) {
+ missingCommands.addAll(commandPaths); // commandPaths should be empty in this case
+ } else {
+ missingCommands.addAll(Sets.difference(commandPaths, existingKeys));
+ unknownCommands.addAll(Sets.difference(existingKeys, commandPaths));
+ }
+ }
+
+ private Set buildCommandPaths() {
+ Set commandPaths = new LinkedHashSet<>();
+ for (CommandDescription command : new CommandInitializer().getCommands()) {
+ commandPaths.addAll(getYamlPaths(command));
+ command.getChildren().forEach(child -> commandPaths.addAll(getYamlPaths(child)));
+ }
+ return commandPaths;
+ }
+
+ private List getYamlPaths(CommandDescription command) {
+ // e.g. commands.authme.register
+ String commandPath = "commands." + CommandUtils.constructParentList(command).stream()
+ .map(cmd -> cmd.getLabels().get(0))
+ .collect(Collectors.joining("."));
+ // The entire command is not present, so just add it as a missing command and don't return any YAML path
+ if (!configuration.contains(commandPath)) {
+ missingCommands.add(commandPath);
+ return Collections.emptyList();
+ }
+
+ // Entries each command can have
+ List paths = newArrayList(commandPath + ".description", commandPath + ".detailedDescription");
+
+ // Add argument entries that may exist
+ for (int argIndex = 1; argIndex <= command.getArguments().size(); ++argIndex) {
+ String argPath = String.format("%s.arg%d", commandPath, argIndex);
+ paths.add(argPath + ".label");
+ paths.add(argPath + ".description");
+ }
+ return paths;
+ }
+
+ /**
+ * Returns the leaf keys of the section at the given path of the file configuration.
+ *
+ * @param path the path whose leaf keys should be retrieved
+ * @return leaf keys of the memory section,
+ * empty set if the configuration does not have a memory section at the given path
+ */
+ private Set getLeafKeys(String path) {
+ if (!(configuration.get(path) instanceof MemorySection)) {
+ return Collections.emptySet();
+ }
+ MemorySection memorySection = (MemorySection) configuration.get(path);
+
+ // MemorySection#getKeys(true) returns all keys on all levels, e.g. if the configuration has
+ // 'commands.authme.register' then it also has 'commands.authme' and 'commands'. We can traverse each node and
+ // build its parents (e.g. for commands.authme.register.description: commands.authme.register, commands.authme,
+ // and commands, which we can remove from the collection since we know they are not a leaf.
+ Set leafKeys = memorySection.getKeys(true);
+ Set allKeys = new HashSet<>(leafKeys);
+
+ for (String key : allKeys) {
+ List pathParts = Arrays.asList(key.split("\\."));
+
+ // We perform construction of parents & their removal in reverse order so we can build the lowest-level
+ // parent of a node first. As soon as the parent doesn't exist in the set already, we know we can continue
+ // with the next node since another node has already removed the concerned parents.
+ for (int i = pathParts.size() - 1; i > 0; --i) {
+ // e.g. for commands.authme.register -> i = {2, 1} => {commands.authme, commands}
+ String parentPath = String.join(".", pathParts.subList(0, i));
+ if (!leafKeys.remove(parentPath)) {
+ break;
+ }
+ }
+ }
+ return leafKeys.stream().map(leaf -> path + "." + leaf).collect(Collectors.toSet());
+ }
+}
diff --git a/src/test/java/tools/helptranslation/VerifyHelpTranslations.java b/src/test/java/tools/helptranslation/VerifyHelpTranslations.java
new file mode 100644
index 000000000..f97447bf9
--- /dev/null
+++ b/src/test/java/tools/helptranslation/VerifyHelpTranslations.java
@@ -0,0 +1,72 @@
+package tools.helptranslation;
+
+import tools.utils.ToolTask;
+import tools.utils.ToolsConstants;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Scanner;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+/**
+ * Verifies the help translations for validity and completeness.
+ */
+public class VerifyHelpTranslations implements ToolTask {
+
+ private static final Pattern HELP_MESSAGE_PATTERN = Pattern.compile("help_[a-z]{2,7}\\.yml");
+ private static final String FOLDER = ToolsConstants.MAIN_RESOURCES_ROOT + "messages/";
+
+ @Override
+ public String getTaskName() {
+ return "verifyHelpTranslations";
+ }
+
+ @Override
+ public void execute(Scanner scanner) {
+ System.out.println("Check specific language file?");
+ System.out.println("Enter the language code for a specific file (e.g. 'it' for help_it.yml)");
+ System.out.println("Empty line will check all files in the resources messages folder (default)");
+
+ String language = scanner.nextLine();
+ if (language.isEmpty()) {
+ getHelpTranslations().forEach(this::processFile);
+ } else {
+ processFile(new File(FOLDER, "help_" + language + ".yml"));
+ }
+ }
+
+ private void processFile(File file) {
+ System.out.println("Checking '" + file.getName() + "'");
+ HelpTranslationVerifier verifier = new HelpTranslationVerifier(file);
+
+ // Check and output errors
+ if (!verifier.getMissingSections().isEmpty()) {
+ System.out.println("Missing sections: " + String.join(", ", verifier.getMissingSections()));
+ }
+ if (!verifier.getUnknownSections().isEmpty()) {
+ System.out.println("Unknown sections: " + String.join(", ", verifier.getUnknownSections()));
+ }
+ if (!verifier.getMissingCommands().isEmpty()) {
+ System.out.println("Missing command entries: " + String.join(", ", verifier.getMissingCommands()));
+ }
+ if (!verifier.getUnknownCommands().isEmpty()) {
+ System.out.println("Unknown command entries: " + String.join(", ", verifier.getUnknownCommands()));
+ }
+ }
+
+ private static List getHelpTranslations() {
+ File[] files = new File(FOLDER).listFiles();
+ if (files == null) {
+ throw new IllegalStateException("Could not get files from '" + FOLDER + "'");
+ }
+ List helpFiles = Arrays.stream(files)
+ .filter(file -> HELP_MESSAGE_PATTERN.matcher(file.getName()).matches())
+ .collect(Collectors.toList());
+ if (helpFiles.isEmpty()) {
+ throw new IllegalStateException("Could not get any matching files!");
+ }
+ return helpFiles;
+ }
+}
diff --git a/src/test/java/tools/messages/MessageFileVerifier.java b/src/test/java/tools/messages/MessageFileVerifier.java
index f0be6bb44..b151228c1 100644
--- a/src/test/java/tools/messages/MessageFileVerifier.java
+++ b/src/test/java/tools/messages/MessageFileVerifier.java
@@ -8,7 +8,7 @@ import com.google.common.collect.Multimap;
import fr.xephi.authme.message.MessageKey;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
-import tools.utils.FileUtils;
+import tools.utils.FileIoUtils;
import java.io.File;
import java.util.ArrayList;
@@ -104,7 +104,7 @@ public class MessageFileVerifier {
* @param defaultMessages The collection of default messages
*/
public void addMissingKeys(FileConfiguration defaultMessages) {
- final List fileLines = FileUtils.readLinesFromFile(messagesFile.toPath());
+ final List fileLines = FileIoUtils.readLinesFromFile(messagesFile.toPath());
List keysToAdd = new ArrayList<>();
for (MissingKey entry : missingKeys) {
@@ -135,7 +135,7 @@ public class MessageFileVerifier {
addCommentForMissingTags(fileLines, key, entry.getValue());
}
- FileUtils.writeToFile(messagesFile.toPath(), String.join("\n", fileLines));
+ FileIoUtils.writeToFile(messagesFile.toPath(), String.join("\n", fileLines));
}
/**
diff --git a/src/test/java/tools/messages/translation/ImportMessagesTask.java b/src/test/java/tools/messages/translation/ImportMessagesTask.java
index c70caaa3a..765c49f1f 100644
--- a/src/test/java/tools/messages/translation/ImportMessagesTask.java
+++ b/src/test/java/tools/messages/translation/ImportMessagesTask.java
@@ -7,7 +7,7 @@ import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import tools.messages.MessageFileVerifier;
import tools.messages.VerifyMessagesTask;
-import tools.utils.FileUtils;
+import tools.utils.FileIoUtils;
import tools.utils.ToolTask;
import tools.utils.ToolsConstants;
@@ -108,9 +108,9 @@ public class ImportMessagesTask implements ToolTask {
* @param file The file whose to-do comments should be removed
*/
private static void removeAllTodoComments(String file) {
- String contents = FileUtils.readFromFile(file);
+ String contents = FileIoUtils.readFromFile(file);
String regex = "^# TODO .*$";
contents = Pattern.compile(regex, Pattern.MULTILINE).matcher(contents).replaceAll("");
- FileUtils.writeToFile(file, contents);
+ FileIoUtils.writeToFile(file, contents);
}
}
diff --git a/src/test/java/tools/messages/translation/WriteAllExportsTask.java b/src/test/java/tools/messages/translation/WriteAllExportsTask.java
index f5f3825bc..f0faf3b03 100644
--- a/src/test/java/tools/messages/translation/WriteAllExportsTask.java
+++ b/src/test/java/tools/messages/translation/WriteAllExportsTask.java
@@ -2,7 +2,7 @@ package tools.messages.translation;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
-import tools.utils.FileUtils;
+import tools.utils.FileIoUtils;
import tools.utils.ToolsConstants;
import java.io.File;
@@ -31,7 +31,7 @@ public class WriteAllExportsTask extends ExportMessagesTask {
for (File file : messageFiles) {
String code = file.getName().substring("messages_".length(), file.getName().length() - ".yml".length());
String json = convertToJson(code, defaultMessages, YamlConfiguration.loadConfiguration(file));
- FileUtils.writeToFile(OUTPUT_FOLDER + "messages_" + code + ".json", json);
+ FileIoUtils.writeToFile(OUTPUT_FOLDER + "messages_" + code + ".json", json);
}
}
}
diff --git a/src/test/java/tools/utils/AutoToolTask.java b/src/test/java/tools/utils/AutoToolTask.java
index b635fe5fe..61b909a52 100644
--- a/src/test/java/tools/utils/AutoToolTask.java
+++ b/src/test/java/tools/utils/AutoToolTask.java
@@ -1,5 +1,7 @@
package tools.utils;
+import java.util.Scanner;
+
/**
* Interface for tasks that can be run automatically, i.e. without any user input.
*/
@@ -10,4 +12,9 @@ public interface AutoToolTask extends ToolTask {
*/
void executeDefault();
+ @Override
+ default void execute(Scanner scanner) {
+ executeDefault();
+ }
+
}
diff --git a/src/test/java/tools/utils/FileUtils.java b/src/test/java/tools/utils/FileIoUtils.java
similarity index 86%
rename from src/test/java/tools/utils/FileUtils.java
rename to src/test/java/tools/utils/FileIoUtils.java
index 44bf5a296..4683633f9 100644
--- a/src/test/java/tools/utils/FileUtils.java
+++ b/src/test/java/tools/utils/FileIoUtils.java
@@ -9,11 +9,11 @@ import java.nio.file.StandardOpenOption;
import java.util.List;
/**
- * Utility class for reading from and writing to files.
+ * Utility class for I/O operations on files.
*/
-public final class FileUtils {
+public final class FileIoUtils {
- private FileUtils() {
+ private FileIoUtils() {
}
public static void generateFileFromTemplate(String templateFile, String destinationFile, TagValueHolder tags) {
@@ -43,8 +43,12 @@ public final class FileUtils {
}
public static String readFromFile(String file) {
+ return readFromFile(Paths.get(file));
+ }
+
+ public static String readFromFile(Path file) {
try {
- return new String(Files.readAllBytes(Paths.get(file)), StandardCharsets.UTF_8);
+ return new String(Files.readAllBytes(file), StandardCharsets.UTF_8);
} catch (IOException e) {
throw new UnsupportedOperationException("Could not read from file '" + file + "'", e);
}
diff --git a/src/test/java/tools/utils/ToolsConstants.java b/src/test/java/tools/utils/ToolsConstants.java
index 5986c378b..e7ba3e05a 100644
--- a/src/test/java/tools/utils/ToolsConstants.java
+++ b/src/test/java/tools/utils/ToolsConstants.java
@@ -9,9 +9,6 @@ public final class ToolsConstants {
public static final String MAIN_RESOURCES_ROOT = "src/main/resources/";
- // Add specific `fr.xephi.authme` package as not to include the tool tasks in the `tools` package
- public static final String TEST_SOURCE_ROOT = "src/test/java/fr/xephi/authme";
-
public static final String TOOLS_SOURCE_ROOT = "src/test/java/tools/";
public static final String DOCS_FOLDER = "docs/";