mirror of
https://github.com/plexusorg/Plex.git
synced 2026-06-04 05:26:55 +00:00
Rewrite the database system to have a proper ORM and migrations
This commit is contained in:
@@ -23,7 +23,10 @@ dependencies {
|
||||
library("commons-io:commons-io:2.22.0")
|
||||
library("redis.clients:jedis:7.5.0")
|
||||
library("org.mariadb.jdbc:mariadb-java-client:3.5.8")
|
||||
library("org.postgresql:postgresql:42.7.11")
|
||||
library("org.xerial:sqlite-jdbc:3.53.1.0")
|
||||
library("com.zaxxer:HikariCP:7.0.2")
|
||||
library("com.j256.ormlite:ormlite-jdbc:6.1")
|
||||
library("org.jetbrains:annotations:26.1.0")
|
||||
compileOnly("io.papermc.paper:paper-api:26.1.2.build.+")
|
||||
compileOnly("com.github.MilkBowl:VaultAPI:1.7.1") {
|
||||
|
||||
@@ -112,7 +112,7 @@ public class Plex extends JavaPlugin
|
||||
|
||||
playerCache = new PlayerCache();
|
||||
|
||||
PlexLog.log("Attempting to connect to DB: {0}", plugin.config.getString("data.central.db"));
|
||||
PlexLog.log("Attempting to connect to DB: {0}", plugin.config.getString("data.db.name"));
|
||||
try
|
||||
{
|
||||
PlexUtils.testConnections();
|
||||
@@ -226,6 +226,11 @@ public class Plex extends JavaPlugin
|
||||
this.getServer().getMessenger().unregisterOutgoingPluginChannel(this);
|
||||
|
||||
moduleManager.disableModules();
|
||||
|
||||
if (sqlConnection != null)
|
||||
{
|
||||
sqlConnection.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void generateWorlds()
|
||||
|
||||
@@ -4,8 +4,6 @@ import dev.plex.Plex;
|
||||
import dev.plex.util.PlexLog;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
@@ -17,22 +15,17 @@ public class Config extends YamlConfiguration
|
||||
/**
|
||||
* The plugin instance
|
||||
*/
|
||||
private Plex plugin;
|
||||
private final Plex plugin;
|
||||
|
||||
/**
|
||||
* The File instance
|
||||
*/
|
||||
private File file;
|
||||
private final File file;
|
||||
|
||||
/**
|
||||
* The file name
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Whether new entries were added to the file automatically
|
||||
*/
|
||||
private boolean added = false;
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Creates a config object
|
||||
@@ -60,37 +53,20 @@ public class Config extends YamlConfiguration
|
||||
/**
|
||||
* Loads the configuration file
|
||||
*/
|
||||
public void load(boolean loadFromFile)
|
||||
public void load(boolean reconcileWithDefaults)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (loadFromFile)
|
||||
if (reconcileWithDefaults)
|
||||
{
|
||||
YamlConfiguration externalYamlConfig = YamlConfiguration.loadConfiguration(file);
|
||||
InputStreamReader internalConfigFileStream = new InputStreamReader(plugin.getResource(name), StandardCharsets.UTF_8);
|
||||
YamlConfiguration internalYamlConfig = YamlConfiguration.loadConfiguration(internalConfigFileStream);
|
||||
|
||||
// Gets all the keys inside the internal file and iterates through all of it's key pairs
|
||||
for (String string : internalYamlConfig.getKeys(true))
|
||||
ConfigDefaultsMerger.Result result = ConfigDefaultsMerger.merge(file, plugin.getResource(name), name);
|
||||
if (!result.addedKeys().isEmpty())
|
||||
{
|
||||
// Checks if the external file contains the key already.
|
||||
if (!externalYamlConfig.contains(string))
|
||||
{
|
||||
// If it doesn't contain the key, we set the key based off what was found inside the plugin jar
|
||||
externalYamlConfig.setComments(string, internalYamlConfig.getComments(string));
|
||||
externalYamlConfig.setInlineComments(string, internalYamlConfig.getInlineComments(string));
|
||||
externalYamlConfig.set(string, internalYamlConfig.get(string));
|
||||
PlexLog.log("Setting key: " + string + " in " + this.name + " to the default value(s) since it does not exist!");
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
if (added)
|
||||
{
|
||||
externalYamlConfig.save(file);
|
||||
PlexLog.log("Saving new file...");
|
||||
added = false;
|
||||
PlexLog.log("Merged default key(s) into " + name + ": " + String.join(", ", result.addedKeys()));
|
||||
}
|
||||
}
|
||||
|
||||
this.options().parseComments(true);
|
||||
super.load(file);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -121,4 +97,4 @@ public class Config extends YamlConfiguration
|
||||
{
|
||||
plugin.saveResource(name, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
package dev.plex.config;
|
||||
|
||||
import dev.plex.util.PlexLog;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
final class ConfigDefaultsMerger
|
||||
{
|
||||
private static final Pattern KEY = Pattern.compile("^(\\s*)([A-Za-z0-9_-]+):(?:\\s+.*)?$");
|
||||
|
||||
private ConfigDefaultsMerger()
|
||||
{
|
||||
}
|
||||
|
||||
static Result merge(File file, InputStream defaultsStream, String displayName) throws IOException, InvalidConfigurationException
|
||||
{
|
||||
if (defaultsStream == null)
|
||||
{
|
||||
PlexLog.warn("Unable to merge defaults into " + displayName + " because no default resource exists.");
|
||||
return new Result(load(file), List.of(), false);
|
||||
}
|
||||
|
||||
String defaultsText = new String(defaultsStream.readAllBytes(), StandardCharsets.UTF_8);
|
||||
List<String> defaultLines = splitLines(defaultsText);
|
||||
List<String> currentLines = splitLines(Files.readString(file.toPath(), StandardCharsets.UTF_8));
|
||||
Map<String, Entry> defaults = parse(defaultLines);
|
||||
Map<String, Entry> current = parse(currentLines);
|
||||
|
||||
List<Insertion> insertions = new ArrayList<>();
|
||||
Set<String> coveredByMissingParent = new HashSet<>();
|
||||
|
||||
int order = 0;
|
||||
for (Entry entry : defaults.values())
|
||||
{
|
||||
if (current.containsKey(entry.path) || isCovered(entry.path, coveredByMissingParent))
|
||||
{
|
||||
order++;
|
||||
continue;
|
||||
}
|
||||
|
||||
String parent = parent(entry.path);
|
||||
if (parent != null && !current.containsKey(parent))
|
||||
{
|
||||
order++;
|
||||
continue;
|
||||
}
|
||||
|
||||
insertions.add(new Insertion(findInsertionIndex(entry, defaults, current, currentLines.size()), order, entry.path, defaultLines.subList(entry.start, entry.end)));
|
||||
coveredByMissingParent.add(entry.path);
|
||||
order++;
|
||||
}
|
||||
|
||||
if (insertions.isEmpty())
|
||||
{
|
||||
return new Result(load(file), List.of(), false);
|
||||
}
|
||||
|
||||
applyInsertions(currentLines, insertions);
|
||||
Files.writeString(file.toPath(), String.join(System.lineSeparator(), currentLines) + System.lineSeparator(), StandardCharsets.UTF_8);
|
||||
return new Result(load(file), insertions.stream().map(Insertion::path).toList(), true);
|
||||
}
|
||||
|
||||
private static int findInsertionIndex(Entry missing, Map<String, Entry> defaults, Map<String, Entry> current, int fallback)
|
||||
{
|
||||
String parent = parent(missing.path);
|
||||
for (Entry candidate : defaults.values())
|
||||
{
|
||||
if (candidate.start <= missing.start || !sameParent(missing.path, candidate.path))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Entry existingCandidate = current.get(candidate.path);
|
||||
if (existingCandidate != null)
|
||||
{
|
||||
return existingCandidate.start;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent != null && current.containsKey(parent))
|
||||
{
|
||||
return current.get(parent).end;
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
private static void applyInsertions(List<String> currentLines, List<Insertion> insertions)
|
||||
{
|
||||
insertions.sort(Comparator.comparingInt(Insertion::index).reversed().thenComparing(Comparator.comparingInt(Insertion::order).reversed()));
|
||||
for (Insertion insertion : insertions)
|
||||
{
|
||||
List<String> block = new ArrayList<>(insertion.lines);
|
||||
if (insertion.index > 0 && !currentLines.get(insertion.index - 1).isBlank() && !block.get(0).isBlank())
|
||||
{
|
||||
block.add(0, "");
|
||||
}
|
||||
if (insertion.index < currentLines.size() && !currentLines.get(insertion.index).isBlank() && !block.get(block.size() - 1).isBlank())
|
||||
{
|
||||
block.add("");
|
||||
}
|
||||
currentLines.addAll(insertion.index, block);
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<String, Entry> parse(List<String> lines)
|
||||
{
|
||||
Map<String, Entry> entries = new LinkedHashMap<>();
|
||||
List<StackEntry> stack = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < lines.size(); i++)
|
||||
{
|
||||
Matcher matcher = KEY.matcher(lines.get(i));
|
||||
if (!matcher.matches() || lines.get(i).trim().startsWith("#"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int indent = matcher.group(1).length();
|
||||
String key = matcher.group(2);
|
||||
while (!stack.isEmpty() && stack.get(stack.size() - 1).indent >= indent)
|
||||
{
|
||||
stack.remove(stack.size() - 1);
|
||||
}
|
||||
|
||||
String path = stack.isEmpty() ? key : stack.get(stack.size() - 1).path + "." + key;
|
||||
entries.put(path, new Entry(path, blockStart(lines, i), blockEnd(lines, i, indent), indent));
|
||||
stack.add(new StackEntry(path, indent));
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
private static int blockStart(List<String> lines, int keyLine)
|
||||
{
|
||||
int start = keyLine;
|
||||
while (start > 0)
|
||||
{
|
||||
String previous = lines.get(start - 1).trim();
|
||||
if (!previous.isBlank() && !previous.startsWith("#"))
|
||||
{
|
||||
break;
|
||||
}
|
||||
start--;
|
||||
}
|
||||
return start;
|
||||
}
|
||||
|
||||
private static int blockEnd(List<String> lines, int keyLine, int indent)
|
||||
{
|
||||
for (int i = keyLine + 1; i < lines.size(); i++)
|
||||
{
|
||||
Matcher matcher = KEY.matcher(lines.get(i));
|
||||
if (matcher.matches() && matcher.group(1).length() <= indent)
|
||||
{
|
||||
return blockStart(lines, i);
|
||||
}
|
||||
}
|
||||
return lines.size();
|
||||
}
|
||||
|
||||
private static boolean sameParent(String first, String second)
|
||||
{
|
||||
String firstParent = parent(first);
|
||||
String secondParent = parent(second);
|
||||
return firstParent == null ? secondParent == null : firstParent.equals(secondParent);
|
||||
}
|
||||
|
||||
private static boolean isCovered(String path, Set<String> covered)
|
||||
{
|
||||
return covered.stream().anyMatch(parent -> path.startsWith(parent + "."));
|
||||
}
|
||||
|
||||
private static String parent(String path)
|
||||
{
|
||||
int index = path.lastIndexOf('.');
|
||||
return index == -1 ? null : path.substring(0, index);
|
||||
}
|
||||
|
||||
private static List<String> splitLines(String text)
|
||||
{
|
||||
return new ArrayList<>(text.lines().toList());
|
||||
}
|
||||
|
||||
static YamlConfiguration load(File file) throws IOException, InvalidConfigurationException
|
||||
{
|
||||
YamlConfiguration config = new YamlConfiguration();
|
||||
config.options().parseComments(true);
|
||||
config.load(file);
|
||||
return config;
|
||||
}
|
||||
|
||||
private record StackEntry(String path, int indent)
|
||||
{
|
||||
}
|
||||
|
||||
private record Entry(String path, int start, int end, int indent)
|
||||
{
|
||||
}
|
||||
|
||||
private record Insertion(int index, int order, String path, List<String> lines)
|
||||
{
|
||||
}
|
||||
|
||||
record Result(YamlConfiguration config, List<String> addedKeys, boolean changed)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
package dev.plex.config;
|
||||
|
||||
import dev.plex.module.PlexModule;
|
||||
import dev.plex.util.PlexLog;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
@@ -17,22 +19,22 @@ public class ModuleConfig extends YamlConfiguration
|
||||
/**
|
||||
* The plugin instance
|
||||
*/
|
||||
private PlexModule module;
|
||||
private final PlexModule module;
|
||||
|
||||
/**
|
||||
* The File instance
|
||||
*/
|
||||
private File file;
|
||||
private final File file;
|
||||
|
||||
/**
|
||||
* Where the file is in the module JAR
|
||||
*/
|
||||
private String from;
|
||||
private final String from;
|
||||
|
||||
/**
|
||||
* Where it should be copied to in the module folder
|
||||
*/
|
||||
private String to;
|
||||
private final String to;
|
||||
|
||||
/**
|
||||
* Creates a config object
|
||||
@@ -57,6 +59,13 @@ public class ModuleConfig extends YamlConfiguration
|
||||
{
|
||||
try
|
||||
{
|
||||
ConfigDefaultsMerger.Result result = ConfigDefaultsMerger.merge(file, module.getClass().getResourceAsStream("/" + from), to);
|
||||
if (!result.addedKeys().isEmpty())
|
||||
{
|
||||
PlexLog.log("Merged default key(s) into " + to + ": " + String.join(", ", result.addedKeys()));
|
||||
}
|
||||
|
||||
this.options().parseComments(true);
|
||||
super.load(file);
|
||||
}
|
||||
catch (IOException | InvalidConfigurationException ex)
|
||||
@@ -87,11 +96,24 @@ public class ModuleConfig extends YamlConfiguration
|
||||
{
|
||||
try
|
||||
{
|
||||
Files.copy(module.getClass().getResourceAsStream("/" + from), this.file.toPath());
|
||||
File parent = file.getParentFile();
|
||||
if (parent != null)
|
||||
{
|
||||
parent.mkdirs();
|
||||
}
|
||||
try (InputStream stream = module.getClass().getResourceAsStream("/" + from))
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
PlexLog.warn("Unable to save default module config " + to + ": missing resource " + from);
|
||||
return;
|
||||
}
|
||||
Files.copy(stream, this.file.toPath());
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ public class PunishedPlayerMenu extends PageableMenu<Punishment>
|
||||
@Override
|
||||
protected ItemStack toItem(Punishment object)
|
||||
{
|
||||
return new ItemBuilder(Material.PAPER).displayName("<!italic><red>" + object.getType().name()).lore("<!italic><red>By: <gold>" + (object.getPunisher() == null ? "CONSOLE" : Plex.get().getSqlPlayerData().getNameByUUID(object.getPunisher())), "<!italic><red>Expire(d/s): <gold>" + TimeUtils.useTimezone(object.getEndDate()), "<!italic><red>Reason: <gold>" + object.getReason()).build();
|
||||
return new ItemBuilder(Material.PAPER).displayName("<!italic><red>" + object.getType().name()).lore("<!italic><red>By: <gold>" + (object.getPunisher() == null ? "CONSOLE" : Plex.get().getSqlPlayerData().getNameByUUID(object.getPunisher())), "<!italic><red>Issued: <gold>" + TimeUtils.useTimezone(object.getIssueDate()), "<!italic><red>Expire(d/s): <gold>" + TimeUtils.useTimezone(object.getEndDate()), "<!italic><red>Reason: <gold>" + object.getReason()).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -6,10 +6,6 @@ import dev.plex.Plex;
|
||||
import dev.plex.punishment.Punishment;
|
||||
import dev.plex.punishment.PunishmentType;
|
||||
import dev.plex.punishment.extra.Note;
|
||||
import dev.plex.storage.annotation.MapObjectList;
|
||||
import dev.plex.storage.annotation.PrimaryKey;
|
||||
import dev.plex.storage.annotation.SQLTable;
|
||||
import dev.plex.storage.annotation.VarcharLimit;
|
||||
import dev.plex.util.adapter.ZonedDateTimeAdapter;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
@@ -26,15 +22,12 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@SQLTable("players")
|
||||
public class PlexPlayer
|
||||
{
|
||||
@Setter(AccessLevel.NONE)
|
||||
@PrimaryKey
|
||||
@NotNull
|
||||
private UUID uuid;
|
||||
|
||||
@VarcharLimit(16)
|
||||
@NotNull
|
||||
private String name;
|
||||
|
||||
@@ -54,10 +47,8 @@ public class PlexPlayer
|
||||
|
||||
private List<String> ips = Lists.newArrayList();
|
||||
|
||||
@MapObjectList
|
||||
private List<Punishment> punishments = Lists.newArrayList();
|
||||
|
||||
@MapObjectList
|
||||
private List<Note> notes = Lists.newArrayList();
|
||||
|
||||
public PlexPlayer()
|
||||
|
||||
@@ -3,11 +3,11 @@ package dev.plex.punishment;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import dev.plex.Plex;
|
||||
import dev.plex.storage.annotation.SQLTable;
|
||||
import dev.plex.util.PlexUtils;
|
||||
import dev.plex.util.TimeUtils;
|
||||
import dev.plex.util.adapter.ZonedDateTimeAdapter;
|
||||
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -18,7 +18,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@SQLTable("punishments")
|
||||
public class Punishment
|
||||
{
|
||||
private static final Gson gson = new GsonBuilder().registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeAdapter()).create();
|
||||
@@ -36,12 +35,14 @@ public class Punishment
|
||||
private String reason;
|
||||
private boolean customTime;
|
||||
private boolean active; // Field is only for bans
|
||||
private ZonedDateTime issueDate;
|
||||
private ZonedDateTime endDate;
|
||||
|
||||
public Punishment(UUID punished, UUID punisher)
|
||||
{
|
||||
this.punished = punished;
|
||||
this.punisher = punisher;
|
||||
this.issueDate = ZonedDateTime.now(ZoneId.of(TimeUtils.TIMEZONE));
|
||||
}
|
||||
|
||||
public static Component generateBanMessage(Punishment punishment)
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package dev.plex.punishment.extra;
|
||||
|
||||
import com.google.gson.GsonBuilder;
|
||||
import dev.plex.storage.annotation.NoLimit;
|
||||
import dev.plex.storage.annotation.SQLTable;
|
||||
import dev.plex.util.adapter.ZonedDateTimeAdapter;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
@@ -11,12 +9,10 @@ import java.util.UUID;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@SQLTable("notes")
|
||||
public class Note
|
||||
{
|
||||
private final UUID uuid;
|
||||
|
||||
@NoLimit
|
||||
private final String note;
|
||||
private final UUID writtenBy;
|
||||
private final ZonedDateTime timestamp;
|
||||
|
||||
@@ -14,11 +14,11 @@ public class RedisConnection implements PlexBase
|
||||
{
|
||||
try
|
||||
{
|
||||
jedis = new Jedis(plugin.config.getString("data.side.hostname"),
|
||||
plugin.config.getInt("data.side.port"));
|
||||
if (plugin.config.getBoolean("data.side.auth"))
|
||||
jedis = new Jedis(plugin.config.getString("data.redis.hostname"),
|
||||
plugin.config.getInt("data.redis.port"));
|
||||
if (plugin.config.getBoolean("data.redis.auth"))
|
||||
{
|
||||
jedis.auth(plugin.config.getString("data.side.password"));
|
||||
jedis.auth(plugin.config.getString("data.redis.password"));
|
||||
}
|
||||
return jedis;
|
||||
}
|
||||
@@ -43,6 +43,6 @@ public class RedisConnection implements PlexBase
|
||||
|
||||
public final boolean isEnabled()
|
||||
{
|
||||
return plugin.config.getBoolean("data.side.enabled");
|
||||
return plugin.config.getBoolean("data.redis.enabled");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,144 +1,16 @@
|
||||
package dev.plex.storage;
|
||||
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import dev.plex.Plex;
|
||||
import dev.plex.PlexBase;
|
||||
import lombok.Getter;
|
||||
import dev.plex.storage.database.Database;
|
||||
|
||||
import java.io.File;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
@Getter
|
||||
public class SQLConnection implements PlexBase
|
||||
/**
|
||||
* Database bootstrap and connection holder.
|
||||
*
|
||||
* <p>The historical name is kept so existing module-facing accessors do not break.</p>
|
||||
*/
|
||||
public class SQLConnection extends Database
|
||||
{
|
||||
private HikariDataSource dataSource;
|
||||
|
||||
public SQLConnection()
|
||||
public java.sql.Connection getCon() throws java.sql.SQLException
|
||||
{
|
||||
if (!plugin.config.getString("data.central.storage").equalsIgnoreCase("sqlite") && !plugin.config.getString("data.central.storage").equalsIgnoreCase("mariadb"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
String host = plugin.config.getString("data.central.hostname");
|
||||
int port = plugin.config.getInt("data.central.port");
|
||||
String username = plugin.config.getString("data.central.user");
|
||||
String password = plugin.config.getString("data.central.password");
|
||||
String database = plugin.config.getString("data.central.db");
|
||||
|
||||
HikariConfig config = new HikariConfig();
|
||||
config.addDataSourceProperty("cachePrepStmts", "true");
|
||||
config.addDataSourceProperty("prepStmtCacheSize", "250");
|
||||
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
|
||||
|
||||
this.dataSource = new HikariDataSource();
|
||||
dataSource.setMaxLifetime(15000);
|
||||
dataSource.setIdleTimeout(15000 * 2);
|
||||
dataSource.setConnectionTimeout(15000 * 4);
|
||||
dataSource.setMinimumIdle(2);
|
||||
dataSource.setMaximumPoolSize(10);
|
||||
try
|
||||
{
|
||||
if (plugin.config.getString("data.central.storage").equalsIgnoreCase("sqlite"))
|
||||
{
|
||||
dataSource.setJdbcUrl("jdbc:sqlite:" + new File(plugin.getDataFolder(), "database.db").getAbsolutePath());
|
||||
plugin.setStorageType(StorageType.SQLITE);
|
||||
}
|
||||
else if (plugin.config.getString("data.central.storage").equalsIgnoreCase("mariadb"))
|
||||
{
|
||||
Class.forName("org.mariadb.jdbc.Driver");
|
||||
dataSource.setJdbcUrl("jdbc:mariadb://" + host + ":" + port + "/" + database);
|
||||
dataSource.setUsername(username);
|
||||
dataSource.setPassword(password);
|
||||
Plex.get().setStorageType(StorageType.MARIADB);
|
||||
}
|
||||
}
|
||||
catch (ClassNotFoundException throwables)
|
||||
{
|
||||
throwables.printStackTrace();
|
||||
}
|
||||
|
||||
try (Connection con = getCon())
|
||||
{
|
||||
if (tableExistsSQL("players"))
|
||||
{
|
||||
|
||||
}
|
||||
con.prepareStatement("CREATE TABLE IF NOT EXISTS `players` (" +
|
||||
"`uuid` VARCHAR(46) NOT NULL, " +
|
||||
"`name` VARCHAR(18), " +
|
||||
"`login_msg` VARCHAR(2000), " +
|
||||
"`prefix` VARCHAR(2000), " +
|
||||
"`staffChat` BOOLEAN, " +
|
||||
"`ips` VARCHAR(2000), " +
|
||||
"`coins` BIGINT, " +
|
||||
"`vanished` BOOLEAN, " +
|
||||
"`commandspy` BOOLEAN, " +
|
||||
"PRIMARY KEY (`uuid`));").execute();
|
||||
con.prepareStatement("CREATE TABLE IF NOT EXISTS `punishments` (" +
|
||||
"`punished` VARCHAR(46) NOT NULL, " +
|
||||
"`punisher` VARCHAR(46), " +
|
||||
"`punisherName` VARCHAR(64), " +
|
||||
"`punishedUsername` VARCHAR(16), " +
|
||||
"`ip` VARCHAR(2000), " +
|
||||
"`type` VARCHAR(30), " +
|
||||
"`reason` VARCHAR(2000), " +
|
||||
"`customTime` BOOLEAN, " +
|
||||
"`active` BOOLEAN, " +
|
||||
"`endDate` BIGINT" +
|
||||
");").execute();
|
||||
con.prepareStatement("CREATE TABLE IF NOT EXISTS `notes` (" +
|
||||
"`id` INT NOT NULL, " +
|
||||
"`uuid` VARCHAR(46) NOT NULL, " +
|
||||
"`written_by` VARCHAR(46), " +
|
||||
"`note` VARCHAR(2000), " +
|
||||
"`timestamp` BIGINT" +
|
||||
");").execute();
|
||||
}
|
||||
catch (SQLException throwables)
|
||||
{
|
||||
throwables.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean tableExistsSQL(String tableName) throws SQLException
|
||||
{
|
||||
try (Connection connection = getCon())
|
||||
{
|
||||
PreparedStatement preparedStatement = connection.prepareStatement("SELECT count(*) "
|
||||
+ "FROM information_schema.tables "
|
||||
+ "WHERE table_name = ?"
|
||||
+ "LIMIT 1;");
|
||||
preparedStatement.setString(1, tableName);
|
||||
|
||||
ResultSet resultSet = preparedStatement.executeQuery();
|
||||
resultSet.next();
|
||||
return resultSet.getInt(1) != 0;
|
||||
}
|
||||
catch (SQLException ignored)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public Connection getCon()
|
||||
{
|
||||
if (this.dataSource == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
try
|
||||
{
|
||||
return dataSource.getConnection();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
return getConnection();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,109 @@
|
||||
package dev.plex.storage;
|
||||
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
import dev.plex.Plex;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
public enum StorageType
|
||||
{
|
||||
MARIADB, SQLITE
|
||||
SQLITE("SQLite", "sqlite", "org.sqlite.JDBC", Set.of("sqlite"))
|
||||
{
|
||||
@Override
|
||||
public void configure(HikariConfig config, Plex plugin)
|
||||
{
|
||||
File databaseFile = new File(plugin.getDataFolder(), "database.db");
|
||||
config.setJdbcUrl("jdbc:sqlite:" + databaseFile.getAbsolutePath());
|
||||
config.setDriverClassName(driverClass);
|
||||
config.setMaximumPoolSize(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String migrationHistoryTableSql(String tableName)
|
||||
{
|
||||
return "CREATE TABLE IF NOT EXISTS " + tableName + " (version VARCHAR(100) NOT NULL PRIMARY KEY, installed_at INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000))";
|
||||
}
|
||||
},
|
||||
|
||||
MARIADB("MariaDB", "mariadb", "org.mariadb.jdbc.Driver", Set.of("mariadb", "mysql"))
|
||||
{
|
||||
@Override
|
||||
public void configure(HikariConfig config, Plex plugin)
|
||||
{
|
||||
configureRemote(config, plugin, "jdbc:mariadb://", driverClass);
|
||||
config.addDataSourceProperty("cachePrepStmts", "true");
|
||||
config.addDataSourceProperty("prepStmtCacheSize", "250");
|
||||
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String migrationHistoryTableSql(String tableName)
|
||||
{
|
||||
return "CREATE TABLE IF NOT EXISTS `" + tableName + "` (`version` VARCHAR(100) NOT NULL PRIMARY KEY, `installed_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP)";
|
||||
}
|
||||
},
|
||||
|
||||
POSTGRES("PostgreSQL", "postgres", "org.postgresql.Driver", Set.of("postgres", "postgresql"))
|
||||
{
|
||||
@Override
|
||||
public void configure(HikariConfig config, Plex plugin)
|
||||
{
|
||||
configureRemote(config, plugin, "jdbc:postgresql://", driverClass);
|
||||
config.addDataSourceProperty("cachePrepStmts", "true");
|
||||
config.addDataSourceProperty("prepStmtCacheSize", "250");
|
||||
}
|
||||
};
|
||||
|
||||
private final Set<String> aliases;
|
||||
private final String displayName;
|
||||
private final String migrationDirectory;
|
||||
protected final String driverClass;
|
||||
|
||||
StorageType(String displayName, String migrationDirectory, String driverClass, Set<String> aliases)
|
||||
{
|
||||
this.aliases = aliases;
|
||||
this.displayName = displayName;
|
||||
this.migrationDirectory = migrationDirectory;
|
||||
this.driverClass = driverClass;
|
||||
}
|
||||
|
||||
public static StorageType fromConfig(String value)
|
||||
{
|
||||
String normalized = value == null ? "sqlite" : value.trim().toLowerCase(Locale.ROOT);
|
||||
return Arrays.stream(values())
|
||||
.filter(type -> type.aliases.contains(normalized))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("Unsupported database storage type: " + value));
|
||||
}
|
||||
|
||||
public abstract void configure(HikariConfig config, Plex plugin);
|
||||
|
||||
public String migrationHistoryTableSql(String tableName)
|
||||
{
|
||||
return "CREATE TABLE IF NOT EXISTS " + tableName + " (version VARCHAR(100) NOT NULL PRIMARY KEY, installed_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP)";
|
||||
}
|
||||
|
||||
public String getDisplayName()
|
||||
{
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public String getMigrationDirectory()
|
||||
{
|
||||
return migrationDirectory;
|
||||
}
|
||||
|
||||
private static void configureRemote(HikariConfig config, Plex plugin, String jdbcPrefix, String driverClass)
|
||||
{
|
||||
String host = plugin.config.getString("data.db.hostname");
|
||||
int port = plugin.config.getInt("data.db.port");
|
||||
String database = plugin.config.getString("data.db.name");
|
||||
config.setJdbcUrl(jdbcPrefix + host + ":" + port + "/" + database);
|
||||
config.setDriverClassName(driverClass);
|
||||
config.setUsername(plugin.config.getString("data.db.user"));
|
||||
config.setPassword(plugin.config.getString("data.db.password"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
package dev.plex.storage.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author Taah
|
||||
* @since 1:42 AM [25-08-2023]
|
||||
*/
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface MapObjectList
|
||||
{
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package dev.plex.storage.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author Taah
|
||||
* @since 1:42 AM [25-08-2023]
|
||||
*/
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface NoLimit
|
||||
{
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package dev.plex.storage.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author Taah
|
||||
* @since 1:42 AM [25-08-2023]
|
||||
*/
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface PrimaryKey
|
||||
{
|
||||
boolean dontSet() default false;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package dev.plex.storage.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author Taah
|
||||
* @since 4:27 AM [25-08-2023]
|
||||
*/
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface SQLTable
|
||||
{
|
||||
String value();
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package dev.plex.storage.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author Taah
|
||||
* @since 1:42 AM [25-08-2023]
|
||||
*/
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface VarcharLimit
|
||||
{
|
||||
int value();
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
package dev.plex.storage.database;
|
||||
|
||||
import com.j256.ormlite.jdbc.DataSourceConnectionSource;
|
||||
import com.j256.ormlite.support.ConnectionSource;
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import dev.plex.PlexBase;
|
||||
import dev.plex.storage.StorageType;
|
||||
import dev.plex.util.PlexLog;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
public class Database implements PlexBase
|
||||
{
|
||||
private static final String MIGRATION_TABLE = "plex_schema_history";
|
||||
|
||||
private final HikariDataSource dataSource;
|
||||
private final ConnectionSource connectionSource;
|
||||
private final StorageType storageType;
|
||||
|
||||
public Database()
|
||||
{
|
||||
this.storageType = StorageType.fromConfig(plugin.config.getString("data.db.storage", "sqlite"));
|
||||
|
||||
HikariConfig config = new HikariConfig();
|
||||
config.setPoolName("Plex-Database");
|
||||
config.setMaxLifetime(1_800_000);
|
||||
config.setIdleTimeout(600_000);
|
||||
config.setKeepaliveTime(0);
|
||||
config.setConnectionTimeout(60_000);
|
||||
config.setMinimumIdle(2);
|
||||
config.setMaximumPoolSize(10);
|
||||
storageType.configure(config, plugin);
|
||||
|
||||
plugin.setStorageType(this.storageType);
|
||||
this.dataSource = new HikariDataSource(config);
|
||||
try
|
||||
{
|
||||
this.connectionSource = new DataSourceConnectionSource(dataSource, config.getJdbcUrl());
|
||||
runMigrations();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
dataSource.close();
|
||||
throw new IllegalStateException("Failed to initialize database", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void runMigrations() throws Exception
|
||||
{
|
||||
try (Connection connection = dataSource.getConnection())
|
||||
{
|
||||
ensureMigrationTable(connection);
|
||||
for (String migration : List.of("001_initial_schema"))
|
||||
{
|
||||
if (hasMigration(connection, migration))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
executeMigration(connection, migration);
|
||||
try (Statement statement = connection.createStatement())
|
||||
{
|
||||
statement.executeUpdate("INSERT INTO " + MIGRATION_TABLE + " (version) VALUES ('" + migration + "')");
|
||||
}
|
||||
PlexLog.log("Applied database migration " + migration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureMigrationTable(Connection connection) throws SQLException
|
||||
{
|
||||
try (Statement statement = connection.createStatement())
|
||||
{
|
||||
statement.execute(storageType.migrationHistoryTableSql(MIGRATION_TABLE));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasMigration(Connection connection, String migration) throws SQLException
|
||||
{
|
||||
try (Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT version FROM " + MIGRATION_TABLE + " WHERE version = '" + migration + "'"))
|
||||
{
|
||||
return resultSet.next();
|
||||
}
|
||||
}
|
||||
|
||||
private void executeMigration(Connection connection, String migration) throws Exception
|
||||
{
|
||||
String resource = "db/migration/" + storageType.getMigrationDirectory() + "/" + migration + ".sql";
|
||||
try (InputStream stream = getClass().getClassLoader().getResourceAsStream(resource))
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
throw new IllegalStateException("Missing database migration resource: " + resource);
|
||||
}
|
||||
|
||||
for (String sql : splitStatements(new String(stream.readAllBytes(), StandardCharsets.UTF_8)))
|
||||
{
|
||||
try (Statement statement = connection.createStatement())
|
||||
{
|
||||
statement.execute(sql);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> splitStatements(String script)
|
||||
{
|
||||
List<String> statements = new ArrayList<>();
|
||||
StringBuilder current = new StringBuilder();
|
||||
boolean inSingleQuote = false;
|
||||
boolean inDoubleQuote = false;
|
||||
|
||||
for (int i = 0; i < script.length(); i++)
|
||||
{
|
||||
char c = script.charAt(i);
|
||||
if (c == '\'' && !inDoubleQuote)
|
||||
{
|
||||
inSingleQuote = !inSingleQuote;
|
||||
}
|
||||
else if (c == '"' && !inSingleQuote)
|
||||
{
|
||||
inDoubleQuote = !inDoubleQuote;
|
||||
}
|
||||
|
||||
if (c == ';' && !inSingleQuote && !inDoubleQuote)
|
||||
{
|
||||
addStatement(statements, current);
|
||||
current.setLength(0);
|
||||
continue;
|
||||
}
|
||||
current.append(c);
|
||||
}
|
||||
addStatement(statements, current);
|
||||
return statements;
|
||||
}
|
||||
|
||||
private void addStatement(List<String> statements, StringBuilder statement)
|
||||
{
|
||||
String sql = statement.toString().replaceAll("(?m)^\\s*--.*$", "").trim();
|
||||
if (!sql.isEmpty())
|
||||
{
|
||||
statements.add(sql);
|
||||
}
|
||||
}
|
||||
|
||||
public Connection getConnection() throws SQLException
|
||||
{
|
||||
return dataSource.getConnection();
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
try
|
||||
{
|
||||
connectionSource.close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
PlexLog.warn("Failed to close ORMLite connection source: " + e.getMessage());
|
||||
}
|
||||
dataSource.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package dev.plex.storage.database.entity;
|
||||
|
||||
import com.j256.ormlite.field.DatabaseField;
|
||||
import com.j256.ormlite.table.DatabaseTable;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@DatabaseTable(tableName = "notes")
|
||||
public class NoteEntity
|
||||
{
|
||||
@DatabaseField(generatedId = true, columnName = "row_id")
|
||||
private long rowId;
|
||||
|
||||
@DatabaseField(columnName = "id", index = true)
|
||||
private int id;
|
||||
|
||||
@DatabaseField(columnName = "uuid", canBeNull = false, index = true, width = 46)
|
||||
private String uuid;
|
||||
|
||||
@DatabaseField(columnName = "written_by", width = 46)
|
||||
private String writtenBy;
|
||||
|
||||
@DatabaseField(columnName = "note", width = 2000)
|
||||
private String note;
|
||||
|
||||
@DatabaseField(columnName = "timestamp")
|
||||
private long timestamp;
|
||||
|
||||
public NoteEntity()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package dev.plex.storage.database.entity;
|
||||
|
||||
import com.j256.ormlite.field.DatabaseField;
|
||||
import com.j256.ormlite.table.DatabaseTable;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@DatabaseTable(tableName = "players")
|
||||
public class PlayerEntity
|
||||
{
|
||||
@DatabaseField(id = true, columnName = "uuid", width = 46)
|
||||
private String uuid;
|
||||
|
||||
@DatabaseField(columnName = "name", width = 18)
|
||||
private String name;
|
||||
|
||||
@DatabaseField(columnName = "login_msg", width = 2000)
|
||||
private String loginMessage;
|
||||
|
||||
@DatabaseField(columnName = "prefix", width = 2000)
|
||||
private String prefix;
|
||||
|
||||
@DatabaseField(columnName = "staffChat")
|
||||
private boolean staffChat;
|
||||
|
||||
@DatabaseField(columnName = "ips", width = 2000)
|
||||
private String ips;
|
||||
|
||||
@DatabaseField(columnName = "coins")
|
||||
private long coins;
|
||||
|
||||
@DatabaseField(columnName = "vanished")
|
||||
private boolean vanished;
|
||||
|
||||
@DatabaseField(columnName = "commandspy")
|
||||
private boolean commandSpy;
|
||||
|
||||
public PlayerEntity()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package dev.plex.storage.database.entity;
|
||||
|
||||
import com.j256.ormlite.field.DatabaseField;
|
||||
import com.j256.ormlite.table.DatabaseTable;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@DatabaseTable(tableName = "player_ips")
|
||||
public class PlayerIpEntity
|
||||
{
|
||||
@DatabaseField(generatedId = true, columnName = "id")
|
||||
private long id;
|
||||
|
||||
@DatabaseField(columnName = "player_uuid", canBeNull = false, index = true, width = 46)
|
||||
private String playerUuid;
|
||||
|
||||
@DatabaseField(columnName = "ip", canBeNull = false, index = true, width = 64)
|
||||
private String ip;
|
||||
|
||||
public PlayerIpEntity()
|
||||
{
|
||||
}
|
||||
|
||||
public PlayerIpEntity(String playerUuid, String ip)
|
||||
{
|
||||
this.playerUuid = playerUuid;
|
||||
this.ip = ip;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package dev.plex.storage.database.entity;
|
||||
|
||||
import com.j256.ormlite.field.DatabaseField;
|
||||
import com.j256.ormlite.table.DatabaseTable;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@DatabaseTable(tableName = "punishments")
|
||||
public class PunishmentEntity
|
||||
{
|
||||
@DatabaseField(generatedId = true, columnName = "id")
|
||||
private long id;
|
||||
|
||||
@DatabaseField(columnName = "punished", canBeNull = false, index = true, width = 46)
|
||||
private String punished;
|
||||
|
||||
@DatabaseField(columnName = "punisher", width = 46)
|
||||
private String punisher;
|
||||
|
||||
@DatabaseField(columnName = "punisherName", width = 64)
|
||||
private String punisherName;
|
||||
|
||||
@DatabaseField(columnName = "punishedUsername", width = 16)
|
||||
private String punishedUsername;
|
||||
|
||||
@DatabaseField(columnName = "ip", width = 2000, index = true)
|
||||
private String ip;
|
||||
|
||||
@DatabaseField(columnName = "type", width = 30)
|
||||
private String type;
|
||||
|
||||
@DatabaseField(columnName = "reason", width = 2000)
|
||||
private String reason;
|
||||
|
||||
@DatabaseField(columnName = "customTime")
|
||||
private boolean customTime;
|
||||
|
||||
@DatabaseField(columnName = "active", index = true)
|
||||
private boolean active;
|
||||
|
||||
@DatabaseField(columnName = "issueDate")
|
||||
private long issueDate;
|
||||
|
||||
@DatabaseField(columnName = "endDate")
|
||||
private long endDate;
|
||||
|
||||
public PunishmentEntity()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -2,72 +2,66 @@ package dev.plex.storage.player;
|
||||
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.gson.Gson;
|
||||
import com.j256.ormlite.dao.Dao;
|
||||
import com.j256.ormlite.dao.DaoManager;
|
||||
import com.j256.ormlite.stmt.DeleteBuilder;
|
||||
import dev.plex.Plex;
|
||||
import dev.plex.player.PlexPlayer;
|
||||
import dev.plex.storage.StorageType;
|
||||
import dev.plex.util.PlexLog;
|
||||
import dev.plex.storage.database.entity.PlayerEntity;
|
||||
import dev.plex.storage.database.entity.PlayerIpEntity;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* SQL fetching utilities for players
|
||||
* Player persistence backed by ORMLite.
|
||||
*/
|
||||
public class SQLPlayerData
|
||||
{
|
||||
private final String SELECT = "SELECT * FROM `players` WHERE uuid=?";
|
||||
private final String UPDATE = "UPDATE `players` SET name=?, login_msg=?, prefix=?, ips=?, coins=?, vanished=?, commandspy=? WHERE uuid=?";
|
||||
private final String INSERT = "INSERT INTO `players` (`uuid`, `name`, `login_msg`, `prefix`, `ips`, `coins`, `vanished`, `commandspy`) VALUES (?, ?, ?, ?, ?, ?, ?, ?);";
|
||||
private static final Gson GSON = new Gson();
|
||||
private final Dao<PlayerEntity, String> players;
|
||||
private final Dao<PlayerIpEntity, Long> playerIps;
|
||||
|
||||
public SQLPlayerData()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.players = DaoManager.createDao(Plex.get().getSqlConnection().getConnectionSource(), PlayerEntity.class);
|
||||
this.playerIps = DaoManager.createDao(Plex.get().getSqlConnection().getConnectionSource(), PlayerIpEntity.class);
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
throw new IllegalStateException("Failed to create player DAOs", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a player exists in the SQL database
|
||||
*
|
||||
* @param uuid The unique ID of the player
|
||||
* @return true if the player was found in the database
|
||||
*/
|
||||
public boolean exists(UUID uuid)
|
||||
{
|
||||
try (Connection con = Plex.get().getSqlConnection().getCon())
|
||||
try
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement(SELECT);
|
||||
statement.setString(1, uuid.toString());
|
||||
ResultSet set = statement.executeQuery();
|
||||
return set.next();
|
||||
return players.idExists(uuid.toString());
|
||||
}
|
||||
catch (SQLException throwables)
|
||||
catch (SQLException e)
|
||||
{
|
||||
throwables.printStackTrace();
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean exists(String username)
|
||||
{
|
||||
try (Connection con = Plex.get().getSqlConnection().getCon())
|
||||
try
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement("SELECT * FROM `players` WHERE name=?");
|
||||
statement.setString(1, username);
|
||||
ResultSet set = statement.executeQuery();
|
||||
return set.next();
|
||||
return players.queryBuilder().where().eq("name", username).queryForFirst() != null;
|
||||
}
|
||||
catch (SQLException throwables)
|
||||
catch (SQLException e)
|
||||
{
|
||||
throwables.printStackTrace();
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the player from cache or from the SQL database
|
||||
*
|
||||
* @param uuid The unique ID of the player
|
||||
* @return a PlexPlayer object
|
||||
* @see PlexPlayer
|
||||
*/
|
||||
public PlexPlayer getByUUID(UUID uuid, boolean loadExtraData)
|
||||
{
|
||||
if (Plex.get().getPlayerCache().getPlexPlayerMap().containsKey(uuid))
|
||||
@@ -75,48 +69,17 @@ public class SQLPlayerData
|
||||
return Plex.get().getPlayerCache().getPlexPlayerMap().get(uuid);
|
||||
}
|
||||
|
||||
try (Connection con = Plex.get().getSqlConnection().getCon())
|
||||
try
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement(SELECT);
|
||||
statement.setString(1, uuid.toString());
|
||||
ResultSet set = statement.executeQuery();
|
||||
PlexPlayer plexPlayer = new PlexPlayer(uuid, loadExtraData);
|
||||
while (set.next())
|
||||
{
|
||||
String name = set.getString("name");
|
||||
String loginMSG = set.getString("login_msg");
|
||||
String prefix = set.getString("prefix");
|
||||
long coins = set.getLong("coins");
|
||||
boolean vanished = set.getBoolean("vanished");
|
||||
boolean commandspy = set.getBoolean("commandspy");
|
||||
List<String> ips = new Gson().fromJson(set.getString("ips"), new TypeToken<List<String>>()
|
||||
{
|
||||
}.getType());
|
||||
plexPlayer.setName(name);
|
||||
plexPlayer.setLoginMessage(loginMSG);
|
||||
plexPlayer.setPrefix(prefix);
|
||||
plexPlayer.setIps(ips);
|
||||
plexPlayer.setCoins(coins);
|
||||
plexPlayer.setVanished(vanished);
|
||||
plexPlayer.setCommandSpy(commandspy);
|
||||
}
|
||||
return plexPlayer;
|
||||
return toPlayer(players.queryForId(uuid.toString()), loadExtraData);
|
||||
}
|
||||
catch (SQLException throwables)
|
||||
catch (SQLException e)
|
||||
{
|
||||
throwables.printStackTrace();
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the player from cache or from the SQL database
|
||||
*
|
||||
* @param uuid The unique ID of the player
|
||||
* @return a PlexPlayer object
|
||||
* @see PlexPlayer
|
||||
*/
|
||||
public String getNameByUUID(UUID uuid)
|
||||
{
|
||||
if (Plex.get().getPlayerCache().getPlexPlayerMap().containsKey(uuid))
|
||||
@@ -124,67 +87,43 @@ public class SQLPlayerData
|
||||
return Plex.get().getPlayerCache().getPlexPlayerMap().get(uuid).getName();
|
||||
}
|
||||
|
||||
try (Connection con = Plex.get().getSqlConnection().getCon())
|
||||
try
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement("SELECT `name` FROM `players` WHERE uuid=?");
|
||||
statement.setString(1, uuid.toString());
|
||||
ResultSet set = statement.executeQuery();
|
||||
if (set.next())
|
||||
{
|
||||
return set.getString("name");
|
||||
}
|
||||
PlayerEntity entity = players.queryForId(uuid.toString());
|
||||
return entity == null ? null : entity.getName();
|
||||
}
|
||||
catch (SQLException throwables)
|
||||
catch (SQLException e)
|
||||
{
|
||||
throwables.printStackTrace();
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public PlexPlayer getByUUID(UUID uuid)
|
||||
{
|
||||
return this.getByUUID(uuid, true);
|
||||
return getByUUID(uuid, true);
|
||||
}
|
||||
|
||||
public PlexPlayer getByName(String username, boolean loadExtraData)
|
||||
{
|
||||
PlexPlayer player = Plex.get().getPlayerCache().getPlexPlayerMap().values().stream().filter(plexPlayer -> plexPlayer.getName().equalsIgnoreCase(username)).findFirst().orElse(null);
|
||||
PlexPlayer player = Plex.get().getPlayerCache().getPlexPlayerMap().values().stream()
|
||||
.filter(plexPlayer -> plexPlayer.getName().equalsIgnoreCase(username))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (player != null)
|
||||
{
|
||||
return player;
|
||||
}
|
||||
try (Connection con = Plex.get().getSqlConnection().getCon())
|
||||
|
||||
try
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement("SELECT * FROM `players` WHERE name=? LIMIT 1");
|
||||
statement.setString(1, username);
|
||||
ResultSet set = statement.executeQuery();
|
||||
while (set.next())
|
||||
{
|
||||
PlexPlayer plexPlayer = new PlexPlayer(UUID.fromString(set.getString("uuid")), loadExtraData);
|
||||
String loginMSG = set.getString("login_msg");
|
||||
String prefix = set.getString("prefix");
|
||||
long coins = set.getLong("coins");
|
||||
boolean vanished = set.getBoolean("vanished");
|
||||
boolean commandspy = set.getBoolean("commandspy");
|
||||
List<String> ips = new Gson().fromJson(set.getString("ips"), new TypeToken<List<String>>()
|
||||
{
|
||||
}.getType());
|
||||
plexPlayer.setName(username);
|
||||
plexPlayer.setLoginMessage(loginMSG);
|
||||
plexPlayer.setPrefix(prefix);
|
||||
plexPlayer.setIps(ips);
|
||||
plexPlayer.setCoins(coins);
|
||||
plexPlayer.setVanished(vanished);
|
||||
plexPlayer.setCommandSpy(commandspy);
|
||||
return plexPlayer;
|
||||
}
|
||||
return toPlayer(players.queryBuilder().limit(1L).where().eq("name", username).queryForFirst(), loadExtraData);
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
catch (SQLException throwables)
|
||||
{
|
||||
throwables.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public PlexPlayer getByName(String username)
|
||||
@@ -192,155 +131,115 @@ public class SQLPlayerData
|
||||
return getByName(username, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the player from cache or from the SQL database
|
||||
*
|
||||
* @param ip The IP address of the player.
|
||||
* @return a PlexPlayer object
|
||||
* @see PlexPlayer
|
||||
*/
|
||||
public PlexPlayer getByIP(String ip)
|
||||
{
|
||||
PlexPlayer player = Plex.get().getPlayerCache().getPlexPlayerMap().values().stream().filter(plexPlayer -> plexPlayer.getIps().contains(ip)).findFirst().orElse(null);
|
||||
PlexPlayer player = Plex.get().getPlayerCache().getPlexPlayerMap().values().stream()
|
||||
.filter(plexPlayer -> plexPlayer.getIps().contains(ip))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (player != null)
|
||||
{
|
||||
return player;
|
||||
}
|
||||
|
||||
if (Plex.get().getStorageType() == StorageType.MARIADB)
|
||||
try
|
||||
{
|
||||
try (Connection con = Plex.get().getSqlConnection().getCon())
|
||||
PlayerIpEntity playerIp = playerIps.queryBuilder().limit(1L).where().eq("ip", ip).queryForFirst();
|
||||
if (playerIp != null)
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement("select * from `players` where json_search(ips, ?, ?) IS NOT NULL LIMIT 1");
|
||||
statement.setString(1, "one");
|
||||
statement.setString(2, ip);
|
||||
ResultSet set = statement.executeQuery();
|
||||
|
||||
PlexPlayer plexPlayer = null;
|
||||
while (set.next())
|
||||
{
|
||||
String uuid = set.getString("uuid");
|
||||
String name = set.getString("name");
|
||||
String loginMSG = set.getString("login_msg");
|
||||
String prefix = set.getString("prefix");
|
||||
long coins = set.getLong("coins");
|
||||
boolean vanished = set.getBoolean("vanished");
|
||||
boolean commandspy = set.getBoolean("commandspy");
|
||||
List<String> ips = new Gson().fromJson(set.getString("ips"), new TypeToken<List<String>>()
|
||||
{
|
||||
}.getType());
|
||||
plexPlayer = new PlexPlayer(UUID.fromString(uuid));
|
||||
plexPlayer.setName(name);
|
||||
plexPlayer.setLoginMessage(loginMSG);
|
||||
plexPlayer.setPrefix(prefix);
|
||||
plexPlayer.setIps(ips);
|
||||
plexPlayer.setCoins(coins);
|
||||
plexPlayer.setVanished(vanished);
|
||||
plexPlayer.setCommandSpy(commandspy);
|
||||
}
|
||||
return plexPlayer;
|
||||
return toPlayer(players.queryForId(playerIp.getPlayerUuid()), true);
|
||||
}
|
||||
catch (SQLException throwables)
|
||||
|
||||
for (PlayerEntity entity : players.queryForAll())
|
||||
{
|
||||
throwables.printStackTrace();
|
||||
List<String> ips = parseIps(entity.getIps());
|
||||
if (ips.contains(ip))
|
||||
{
|
||||
syncIps(entity.getUuid(), ips);
|
||||
return toPlayer(entity, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Plex.get().getStorageType() == StorageType.SQLITE)
|
||||
catch (SQLException e)
|
||||
{
|
||||
PlexLog.warn("Querying a user by IP running SQLite can cause performance issues! Please try to switch to a remote DB ASAP!");
|
||||
try (Connection con = Plex.get().getSqlConnection().getCon())
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement("select * from `players`");
|
||||
ResultSet set = statement.executeQuery();
|
||||
|
||||
PlexPlayer plexPlayer = null;
|
||||
while (set.next())
|
||||
{
|
||||
List<String> ips = new Gson().fromJson(set.getString("ips"), new TypeToken<List<String>>()
|
||||
{
|
||||
}.getType());
|
||||
if (!ips.contains(ip))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
String uuid = set.getString("uuid");
|
||||
String name = set.getString("name");
|
||||
String loginMSG = set.getString("login_msg");
|
||||
String prefix = set.getString("prefix");
|
||||
long coins = set.getLong("coins");
|
||||
boolean vanished = set.getBoolean("vanished");
|
||||
boolean commandspy = set.getBoolean("commandspy");
|
||||
|
||||
plexPlayer = new PlexPlayer(UUID.fromString(uuid));
|
||||
plexPlayer.setName(name);
|
||||
plexPlayer.setLoginMessage(loginMSG);
|
||||
plexPlayer.setPrefix(prefix);
|
||||
plexPlayer.setIps(ips);
|
||||
plexPlayer.setCoins(coins);
|
||||
plexPlayer.setVanished(vanished);
|
||||
plexPlayer.setCommandSpy(commandspy);
|
||||
}
|
||||
return plexPlayer;
|
||||
}
|
||||
catch (SQLException throwables)
|
||||
{
|
||||
throwables.printStackTrace();
|
||||
}
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a player's information in the SQL database
|
||||
*
|
||||
* @param player The PlexPlayer object
|
||||
* @see PlexPlayer
|
||||
*/
|
||||
public void update(PlexPlayer player)
|
||||
{
|
||||
try (Connection con = Plex.get().getSqlConnection().getCon())
|
||||
try
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement(UPDATE);
|
||||
statement.setString(1, player.getName());
|
||||
statement.setString(2, player.getLoginMessage());
|
||||
statement.setString(3, player.getPrefix());
|
||||
statement.setString(4, new Gson().toJson(player.getIps()));
|
||||
statement.setLong(5, player.getCoins());
|
||||
statement.setBoolean(6, player.isVanished());
|
||||
statement.setBoolean(7, player.isCommandSpy());
|
||||
statement.setString(8, player.getUuid().toString());
|
||||
statement.executeUpdate();
|
||||
players.createOrUpdate(toEntity(player));
|
||||
syncIps(player.getUuid().toString(), player.getIps());
|
||||
}
|
||||
catch (SQLException throwables)
|
||||
catch (SQLException e)
|
||||
{
|
||||
throwables.printStackTrace();
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the player's information in the database
|
||||
*
|
||||
* @param player The PlexPlayer object
|
||||
* @see PlexPlayer
|
||||
*/
|
||||
public void insert(PlexPlayer player)
|
||||
{
|
||||
try (Connection con = Plex.get().getSqlConnection().getCon())
|
||||
update(player);
|
||||
}
|
||||
|
||||
private PlexPlayer toPlayer(PlayerEntity entity, boolean loadExtraData)
|
||||
{
|
||||
if (entity == null)
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement(INSERT);
|
||||
statement.setString(1, player.getUuid().toString());
|
||||
statement.setString(2, player.getName());
|
||||
statement.setString(3, player.getLoginMessage());
|
||||
statement.setString(4, player.getPrefix());
|
||||
statement.setString(5, new Gson().toJson(player.getIps()));
|
||||
statement.setLong(6, player.getCoins());
|
||||
statement.setBoolean(7, player.isVanished());
|
||||
statement.setBoolean(8, player.isCommandSpy());
|
||||
statement.execute();
|
||||
return null;
|
||||
}
|
||||
catch (SQLException throwables)
|
||||
|
||||
PlexPlayer plexPlayer = new PlexPlayer(UUID.fromString(entity.getUuid()), loadExtraData);
|
||||
plexPlayer.setName(entity.getName());
|
||||
plexPlayer.setLoginMessage(entity.getLoginMessage());
|
||||
plexPlayer.setPrefix(entity.getPrefix());
|
||||
plexPlayer.setStaffChat(entity.isStaffChat());
|
||||
plexPlayer.setIps(parseIps(entity.getIps()));
|
||||
plexPlayer.setCoins(entity.getCoins());
|
||||
plexPlayer.setVanished(entity.isVanished());
|
||||
plexPlayer.setCommandSpy(entity.isCommandSpy());
|
||||
return plexPlayer;
|
||||
}
|
||||
|
||||
private PlayerEntity toEntity(PlexPlayer player)
|
||||
{
|
||||
PlayerEntity entity = new PlayerEntity();
|
||||
entity.setUuid(player.getUuid().toString());
|
||||
entity.setName(player.getName());
|
||||
entity.setLoginMessage(player.getLoginMessage());
|
||||
entity.setPrefix(player.getPrefix());
|
||||
entity.setStaffChat(player.isStaffChat());
|
||||
entity.setIps(GSON.toJson(player.getIps()));
|
||||
entity.setCoins(player.getCoins());
|
||||
entity.setVanished(player.isVanished());
|
||||
entity.setCommandSpy(player.isCommandSpy());
|
||||
return entity;
|
||||
}
|
||||
|
||||
private List<String> parseIps(String ips)
|
||||
{
|
||||
if (ips == null || ips.isBlank())
|
||||
{
|
||||
throwables.printStackTrace();
|
||||
return List.of();
|
||||
}
|
||||
List<String> parsed = GSON.fromJson(ips, new TypeToken<List<String>>()
|
||||
{
|
||||
}.getType());
|
||||
return parsed == null ? List.of() : parsed;
|
||||
}
|
||||
|
||||
private void syncIps(String playerUuid, List<String> ips) throws SQLException
|
||||
{
|
||||
DeleteBuilder<PlayerIpEntity, Long> delete = playerIps.deleteBuilder();
|
||||
delete.where().eq("player_uuid", playerUuid);
|
||||
delete.delete();
|
||||
|
||||
for (String ip : ips.stream().distinct().toList())
|
||||
{
|
||||
playerIps.create(new PlayerIpEntity(playerUuid, ip));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +1,55 @@
|
||||
package dev.plex.storage.punishment;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.j256.ormlite.dao.Dao;
|
||||
import com.j256.ormlite.dao.DaoManager;
|
||||
import com.j256.ormlite.stmt.DeleteBuilder;
|
||||
import dev.plex.Plex;
|
||||
import dev.plex.punishment.extra.Note;
|
||||
import dev.plex.storage.database.entity.NoteEntity;
|
||||
import dev.plex.util.TimeUtils;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class SQLNotes
|
||||
{
|
||||
private static final String SELECT = "SELECT * FROM `notes` WHERE uuid=?";
|
||||
private static final String INSERT = "INSERT INTO `notes` (`id`, `uuid`, `written_by`, `note`, `timestamp`) VALUES(?, ?, ?, ?, ?)";
|
||||
private static final String DELETE = "DELETE FROM `notes` WHERE uuid=? AND id=?";
|
||||
private final Dao<NoteEntity, Long> notes;
|
||||
|
||||
public SQLNotes()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.notes = DaoManager.createDao(Plex.get().getSqlConnection().getConnectionSource(), NoteEntity.class);
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
throw new IllegalStateException("Failed to create note DAO", e);
|
||||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<List<Note>> getNotes(UUID uuid)
|
||||
{
|
||||
return CompletableFuture.supplyAsync(() ->
|
||||
{
|
||||
List<Note> notes = Lists.newArrayList();
|
||||
try (Connection con = Plex.get().getSqlConnection().getCon())
|
||||
try
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement(SELECT);
|
||||
statement.setString(1, uuid.toString());
|
||||
ResultSet set = statement.executeQuery();
|
||||
while (set.next())
|
||||
{
|
||||
Note note = new Note(
|
||||
uuid,
|
||||
set.getString("note"),
|
||||
UUID.fromString(set.getString("written_by")),
|
||||
ZonedDateTime.ofInstant(Instant.ofEpochMilli(set.getLong("timestamp")), ZoneId.of(TimeUtils.TIMEZONE))
|
||||
);
|
||||
note.setId(set.getInt("id"));
|
||||
notes.add(note);
|
||||
}
|
||||
return notes.queryForEq("uuid", uuid.toString()).stream()
|
||||
.sorted(Comparator.comparingInt(NoteEntity::getId))
|
||||
.map(this::toNote)
|
||||
.toList();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return notes;
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
return notes;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -57,12 +57,11 @@ public class SQLNotes
|
||||
{
|
||||
return CompletableFuture.runAsync(() ->
|
||||
{
|
||||
try (Connection con = Plex.get().getSqlConnection().getCon())
|
||||
try
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement(DELETE);
|
||||
statement.setString(1, uuid.toString());
|
||||
statement.setInt(2, id);
|
||||
statement.execute();
|
||||
DeleteBuilder<NoteEntity, Long> delete = notes.deleteBuilder();
|
||||
delete.where().eq("uuid", uuid.toString()).and().eq("id", id);
|
||||
delete.delete();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
@@ -75,24 +74,44 @@ public class SQLNotes
|
||||
{
|
||||
return CompletableFuture.runAsync(() ->
|
||||
{
|
||||
getNotes(note.getUuid()).whenComplete((notes, throwable) ->
|
||||
try
|
||||
{
|
||||
try (Connection con = Plex.get().getSqlConnection().getCon())
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement(INSERT);
|
||||
statement.setInt(1, notes.size() + 1);
|
||||
statement.setString(2, note.getUuid().toString());
|
||||
statement.setString(3, note.getWrittenBy().toString());
|
||||
statement.setString(4, note.getNote());
|
||||
statement.setLong(5, note.getTimestamp().toInstant().toEpochMilli());
|
||||
statement.execute();
|
||||
note.setId(notes.size());
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
int nextId = notes.queryForEq("uuid", note.getUuid().toString()).stream()
|
||||
.map(NoteEntity::getId)
|
||||
.max(Integer::compareTo)
|
||||
.orElse(0) + 1;
|
||||
NoteEntity entity = toEntity(note);
|
||||
entity.setId(nextId);
|
||||
notes.create(entity);
|
||||
note.setId(nextId);
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Note toNote(NoteEntity entity)
|
||||
{
|
||||
Note note = new Note(
|
||||
UUID.fromString(entity.getUuid()),
|
||||
entity.getNote(),
|
||||
UUID.fromString(entity.getWrittenBy()),
|
||||
ZonedDateTime.ofInstant(Instant.ofEpochMilli(entity.getTimestamp()), ZoneId.of(TimeUtils.TIMEZONE))
|
||||
);
|
||||
note.setId(entity.getId());
|
||||
return note;
|
||||
}
|
||||
|
||||
private NoteEntity toEntity(Note note)
|
||||
{
|
||||
NoteEntity entity = new NoteEntity();
|
||||
entity.setId(note.getId());
|
||||
entity.setUuid(note.getUuid().toString());
|
||||
entity.setWrittenBy(note.getWrittenBy().toString());
|
||||
entity.setNote(note.getNote());
|
||||
entity.setTimestamp(note.getTimestamp().toInstant().toEpochMilli());
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
package dev.plex.storage.punishment;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.j256.ormlite.dao.Dao;
|
||||
import com.j256.ormlite.dao.DaoManager;
|
||||
import com.j256.ormlite.stmt.UpdateBuilder;
|
||||
import dev.plex.Plex;
|
||||
import dev.plex.punishment.Punishment;
|
||||
import dev.plex.punishment.PunishmentType;
|
||||
import dev.plex.storage.database.entity.PunishmentEntity;
|
||||
import dev.plex.util.PlexLog;
|
||||
import dev.plex.util.TimeUtils;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
@@ -20,122 +21,70 @@ import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class SQLPunishment
|
||||
{
|
||||
private static final String SELECT = "SELECT * FROM `punishments` WHERE punished=?";
|
||||
private static final String SELECT_BY_IP = "SELECT * FROM `punishments` WHERE ip=?";
|
||||
private static final String SELECT_BY = "SELECT * FROM `punishments` WHERE punisher=?";
|
||||
private final Dao<PunishmentEntity, Long> punishments;
|
||||
|
||||
private static final String INSERT = "INSERT INTO `punishments` (`punished`, `punisher`, `punisherName`, `punishedUsername`, `ip`, `type`, `reason`, `customTime`, `active`, `endDate`) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
private static final String UPDATE_PUNISHMENT = "UPDATE `punishments` SET active=? WHERE punished=? AND type=?";
|
||||
public SQLPunishment()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.punishments = DaoManager.createDao(Plex.get().getSqlConnection().getConnectionSource(), PunishmentEntity.class);
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
throw new IllegalStateException("Failed to create punishment DAO", e);
|
||||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<List<Punishment>> getPunishments()
|
||||
{
|
||||
return CompletableFuture.supplyAsync(() ->
|
||||
{
|
||||
List<Punishment> punishments = Lists.newArrayList();
|
||||
try (Connection con = Plex.get().getSqlConnection().getCon())
|
||||
try
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement("SELECT * FROM `punishments`");
|
||||
ResultSet set = statement.executeQuery();
|
||||
while (set.next())
|
||||
{
|
||||
Punishment punishment = new Punishment(UUID.fromString(set.getString("punished")), set.getString("punisher") != null && set.getString("punisher").isEmpty() ? UUID.fromString(set.getString("punisher")) : null);
|
||||
punishment.setActive(set.getBoolean("active"));
|
||||
punishment.setType(PunishmentType.valueOf(set.getString("type")));
|
||||
punishment.setCustomTime(set.getBoolean("customTime"));
|
||||
punishment.setPunishedUsername(set.getString("punishedUsername"));
|
||||
punishment.setPunisherName(set.getString("punisherName"));
|
||||
punishment.setEndDate(ZonedDateTime.ofInstant(Instant.ofEpochMilli(set.getLong("endDate")), ZoneId.of(TimeUtils.TIMEZONE)));
|
||||
punishment.setReason(set.getString("reason"));
|
||||
punishment.setIp(set.getString("ip"));
|
||||
punishments.add(punishment);
|
||||
}
|
||||
return punishments.queryForAll().stream().map(this::toPunishment).toList();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return punishments;
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
return punishments;
|
||||
});
|
||||
}
|
||||
|
||||
public List<Punishment> getPunishments(UUID uuid)
|
||||
{
|
||||
List<Punishment> punishments = Lists.newArrayList();
|
||||
try (Connection con = Plex.get().getSqlConnection().getCon())
|
||||
try
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement(SELECT);
|
||||
statement.setString(1, uuid.toString());
|
||||
ResultSet set = statement.executeQuery();
|
||||
while (set.next())
|
||||
{
|
||||
Punishment punishment = new Punishment(UUID.fromString(set.getString("punished")), set.getString("punisher") == null ? null : UUID.fromString(set.getString("punisher")));
|
||||
punishment.setActive(set.getBoolean("active"));
|
||||
punishment.setType(PunishmentType.valueOf(set.getString("type")));
|
||||
punishment.setCustomTime(set.getBoolean("customTime"));
|
||||
punishment.setPunishedUsername(set.getString("punishedUsername"));
|
||||
punishment.setEndDate(ZonedDateTime.ofInstant(Instant.ofEpochMilli(set.getLong("endDate")), ZoneId.of(TimeUtils.TIMEZONE)));
|
||||
punishment.setReason(set.getString("reason"));
|
||||
punishment.setIp(set.getString("ip"));
|
||||
punishments.add(punishment);
|
||||
}
|
||||
return punishments.queryForEq("punished", uuid.toString()).stream().map(this::toPunishment).toList();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
return punishments;
|
||||
}
|
||||
|
||||
public List<Punishment> getPunishments(String ip)
|
||||
{
|
||||
List<Punishment> punishments = Lists.newArrayList();
|
||||
try (Connection con = Plex.get().getSqlConnection().getCon())
|
||||
try
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement(SELECT_BY_IP);
|
||||
statement.setString(1, ip);
|
||||
ResultSet set = statement.executeQuery();
|
||||
while (set.next())
|
||||
{
|
||||
Punishment punishment = new Punishment(UUID.fromString(set.getString("punished")), set.getString("punisher") == null ? null : UUID.fromString(set.getString("punisher")));
|
||||
punishment.setActive(set.getBoolean("active"));
|
||||
punishment.setType(PunishmentType.valueOf(set.getString("type")));
|
||||
punishment.setCustomTime(set.getBoolean("customTime"));
|
||||
punishment.setPunishedUsername(set.getString("punishedUsername"));
|
||||
punishment.setEndDate(ZonedDateTime.ofInstant(Instant.ofEpochMilli(set.getLong("endDate")), ZoneId.of(TimeUtils.TIMEZONE)));
|
||||
punishment.setReason(set.getString("reason"));
|
||||
punishment.setIp(set.getString("ip"));
|
||||
punishments.add(punishment);
|
||||
}
|
||||
return punishments.queryForEq("ip", ip).stream().map(this::toPunishment).toList();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
return punishments;
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> insertPunishment(Punishment punishment)
|
||||
{
|
||||
|
||||
return CompletableFuture.runAsync(() ->
|
||||
{
|
||||
try (Connection con = Plex.get().getSqlConnection().getCon())
|
||||
try
|
||||
{
|
||||
PlexLog.debug("Running execute punishment on " + punishment.getPunished().toString());
|
||||
PreparedStatement statement = con.prepareStatement(INSERT);
|
||||
statement.setString(1, punishment.getPunished().toString());
|
||||
statement.setString(2, punishment.getPunisher() == null ? null : punishment.getPunisher().toString());
|
||||
statement.setString(3, punishment.getPunisherName());
|
||||
statement.setString(4, punishment.getPunishedUsername());
|
||||
statement.setString(5, punishment.getIp());
|
||||
statement.setString(6, punishment.getType().name());
|
||||
statement.setString(7, punishment.getReason());
|
||||
statement.setBoolean(8, punishment.isCustomTime());
|
||||
statement.setBoolean(9, punishment.isActive());
|
||||
statement.setLong(10, punishment.getEndDate().toInstant().toEpochMilli());
|
||||
PlexLog.debug("Executing punishment");
|
||||
statement.execute();
|
||||
PlexLog.debug("Persisting punishment for " + punishment.getPunished());
|
||||
punishments.create(toEntity(punishment));
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
@@ -146,19 +95,28 @@ public class SQLPunishment
|
||||
|
||||
public void syncRemoveBan(UUID uuid)
|
||||
{
|
||||
try (Connection con = Plex.get().getSqlConnection().getCon())
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement(UPDATE_PUNISHMENT);
|
||||
statement.setBoolean(1, false);
|
||||
statement.setString(2, uuid.toString());
|
||||
statement.setString(3, PunishmentType.BAN.name());
|
||||
statement.executeUpdate();
|
||||
setActive(uuid, PunishmentType.BAN, false);
|
||||
setActive(uuid, PunishmentType.TEMPBAN, false);
|
||||
}
|
||||
|
||||
PreparedStatement statement1 = con.prepareStatement(UPDATE_PUNISHMENT);
|
||||
statement1.setBoolean(1, false);
|
||||
statement1.setString(2, uuid.toString());
|
||||
statement1.setString(3, PunishmentType.TEMPBAN.name());
|
||||
statement1.executeUpdate();
|
||||
public CompletableFuture<Void> updatePunishment(PunishmentType type, boolean active, UUID punished)
|
||||
{
|
||||
return CompletableFuture.runAsync(() -> setActive(punished, type, active));
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> removeBan(UUID uuid)
|
||||
{
|
||||
return CompletableFuture.runAsync(() -> syncRemoveBan(uuid));
|
||||
}
|
||||
|
||||
private void setActive(UUID punished, PunishmentType type, boolean active)
|
||||
{
|
||||
try
|
||||
{
|
||||
UpdateBuilder<PunishmentEntity, Long> update = punishments.updateBuilder();
|
||||
update.updateColumnValue("active", active);
|
||||
update.where().eq("punished", punished.toString()).and().eq("type", type.name());
|
||||
update.update();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
@@ -166,48 +124,36 @@ public class SQLPunishment
|
||||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> updatePunishment(PunishmentType type, boolean active, UUID punished)
|
||||
private Punishment toPunishment(PunishmentEntity entity)
|
||||
{
|
||||
return CompletableFuture.runAsync(() ->
|
||||
{
|
||||
try (Connection con = Plex.get().getSqlConnection().getCon())
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement(UPDATE_PUNISHMENT);
|
||||
statement.setBoolean(1, active);
|
||||
statement.setString(2, punished.toString());
|
||||
statement.setString(3, type.name());
|
||||
statement.executeUpdate();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
UUID punisher = entity.getPunisher() == null || entity.getPunisher().isBlank() ? null : UUID.fromString(entity.getPunisher());
|
||||
Punishment punishment = new Punishment(UUID.fromString(entity.getPunished()), punisher);
|
||||
punishment.setActive(entity.isActive());
|
||||
punishment.setType(PunishmentType.valueOf(entity.getType()));
|
||||
punishment.setCustomTime(entity.isCustomTime());
|
||||
punishment.setPunishedUsername(entity.getPunishedUsername());
|
||||
punishment.setPunisherName(entity.getPunisherName());
|
||||
punishment.setIssueDate(ZonedDateTime.ofInstant(Instant.ofEpochMilli(entity.getIssueDate()), ZoneId.of(TimeUtils.TIMEZONE)));
|
||||
punishment.setEndDate(ZonedDateTime.ofInstant(Instant.ofEpochMilli(entity.getEndDate()), ZoneId.of(TimeUtils.TIMEZONE)));
|
||||
punishment.setReason(entity.getReason());
|
||||
punishment.setIp(entity.getIp());
|
||||
return punishment;
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> removeBan(UUID uuid)
|
||||
private PunishmentEntity toEntity(Punishment punishment)
|
||||
{
|
||||
return CompletableFuture.runAsync(() ->
|
||||
{
|
||||
try (Connection con = Plex.get().getSqlConnection().getCon())
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement(UPDATE_PUNISHMENT);
|
||||
statement.setBoolean(1, false);
|
||||
statement.setString(2, uuid.toString());
|
||||
statement.setString(3, PunishmentType.BAN.name());
|
||||
statement.executeUpdate();
|
||||
|
||||
PreparedStatement statement1 = con.prepareStatement(UPDATE_PUNISHMENT);
|
||||
statement1.setBoolean(1, false);
|
||||
statement1.setString(2, uuid.toString());
|
||||
statement1.setString(3, PunishmentType.TEMPBAN.name());
|
||||
statement1.executeUpdate();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
PunishmentEntity entity = new PunishmentEntity();
|
||||
entity.setPunished(punishment.getPunished().toString());
|
||||
entity.setPunisher(punishment.getPunisher() == null ? null : punishment.getPunisher().toString());
|
||||
entity.setPunisherName(punishment.getPunisherName());
|
||||
entity.setPunishedUsername(punishment.getPunishedUsername());
|
||||
entity.setIp(punishment.getIp());
|
||||
entity.setType(punishment.getType().name());
|
||||
entity.setReason(punishment.getReason());
|
||||
entity.setCustomTime(punishment.isCustomTime());
|
||||
entity.setActive(punishment.isActive());
|
||||
entity.setIssueDate(punishment.getIssueDate().toInstant().toEpochMilli());
|
||||
entity.setEndDate(punishment.getEndDate().toInstant().toEpochMilli());
|
||||
return entity;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.google.common.collect.Lists;
|
||||
import dev.plex.Plex;
|
||||
import dev.plex.PlexBase;
|
||||
import dev.plex.listener.impl.ChatListener;
|
||||
import dev.plex.storage.StorageType;
|
||||
import dev.plex.util.minimessage.SafeMiniMessage;
|
||||
|
||||
import java.sql.Connection;
|
||||
@@ -85,14 +84,7 @@ public class PlexUtils implements PlexBase
|
||||
{
|
||||
try (Connection ignored = Plex.get().getSqlConnection().getCon())
|
||||
{
|
||||
if (Plex.get().getStorageType() == StorageType.MARIADB)
|
||||
{
|
||||
PlexLog.log("Successfully enabled MySQL!");
|
||||
}
|
||||
else if (Plex.get().getStorageType() == StorageType.SQLITE)
|
||||
{
|
||||
PlexLog.log("Successfully enabled SQLite!");
|
||||
}
|
||||
PlexLog.log("Successfully enabled " + Plex.get().getStorageType().getDisplayName() + "!");
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
|
||||
@@ -1,204 +0,0 @@
|
||||
package dev.plex.util.sql;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import dev.plex.punishment.PunishmentType;
|
||||
import dev.plex.storage.annotation.MapObjectList;
|
||||
import dev.plex.storage.annotation.NoLimit;
|
||||
import dev.plex.storage.annotation.PrimaryKey;
|
||||
import dev.plex.storage.annotation.SQLTable;
|
||||
import dev.plex.storage.annotation.VarcharLimit;
|
||||
import dev.plex.util.PlexLog;
|
||||
import dev.plex.util.ReflectionsUtil;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.experimental.Accessors;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Taah
|
||||
* @since 4:28 AM [25-08-2023]
|
||||
*/
|
||||
public class SQLUtil
|
||||
{
|
||||
public static final Map<String, Table> TABLES = Maps.newHashMap();
|
||||
|
||||
public static List<String> createTable(List<String> result, Class<?> clazz)
|
||||
{
|
||||
if (!clazz.isAnnotationPresent(SQLTable.class))
|
||||
{
|
||||
PlexLog.error("Unable to map {0} to a table, it is missing the SQLTable's annotation", clazz.getName());
|
||||
return null;
|
||||
}
|
||||
final List<Field> collectionFields = Lists.newArrayList();
|
||||
|
||||
final Table table = new Table(clazz.getAnnotation(SQLTable.class).value());
|
||||
|
||||
final StringBuilder mainResult = new StringBuilder("CREATE TABLE IF NOT EXISTS `" + table.name() + "` (");
|
||||
final List<Field> declaredFields = Arrays.stream(clazz.getDeclaredFields()).filter(field -> !Modifier.isTransient(field.getModifiers()) && !Modifier.isStatic(field.getModifiers())).collect(Collectors.toList());
|
||||
final List<Field> iterating = declaredFields.stream().toList();
|
||||
for (Field value : iterating)
|
||||
{
|
||||
if (Collection.class.isAssignableFrom(value.getType()))
|
||||
{
|
||||
collectionFields.add(value);
|
||||
declaredFields.remove(value);
|
||||
}
|
||||
}
|
||||
Field primaryKey = null;
|
||||
|
||||
for (int i = 0; i < declaredFields.size(); i++)
|
||||
{
|
||||
Field declaredField = declaredFields.get(i);
|
||||
final Mapper mapped = Mapper.getByClass(declaredField.getType());
|
||||
if (mapped == null)
|
||||
{
|
||||
PlexLog.warn("Could not map field {0} for class {1}", declaredField.getName(), clazz.getName());
|
||||
continue;
|
||||
}
|
||||
if (declaredField.isAnnotationPresent(PrimaryKey.class))
|
||||
{
|
||||
if (primaryKey != null)
|
||||
{
|
||||
PlexLog.error("You can only have one primary key for a table! The class {0} has more than one!", clazz.getName());
|
||||
return ImmutableList.of();
|
||||
}
|
||||
primaryKey = declaredField;
|
||||
}
|
||||
|
||||
writeFieldToSQL(table, mainResult, mapped, declaredField);
|
||||
if (i < declaredFields.size() - 1)
|
||||
{
|
||||
mainResult.append(", ");
|
||||
}
|
||||
}
|
||||
if (primaryKey != null && !primaryKey.getAnnotation(PrimaryKey.class).dontSet())
|
||||
{
|
||||
mainResult.append(", PRIMARY KEY (`").append(primaryKey.getName()).append("`)");
|
||||
}
|
||||
mainResult.append(");");
|
||||
result.add(mainResult.toString());
|
||||
|
||||
TABLES.put(table.name(), table);
|
||||
|
||||
if (primaryKey == null && !collectionFields.isEmpty())
|
||||
{
|
||||
PlexLog.error("You must define a primary key to point to if you wish to have a list saved. You can use @PrimaryKey(dontSet = true) to make sure that SQL does not save it as a primary key.");
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
Field finalPrimaryKey = primaryKey;
|
||||
collectionFields.forEach(field ->
|
||||
{
|
||||
final String tableName = field.getName() + "To" + StringUtils.capitalize(clazz.getSimpleName());
|
||||
StringBuilder sql = new StringBuilder("CREATE TABLE IF NOT EXISTS `" + tableName + "` (");
|
||||
if (field.isAnnotationPresent(MapObjectList.class))
|
||||
{
|
||||
createTable(result, ReflectionsUtil.getGenericField(field));
|
||||
return;
|
||||
}
|
||||
final Mapper mapped = Mapper.getByClass(ReflectionsUtil.getGenericField(field));
|
||||
if (mapped == null)
|
||||
{
|
||||
PlexLog.warn("Could not map collection field {0} for class {1}", field.getName(), clazz.getName());
|
||||
return;
|
||||
}
|
||||
final Table listTable = new Table(tableName);
|
||||
writeFieldToSQL(listTable, sql, mapped, field);
|
||||
sql.append(", ");
|
||||
writeFieldToSQL(listTable, sql, Mapper.getByClass(finalPrimaryKey.getType()), finalPrimaryKey);
|
||||
sql.append(");");
|
||||
result.add(sql.toString());
|
||||
table.mappedTables().put(field, listTable);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void update(String tableName, Object object)
|
||||
{
|
||||
final Table table = TABLES.get(tableName);
|
||||
if (table == null)
|
||||
{
|
||||
PlexLog.error("Table {0} was not found", tableName);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void writeFieldToSQL(Table table, StringBuilder sb, Mapper mapped, Field field)
|
||||
{
|
||||
|
||||
sb.append("`").append(field.getName()).append("` ");
|
||||
if (mapped == Mapper.VARCHAR)
|
||||
{
|
||||
if (field.isAnnotationPresent(NoLimit.class))
|
||||
{
|
||||
sb.append("TEXT");
|
||||
table.columns().put(field.getName(), Mapper.TEXT);
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append(mapped.name());
|
||||
table.columns().put(field.getName(), mapped);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append(mapped.name());
|
||||
table.columns().put(field.getName(), mapped);
|
||||
}
|
||||
if (mapped == Mapper.VARCHAR && !field.isAnnotationPresent(NoLimit.class))
|
||||
{
|
||||
if (UUID.class.isAssignableFrom(field.getType()))
|
||||
{
|
||||
sb.append(" (").append(36).append(")");
|
||||
}
|
||||
else if (field.isAnnotationPresent(VarcharLimit.class))
|
||||
{
|
||||
int limit = field.getAnnotation(VarcharLimit.class).value();
|
||||
sb.append(" (").append(limit).append(")");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append("(65535)");
|
||||
}
|
||||
}
|
||||
if (field.isAnnotationPresent(NotNull.class))
|
||||
{
|
||||
sb.append(" NOT NULL");
|
||||
}
|
||||
}
|
||||
|
||||
@Accessors(fluent = true)
|
||||
public enum Mapper
|
||||
{
|
||||
VARCHAR(String.class, UUID.class, PunishmentType.class),
|
||||
BOOLEAN(Boolean.class, boolean.class),
|
||||
BIGINT(Long.class, long.class, ZonedDateTime.class),
|
||||
INT(Integer.class, int.class),
|
||||
TEXT;
|
||||
|
||||
private final Class<?>[] clazz;
|
||||
|
||||
Mapper(Class<?>... clazz)
|
||||
{
|
||||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
public static Mapper getByClass(Class<?> clazz)
|
||||
{
|
||||
return Arrays.stream(values()).filter(mapper -> mapper.clazz != null && Arrays.asList(mapper.clazz).contains(clazz)).findFirst().orElse(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package dev.plex.util.sql;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* @author Taah
|
||||
* @since 5:30 AM [26-08-2023]
|
||||
*/
|
||||
|
||||
@Data
|
||||
@Accessors(fluent = true)
|
||||
public class Table
|
||||
{
|
||||
private final String name;
|
||||
private final Map<String, SQLUtil.Mapper> columns = Maps.newHashMap();
|
||||
private final Map<Field, Table> mappedTables = Maps.newHashMap();
|
||||
}
|
||||
@@ -41,14 +41,14 @@ loginmessages:
|
||||
name: true
|
||||
|
||||
data:
|
||||
central:
|
||||
storage: sqlite # Use mariadb, or sqlite here
|
||||
db:
|
||||
storage: sqlite # Use mariadb, postgres, or sqlite here
|
||||
user: ""
|
||||
password: ""
|
||||
hostname: 127.0.0.1
|
||||
port: 27017
|
||||
db: "plex"
|
||||
side: # This is Redis, leave password blank if auth is false
|
||||
port: 3306
|
||||
name: "plex"
|
||||
redis: # Leave password blank if auth is false
|
||||
enabled: false
|
||||
auth: true
|
||||
hostname: 127.0.0.1
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
CREATE TABLE IF NOT EXISTS `players` (
|
||||
`uuid` VARCHAR(46) NOT NULL,
|
||||
`name` VARCHAR(18),
|
||||
`login_msg` VARCHAR(2000),
|
||||
`prefix` VARCHAR(2000),
|
||||
`staffChat` BOOLEAN,
|
||||
`ips` VARCHAR(2000),
|
||||
`coins` BIGINT,
|
||||
`vanished` BOOLEAN,
|
||||
`commandspy` BOOLEAN,
|
||||
PRIMARY KEY (`uuid`),
|
||||
INDEX `idx_players_name` (`name`)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `punishments` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`punished` VARCHAR(46) NOT NULL,
|
||||
`punisher` VARCHAR(46),
|
||||
`punisherName` VARCHAR(64),
|
||||
`punishedUsername` VARCHAR(16),
|
||||
`ip` VARCHAR(2000),
|
||||
`type` VARCHAR(30),
|
||||
`reason` VARCHAR(2000),
|
||||
`customTime` BOOLEAN,
|
||||
`active` BOOLEAN,
|
||||
`issueDate` BIGINT NOT NULL,
|
||||
`endDate` BIGINT,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `idx_punishments_punished` (`punished`),
|
||||
INDEX `idx_punishments_ip` (`ip`(64))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `notes` (
|
||||
`row_id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`id` INT NOT NULL,
|
||||
`uuid` VARCHAR(46) NOT NULL,
|
||||
`written_by` VARCHAR(46),
|
||||
`note` VARCHAR(2000),
|
||||
`timestamp` BIGINT,
|
||||
PRIMARY KEY (`row_id`),
|
||||
INDEX `idx_notes_uuid` (`uuid`)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `player_ips` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`player_uuid` VARCHAR(46) NOT NULL,
|
||||
`ip` VARCHAR(64) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uq_player_ips_player_ip` (`player_uuid`, `ip`),
|
||||
INDEX `idx_player_ips_ip` (`ip`)
|
||||
);
|
||||
@@ -0,0 +1,51 @@
|
||||
CREATE TABLE IF NOT EXISTS players (
|
||||
uuid VARCHAR(46) NOT NULL PRIMARY KEY,
|
||||
name VARCHAR(18),
|
||||
login_msg VARCHAR(2000),
|
||||
prefix VARCHAR(2000),
|
||||
staffChat BOOLEAN,
|
||||
ips VARCHAR(2000),
|
||||
coins BIGINT,
|
||||
vanished BOOLEAN,
|
||||
commandspy BOOLEAN
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_players_name ON players(name);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS punishments (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
punished VARCHAR(46) NOT NULL,
|
||||
punisher VARCHAR(46),
|
||||
punisherName VARCHAR(64),
|
||||
punishedUsername VARCHAR(16),
|
||||
ip VARCHAR(2000),
|
||||
type VARCHAR(30),
|
||||
reason VARCHAR(2000),
|
||||
customTime BOOLEAN,
|
||||
active BOOLEAN,
|
||||
issueDate BIGINT NOT NULL,
|
||||
endDate BIGINT
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_punishments_punished ON punishments(punished);
|
||||
CREATE INDEX IF NOT EXISTS idx_punishments_ip ON punishments(ip);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS notes (
|
||||
row_id BIGSERIAL PRIMARY KEY,
|
||||
id INT NOT NULL,
|
||||
uuid VARCHAR(46) NOT NULL,
|
||||
written_by VARCHAR(46),
|
||||
note VARCHAR(2000),
|
||||
timestamp BIGINT
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_notes_uuid ON notes(uuid);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS player_ips (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
player_uuid VARCHAR(46) NOT NULL,
|
||||
ip VARCHAR(64) NOT NULL,
|
||||
CONSTRAINT uq_player_ips_player_ip UNIQUE (player_uuid, ip)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_player_ips_ip ON player_ips(ip);
|
||||
@@ -0,0 +1,48 @@
|
||||
CREATE TABLE IF NOT EXISTS players (
|
||||
uuid VARCHAR(46) NOT NULL PRIMARY KEY,
|
||||
name VARCHAR(18),
|
||||
login_msg VARCHAR(2000),
|
||||
prefix VARCHAR(2000),
|
||||
staffChat BOOLEAN,
|
||||
ips VARCHAR(2000),
|
||||
coins BIGINT,
|
||||
vanished BOOLEAN,
|
||||
commandspy BOOLEAN
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS punishments (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
punished VARCHAR(46) NOT NULL,
|
||||
punisher VARCHAR(46),
|
||||
punisherName VARCHAR(64),
|
||||
punishedUsername VARCHAR(16),
|
||||
ip VARCHAR(2000),
|
||||
type VARCHAR(30),
|
||||
reason VARCHAR(2000),
|
||||
customTime BOOLEAN,
|
||||
active BOOLEAN,
|
||||
issueDate BIGINT NOT NULL,
|
||||
endDate BIGINT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS notes (
|
||||
row_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
id INT NOT NULL,
|
||||
uuid VARCHAR(46) NOT NULL,
|
||||
written_by VARCHAR(46),
|
||||
note VARCHAR(2000),
|
||||
timestamp BIGINT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS player_ips (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
player_uuid VARCHAR(46) NOT NULL,
|
||||
ip VARCHAR(64) NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_players_name ON players(name);
|
||||
CREATE INDEX IF NOT EXISTS idx_punishments_punished ON punishments(punished);
|
||||
CREATE INDEX IF NOT EXISTS idx_punishments_ip ON punishments(ip);
|
||||
CREATE INDEX IF NOT EXISTS idx_notes_uuid ON notes(uuid);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uq_player_ips_player_ip ON player_ips(player_uuid, ip);
|
||||
CREATE INDEX IF NOT EXISTS idx_player_ips_ip ON player_ips(ip);
|
||||
Reference in New Issue
Block a user