From a49affb44e43c4a707074ab64173f72094b10f7c Mon Sep 17 00:00:00 2001 From: itqop Date: Sat, 18 Oct 2025 19:16:09 +0300 Subject: [PATCH] 6 --- .../itqop/whitelist/WhitelistApiClient.java | 131 +++++++++++++++--- .../itqop/whitelist/WhitelistCommands.java | 23 +-- 2 files changed, 127 insertions(+), 27 deletions(-) diff --git a/src/main/java/org/itqop/whitelist/WhitelistApiClient.java b/src/main/java/org/itqop/whitelist/WhitelistApiClient.java index c4c0cff..5be2b6f 100644 --- a/src/main/java/org/itqop/whitelist/WhitelistApiClient.java +++ b/src/main/java/org/itqop/whitelist/WhitelistApiClient.java @@ -1,9 +1,6 @@ package org.itqop.whitelist; -import com.google.gson.Gson; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; +import com.google.gson.*; import com.mojang.logging.LogUtils; import org.slf4j.Logger; @@ -13,6 +10,7 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.time.Duration; import java.time.Instant; +import java.util.List; import java.util.Objects; import java.util.concurrent.CompletableFuture; @@ -22,7 +20,7 @@ public class WhitelistApiClient { public static void refreshConfigFromSpec() { INSTANCE.refreshFromConfig(); } private static final Logger LOGGER = LogUtils.getLogger(); - private static final Gson GSON = new Gson(); + private static final Gson GSON = new GsonBuilder().create(); private volatile HttpClient http; private volatile String baseUrl; @@ -58,45 +56,69 @@ public class WhitelistApiClient { return addPlayer(playerName, null, null, null); } - public CompletableFuture addPlayer(String playerName, String playerUuid, String addedBy, String addedAt) { + public CompletableFuture addPlayer(String playerName, String playerUuid, String addedBy, String addedAtIso) { Objects.requireNonNull(playerName, "playerName"); - if (Config.enableLogging) LOGGER.info("[ADD] player={}", playerName); JsonObject body = new JsonObject(); body.addProperty("player_name", playerName); if (playerUuid != null && !playerUuid.isBlank()) body.addProperty("player_uuid", playerUuid); if (addedBy != null && !addedBy.isBlank()) body.addProperty("added_by", addedBy); - if (addedAt != null && !addedAt.isBlank()) body.addProperty("added_at", addedAt); + if (addedAtIso != null && !addedAtIso.isBlank()) body.addProperty("added_at", addedAtIso); return makeRequest("POST", "/add", HttpRequest.BodyPublishers.ofString(GSON.toJson(body))) - .thenApply(resp -> resp != null && resp.statusCode() / 100 == 2); + .thenApply(resp -> resp != null && resp.statusCode() == 201); + } + + public CompletableFuture addPlayer(String playerName, + String playerUuid, + String addedBy, + Instant addedAt, + Instant expiresAt, + Boolean isActive, + String reason) { + Objects.requireNonNull(playerName, "playerName"); + JsonObject body = new JsonObject(); + body.addProperty("player_name", playerName); + if (playerUuid != null && !playerUuid.isBlank()) body.addProperty("player_uuid", playerUuid); + if (addedBy != null && !addedBy.isBlank()) body.addProperty("added_by", addedBy); + if (addedAt != null) body.addProperty("added_at", addedAt.toString()); + if (expiresAt != null) body.addProperty("expires_at", expiresAt.toString()); + if (isActive != null) body.addProperty("is_active", isActive); + if (reason != null && !reason.isBlank()) body.addProperty("reason", reason); + return makeRequest("POST", "/add", HttpRequest.BodyPublishers.ofString(GSON.toJson(body))) + .thenApply(resp -> { + if (resp == null || resp.statusCode() != 201) return null; + try { + JsonObject json = JsonParser.parseString(resp.body()).getAsJsonObject(); + return WhitelistEntry.fromJson(json); + } catch (Exception e) { + return null; + } + }); } public CompletableFuture removePlayer(String playerName) { Objects.requireNonNull(playerName, "playerName"); - if (Config.enableLogging) LOGGER.info("[REMOVE] player={}", playerName); JsonObject body = new JsonObject(); body.addProperty("player_name", playerName); return makeRequest("POST", "/remove", HttpRequest.BodyPublishers.ofString(GSON.toJson(body))) - .thenApply(resp -> resp != null && resp.statusCode() / 100 == 2); + .thenApply(resp -> resp != null && resp.statusCode() == 204); } public CompletableFuture checkPlayer(String playerName) { Objects.requireNonNull(playerName, "playerName"); - if (Config.enableLogging) LOGGER.info("[CHECK] player={}", playerName); JsonObject body = new JsonObject(); body.addProperty("player_name", playerName); return makeRequest("POST", "/check", HttpRequest.BodyPublishers.ofString(GSON.toJson(body))) .thenApply(response -> { if (response == null) return new CheckResponse(false, false, null); try { - String bodyStr = response.body(); - JsonElement el = JsonParser.parseString(bodyStr); - JsonObject json = el.getAsJsonObject(); - boolean ok = json.has("ok") && json.get("ok").getAsBoolean(); + int code = response.statusCode(); + if (code < 200 || code >= 300) return new CheckResponse(false, false, null); + JsonObject json = JsonParser.parseString(response.body()).getAsJsonObject(); boolean isWhitelisted = json.has("is_whitelisted") && json.get("is_whitelisted").getAsBoolean(); String uuid = json.has("player_uuid") && !json.get("player_uuid").isJsonNull() ? json.get("player_uuid").getAsString() : null; - return new CheckResponse(ok, isWhitelisted, uuid); + return new CheckResponse(true, isWhitelisted, uuid); } catch (Exception e) { return new CheckResponse(false, false, null); } @@ -104,6 +126,38 @@ public class WhitelistApiClient { .exceptionally(ex -> new CheckResponse(false, false, null)); } + public CompletableFuture listAll() { + return makeRequest("GET", "/", HttpRequest.BodyPublishers.noBody()) + .thenApply(resp -> { + if (resp == null) return null; + try { + JsonObject json = JsonParser.parseString(resp.body()).getAsJsonObject(); + JsonArray arr = json.getAsJsonArray("entries"); + int total = json.has("total") ? json.get("total").getAsInt() : 0; + WhitelistEntry[] entries = new WhitelistEntry[arr.size()]; + for (int i = 0; i < arr.size(); i++) { + entries[i] = WhitelistEntry.fromJson(arr.get(i).getAsJsonObject()); + } + return new WhitelistListResponse(List.of(entries), total); + } catch (Exception e) { + return null; + } + }); + } + + public CompletableFuture count() { + return makeRequest("GET", "/count", HttpRequest.BodyPublishers.noBody()) + .thenApply(resp -> { + if (resp == null) return null; + try { + JsonObject json = JsonParser.parseString(resp.body()).getAsJsonObject(); + return json.has("total") ? json.get("total").getAsInt() : 0; + } catch (Exception e) { + return null; + } + }); + } + private CompletableFuture> makeRequest(String method, String path, HttpRequest.BodyPublisher body) { HttpRequest.Builder b = baseBuilder(path); if ("POST".equalsIgnoreCase(method)) b.POST(body); @@ -126,4 +180,47 @@ public class WhitelistApiClient { public boolean isWhitelisted() { return isWhitelisted; } public String getPlayerUuid() { return playerUuid; } } + + public static final class WhitelistEntry { + public final String id; + public final String playerName; + public final String playerUuid; + public final String addedBy; + public final String addedAt; + public final String expiresAt; + public final boolean isActive; + public final String reason; + + public WhitelistEntry(String id, String playerName, String playerUuid, String addedBy, String addedAt, String expiresAt, boolean isActive, String reason) { + this.id = id; + this.playerName = playerName; + this.playerUuid = playerUuid; + this.addedBy = addedBy; + this.addedAt = addedAt; + this.expiresAt = expiresAt; + this.isActive = isActive; + this.reason = reason; + } + + public static WhitelistEntry fromJson(JsonObject json) { + String id = json.has("id") && !json.get("id").isJsonNull() ? json.get("id").getAsString() : null; + String pn = json.has("player_name") && !json.get("player_name").isJsonNull() ? json.get("player_name").getAsString() : null; + String pu = json.has("player_uuid") && !json.get("player_uuid").isJsonNull() ? json.get("player_uuid").getAsString() : null; + String by = json.has("added_by") && !json.get("added_by").isJsonNull() ? json.get("added_by").getAsString() : null; + String at = json.has("added_at") && !json.get("added_at").isJsonNull() ? json.get("added_at").getAsString() : null; + String exp = json.has("expires_at") && !json.get("expires_at").isJsonNull() ? json.get("expires_at").getAsString() : null; + boolean active = json.has("is_active") && !json.get("is_active").isJsonNull() && json.get("is_active").getAsBoolean(); + String rsn = json.has("reason") && !json.get("reason").isJsonNull() ? json.get("reason").getAsString() : null; + return new WhitelistEntry(id, pn, pu, by, at, exp, active, rsn); + } + } + + public static final class WhitelistListResponse { + public final List entries; + public final int total; + public WhitelistListResponse(List entries, int total) { + this.entries = entries; + this.total = total; + } + } } diff --git a/src/main/java/org/itqop/whitelist/WhitelistCommands.java b/src/main/java/org/itqop/whitelist/WhitelistCommands.java index 537271c..597d971 100644 --- a/src/main/java/org/itqop/whitelist/WhitelistCommands.java +++ b/src/main/java/org/itqop/whitelist/WhitelistCommands.java @@ -19,7 +19,7 @@ import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; public class WhitelistCommands { - private static final WhitelistApiClient API = new WhitelistApiClient(); + private static final WhitelistApiClient API = WhitelistApiClient.get(); private static final SuggestionProvider ONLINE_PLAYER_SUGGESTIONS = (ctx, builder) -> { List names = ctx.getSource().getServer().getPlayerList().getPlayers() @@ -79,21 +79,24 @@ public class WhitelistCommands { private static int addPlayer(CommandContext ctx) { String player = StringArgumentType.getString(ctx, "player"); - String input = ctx.getInput(); String reason = null; - int idx = input.indexOf(" add "); - if (idx >= 0) { - String tail = input.substring(idx + 5); - int sp = tail.indexOf(' '); - if (sp >= 0) reason = tail.substring(sp + 1).trim(); - } + try { + reason = StringArgumentType.getString(ctx, "reason"); + if (reason != null && reason.isBlank()) reason = null; + } catch (IllegalArgumentException ignored) {} + String addedBy = getSourceName(ctx); String addedAt = Instant.now().toString(); String uuid = resolveUuid(ctx.getSource().getServer(), player); + sendOnServer(ctx, Component.literal("Adding player to whitelist: " + player), false); - API.addPlayer(player, uuid, addedBy, addedAt).thenAccept(success -> + + CompletableFuture fut = + API.addPlayer(player, uuid, addedBy, Instant.parse(addedAt), null, true, reason); + + fut.thenAccept(entry -> dispatchBack(ctx, () -> { - if (success) { + if (entry != null) { ctx.getSource().sendSuccess(() -> Component.literal("Player " + player + " added"), false); } else { ctx.getSource().sendFailure(Component.literal("Failed to add " + player));