Update from Git Manager GUI

This commit is contained in:
2026-02-21 00:55:27 +01:00
parent a91e17a097
commit b7de357e81
15 changed files with 2313 additions and 1034 deletions

View File

@@ -2,7 +2,13 @@ package de.ticketsystem.commands;
import de.ticketsystem.TicketPlugin;
import de.ticketsystem.model.Ticket;
import de.ticketsystem.manager.CategoryManager;
import de.ticketsystem.model.ConfigCategory;
import de.ticketsystem.model.TicketComment;
import de.ticketsystem.model.TicketPriority;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
@@ -12,14 +18,13 @@ import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
public class TicketCommand implements CommandExecutor, TabCompleter {
private final TicketPlugin plugin;
public TicketCommand(TicketPlugin plugin) {
this.plugin = plugin;
}
public TicketCommand(TicketPlugin plugin) { this.plugin = plugin; }
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
@@ -27,23 +32,25 @@ public class TicketCommand implements CommandExecutor, TabCompleter {
sender.sendMessage("Dieser Befehl kann nur von Spielern ausgeführt werden.");
return true;
}
if (args.length == 0) {
plugin.getTicketManager().sendHelpMessage(player);
return true;
}
if (args.length == 0) { plugin.getTicketManager().sendHelpMessage(player); return true; }
switch (args[0].toLowerCase()) {
case "create" -> handleCreate(player, args);
case "list" -> handleList(player);
case "claim" -> handleClaim(player, args);
case "close" -> handleClose(player, args);
case "forward" -> handleForward(player, args);
case "reload" -> handleReload(player);
case "migrate" -> handleMigrate(player, args);
case "export" -> handleExport(player, args);
case "import" -> handleImport(player, args);
case "stats" -> handleStats(player);
case "archive" -> handleArchive(player);
default -> plugin.getTicketManager().sendHelpMessage(player);
case "create" -> handleCreate(player, args);
case "list" -> handleList(player);
case "claim" -> handleClaim(player, args);
case "close" -> handleClose(player, args);
case "forward" -> handleForward(player, args);
case "reload" -> handleReload(player);
case "migrate" -> handleMigrate(player, args);
case "export" -> handleExport(player, args);
case "import" -> handleImport(player, args);
case "stats" -> handleStats(player);
case "archive" -> handleArchive(player);
case "comment" -> handleComment(player, args);
case "blacklist" -> handleBlacklist(player, args);
case "rate" -> handleRate(player, args);
case "setpriority" -> handleSetPriority(player, args);
default -> plugin.getTicketManager().sendHelpMessage(player);
}
return true;
}
@@ -52,44 +59,113 @@ public class TicketCommand implements CommandExecutor, TabCompleter {
private void handleCreate(Player player, String[] args) {
if (!player.hasPermission("ticket.create")) {
player.sendMessage(plugin.formatMessage("messages.no-permission"));
player.sendMessage(plugin.formatMessage("messages.no-permission")); return;
}
// Blacklist-Check
if (plugin.getDatabaseManager().isBlacklisted(player.getUniqueId())) {
player.sendMessage(plugin.color("&cDu wurdest vom Ticket-System gesperrt und kannst keine Tickets erstellen."));
return;
}
if (args.length < 2) {
player.sendMessage(plugin.color("&cBenutzung: /ticket create <Beschreibung>"));
player.sendMessage(plugin.color("&cBenutzung: /ticket create [Kategorie] [Priorität] <Beschreibung>"));
if (plugin.getConfig().getBoolean("categories-enabled", true)) {
player.sendMessage(plugin.color("&7Kategorien: &ebug&7, &efrage&7, &ebeschwerde&7, &esonstiges&7, &eallgemein"));
}
if (plugin.getConfig().getBoolean("priorities-enabled", true)) {
player.sendMessage(plugin.color("&7Prioritäten: &alow&7, &enormal&7, &6high&7, &curgent"));
}
return;
}
if (plugin.getTicketManager().hasCooldown(player.getUniqueId())) {
long remaining = plugin.getTicketManager().getRemainingCooldown(player.getUniqueId());
player.sendMessage(plugin.formatMessage("messages.cooldown")
.replace("{seconds}", String.valueOf(remaining)));
player.sendMessage(plugin.formatMessage("messages.cooldown").replace("{seconds}", String.valueOf(remaining)));
return;
}
if (plugin.getTicketManager().hasReachedTicketLimit(player.getUniqueId())) {
int max = plugin.getConfig().getInt("max-open-tickets-per-player", 2);
player.sendMessage(plugin.color("&cDu hast bereits &e" + max
+ " &coffene Ticket(s). Bitte warte, bis dein Ticket bearbeitet wurde."));
player.sendMessage(plugin.color("&cDu hast bereits &e" + max + " &coffene Ticket(s). Bitte warte, bis dein Ticket bearbeitet wurde."));
return;
}
String message = String.join(" ", Arrays.copyOfRange(args, 1, args.length));
// Kategorie und Priorität optional parsen
CategoryManager cm = plugin.getCategoryManager();
ConfigCategory category = cm.getDefault();
TicketPriority priority = TicketPriority.NORMAL;
int messageStartIndex = 1;
boolean categoriesOn = plugin.getConfig().getBoolean("categories-enabled", true);
boolean prioritiesOn = plugin.getConfig().getBoolean("priorities-enabled", true);
if (args.length >= 3) {
// args[1]: erst als Kategorie prüfen, dann als Priorität
if (categoriesOn) {
ConfigCategory parsedCat = cm.resolve(args[1]);
if (parsedCat != null) {
category = parsedCat;
messageStartIndex = 2;
// args[2]: Priorität prüfen (nur wenn danach noch Text kommt)
if (prioritiesOn && args.length >= 4) {
TicketPriority parsedPrio = parsePriority(args[2]);
if (parsedPrio != null) {
priority = parsedPrio;
messageStartIndex = 3;
}
}
} else {
// Keine Kategorie erkannt → args[1] als Priorität prüfen
if (prioritiesOn) {
TicketPriority parsedPrio = parsePriority(args[1]);
if (parsedPrio != null) {
priority = parsedPrio;
messageStartIndex = 2;
}
}
}
} else if (prioritiesOn) {
// Kategorien aus → args[1] direkt als Priorität prüfen
TicketPriority parsedPrio = parsePriority(args[1]);
if (parsedPrio != null) {
priority = parsedPrio;
messageStartIndex = 2;
}
}
} else if (args.length == 2) {
// Nur ein Argument: könnte Kategorie oder Priorität sein, aber kein Text danach
// → einfach als Beschreibung behandeln, nichts parsen
}
String message = String.join(" ", Arrays.copyOfRange(args, messageStartIndex, args.length));
int maxLen = plugin.getConfig().getInt("max-description-length", 100);
if (message.isEmpty()) {
player.sendMessage(plugin.color("&cBitte gib eine Beschreibung für dein Ticket an."));
return;
}
if (message.length() > maxLen) {
player.sendMessage(plugin.color("&cDeine Beschreibung ist zu lang! Maximal " + maxLen + " Zeichen."));
return;
}
final ConfigCategory finalCategory = category;
final TicketPriority finalPriority = priority;
Ticket ticket = new Ticket(player.getUniqueId(), player.getName(), message, player.getLocation());
ticket.setCategoryKey(finalCategory.getKey());
ticket.setPriority(finalPriority);
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
int id = plugin.getDatabaseManager().createTicket(ticket);
if (id == -1) {
player.sendMessage(plugin.color("&cFehler beim Erstellen des Tickets!"));
return;
}
if (id == -1) { player.sendMessage(plugin.color("&cFehler beim Erstellen des Tickets!")); return; }
ticket.setId(id);
plugin.getTicketManager().setCooldown(player.getUniqueId());
Bukkit.getScheduler().runTask(plugin, () -> {
player.sendMessage(plugin.formatMessage("messages.ticket-created")
.replace("{id}", String.valueOf(id)));
plugin.getTicketManager().notifyTeam(ticket); // ruft auch Discord-Webhook auf
String catInfo = plugin.getConfig().getBoolean("categories-enabled", true)
? " §7[" + finalCategory.getColored() + "§7]" : "";
String prioInfo = plugin.getConfig().getBoolean("priorities-enabled", true)
? " §7[" + finalPriority.getColored() + "§7]" : "";
player.sendMessage(plugin.formatMessage("messages.ticket-created").replace("{id}", String.valueOf(id)) + catInfo + prioInfo);
plugin.getTicketManager().notifyTeam(ticket);
});
});
}
@@ -99,12 +175,10 @@ public class TicketCommand implements CommandExecutor, TabCompleter {
private void handleList(Player player) {
if (player.hasPermission("ticket.support") || player.hasPermission("ticket.admin")) {
Bukkit.getScheduler().runTaskAsynchronously(plugin, () ->
Bukkit.getScheduler().runTask(plugin, () ->
plugin.getTicketGUI().openGUI(player)));
Bukkit.getScheduler().runTask(plugin, () -> plugin.getTicketGUI().openGUI(player)));
} else {
Bukkit.getScheduler().runTaskAsynchronously(plugin, () ->
Bukkit.getScheduler().runTask(plugin, () ->
plugin.getTicketGUI().openPlayerGUI(player)));
Bukkit.getScheduler().runTask(plugin, () -> plugin.getTicketGUI().openPlayerGUI(player)));
}
}
@@ -112,13 +186,9 @@ public class TicketCommand implements CommandExecutor, TabCompleter {
private void handleClaim(Player player, String[] args) {
if (!player.hasPermission("ticket.support") && !player.hasPermission("ticket.admin")) {
player.sendMessage(plugin.formatMessage("messages.no-permission"));
return;
}
if (args.length < 2) {
player.sendMessage(plugin.color("&cBenutzung: /ticket claim <ID>"));
return;
player.sendMessage(plugin.formatMessage("messages.no-permission")); return;
}
if (args.length < 2) { player.sendMessage(plugin.color("&cBenutzung: /ticket claim <ID>")); return; }
int id;
try { id = Integer.parseInt(args[1]); }
catch (NumberFormatException e) { player.sendMessage(plugin.color("&cUngültige ID!")); return; }
@@ -143,40 +213,30 @@ public class TicketCommand implements CommandExecutor, TabCompleter {
private void handleClose(Player player, String[] args) {
if (!player.hasPermission("ticket.support") && !player.hasPermission("ticket.admin")) {
player.sendMessage(plugin.formatMessage("messages.no-permission"));
return;
}
if (args.length < 2) {
player.sendMessage(plugin.color("&cBenutzung: /ticket close <ID> [Kommentar]"));
return;
player.sendMessage(plugin.formatMessage("messages.no-permission")); return;
}
if (args.length < 2) { player.sendMessage(plugin.color("&cBenutzung: /ticket close <ID> [Kommentar]")); return; }
int id;
try { id = Integer.parseInt(args[1]); }
catch (NumberFormatException e) { player.sendMessage(plugin.color("&cUngültige ID!")); return; }
String closeComment = args.length > 2
? String.join(" ", Arrays.copyOfRange(args, 2, args.length)) : "";
final int ticketId = id;
final String comment = closeComment;
final String closer = player.getName();
String closeComment = args.length > 2 ? String.join(" ", Arrays.copyOfRange(args, 2, args.length)) : "";
final int ticketId = id;
final String comment = closeComment;
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
boolean success = plugin.getDatabaseManager().closeTicket(ticketId, comment);
if (success) {
Ticket ticket = plugin.getDatabaseManager().getTicketById(ticketId);
Bukkit.getScheduler().runTask(plugin, () -> {
player.sendMessage(plugin.formatMessage("messages.ticket-closed")
.replace("{id}", String.valueOf(ticketId)));
player.sendMessage(plugin.formatMessage("messages.ticket-closed").replace("{id}", String.valueOf(ticketId)));
if (ticket != null) {
ticket.setCloseComment(comment);
// closerName für Discord-Nachricht mitgeben
plugin.getTicketManager().notifyCreatorClosed(ticket, closer);
plugin.getTicketManager().notifyCreatorClosed(ticket, player.getName());
}
});
} else {
Bukkit.getScheduler().runTask(plugin, () ->
player.sendMessage(plugin.formatMessage("messages.ticket-not-found")));
Bukkit.getScheduler().runTask(plugin, () -> player.sendMessage(plugin.formatMessage("messages.ticket-not-found")));
}
});
}
@@ -185,161 +245,260 @@ public class TicketCommand implements CommandExecutor, TabCompleter {
private void handleForward(Player player, String[] args) {
if (!player.hasPermission("ticket.admin")) {
player.sendMessage(plugin.formatMessage("messages.no-permission"));
return;
}
if (args.length < 3) {
player.sendMessage(plugin.color("&cBenutzung: /ticket forward <ID> <Spieler>"));
return;
player.sendMessage(plugin.formatMessage("messages.no-permission")); return;
}
if (args.length < 3) { player.sendMessage(plugin.color("&cBenutzung: /ticket forward <ID> <Spieler>")); return; }
int id;
try { id = Integer.parseInt(args[1]); }
catch (NumberFormatException e) { player.sendMessage(plugin.color("&cUngültige ID!")); return; }
Player target = Bukkit.getPlayer(args[2]);
if (target == null || !target.isOnline()) {
player.sendMessage(plugin.color("&cSpieler &e" + args[2] + " &cist nicht online!"));
if (target == null) { player.sendMessage(plugin.color("&cSpieler nicht gefunden!")); return; }
final int ticketId = id;
final String fromName = player.getName();
final Player t = target;
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
boolean success = plugin.getDatabaseManager().forwardTicket(ticketId, t.getUniqueId(), t.getName());
Bukkit.getScheduler().runTask(plugin, () -> {
if (!success) { player.sendMessage(plugin.formatMessage("messages.ticket-not-found")); return; }
Ticket ticket = plugin.getDatabaseManager().getTicketById(ticketId);
if (ticket == null) return;
player.sendMessage(plugin.color("&aTicket &e#" + ticketId + " &awurde an &e" + t.getName() + " &aweitergeleitet."));
plugin.getTicketManager().notifyForwardedTo(ticket, fromName);
plugin.getTicketManager().notifyCreatorForwarded(ticket);
});
});
}
// ─────────────────────────── /ticket comment ───────────────────────────
private void handleComment(Player player, String[] args) {
if (!player.hasPermission("ticket.create") && !player.hasPermission("ticket.support") && !player.hasPermission("ticket.admin")) {
player.sendMessage(plugin.formatMessage("messages.no-permission")); return;
}
if (args.length < 3) { player.sendMessage(plugin.color("&cBenutzung: /ticket comment <ID> <Nachricht>")); return; }
int id;
try { id = Integer.parseInt(args[1]); }
catch (NumberFormatException e) { player.sendMessage(plugin.color("&cUngültige ID!")); return; }
String msg = String.join(" ", Arrays.copyOfRange(args, 2, args.length));
if (msg.length() > 500) { player.sendMessage(plugin.color("&cNachricht zu lang! Maximal 500 Zeichen.")); return; }
final int ticketId = id;
final String message = msg;
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
Ticket ticket = plugin.getDatabaseManager().getTicketById(ticketId);
if (ticket == null) {
Bukkit.getScheduler().runTask(plugin, () -> player.sendMessage(plugin.formatMessage("messages.ticket-not-found")));
return;
}
// Spieler darf nur auf eigene Tickets kommentieren (Supporter/Admin: alle)
boolean isOwner = ticket.getCreatorUUID().equals(player.getUniqueId());
boolean isStaff = player.hasPermission("ticket.support") || player.hasPermission("ticket.admin");
if (!isOwner && !isStaff) {
Bukkit.getScheduler().runTask(plugin, () -> player.sendMessage(plugin.color("&cDu kannst nur deine eigenen Tickets kommentieren.")));
return;
}
TicketComment comment = new TicketComment(ticketId, player.getUniqueId(), player.getName(), message);
boolean success = plugin.getDatabaseManager().addComment(comment);
Bukkit.getScheduler().runTask(plugin, () -> {
if (success) {
player.sendMessage(plugin.color("&aDein Kommentar zu Ticket &e#" + ticketId + " &awurde gespeichert."));
// Supporter/Admin und Ticket-Ersteller benachrichtigen
notifyCommentReceivers(player, ticket, message);
} else {
player.sendMessage(plugin.color("&cFehler beim Speichern des Kommentars."));
}
});
});
}
private void notifyCommentReceivers(Player author, Ticket ticket, String message) {
String onlineMsg = plugin.color("&e[Ticket #" + ticket.getId() + "] &f" + author.getName() + " &7hat kommentiert: &f" + message);
String offlineMsg = "&e[Ticket #" + ticket.getId() + "] &f" + author.getName() + " &7hat kommentiert (während du offline warst): &f" + message;
// Ticket-Ersteller benachrichtigen (wenn nicht der Autor selbst)
if (!ticket.getCreatorUUID().equals(author.getUniqueId())) {
Player creator = Bukkit.getPlayer(ticket.getCreatorUUID());
if (creator != null && creator.isOnline()) {
creator.sendMessage(onlineMsg);
} else {
// Offline → für nächsten Login speichern
Bukkit.getScheduler().runTaskAsynchronously(plugin, () ->
plugin.getDatabaseManager().addPendingNotification(ticket.getCreatorUUID(), offlineMsg));
}
}
// Supporter/Admin benachrichtigen (wenn Autor kein Supporter ist)
if (!author.hasPermission("ticket.support") && !author.hasPermission("ticket.admin")) {
// Claimer des Tickets bevorzugt benachrichtigen
UUID claimerUUID = ticket.getClaimerUUID();
if (claimerUUID != null && !claimerUUID.equals(author.getUniqueId())) {
Player claimer = Bukkit.getPlayer(claimerUUID);
if (claimer != null && claimer.isOnline()) {
claimer.sendMessage(onlineMsg);
} else {
String claimerOffline = "&e[Ticket #" + ticket.getId() + "] &f" + author.getName() + " &7hat auf dein bearbeitetes Ticket kommentiert (offline): &f" + message;
Bukkit.getScheduler().runTaskAsynchronously(plugin, () ->
plugin.getDatabaseManager().addPendingNotification(claimerUUID, claimerOffline));
}
}
// Alle anderen Online-Supporter zusätzlich informieren
for (Player p : Bukkit.getOnlinePlayers()) {
if (p.getUniqueId().equals(author.getUniqueId())) continue;
if (claimerUUID != null && p.getUniqueId().equals(claimerUUID)) continue; // schon oben
if (p.hasPermission("ticket.support") || p.hasPermission("ticket.admin")) {
p.sendMessage(onlineMsg);
}
}
}
}
// ─────────────────────────── /ticket rate ──────────────────────────────
private void handleRate(Player player, String[] args) {
if (!plugin.getConfig().getBoolean("rating-enabled", true)) {
player.sendMessage(plugin.color("&cBewertungen sind deaktiviert.")); return;
}
if (args.length < 3) { player.sendMessage(plugin.color("&cBenutzung: /ticket rate <ID> <good|bad>")); return; }
int id;
try { id = Integer.parseInt(args[1]); }
catch (NumberFormatException e) { player.sendMessage(plugin.color("&cUngültige ID!")); return; }
String ratingArg = args[2].toLowerCase();
String rating;
if (ratingArg.equals("good") || ratingArg.equals("gut") || ratingArg.equals("thumbsup")) {
rating = "THUMBS_UP";
} else if (ratingArg.equals("bad") || ratingArg.equals("schlecht") || ratingArg.equals("thumbsdown")) {
rating = "THUMBS_DOWN";
} else {
player.sendMessage(plugin.color("&cUngültige Bewertung! Benutze &egood &coder &ebad&c."));
return;
}
final int ticketId = id;
final Player finalTarget = target;
final String fromName = player.getName();
final int ticketId = id;
final String finalRating = rating;
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
boolean success = plugin.getDatabaseManager()
.forwardTicket(ticketId, finalTarget.getUniqueId(), finalTarget.getName());
if (success) {
Ticket ticket = plugin.getDatabaseManager().getTicketById(ticketId);
Bukkit.getScheduler().runTask(plugin, () -> {
player.sendMessage(plugin.formatMessage("messages.ticket-forwarded")
.replace("{id}", String.valueOf(ticketId))
.replace("{player}", finalTarget.getName()));
if (ticket != null) {
// fromName für Discord mitgeben
plugin.getTicketManager().notifyForwardedTo(ticket, fromName);
plugin.getTicketManager().notifyCreatorForwarded(ticket);
}
});
} else {
Bukkit.getScheduler().runTask(plugin, () ->
player.sendMessage(plugin.formatMessage("messages.ticket-not-found")));
Ticket ticket = plugin.getDatabaseManager().getTicketById(ticketId);
if (ticket == null) {
Bukkit.getScheduler().runTask(plugin, () -> player.sendMessage(plugin.formatMessage("messages.ticket-not-found")));
return;
}
if (!ticket.getCreatorUUID().equals(player.getUniqueId())) {
Bukkit.getScheduler().runTask(plugin, () -> player.sendMessage(plugin.color("&cDu kannst nur deine eigenen Tickets bewerten.")));
return;
}
if (ticket.hasRating()) {
Bukkit.getScheduler().runTask(plugin, () -> player.sendMessage(plugin.color("&cDu hast dieses Ticket bereits bewertet.")));
return;
}
boolean success = plugin.getDatabaseManager().rateTicket(ticketId, finalRating);
Bukkit.getScheduler().runTask(plugin, () -> {
if (success) {
String emoji = "THUMBS_UP".equals(finalRating) ? "§a👍 Positiv" : "§c👎 Negativ";
player.sendMessage(plugin.color("&aDanke für deine Bewertung! (" + emoji + "§a)"));
} else {
player.sendMessage(plugin.color("&cBewertung konnte nicht gespeichert werden. Ticket geschlossen?"));
}
});
});
}
// ─────────────────────────── /ticket blacklist ─────────────────────────
private void handleBlacklist(Player player, String[] args) {
if (!player.hasPermission("ticket.admin")) {
player.sendMessage(plugin.formatMessage("messages.no-permission")); return;
}
if (args.length < 2) {
player.sendMessage(plugin.color("&cBenutzung: /ticket blacklist <add|remove|list> [Spieler] [Grund]"));
return;
}
switch (args[1].toLowerCase()) {
case "add" -> {
if (args.length < 3) { player.sendMessage(plugin.color("&cBenutzung: /ticket blacklist add <Spieler> [Grund]")); return; }
String targetName = args[2];
String reason = args.length > 3 ? String.join(" ", Arrays.copyOfRange(args, 3, args.length)) : "Missbrauch";
@SuppressWarnings("deprecation")
OfflinePlayer target = Bukkit.getOfflinePlayer(targetName);
if (target.getUniqueId() == null) { player.sendMessage(plugin.color("&cSpieler nicht gefunden.")); return; }
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
boolean success = plugin.getDatabaseManager().addBlacklist(
target.getUniqueId(), targetName, reason, player.getName());
Bukkit.getScheduler().runTask(plugin, () -> {
if (success)
player.sendMessage(plugin.color("&a" + targetName + " &awurde zur Ticket-Blacklist hinzugefügt. &7Grund: &e" + reason));
else
player.sendMessage(plugin.color("&cSpieler ist bereits auf der Blacklist."));
});
});
}
case "remove" -> {
if (args.length < 3) { player.sendMessage(plugin.color("&cBenutzung: /ticket blacklist remove <Spieler>")); return; }
String targetName = args[2];
@SuppressWarnings("deprecation")
OfflinePlayer target = Bukkit.getOfflinePlayer(targetName);
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
boolean success = plugin.getDatabaseManager().removeBlacklist(target.getUniqueId());
Bukkit.getScheduler().runTask(plugin, () -> {
if (success) player.sendMessage(plugin.color("&a" + targetName + " &awurde von der Blacklist entfernt."));
else player.sendMessage(plugin.color("&cSpieler war nicht auf der Blacklist."));
});
});
}
case "list" -> {
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
var list = plugin.getDatabaseManager().getBlacklist();
Bukkit.getScheduler().runTask(plugin, () -> {
player.sendMessage(plugin.color("&8&m "));
player.sendMessage(plugin.color("&6Ticket-Blacklist &7(" + list.size() + " Einträge)"));
player.sendMessage(plugin.color("&8&m "));
if (list.isEmpty()) {
player.sendMessage(plugin.color("&7Keine gesperrten Spieler."));
} else {
for (String[] entry : list) {
// {uuid, name, reason, bannedBy, bannedAt}
player.sendMessage(plugin.color("&e" + entry[1] + " &7 &f" + entry[2]
+ " &7(gesperrt von &e" + entry[3] + "&7)"));
}
}
player.sendMessage(plugin.color("&8&m "));
});
});
}
default -> player.sendMessage(plugin.color("&cBenutzung: /ticket blacklist <add|remove|list> [Spieler] [Grund]"));
}
}
// ─────────────────────────── /ticket reload ────────────────────────────
private void handleReload(Player player) {
if (!player.hasPermission("ticket.admin")) {
player.sendMessage(plugin.formatMessage("messages.no-permission"));
return;
}
if (!player.hasPermission("ticket.admin")) { player.sendMessage(plugin.formatMessage("messages.no-permission")); return; }
plugin.reloadConfig();
player.sendMessage(plugin.color("&aKonfiguration wurde neu geladen."));
plugin.getCategoryManager().reload();
player.sendMessage(plugin.color("&aKonfiguration wurde neu geladen. &7(inkl. Kategorien)"));
}
// ─────────────────────────── /ticket archive ───────────────────────────
private void handleArchive(Player player) {
if (!player.hasPermission("ticket.admin")) {
player.sendMessage(plugin.formatMessage("messages.no-permission"));
return;
}
if (!player.hasPermission("ticket.admin")) { player.sendMessage(plugin.formatMessage("messages.no-permission")); return; }
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
int count = plugin.getDatabaseManager().archiveClosedTickets();
Bukkit.getScheduler().runTask(plugin, () -> {
if (count > 0) {
player.sendMessage(plugin.formatMessage("messages.archive-success")
.replace("{count}", String.valueOf(count)));
} else {
player.sendMessage(plugin.formatMessage("messages.archive-fail"));
}
});
});
}
// ─────────────────────────── /ticket migrate ───────────────────────────
private void handleMigrate(Player player, String[] args) {
if (!player.hasPermission("ticket.admin")) {
player.sendMessage(plugin.formatMessage("messages.no-permission"));
return;
}
if (args.length < 2) {
player.sendMessage(plugin.color("&cBenutzung: /ticket migrate <tomysql|tofile>"));
return;
}
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
int migrated = 0;
String mode = args[1].toLowerCase();
if (mode.equals("tomysql")) migrated = plugin.getDatabaseManager().migrateToMySQL();
else if (mode.equals("tofile")) migrated = plugin.getDatabaseManager().migrateToFile();
else { player.sendMessage(plugin.formatMessage("messages.unknown-mode")); return; }
int finalMigrated = migrated;
Bukkit.getScheduler().runTask(plugin, () -> {
if (finalMigrated > 0) {
player.sendMessage(plugin.formatMessage("messages.migration-success")
.replace("{count}", String.valueOf(finalMigrated)));
} else {
player.sendMessage(plugin.formatMessage("messages.migration-fail"));
}
});
});
}
// ─────────────────────────── /ticket export ────────────────────────────
private void handleExport(Player player, String[] args) {
if (!player.hasPermission("ticket.admin")) {
player.sendMessage(plugin.formatMessage("messages.no-permission"));
return;
}
if (args.length < 2) {
player.sendMessage(plugin.color("&cBenutzung: /ticket export <Dateiname>"));
return;
}
String filename = args[1];
File exportFile = new File(plugin.getDataFolder(), filename);
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
int count = plugin.getDatabaseManager().exportTickets(exportFile);
Bukkit.getScheduler().runTask(plugin, () -> {
if (count > 0) {
player.sendMessage(plugin.formatMessage("messages.export-success")
.replace("{count}", String.valueOf(count)).replace("{file}", filename));
} else {
player.sendMessage(plugin.formatMessage("messages.export-fail"));
}
});
});
}
// ─────────────────────────── /ticket import ────────────────────────────
private void handleImport(Player player, String[] args) {
if (!player.hasPermission("ticket.admin")) {
player.sendMessage(plugin.formatMessage("messages.no-permission"));
return;
}
if (args.length < 2) {
player.sendMessage(plugin.color("&cBenutzung: /ticket import <Dateiname>"));
return;
}
String filename = args[1];
File importFile = new File(plugin.getDataFolder(), filename);
if (!importFile.exists()) {
player.sendMessage(plugin.formatMessage("messages.file-not-found").replace("{file}", filename));
return;
}
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
int count = plugin.getDatabaseManager().importTickets(importFile);
Bukkit.getScheduler().runTask(plugin, () -> {
if (count > 0) {
player.sendMessage(plugin.formatMessage("messages.import-success")
.replace("{count}", String.valueOf(count)));
} else {
player.sendMessage(plugin.formatMessage("messages.import-fail"));
}
if (count > 0) player.sendMessage(plugin.formatMessage("messages.archive-success").replace("{count}", String.valueOf(count)));
else player.sendMessage(plugin.formatMessage("messages.archive-fail"));
});
});
}
@@ -347,44 +506,190 @@ public class TicketCommand implements CommandExecutor, TabCompleter {
// ─────────────────────────── /ticket stats ─────────────────────────────
private void handleStats(Player player) {
if (!player.hasPermission("ticket.admin")) {
player.sendMessage(plugin.formatMessage("messages.no-permission"));
return;
}
if (!player.hasPermission("ticket.admin")) { player.sendMessage(plugin.formatMessage("messages.no-permission")); return; }
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
var stats = plugin.getDatabaseManager().getTicketStats();
Bukkit.getScheduler().runTask(plugin, () -> {
player.sendMessage(plugin.color("&6--- Ticket Statistik ---"));
player.sendMessage(plugin.color("&eGesamt: &a" + stats.total
+ " &7| &eOffen: &a" + stats.open
+ " &7| &eGeschlossen: &a" + stats.closed
+ " &7| &eWeitergeleitet: &a" + stats.forwarded));
player.sendMessage(plugin.color("&8&m "));
player.sendMessage(plugin.color("&6Ticket Statistik"));
player.sendMessage(plugin.color("&8&m "));
player.sendMessage(plugin.color("&eGesamt: &a" + stats.total));
player.sendMessage(plugin.color("&eOffen: &a" + stats.open));
player.sendMessage(plugin.color("&eGeschlossen: &a" + stats.closed));
player.sendMessage(plugin.color("&eWeitergeleitet: &a" + stats.forwarded));
if (plugin.getConfig().getBoolean("rating-enabled", true)) {
player.sendMessage(plugin.color("&8&m "));
player.sendMessage(plugin.color("&6Support-Bewertungen"));
player.sendMessage(plugin.color("&a👍 Positiv: &f" + stats.thumbsUp
+ " &c👎 Negativ: &f" + stats.thumbsDown));
int total = stats.thumbsUp + stats.thumbsDown;
if (total > 0) {
int percent = (int) Math.round(stats.thumbsUp * 100.0 / total);
player.sendMessage(plugin.color("&7Zufriedenheit: &e" + percent + "%"));
}
}
player.sendMessage(plugin.color("&8&m "));
player.sendMessage(plugin.color("&6Top Ersteller:"));
stats.byPlayer.entrySet().stream()
.sorted((a, b) -> b.getValue() - a.getValue())
.limit(5)
.forEach(e -> player.sendMessage(plugin.color("&e" + e.getKey() + ": &a" + e.getValue())));
.forEach(e -> player.sendMessage(plugin.color("&e " + e.getKey() + ": &a" + e.getValue())));
player.sendMessage(plugin.color("&8&m "));
});
});
}
// ─────────────────────────── /ticket migrate ───────────────────────────
private void handleMigrate(Player player, String[] args) {
if (!player.hasPermission("ticket.admin")) { player.sendMessage(plugin.formatMessage("messages.no-permission")); return; }
if (args.length < 2) { player.sendMessage(plugin.color("&cBenutzung: /ticket migrate <tomysql|tofile>")); return; }
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
int migrated = 0;
String mode = args[1].toLowerCase();
if (mode.equals("tomysql")) migrated = plugin.getDatabaseManager().migrateToMySQL();
else if (mode.equals("tofile")) migrated = plugin.getDatabaseManager().migrateToFile();
else { player.sendMessage(plugin.formatMessage("messages.unknown-mode")); return; }
int f = migrated;
Bukkit.getScheduler().runTask(plugin, () -> {
if (f > 0) player.sendMessage(plugin.formatMessage("messages.migration-success").replace("{count}", String.valueOf(f)));
else player.sendMessage(plugin.formatMessage("messages.migration-fail"));
});
});
}
// ─────────────────────────── /ticket export ────────────────────────────
private void handleExport(Player player, String[] args) {
if (!player.hasPermission("ticket.admin")) { player.sendMessage(plugin.formatMessage("messages.no-permission")); return; }
if (args.length < 2) { player.sendMessage(plugin.color("&cBenutzung: /ticket export <Dateiname>")); return; }
String filename = args[1];
File exportFile = new File(plugin.getDataFolder(), filename);
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
int count = plugin.getDatabaseManager().exportTickets(exportFile);
Bukkit.getScheduler().runTask(plugin, () -> {
if (count > 0) player.sendMessage(plugin.formatMessage("messages.export-success").replace("{count}", String.valueOf(count)).replace("{file}", filename));
else player.sendMessage(plugin.formatMessage("messages.export-fail"));
});
});
}
// ─────────────────────────── /ticket import ────────────────────────────
private void handleImport(Player player, String[] args) {
if (!player.hasPermission("ticket.admin")) { player.sendMessage(plugin.formatMessage("messages.no-permission")); return; }
if (args.length < 2) { player.sendMessage(plugin.color("&cBenutzung: /ticket import <Dateiname>")); return; }
String filename = args[1];
File importFile = new File(plugin.getDataFolder(), filename);
if (!importFile.exists()) { player.sendMessage(plugin.formatMessage("messages.file-not-found").replace("{file}", filename)); return; }
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
int count = plugin.getDatabaseManager().importTickets(importFile);
Bukkit.getScheduler().runTask(plugin, () -> {
if (count > 0) player.sendMessage(plugin.formatMessage("messages.import-success").replace("{count}", String.valueOf(count)));
else player.sendMessage(plugin.formatMessage("messages.import-fail"));
});
});
}
// ─────────────────────────── /ticket setpriority ──────────────────────
private void handleSetPriority(Player player, String[] args) {
if (!player.hasPermission("ticket.support") && !player.hasPermission("ticket.admin")) {
player.sendMessage(plugin.formatMessage("messages.no-permission")); return;
}
if (!plugin.getConfig().getBoolean("priorities-enabled", true)) {
player.sendMessage(plugin.color("&cDas Prioritäten-System ist deaktiviert.")); return;
}
if (args.length < 3) {
player.sendMessage(plugin.color("&cBenutzung: /ticket setpriority <ID> <low|normal|high|urgent>")); return;
}
int ticketId;
try { ticketId = Integer.parseInt(args[1]); }
catch (NumberFormatException e) {
player.sendMessage(plugin.color("&cUngültige Ticket-ID: &e" + args[1])); return;
}
TicketPriority priority = parsePriority(args[2]);
if (priority == null) {
player.sendMessage(plugin.color("&cUngültige Priorität! Gültig: &alow&7, &enormal&7, &6high&7, &curgent")); return;
}
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
boolean success = plugin.getDatabaseManager().setTicketPriority(ticketId, priority);
Bukkit.getScheduler().runTask(plugin, () -> {
if (success) {
player.sendMessage(plugin.color("&aPriorität von Ticket &e#" + ticketId
+ " &awurde auf " + priority.getColored() + " &agesetzt."));
} else {
player.sendMessage(plugin.color("&cTicket &e#" + ticketId + " &cwurde nicht gefunden."));
}
});
});
}
/** Parst Benutzer-Eingaben wie "high", "hoch", "urgent", "dringend" etc. zu TicketPriority.
* Gibt null zurück wenn keine Übereinstimmung. */
private TicketPriority parsePriority(String input) {
if (input == null) return null;
return switch (input.toLowerCase()) {
case "low", "niedrig" -> TicketPriority.LOW;
case "normal" -> TicketPriority.NORMAL;
case "high", "hoch" -> TicketPriority.HIGH;
case "urgent", "dringend" -> TicketPriority.URGENT;
default -> null;
};
}
// ─────────────────────────── Tab-Completion ────────────────────────────
@Override
public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) {
List<String> completions = new ArrayList<>();
if (!(sender instanceof Player player)) return completions;
if (args.length == 1) {
List<String> subs = new ArrayList<>(List.of("create", "list"));
List<String> subs = new ArrayList<>(List.of("create", "list", "comment"));
if (player.hasPermission("ticket.support") || player.hasPermission("ticket.admin"))
subs.addAll(List.of("claim", "close"));
if (plugin.getConfig().getBoolean("rating-enabled", true)) subs.add("rate");
if (player.hasPermission("ticket.admin"))
subs.addAll(List.of("forward", "reload", "stats", "archive", "migrate", "export", "import"));
for (String s : subs)
if (s.startsWith(args[0].toLowerCase())) completions.add(s);
subs.addAll(List.of("forward", "reload", "stats", "archive", "migrate", "export", "import", "blacklist"));
if ((player.hasPermission("ticket.support") || player.hasPermission("ticket.admin"))
&& plugin.getConfig().getBoolean("priorities-enabled", true))
subs.add("setpriority");
for (String s : subs) if (s.startsWith(args[0].toLowerCase())) completions.add(s);
} else if (args.length == 2 && args[0].equalsIgnoreCase("create")
&& plugin.getConfig().getBoolean("categories-enabled", true)) {
for (ConfigCategory c : plugin.getCategoryManager().getAll())
if (c.getKey().startsWith(args[1].toLowerCase())) completions.add(c.getKey());
// auch Priorität direkt ohne Kategorie anbieten
if (plugin.getConfig().getBoolean("priorities-enabled", true))
for (String p : List.of("low", "normal", "high", "urgent"))
if (p.startsWith(args[1].toLowerCase())) completions.add(p);
} else if (args.length == 3 && args[0].equalsIgnoreCase("create")
&& plugin.getConfig().getBoolean("priorities-enabled", true)) {
// Priorität nach Kategorie
for (String p : List.of("low", "normal", "high", "urgent"))
if (p.startsWith(args[2].toLowerCase())) completions.add(p);
} else if (args.length == 3 && args[0].equalsIgnoreCase("setpriority")) {
for (String p : List.of("low", "normal", "high", "urgent"))
if (p.startsWith(args[2].toLowerCase())) completions.add(p);
} else if (args.length == 3 && args[0].equalsIgnoreCase("forward")) {
for (Player p : Bukkit.getOnlinePlayers())
if (p.getName().toLowerCase().startsWith(args[2].toLowerCase())) completions.add(p.getName());
} else if (args.length == 2 && args[0].equalsIgnoreCase("blacklist")) {
completions.addAll(List.of("add", "remove", "list"));
} else if (args.length == 3 && args[0].equalsIgnoreCase("blacklist")
&& (args[1].equalsIgnoreCase("add") || args[1].equalsIgnoreCase("remove"))) {
for (Player p : Bukkit.getOnlinePlayers())
if (p.getName().toLowerCase().startsWith(args[2].toLowerCase())) completions.add(p.getName());
} else if (args.length == 3 && args[0].equalsIgnoreCase("rate")) {
completions.addAll(List.of("good", "bad"));
}
return completions;
}