diff --git a/src/main/java/net/viper/status/modules/chat/ReportManager.java b/src/main/java/net/viper/status/modules/chat/ReportManager.java deleted file mode 100644 index 27a52a1..0000000 --- a/src/main/java/net/viper/status/modules/chat/ReportManager.java +++ /dev/null @@ -1,227 +0,0 @@ -package net.viper.status.modules.chat; - -import java.io.*; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.logging.Logger; - -/** - * Verwaltet Spieler-Reports (/report). - * - * Reports werden mit einer eindeutigen ID (z.B. RPT-0001) gespeichert und - * bleiben offen, bis ein Admin sie explizit mit /reportclose schließt. - * - * Online-Admins werden sofort benachrichtigt. - * Offline-Admins erhalten eine verzögerte Benachrichtigung beim nächsten Login - * (gesteuert von außen via getPendingNotificationFor()). - * - * Speicherformat (chat_reports.dat): - * id|reporter|reporterUUID|reported|server|messageContext|reason|timestamp|closed|closedBy - */ -public class ReportManager { - - private final File file; - private final Logger logger; - - /** Alle Reports (offen und geschlossen). */ - private final ConcurrentHashMap reports = new ConcurrentHashMap<>(); - - /** Zähler für Report-IDs. Wird beim Laden synchronisiert. */ - private final AtomicInteger idCounter = new AtomicInteger(0); - - private static final SimpleDateFormat DATE_FMT = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss"); - - // ===== Report-Datenklasse ===== - - public static class ChatReport { - public String id; - public String reporterName; - public UUID reporterUUID; - public String reportedName; - public String server; - public String messageContext; // letzte bekannte Chatnachricht des Gemeldeten - public String reason; - public long timestamp; - public boolean closed; - public String closedBy; // Name des schließenden Admins (oder leer) - - public String getFormattedTime() { - return DATE_FMT.format(new Date(timestamp)); - } - } - - // ===== Konstruktor ===== - - public ReportManager(File dataFolder, Logger logger) { - this.file = new File(dataFolder, "chat_reports.dat"); - this.logger = logger; - } - - // ===== Report-Logik ===== - - /** - * Erstellt einen neuen Report. - * - * @param reporterName Name des meldenden Spielers - * @param reporterUUID UUID des meldenden Spielers - * @param reportedName Name des gemeldeten Spielers - * @param server Server, auf dem sich der Reporter befand - * @param messageContext Letzte bekannte Nachricht des Gemeldeten (für Kontext) - * @param reason Freitext-Begründung - * @return die neue Report-ID (z.B. RPT-0001) - */ - public String createReport(String reporterName, UUID reporterUUID, - String reportedName, String server, - String messageContext, String reason) { - String id = String.format("RPT-%04d", idCounter.incrementAndGet()); - - ChatReport report = new ChatReport(); - report.id = id; - report.reporterName = reporterName; - report.reporterUUID = reporterUUID; - report.reportedName = reportedName; - report.server = server; - report.messageContext = messageContext != null ? messageContext : ""; - report.reason = reason; - report.timestamp = System.currentTimeMillis(); - report.closed = false; - report.closedBy = ""; - - reports.put(id, report); - save(); - return id; - } - - /** - * Schließt einen Report. - * - * @param id Report-ID (z.B. RPT-0001, case-insensitiv) - * @param adminName Name des Admins, der den Report schließt - * @return true wenn erfolgreich geschlossen, false wenn nicht gefunden / bereits geschlossen - */ - public boolean closeReport(String id, String adminName) { - ChatReport report = getReport(id); - if (report == null || report.closed) return false; - report.closed = true; - report.closedBy = adminName; - save(); - return true; - } - - /** Gibt einen Report nach ID zurück (case-insensitiv). */ - public ChatReport getReport(String id) { - if (id == null) return null; - return reports.get(id.toUpperCase()); - } - - /** Gibt alle offenen Reports chronologisch (älteste zuerst) zurück. */ - public List getOpenReports() { - List list = new ArrayList<>(); - for (ChatReport r : reports.values()) { - if (!r.closed) list.add(r); - } - list.sort(Comparator.comparingLong(r -> r.timestamp)); - return list; - } - - /** Gibt alle Reports chronologisch zurück (auch geschlossene). */ - public List getAllReports() { - List list = new ArrayList<>(reports.values()); - list.sort(Comparator.comparingLong(r -> r.timestamp)); - return list; - } - - /** Anzahl offener Reports. */ - public int getOpenCount() { - int count = 0; - for (ChatReport r : reports.values()) if (!r.closed) count++; - return count; - } - - // ===== Persistenz ===== - - public void save() { - try (BufferedWriter bw = new BufferedWriter( - new OutputStreamWriter(new FileOutputStream(file), "UTF-8"))) { - for (ChatReport r : reports.values()) { - bw.write( - esc(r.id) + "|" + - esc(r.reporterName) + "|" + - r.reporterUUID + "|" + - esc(r.reportedName) + "|" + - esc(r.server) + "|" + - esc(r.messageContext) + "|" + - esc(r.reason) + "|" + - r.timestamp + "|" + - r.closed + "|" + - esc(r.closedBy != null ? r.closedBy : "") - ); - bw.newLine(); - } - } catch (IOException e) { - logger.warning("[ChatModule] Fehler beim Speichern der Reports: " + e.getMessage()); - } - } - - public void load() { - reports.clear(); - if (!file.exists()) return; - - int maxNum = 0; - try (BufferedReader br = new BufferedReader( - new InputStreamReader(new FileInputStream(file), "UTF-8"))) { - String line; - while ((line = br.readLine()) != null) { - line = line.trim(); - if (line.isEmpty()) continue; - String[] p = line.split("\\|", -1); - if (p.length < 10) continue; - try { - ChatReport r = new ChatReport(); - r.id = unesc(p[0]); - r.reporterName = unesc(p[1]); - r.reporterUUID = UUID.fromString(p[2]); - r.reportedName = unesc(p[3]); - r.server = unesc(p[4]); - r.messageContext = unesc(p[5]); - r.reason = unesc(p[6]); - r.timestamp = Long.parseLong(p[7]); - r.closed = Boolean.parseBoolean(p[8]); - r.closedBy = unesc(p[9]); - reports.put(r.id.toUpperCase(), r); - - // Zähler auf höchste bekannte Nummer synchronisieren - if (r.id.toUpperCase().startsWith("RPT-")) { - try { - int num = Integer.parseInt(r.id.substring(4)); - if (num > maxNum) maxNum = num; - } catch (NumberFormatException ignored) {} - } - } catch (Exception ignored) {} - } - } catch (IOException e) { - logger.warning("[ChatModule] Fehler beim Laden der Reports: " + e.getMessage()); - } - idCounter.set(maxNum); - - } - - // ===== Escape-Helfer (Pipe-Zeichen und Zeilenumbrüche escapen) ===== - - private static String esc(String s) { - if (s == null) return ""; - return s.replace("\\", "\\\\") - .replace("|", "\\p") - .replace("\n", "\\n") - .replace("\r", ""); - } - - private static String unesc(String s) { - if (s == null) return ""; - return s.replace("\\n", "\n") - .replace("\\p", "|") - .replace("\\\\", "\\"); - } -} \ No newline at end of file