199 lines
8.4 KiB
Java
199 lines
8.4 KiB
Java
package fr.xephi.authme.message.updater;
|
|
|
|
import ch.jalu.configme.configurationdata.ConfigurationData;
|
|
import ch.jalu.configme.configurationdata.PropertyListBuilder;
|
|
import ch.jalu.configme.properties.StringProperty;
|
|
import ch.jalu.configme.properties.convertresult.ConvertErrorRecorder;
|
|
import ch.jalu.configme.resource.PropertyReader;
|
|
import ch.jalu.configme.resource.PropertyResource;
|
|
import com.google.common.collect.ImmutableMap;
|
|
import com.google.common.io.Files;
|
|
import fr.xephi.authme.ConsoleLogger;
|
|
import fr.xephi.authme.message.MessageKey;
|
|
import fr.xephi.authme.output.ConsoleLoggerFactory;
|
|
import fr.xephi.authme.util.FileUtils;
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.stream.Collectors;
|
|
|
|
import static java.util.Collections.singletonList;
|
|
|
|
/**
|
|
* Migrates the used messages file to a complete, up-to-date version when necessary.
|
|
*/
|
|
public class MessageUpdater {
|
|
|
|
private ConsoleLogger logger = ConsoleLoggerFactory.get(MessageUpdater.class);
|
|
|
|
/**
|
|
* Applies any necessary migrations to the user's messages file and saves it if it has been modified.
|
|
*
|
|
* @param userFile the user's messages file (yml file in the plugin's folder)
|
|
* @param localJarPath path to the messages file in the JAR for the same language (may not exist)
|
|
* @param defaultJarPath path to the messages file in the JAR for the default language
|
|
* @return true if the file has been migrated and saved, false if it is up-to-date
|
|
*/
|
|
public boolean migrateAndSave(File userFile, String localJarPath, String defaultJarPath) {
|
|
JarMessageSource jarMessageSource = new JarMessageSource(localJarPath, defaultJarPath);
|
|
return migrateAndSave(userFile, jarMessageSource);
|
|
}
|
|
|
|
/**
|
|
* Performs the migration.
|
|
*
|
|
* @param userFile the file to verify and migrate
|
|
* @param jarMessageSource jar message source to get texts from if missing
|
|
* @return true if the file has been migrated and saved, false if it is up-to-date
|
|
*/
|
|
private boolean migrateAndSave(File userFile, JarMessageSource jarMessageSource) {
|
|
// YamlConfiguration escapes all special characters when saving, making the file hard to use, so use ConfigMe
|
|
MessageKeyConfigurationData configurationData = createConfigurationData();
|
|
PropertyResource userResource = new MigraterYamlFileResource(userFile);
|
|
|
|
PropertyReader reader = userResource.createReader();
|
|
configurationData.initializeValues(reader);
|
|
|
|
// Step 1: Migrate any old keys in the file to the new paths
|
|
boolean movedOldKeys = migrateOldKeys(reader, configurationData);
|
|
// Step 2: Perform newer migrations
|
|
boolean movedNewerKeys = migrateKeys(reader, configurationData);
|
|
// Step 3: Take any missing messages from the message files shipped in the AuthMe JAR
|
|
boolean addedMissingKeys = addMissingKeys(jarMessageSource, configurationData);
|
|
|
|
if (movedOldKeys || movedNewerKeys || addedMissingKeys) {
|
|
backupMessagesFile(userFile);
|
|
|
|
userResource.exportProperties(configurationData);
|
|
logger.debug("Successfully saved {0}", userFile);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private boolean migrateKeys(PropertyReader propertyReader, MessageKeyConfigurationData configurationData) {
|
|
return moveIfApplicable(propertyReader, configurationData,
|
|
"misc.two_factor_create", MessageKey.TWO_FACTOR_CREATE);
|
|
}
|
|
|
|
private static boolean moveIfApplicable(PropertyReader reader, MessageKeyConfigurationData configurationData,
|
|
String oldPath, MessageKey messageKey) {
|
|
if (configurationData.getMessage(messageKey) == null && reader.getString(oldPath) != null) {
|
|
configurationData.setMessage(messageKey, reader.getString(oldPath));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private boolean migrateOldKeys(PropertyReader propertyReader, MessageKeyConfigurationData configurationData) {
|
|
boolean hasChange = OldMessageKeysMigrater.migrateOldPaths(propertyReader, configurationData);
|
|
if (hasChange) {
|
|
logger.info("Old keys have been moved to the new ones in your messages_xx.yml file");
|
|
}
|
|
return hasChange;
|
|
}
|
|
|
|
private boolean addMissingKeys(JarMessageSource jarMessageSource, MessageKeyConfigurationData configurationData) {
|
|
List<String> addedKeys = new ArrayList<>();
|
|
for (MessageKeyProperty property : configurationData.getAllMessageProperties()) {
|
|
final String key = property.getPath();
|
|
if (configurationData.getMessage(property) == null) {
|
|
configurationData.setValue(property, jarMessageSource.getMessageFromJar(property));
|
|
addedKeys.add(key);
|
|
}
|
|
}
|
|
if (!addedKeys.isEmpty()) {
|
|
logger.info(
|
|
"Added " + addedKeys.size() + " missing keys to your messages_xx.yml file: " + addedKeys);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static void backupMessagesFile(File messagesFile) {
|
|
String backupName = FileUtils.createBackupFilePath(messagesFile);
|
|
File backupFile = new File(backupName);
|
|
try {
|
|
Files.copy(messagesFile, backupFile);
|
|
} catch (IOException e) {
|
|
throw new IllegalStateException("Could not back up '" + messagesFile + "' to '" + backupFile + "'", e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Constructs the {@link ConfigurationData} for exporting a messages file in its entirety.
|
|
*
|
|
* @return the configuration data to export with
|
|
*/
|
|
public static MessageKeyConfigurationData createConfigurationData() {
|
|
Map<String, String> comments = ImmutableMap.<String, String>builder()
|
|
.put("registration", "Registration")
|
|
.put("password", "Password errors on registration")
|
|
.put("login", "Login")
|
|
.put("error", "Errors")
|
|
.put("antibot", "AntiBot")
|
|
.put("unregister", "Unregister")
|
|
.put("misc", "Other messages")
|
|
.put("session", "Session messages")
|
|
.put("on_join_validation", "Error messages when joining")
|
|
.put("email", "Email")
|
|
.put("recovery", "Password recovery by email")
|
|
.put("captcha", "Captcha")
|
|
.put("verification", "Verification code")
|
|
.put("time", "Time units")
|
|
.put("two_factor", "Two-factor authentication")
|
|
.build();
|
|
|
|
Set<String> addedKeys = new HashSet<>();
|
|
MessageKeyPropertyListBuilder builder = new MessageKeyPropertyListBuilder();
|
|
// Add one key per section based on the comments map above so that the order is clear
|
|
for (String path : comments.keySet()) {
|
|
MessageKey key = Arrays.stream(MessageKey.values()).filter(p -> p.getKey().startsWith(path + "."))
|
|
.findFirst().orElseThrow(() -> new IllegalStateException(path));
|
|
builder.addMessageKey(key);
|
|
addedKeys.add(key.getKey());
|
|
}
|
|
// Add all remaining keys to the property list builder
|
|
Arrays.stream(MessageKey.values())
|
|
.filter(key -> !addedKeys.contains(key.getKey()))
|
|
.forEach(builder::addMessageKey);
|
|
|
|
// Create ConfigurationData instance
|
|
Map<String, List<String>> commentsMap = comments.entrySet().stream()
|
|
.collect(Collectors.toMap(e -> e.getKey(), e -> singletonList(e.getValue())));
|
|
return new MessageKeyConfigurationData(builder, commentsMap);
|
|
}
|
|
|
|
static final class MessageKeyProperty extends StringProperty {
|
|
|
|
MessageKeyProperty(MessageKey messageKey) {
|
|
super(messageKey.getKey(), "");
|
|
}
|
|
|
|
@Override
|
|
protected String getFromReader(PropertyReader reader, ConvertErrorRecorder errorRecorder) {
|
|
return reader.getString(getPath());
|
|
}
|
|
}
|
|
|
|
static final class MessageKeyPropertyListBuilder {
|
|
|
|
private PropertyListBuilder propertyListBuilder = new PropertyListBuilder();
|
|
|
|
void addMessageKey(MessageKey key) {
|
|
propertyListBuilder.add(new MessageKeyProperty(key));
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
List<MessageKeyProperty> getAllProperties() {
|
|
return (List) propertyListBuilder.create();
|
|
}
|
|
}
|
|
}
|