mirror of
https://github.com/AuthMe/AuthMeReloaded.git
synced 2025-01-02 05:58:08 +01:00
Settings: use class constants for properties, create custom writer
- Create Property class for defining config properties - Create logic for typed retrival of properties from YAML file - Add custom save method - Retain comments from Comment annotations in the classes - Write in a sorted order: first discovered properties are first written to config.yml - Adjust properties to reflect the current config.yml - Add sample tests for the retrieval and writing of properties with the new setup
This commit is contained in:
parent
c2deb9d0b5
commit
7d41ccbc9c
@ -1,46 +1,32 @@
|
||||
package fr.xephi.authme.settings.custom;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import fr.xephi.authme.settings.custom.domain.Comment;
|
||||
import fr.xephi.authme.settings.custom.domain.Property;
|
||||
import fr.xephi.authme.settings.custom.domain.SettingsClass;
|
||||
|
||||
import fr.xephi.authme.settings.custom.annotations.Comment;
|
||||
import fr.xephi.authme.settings.custom.annotations.Type;
|
||||
import fr.xephi.authme.settings.custom.annotations.Type.SettingType;
|
||||
import static fr.xephi.authme.settings.custom.domain.Property.newProperty;
|
||||
import static fr.xephi.authme.settings.custom.domain.PropertyType.BOOLEAN;
|
||||
import static fr.xephi.authme.settings.custom.domain.PropertyType.STRING;
|
||||
|
||||
public class ConverterSettings extends CustomSetting {
|
||||
public class ConverterSettings implements SettingsClass {
|
||||
|
||||
@Comment("Rakamak file name")
|
||||
@Type(SettingType.String)
|
||||
public String rakamakFileName = "users.rak";
|
||||
public static final Property<String> RAKAMAK_FILE_NAME =
|
||||
newProperty(STRING, "Converter.Rakamak.fileName", "users.rak");
|
||||
|
||||
@Comment("Rakamak use Ip ?")
|
||||
@Type(SettingType.Boolean)
|
||||
public boolean rakamakeUseIP = false;
|
||||
@Comment("Rakamak use IP?")
|
||||
public static final Property<Boolean> RAKAMAK_USE_IP =
|
||||
newProperty(BOOLEAN, "Converter.Rakamak.useIP", false);
|
||||
|
||||
@Comment("Rakamak IP file name")
|
||||
@Type(SettingType.String)
|
||||
public String rakamakIPFileName = "UsersIp.rak";
|
||||
public static final Property<String> RAKAMAK_IP_FILE_NAME =
|
||||
newProperty(STRING, "Converter.Rakamak.ipFileName", "UsersIp.rak");
|
||||
|
||||
@Comment("CrazyLogin database file name")
|
||||
@Type(SettingType.String)
|
||||
public String crazyLoginFileName = "accounts.db";
|
||||
public static final Property<String> CRAZYLOGIN_FILE_NAME =
|
||||
newProperty(STRING, "Converter.CrazyLogin.fileName", "accounts.db");
|
||||
|
||||
private static File configFile = new File("." + File.separator + "plugins" + File.separator + "AuthMe" + File.separator + "converter.yml");
|
||||
private ConverterSettings() {
|
||||
}
|
||||
|
||||
private ConverterSettings instance;
|
||||
|
||||
public ConverterSettings()
|
||||
{
|
||||
super(configFile);
|
||||
instance = this;
|
||||
}
|
||||
|
||||
public ConverterSettings getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void setInstance(ConverterSettings instance) {
|
||||
this.instance = instance;
|
||||
}
|
||||
}
|
||||
|
@ -1,156 +0,0 @@
|
||||
package fr.xephi.authme.settings.custom;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.settings.CustomConfiguration;
|
||||
import fr.xephi.authme.settings.custom.annotations.Comment;
|
||||
import fr.xephi.authme.settings.custom.annotations.Type;
|
||||
|
||||
public class CustomSetting extends CustomConfiguration {
|
||||
|
||||
private File configFile;
|
||||
public boolean isFirstLaunch = false;
|
||||
|
||||
public CustomSetting(File file) {
|
||||
super(file);
|
||||
this.configFile = file;
|
||||
try {
|
||||
if (!configFile.exists())
|
||||
{
|
||||
isFirstLaunch = true;
|
||||
configFile.createNewFile();
|
||||
}
|
||||
else
|
||||
{
|
||||
load();
|
||||
loadValues();
|
||||
}
|
||||
save();
|
||||
} catch (IOException e)
|
||||
{
|
||||
ConsoleLogger.writeStackTrace(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean reLoad()
|
||||
{
|
||||
boolean out = true;
|
||||
if (!configFile.exists()) {
|
||||
try {
|
||||
configFile.createNewFile();
|
||||
save();
|
||||
} catch (IOException e) {
|
||||
out = false;
|
||||
}
|
||||
}
|
||||
if (out)
|
||||
{
|
||||
load();
|
||||
loadValues();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
public void loadValues()
|
||||
{
|
||||
for (Field f : this.getClass().getDeclaredFields())
|
||||
{
|
||||
if (!f.isAnnotationPresent(Type.class))
|
||||
continue;
|
||||
f.setAccessible(true);
|
||||
try {
|
||||
switch (f.getAnnotation(Type.class).value())
|
||||
{
|
||||
case Boolean:
|
||||
f.setBoolean(this, this.getBoolean(f.getName()));
|
||||
break;
|
||||
case Double:
|
||||
f.setDouble(this, this.getDouble(f.getName()));
|
||||
break;
|
||||
case Int:
|
||||
f.setInt(this, this.getInt(f.getName()));
|
||||
break;
|
||||
case Long:
|
||||
f.setLong(this, this.getLong(f.getName()));
|
||||
break;
|
||||
case String:
|
||||
f.set(this, this.getString(f.getName()));
|
||||
break;
|
||||
case StringList:
|
||||
f.set(this, this.getStringList(f.getName()));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} catch (Exception e)
|
||||
{
|
||||
ConsoleLogger.writeStackTrace(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save()
|
||||
{
|
||||
FileWriter writer = null;
|
||||
try {
|
||||
writer = new FileWriter(configFile);
|
||||
writer.write("");
|
||||
for (Field f : this.getClass().getDeclaredFields())
|
||||
{
|
||||
if (!f.isAnnotationPresent(Comment.class))
|
||||
continue;
|
||||
if (!f.isAnnotationPresent(Type.class))
|
||||
continue;
|
||||
for (String s : f.getAnnotation(Comment.class).value())
|
||||
{
|
||||
writer.append("# " + s + "\n");
|
||||
}
|
||||
writer.append(f.getName() + ": ");
|
||||
switch (f.getAnnotation(Type.class).value())
|
||||
{
|
||||
case Boolean:
|
||||
writer.append(f.getBoolean(this) ? "true" : "false");
|
||||
break;
|
||||
case Double:
|
||||
writer.append("" + f.getDouble(this));
|
||||
break;
|
||||
case Int:
|
||||
writer.append("" + f.getInt(this));
|
||||
break;
|
||||
case String:
|
||||
writer.append("'" + f.get(this).toString() + "'");
|
||||
break;
|
||||
case StringList:
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> list = (List<String>) f.get(this);
|
||||
writer.append("\n");
|
||||
if (list.isEmpty())
|
||||
writer.write("[]");
|
||||
else
|
||||
for (String s : list)
|
||||
writer.append(" - '" + s + "'\n");
|
||||
break;
|
||||
case Long:
|
||||
writer.append("" + f.getLong(this));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
writer.append("\n");
|
||||
writer.flush();
|
||||
}
|
||||
writer.close();
|
||||
} catch (Exception e) {
|
||||
ConsoleLogger.writeStackTrace(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,121 +1,109 @@
|
||||
package fr.xephi.authme.settings.custom;
|
||||
|
||||
import java.io.File;
|
||||
import fr.xephi.authme.settings.custom.domain.Comment;
|
||||
import fr.xephi.authme.settings.custom.domain.Property;
|
||||
import fr.xephi.authme.settings.custom.domain.SettingsClass;
|
||||
|
||||
import fr.xephi.authme.settings.custom.annotations.Comment;
|
||||
import fr.xephi.authme.settings.custom.annotations.Type;
|
||||
import fr.xephi.authme.settings.custom.annotations.Type.SettingType;
|
||||
import static fr.xephi.authme.settings.custom.domain.Property.newProperty;
|
||||
import static fr.xephi.authme.settings.custom.domain.PropertyType.BOOLEAN;
|
||||
import static fr.xephi.authme.settings.custom.domain.PropertyType.STRING;
|
||||
|
||||
public class DatabaseSettings extends CustomSetting {
|
||||
public class DatabaseSettings implements SettingsClass {
|
||||
|
||||
@Comment({"What type of database do you want to use?",
|
||||
"Valid values: sqlite, mysql"})
|
||||
@Type(SettingType.String)
|
||||
public String backend = "sqlite";
|
||||
public static final Property<String> BACKEND =
|
||||
newProperty(STRING, "DataSource.backend", "sqlite");
|
||||
|
||||
@Comment("Enable database caching, should improve database performance")
|
||||
@Type(SettingType.Boolean)
|
||||
public boolean caching = true;
|
||||
public static final Property<Boolean> USE_CACHING =
|
||||
newProperty(BOOLEAN, "DataSource.caching", true);
|
||||
|
||||
@Comment("Database host address")
|
||||
@Type(SettingType.String)
|
||||
public String mySQLHost = "127.0.0.1";
|
||||
public static final Property<String> MYSQL_HOST =
|
||||
newProperty(STRING, "DataSource.mySQLHost", "127.0.0.1");
|
||||
|
||||
@Comment("Database port")
|
||||
@Type(SettingType.String)
|
||||
public String mySQLPort = "3306";
|
||||
public static final Property<String> MYSQL_PORT =
|
||||
newProperty(STRING, "DataSource.mySQLPort", "3306");
|
||||
|
||||
@Comment("Username about Database Connection Infos")
|
||||
@Type(SettingType.String)
|
||||
public String mySQLUsername = "authme";
|
||||
public static final Property<String> MYSQL_USERNAME =
|
||||
newProperty(STRING, "DataSource.mySQLUsername", "authme");
|
||||
|
||||
@Comment("Password about Database Connection Infos")
|
||||
@Type(SettingType.String)
|
||||
public String mySQLPassword = "12345";
|
||||
public static final Property<String> MYSQL_PASSWORD =
|
||||
newProperty(STRING, "DataSource.mySQLPassword", "123456");
|
||||
|
||||
@Comment("Database Name, use with converters or as SQLITE database name")
|
||||
@Type(SettingType.String)
|
||||
public String mySQLDatabase = "authme";
|
||||
public static final Property<String> MYSQL_DATABASE =
|
||||
newProperty(STRING, "DataSource.mySQLDatabase", "authme");
|
||||
|
||||
@Comment("Table of the database")
|
||||
@Type(SettingType.String)
|
||||
public String mySQLTablename = "authme";
|
||||
public static final Property<String> MYSQL_TABLE =
|
||||
newProperty(STRING, "DataSource.mySQLTablename", "authme");
|
||||
|
||||
@Comment("Column of IDs to sort data")
|
||||
@Type(SettingType.String)
|
||||
public String mySQLColumnId = "id";
|
||||
public static final Property<String> MYSQL_COL_ID =
|
||||
newProperty(STRING, "DataSource.mySQLColumnId", "id");
|
||||
|
||||
@Comment("Column for storing or checking players nickname")
|
||||
@Type(SettingType.String)
|
||||
public String mySQLColumnName = "username";
|
||||
public static final Property<String> MYSQL_COL_NAME =
|
||||
newProperty(STRING, "DataSource.mySQLColumnName", "username");
|
||||
|
||||
@Comment("Column for storing or checking players RealName ")
|
||||
@Type(SettingType.String)
|
||||
public String mySQLColumnRealName = "realname";
|
||||
public static final Property<String> MYSQL_COL_REALNAME =
|
||||
newProperty(STRING, "DataSource.mySQLRealName", "realname");
|
||||
|
||||
@Comment("Column for storing players passwords")
|
||||
@Type(SettingType.String)
|
||||
public String mySQLColumnPassword = "password";
|
||||
public static final Property<String> MYSQL_COL_PASSWORD =
|
||||
newProperty(STRING, "DataSource.mySQLColumnPassword", "password");
|
||||
|
||||
@Comment("Column for storing players passwords salts")
|
||||
@Type(SettingType.String)
|
||||
public String mySQLColumnSalt = "";
|
||||
public static final Property<String> MYSQL_COL_SALT =
|
||||
newProperty(STRING, "ExternalBoardOptions.mySQLColumnSalt", "");
|
||||
|
||||
@Comment("Column for storing players emails")
|
||||
@Type(SettingType.String)
|
||||
public String mySQLColumnEmail = "email";
|
||||
public static final Property<String> MYSQL_COL_EMAIL =
|
||||
newProperty(STRING, "DataSource.mySQLColumnEmail", "email");
|
||||
|
||||
@Comment("Column for storing if a player is logged in or not")
|
||||
@Type(SettingType.String)
|
||||
public String mySQLColumnLogged = "isLogged";
|
||||
public static final Property<String> MYSQL_COL_ISLOGGED =
|
||||
newProperty(STRING, "DataSource.mySQLColumnLogged", "isLogged");
|
||||
|
||||
@Comment("Column for storing players ips")
|
||||
@Type(SettingType.String)
|
||||
public String mySQLColumnIp = "ip";
|
||||
public static final Property<String> MYSQL_COL_IP =
|
||||
newProperty(STRING, "DataSource.mySQLColumnIp", "ip");
|
||||
|
||||
@Comment("Column for storing players lastlogins")
|
||||
@Type(SettingType.String)
|
||||
public String mySQLColumnLastLogin = "lastlogin";
|
||||
public static final Property<String> MYSQL_COL_LASTLOGIN =
|
||||
newProperty(STRING, "DataSource.mySQLColumnLastLogin", "lastlogin");
|
||||
|
||||
@Comment("Column for storing player LastLocation - X")
|
||||
@Type(SettingType.String)
|
||||
public String mySQLColumnLastLocX = "x";
|
||||
public static final Property<String> MYSQL_COL_LASTLOC_X =
|
||||
newProperty(STRING, "DataSource.mySQLlastlocX", "x");
|
||||
|
||||
@Comment("Column for storing player LastLocation - Y")
|
||||
@Type(SettingType.String)
|
||||
public String mySQLColumnLastLocY = "y";
|
||||
public static final Property<String> MYSQL_COL_LASTLOC_Y =
|
||||
newProperty(STRING, "DataSource.mySQLlastlocY", "y");
|
||||
|
||||
@Comment("Column for storing player LastLocation - Z")
|
||||
@Type(SettingType.String)
|
||||
public String mySQLColumnLastLocZ = "z";
|
||||
public static final Property<String> MYSQL_COL_LASTLOC_Z =
|
||||
newProperty(STRING, "DataSource.mySQLlastlocZ", "z");
|
||||
|
||||
@Comment("Column for storing player LastLocation - World Name")
|
||||
@Type(SettingType.String)
|
||||
public String mySQLColumnLastLocWorld = "world";
|
||||
public static final Property<String> MYSQL_COL_LASTLOC_WORLD =
|
||||
newProperty(STRING, "DataSource.mySQLlastlocWorld", "world");
|
||||
|
||||
@Comment("Column for storing players groups")
|
||||
@Type(SettingType.String)
|
||||
public String mySQLColumnGroup = "";
|
||||
public static final Property<String> MYSQL_COL_GROUP =
|
||||
newProperty(STRING, "ExternalBoardOptions.mySQLColumnGroup", "");
|
||||
|
||||
@Comment("Enable this when you allow registration through a website")
|
||||
@Type(SettingType.Boolean)
|
||||
public boolean mySQLWebsite = false;
|
||||
public static final Property<Boolean> MYSQL_WEBSITE =
|
||||
newProperty(BOOLEAN, "DataSource.mySQLWebsite", false);
|
||||
|
||||
private static File configFile = new File("." + File.separator + "plugins" + File.separator + "AuthMe" + File.separator + "database.yml");
|
||||
|
||||
private DatabaseSettings instance;
|
||||
|
||||
public DatabaseSettings()
|
||||
{
|
||||
super(configFile);
|
||||
instance = this;
|
||||
private DatabaseSettings() {
|
||||
}
|
||||
|
||||
public DatabaseSettings getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void setInstance(DatabaseSettings instance) {
|
||||
this.instance = instance;
|
||||
}
|
||||
}
|
||||
|
@ -1,83 +1,72 @@
|
||||
package fr.xephi.authme.settings.custom;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import fr.xephi.authme.settings.custom.domain.Comment;
|
||||
import fr.xephi.authme.settings.custom.domain.Property;
|
||||
import fr.xephi.authme.settings.custom.domain.SettingsClass;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import fr.xephi.authme.settings.custom.annotations.Comment;
|
||||
import fr.xephi.authme.settings.custom.annotations.Type;
|
||||
import fr.xephi.authme.settings.custom.annotations.Type.SettingType;
|
||||
import static fr.xephi.authme.settings.custom.domain.Property.newProperty;
|
||||
import static fr.xephi.authme.settings.custom.domain.PropertyType.BOOLEAN;
|
||||
import static fr.xephi.authme.settings.custom.domain.PropertyType.INTEGER;
|
||||
import static fr.xephi.authme.settings.custom.domain.PropertyType.STRING;
|
||||
import static fr.xephi.authme.settings.custom.domain.PropertyType.STRING_LIST;
|
||||
|
||||
public class EmailSettings extends CustomSetting {
|
||||
public class EmailSettings implements SettingsClass {
|
||||
|
||||
@Comment("Email SMTP server host")
|
||||
@Type(SettingType.String)
|
||||
public String mailSMTP = "smtp.gmail.com";
|
||||
public static final Property<String> SMTP_HOST =
|
||||
newProperty(STRING, "Email.mailSMTP", "smtp.gmail.com");
|
||||
|
||||
@Comment("Email SMTP server port")
|
||||
@Type(SettingType.Int)
|
||||
public int mailPort = 465;
|
||||
public static final Property<Integer> SMTP_PORT =
|
||||
newProperty(INTEGER, "Email.mailPort", 465);
|
||||
|
||||
@Comment("Email account whose send the mail")
|
||||
@Type(SettingType.String)
|
||||
public String mailAccount = "";
|
||||
@Comment("Email account which sends the mails")
|
||||
public static final Property<String> MAIL_ACCOUNT =
|
||||
newProperty(STRING, "Email.mailAccount", "");
|
||||
|
||||
@Comment("Email account password")
|
||||
@Type(SettingType.String)
|
||||
public String mailPassword = "";
|
||||
public static final Property<String> MAIL_PASSWORD =
|
||||
newProperty(STRING, "Email.mailPassword", "");
|
||||
|
||||
@Comment("Random password length")
|
||||
@Type(SettingType.Int)
|
||||
public int recoveryPasswordLength = 8;
|
||||
@Comment("Recovery password length")
|
||||
public static final Property<Integer> RECOVERY_PASSWORD_LENGTH =
|
||||
newProperty(INTEGER, "Email.RecoveryPasswordLength", 8);
|
||||
|
||||
@Comment("Mail Subject")
|
||||
@Type(SettingType.String)
|
||||
public String mailSubject = "Your new AuthMe password";
|
||||
public static final Property<String> RECOVERY_MAIL_SUBJECT =
|
||||
newProperty(STRING, "Email.mailSubject", "Your new AuthMe password");
|
||||
|
||||
@Comment("Like maxRegPerIP but with email")
|
||||
@Type(SettingType.Int)
|
||||
public int maxRegPerEmail = 1;
|
||||
public static final Property<Integer> MAX_REG_PER_EMAIL =
|
||||
newProperty(INTEGER, "Email.maxRegPerEmail", 1);
|
||||
|
||||
@Comment("Recall players to add an email ?")
|
||||
@Type(SettingType.Boolean)
|
||||
public boolean recallPlayers = false;
|
||||
@Comment("Recall players to add an email?")
|
||||
public static final Property<Boolean> RECALL_PLAYERS =
|
||||
newProperty(BOOLEAN, "Email.recallPlayers", false);
|
||||
|
||||
@Comment("Delay in minute for the recall scheduler")
|
||||
@Type(SettingType.Int)
|
||||
public int delayRecall = 5;
|
||||
public static final Property<Integer> DELAY_RECALL =
|
||||
newProperty(INTEGER, "Email.delayRecall", 5);
|
||||
|
||||
@Comment("Blacklist these domains for emails")
|
||||
@Type(SettingType.StringList)
|
||||
public List<String> emailBlackListed = new ArrayList<String>();
|
||||
public static final Property<List<String>> DOMAIN_BLACKLIST =
|
||||
newProperty(STRING_LIST, "Email.emailBlacklisted", "10minutemail.com");
|
||||
|
||||
@Comment("Whitelist ONLY these domains for emails")
|
||||
@Type(SettingType.StringList)
|
||||
public List<String> emailWhiteListed = new ArrayList<String>();
|
||||
public static final Property<List<String>> DOMAIN_WHITELIST =
|
||||
newProperty(STRING_LIST, "Email.emailWhitelisted");
|
||||
|
||||
@Comment("Do we need to send new password draw in an image ?")
|
||||
@Type(SettingType.Boolean)
|
||||
public boolean generateImage = false;
|
||||
@Comment("Send the new password drawn in an image?")
|
||||
public static final Property<Boolean> PASSWORD_AS_IMAGE =
|
||||
newProperty(BOOLEAN, "Email.generateImage", false);
|
||||
|
||||
private static File configFile = new File("." + File.separator + "plugins" + File.separator + "AuthMe" + File.separator + "emails.yml");
|
||||
@Comment("The OAuth2 token")
|
||||
public static final Property<String> OAUTH2_TOKEN =
|
||||
newProperty(STRING, "Email.emailOauth2Token", "");
|
||||
|
||||
private EmailSettings instance;
|
||||
private EmailSettings() {
|
||||
}
|
||||
|
||||
public EmailSettings()
|
||||
{
|
||||
super(configFile);
|
||||
instance = this;
|
||||
if (this.isFirstLaunch)
|
||||
{
|
||||
this.emailBlackListed.add("10minutemail.com");
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
||||
public EmailSettings getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void setInstance(EmailSettings instance) {
|
||||
this.instance = instance;
|
||||
}
|
||||
}
|
||||
|
@ -1,54 +1,39 @@
|
||||
package fr.xephi.authme.settings.custom;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import fr.xephi.authme.settings.custom.domain.Comment;
|
||||
import fr.xephi.authme.settings.custom.domain.Property;
|
||||
import fr.xephi.authme.settings.custom.domain.PropertyType;
|
||||
import fr.xephi.authme.settings.custom.domain.SettingsClass;
|
||||
|
||||
import fr.xephi.authme.settings.custom.annotations.Comment;
|
||||
import fr.xephi.authme.settings.custom.annotations.Type;
|
||||
import fr.xephi.authme.settings.custom.annotations.Type.SettingType;
|
||||
import static fr.xephi.authme.settings.custom.domain.Property.newProperty;
|
||||
|
||||
public class HooksSettings extends CustomSetting {
|
||||
public class HooksSettings implements SettingsClass {
|
||||
|
||||
@Comment("Do we need to hook with multiverse for spawn checking?")
|
||||
@Type(SettingType.Boolean)
|
||||
public boolean multiverse = true;
|
||||
public static final Property<Boolean> MULTIVERSE =
|
||||
newProperty(PropertyType.BOOLEAN, "Hooks.multiverse", true);
|
||||
|
||||
@Comment("Do we need to hook with BungeeCord ?")
|
||||
@Type(SettingType.Boolean)
|
||||
public boolean bungeecord = false;
|
||||
@Comment("Do we need to hook with BungeeCord?")
|
||||
public static final Property<Boolean> BUNGEECORD =
|
||||
newProperty(PropertyType.BOOLEAN, "Hooks.bungeecord", false);
|
||||
|
||||
@Comment("Send player to this BungeeCord server after register/login")
|
||||
@Type(SettingType.String)
|
||||
public String sendPlayerTo = "";
|
||||
public static final Property<String> BUNGEECORD_SERVER =
|
||||
newProperty(PropertyType.STRING, "bungeecord.server", "");
|
||||
|
||||
@Comment("Do we need to disable Essentials SocialSpy on join?")
|
||||
@Type(SettingType.Boolean)
|
||||
public boolean disableSocialSpy = false;
|
||||
public static final Property<Boolean> DISABLE_SOCIAL_SPY =
|
||||
newProperty(PropertyType.BOOLEAN, "Hooks.disableSocialSpy", false);
|
||||
|
||||
@Comment("Do we need to force /motd Essentials command on join?")
|
||||
@Type(SettingType.Boolean)
|
||||
public boolean useEssentialsMotd = false;
|
||||
public static final Property<Boolean> USE_ESSENTIALS_MOTD =
|
||||
newProperty(PropertyType.BOOLEAN, "Hooks.useEssentialsMotd", false);
|
||||
|
||||
@Comment("Do we need to cache custom Attributes?")
|
||||
@Type(SettingType.Boolean)
|
||||
public boolean customAttributes = false;
|
||||
public static final Property<Boolean> CACHE_CUSTOM_ATTRIBUTES =
|
||||
newProperty(PropertyType.BOOLEAN, "Hooks.customAttributes", false);
|
||||
|
||||
private static File configFile = new File("." + File.separator + "plugins" + File.separator + "AuthMe" + File.separator + "hooks.yml");
|
||||
private HooksSettings() {
|
||||
}
|
||||
|
||||
private HooksSettings instance;
|
||||
|
||||
public HooksSettings()
|
||||
{
|
||||
super(configFile);
|
||||
instance = this;
|
||||
}
|
||||
|
||||
public HooksSettings getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void setInstance(HooksSettings instance) {
|
||||
this.instance = instance;
|
||||
}
|
||||
}
|
||||
|
148
src/main/java/fr/xephi/authme/settings/custom/NewSetting.java
Normal file
148
src/main/java/fr/xephi/authme/settings/custom/NewSetting.java
Normal file
@ -0,0 +1,148 @@
|
||||
package fr.xephi.authme.settings.custom;
|
||||
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.settings.custom.domain.Comment;
|
||||
import fr.xephi.authme.settings.custom.domain.Property;
|
||||
import fr.xephi.authme.settings.custom.domain.SettingsClass;
|
||||
import fr.xephi.authme.settings.custom.propertymap.PropertyMap;
|
||||
import fr.xephi.authme.util.CollectionUtils;
|
||||
import fr.xephi.authme.util.StringUtils;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The new settings manager.
|
||||
*/
|
||||
public class NewSetting {
|
||||
|
||||
private static final List<Class<? extends SettingsClass>> CONFIGURATION_CLASSES = Arrays.asList(
|
||||
ConverterSettings.class, DatabaseSettings.class, EmailSettings.class, HooksSettings.class,
|
||||
ProtectionSettings.class, PurgeSettings.class, SecuritySettings.class);
|
||||
|
||||
private static final int YAML_INDENTATION = 4;
|
||||
|
||||
private File file;
|
||||
private YamlConfiguration configuration;
|
||||
|
||||
public NewSetting(File file) {
|
||||
this.configuration = YamlConfiguration.loadConfiguration(file);
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
// TODO: No way of passing just a YamlConfiguration object (later on for mocking purposes) ?
|
||||
// If not, best is probably to keep this constructor as package-private with @VisibleForTesting
|
||||
// but it's not a satisfying solution
|
||||
public NewSetting(YamlConfiguration yamlConfiguration, String file) {
|
||||
this.configuration = yamlConfiguration;
|
||||
this.file = new File(file);
|
||||
}
|
||||
|
||||
public <T> T getOption(Property<T> property) {
|
||||
return property.getFromFile(configuration);
|
||||
}
|
||||
|
||||
public void save() {
|
||||
PropertyMap properties = getAllPropertyFields();
|
||||
|
||||
try (FileWriter writer = new FileWriter(file)) {
|
||||
writer.write("");
|
||||
|
||||
// Contains all but the last node of the setting, e.g. [DataSource, mysql] for "DataSource.mysql.username"
|
||||
List<String> currentPath = new ArrayList<>();
|
||||
for (Map.Entry<Property, String[]> entry : properties.entrySet()) {
|
||||
Property<?> property = entry.getKey();
|
||||
|
||||
// Handle properties
|
||||
List<String> propertyPath = Arrays.asList(property.getPath().split("\\."));
|
||||
List<String> commonPathParts = CollectionUtils.filterCommonStart(
|
||||
currentPath, propertyPath.subList(0, propertyPath.size() - 1));
|
||||
List<String> newPathParts = CollectionUtils.getRange(propertyPath, commonPathParts.size());
|
||||
|
||||
if (commonPathParts.isEmpty()) {
|
||||
writer.append("\n");
|
||||
}
|
||||
|
||||
int indentationLevel = commonPathParts.size();
|
||||
if (newPathParts.size() > 1) {
|
||||
for (String path : newPathParts.subList(0, newPathParts.size() - 1)) {
|
||||
writer.append("\n")
|
||||
.append(StringUtils.repeat(" ", indentationLevel * YAML_INDENTATION))
|
||||
.append(path)
|
||||
.append(": ");
|
||||
++indentationLevel;
|
||||
}
|
||||
}
|
||||
for (String comment : entry.getValue()) {
|
||||
writer.append("\n")
|
||||
.append(StringUtils.repeat(" ", indentationLevel * YAML_INDENTATION))
|
||||
.append("# ")
|
||||
.append(comment);
|
||||
}
|
||||
writer.append("\n")
|
||||
.append(StringUtils.repeat(" ", indentationLevel * YAML_INDENTATION))
|
||||
.append(CollectionUtils.getRange(newPathParts, newPathParts.size() - 1).get(0))
|
||||
.append(": ");
|
||||
|
||||
List<String> yamlLines = property.formatValueAsYaml(configuration);
|
||||
String delim = "";
|
||||
for (String yamlLine : yamlLines) {
|
||||
writer.append(delim).append(yamlLine);
|
||||
delim = "\n" + StringUtils.repeat(" ", indentationLevel * YAML_INDENTATION);
|
||||
}
|
||||
|
||||
currentPath = propertyPath.subList(0, propertyPath.size() - 1);
|
||||
}
|
||||
writer.flush();
|
||||
writer.close();
|
||||
} catch (IOException e) {
|
||||
ConsoleLogger.showError("Could not save config file - " + StringUtils.formatException(e));
|
||||
ConsoleLogger.writeStackTrace(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static PropertyMap getAllPropertyFields() {
|
||||
PropertyMap properties = new PropertyMap();
|
||||
for (Class<?> clazz : CONFIGURATION_CLASSES) {
|
||||
Field[] declaredFields = clazz.getDeclaredFields();
|
||||
for (Field field : declaredFields) {
|
||||
Property property = getFieldIfRelevant(field);
|
||||
if (property != null) {
|
||||
properties.put(property, getCommentsForField(field));
|
||||
}
|
||||
}
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
private static String[] getCommentsForField(Field field) {
|
||||
if (field.isAnnotationPresent(Comment.class)) {
|
||||
return field.getAnnotation(Comment.class).value();
|
||||
}
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
private static Property<?> getFieldIfRelevant(Field field) {
|
||||
field.setAccessible(true);
|
||||
if (field.isAccessible() && Property.class.equals(field.getType()) && Modifier.isStatic(field.getModifiers())) {
|
||||
try {
|
||||
return (Property) field.get(null);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalStateException("Could not fetch field '" + field.getName() + "' from class '"
|
||||
+ field.getDeclaringClass().getSimpleName() + "': " + StringUtils.formatException(e));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,63 +1,46 @@
|
||||
package fr.xephi.authme.settings.custom;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import fr.xephi.authme.settings.custom.domain.Comment;
|
||||
import fr.xephi.authme.settings.custom.domain.Property;
|
||||
import fr.xephi.authme.settings.custom.domain.SettingsClass;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import fr.xephi.authme.settings.custom.annotations.Comment;
|
||||
import fr.xephi.authme.settings.custom.annotations.Type;
|
||||
import fr.xephi.authme.settings.custom.annotations.Type.SettingType;
|
||||
import static fr.xephi.authme.settings.custom.domain.Property.newProperty;
|
||||
import static fr.xephi.authme.settings.custom.domain.PropertyType.BOOLEAN;
|
||||
import static fr.xephi.authme.settings.custom.domain.PropertyType.INTEGER;
|
||||
import static fr.xephi.authme.settings.custom.domain.PropertyType.STRING_LIST;
|
||||
|
||||
public class ProtectionSettings extends CustomSetting {
|
||||
|
||||
@Comment("Enable some servers protection ( country based login, antibot )")
|
||||
@Type(SettingType.Boolean)
|
||||
public boolean enableProtection = false;
|
||||
public class ProtectionSettings implements SettingsClass {
|
||||
|
||||
@Comment("Enable some servers protection (country based login, antibot)")
|
||||
public static final Property<Boolean> ENABLE_PROTECTION =
|
||||
newProperty(BOOLEAN, "Protection.enableProtection", false);
|
||||
|
||||
@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 !"})
|
||||
@Type(SettingType.StringList)
|
||||
public List<String> countriesWhitelist = new ArrayList<String>();
|
||||
"PLEASE USE QUOTES!"})
|
||||
public static final Property<List<String>> COUNTRIES_WHITELIST =
|
||||
newProperty(STRING_LIST, "Protection.countries", "US", "GB", "A1");
|
||||
|
||||
@Comment({"Countries not allowed to join the server and register",
|
||||
"PLEASE USE QUOTES !"})
|
||||
@Type(SettingType.StringList)
|
||||
public List<String> countriesBlacklist = new ArrayList<String>();
|
||||
"PLEASE USE QUOTES!"})
|
||||
public static final Property<List<String>> COUNTRIES_BLACKLIST =
|
||||
newProperty(STRING_LIST, "Protection.countriesBlacklist");
|
||||
|
||||
@Comment("Do we need to enable automatic antibot system?")
|
||||
@Type(SettingType.Boolean)
|
||||
public boolean enableAntiBot = false;
|
||||
public static final Property<Boolean> ENABLE_ANTIBOT =
|
||||
newProperty(BOOLEAN, "Protection.enableAntiBot", false);
|
||||
|
||||
@Comment("Max number of player allowed to login in 5 secs before enable AntiBot system automatically")
|
||||
@Type(SettingType.Int)
|
||||
public int antiBotSensibility = 5;
|
||||
public static final Property<Integer> ANTIBOT_SENSIBILITY =
|
||||
newProperty(INTEGER, "Protection.antiBotSensibility", 5);
|
||||
|
||||
@Comment("Duration in minutes of the antibot automatic system")
|
||||
@Type(SettingType.Int)
|
||||
public int antiBotDuration = 10;
|
||||
public static final Property<Integer> ANTIBOT_DURATION =
|
||||
newProperty(INTEGER, "Protection.antiBotDuration", 10);
|
||||
|
||||
private static File configFile = new File("." + File.separator + "plugins" + File.separator + "AuthMe" + File.separator + "protection.yml");
|
||||
private ProtectionSettings() {
|
||||
}
|
||||
|
||||
private ProtectionSettings instance;
|
||||
|
||||
public ProtectionSettings()
|
||||
{
|
||||
super(configFile);
|
||||
instance = this;
|
||||
if (this.isFirstLaunch)
|
||||
{
|
||||
this.countriesWhitelist.add("US");
|
||||
this.countriesWhitelist.add("GB");
|
||||
this.countriesBlacklist.add("A1");
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
||||
public ProtectionSettings getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void setInstance(ProtectionSettings instance) {
|
||||
this.instance = instance;
|
||||
}
|
||||
}
|
||||
|
@ -1,62 +1,49 @@
|
||||
package fr.xephi.authme.settings.custom;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import fr.xephi.authme.settings.custom.domain.Comment;
|
||||
import fr.xephi.authme.settings.custom.domain.Property;
|
||||
import fr.xephi.authme.settings.custom.domain.SettingsClass;
|
||||
|
||||
import fr.xephi.authme.settings.custom.annotations.Comment;
|
||||
import fr.xephi.authme.settings.custom.annotations.Type;
|
||||
import fr.xephi.authme.settings.custom.annotations.Type.SettingType;
|
||||
import static fr.xephi.authme.settings.custom.domain.Property.newProperty;
|
||||
import static fr.xephi.authme.settings.custom.domain.PropertyType.BOOLEAN;
|
||||
import static fr.xephi.authme.settings.custom.domain.PropertyType.INTEGER;
|
||||
import static fr.xephi.authme.settings.custom.domain.PropertyType.STRING;
|
||||
|
||||
public class PurgeSettings extends CustomSetting {
|
||||
public class PurgeSettings implements SettingsClass {
|
||||
|
||||
@Comment("If enabled, AuthMe automatically purges old, unused accounts")
|
||||
@Type(SettingType.Boolean)
|
||||
public boolean useAutoPurge = false;
|
||||
public static final Property<Boolean> USE_AUTO_PURGE =
|
||||
newProperty(BOOLEAN, "Purge.useAutoPurge", false);
|
||||
|
||||
@Comment("Number of Days an account become Unused")
|
||||
@Type(SettingType.Int)
|
||||
public int daysBeforeRemovePlayer = 60;
|
||||
public static final Property<Integer> DAYS_BEFORE_REMOVE_PLAYER =
|
||||
newProperty(INTEGER, "Purge.daysBeforeRemovePlayer", 60);
|
||||
|
||||
@Comment("Do we need to remove the player.dat file during purge process?")
|
||||
@Type(SettingType.Boolean)
|
||||
public boolean removePlayerDat = false;
|
||||
public static final Property<Boolean> REMOVE_PLAYER_DAT =
|
||||
newProperty(BOOLEAN, "Purge.removePlayerDat", false);
|
||||
|
||||
@Comment("Do we need to remove the Essentials/users/player.yml file during purge process?")
|
||||
@Type(SettingType.Boolean)
|
||||
public boolean removeEssentialsFiles = false;
|
||||
public static final Property<Boolean> REMOVE_ESSENTIALS_FILES =
|
||||
newProperty(BOOLEAN, "Purge.removeEssentialsFiles", false);
|
||||
|
||||
@Comment("World where are players.dat stores")
|
||||
@Type(SettingType.String)
|
||||
public String defaultWorld = "world";
|
||||
public static final Property<String> DEFAULT_WORLD =
|
||||
newProperty(STRING, "Purge.defaultWorld", "world");
|
||||
|
||||
@Comment("Do we need to remove LimitedCreative/inventories/player.yml, player_creative.yml files during purge process ?")
|
||||
@Type(SettingType.Boolean)
|
||||
public boolean removeLimiteCreativeInventories = false;
|
||||
public static final Property<Boolean> REMOVE_LIMITED_CREATIVE_INVENTORIES =
|
||||
newProperty(BOOLEAN, "Purge.removeLimitedCreativesInventories", false);
|
||||
|
||||
@Comment("Do we need to remove the AntiXRayData/PlayerData/player file during purge process?")
|
||||
@Type(SettingType.Boolean)
|
||||
public boolean removeAntiXRayFile = false;
|
||||
public static final Property<Boolean> REMOVE_ANTI_XRAY_FILE =
|
||||
newProperty(BOOLEAN, "Purge.removeAntiXRayFile", false);
|
||||
|
||||
@Comment("Do we need to remove permissions?")
|
||||
@Type(SettingType.Boolean)
|
||||
public boolean removePermissions = false;
|
||||
public static final Property<Boolean> REMOVE_PERMISSIONS =
|
||||
newProperty(BOOLEAN, "Purge.removePermissions", false);
|
||||
|
||||
private static File configFile = new File("." + File.separator + "plugins" + File.separator + "AuthMe" + File.separator + "purge.yml");
|
||||
private PurgeSettings() {
|
||||
}
|
||||
|
||||
private PurgeSettings instance;
|
||||
|
||||
public PurgeSettings()
|
||||
{
|
||||
super(configFile);
|
||||
instance = this;
|
||||
}
|
||||
|
||||
public PurgeSettings getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void setInstance(PurgeSettings instance) {
|
||||
this.instance = instance;
|
||||
}
|
||||
}
|
||||
|
@ -1,60 +1,51 @@
|
||||
package fr.xephi.authme.settings.custom;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import fr.xephi.authme.settings.custom.domain.Comment;
|
||||
import fr.xephi.authme.settings.custom.domain.Property;
|
||||
import fr.xephi.authme.settings.custom.domain.SettingsClass;
|
||||
|
||||
import fr.xephi.authme.settings.custom.annotations.Comment;
|
||||
import fr.xephi.authme.settings.custom.annotations.Type;
|
||||
import fr.xephi.authme.settings.custom.annotations.Type.SettingType;
|
||||
import static fr.xephi.authme.settings.custom.domain.Property.newProperty;
|
||||
import static fr.xephi.authme.settings.custom.domain.PropertyType.BOOLEAN;
|
||||
import static fr.xephi.authme.settings.custom.domain.PropertyType.INTEGER;
|
||||
|
||||
public class SecuritySettings extends CustomSetting {
|
||||
public class SecuritySettings implements SettingsClass {
|
||||
|
||||
@Comment({"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!"})
|
||||
@Type(SettingType.Boolean)
|
||||
public boolean stopServerOnProblem = true;
|
||||
"Take care with this, if you set this to false,",
|
||||
"AuthMe will automatically disable and the server won't be protected!"})
|
||||
public static final Property<Boolean> STOP_SERVER_ON_PROBLEM =
|
||||
newProperty(BOOLEAN, "Security.SQLProblem.stopServer", true);
|
||||
|
||||
@Comment("/reload support")
|
||||
@Type(SettingType.Boolean)
|
||||
public boolean useReloadCommandSupport = true;
|
||||
public static final Property<Boolean> USE_RELOAD_COMMAND_SUPPORT =
|
||||
newProperty(BOOLEAN, "Security.ReloadCommand.useReloadCommandSupport", true);
|
||||
|
||||
@Comment("Remove Spam from Console ?")
|
||||
@Type(SettingType.Boolean)
|
||||
public boolean removeSpamFromConsole = false;
|
||||
@Comment("Remove spam from console?")
|
||||
public static final Property<Boolean> REMOVE_SPAM_FROM_CONSOLE =
|
||||
newProperty(BOOLEAN, "Security.console.noConsoleSpam", false);
|
||||
|
||||
@Comment("Remove Password from Console ?")
|
||||
@Type(SettingType.Boolean)
|
||||
public boolean removePasswordFromConsole = true;
|
||||
@Comment("Remove passwords from console?")
|
||||
public static final Property<Boolean> REMOVE_PASSWORD_FROM_CONSOLE =
|
||||
newProperty(BOOLEAN, "Security.console.removePassword", true);
|
||||
|
||||
@Comment("Player need to put a captcha when he fails too lot the password")
|
||||
@Type(SettingType.Boolean)
|
||||
public boolean useCaptcha = false;
|
||||
public static final Property<Boolean> USE_CAPTCHA =
|
||||
newProperty(BOOLEAN, "Security.captcha.useCaptcha", false);
|
||||
|
||||
@Comment("Max allowed tries before request a captcha")
|
||||
@Type(SettingType.Int)
|
||||
public int maxLoginTryBeforeCaptcha = 5;
|
||||
public static final Property<Integer> MAX_LOGIN_TRIES_BEFORE_CAPTCHA =
|
||||
newProperty(INTEGER, "Security.captcha.maxLoginTry", 5);
|
||||
|
||||
@Comment("Captcha length ")
|
||||
@Type(SettingType.Int)
|
||||
public int captchaLength = 5;
|
||||
@Comment("Captcha length")
|
||||
public static final Property<Integer> CAPTCHA_LENGTH =
|
||||
newProperty(INTEGER, "Security.captcha.captchaLength", 5);
|
||||
|
||||
private static File configFile = new File("." + File.separator + "plugins" + File.separator + "AuthMe" + File.separator + "security.yml");
|
||||
@Comment({"Kick players before stopping the server, that allow us to save position of players",
|
||||
"and all needed information correctly without any corruption."})
|
||||
public static final Property<Boolean> KICK_PLAYERS_BEFORE_STOPPING =
|
||||
newProperty(BOOLEAN, "Security.stop.kickPlayersBeforeStopping", true);
|
||||
|
||||
private SecuritySettings instance;
|
||||
private SecuritySettings() {
|
||||
}
|
||||
|
||||
public SecuritySettings()
|
||||
{
|
||||
super(configFile);
|
||||
instance = this;
|
||||
}
|
||||
|
||||
public SecuritySettings getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void setInstance(SecuritySettings instance) {
|
||||
this.instance = instance;
|
||||
}
|
||||
}
|
||||
|
@ -1,43 +0,0 @@
|
||||
package fr.xephi.authme.settings.custom.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import fr.xephi.authme.settings.custom.annotations.Type.SettingType;
|
||||
|
||||
/**
|
||||
*
|
||||
* Set the type of a field value
|
||||
*
|
||||
* @author xephi59
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Type {
|
||||
|
||||
public enum SettingType {
|
||||
String(0),
|
||||
Int(1),
|
||||
Boolean(2),
|
||||
Double(3),
|
||||
StringList(4),
|
||||
Long(5);
|
||||
|
||||
private int type;
|
||||
|
||||
SettingType(int type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public int getType()
|
||||
{
|
||||
return this.type;
|
||||
}
|
||||
}
|
||||
|
||||
public SettingType value() default SettingType.String;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package fr.xephi.authme.settings.custom.annotations;
|
||||
package fr.xephi.authme.settings.custom.domain;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
@ -6,15 +6,12 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
*
|
||||
* Add a comment to a field value
|
||||
*
|
||||
* @author xephi59
|
||||
*
|
||||
* Comment for properties which are also included in the YAML file upon saving.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Comment {
|
||||
|
||||
public String[] value() default "";
|
||||
String[] value() default "";
|
||||
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
package fr.xephi.authme.settings.custom.domain;
|
||||
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Properties (i.e. a <i>setting</i> that is read from the config.yml file).
|
||||
*/
|
||||
public class Property<T> {
|
||||
|
||||
private final PropertyType<T> type;
|
||||
private final String path;
|
||||
private final T defaultValue;
|
||||
|
||||
private Property(PropertyType<T> type, String path, T defaultValue) {
|
||||
Objects.requireNonNull(defaultValue);
|
||||
this.type = type;
|
||||
this.path = path;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public static <T> Property<T> newProperty(PropertyType<T> type, String path, T defaultValue) {
|
||||
return new Property<>(type, path, defaultValue);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <U> Property<List<U>> newProperty(PropertyType<List<U>> type, String path, U... defaultValues) {
|
||||
return new Property<>(type, path, Arrays.asList(defaultValues));
|
||||
}
|
||||
|
||||
// -----
|
||||
// Overloaded convenience methods for specific types
|
||||
// -----
|
||||
public static Property<Boolean> newProperty(String path, boolean defaultValue) {
|
||||
return new Property<>(PropertyType.BOOLEAN, path, defaultValue);
|
||||
}
|
||||
|
||||
public static Property<Integer> newProperty(String path, int defaultValue) {
|
||||
return new Property<>(PropertyType.INTEGER, path, defaultValue);
|
||||
}
|
||||
|
||||
public static Property<String> newProperty(String path, String defaultValue) {
|
||||
return new Property<>(PropertyType.STRING, path, defaultValue);
|
||||
}
|
||||
|
||||
// -----
|
||||
// Hooks to the PropertyType methods
|
||||
// -----
|
||||
|
||||
/**
|
||||
* Get the property value from the given configuration.
|
||||
*
|
||||
* @param configuration The configuration to read the value from
|
||||
* @return The value, or default if not present
|
||||
*/
|
||||
public T getFromFile(YamlConfiguration configuration) {
|
||||
return type.getFromFile(this, configuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the property value as YAML.
|
||||
*
|
||||
* @param configuration The configuration to read the value from
|
||||
* @return The property value as YAML
|
||||
*/
|
||||
public List<String> formatValueAsYaml(YamlConfiguration configuration) {
|
||||
return type.asYaml(this, configuration);
|
||||
}
|
||||
|
||||
// -----
|
||||
// Trivial getters
|
||||
// -----
|
||||
|
||||
/**
|
||||
* Return the default value of the property.
|
||||
*
|
||||
* @return The default value
|
||||
*/
|
||||
public T getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property path (i.e. the node at which this property is located in the YAML file).
|
||||
*
|
||||
* @return The path
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Property '" + path + "'";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,146 @@
|
||||
package fr.xephi.authme.settings.custom.domain;
|
||||
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
/**
|
||||
* Handles a certain property type and provides type-specific functionality.
|
||||
*
|
||||
* @param <T> The value of the property
|
||||
* @see Property
|
||||
*/
|
||||
public abstract class PropertyType<T> {
|
||||
|
||||
public static final PropertyType<Boolean> BOOLEAN = new BooleanProperty();
|
||||
public static final PropertyType<Double> DOUBLE = new DoubleProperty();
|
||||
public static final PropertyType<Integer> INTEGER = new IntegerProperty();
|
||||
public static final PropertyType<String> STRING = new StringProperty();
|
||||
public static final PropertyType<List<String>> STRING_LIST = new StringListProperty();
|
||||
|
||||
/**
|
||||
* Get the property's value from the given YAML configuration.
|
||||
*
|
||||
* @param property The property to retrieve
|
||||
* @param configuration The YAML configuration to read from
|
||||
* @return The read value, or the default value if absent
|
||||
*/
|
||||
public abstract T getFromFile(Property<T> property, YamlConfiguration configuration);
|
||||
|
||||
/**
|
||||
* Return the property's value (or its default) as YAML.
|
||||
*
|
||||
* @param property The property to transform
|
||||
* @param configuration The YAML configuration to read from
|
||||
* @return The read value or its default in YAML format
|
||||
*/
|
||||
public List<String> asYaml(Property<T> property, YamlConfiguration configuration) {
|
||||
return asYaml(getFromFile(property, configuration));
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the given value to YAML.
|
||||
*
|
||||
* @param value The value to transform
|
||||
* @return The value as YAML
|
||||
*/
|
||||
protected abstract List<String> asYaml(T value);
|
||||
|
||||
|
||||
/**
|
||||
* Boolean property.
|
||||
*/
|
||||
private static final class BooleanProperty extends PropertyType<Boolean> {
|
||||
@Override
|
||||
public Boolean getFromFile(Property<Boolean> property, YamlConfiguration configuration) {
|
||||
return configuration.getBoolean(property.getPath(), property.getDefaultValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> asYaml(Boolean value) {
|
||||
return asList(value ? "true" : "false");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Double property.
|
||||
*/
|
||||
private static final class DoubleProperty extends PropertyType<Double> {
|
||||
@Override
|
||||
public Double getFromFile(Property<Double> property, YamlConfiguration configuration) {
|
||||
return configuration.getDouble(property.getPath(), property.getDefaultValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> asYaml(Double value) {
|
||||
return asList(String.valueOf(value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Integer property.
|
||||
*/
|
||||
private static final class IntegerProperty extends PropertyType<Integer> {
|
||||
@Override
|
||||
public Integer getFromFile(Property<Integer> property, YamlConfiguration configuration) {
|
||||
return configuration.getInt(property.getPath(), property.getDefaultValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> asYaml(Integer value) {
|
||||
return asList(String.valueOf(value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* String property.
|
||||
*/
|
||||
private static final class StringProperty extends PropertyType<String> {
|
||||
@Override
|
||||
public String getFromFile(Property<String> property, YamlConfiguration configuration) {
|
||||
return configuration.getString(property.getPath(), property.getDefaultValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> asYaml(String value) {
|
||||
return asList(toYamlLiteral(value));
|
||||
}
|
||||
|
||||
public static String toYamlLiteral(String str) {
|
||||
// TODO: Need to handle new lines properly
|
||||
return "'" + str.replace("'", "''") + "'";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* String list property.
|
||||
*/
|
||||
private static final class StringListProperty extends PropertyType<List<String>> {
|
||||
@Override
|
||||
public List<String> getFromFile(Property<List<String>> property, YamlConfiguration configuration) {
|
||||
if (!configuration.isList(property.getPath())) {
|
||||
return property.getDefaultValue();
|
||||
}
|
||||
return configuration.getStringList(property.getPath());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> asYaml(List<String> value) {
|
||||
if (value.isEmpty()) {
|
||||
return asList("[]");
|
||||
}
|
||||
|
||||
List<String> resultLines = new ArrayList<>();
|
||||
resultLines.add(""); // add
|
||||
for (String entry : value) {
|
||||
// TODO: StringProperty#toYamlLiteral will return List<String>...
|
||||
resultLines.add(" - " + StringProperty.toYamlLiteral(entry));
|
||||
}
|
||||
return resultLines;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package fr.xephi.authme.settings.custom.domain;
|
||||
|
||||
/**
|
||||
* Marker for classes that define {@link Property} fields.
|
||||
*/
|
||||
public interface SettingsClass {
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
package fr.xephi.authme.settings.custom.propertymap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Node class for building a tree from supplied String paths, ordered by insertion.
|
||||
* <p>
|
||||
* For instance, consider a tree to which the following paths are inserted (in the given order):
|
||||
* "animal.bird.duck", "color.yellow", "animal.rodent.rat", "animal.rodent.rabbit", "color.red".
|
||||
* For such a tree:<ul>
|
||||
* <li>"animal" (or any of its children) is sorted before "color" (or any of its children)</li>
|
||||
* <li>"animal.bird" or any child thereof is sorted before "animal.rodent"</li>
|
||||
* <li>"animal.rodent.rat" comes before "animal.rodent.rabbit"</li>
|
||||
* </ul>
|
||||
*
|
||||
* @see PropertyMapComparator
|
||||
*/
|
||||
final class Node {
|
||||
|
||||
private final String name;
|
||||
private final List<Node> children;
|
||||
|
||||
private Node(String name) {
|
||||
this.name = name;
|
||||
this.children = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a root node, i.e. the starting node for a new tree. Call this method to create
|
||||
* a new tree and always pass this root to other methods.
|
||||
*
|
||||
* @return The generated root node.
|
||||
*/
|
||||
public static Node createRoot() {
|
||||
return new Node(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a node to the root, creating any intermediary children that don't exist.
|
||||
*
|
||||
* @param root The root to add the path to
|
||||
* @param fullPath The entire path of the node to add, separate by periods
|
||||
*/
|
||||
public static void addNode(Node root, String fullPath) {
|
||||
String[] pathParts = fullPath.split("\\.");
|
||||
Node parent = root;
|
||||
for (String part : pathParts) {
|
||||
Node child = parent.getChild(part);
|
||||
if (child == null) {
|
||||
child = new Node(part);
|
||||
parent.children.add(child);
|
||||
}
|
||||
parent = child;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two nodes by this class' sorting behavior (insertion order).
|
||||
* Note that this method assumes that both supplied paths exist in the tree.
|
||||
*
|
||||
* @param root The root of the tree
|
||||
* @param fullPath1 The full path to the first node
|
||||
* @param fullPath2 The full path to the second node
|
||||
* @return The comparison result, in the same format as {@link Comparable#compareTo}
|
||||
*/
|
||||
public static int compare(Node root, String fullPath1, String fullPath2) {
|
||||
String[] path1 = fullPath1.split("\\.");
|
||||
String[] path2 = fullPath2.split("\\.");
|
||||
|
||||
int commonCount = 0;
|
||||
Node commonNode = root;
|
||||
while (commonCount < path1.length && commonCount < path2.length
|
||||
&& path1[commonCount].equals(path2[commonCount]) && commonNode != null) {
|
||||
commonNode = commonNode.getChild(path1[commonCount]);
|
||||
++commonCount;
|
||||
}
|
||||
|
||||
if (commonNode == null) {
|
||||
System.err.println("Could not find common node for '" + fullPath1 + "' at index " + commonCount);
|
||||
return fullPath1.compareTo(fullPath2); // fallback
|
||||
} else if (commonCount >= path1.length || commonCount >= path2.length) {
|
||||
return Integer.compare(path1.length, path2.length);
|
||||
}
|
||||
int child1Index = commonNode.getChildIndex(path1[commonCount]);
|
||||
int child2Index = commonNode.getChildIndex(path2[commonCount]);
|
||||
return Integer.compare(child1Index, child2Index);
|
||||
}
|
||||
|
||||
private Node getChild(String name) {
|
||||
for (Node child : children) {
|
||||
if (child.name.equals(name)) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the child's index, i.e. the position at which it was inserted to its parent.
|
||||
*
|
||||
* @param name The name of the node
|
||||
* @return The insertion index
|
||||
*/
|
||||
private int getChildIndex(String name) {
|
||||
int i = 0;
|
||||
for (Node child : children) {
|
||||
if (child.name.equals(name)) {
|
||||
return i;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Node '" + name + "'";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package fr.xephi.authme.settings.custom.propertymap;
|
||||
|
||||
import fr.xephi.authme.settings.custom.domain.Property;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* Class wrapping a {@code Map<Property, String[]>} for storing properties and their associated
|
||||
* comments with custom ordering.
|
||||
*
|
||||
* @see PropertyMapComparator for details about the map's order
|
||||
*/
|
||||
public class PropertyMap {
|
||||
|
||||
private Map<Property, String[]> propertyMap;
|
||||
private PropertyMapComparator comparator;
|
||||
|
||||
/**
|
||||
* Create a new property map.
|
||||
*/
|
||||
public PropertyMap() {
|
||||
comparator = new PropertyMapComparator();
|
||||
propertyMap = new TreeMap<>(comparator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new property to the map.
|
||||
*
|
||||
* @param property The property to add
|
||||
* @param comments The comments associated to the property
|
||||
*/
|
||||
public void put(Property property, String[] comments) {
|
||||
comparator.add(property);
|
||||
propertyMap.put(property, comments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the entry set of the map.
|
||||
*
|
||||
* @return The entry set
|
||||
*/
|
||||
public Set<Map.Entry<Property, String[]>> entrySet() {
|
||||
return propertyMap.entrySet();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package fr.xephi.authme.settings.custom.propertymap;
|
||||
|
||||
import fr.xephi.authme.settings.custom.domain.Property;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* Custom comparator for {@link PropertyMap}. It guarantees that the map's entries:
|
||||
* <ul>
|
||||
* <li>are grouped by path, e.g. all "DataSource.mysql" properties are together, and "DataSource.mysql" properties
|
||||
* are within the broader "DataSource" group.</li>
|
||||
* <li>are ordered by insertion, e.g. if the first "DataSource" property is inserted before the first "security"
|
||||
* property, then "DataSource" properties will come before the "security" ones.</li>
|
||||
* </ul>
|
||||
*/
|
||||
final class PropertyMapComparator implements Comparator<Property> {
|
||||
|
||||
private Node parent = Node.createRoot();
|
||||
|
||||
/**
|
||||
* Method to call when adding a new property to the map (as to retain its insertion time).
|
||||
*
|
||||
* @param property The property that is being added
|
||||
*/
|
||||
public void add(Property property) {
|
||||
Node.addNode(parent, property.getPath());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(Property p1, Property p2) {
|
||||
return Node.compare(parent, p1.getPath(), p2.getPath());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return this == obj;
|
||||
}
|
||||
|
||||
}
|
@ -3,6 +3,7 @@ package fr.xephi.authme.util;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Utils class for collections.
|
||||
@ -58,4 +59,17 @@ public final class CollectionUtils {
|
||||
public static <T> boolean isEmpty(Collection<T> coll) {
|
||||
return coll == null || coll.isEmpty();
|
||||
}
|
||||
|
||||
public static <T> List<T> filterCommonStart(List<T> coll1, List<T> coll2) {
|
||||
List<T> commonStart = new ArrayList<>();
|
||||
int minSize = Math.min(coll1.size(), coll2.size());
|
||||
for (int i = 0; i < minSize; ++i) {
|
||||
if (Objects.equals(coll1.get(i), coll2.get(i))) {
|
||||
commonStart.add(coll1.get(i));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return commonStart;
|
||||
}
|
||||
}
|
||||
|
@ -117,4 +117,12 @@ public final class StringUtils {
|
||||
return "[" + th.getClass().getSimpleName() + "]: " + th.getMessage();
|
||||
}
|
||||
|
||||
public static String repeat(String str, int times) {
|
||||
StringBuilder sb = new StringBuilder(str.length() * times);
|
||||
for (int i = 0; i < times; ++i) {
|
||||
sb.append(str);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,111 @@
|
||||
package fr.xephi.authme.settings.custom;
|
||||
|
||||
import fr.xephi.authme.settings.custom.domain.Property;
|
||||
import fr.xephi.authme.settings.custom.domain.PropertyType;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.junit.Test;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
import static fr.xephi.authme.settings.custom.domain.Property.newProperty;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Matchers.anyBoolean;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
public class NewSettingTest {
|
||||
|
||||
private static final String CONFIG_FILE = "437-config-test.yml";
|
||||
|
||||
@Test
|
||||
public void shouldReturnIntegerFromFile() {
|
||||
// given
|
||||
YamlConfiguration file = mock(YamlConfiguration.class);
|
||||
Property<Integer> config = TestConfiguration.DURATION_IN_SECONDS;
|
||||
given(file.getInt("test.duration", 4)).willReturn(18);
|
||||
NewSetting settings = new NewSetting(file, "conf.txt");
|
||||
|
||||
// when
|
||||
int retrieve = settings.getOption(config);
|
||||
|
||||
// then
|
||||
assertThat(retrieve, equalTo(18));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldLoadAllConfigs() {
|
||||
// given
|
||||
YamlConfiguration file = mock(YamlConfiguration.class);
|
||||
|
||||
given(file.getString(anyString(), anyString())).willAnswer(new Answer<String>() {
|
||||
@Override
|
||||
public String answer(InvocationOnMock invocation) throws Throwable {
|
||||
// Return the second parameter -> the default
|
||||
return (String) invocation.getArguments()[1];
|
||||
}
|
||||
});
|
||||
|
||||
given(file.getInt(eq(EmailSettings.RECOVERY_PASSWORD_LENGTH.getPath()), anyInt()))
|
||||
.willReturn(20);
|
||||
given(file.getBoolean(eq(SecuritySettings.REMOVE_PASSWORD_FROM_CONSOLE.getPath()), anyBoolean()))
|
||||
.willReturn(false);
|
||||
|
||||
// when
|
||||
NewSetting settings = new NewSetting(file, "conf.txt");
|
||||
|
||||
// then
|
||||
// Expect the value we told the YAML mock to return:
|
||||
assertThat(settings.getOption(EmailSettings.RECOVERY_PASSWORD_LENGTH), equalTo(20));
|
||||
// Expect the default:
|
||||
assertThat(settings.getOption(EmailSettings.SMTP_HOST), equalTo(EmailSettings.SMTP_HOST.getDefaultValue()));
|
||||
// Expect the value we told the YAML mock to return:
|
||||
assertThat(settings.getOption(SecuritySettings.REMOVE_PASSWORD_FROM_CONSOLE), equalTo(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executeIntegrationTest() {
|
||||
// given
|
||||
YamlConfiguration yamlFile = YamlConfiguration.loadConfiguration(getConfigFile());
|
||||
NewSetting settings = new NewSetting(yamlFile, "conf.txt");
|
||||
|
||||
// when
|
||||
int result = settings.getOption(TestConfiguration.DURATION_IN_SECONDS);
|
||||
String systemName = settings.getOption(TestConfiguration.SYSTEM_NAME);
|
||||
String helpHeader = settings.getOption(newProperty("settings.helpHeader", ""));
|
||||
List<String> unsafePasswords = settings.getOption(
|
||||
newProperty(PropertyType.STRING_LIST, "Security.unsafePasswords"));
|
||||
|
||||
// then
|
||||
assertThat(result, equalTo(22));
|
||||
assertThat(systemName, equalTo(TestConfiguration.SYSTEM_NAME.getDefaultValue()));
|
||||
assertThat(helpHeader, equalTo("AuthMeReloaded"));
|
||||
assertThat(unsafePasswords, contains("123456", "qwerty", "54321"));
|
||||
}
|
||||
|
||||
private File getConfigFile() {
|
||||
URL url = getClass().getClassLoader().getResource(CONFIG_FILE);
|
||||
if (url == null) {
|
||||
throw new RuntimeException("File '" + CONFIG_FILE + "' could not be loaded");
|
||||
}
|
||||
return new File(url.getFile());
|
||||
}
|
||||
|
||||
private static class TestConfiguration {
|
||||
|
||||
public static final Property<Integer> DURATION_IN_SECONDS =
|
||||
newProperty("test.duration", 4);
|
||||
|
||||
public static final Property<String> SYSTEM_NAME =
|
||||
newProperty("test.systemName", "[TestDefaultValue]");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package fr.xephi.authme.settings.custom;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
/**
|
||||
* Test for the save() function of new settings
|
||||
*/
|
||||
public class NewSettingsWriteTest {
|
||||
|
||||
private static final String CONFIG_FILE = "437-write-test.yml";
|
||||
|
||||
@Test
|
||||
public void shouldWriteProperties() {
|
||||
File file = getConfigFile();
|
||||
NewSetting setting = new NewSetting(file);
|
||||
setting.save();
|
||||
|
||||
// assert that we can load the file again -- i.e. that it's valid YAML!
|
||||
NewSetting newSetting = new NewSetting(file);
|
||||
assertThat(newSetting.getOption(SecuritySettings.CAPTCHA_LENGTH),
|
||||
equalTo(SecuritySettings.CAPTCHA_LENGTH.getDefaultValue()));
|
||||
assertThat(newSetting.getOption(ProtectionSettings.COUNTRIES_BLACKLIST),
|
||||
equalTo(ProtectionSettings.COUNTRIES_BLACKLIST.getDefaultValue()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
private File getConfigFile() {
|
||||
URL url = getClass().getClassLoader().getResource(CONFIG_FILE);
|
||||
if (url == null) {
|
||||
throw new RuntimeException("File '" + CONFIG_FILE + "' could not be loaded");
|
||||
}
|
||||
return new File(url.getFile());
|
||||
}
|
||||
|
||||
}
|
44
src/test/resources/437-config-test.yml
Normal file
44
src/test/resources/437-config-test.yml
Normal file
@ -0,0 +1,44 @@
|
||||
test:
|
||||
duration: 22
|
||||
DataSource:
|
||||
# What type of database do you want to use?
|
||||
# Valid values: sqlite, mysql
|
||||
backend: sqlite
|
||||
# Enable database caching, should improve database performance
|
||||
caching: true
|
||||
settings:
|
||||
# The name shown in the help messages.
|
||||
helpHeader: AuthMeReloaded
|
||||
GameMode:
|
||||
# ForceSurvivalMode to player when join ?
|
||||
ForceSurvivalMode: 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!
|
||||
stopServer: true
|
||||
ReloadCommand:
|
||||
# /reload support
|
||||
useReloadCommandSupport: true
|
||||
console:
|
||||
# Remove spam console
|
||||
noConsoleSpam: false
|
||||
# Replace passwords in the console when player type a command like /login
|
||||
removePassword: true
|
||||
captcha:
|
||||
# Player need to put a captcha when he fails too lot the password
|
||||
useCaptcha: false
|
||||
# Max allowed tries before request a captcha
|
||||
maxLoginTry: 5
|
||||
# Captcha length
|
||||
captchaLength: 5
|
||||
unsafePasswords:
|
||||
- '123456'
|
||||
- 'qwerty'
|
||||
- '54321'
|
||||
Email:
|
||||
# Email SMTP server host
|
||||
mailSMTP: smtp.gmail.com
|
||||
# Email SMTP server port
|
||||
mailPort: 465
|
172
src/test/resources/437-write-test.yml
Normal file
172
src/test/resources/437-write-test.yml
Normal file
@ -0,0 +1,172 @@
|
||||
|
||||
|
||||
Converter:
|
||||
Rakamak:
|
||||
# Rakamak file name
|
||||
fileName: 'users.rak'
|
||||
# Rakamak use IP?
|
||||
useIP: false
|
||||
# Rakamak IP file name
|
||||
ipFileName: 'UsersIp.rak'
|
||||
CrazyLogin:
|
||||
# CrazyLogin database file name
|
||||
fileName: 'accounts.db'
|
||||
|
||||
DataSource:
|
||||
# What type of database do you want to use?
|
||||
# Valid values: sqlite, mysql
|
||||
backend: 'sqlite'
|
||||
# Enable database caching, should improve database performance
|
||||
caching: true
|
||||
# Database host address
|
||||
mySQLHost: '127.0.0.1'
|
||||
# Database port
|
||||
mySQLPort: '3306'
|
||||
# Username about Database Connection Infos
|
||||
mySQLUsername: 'authme'
|
||||
# Password about Database Connection Infos
|
||||
mySQLPassword: '123456'
|
||||
# Database Name, use with converters or as SQLITE database name
|
||||
mySQLDatabase: 'authme'
|
||||
# Table of the database
|
||||
mySQLTablename: 'authme'
|
||||
# Column of IDs to sort data
|
||||
mySQLColumnId: 'id'
|
||||
# Column for storing or checking players nickname
|
||||
mySQLColumnName: 'username'
|
||||
# Column for storing or checking players RealName
|
||||
mySQLRealName: 'realname'
|
||||
# Column for storing players passwords
|
||||
mySQLColumnPassword: 'password'
|
||||
# Column for storing players emails
|
||||
mySQLColumnEmail: 'email'
|
||||
# Column for storing if a player is logged in or not
|
||||
mySQLColumnLogged: 'email'
|
||||
# Column for storing players ips
|
||||
mySQLColumnIp: 'ip'
|
||||
# Column for storing players lastlogins
|
||||
mySQLColumnLastLogin: 'lastlogin'
|
||||
# Column for storing player LastLocation - X
|
||||
mySQLlastlocX: 'x'
|
||||
# Column for storing player LastLocation - Y
|
||||
mySQLlastlocY: 'y'
|
||||
# Column for storing player LastLocation - Z
|
||||
mySQLlastlocZ: 'z'
|
||||
# Column for storing player LastLocation - World Name
|
||||
mySQLlastlocWorld: 'world'
|
||||
# Enable this when you allow registration through a website
|
||||
mySQLWebsite: false
|
||||
|
||||
ExternalBoardOptions:
|
||||
# Column for storing players passwords salts
|
||||
mySQLColumnSalt: ''
|
||||
# Column for storing players groups
|
||||
mySQLColumnGroup: ''
|
||||
|
||||
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: ''
|
||||
# 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
|
||||
# Do we need to disable Essentials SocialSpy on join?
|
||||
disableSocialSpy: false
|
||||
# Do we need to force /motd Essentials command on join?
|
||||
useEssentialsMotd: false
|
||||
# Do we need to cache custom Attributes?
|
||||
customAttributes: false
|
||||
|
||||
bungeecord:
|
||||
# Send player to this BungeeCord server after register/login
|
||||
server: ''
|
||||
|
||||
Protection:
|
||||
# Enable some servers protection (country based login, antibot)
|
||||
enableProtection: false
|
||||
# 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'
|
||||
- 'A1'
|
||||
# Countries not allowed to join the server and register
|
||||
# PLEASE USE QUOTES!
|
||||
countriesBlacklist: []
|
||||
# Do we need to enable automatic antibot system?
|
||||
enableAntiBot: false
|
||||
# Max number of player allowed to login in 5 secs before enable AntiBot system automatically
|
||||
antiBotSensibility: 5
|
||||
# Duration in minutes of the antibot automatic system
|
||||
antiBotDuration: 10
|
||||
|
||||
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/users/player.yml file during purge process?
|
||||
removeEssentialsFiles: 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
|
||||
|
||||
Security:
|
||||
SQLProblem:
|
||||
# Stop the server if we can't contact the sql database
|
||||
# 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:
|
||||
# Remove spam from console?
|
||||
noConsoleSpam: false
|
||||
# Remove passwords from console?
|
||||
removePassword: true
|
||||
captcha:
|
||||
# Player need to put a captcha when he fails too lot the password
|
||||
useCaptcha: false
|
||||
# Max allowed tries before request a captcha
|
||||
maxLoginTry: 5
|
||||
# Captcha length
|
||||
captchaLength: 5
|
||||
stop:
|
||||
# Kick players before stopping the server, that allow us to save position of players
|
||||
# and all needed information correctly without any corruption.
|
||||
kickPlayersBeforeStopping: true
|
Loading…
Reference in New Issue
Block a user