feat: RP support, config-driven GUI, rich Discord embeds, i18n messages.yml
This commit is contained in:
parent
987e69a976
commit
c9f75fbcf2
17 changed files with 1106 additions and 235 deletions
|
|
@ -22,6 +22,7 @@ dependencies {
|
||||||
// Paper API для 1.19.4+
|
// Paper API для 1.19.4+
|
||||||
compileOnly("io.papermc.paper:paper-api:1.19.4-R0.1-SNAPSHOT")
|
compileOnly("io.papermc.paper:paper-api:1.19.4-R0.1-SNAPSHOT")
|
||||||
|
|
||||||
|
implementation("com.google.code.gson:gson:2.11.0")
|
||||||
implementation("com.squareup.okhttp3:okhttp:4.12.0")
|
implementation("com.squareup.okhttp3:okhttp:4.12.0")
|
||||||
implementation("com.zaxxer:HikariCP:6.2.1")
|
implementation("com.zaxxer:HikariCP:6.2.1")
|
||||||
implementation("org.postgresql:postgresql:42.7.4")
|
implementation("org.postgresql:postgresql:42.7.4")
|
||||||
|
|
|
||||||
|
|
@ -16,127 +16,177 @@ import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class ReportCommand implements CommandExecutor, TabCompleter {
|
public class ReportCommand implements CommandExecutor, TabCompleter {
|
||||||
|
|
||||||
private final LorepPlugin plugin;
|
private final LorepPlugin plugin;
|
||||||
|
|
||||||
public ReportCommand(LorepPlugin plugin) {
|
public ReportCommand(LorepPlugin plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
if (!(sender instanceof Player player)) {
|
if (!(sender instanceof Player player)) {
|
||||||
sender.sendMessage("§cЭта команда только для игроков!");
|
sender.sendMessage(plugin.getConfigManager().getMessage("console-only"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.length == 0) {
|
if (args.length == 0) {
|
||||||
player.sendMessage(plugin.getConfigManager().getMessage("usage"));
|
player.sendMessage(plugin.getConfigManager().getMessage("usage"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle subcommands for admins
|
|
||||||
if (args[0].equalsIgnoreCase("gui")) {
|
if (args[0].equalsIgnoreCase("gui")) {
|
||||||
return handleGui(player);
|
return handleGui(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args[0].equalsIgnoreCase("stats") && args.length >= 2) {
|
if (args[0].equalsIgnoreCase("stats") && args.length >= 2) {
|
||||||
return handleStats(player, args[1]);
|
return handleStats(player, args[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Regular report command
|
if (args[0].equalsIgnoreCase("image") && args.length >= 3) {
|
||||||
|
return handleReportImage(player, args[1], args[2]);
|
||||||
|
}
|
||||||
|
|
||||||
if (!player.hasPermission("lorep.report")) {
|
if (!player.hasPermission("lorep.report")) {
|
||||||
player.sendMessage(plugin.getConfigManager().getMessage("no-permission"));
|
player.sendMessage(plugin.getConfigManager().getMessage("no-permission"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.length < 2) {
|
if (args.length < 2) {
|
||||||
player.sendMessage(plugin.getConfigManager().getMessage("usage"));
|
player.sendMessage(plugin.getConfigManager().getMessage("usage"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
String targetName = args[0];
|
|
||||||
String reason = String.join(" ", Arrays.copyOfRange(args, 1, args.length));
|
|
||||||
|
|
||||||
// Validate reason
|
String targetName = args[0];
|
||||||
|
String reason;
|
||||||
|
String imageUrl = null;
|
||||||
|
|
||||||
|
if (args.length >= 3 && args[2].startsWith("http")) {
|
||||||
|
reason = args[1];
|
||||||
|
imageUrl = args[2];
|
||||||
|
} else {
|
||||||
|
reason = String.join(" ", Arrays.copyOfRange(args, 1, args.length));
|
||||||
|
}
|
||||||
|
|
||||||
if (reason.trim().isEmpty()) {
|
if (reason.trim().isEmpty()) {
|
||||||
player.sendMessage(plugin.getConfigManager().getMessage("usage"));
|
player.sendMessage(plugin.getConfigManager().getMessage("usage"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reason.length() > 500) {
|
if (reason.length() > 500) {
|
||||||
player.sendMessage("§cПричина слишком длинная! Максимум 500 символов.");
|
player.sendMessage(plugin.getConfigManager().getMessage("reason-too-long", "%max%", "500"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return handleReport(player, targetName, reason);
|
return handleReport(player, targetName, reason, imageUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean handleReport(Player reporter, String targetName, String reason) {
|
private boolean handleReport(Player reporter, String targetName, String reason) {
|
||||||
// Check if target exists
|
return handleReport(reporter, targetName, reason, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean handleReport(Player reporter, String targetName, String reason, String imageUrl) {
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
OfflinePlayer target = Bukkit.getOfflinePlayer(targetName);
|
OfflinePlayer target = Bukkit.getOfflinePlayer(targetName);
|
||||||
|
|
||||||
if (!target.hasPlayedBefore() && !target.isOnline()) {
|
if (!target.hasPlayedBefore() && !target.isOnline()) {
|
||||||
reporter.sendMessage(plugin.getConfigManager().getMessage("player-not-found"));
|
reporter.sendMessage(plugin.getConfigManager().getMessage("player-not-found"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check self-report
|
|
||||||
if (target.getUniqueId().equals(reporter.getUniqueId())) {
|
if (target.getUniqueId().equals(reporter.getUniqueId())) {
|
||||||
reporter.sendMessage(plugin.getConfigManager().getMessage("self-report"));
|
reporter.sendMessage(plugin.getConfigManager().getMessage("self-report"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check duplicate report
|
|
||||||
if (plugin.getDatabaseManager().hasReported(reporter.getUniqueId(), target.getUniqueId())) {
|
if (plugin.getDatabaseManager().hasReported(reporter.getUniqueId(), target.getUniqueId())) {
|
||||||
reporter.sendMessage(plugin.getConfigManager().getMessage("already-reported"));
|
reporter.sendMessage(plugin.getConfigManager().getMessage("already-reported"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create and save report
|
|
||||||
Report report = new Report(
|
Report report = new Report(
|
||||||
reporter.getUniqueId(),
|
reporter.getUniqueId(),
|
||||||
reporter.getName(),
|
reporter.getName(),
|
||||||
target.getUniqueId(),
|
target.getUniqueId(),
|
||||||
target.getName() != null ? target.getName() : targetName,
|
target.getName() != null ? target.getName() : targetName,
|
||||||
reason
|
reason,
|
||||||
|
imageUrl
|
||||||
);
|
);
|
||||||
|
|
||||||
plugin.getDatabaseManager().saveReport(report);
|
plugin.getDatabaseManager().saveReport(report);
|
||||||
|
|
||||||
// Send to Discord webhook
|
|
||||||
if (plugin.getDiscordWebhook() != null) {
|
if (plugin.getDiscordWebhook() != null) {
|
||||||
plugin.getDiscordWebhook().sendReport(report);
|
plugin.getDiscordWebhook().sendReport(report);
|
||||||
}
|
}
|
||||||
|
|
||||||
reporter.sendMessage(plugin.getConfigManager().getMessage("report-sent"));
|
reporter.sendMessage(plugin.getConfigManager().getMessage("report-sent"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean handleReportImage(Player player, String idStr, String imageUrl) {
|
||||||
|
if (!player.hasPermission("lorep.admin")) {
|
||||||
|
player.sendMessage(plugin.getConfigManager().getMessage("no-permission"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int reportId;
|
||||||
|
try {
|
||||||
|
reportId = Integer.parseInt(idStr);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
player.sendMessage(plugin.getConfigManager().getMessage("invalid-report-id"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Report report = plugin.getDatabaseManager().getReportById(reportId);
|
||||||
|
if (report == null) {
|
||||||
|
player.sendMessage(plugin.getConfigManager().getMessage("report-not-found"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.getDatabaseManager().updateReportImage(reportId, imageUrl);
|
||||||
|
|
||||||
|
Report updated = new Report(
|
||||||
|
report.id(),
|
||||||
|
report.reporterUuid(),
|
||||||
|
report.reporterName(),
|
||||||
|
report.targetUuid(),
|
||||||
|
report.targetName(),
|
||||||
|
report.reason(),
|
||||||
|
imageUrl,
|
||||||
|
report.status(),
|
||||||
|
report.createdAt()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (plugin.getDiscordWebhook() != null) {
|
||||||
|
plugin.getDiscordWebhook().sendReport(updated);
|
||||||
|
}
|
||||||
|
|
||||||
|
player.sendMessage(plugin.getConfigManager().getMessage("report-image-updated", "%id%", String.valueOf(reportId)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean handleGui(Player player) {
|
private boolean handleGui(Player player) {
|
||||||
if (!player.hasPermission("lorep.admin")) {
|
if (!player.hasPermission("lorep.admin")) {
|
||||||
player.sendMessage(plugin.getConfigManager().getMessage("no-permission"));
|
player.sendMessage(plugin.getConfigManager().getMessage("no-permission"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
new dev.loki.lorep.gui.ReportGui(plugin, 0).open(player);
|
new dev.loki.lorep.gui.ReportGui(plugin, 0).open(player);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean handleStats(Player player, String targetName) {
|
private boolean handleStats(Player player, String targetName) {
|
||||||
new ReportStatsCommand(plugin).execute(player, targetName);
|
new ReportStatsCommand(plugin).execute(player, targetName);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
|
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
|
||||||
List<String> completions = new ArrayList<>();
|
List<String> completions = new ArrayList<>();
|
||||||
|
|
||||||
if (args.length == 1) {
|
if (args.length == 1) {
|
||||||
// First argument: player names or subcommands
|
|
||||||
String input = args[0].toLowerCase();
|
String input = args[0].toLowerCase();
|
||||||
|
|
||||||
if (sender.hasPermission("lorep.admin")) {
|
if (sender.hasPermission("lorep.admin")) {
|
||||||
if ("gui".startsWith(input)) {
|
if ("gui".startsWith(input)) {
|
||||||
completions.add("gui");
|
completions.add("gui");
|
||||||
|
|
@ -144,9 +194,11 @@ public class ReportCommand implements CommandExecutor, TabCompleter {
|
||||||
if ("stats".startsWith(input)) {
|
if ("stats".startsWith(input)) {
|
||||||
completions.add("stats");
|
completions.add("stats");
|
||||||
}
|
}
|
||||||
|
if ("image".startsWith(input)) {
|
||||||
|
completions.add("image");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add online player names
|
|
||||||
completions.addAll(
|
completions.addAll(
|
||||||
Bukkit.getOnlinePlayers().stream()
|
Bukkit.getOnlinePlayers().stream()
|
||||||
.map(Player::getName)
|
.map(Player::getName)
|
||||||
|
|
@ -154,7 +206,6 @@ public class ReportCommand implements CommandExecutor, TabCompleter {
|
||||||
.collect(Collectors.toList())
|
.collect(Collectors.toList())
|
||||||
);
|
);
|
||||||
} else if (args.length == 2 && args[0].equalsIgnoreCase("stats")) {
|
} else if (args.length == 2 && args[0].equalsIgnoreCase("stats")) {
|
||||||
// Second argument for stats: player names
|
|
||||||
String input = args[1].toLowerCase();
|
String input = args[1].toLowerCase();
|
||||||
completions.addAll(
|
completions.addAll(
|
||||||
Bukkit.getOnlinePlayers().stream()
|
Bukkit.getOnlinePlayers().stream()
|
||||||
|
|
@ -163,7 +214,7 @@ public class ReportCommand implements CommandExecutor, TabCompleter {
|
||||||
.collect(Collectors.toList())
|
.collect(Collectors.toList())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return completions;
|
return completions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,14 +49,13 @@ public class ReportStatsCommand {
|
||||||
player.sendMessage(plugin.getConfigManager().getMessage("stats-count",
|
player.sendMessage(plugin.getConfigManager().getMessage("stats-count",
|
||||||
"%count%", String.valueOf(reportCount)));
|
"%count%", String.valueOf(reportCount)));
|
||||||
|
|
||||||
// Last online
|
String lastOnline = target.isOnline()
|
||||||
String lastOnline = target.isOnline() ? "Сейчас онлайн" :
|
? plugin.getConfigManager().getMessage("online-status")
|
||||||
TimeUtil.formatTimeAgo(target.getLastPlayed());
|
: TimeUtil.formatTimeAgo(target.getLastPlayed());
|
||||||
player.sendMessage(plugin.getConfigManager().getMessage("stats-last-online",
|
player.sendMessage(plugin.getConfigManager().getMessage("stats-last-online",
|
||||||
"%time%", lastOnline));
|
"%time%", lastOnline));
|
||||||
|
|
||||||
// Recent reports (max 5)
|
player.sendMessage(plugin.getConfigManager().getMessage("stats-recent-header"));
|
||||||
player.sendMessage("§7Последние репорты:");
|
|
||||||
int shown = Math.min(MAX_RECENT_REPORTS, reports.size());
|
int shown = Math.min(MAX_RECENT_REPORTS, reports.size());
|
||||||
for (int i = 0; i < shown; i++) {
|
for (int i = 0; i < shown; i++) {
|
||||||
Report report = reports.get(i);
|
Report report = reports.get(i);
|
||||||
|
|
@ -67,7 +66,8 @@ public class ReportStatsCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reports.size() > MAX_RECENT_REPORTS) {
|
if (reports.size() > MAX_RECENT_REPORTS) {
|
||||||
player.sendMessage("§7... и ещё " + (reports.size() - MAX_RECENT_REPORTS) + " репортов");
|
player.sendMessage(plugin.getConfigManager().getMessage("stats-more-reports",
|
||||||
|
"%count%", String.valueOf(reports.size() - MAX_RECENT_REPORTS)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,21 @@ package dev.loki.lorep.config;
|
||||||
|
|
||||||
import dev.loki.lorep.LorepPlugin;
|
import dev.loki.lorep.LorepPlugin;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class ConfigManager {
|
public class ConfigManager {
|
||||||
|
|
||||||
private final LorepPlugin plugin;
|
private final LorepPlugin plugin;
|
||||||
private FileConfiguration config;
|
private FileConfiguration config;
|
||||||
|
private FileConfiguration messages;
|
||||||
|
|
||||||
public ConfigManager(LorepPlugin plugin) {
|
public ConfigManager(LorepPlugin plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
|
@ -18,6 +27,15 @@ public class ConfigManager {
|
||||||
plugin.saveDefaultConfig();
|
plugin.saveDefaultConfig();
|
||||||
plugin.reloadConfig();
|
plugin.reloadConfig();
|
||||||
this.config = plugin.getConfig();
|
this.config = plugin.getConfig();
|
||||||
|
loadMessages();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadMessages() {
|
||||||
|
File messagesFile = new File(plugin.getDataFolder(), "messages.yml");
|
||||||
|
if (!messagesFile.exists()) {
|
||||||
|
plugin.saveResource("messages.yml", false);
|
||||||
|
}
|
||||||
|
this.messages = YamlConfiguration.loadConfiguration(messagesFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getWebhookUrl() {
|
public String getWebhookUrl() {
|
||||||
|
|
@ -57,10 +75,52 @@ public class ConfigManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMessage(String key) {
|
public String getMessage(String key) {
|
||||||
String message = config.getString("messages." + key, "&cMessage not found: " + key);
|
String message = messages.getString(key);
|
||||||
|
if (message == null) {
|
||||||
|
message = config.getString("messages." + key);
|
||||||
|
}
|
||||||
|
if (message == null) {
|
||||||
|
message = "&cMessage not found: " + key;
|
||||||
|
}
|
||||||
return ChatColor.translateAlternateColorCodes('&', message);
|
return ChatColor.translateAlternateColorCodes('&', message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GuiItemConfig getGuiItem(String path) {
|
||||||
|
ConfigurationSection section = config.getConfigurationSection("gui.items." + path);
|
||||||
|
if (section == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Material material = Material.getMaterial(section.getString("material", "STONE").toUpperCase());
|
||||||
|
if (material == null) {
|
||||||
|
material = Material.STONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int customModelData = section.contains("custom-model-data") ? section.getInt("custom-model-data") : GuiItemConfig.NO_CUSTOM_MODEL;
|
||||||
|
|
||||||
|
String displayName = section.contains("name") ? ChatColor.translateAlternateColorCodes('&', section.getString("name")) : null;
|
||||||
|
|
||||||
|
List<String> lore = section.contains("lore")
|
||||||
|
? section.getStringList("lore").stream()
|
||||||
|
.map(line -> ChatColor.translateAlternateColorCodes('&', line))
|
||||||
|
.collect(Collectors.toList())
|
||||||
|
: Collections.emptyList();
|
||||||
|
|
||||||
|
List<Integer> slots = section.contains("slots") ? section.getIntegerList("slots") : Collections.emptyList();
|
||||||
|
|
||||||
|
boolean glowing = section.getBoolean("glowing", false);
|
||||||
|
|
||||||
|
return new GuiItemConfig(material, customModelData, displayName, lore, slots, glowing);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Integer> getItemSlots(String path) {
|
||||||
|
GuiItemConfig config = getGuiItem(path);
|
||||||
|
if (config != null && !config.slots().isEmpty()) {
|
||||||
|
return config.slots();
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
public String getMessage(String key, String... replacements) {
|
public String getMessage(String key, String... replacements) {
|
||||||
String message = getMessage(key);
|
String message = getMessage(key);
|
||||||
if (replacements == null || replacements.length == 0) {
|
if (replacements == null || replacements.length == 0) {
|
||||||
|
|
|
||||||
42
src/main/java/dev/loki/lorep/config/GuiItemConfig.java
Normal file
42
src/main/java/dev/loki/lorep/config/GuiItemConfig.java
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
package dev.loki.lorep.config;
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.enchantments.Enchantment;
|
||||||
|
import org.bukkit.inventory.ItemFlag;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public record GuiItemConfig(
|
||||||
|
Material material,
|
||||||
|
int customModelData,
|
||||||
|
String displayName,
|
||||||
|
List<String> lore,
|
||||||
|
List<Integer> slots,
|
||||||
|
boolean glowing
|
||||||
|
) {
|
||||||
|
public static final int NO_CUSTOM_MODEL = -1;
|
||||||
|
|
||||||
|
public ItemStack createItem() {
|
||||||
|
ItemStack item = new ItemStack(material);
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
if (meta != null) {
|
||||||
|
if (customModelData != NO_CUSTOM_MODEL) {
|
||||||
|
meta.setCustomModelData(customModelData);
|
||||||
|
}
|
||||||
|
if (displayName != null) {
|
||||||
|
meta.setDisplayName(displayName);
|
||||||
|
}
|
||||||
|
if (lore != null && !lore.isEmpty()) {
|
||||||
|
meta.setLore(lore);
|
||||||
|
}
|
||||||
|
if (glowing) {
|
||||||
|
meta.addEnchant(Enchantment.DURABILITY, 1, true);
|
||||||
|
meta.addItemFlags(ItemFlag.HIDE_ENCHANTS);
|
||||||
|
}
|
||||||
|
item.setItemMeta(meta);
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -20,6 +20,12 @@ public interface DatabaseManager {
|
||||||
boolean hasReported(UUID reporterUuid, UUID targetUuid);
|
boolean hasReported(UUID reporterUuid, UUID targetUuid);
|
||||||
|
|
||||||
List<Report> getReportsPaginated(int page, int pageSize);
|
List<Report> getReportsPaginated(int page, int pageSize);
|
||||||
|
|
||||||
int getTotalReportCount();
|
int getTotalReportCount();
|
||||||
|
|
||||||
|
void updateReportStatus(int reportId, String status);
|
||||||
|
|
||||||
|
void updateReportImage(int reportId, String imageUrl);
|
||||||
|
|
||||||
|
Report getReportById(int id);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,8 @@ public class PostgreSQLDatabaseManager implements DatabaseManager {
|
||||||
target_uuid TEXT NOT NULL,
|
target_uuid TEXT NOT NULL,
|
||||||
target_name TEXT NOT NULL,
|
target_name TEXT NOT NULL,
|
||||||
reason TEXT NOT NULL,
|
reason TEXT NOT NULL,
|
||||||
|
image_url TEXT,
|
||||||
|
status TEXT NOT NULL DEFAULT 'PENDING',
|
||||||
created_at BIGINT NOT NULL
|
created_at BIGINT NOT NULL
|
||||||
)
|
)
|
||||||
""";
|
""";
|
||||||
|
|
@ -98,7 +100,8 @@ public class PostgreSQLDatabaseManager implements DatabaseManager {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveReport(Report report) {
|
public void saveReport(Report report) {
|
||||||
String sql = "INSERT INTO reports (reporter_uuid, reporter_name, target_uuid, target_name, reason, created_at) VALUES (?, ?, ?, ?, ?, ?)";
|
String sql = "INSERT INTO reports (reporter_uuid, reporter_name, target_uuid, "
|
||||||
|
+ "target_name, reason, image_url, status, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
|
||||||
|
|
||||||
try (Connection conn = dataSource.getConnection();
|
try (Connection conn = dataSource.getConnection();
|
||||||
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
||||||
|
|
@ -107,7 +110,13 @@ public class PostgreSQLDatabaseManager implements DatabaseManager {
|
||||||
stmt.setString(3, report.targetUuid().toString());
|
stmt.setString(3, report.targetUuid().toString());
|
||||||
stmt.setString(4, report.targetName());
|
stmt.setString(4, report.targetName());
|
||||||
stmt.setString(5, report.reason());
|
stmt.setString(5, report.reason());
|
||||||
stmt.setLong(6, report.createdAt().toEpochMilli());
|
if (report.imageUrl() != null) {
|
||||||
|
stmt.setString(6, report.imageUrl());
|
||||||
|
} else {
|
||||||
|
stmt.setNull(6, java.sql.Types.VARCHAR);
|
||||||
|
}
|
||||||
|
stmt.setString(7, report.status());
|
||||||
|
stmt.setLong(8, report.createdAt().toEpochMilli());
|
||||||
stmt.executeUpdate();
|
stmt.executeUpdate();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
logger.log(Level.SEVERE, "Failed to save report", e);
|
logger.log(Level.SEVERE, "Failed to save report", e);
|
||||||
|
|
@ -230,6 +239,10 @@ public class PostgreSQLDatabaseManager implements DatabaseManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Report mapReport(ResultSet rs) throws SQLException {
|
private Report mapReport(ResultSet rs) throws SQLException {
|
||||||
|
String imageUrl = rs.getString("image_url");
|
||||||
|
if (rs.wasNull()) {
|
||||||
|
imageUrl = null;
|
||||||
|
}
|
||||||
return new Report(
|
return new Report(
|
||||||
rs.getInt("id"),
|
rs.getInt("id"),
|
||||||
UUID.fromString(rs.getString("reporter_uuid")),
|
UUID.fromString(rs.getString("reporter_uuid")),
|
||||||
|
|
@ -237,7 +250,60 @@ public class PostgreSQLDatabaseManager implements DatabaseManager {
|
||||||
UUID.fromString(rs.getString("target_uuid")),
|
UUID.fromString(rs.getString("target_uuid")),
|
||||||
rs.getString("target_name"),
|
rs.getString("target_name"),
|
||||||
rs.getString("reason"),
|
rs.getString("reason"),
|
||||||
|
imageUrl,
|
||||||
|
rs.getString("status"),
|
||||||
Instant.ofEpochMilli(rs.getLong("created_at"))
|
Instant.ofEpochMilli(rs.getLong("created_at"))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateReportStatus(int reportId, String status) {
|
||||||
|
String sql = "UPDATE reports SET status = ? WHERE id = ?";
|
||||||
|
|
||||||
|
try (Connection conn = dataSource.getConnection();
|
||||||
|
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
||||||
|
stmt.setString(1, status);
|
||||||
|
stmt.setInt(2, reportId);
|
||||||
|
stmt.executeUpdate();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
logger.log(Level.SEVERE, "Failed to update report status", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateReportImage(int reportId, String imageUrl) {
|
||||||
|
String sql = "UPDATE reports SET image_url = ? WHERE id = ?";
|
||||||
|
|
||||||
|
try (Connection conn = dataSource.getConnection();
|
||||||
|
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
||||||
|
if (imageUrl != null) {
|
||||||
|
stmt.setString(1, imageUrl);
|
||||||
|
} else {
|
||||||
|
stmt.setNull(1, java.sql.Types.VARCHAR);
|
||||||
|
}
|
||||||
|
stmt.setInt(2, reportId);
|
||||||
|
stmt.executeUpdate();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
logger.log(Level.SEVERE, "Failed to update report image", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Report getReportById(int id) {
|
||||||
|
String sql = "SELECT * FROM reports WHERE id = ?";
|
||||||
|
|
||||||
|
try (Connection conn = dataSource.getConnection();
|
||||||
|
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
||||||
|
stmt.setInt(1, id);
|
||||||
|
try (ResultSet rs = stmt.executeQuery()) {
|
||||||
|
if (rs.next()) {
|
||||||
|
return mapReport(rs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
logger.log(Level.SEVERE, "Failed to get report by id", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,15 @@ public record Report(
|
||||||
UUID targetUuid,
|
UUID targetUuid,
|
||||||
String targetName,
|
String targetName,
|
||||||
String reason,
|
String reason,
|
||||||
|
String imageUrl,
|
||||||
|
String status,
|
||||||
Instant createdAt
|
Instant createdAt
|
||||||
) {
|
) {
|
||||||
public Report(UUID reporterUuid, String reporterName, UUID targetUuid, String targetName, String reason) {
|
public Report(UUID reporterUuid, String reporterName, UUID targetUuid, String targetName, String reason) {
|
||||||
this(0, reporterUuid, reporterName, targetUuid, targetName, reason, Instant.now());
|
this(0, reporterUuid, reporterName, targetUuid, targetName, reason, null, "PENDING", Instant.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Report(UUID reporterUuid, String reporterName, UUID targetUuid, String targetName, String reason, String imageUrl) {
|
||||||
|
this(0, reporterUuid, reporterName, targetUuid, targetName, reason, imageUrl, "PENDING", Instant.now());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,8 @@ public class SQLiteDatabaseManager implements DatabaseManager {
|
||||||
target_uuid TEXT NOT NULL,
|
target_uuid TEXT NOT NULL,
|
||||||
target_name TEXT NOT NULL,
|
target_name TEXT NOT NULL,
|
||||||
reason TEXT NOT NULL,
|
reason TEXT NOT NULL,
|
||||||
|
image_url TEXT,
|
||||||
|
status TEXT NOT NULL DEFAULT 'PENDING',
|
||||||
created_at INTEGER NOT NULL
|
created_at INTEGER NOT NULL
|
||||||
)
|
)
|
||||||
""";
|
""";
|
||||||
|
|
@ -82,7 +84,8 @@ public class SQLiteDatabaseManager implements DatabaseManager {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveReport(Report report) {
|
public void saveReport(Report report) {
|
||||||
String sql = "INSERT INTO reports (reporter_uuid, reporter_name, target_uuid, target_name, reason, created_at) VALUES (?, ?, ?, ?, ?, ?)";
|
String sql = "INSERT INTO reports (reporter_uuid, reporter_name, target_uuid, "
|
||||||
|
+ "target_name, reason, image_url, status, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
|
||||||
|
|
||||||
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
|
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
|
||||||
stmt.setString(1, report.reporterUuid().toString());
|
stmt.setString(1, report.reporterUuid().toString());
|
||||||
|
|
@ -90,7 +93,13 @@ public class SQLiteDatabaseManager implements DatabaseManager {
|
||||||
stmt.setString(3, report.targetUuid().toString());
|
stmt.setString(3, report.targetUuid().toString());
|
||||||
stmt.setString(4, report.targetName());
|
stmt.setString(4, report.targetName());
|
||||||
stmt.setString(5, report.reason());
|
stmt.setString(5, report.reason());
|
||||||
stmt.setLong(6, report.createdAt().toEpochMilli());
|
if (report.imageUrl() != null) {
|
||||||
|
stmt.setString(6, report.imageUrl());
|
||||||
|
} else {
|
||||||
|
stmt.setNull(6, java.sql.Types.VARCHAR);
|
||||||
|
}
|
||||||
|
stmt.setString(7, report.status());
|
||||||
|
stmt.setLong(8, report.createdAt().toEpochMilli());
|
||||||
stmt.executeUpdate();
|
stmt.executeUpdate();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
logger.log(Level.SEVERE, "Failed to save report", e);
|
logger.log(Level.SEVERE, "Failed to save report", e);
|
||||||
|
|
@ -207,6 +216,10 @@ public class SQLiteDatabaseManager implements DatabaseManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Report mapReport(ResultSet rs) throws SQLException {
|
private Report mapReport(ResultSet rs) throws SQLException {
|
||||||
|
String imageUrl = rs.getString("image_url");
|
||||||
|
if (rs.wasNull()) {
|
||||||
|
imageUrl = null;
|
||||||
|
}
|
||||||
return new Report(
|
return new Report(
|
||||||
rs.getInt("id"),
|
rs.getInt("id"),
|
||||||
UUID.fromString(rs.getString("reporter_uuid")),
|
UUID.fromString(rs.getString("reporter_uuid")),
|
||||||
|
|
@ -214,7 +227,57 @@ public class SQLiteDatabaseManager implements DatabaseManager {
|
||||||
UUID.fromString(rs.getString("target_uuid")),
|
UUID.fromString(rs.getString("target_uuid")),
|
||||||
rs.getString("target_name"),
|
rs.getString("target_name"),
|
||||||
rs.getString("reason"),
|
rs.getString("reason"),
|
||||||
|
imageUrl,
|
||||||
|
rs.getString("status"),
|
||||||
Instant.ofEpochMilli(rs.getLong("created_at"))
|
Instant.ofEpochMilli(rs.getLong("created_at"))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateReportStatus(int reportId, String status) {
|
||||||
|
String sql = "UPDATE reports SET status = ? WHERE id = ?";
|
||||||
|
|
||||||
|
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
|
||||||
|
stmt.setString(1, status);
|
||||||
|
stmt.setInt(2, reportId);
|
||||||
|
stmt.executeUpdate();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
logger.log(Level.SEVERE, "Failed to update report status", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateReportImage(int reportId, String imageUrl) {
|
||||||
|
String sql = "UPDATE reports SET image_url = ? WHERE id = ?";
|
||||||
|
|
||||||
|
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
|
||||||
|
if (imageUrl != null) {
|
||||||
|
stmt.setString(1, imageUrl);
|
||||||
|
} else {
|
||||||
|
stmt.setNull(1, java.sql.Types.VARCHAR);
|
||||||
|
}
|
||||||
|
stmt.setInt(2, reportId);
|
||||||
|
stmt.executeUpdate();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
logger.log(Level.SEVERE, "Failed to update report image", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Report getReportById(int id) {
|
||||||
|
String sql = "SELECT * FROM reports WHERE id = ?";
|
||||||
|
|
||||||
|
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
|
||||||
|
stmt.setInt(1, id);
|
||||||
|
try (ResultSet rs = stmt.executeQuery()) {
|
||||||
|
if (rs.next()) {
|
||||||
|
return mapReport(rs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
logger.log(Level.SEVERE, "Failed to get report by id", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
package dev.loki.lorep.gui;
|
package dev.loki.lorep.gui;
|
||||||
|
|
||||||
import dev.loki.lorep.LorepPlugin;
|
import dev.loki.lorep.LorepPlugin;
|
||||||
|
import dev.loki.lorep.database.Report;
|
||||||
import dev.loki.lorep.util.PaginationUtil;
|
import dev.loki.lorep.util.PaginationUtil;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
|
|
@ -9,43 +11,119 @@ import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
import org.bukkit.event.inventory.InventoryDragEvent;
|
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||||
|
|
||||||
public class GuiClickListener implements Listener {
|
public class GuiClickListener implements Listener {
|
||||||
|
|
||||||
private final LorepPlugin plugin;
|
private final LorepPlugin plugin;
|
||||||
|
|
||||||
public GuiClickListener(LorepPlugin plugin) {
|
public GuiClickListener(LorepPlugin plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onInventoryClick(InventoryClickEvent event) {
|
public void onInventoryClick(InventoryClickEvent event) {
|
||||||
if (!(event.getInventory().getHolder() instanceof ReportGui gui)) {
|
if (!(event.getInventory().getHolder() instanceof ReportGui gui)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
|
|
||||||
if (!(event.getWhoClicked() instanceof Player player)) {
|
if (!(event.getWhoClicked() instanceof Player player)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int slot = event.getRawSlot();
|
|
||||||
|
|
||||||
// Navigation buttons are in bottom row
|
String action = gui.slotActions.get(event.getRawSlot());
|
||||||
if (slot == ReportGui.SLOT_PREV_PAGE) {
|
|
||||||
if (gui.getPage() > 0) {
|
if (action == null) {
|
||||||
new ReportGui(plugin, gui.getPage() - 1).open(player);
|
return;
|
||||||
}
|
}
|
||||||
} else if (slot == ReportGui.SLOT_CLOSE) {
|
|
||||||
player.closeInventory();
|
switch (action) {
|
||||||
} else if (slot == ReportGui.SLOT_NEXT_PAGE) {
|
case "prev_page" -> handlePrevPage(player, gui);
|
||||||
int totalReports = plugin.getDatabaseManager().getTotalReportCount();
|
case "next_page" -> handleNextPage(player, gui);
|
||||||
int totalPages = PaginationUtil.calculateTotalPages(totalReports, ReportGui.PAGE_SIZE);
|
case "close" -> handleClose(player, gui);
|
||||||
if (gui.getPage() < totalPages - 1) {
|
case "teleport" -> handleTeleport(player, gui);
|
||||||
new ReportGui(plugin, gui.getPage() + 1).open(player);
|
case "screenshot" -> handleScreenshot(player, gui);
|
||||||
}
|
default -> handleDefaultAction(player, gui, action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handlePrevPage(Player player, ReportGui gui) {
|
||||||
|
if (gui.page > 0) {
|
||||||
|
new ReportGui(plugin, gui.page - 1).open(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleNextPage(Player player, ReportGui gui) {
|
||||||
|
int totalReports = plugin.getDatabaseManager().getTotalReportCount();
|
||||||
|
int pageSize = plugin.getConfig().getInt("gui.reports-per-page", 45);
|
||||||
|
int totalPages = PaginationUtil.calculateTotalPages(totalReports, pageSize);
|
||||||
|
if (gui.page < totalPages - 1) {
|
||||||
|
new ReportGui(plugin, gui.page + 1).open(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleClose(Player player, ReportGui gui) {
|
||||||
|
if (gui.detailView) {
|
||||||
|
new ReportGui(plugin, gui.page).open(player);
|
||||||
|
} else {
|
||||||
|
player.closeInventory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleTeleport(Player player, ReportGui gui) {
|
||||||
|
Report report = gui.currentReport;
|
||||||
|
if (report == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Player target = Bukkit.getPlayer(report.targetUuid());
|
||||||
|
if (target != null && target.isOnline()) {
|
||||||
|
player.teleport(target.getLocation());
|
||||||
|
player.sendMessage(plugin.getConfigManager().getMessage("teleported-to", "%player%", report.targetName()));
|
||||||
|
} else {
|
||||||
|
player.sendMessage(plugin.getConfigManager().getMessage("player-offline", "%player%", report.targetName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleScreenshot(Player player, ReportGui gui) {
|
||||||
|
Report report = gui.currentReport;
|
||||||
|
if (report != null && report.imageUrl() != null && !report.imageUrl().isEmpty()) {
|
||||||
|
player.sendMessage(plugin.getConfigManager().getMessage("screenshot-link", "%url%", report.imageUrl()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleDefaultAction(Player player, ReportGui gui, String action) {
|
||||||
|
if (action.startsWith("status_set:")) {
|
||||||
|
handleStatusSet(player, gui, action.substring("status_set:".length()));
|
||||||
|
} else if (action.startsWith("report_detail:")) {
|
||||||
|
handleReportDetail(player, gui, action.substring("report_detail:".length()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleStatusSet(Player player, ReportGui gui, String status) {
|
||||||
|
Report report = gui.currentReport;
|
||||||
|
if (report == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
plugin.getDatabaseManager().updateReportStatus(report.id(), status);
|
||||||
|
Report updated = plugin.getDatabaseManager().getReportById(report.id());
|
||||||
|
if (updated != null && plugin.getDiscordWebhook() != null) {
|
||||||
|
plugin.getDiscordWebhook().sendStatusUpdate(updated);
|
||||||
|
}
|
||||||
|
if (updated != null) {
|
||||||
|
new ReportGui(plugin, gui.page).openDetail(player, updated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleReportDetail(Player player, ReportGui gui, String idStr) {
|
||||||
|
try {
|
||||||
|
int reportId = Integer.parseInt(idStr);
|
||||||
|
Report report = plugin.getDatabaseManager().getReportById(reportId);
|
||||||
|
if (report != null) {
|
||||||
|
new ReportGui(plugin, gui.page).openDetail(player, report);
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onInventoryDrag(InventoryDragEvent event) {
|
public void onInventoryDrag(InventoryDragEvent event) {
|
||||||
if (event.getInventory().getHolder() instanceof ReportGui) {
|
if (event.getInventory().getHolder() instanceof ReportGui) {
|
||||||
|
|
|
||||||
|
|
@ -1,140 +1,356 @@
|
||||||
package dev.loki.lorep.gui;
|
package dev.loki.lorep.gui;
|
||||||
|
|
||||||
import dev.loki.lorep.LorepPlugin;
|
import dev.loki.lorep.LorepPlugin;
|
||||||
|
import dev.loki.lorep.config.GuiItemConfig;
|
||||||
import dev.loki.lorep.database.Report;
|
import dev.loki.lorep.database.Report;
|
||||||
|
import dev.loki.lorep.util.PaginationUtil;
|
||||||
import dev.loki.lorep.util.TimeUtil;
|
import dev.loki.lorep.util.TimeUtil;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.enchantments.Enchantment;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.Inventory;
|
import org.bukkit.inventory.Inventory;
|
||||||
import org.bukkit.inventory.InventoryHolder;
|
import org.bukkit.inventory.InventoryHolder;
|
||||||
|
import org.bukkit.inventory.ItemFlag;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
import org.bukkit.inventory.meta.SkullMeta;
|
import org.bukkit.inventory.meta.SkullMeta;
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class ReportGui implements InventoryHolder {
|
public class ReportGui implements InventoryHolder {
|
||||||
|
|
||||||
public static final int PAGE_SIZE = 45; // 5 rows for reports
|
public static final int INVENTORY_SIZE = 54;
|
||||||
public static final int INVENTORY_SIZE = 54; // 6 rows total
|
|
||||||
|
|
||||||
public static final int SLOT_PREV_PAGE = 45;
|
final int page;
|
||||||
public static final int SLOT_CLOSE = 47;
|
boolean detailView;
|
||||||
public static final int SLOT_PAGE_INFO = 49;
|
Report currentReport;
|
||||||
public static final int SLOT_NEXT_PAGE = 53;
|
final Map<Integer, String> slotActions = new HashMap<>();
|
||||||
|
|
||||||
private final LorepPlugin plugin;
|
private final LorepPlugin plugin;
|
||||||
private final int page;
|
|
||||||
private Inventory inventory;
|
private Inventory inventory;
|
||||||
|
|
||||||
public ReportGui(LorepPlugin plugin, int page) {
|
public ReportGui(LorepPlugin plugin, int page) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.page = page;
|
this.page = page;
|
||||||
|
this.detailView = false;
|
||||||
|
this.currentReport = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void open(Player player) {
|
public void open(Player player) {
|
||||||
String title = plugin.getConfigManager().getMessage("gui-title", "%page%", String.valueOf(page + 1));
|
detailView = false;
|
||||||
|
currentReport = null;
|
||||||
|
slotActions.clear();
|
||||||
|
|
||||||
|
String title = plugin.getConfigManager().getMessage("gui-title",
|
||||||
|
"%page%", String.valueOf(page + 1));
|
||||||
this.inventory = Bukkit.createInventory(this, INVENTORY_SIZE, title);
|
this.inventory = Bukkit.createInventory(this, INVENTORY_SIZE, title);
|
||||||
|
|
||||||
List<Report> reports = plugin.getDatabaseManager().getReportsPaginated(page, PAGE_SIZE);
|
int pageSize = plugin.getConfig().getInt("gui.reports-per-page", 45);
|
||||||
|
List<Report> reports = plugin.getDatabaseManager().getReportsPaginated(page, pageSize);
|
||||||
int totalReports = plugin.getDatabaseManager().getTotalReportCount();
|
int totalReports = plugin.getDatabaseManager().getTotalReportCount();
|
||||||
|
int totalPages = PaginationUtil.calculateTotalPages(totalReports, pageSize);
|
||||||
// Add report items
|
|
||||||
|
GuiItemConfig entryConfig = plugin.getConfigManager().getGuiItem("report-entry");
|
||||||
|
|
||||||
for (int i = 0; i < reports.size(); i++) {
|
for (int i = 0; i < reports.size(); i++) {
|
||||||
Report report = reports.get(i);
|
Report report = reports.get(i);
|
||||||
int targetReportCount = plugin.getDatabaseManager().getReportCount(report.targetUuid());
|
int targetReportCount = plugin.getDatabaseManager().getReportCount(report.targetUuid());
|
||||||
inventory.setItem(i, createReportItem(report, targetReportCount));
|
|
||||||
|
ItemStack item;
|
||||||
|
if (entryConfig != null) {
|
||||||
|
item = entryConfig.createItem();
|
||||||
|
if (item.getItemMeta() instanceof SkullMeta skullMeta) {
|
||||||
|
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(report.targetUuid());
|
||||||
|
skullMeta.setOwningPlayer(offlinePlayer);
|
||||||
|
item.setItemMeta(skullMeta);
|
||||||
|
}
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
if (meta != null) {
|
||||||
|
meta.setDisplayName(replacePlaceholders(meta.getDisplayName(), report, targetReportCount));
|
||||||
|
if (meta.getLore() != null) {
|
||||||
|
List<String> lore = meta.getLore();
|
||||||
|
List<String> newLore = new ArrayList<>();
|
||||||
|
for (String line : lore) {
|
||||||
|
newLore.add(replacePlaceholders(line, report, targetReportCount));
|
||||||
|
}
|
||||||
|
meta.setLore(newLore);
|
||||||
|
}
|
||||||
|
item.setItemMeta(meta);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
item = createFallbackReportItem(report, targetReportCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Integer> slots = entryConfig != null ? entryConfig.slots() : List.of();
|
||||||
|
if (!slots.isEmpty() && i < slots.size()) {
|
||||||
|
int slot = slots.get(i);
|
||||||
|
inventory.setItem(slot, item);
|
||||||
|
slotActions.put(slot, "report_detail:" + report.id());
|
||||||
|
} else {
|
||||||
|
inventory.setItem(i, item);
|
||||||
|
slotActions.put(i, "report_detail:" + report.id());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add navigation buttons
|
addNavigation(totalReports, totalPages);
|
||||||
addNavigationButtons(totalReports);
|
|
||||||
|
|
||||||
player.openInventory(inventory);
|
player.openInventory(inventory);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ItemStack createReportItem(Report report, int totalReports) {
|
public void openDetail(Player player, Report report) {
|
||||||
|
detailView = true;
|
||||||
|
currentReport = report;
|
||||||
|
slotActions.clear();
|
||||||
|
|
||||||
|
String title = plugin.getConfigManager().getMessage("gui-title-detail", "%id%", String.valueOf(report.id()));
|
||||||
|
this.inventory = Bukkit.createInventory(this, INVENTORY_SIZE, title);
|
||||||
|
|
||||||
|
int targetReportCount = plugin.getDatabaseManager().getReportCount(report.targetUuid());
|
||||||
|
|
||||||
|
GuiItemConfig entryConfig = plugin.getConfigManager().getGuiItem("report-entry");
|
||||||
|
ItemStack item;
|
||||||
|
if (entryConfig != null) {
|
||||||
|
item = entryConfig.createItem();
|
||||||
|
if (item.getItemMeta() instanceof SkullMeta skullMeta) {
|
||||||
|
skullMeta.setOwningPlayer(Bukkit.getOfflinePlayer(report.targetUuid()));
|
||||||
|
item.setItemMeta(skullMeta);
|
||||||
|
}
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
if (meta != null) {
|
||||||
|
meta.setDisplayName(replacePlaceholders(meta.getDisplayName(), report, targetReportCount));
|
||||||
|
if (meta.getLore() != null) {
|
||||||
|
List<String> lore = meta.getLore();
|
||||||
|
List<String> newLore = new ArrayList<>();
|
||||||
|
for (String line : lore) {
|
||||||
|
newLore.add(replacePlaceholders(line, report, targetReportCount));
|
||||||
|
}
|
||||||
|
meta.setLore(newLore);
|
||||||
|
}
|
||||||
|
item.setItemMeta(meta);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
item = createFallbackReportItem(report, targetReportCount);
|
||||||
|
}
|
||||||
|
inventory.setItem(22, item);
|
||||||
|
|
||||||
|
placeDetailButton("teleport", "teleport");
|
||||||
|
if (report.imageUrl() != null && !report.imageUrl().isEmpty()) {
|
||||||
|
placeDetailButton("screenshot", "screenshot");
|
||||||
|
}
|
||||||
|
|
||||||
|
String currentStatus = report.status() != null ? report.status() : "PENDING";
|
||||||
|
placeStatusButton("status-pending", "status_set:PENDING", "PENDING".equals(currentStatus));
|
||||||
|
placeStatusButton("status-reviewing", "status_set:REVIEWING", "REVIEWING".equals(currentStatus));
|
||||||
|
placeStatusButton("status-resolved", "status_set:RESOLVED", "RESOLVED".equals(currentStatus));
|
||||||
|
placeStatusButton("status-dismissed", "status_set:DISMISSED", "DISMISSED".equals(currentStatus));
|
||||||
|
|
||||||
|
GuiItemConfig closeConfig = plugin.getConfigManager().getGuiItem("close");
|
||||||
|
if (closeConfig != null) {
|
||||||
|
List<Integer> slots = closeConfig.slots();
|
||||||
|
ItemStack closeItem = closeConfig.createItem();
|
||||||
|
if (slots.isEmpty()) {
|
||||||
|
inventory.setItem(49, closeItem);
|
||||||
|
slotActions.put(49, "close");
|
||||||
|
} else {
|
||||||
|
for (int slot : slots) {
|
||||||
|
inventory.setItem(slot, closeItem);
|
||||||
|
slotActions.put(slot, "close");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
player.openInventory(inventory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void placeDetailButton(String configPath, String action) {
|
||||||
|
GuiItemConfig config = plugin.getConfigManager().getGuiItem(configPath);
|
||||||
|
if (config == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Integer> slots = config.slots();
|
||||||
|
ItemStack button = config.createItem();
|
||||||
|
if (slots.isEmpty()) {
|
||||||
|
int slot = switch (action) {
|
||||||
|
case "teleport" -> 20;
|
||||||
|
case "screenshot" -> 24;
|
||||||
|
default -> 22;
|
||||||
|
};
|
||||||
|
inventory.setItem(slot, button);
|
||||||
|
slotActions.put(slot, action);
|
||||||
|
} else {
|
||||||
|
for (int slot : slots) {
|
||||||
|
inventory.setItem(slot, button);
|
||||||
|
slotActions.put(slot, action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void placeStatusButton(String configPath, String action, boolean active) {
|
||||||
|
GuiItemConfig config = plugin.getConfigManager().getGuiItem(configPath);
|
||||||
|
if (config == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Integer> slots = config.slots();
|
||||||
|
ItemStack button = config.createItem();
|
||||||
|
if (active) {
|
||||||
|
button.addUnsafeEnchantment(Enchantment.ARROW_DAMAGE, 1);
|
||||||
|
ItemMeta meta = button.getItemMeta();
|
||||||
|
if (meta != null) {
|
||||||
|
meta.addItemFlags(ItemFlag.HIDE_ENCHANTS);
|
||||||
|
button.setItemMeta(meta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (slots.isEmpty()) {
|
||||||
|
int slot = switch (action) {
|
||||||
|
case "status_set:PENDING" -> 29;
|
||||||
|
case "status_set:REVIEWING" -> 30;
|
||||||
|
case "status_set:RESOLVED" -> 31;
|
||||||
|
case "status_set:DISMISSED" -> 32;
|
||||||
|
default -> 29;
|
||||||
|
};
|
||||||
|
inventory.setItem(slot, button);
|
||||||
|
slotActions.put(slot, action);
|
||||||
|
} else {
|
||||||
|
for (int slot : slots) {
|
||||||
|
inventory.setItem(slot, button);
|
||||||
|
slotActions.put(slot, action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addNavigation(int totalReports, int totalPages) {
|
||||||
|
if (page > 0) {
|
||||||
|
GuiItemConfig prevConfig = plugin.getConfigManager().getGuiItem("prev-page");
|
||||||
|
if (prevConfig != null) {
|
||||||
|
List<Integer> slots = prevConfig.slots();
|
||||||
|
ItemStack item = prevConfig.createItem();
|
||||||
|
if (slots.isEmpty()) {
|
||||||
|
inventory.setItem(45, item);
|
||||||
|
slotActions.put(45, "prev_page");
|
||||||
|
} else {
|
||||||
|
for (int slot : slots) {
|
||||||
|
inventory.setItem(slot, item);
|
||||||
|
slotActions.put(slot, "prev_page");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GuiItemConfig pageInfoConfig = plugin.getConfigManager().getGuiItem("page-info");
|
||||||
|
if (pageInfoConfig != null) {
|
||||||
|
List<Integer> slots = pageInfoConfig.slots();
|
||||||
|
ItemStack item = pageInfoConfig.createItem();
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
if (meta != null) {
|
||||||
|
meta.setDisplayName(meta.getDisplayName()
|
||||||
|
.replace("%page%", String.valueOf(page + 1))
|
||||||
|
.replace("%total%", String.valueOf(Math.max(1, totalPages)))
|
||||||
|
.replace("%total_reports%", String.valueOf(totalReports)));
|
||||||
|
if (meta.getLore() != null) {
|
||||||
|
List<String> lore = meta.getLore();
|
||||||
|
List<String> newLore = new ArrayList<>();
|
||||||
|
for (String line : lore) {
|
||||||
|
newLore.add(line
|
||||||
|
.replace("%page%", String.valueOf(page + 1))
|
||||||
|
.replace("%total%", String.valueOf(Math.max(1, totalPages)))
|
||||||
|
.replace("%total_reports%", String.valueOf(totalReports)));
|
||||||
|
}
|
||||||
|
meta.setLore(newLore);
|
||||||
|
}
|
||||||
|
item.setItemMeta(meta);
|
||||||
|
}
|
||||||
|
if (slots.isEmpty()) {
|
||||||
|
inventory.setItem(49, item);
|
||||||
|
} else {
|
||||||
|
for (int slot : slots) {
|
||||||
|
inventory.setItem(slot, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (page < totalPages - 1) {
|
||||||
|
GuiItemConfig nextConfig = plugin.getConfigManager().getGuiItem("next-page");
|
||||||
|
if (nextConfig != null) {
|
||||||
|
List<Integer> slots = nextConfig.slots();
|
||||||
|
ItemStack item = nextConfig.createItem();
|
||||||
|
if (slots.isEmpty()) {
|
||||||
|
inventory.setItem(53, item);
|
||||||
|
slotActions.put(53, "next_page");
|
||||||
|
} else {
|
||||||
|
for (int slot : slots) {
|
||||||
|
inventory.setItem(slot, item);
|
||||||
|
slotActions.put(slot, "next_page");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GuiItemConfig closeConfig = plugin.getConfigManager().getGuiItem("close");
|
||||||
|
if (closeConfig != null) {
|
||||||
|
List<Integer> slots = closeConfig.slots();
|
||||||
|
ItemStack item = closeConfig.createItem();
|
||||||
|
if (slots.isEmpty()) {
|
||||||
|
inventory.setItem(47, item);
|
||||||
|
slotActions.put(47, "close");
|
||||||
|
} else {
|
||||||
|
for (int slot : slots) {
|
||||||
|
inventory.setItem(slot, item);
|
||||||
|
slotActions.put(slot, "close");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String replacePlaceholders(String text, Report report, int reportCount) {
|
||||||
|
String statusDisplay = plugin.getConfigManager().getMessage("status-" + report.status().toLowerCase());
|
||||||
|
return text
|
||||||
|
.replace("%target_name%", report.targetName() != null ? report.targetName() : "")
|
||||||
|
.replace("%reporter_name%", report.reporterName() != null ? report.reporterName() : "")
|
||||||
|
.replace("%reason%", report.reason() != null ? report.reason() : "")
|
||||||
|
.replace("%time%", TimeUtil.formatTimeAgo(report.createdAt()))
|
||||||
|
.replace("%status%", statusDisplay)
|
||||||
|
.replace("%report_count%", String.valueOf(reportCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
private ItemStack createFallbackReportItem(Report report, int totalReports) {
|
||||||
ItemStack head = new ItemStack(Material.PLAYER_HEAD);
|
ItemStack head = new ItemStack(Material.PLAYER_HEAD);
|
||||||
SkullMeta meta = (SkullMeta) head.getItemMeta();
|
SkullMeta meta = (SkullMeta) head.getItemMeta();
|
||||||
|
|
||||||
if (meta != null) {
|
if (meta != null) {
|
||||||
// Set skull owner for skin
|
|
||||||
meta.setOwningPlayer(Bukkit.getOfflinePlayer(report.targetUuid()));
|
meta.setOwningPlayer(Bukkit.getOfflinePlayer(report.targetUuid()));
|
||||||
|
|
||||||
// Display name
|
|
||||||
meta.setDisplayName("§c" + report.targetName());
|
meta.setDisplayName("§c" + report.targetName());
|
||||||
|
|
||||||
// Lore with report info
|
|
||||||
List<String> lore = new ArrayList<>();
|
List<String> lore = new ArrayList<>();
|
||||||
lore.add("§7");
|
lore.add("§7");
|
||||||
lore.add("§eОтправитель: §f" + report.reporterName());
|
lore.add("§eBy: §f" + report.reporterName());
|
||||||
lore.add("§ePричина: §f" + report.reason());
|
lore.add("§eReason: §f" + report.reason());
|
||||||
lore.add("§eВремя: §f" + TimeUtil.formatTimeAgo(report.createdAt().toEpochMilli()));
|
lore.add("§eTime: §f" + TimeUtil.formatTimeAgo(report.createdAt()));
|
||||||
lore.add("§7");
|
lore.add("§7");
|
||||||
lore.add("§eВсего репортов: §c" + totalReports);
|
lore.add("§eReports: §c" + totalReports);
|
||||||
|
|
||||||
meta.setLore(lore);
|
meta.setLore(lore);
|
||||||
head.setItemMeta(meta);
|
head.setItemMeta(meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
return head;
|
return head;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addNavigationButtons(int totalReports) {
|
|
||||||
int totalPages = (int) Math.ceil((double) totalReports / PAGE_SIZE);
|
|
||||||
|
|
||||||
// Previous page button
|
|
||||||
if (page > 0) {
|
|
||||||
ItemStack prevButton = new ItemStack(Material.ARROW);
|
|
||||||
ItemMeta prevMeta = prevButton.getItemMeta();
|
|
||||||
if (prevMeta != null) {
|
|
||||||
prevMeta.setDisplayName("§a← Предыдущая страница");
|
|
||||||
prevButton.setItemMeta(prevMeta);
|
|
||||||
}
|
|
||||||
inventory.setItem(SLOT_PREV_PAGE, prevButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Page info
|
|
||||||
ItemStack pageInfo = new ItemStack(Material.PAPER);
|
|
||||||
ItemMeta pageMeta = pageInfo.getItemMeta();
|
|
||||||
if (pageMeta != null) {
|
|
||||||
pageMeta.setDisplayName("§eСтраница " + (page + 1) + " из " + Math.max(1, totalPages));
|
|
||||||
List<String> lore = new ArrayList<>();
|
|
||||||
lore.add("§7Всего репортов: " + totalReports);
|
|
||||||
pageMeta.setLore(lore);
|
|
||||||
pageInfo.setItemMeta(pageMeta);
|
|
||||||
}
|
|
||||||
inventory.setItem(SLOT_PAGE_INFO, pageInfo);
|
|
||||||
|
|
||||||
// Next page button
|
|
||||||
if (page < totalPages - 1) {
|
|
||||||
ItemStack nextButton = new ItemStack(Material.ARROW);
|
|
||||||
ItemMeta nextMeta = nextButton.getItemMeta();
|
|
||||||
if (nextMeta != null) {
|
|
||||||
nextMeta.setDisplayName("§aСледующая страница →");
|
|
||||||
nextButton.setItemMeta(nextMeta);
|
|
||||||
}
|
|
||||||
inventory.setItem(SLOT_NEXT_PAGE, nextButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close button
|
|
||||||
ItemStack closeButton = new ItemStack(Material.BARRIER);
|
|
||||||
ItemMeta closeMeta = closeButton.getItemMeta();
|
|
||||||
if (closeMeta != null) {
|
|
||||||
closeMeta.setDisplayName("§cЗакрыть");
|
|
||||||
closeButton.setItemMeta(closeMeta);
|
|
||||||
}
|
|
||||||
inventory.setItem(SLOT_CLOSE, closeButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPage() {
|
public int getPage() {
|
||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isDetailView() {
|
||||||
|
return detailView;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Report getCurrentReport() {
|
||||||
|
return currentReport;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Inventory getInventory() {
|
public Inventory getInventory() {
|
||||||
return inventory;
|
return inventory;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
package dev.loki.lorep.webhook;
|
package dev.loki.lorep.webhook;
|
||||||
|
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
import dev.loki.lorep.database.Report;
|
import dev.loki.lorep.database.Report;
|
||||||
import okhttp3.Call;
|
import okhttp3.Call;
|
||||||
import okhttp3.Callback;
|
import okhttp3.Callback;
|
||||||
|
|
@ -16,42 +19,42 @@ import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public class DiscordWebhook {
|
public class DiscordWebhook {
|
||||||
|
|
||||||
private static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
|
private static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
|
||||||
private static final DateTimeFormatter FORMATTER = DateTimeFormatter
|
private static final DateTimeFormatter FORMATTER = DateTimeFormatter
|
||||||
.ofPattern("dd.MM.yyyy HH:mm:ss")
|
.ofPattern("dd.MM.yyyy HH:mm:ss")
|
||||||
.withZone(ZoneId.systemDefault());
|
.withZone(ZoneId.systemDefault());
|
||||||
|
|
||||||
private final String webhookUrl;
|
private final String webhookUrl;
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
private final OkHttpClient client;
|
private final OkHttpClient client;
|
||||||
|
|
||||||
public DiscordWebhook(String webhookUrl, Logger logger) {
|
public DiscordWebhook(String webhookUrl, Logger logger) {
|
||||||
this.webhookUrl = webhookUrl;
|
this.webhookUrl = webhookUrl;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.client = new OkHttpClient();
|
this.client = new OkHttpClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendReport(Report report) {
|
public void sendReport(Report report) {
|
||||||
if (webhookUrl == null || webhookUrl.isEmpty()) {
|
if (webhookUrl == null || webhookUrl.isEmpty()) {
|
||||||
logger.warning("Discord webhook URL is not configured");
|
logger.warning("Discord webhook URL is not configured");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String json = buildPayload(report);
|
String json = buildPayload(report);
|
||||||
|
|
||||||
RequestBody body = RequestBody.create(json, JSON);
|
RequestBody body = RequestBody.create(json, JSON);
|
||||||
Request request = new Request.Builder()
|
Request request = new Request.Builder()
|
||||||
.url(webhookUrl)
|
.url(webhookUrl)
|
||||||
.post(body)
|
.post(body)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
client.newCall(request).enqueue(new Callback() {
|
client.newCall(request).enqueue(new Callback() {
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Call call, IOException e) {
|
public void onFailure(Call call, IOException e) {
|
||||||
logger.log(Level.WARNING, "Failed to send Discord webhook", e);
|
logger.log(Level.WARNING, "Failed to send Discord webhook", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call call, Response response) {
|
public void onResponse(Call call, Response response) {
|
||||||
if (!response.isSuccessful()) {
|
if (!response.isSuccessful()) {
|
||||||
|
|
@ -61,31 +64,164 @@ public class DiscordWebhook {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public String buildPayload(Report report) {
|
public void sendStatusUpdate(Report report) {
|
||||||
String timestamp = FORMATTER.format(report.createdAt());
|
if (webhookUrl == null || webhookUrl.isEmpty()) {
|
||||||
|
logger.warning("Discord webhook URL is not configured");
|
||||||
return String.format("""
|
return;
|
||||||
{
|
}
|
||||||
"embeds": [{
|
|
||||||
"title": "📢 Новый репорт",
|
String json = buildStatusPayload(report);
|
||||||
"color": 16711680,
|
|
||||||
"fields": [
|
RequestBody body = RequestBody.create(json, JSON);
|
||||||
{"name": "👤 Нарушитель", "value": "%s", "inline": true},
|
Request request = new Request.Builder()
|
||||||
{"name": "📝 Отправитель", "value": "%s", "inline": true},
|
.url(webhookUrl)
|
||||||
{"name": "📋 Причина", "value": "%s", "inline": false},
|
.post(body)
|
||||||
{"name": "🕐 Время", "value": "%s", "inline": false}
|
.build();
|
||||||
]
|
|
||||||
}]
|
client.newCall(request).enqueue(new Callback() {
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call call, IOException e) {
|
||||||
|
logger.log(Level.WARNING, "Failed to send status update webhook", e);
|
||||||
}
|
}
|
||||||
""",
|
|
||||||
escapeJson(report.targetName()),
|
@Override
|
||||||
escapeJson(report.reporterName()),
|
public void onResponse(Call call, Response response) {
|
||||||
escapeJson(report.reason()),
|
if (!response.isSuccessful()) {
|
||||||
timestamp
|
logger.warning("Status update webhook returned: " + response.code());
|
||||||
);
|
}
|
||||||
|
response.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String buildPayload(Report report) {
|
||||||
|
JsonObject embed = new JsonObject();
|
||||||
|
embed.addProperty("title", "\uD83D\uDCE2 Новый репорт #" + report.id());
|
||||||
|
embed.addProperty("color", getColorForStatus(report.status()));
|
||||||
|
|
||||||
|
JsonObject thumbnail = new JsonObject();
|
||||||
|
thumbnail.addProperty("url", "https://mc-heads.net/avatar/" + report.targetUuid());
|
||||||
|
embed.add("thumbnail", thumbnail);
|
||||||
|
|
||||||
|
JsonObject author = new JsonObject();
|
||||||
|
author.addProperty("name", report.reporterName());
|
||||||
|
author.addProperty("icon_url", "https://mc-heads.net/avatar/" + report.reporterUuid());
|
||||||
|
embed.add("author", author);
|
||||||
|
|
||||||
|
JsonArray fields = new JsonArray();
|
||||||
|
|
||||||
|
JsonObject targetField = new JsonObject();
|
||||||
|
targetField.addProperty("name", "\uD83D\uDC64 Нарушитель");
|
||||||
|
targetField.addProperty("value", report.targetName());
|
||||||
|
targetField.addProperty("inline", true);
|
||||||
|
fields.add(targetField);
|
||||||
|
|
||||||
|
JsonObject reporterField = new JsonObject();
|
||||||
|
reporterField.addProperty("name", "\uD83D\uDCDD Отправитель");
|
||||||
|
reporterField.addProperty("value", report.reporterName());
|
||||||
|
reporterField.addProperty("inline", true);
|
||||||
|
fields.add(reporterField);
|
||||||
|
|
||||||
|
JsonObject reasonField = new JsonObject();
|
||||||
|
reasonField.addProperty("name", "\uD83D\uDCCB Причина");
|
||||||
|
reasonField.addProperty("value", report.reason());
|
||||||
|
reasonField.addProperty("inline", false);
|
||||||
|
fields.add(reasonField);
|
||||||
|
|
||||||
|
JsonObject statusField = new JsonObject();
|
||||||
|
statusField.addProperty("name", "\uD83C\uDFF7 Статус");
|
||||||
|
statusField.addProperty("value", getStatusDisplay(report.status()));
|
||||||
|
statusField.addProperty("inline", true);
|
||||||
|
fields.add(statusField);
|
||||||
|
|
||||||
|
JsonObject timeField = new JsonObject();
|
||||||
|
timeField.addProperty("name", "\uD83D\uDD50 Время");
|
||||||
|
timeField.addProperty("value", FORMATTER.format(report.createdAt()));
|
||||||
|
timeField.addProperty("inline", true);
|
||||||
|
fields.add(timeField);
|
||||||
|
|
||||||
|
embed.add("fields", fields);
|
||||||
|
|
||||||
|
if (report.imageUrl() != null && !report.imageUrl().isEmpty()) {
|
||||||
|
JsonObject image = new JsonObject();
|
||||||
|
image.addProperty("url", report.imageUrl());
|
||||||
|
embed.add("image", image);
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject footer = new JsonObject();
|
||||||
|
footer.addProperty("text", "LoReport \u2022 " + FORMATTER.format(report.createdAt()));
|
||||||
|
embed.add("footer", footer);
|
||||||
|
|
||||||
|
embed.addProperty("timestamp", report.createdAt().toString());
|
||||||
|
|
||||||
|
JsonObject root = new JsonObject();
|
||||||
|
JsonArray embeds = new JsonArray();
|
||||||
|
embeds.add(embed);
|
||||||
|
root.add("embeds", embeds);
|
||||||
|
|
||||||
|
return new GsonBuilder().create().toJson(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildStatusPayload(Report report) {
|
||||||
|
JsonObject embed = new JsonObject();
|
||||||
|
embed.addProperty("title", "\uD83D\uDD04 Статус репорта #" + report.id() + " изменён");
|
||||||
|
embed.addProperty("color", getColorForStatus(report.status()));
|
||||||
|
|
||||||
|
JsonObject thumbnail = new JsonObject();
|
||||||
|
thumbnail.addProperty("url", "https://mc-heads.net/avatar/" + report.targetUuid());
|
||||||
|
embed.add("thumbnail", thumbnail);
|
||||||
|
|
||||||
|
JsonArray fields = new JsonArray();
|
||||||
|
|
||||||
|
JsonObject targetField = new JsonObject();
|
||||||
|
targetField.addProperty("name", "\uD83D\uDC64 Нарушитель");
|
||||||
|
targetField.addProperty("value", report.targetName());
|
||||||
|
targetField.addProperty("inline", true);
|
||||||
|
fields.add(targetField);
|
||||||
|
|
||||||
|
JsonObject statusField = new JsonObject();
|
||||||
|
statusField.addProperty("name", "\uD83C\uDFF7 Новый статус");
|
||||||
|
statusField.addProperty("value", getStatusDisplay(report.status()));
|
||||||
|
statusField.addProperty("inline", false);
|
||||||
|
fields.add(statusField);
|
||||||
|
|
||||||
|
embed.add("fields", fields);
|
||||||
|
|
||||||
|
JsonObject footer = new JsonObject();
|
||||||
|
footer.addProperty("text", "LoReport \u2022 " + FORMATTER.format(report.createdAt()));
|
||||||
|
embed.add("footer", footer);
|
||||||
|
|
||||||
|
embed.addProperty("timestamp", report.createdAt().toString());
|
||||||
|
|
||||||
|
JsonObject root = new JsonObject();
|
||||||
|
JsonArray embeds = new JsonArray();
|
||||||
|
embeds.add(embed);
|
||||||
|
root.add("embeds", embeds);
|
||||||
|
|
||||||
|
return new GsonBuilder().create().toJson(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getColorForStatus(String status) {
|
||||||
|
return switch (status != null ? status.toUpperCase() : "PENDING") {
|
||||||
|
case "PENDING" -> 0xFF0000;
|
||||||
|
case "REVIEWING" -> 0xFFAA00;
|
||||||
|
case "RESOLVED" -> 0x00FF00;
|
||||||
|
case "DISMISSED" -> 0x808080;
|
||||||
|
default -> 0xFF0000;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getStatusDisplay(String status) {
|
||||||
|
return switch (status != null ? status.toUpperCase() : "PENDING") {
|
||||||
|
case "PENDING" -> "\u23F3 Ожидает";
|
||||||
|
case "REVIEWING" -> "\uD83D\uDD0D На рассмотрении";
|
||||||
|
case "RESOLVED" -> "\u2705 Решён";
|
||||||
|
case "DISMISSED" -> "\u274C Отклонён";
|
||||||
|
default -> "\u2753 Неизвестно";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private String escapeJson(String text) {
|
private String escapeJson(String text) {
|
||||||
if (text == null) {
|
if (text == null) {
|
||||||
return "";
|
return "";
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
# Discord Webhook URL для уведомлений
|
# Discord webhook URL for report notifications
|
||||||
webhook-url: ""
|
webhook-url: ""
|
||||||
|
|
||||||
# Настройки базы данных
|
# Database configuration
|
||||||
database:
|
database:
|
||||||
# Тип БД: sqlite или postgresql
|
# Database type: "sqlite" or "postgresql"
|
||||||
type: "sqlite"
|
type: "sqlite"
|
||||||
|
|
||||||
# Настройки SQLite
|
# SQLite settings
|
||||||
sqlite:
|
sqlite:
|
||||||
file: "reports.db"
|
file: "reports.db"
|
||||||
|
|
||||||
# Настройки PostgreSQL
|
# PostgreSQL settings
|
||||||
postgresql:
|
postgresql:
|
||||||
host: "localhost"
|
host: "localhost"
|
||||||
port: 5432
|
port: 5432
|
||||||
|
|
@ -19,48 +19,145 @@ database:
|
||||||
password: "password"
|
password: "password"
|
||||||
pool-size: 10
|
pool-size: 10
|
||||||
|
|
||||||
# Настройки GUI
|
# GUI settings
|
||||||
gui:
|
gui:
|
||||||
# Количество репортов на странице
|
# Reports per page in GUI
|
||||||
reports-per-page: 45
|
reports-per-page: 45
|
||||||
# Автообновление GUI (в тиках, 20 тиков = 1 секунда)
|
# Auto-refresh interval in ticks (20 ticks = 1 second)
|
||||||
auto-refresh: 100
|
auto-refresh: 100
|
||||||
# Показывать головы игроков в GUI
|
# Show player heads in GUI
|
||||||
show-player-heads: true
|
show-player-heads: true
|
||||||
|
# GUI item definitions — customize materials, textures, and positions
|
||||||
|
# Set custom-model-data to your resource pack model ID (-1 to disable)
|
||||||
|
# Use slots to make an item span multiple slots (empty = default position)
|
||||||
|
items:
|
||||||
|
prev-page:
|
||||||
|
material: ARROW
|
||||||
|
custom-model-data: -1
|
||||||
|
name: "&a← Previous page"
|
||||||
|
lore: []
|
||||||
|
slots: [45]
|
||||||
|
glowing: false
|
||||||
|
next-page:
|
||||||
|
material: ARROW
|
||||||
|
custom-model-data: -1
|
||||||
|
name: "&aNext page →"
|
||||||
|
lore: []
|
||||||
|
slots: [53]
|
||||||
|
glowing: false
|
||||||
|
page-info:
|
||||||
|
material: PAPER
|
||||||
|
custom-model-data: -1
|
||||||
|
name: "&ePage %page% of %total%"
|
||||||
|
lore:
|
||||||
|
- "&7Total reports: %total_reports%"
|
||||||
|
slots: [49]
|
||||||
|
glowing: false
|
||||||
|
close:
|
||||||
|
material: BARRIER
|
||||||
|
custom-model-data: -1
|
||||||
|
name: "&cClose"
|
||||||
|
lore: []
|
||||||
|
slots: [47]
|
||||||
|
glowing: false
|
||||||
|
report-entry:
|
||||||
|
material: PLAYER_HEAD
|
||||||
|
custom-model-data: -1
|
||||||
|
name: "&c%target_name%"
|
||||||
|
lore:
|
||||||
|
- "&7"
|
||||||
|
- "&eBy: &f%reporter_name%"
|
||||||
|
- "&eReason: &f%reason%"
|
||||||
|
- "&eTime: &f%time%"
|
||||||
|
- "&eStatus: &f%status%"
|
||||||
|
- "&7"
|
||||||
|
- "&eReports: &c%report_count%"
|
||||||
|
slots: []
|
||||||
|
glowing: false
|
||||||
|
status-pending:
|
||||||
|
material: RED_STAINED_GLASS_PANE
|
||||||
|
custom-model-data: -1
|
||||||
|
name: "&cPending"
|
||||||
|
lore: []
|
||||||
|
slots: []
|
||||||
|
glowing: false
|
||||||
|
status-reviewing:
|
||||||
|
material: YELLOW_STAINED_GLASS_PANE
|
||||||
|
custom-model-data: -1
|
||||||
|
name: "&eReviewing"
|
||||||
|
lore: []
|
||||||
|
slots: []
|
||||||
|
glowing: true
|
||||||
|
status-resolved:
|
||||||
|
material: GREEN_STAINED_GLASS_PANE
|
||||||
|
custom-model-data: -1
|
||||||
|
name: "&aResolved"
|
||||||
|
lore: []
|
||||||
|
slots: []
|
||||||
|
glowing: false
|
||||||
|
status-dismissed:
|
||||||
|
material: GRAY_STAINED_GLASS_PANE
|
||||||
|
custom-model-data: -1
|
||||||
|
name: "&7Dismissed"
|
||||||
|
lore: []
|
||||||
|
slots: []
|
||||||
|
glowing: false
|
||||||
|
teleport:
|
||||||
|
material: ENDER_PEARL
|
||||||
|
custom-model-data: -1
|
||||||
|
name: "&bTeleport to player"
|
||||||
|
lore: []
|
||||||
|
slots: []
|
||||||
|
glowing: false
|
||||||
|
screenshot:
|
||||||
|
material: MAP
|
||||||
|
custom-model-data: -1
|
||||||
|
name: "&aScreenshot"
|
||||||
|
lore: []
|
||||||
|
slots: []
|
||||||
|
glowing: false
|
||||||
|
|
||||||
# Ограничения
|
# Limits
|
||||||
limits:
|
limits:
|
||||||
# Максимальная длина причины репорта
|
# Maximum reason length in characters
|
||||||
max-reason-length: 100
|
max-reason-length: 100
|
||||||
# Кулдаун между репортами (в секундах)
|
# Cooldown between reports (seconds)
|
||||||
report-cooldown: 30
|
report-cooldown: 30
|
||||||
# Максимум репортов на одного игрока от одного отправителя
|
# Max reports per player from the same reporter
|
||||||
max-reports-per-player: 3
|
max-reports-per-player: 3
|
||||||
|
|
||||||
# Уведомления
|
# Notifications
|
||||||
notifications:
|
notifications:
|
||||||
# Уведомлять администраторов о новых репортах
|
# Notify admins about new reports
|
||||||
notify-admins: true
|
notify-admins: true
|
||||||
# Звук уведомления для администраторов
|
# Admin notification sound
|
||||||
admin-notification-sound: "BLOCK_NOTE_BLOCK_PLING"
|
admin-notification-sound: "BLOCK_NOTE_BLOCK_PLING"
|
||||||
# Уведомлять игрока о принятии репорта
|
# Notify reporter when report is handled
|
||||||
notify-reporter: true
|
notify-reporter: true
|
||||||
|
|
||||||
# Сообщения
|
# Messages (override defaults from messages.yml)
|
||||||
messages:
|
messages:
|
||||||
report-sent: "&aРепорт успешно отправлен!"
|
report-sent: "&aReport sent successfully!"
|
||||||
already-reported: "&cВы уже отправляли репорт на этого игрока!"
|
already-reported: "&cYou have already reported this player!"
|
||||||
self-report: "&cВы не можете отправить репорт на себя!"
|
self-report: "&cYou cannot report yourself!"
|
||||||
player-not-found: "&cИгрок не найден!"
|
player-not-found: "&cPlayer not found!"
|
||||||
no-permission: "&cУ вас нет прав на эту команду!"
|
no-permission: "&cYou don't have permission!"
|
||||||
usage: "&eИспользование: /report <ник> <причина>"
|
usage: "&eUsage: /report <player> <reason> [screenshot_url] | /report gui | /report stats <player> | /report image <id> <url>"
|
||||||
no-reports: "&eУ этого игрока нет репортов."
|
no-reports: "&eThis player has no reports."
|
||||||
stats-header: "&6=== Статистика репортов: %player% ==="
|
stats-header: "&6=== Report stats: %player% ==="
|
||||||
stats-count: "&eВсего репортов: &f%count%"
|
stats-count: "&eTotal reports: &f%count%"
|
||||||
stats-last-online: "&eПоследний онлайн: &f%time%"
|
stats-last-online: "&eLast online: &f%time%"
|
||||||
stats-report-entry: "&7- %reason% &8(%time% назад)"
|
stats-report-entry: "&7- %reason% &8(%time% ago)"
|
||||||
gui-title: "Репорты - Страница %page%"
|
gui-title: "Reports - Page %page%"
|
||||||
cooldown: "&cПодождите %time% секунд перед следующим репортом!"
|
cooldown: "&cPlease wait %time% seconds before your next report!"
|
||||||
reason-too-long: "&cПричина слишком длинная! Максимум %max% символов."
|
reason-too-long: "&cReason too long! Max %max% characters."
|
||||||
max-reports-reached: "&cВы уже отправили максимальное количество репортов на этого игрока!"
|
max-reports-reached: "&cYou've reached the max reports for this player!"
|
||||||
admin-notification: "&6[Loreport] &eНовый репорт от &f%reporter% &eна &f%reported%: &7%reason%"
|
admin-notification: "&6[LoReport] &eNew report from &f%reporter% &eon &f%reported%: &7%reason%"
|
||||||
|
report-status-changed: "&aReport #%id% status changed to: %status%"
|
||||||
|
report-image-added: "&aScreenshot added to report #%id%"
|
||||||
|
report-image-usage: "&eUsage: /report <player> <reason> [screenshot_url]"
|
||||||
|
report-image-url-usage: "&eUsage: /report image <id> <url>"
|
||||||
|
status-pending: "&cPending"
|
||||||
|
status-reviewing: "&eReviewing"
|
||||||
|
status-resolved: "&aResolved"
|
||||||
|
status-dismissed: "&7Dismissed"
|
||||||
|
|
|
||||||
50
src/main/resources/messages.yml
Normal file
50
src/main/resources/messages.yml
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
# LoReport messages
|
||||||
|
# You can edit these to change plugin messages without recompiling
|
||||||
|
# Color codes: &0-9, &a-f, &k-o, &r
|
||||||
|
|
||||||
|
# General
|
||||||
|
console-only: "&cThis command is for players only!"
|
||||||
|
no-permission: "&cYou don't have permission to use this command!"
|
||||||
|
usage: "&eUsage: /report <player> <reason> [screenshot_url] | /report gui | /report stats <player> | /report image <id> <url>"
|
||||||
|
|
||||||
|
# Reporting
|
||||||
|
report-sent: "&aReport sent successfully!"
|
||||||
|
already-reported: "&cYou have already reported this player!"
|
||||||
|
self-report: "&cYou cannot report yourself!"
|
||||||
|
player-not-found: "&cPlayer not found!"
|
||||||
|
reason-too-long: "&cReason is too long! Maximum %max% characters."
|
||||||
|
max-reports-reached: "&cYou have reached the maximum number of reports for this player!"
|
||||||
|
cooldown: "&cPlease wait %time% seconds before your next report!"
|
||||||
|
invalid-report-id: "&cInvalid report ID."
|
||||||
|
report-not-found: "&cReport with this ID not found."
|
||||||
|
report-image-updated: "&aImage for report #%id% updated."
|
||||||
|
|
||||||
|
# Admin notifications
|
||||||
|
admin-notification: "&6[LoReport] &eNew report from &f%reporter% &eon &f%reported%: &7%reason%"
|
||||||
|
|
||||||
|
# Report status
|
||||||
|
report-status-changed: "&aReport #%id% status changed to: %status%"
|
||||||
|
report-image-added: "&aScreenshot added to report #%id%"
|
||||||
|
report-image-usage: "&eUsage: /report <player> <reason> [screenshot_url]"
|
||||||
|
report-image-url-usage: "&eUsage: /report image <id> <url>"
|
||||||
|
status-pending: "&cPending"
|
||||||
|
status-reviewing: "&eReviewing"
|
||||||
|
status-resolved: "&aResolved"
|
||||||
|
status-dismissed: "&7Dismissed"
|
||||||
|
|
||||||
|
# GUI
|
||||||
|
gui-title: "Reports - Page %page%"
|
||||||
|
gui-title-detail: "&8Report #%id%"
|
||||||
|
teleported-to: "&aTeleported to %player%"
|
||||||
|
player-offline: "&cPlayer %player% is offline"
|
||||||
|
screenshot-link: "&aScreenshot: &e%url%"
|
||||||
|
|
||||||
|
# Stats
|
||||||
|
online-status: "&aOnline now"
|
||||||
|
no-reports: "&eThis player has no reports."
|
||||||
|
stats-header: "&6=== Report stats: %player% ==="
|
||||||
|
stats-count: "&eTotal reports: &f%count%"
|
||||||
|
stats-last-online: "&eLast online: &f%time%"
|
||||||
|
stats-report-entry: "&7- %reason% &8(%time% ago)"
|
||||||
|
stats-recent-header: "&7Recent reports:"
|
||||||
|
stats-more-reports: "&7... and %count% more reports"
|
||||||
|
|
@ -9,7 +9,7 @@ website: https://codeberg.org/loki5512344/Loreport
|
||||||
commands:
|
commands:
|
||||||
report:
|
report:
|
||||||
description: Report a player or manage reports
|
description: Report a player or manage reports
|
||||||
usage: /report <player> <reason> | /report gui | /report stats <player>
|
usage: /report <player> <reason> [image_url] | /report gui | /report stats <player> | /report image <id> <url>
|
||||||
permission: lorep.report
|
permission: lorep.report
|
||||||
aliases: [rep, reports]
|
aliases: [rep, reports]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ public class DatabaseManagerTest {
|
||||||
Assume.that(!reporterUuid.equals(targetUuid));
|
Assume.that(!reporterUuid.equals(targetUuid));
|
||||||
|
|
||||||
Report report = new Report(
|
Report report = new Report(
|
||||||
0, reporterUuid, "Reporter", targetUuid, "Target", reason, Instant.now()
|
reporterUuid, "Reporter", targetUuid, "Target", reason
|
||||||
);
|
);
|
||||||
|
|
||||||
dbManager.saveReport(report);
|
dbManager.saveReport(report);
|
||||||
|
|
@ -95,7 +95,7 @@ public class DatabaseManagerTest {
|
||||||
"Should not have reported before creating report");
|
"Should not have reported before creating report");
|
||||||
|
|
||||||
Report report = new Report(
|
Report report = new Report(
|
||||||
0, reporterUuid, "Reporter", targetUuid, "Target", "Test reason", Instant.now()
|
reporterUuid, "Reporter", targetUuid, "Target", "Test reason"
|
||||||
);
|
);
|
||||||
dbManager.saveReport(report);
|
dbManager.saveReport(report);
|
||||||
|
|
||||||
|
|
@ -121,7 +121,7 @@ public class DatabaseManagerTest {
|
||||||
String targetName = "Target_" + targetUuid.toString().substring(0, 8);
|
String targetName = "Target_" + targetUuid.toString().substring(0, 8);
|
||||||
Instant createdAt = Instant.now();
|
Instant createdAt = Instant.now();
|
||||||
|
|
||||||
Report original = new Report(0, reporterUuid, reporterName, targetUuid, targetName, reason, createdAt);
|
Report original = new Report(0, reporterUuid, reporterName, targetUuid, targetName, reason, null, "PENDING", createdAt);
|
||||||
dbManager.saveReport(original);
|
dbManager.saveReport(original);
|
||||||
|
|
||||||
// Close and reopen database
|
// Close and reopen database
|
||||||
|
|
@ -151,9 +151,10 @@ public class DatabaseManagerTest {
|
||||||
UUID targetUuid = UUID.randomUUID();
|
UUID targetUuid = UUID.randomUUID();
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
|
Instant reportTime = Instant.now().minusSeconds(count - i);
|
||||||
Report report = new Report(
|
Report report = new Report(
|
||||||
0, UUID.randomUUID(), "Reporter" + i, targetUuid, "Target",
|
0, UUID.randomUUID(), "Reporter" + i, targetUuid, "Target",
|
||||||
"Reason " + i, Instant.now().minusSeconds(count - i)
|
"Reason " + i, null, "PENDING", reportTime
|
||||||
);
|
);
|
||||||
dbManager.saveReport(report);
|
dbManager.saveReport(report);
|
||||||
}
|
}
|
||||||
|
|
@ -180,8 +181,8 @@ public class DatabaseManagerTest {
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
Report report = new Report(
|
Report report = new Report(
|
||||||
0, UUID.randomUUID(), "Reporter" + i, targetUuid, "Target",
|
UUID.randomUUID(), "Reporter" + i, targetUuid, "Target",
|
||||||
"Reason " + i, Instant.now()
|
"Reason " + i
|
||||||
);
|
);
|
||||||
dbManager.saveReport(report);
|
dbManager.saveReport(report);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,13 +33,11 @@ public class DiscordWebhookTest {
|
||||||
DiscordWebhook webhook = new DiscordWebhook("https://example.com/webhook", logger);
|
DiscordWebhook webhook = new DiscordWebhook("https://example.com/webhook", logger);
|
||||||
|
|
||||||
Report report = new Report(
|
Report report = new Report(
|
||||||
1,
|
|
||||||
UUID.randomUUID(),
|
UUID.randomUUID(),
|
||||||
reporterName,
|
reporterName,
|
||||||
UUID.randomUUID(),
|
UUID.randomUUID(),
|
||||||
targetName,
|
targetName,
|
||||||
reason,
|
reason
|
||||||
Instant.now()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
String payload = webhook.buildPayload(report);
|
String payload = webhook.buildPayload(report);
|
||||||
|
|
@ -95,9 +93,9 @@ public class DiscordWebhookTest {
|
||||||
DiscordWebhook webhook = new DiscordWebhook("https://example.com/webhook", logger);
|
DiscordWebhook webhook = new DiscordWebhook("https://example.com/webhook", logger);
|
||||||
|
|
||||||
Report report = new Report(
|
Report report = new Report(
|
||||||
1, UUID.randomUUID(), "TestReporter",
|
UUID.randomUUID(), "TestReporter",
|
||||||
UUID.randomUUID(), "TestTarget",
|
UUID.randomUUID(), "TestTarget",
|
||||||
"Test reason", Instant.now()
|
"Test reason"
|
||||||
);
|
);
|
||||||
|
|
||||||
String payload = webhook.buildPayload(report);
|
String payload = webhook.buildPayload(report);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue