Delete src/main/java/net/viper/status/modules/forum/ForumBridgeModule.java via Git Manager GUI
This commit is contained in:
@@ -1,349 +0,0 @@
|
||||
package net.viper.status.modules.forum;
|
||||
|
||||
import net.viper.status.StatusAPI;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.viper.status.StatusAPI;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.viper.status.StatusAPI;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.viper.status.StatusAPI;
|
||||
import net.md_5.bungee.api.chat.ClickEvent;
|
||||
import net.viper.status.StatusAPI;
|
||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||
import net.viper.status.StatusAPI;
|
||||
import net.md_5.bungee.api.chat.HoverEvent;
|
||||
import net.viper.status.StatusAPI;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.viper.status.StatusAPI;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.viper.status.StatusAPI;
|
||||
import net.md_5.bungee.api.event.PostLoginEvent;
|
||||
import net.viper.status.StatusAPI;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
import net.viper.status.StatusAPI;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.viper.status.StatusAPI;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import net.viper.status.StatusAPI;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import net.viper.status.module.Module;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* ForumBridgeModule: Verbindet das WP Business Forum mit dem Minecraft-Server.
|
||||
*
|
||||
* Fix #13: extractJsonString() gibt jetzt immer einen leeren String statt null zurück.
|
||||
* Alle Aufrufer müssen nicht mehr auf null prüfen, was NullPointerExceptions verhindert.
|
||||
*/
|
||||
public class ForumBridgeModule implements Module, Listener {
|
||||
|
||||
private Plugin plugin;
|
||||
private ForumNotifStorage storage;
|
||||
|
||||
private boolean enabled = true;
|
||||
private String wpBaseUrl = "";
|
||||
private String apiSecret = "";
|
||||
private int loginDelaySeconds = 3;
|
||||
|
||||
@Override
|
||||
public String getName() { return "ForumBridgeModule"; }
|
||||
|
||||
@Override
|
||||
public void onEnable(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
loadConfig(plugin);
|
||||
if (!enabled) { StatusAPI.debugLog(plugin, "ForumBridgeModule ist deaktiviert."); return; }
|
||||
|
||||
storage = new ForumNotifStorage(plugin.getDataFolder(), plugin.getLogger());
|
||||
storage.load();
|
||||
|
||||
plugin.getProxy().getPluginManager().registerListener(plugin, this);
|
||||
ProxyServer.getInstance().getPluginManager().registerCommand(plugin, new ForumLinkCommand());
|
||||
ProxyServer.getInstance().getPluginManager().registerCommand(plugin, new ForumCommand());
|
||||
|
||||
plugin.getProxy().getScheduler().schedule(plugin, () -> {
|
||||
try { storage.save(); } catch (Exception e) { plugin.getLogger().warning("ForumBridge Auto-Save Fehler: " + e.getMessage()); }
|
||||
}, 10, 10, TimeUnit.MINUTES);
|
||||
|
||||
plugin.getProxy().getScheduler().schedule(plugin, () -> storage.purgeOld(30), 1, 24, TimeUnit.HOURS);
|
||||
plugin.getLogger().fine("ForumBridgeModule aktiviert.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable(Plugin plugin) {
|
||||
if (storage != null) { storage.save(); StatusAPI.debugLog(plugin, "Forum-Benachrichtigungen gespeichert."); }
|
||||
}
|
||||
|
||||
private void loadConfig(Plugin plugin) {
|
||||
try {
|
||||
Properties props = new Properties();
|
||||
File configFile = new File(plugin.getDataFolder(), "verify.properties");
|
||||
if (configFile.exists()) {
|
||||
try (FileInputStream fis = new FileInputStream(configFile)) { props.load(fis); }
|
||||
}
|
||||
this.enabled = !"false".equalsIgnoreCase(props.getProperty("forum.enabled", "true"));
|
||||
this.wpBaseUrl = props.getProperty("forum.wp_url", props.getProperty("wp_verify_url", ""));
|
||||
this.apiSecret = props.getProperty("forum.api_secret", "");
|
||||
this.loginDelaySeconds = parseInt(props.getProperty("forum.login_delay_seconds", "3"), 3);
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().warning("Fehler beim Laden der ForumBridge-Config: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private int parseInt(String s, int def) { try { return Integer.parseInt(s); } catch (Exception e) { return def; } }
|
||||
|
||||
// ===== HTTP HANDLER =====
|
||||
|
||||
public String handleNotify(String body, String apiKeyHeader) {
|
||||
if (!apiSecret.isEmpty() && !apiSecret.equals(apiKeyHeader)) {
|
||||
return "{\"success\":false,\"error\":\"unauthorized\"}";
|
||||
}
|
||||
|
||||
// FIX #13: extractJsonString gibt "" statt null → kein NullPointerException möglich
|
||||
String playerUuid = extractJsonString(body, "player_uuid");
|
||||
String type = extractJsonString(body, "type");
|
||||
String title = extractJsonString(body, "title");
|
||||
String author = extractJsonString(body, "author");
|
||||
String url = extractJsonString(body, "url");
|
||||
|
||||
if (playerUuid.isEmpty()) return "{\"success\":false,\"error\":\"missing_player_uuid\"}";
|
||||
|
||||
java.util.UUID uuid;
|
||||
try { uuid = java.util.UUID.fromString(playerUuid); }
|
||||
catch (Exception e) { return "{\"success\":false,\"error\":\"invalid_uuid\"}"; }
|
||||
|
||||
if ("thread".equalsIgnoreCase(type) && title.toLowerCase().contains("umfrage")) type = "poll";
|
||||
if (type.isEmpty()) type = "reply";
|
||||
|
||||
// Alle Werte sind garantiert nicht null (extractJsonString gibt "" zurück)
|
||||
ForumNotification notification = new ForumNotification(uuid, type, title, author, url);
|
||||
|
||||
ProxiedPlayer online = ProxyServer.getInstance().getPlayer(uuid);
|
||||
if (online != null && online.isConnected()) {
|
||||
deliverNotification(online, notification);
|
||||
notification.setDelivered(true);
|
||||
return "{\"success\":true,\"delivered\":true}";
|
||||
}
|
||||
|
||||
storage.add(notification);
|
||||
return "{\"success\":true,\"delivered\":false}";
|
||||
}
|
||||
|
||||
public String handleUnlink(String body, String apiKeyHeader) {
|
||||
if (!apiSecret.isEmpty() && !apiSecret.equals(apiKeyHeader)) return "{\"success\":false,\"error\":\"unauthorized\"}";
|
||||
return "{\"success\":true}";
|
||||
}
|
||||
|
||||
public String handleStatus() {
|
||||
String version = "unknown";
|
||||
try { if (plugin.getDescription() != null) version = plugin.getDescription().getVersion(); } catch (Exception ignored) {}
|
||||
return "{\"success\":true,\"module\":\"ForumBridgeModule\",\"version\":\"" + version + "\"}";
|
||||
}
|
||||
|
||||
// ===== NOTIFICATION =====
|
||||
|
||||
private void deliverNotification(ProxiedPlayer player, ForumNotification notif) {
|
||||
String color = notif.getTypeColor();
|
||||
String label = notif.getTypeLabel();
|
||||
player.sendMessage(new TextComponent("§8§m "));
|
||||
player.sendMessage(new TextComponent("§6§l✉ Forum §8» " + color + label));
|
||||
if (!notif.getTitle().isEmpty()) player.sendMessage(new TextComponent("§7 " + notif.getTitle()));
|
||||
if (!notif.getAuthor().isEmpty()) player.sendMessage(new TextComponent("§7 von §f" + notif.getAuthor()));
|
||||
if (!notif.getUrl().isEmpty()) {
|
||||
TextComponent link = new TextComponent("§a ➜ Im Forum ansehen");
|
||||
link.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, notif.getUrl()));
|
||||
link.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT,
|
||||
new ComponentBuilder("§7Klicke um den Beitrag im Forum zu öffnen").create()));
|
||||
player.sendMessage(link);
|
||||
}
|
||||
player.sendMessage(new TextComponent("§8§m "));
|
||||
}
|
||||
|
||||
private void deliverPending(ProxiedPlayer player) {
|
||||
List<ForumNotification> pending = storage.getPending(player.getUniqueId());
|
||||
if (pending.isEmpty()) return;
|
||||
int count = pending.size();
|
||||
if (count > 3) {
|
||||
player.sendMessage(new TextComponent("§8§m "));
|
||||
player.sendMessage(new TextComponent("§6§l✉ Forum §8» §fDu hast §e" + count + " §fneue Benachrichtigungen!"));
|
||||
player.sendMessage(new TextComponent("§7 Tippe §e/forum §7um sie anzuzeigen."));
|
||||
player.sendMessage(new TextComponent("§8§m "));
|
||||
} else {
|
||||
for (ForumNotification n : pending) deliverNotification(player, n);
|
||||
}
|
||||
storage.markAllDelivered(player.getUniqueId());
|
||||
storage.clearDelivered(player.getUniqueId());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onJoin(PostLoginEvent e) {
|
||||
ProxiedPlayer player = e.getPlayer();
|
||||
plugin.getProxy().getScheduler().schedule(plugin, () -> {
|
||||
if (player.isConnected()) deliverPending(player);
|
||||
}, loginDelaySeconds, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
// ===== COMMANDS =====
|
||||
|
||||
private class ForumLinkCommand extends Command {
|
||||
public ForumLinkCommand() { super("forumlink", null, "fl"); }
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args) {
|
||||
if (!(sender instanceof ProxiedPlayer)) { sender.sendMessage(new TextComponent("§cNur Spieler können diesen Befehl benutzen.")); return; }
|
||||
ProxiedPlayer p = (ProxiedPlayer) sender;
|
||||
if (args.length != 1) {
|
||||
p.sendMessage(new TextComponent("§eBenutzung: §f/forumlink <token>"));
|
||||
p.sendMessage(new TextComponent("§7Den Token erhältst du in deinem Forum-Profil unter §fMinecraft-Verknüpfung§7."));
|
||||
return;
|
||||
}
|
||||
String token = args[0].trim().toUpperCase();
|
||||
if (wpBaseUrl.isEmpty()) { p.sendMessage(new TextComponent("§cForum-Verknüpfung ist nicht konfiguriert.")); return; }
|
||||
p.sendMessage(new TextComponent("§7Überprüfe Token..."));
|
||||
|
||||
plugin.getProxy().getScheduler().runAsync(plugin, () -> {
|
||||
try {
|
||||
String endpoint = wpBaseUrl + "/wp-json/mc-bridge/v1/verify-link";
|
||||
String payload = "{\"token\":\"" + escapeJson(token) + "\","
|
||||
+ "\"mc_uuid\":\"" + p.getUniqueId() + "\","
|
||||
+ "\"mc_name\":\"" + escapeJson(p.getName()) + "\"}";
|
||||
|
||||
HttpURLConnection conn = (HttpURLConnection) new URL(endpoint).openConnection();
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setDoOutput(true);
|
||||
conn.setConnectTimeout(5000);
|
||||
conn.setReadTimeout(7000);
|
||||
conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
|
||||
if (!apiSecret.isEmpty()) conn.setRequestProperty("X-Api-Key", apiSecret);
|
||||
|
||||
Charset utf8 = Charset.forName("UTF-8");
|
||||
try (OutputStream os = conn.getOutputStream()) { os.write(payload.getBytes(utf8)); }
|
||||
|
||||
int code = conn.getResponseCode();
|
||||
String resp = code >= 200 && code < 300
|
||||
? streamToString(conn.getInputStream(), utf8)
|
||||
: streamToString(conn.getErrorStream(), utf8);
|
||||
|
||||
if (resp != null && resp.contains("\"success\":true")) {
|
||||
String displayName = extractJsonString(resp, "display_name");
|
||||
String username = extractJsonString(resp, "username");
|
||||
String show = !displayName.isEmpty() ? displayName : username;
|
||||
p.sendMessage(new TextComponent("§8§m "));
|
||||
p.sendMessage(new TextComponent("§a§l✓ §fForum-Account erfolgreich verknüpft!"));
|
||||
if (!show.isEmpty()) p.sendMessage(new TextComponent("§7 Forum-User: §f" + show));
|
||||
p.sendMessage(new TextComponent("§7 Du erhältst jetzt Ingame-Benachrichtigungen."));
|
||||
p.sendMessage(new TextComponent("§8§m "));
|
||||
} else {
|
||||
String error = extractJsonString(resp, "error");
|
||||
String message = extractJsonString(resp, "message");
|
||||
if ("token_expired".equals(error)) p.sendMessage(new TextComponent("§c✗ Der Token ist abgelaufen."));
|
||||
else if ("uuid_already_linked".equals(error)) p.sendMessage(new TextComponent("§c✗ " + (!message.isEmpty() ? message : "Diese UUID ist bereits verknüpft.")));
|
||||
else if ("invalid_token".equals(error)) p.sendMessage(new TextComponent("§c✗ Ungültiger Token."));
|
||||
else p.sendMessage(new TextComponent("§c✗ Verknüpfung fehlgeschlagen: " + (!error.isEmpty() ? error : "Unbekannter Fehler")));
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
p.sendMessage(new TextComponent("§c✗ Fehler bei der Verbindung zum Forum."));
|
||||
plugin.getLogger().warning("ForumLink Fehler: " + ex.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private class ForumCommand extends Command {
|
||||
public ForumCommand() { super("forum"); }
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args) {
|
||||
if (!(sender instanceof ProxiedPlayer)) { sender.sendMessage(new TextComponent("§cNur Spieler können diesen Befehl benutzen.")); return; }
|
||||
ProxiedPlayer p = (ProxiedPlayer) sender;
|
||||
List<ForumNotification> pending = storage.getPending(p.getUniqueId());
|
||||
|
||||
if (pending.isEmpty()) {
|
||||
p.sendMessage(new TextComponent("§7Keine neuen Forum-Benachrichtigungen."));
|
||||
if (!wpBaseUrl.isEmpty()) {
|
||||
TextComponent link = new TextComponent("§a➜ Forum öffnen");
|
||||
link.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, wpBaseUrl));
|
||||
link.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder("§7Klicke um das Forum zu öffnen").create()));
|
||||
p.sendMessage(link);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
p.sendMessage(new TextComponent("§8§m "));
|
||||
p.sendMessage(new TextComponent("§6§l✉ Forum-Benachrichtigungen §8(§f" + pending.size() + "§8)"));
|
||||
p.sendMessage(new TextComponent(""));
|
||||
int shown = 0;
|
||||
for (ForumNotification n : pending) {
|
||||
if (shown >= 10) { p.sendMessage(new TextComponent("§7 ... und " + (pending.size() - 10) + " weitere")); break; }
|
||||
String color = n.getTypeColor();
|
||||
TextComponent line = new TextComponent(color + " • " + n.getTypeLabel() + "§7: ");
|
||||
TextComponent detail = new TextComponent(!n.getTitle().isEmpty() ? "§f" + n.getTitle() : "§fvon " + n.getAuthor());
|
||||
if (!n.getUrl().isEmpty()) {
|
||||
detail.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, n.getUrl()));
|
||||
detail.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder("§7Klicke zum Öffnen").create()));
|
||||
}
|
||||
line.addExtra(detail);
|
||||
p.sendMessage(line);
|
||||
shown++;
|
||||
}
|
||||
p.sendMessage(new TextComponent(""));
|
||||
p.sendMessage(new TextComponent("§8§m "));
|
||||
storage.markAllDelivered(p.getUniqueId());
|
||||
storage.clearDelivered(p.getUniqueId());
|
||||
}
|
||||
}
|
||||
|
||||
// ===== HELPER =====
|
||||
|
||||
public ForumNotifStorage getStorage() { return storage; }
|
||||
|
||||
/**
|
||||
* FIX #13: Gibt immer einen leeren String zurück, niemals null.
|
||||
* Verhindert NullPointerExceptions in allen Aufrufern.
|
||||
*/
|
||||
private static String extractJsonString(String json, String key) {
|
||||
if (json == null || key == null) return "";
|
||||
String search = "\"" + key + "\"";
|
||||
int idx = json.indexOf(search);
|
||||
if (idx < 0) return "";
|
||||
int colon = json.indexOf(':', idx + search.length());
|
||||
if (colon < 0) return "";
|
||||
int i = colon + 1;
|
||||
while (i < json.length() && Character.isWhitespace(json.charAt(i))) i++;
|
||||
if (i >= json.length()) return "";
|
||||
char c = json.charAt(i);
|
||||
if (c == '"') {
|
||||
i++;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
boolean escape = false;
|
||||
while (i < json.length()) {
|
||||
char ch = json.charAt(i++);
|
||||
if (escape) { sb.append(ch); escape = false; }
|
||||
else { if (ch == '\\') escape = true; else if (ch == '"') break; else sb.append(ch); }
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private static String escapeJson(String s) {
|
||||
if (s == null) return "";
|
||||
return s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n").replace("\r", "\\r");
|
||||
}
|
||||
|
||||
private static String streamToString(InputStream in, Charset charset) throws IOException {
|
||||
if (in == null) return "";
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(in, charset))) {
|
||||
StringBuilder sb = new StringBuilder(); String line;
|
||||
while ((line = br.readLine()) != null) sb.append(line);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user