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+
|
||||
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.zaxxer:HikariCP:6.2.1")
|
||||
implementation("org.postgresql:postgresql:42.7.4")
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ public class ReportCommand implements CommandExecutor, TabCompleter {
|
|||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!(sender instanceof Player player)) {
|
||||
sender.sendMessage("§cЭта команда только для игроков!");
|
||||
sender.sendMessage(plugin.getConfigManager().getMessage("console-only"));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -35,7 +35,6 @@ public class ReportCommand implements CommandExecutor, TabCompleter {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Handle subcommands for admins
|
||||
if (args[0].equalsIgnoreCase("gui")) {
|
||||
return handleGui(player);
|
||||
}
|
||||
|
|
@ -44,7 +43,10 @@ public class ReportCommand implements CommandExecutor, TabCompleter {
|
|||
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")) {
|
||||
player.sendMessage(plugin.getConfigManager().getMessage("no-permission"));
|
||||
return true;
|
||||
|
|
@ -56,24 +58,34 @@ public class ReportCommand implements CommandExecutor, TabCompleter {
|
|||
}
|
||||
|
||||
String targetName = args[0];
|
||||
String reason = String.join(" ", Arrays.copyOfRange(args, 1, args.length));
|
||||
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));
|
||||
}
|
||||
|
||||
// Validate reason
|
||||
if (reason.trim().isEmpty()) {
|
||||
player.sendMessage(plugin.getConfigManager().getMessage("usage"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (reason.length() > 500) {
|
||||
player.sendMessage("§cПричина слишком длинная! Максимум 500 символов.");
|
||||
player.sendMessage(plugin.getConfigManager().getMessage("reason-too-long", "%max%", "500"));
|
||||
return true;
|
||||
}
|
||||
|
||||
return handleReport(player, targetName, reason);
|
||||
return handleReport(player, targetName, reason, imageUrl);
|
||||
}
|
||||
|
||||
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")
|
||||
OfflinePlayer target = Bukkit.getOfflinePlayer(targetName);
|
||||
|
||||
|
|
@ -82,30 +94,27 @@ public class ReportCommand implements CommandExecutor, TabCompleter {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Check self-report
|
||||
if (target.getUniqueId().equals(reporter.getUniqueId())) {
|
||||
reporter.sendMessage(plugin.getConfigManager().getMessage("self-report"));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check duplicate report
|
||||
if (plugin.getDatabaseManager().hasReported(reporter.getUniqueId(), target.getUniqueId())) {
|
||||
reporter.sendMessage(plugin.getConfigManager().getMessage("already-reported"));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create and save report
|
||||
Report report = new Report(
|
||||
reporter.getUniqueId(),
|
||||
reporter.getName(),
|
||||
target.getUniqueId(),
|
||||
target.getName() != null ? target.getName() : targetName,
|
||||
reason
|
||||
reason,
|
||||
imageUrl
|
||||
);
|
||||
|
||||
plugin.getDatabaseManager().saveReport(report);
|
||||
|
||||
// Send to Discord webhook
|
||||
if (plugin.getDiscordWebhook() != null) {
|
||||
plugin.getDiscordWebhook().sendReport(report);
|
||||
}
|
||||
|
|
@ -114,6 +123,48 @@ public class ReportCommand implements CommandExecutor, TabCompleter {
|
|||
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) {
|
||||
if (!player.hasPermission("lorep.admin")) {
|
||||
player.sendMessage(plugin.getConfigManager().getMessage("no-permission"));
|
||||
|
|
@ -134,7 +185,6 @@ public class ReportCommand implements CommandExecutor, TabCompleter {
|
|||
List<String> completions = new ArrayList<>();
|
||||
|
||||
if (args.length == 1) {
|
||||
// First argument: player names or subcommands
|
||||
String input = args[0].toLowerCase();
|
||||
|
||||
if (sender.hasPermission("lorep.admin")) {
|
||||
|
|
@ -144,9 +194,11 @@ public class ReportCommand implements CommandExecutor, TabCompleter {
|
|||
if ("stats".startsWith(input)) {
|
||||
completions.add("stats");
|
||||
}
|
||||
if ("image".startsWith(input)) {
|
||||
completions.add("image");
|
||||
}
|
||||
}
|
||||
|
||||
// Add online player names
|
||||
completions.addAll(
|
||||
Bukkit.getOnlinePlayers().stream()
|
||||
.map(Player::getName)
|
||||
|
|
@ -154,7 +206,6 @@ public class ReportCommand implements CommandExecutor, TabCompleter {
|
|||
.collect(Collectors.toList())
|
||||
);
|
||||
} else if (args.length == 2 && args[0].equalsIgnoreCase("stats")) {
|
||||
// Second argument for stats: player names
|
||||
String input = args[1].toLowerCase();
|
||||
completions.addAll(
|
||||
Bukkit.getOnlinePlayers().stream()
|
||||
|
|
|
|||
|
|
@ -49,14 +49,13 @@ public class ReportStatsCommand {
|
|||
player.sendMessage(plugin.getConfigManager().getMessage("stats-count",
|
||||
"%count%", String.valueOf(reportCount)));
|
||||
|
||||
// Last online
|
||||
String lastOnline = target.isOnline() ? "Сейчас онлайн" :
|
||||
TimeUtil.formatTimeAgo(target.getLastPlayed());
|
||||
String lastOnline = target.isOnline()
|
||||
? plugin.getConfigManager().getMessage("online-status")
|
||||
: TimeUtil.formatTimeAgo(target.getLastPlayed());
|
||||
player.sendMessage(plugin.getConfigManager().getMessage("stats-last-online",
|
||||
"%time%", lastOnline));
|
||||
|
||||
// Recent reports (max 5)
|
||||
player.sendMessage("§7Последние репорты:");
|
||||
player.sendMessage(plugin.getConfigManager().getMessage("stats-recent-header"));
|
||||
int shown = Math.min(MAX_RECENT_REPORTS, reports.size());
|
||||
for (int i = 0; i < shown; i++) {
|
||||
Report report = reports.get(i);
|
||||
|
|
@ -67,7 +66,8 @@ public class ReportStatsCommand {
|
|||
}
|
||||
|
||||
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 org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
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 {
|
||||
|
||||
private final LorepPlugin plugin;
|
||||
private FileConfiguration config;
|
||||
private FileConfiguration messages;
|
||||
|
||||
public ConfigManager(LorepPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
|
|
@ -18,6 +27,15 @@ public class ConfigManager {
|
|||
plugin.saveDefaultConfig();
|
||||
plugin.reloadConfig();
|
||||
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() {
|
||||
|
|
@ -57,10 +75,52 @@ public class ConfigManager {
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
String message = getMessage(key);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -22,4 +22,10 @@ public interface DatabaseManager {
|
|||
List<Report> getReportsPaginated(int page, int pageSize);
|
||||
|
||||
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_name TEXT NOT NULL,
|
||||
reason TEXT NOT NULL,
|
||||
image_url TEXT,
|
||||
status TEXT NOT NULL DEFAULT 'PENDING',
|
||||
created_at BIGINT NOT NULL
|
||||
)
|
||||
""";
|
||||
|
|
@ -98,7 +100,8 @@ public class PostgreSQLDatabaseManager implements DatabaseManager {
|
|||
|
||||
@Override
|
||||
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();
|
||||
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
||||
|
|
@ -107,7 +110,13 @@ public class PostgreSQLDatabaseManager implements DatabaseManager {
|
|||
stmt.setString(3, report.targetUuid().toString());
|
||||
stmt.setString(4, report.targetName());
|
||||
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();
|
||||
} catch (SQLException 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 {
|
||||
String imageUrl = rs.getString("image_url");
|
||||
if (rs.wasNull()) {
|
||||
imageUrl = null;
|
||||
}
|
||||
return new Report(
|
||||
rs.getInt("id"),
|
||||
UUID.fromString(rs.getString("reporter_uuid")),
|
||||
|
|
@ -237,7 +250,60 @@ public class PostgreSQLDatabaseManager implements DatabaseManager {
|
|||
UUID.fromString(rs.getString("target_uuid")),
|
||||
rs.getString("target_name"),
|
||||
rs.getString("reason"),
|
||||
imageUrl,
|
||||
rs.getString("status"),
|
||||
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,
|
||||
String targetName,
|
||||
String reason,
|
||||
String imageUrl,
|
||||
String status,
|
||||
Instant createdAt
|
||||
) {
|
||||
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_name TEXT NOT NULL,
|
||||
reason TEXT NOT NULL,
|
||||
image_url TEXT,
|
||||
status TEXT NOT NULL DEFAULT 'PENDING',
|
||||
created_at INTEGER NOT NULL
|
||||
)
|
||||
""";
|
||||
|
|
@ -82,7 +84,8 @@ public class SQLiteDatabaseManager implements DatabaseManager {
|
|||
|
||||
@Override
|
||||
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)) {
|
||||
stmt.setString(1, report.reporterUuid().toString());
|
||||
|
|
@ -90,7 +93,13 @@ public class SQLiteDatabaseManager implements DatabaseManager {
|
|||
stmt.setString(3, report.targetUuid().toString());
|
||||
stmt.setString(4, report.targetName());
|
||||
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();
|
||||
} catch (SQLException 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 {
|
||||
String imageUrl = rs.getString("image_url");
|
||||
if (rs.wasNull()) {
|
||||
imageUrl = null;
|
||||
}
|
||||
return new Report(
|
||||
rs.getInt("id"),
|
||||
UUID.fromString(rs.getString("reporter_uuid")),
|
||||
|
|
@ -214,7 +227,57 @@ public class SQLiteDatabaseManager implements DatabaseManager {
|
|||
UUID.fromString(rs.getString("target_uuid")),
|
||||
rs.getString("target_name"),
|
||||
rs.getString("reason"),
|
||||
imageUrl,
|
||||
rs.getString("status"),
|
||||
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;
|
||||
|
||||
import dev.loki.lorep.LorepPlugin;
|
||||
import dev.loki.lorep.database.Report;
|
||||
import dev.loki.lorep.util.PaginationUtil;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
|
|
@ -28,21 +30,97 @@ public class GuiClickListener implements Listener {
|
|||
return;
|
||||
}
|
||||
|
||||
int slot = event.getRawSlot();
|
||||
String action = gui.slotActions.get(event.getRawSlot());
|
||||
|
||||
// Navigation buttons are in bottom row
|
||||
if (slot == ReportGui.SLOT_PREV_PAGE) {
|
||||
if (gui.getPage() > 0) {
|
||||
new ReportGui(plugin, gui.getPage() - 1).open(player);
|
||||
}
|
||||
} else if (slot == ReportGui.SLOT_CLOSE) {
|
||||
if (action == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case "prev_page" -> handlePrevPage(player, gui);
|
||||
case "next_page" -> handleNextPage(player, gui);
|
||||
case "close" -> handleClose(player, gui);
|
||||
case "teleport" -> handleTeleport(player, gui);
|
||||
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();
|
||||
} else if (slot == ReportGui.SLOT_NEXT_PAGE) {
|
||||
int totalReports = plugin.getDatabaseManager().getTotalReportCount();
|
||||
int totalPages = PaginationUtil.calculateTotalPages(totalReports, ReportGui.PAGE_SIZE);
|
||||
if (gui.getPage() < totalPages - 1) {
|
||||
new ReportGui(plugin, gui.getPage() + 1).open(player);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,140 +1,356 @@
|
|||
package dev.loki.lorep.gui;
|
||||
|
||||
import dev.loki.lorep.LorepPlugin;
|
||||
import dev.loki.lorep.config.GuiItemConfig;
|
||||
import dev.loki.lorep.database.Report;
|
||||
import dev.loki.lorep.util.PaginationUtil;
|
||||
import dev.loki.lorep.util.TimeUtil;
|
||||
import org.bukkit.Bukkit;
|
||||
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.InventoryHolder;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.SkullMeta;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ReportGui implements InventoryHolder {
|
||||
|
||||
public static final int PAGE_SIZE = 45; // 5 rows for reports
|
||||
public static final int INVENTORY_SIZE = 54; // 6 rows total
|
||||
public static final int INVENTORY_SIZE = 54;
|
||||
|
||||
public static final int SLOT_PREV_PAGE = 45;
|
||||
public static final int SLOT_CLOSE = 47;
|
||||
public static final int SLOT_PAGE_INFO = 49;
|
||||
public static final int SLOT_NEXT_PAGE = 53;
|
||||
final int page;
|
||||
boolean detailView;
|
||||
Report currentReport;
|
||||
final Map<Integer, String> slotActions = new HashMap<>();
|
||||
|
||||
private final LorepPlugin plugin;
|
||||
private final int page;
|
||||
private Inventory inventory;
|
||||
|
||||
public ReportGui(LorepPlugin plugin, int page) {
|
||||
this.plugin = plugin;
|
||||
this.page = page;
|
||||
this.detailView = false;
|
||||
this.currentReport = null;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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 totalPages = PaginationUtil.calculateTotalPages(totalReports, pageSize);
|
||||
|
||||
GuiItemConfig entryConfig = plugin.getConfigManager().getGuiItem("report-entry");
|
||||
|
||||
// Add report items
|
||||
for (int i = 0; i < reports.size(); i++) {
|
||||
Report report = reports.get(i);
|
||||
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
|
||||
addNavigationButtons(totalReports);
|
||||
addNavigation(totalReports, totalPages);
|
||||
player.openInventory(inventory);
|
||||
}
|
||||
|
||||
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 ItemStack createReportItem(Report report, int totalReports) {
|
||||
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);
|
||||
SkullMeta meta = (SkullMeta) head.getItemMeta();
|
||||
|
||||
if (meta != null) {
|
||||
// Set skull owner for skin
|
||||
meta.setOwningPlayer(Bukkit.getOfflinePlayer(report.targetUuid()));
|
||||
|
||||
// Display name
|
||||
meta.setDisplayName("§c" + report.targetName());
|
||||
|
||||
// Lore with report info
|
||||
List<String> lore = new ArrayList<>();
|
||||
lore.add("§7");
|
||||
lore.add("§eОтправитель: §f" + report.reporterName());
|
||||
lore.add("§ePричина: §f" + report.reason());
|
||||
lore.add("§eВремя: §f" + TimeUtil.formatTimeAgo(report.createdAt().toEpochMilli()));
|
||||
lore.add("§eBy: §f" + report.reporterName());
|
||||
lore.add("§eReason: §f" + report.reason());
|
||||
lore.add("§eTime: §f" + TimeUtil.formatTimeAgo(report.createdAt()));
|
||||
lore.add("§7");
|
||||
lore.add("§eВсего репортов: §c" + totalReports);
|
||||
|
||||
lore.add("§eReports: §c" + totalReports);
|
||||
meta.setLore(lore);
|
||||
head.setItemMeta(meta);
|
||||
}
|
||||
|
||||
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() {
|
||||
return page;
|
||||
}
|
||||
|
||||
public boolean isDetailView() {
|
||||
return detailView;
|
||||
}
|
||||
|
||||
public Report getCurrentReport() {
|
||||
return currentReport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Inventory getInventory() {
|
||||
return inventory;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
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 okhttp3.Call;
|
||||
import okhttp3.Callback;
|
||||
|
|
@ -62,28 +65,161 @@ public class DiscordWebhook {
|
|||
});
|
||||
}
|
||||
|
||||
public String buildPayload(Report report) {
|
||||
String timestamp = FORMATTER.format(report.createdAt());
|
||||
public void sendStatusUpdate(Report report) {
|
||||
if (webhookUrl == null || webhookUrl.isEmpty()) {
|
||||
logger.warning("Discord webhook URL is not configured");
|
||||
return;
|
||||
}
|
||||
|
||||
return String.format("""
|
||||
{
|
||||
"embeds": [{
|
||||
"title": "📢 Новый репорт",
|
||||
"color": 16711680,
|
||||
"fields": [
|
||||
{"name": "👤 Нарушитель", "value": "%s", "inline": true},
|
||||
{"name": "📝 Отправитель", "value": "%s", "inline": true},
|
||||
{"name": "📋 Причина", "value": "%s", "inline": false},
|
||||
{"name": "🕐 Время", "value": "%s", "inline": false}
|
||||
]
|
||||
}]
|
||||
String json = buildStatusPayload(report);
|
||||
|
||||
RequestBody body = RequestBody.create(json, JSON);
|
||||
Request request = new Request.Builder()
|
||||
.url(webhookUrl)
|
||||
.post(body)
|
||||
.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()),
|
||||
escapeJson(report.reporterName()),
|
||||
escapeJson(report.reason()),
|
||||
timestamp
|
||||
);
|
||||
|
||||
@Override
|
||||
public void onResponse(Call call, Response response) {
|
||||
if (!response.isSuccessful()) {
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
# Discord Webhook URL для уведомлений
|
||||
# Discord webhook URL for report notifications
|
||||
webhook-url: ""
|
||||
|
||||
# Настройки базы данных
|
||||
# Database configuration
|
||||
database:
|
||||
# Тип БД: sqlite или postgresql
|
||||
# Database type: "sqlite" or "postgresql"
|
||||
type: "sqlite"
|
||||
|
||||
# Настройки SQLite
|
||||
# SQLite settings
|
||||
sqlite:
|
||||
file: "reports.db"
|
||||
|
||||
# Настройки PostgreSQL
|
||||
# PostgreSQL settings
|
||||
postgresql:
|
||||
host: "localhost"
|
||||
port: 5432
|
||||
|
|
@ -19,48 +19,145 @@ database:
|
|||
password: "password"
|
||||
pool-size: 10
|
||||
|
||||
# Настройки GUI
|
||||
# GUI settings
|
||||
gui:
|
||||
# Количество репортов на странице
|
||||
# Reports per page in GUI
|
||||
reports-per-page: 45
|
||||
# Автообновление GUI (в тиках, 20 тиков = 1 секунда)
|
||||
# Auto-refresh interval in ticks (20 ticks = 1 second)
|
||||
auto-refresh: 100
|
||||
# Показывать головы игроков в GUI
|
||||
# Show player heads in GUI
|
||||
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:
|
||||
# Максимальная длина причины репорта
|
||||
# Maximum reason length in characters
|
||||
max-reason-length: 100
|
||||
# Кулдаун между репортами (в секундах)
|
||||
# Cooldown between reports (seconds)
|
||||
report-cooldown: 30
|
||||
# Максимум репортов на одного игрока от одного отправителя
|
||||
# Max reports per player from the same reporter
|
||||
max-reports-per-player: 3
|
||||
|
||||
# Уведомления
|
||||
# Notifications
|
||||
notifications:
|
||||
# Уведомлять администраторов о новых репортах
|
||||
# Notify admins about new reports
|
||||
notify-admins: true
|
||||
# Звук уведомления для администраторов
|
||||
# Admin notification sound
|
||||
admin-notification-sound: "BLOCK_NOTE_BLOCK_PLING"
|
||||
# Уведомлять игрока о принятии репорта
|
||||
# Notify reporter when report is handled
|
||||
notify-reporter: true
|
||||
|
||||
# Сообщения
|
||||
# Messages (override defaults from messages.yml)
|
||||
messages:
|
||||
report-sent: "&aРепорт успешно отправлен!"
|
||||
already-reported: "&cВы уже отправляли репорт на этого игрока!"
|
||||
self-report: "&cВы не можете отправить репорт на себя!"
|
||||
player-not-found: "&cИгрок не найден!"
|
||||
no-permission: "&cУ вас нет прав на эту команду!"
|
||||
usage: "&eИспользование: /report <ник> <причина>"
|
||||
no-reports: "&eУ этого игрока нет репортов."
|
||||
stats-header: "&6=== Статистика репортов: %player% ==="
|
||||
stats-count: "&eВсего репортов: &f%count%"
|
||||
stats-last-online: "&eПоследний онлайн: &f%time%"
|
||||
stats-report-entry: "&7- %reason% &8(%time% назад)"
|
||||
gui-title: "Репорты - Страница %page%"
|
||||
cooldown: "&cПодождите %time% секунд перед следующим репортом!"
|
||||
reason-too-long: "&cПричина слишком длинная! Максимум %max% символов."
|
||||
max-reports-reached: "&cВы уже отправили максимальное количество репортов на этого игрока!"
|
||||
admin-notification: "&6[Loreport] &eНовый репорт от &f%reporter% &eна &f%reported%: &7%reason%"
|
||||
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!"
|
||||
no-permission: "&cYou don't have permission!"
|
||||
usage: "&eUsage: /report <player> <reason> [screenshot_url] | /report gui | /report stats <player> | /report image <id> <url>"
|
||||
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)"
|
||||
gui-title: "Reports - Page %page%"
|
||||
cooldown: "&cPlease wait %time% seconds before your next report!"
|
||||
reason-too-long: "&cReason too long! Max %max% characters."
|
||||
max-reports-reached: "&cYou've reached the max reports for this player!"
|
||||
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:
|
||||
report:
|
||||
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
|
||||
aliases: [rep, reports]
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ public class DatabaseManagerTest {
|
|||
Assume.that(!reporterUuid.equals(targetUuid));
|
||||
|
||||
Report report = new Report(
|
||||
0, reporterUuid, "Reporter", targetUuid, "Target", reason, Instant.now()
|
||||
reporterUuid, "Reporter", targetUuid, "Target", reason
|
||||
);
|
||||
|
||||
dbManager.saveReport(report);
|
||||
|
|
@ -95,7 +95,7 @@ public class DatabaseManagerTest {
|
|||
"Should not have reported before creating report");
|
||||
|
||||
Report report = new Report(
|
||||
0, reporterUuid, "Reporter", targetUuid, "Target", "Test reason", Instant.now()
|
||||
reporterUuid, "Reporter", targetUuid, "Target", "Test reason"
|
||||
);
|
||||
dbManager.saveReport(report);
|
||||
|
||||
|
|
@ -121,7 +121,7 @@ public class DatabaseManagerTest {
|
|||
String targetName = "Target_" + targetUuid.toString().substring(0, 8);
|
||||
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);
|
||||
|
||||
// Close and reopen database
|
||||
|
|
@ -151,9 +151,10 @@ public class DatabaseManagerTest {
|
|||
UUID targetUuid = UUID.randomUUID();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
Instant reportTime = Instant.now().minusSeconds(count - i);
|
||||
Report report = new Report(
|
||||
0, UUID.randomUUID(), "Reporter" + i, targetUuid, "Target",
|
||||
"Reason " + i, Instant.now().minusSeconds(count - i)
|
||||
"Reason " + i, null, "PENDING", reportTime
|
||||
);
|
||||
dbManager.saveReport(report);
|
||||
}
|
||||
|
|
@ -180,8 +181,8 @@ public class DatabaseManagerTest {
|
|||
|
||||
for (int i = 0; i < count; i++) {
|
||||
Report report = new Report(
|
||||
0, UUID.randomUUID(), "Reporter" + i, targetUuid, "Target",
|
||||
"Reason " + i, Instant.now()
|
||||
UUID.randomUUID(), "Reporter" + i, targetUuid, "Target",
|
||||
"Reason " + i
|
||||
);
|
||||
dbManager.saveReport(report);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,13 +33,11 @@ public class DiscordWebhookTest {
|
|||
DiscordWebhook webhook = new DiscordWebhook("https://example.com/webhook", logger);
|
||||
|
||||
Report report = new Report(
|
||||
1,
|
||||
UUID.randomUUID(),
|
||||
reporterName,
|
||||
UUID.randomUUID(),
|
||||
targetName,
|
||||
reason,
|
||||
Instant.now()
|
||||
reason
|
||||
);
|
||||
|
||||
String payload = webhook.buildPayload(report);
|
||||
|
|
@ -95,9 +93,9 @@ public class DiscordWebhookTest {
|
|||
DiscordWebhook webhook = new DiscordWebhook("https://example.com/webhook", logger);
|
||||
|
||||
Report report = new Report(
|
||||
1, UUID.randomUUID(), "TestReporter",
|
||||
UUID.randomUUID(), "TestReporter",
|
||||
UUID.randomUUID(), "TestTarget",
|
||||
"Test reason", Instant.now()
|
||||
"Test reason"
|
||||
);
|
||||
|
||||
String payload = webhook.buildPayload(report);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue