Add logging configuration endpoints for guilds
Introduced `/guilds/config/{guildId}`, `/guilds/debug/{guildId}`, `/guilds/logging/{guildId}`, and `/guilds/log-channel/{guildId}` endpoints to manage guild-level logging settings via API. Updated `GuildService` with methods for handling debug, logging mode, and log channel configuration. Integrated new routes into `GuildRoutes` and updated OpenAPI schemas with corresponding DTOs.
This commit is contained in:
1 parent
0f96051fd0
commit
88298380f8
6 files changed
+208
-5
No files matched your search
@@ -83,6 +83,31 @@ public class GuildService {
|
||||
this.oGuild = guildRepository.save(current);
|
||||
}
|
||||
|
||||
public boolean isLoggingEnabled() {
|
||||
return oGuild.getLogging();
|
||||
}
|
||||
|
||||
public void updateLoggingMode(boolean logging) {
|
||||
OGuild current = findOrCreateGuild(guildId);
|
||||
current.setLogging(logging);
|
||||
this.oGuild = guildRepository.save(current);
|
||||
}
|
||||
|
||||
public String getLogChannel() {
|
||||
return oGuild.getLogChannel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets (or clears, when {@code logChannel} is {@code null}/blank) the guild's log channel id.
|
||||
*
|
||||
* @param logChannel the Discord channel id to log to, or {@code null}/blank to clear it
|
||||
*/
|
||||
public void updateLogChannel(String logChannel) {
|
||||
OGuild current = findOrCreateGuild(guildId);
|
||||
current.setLogChannel(logChannel == null || logChannel.isBlank() ? null : logChannel);
|
||||
this.oGuild = guildRepository.save(current);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mirrors the guild's name/icon into the database so they survive JDA cache eviction. Only
|
||||
* writes when a value actually changed, to avoid needless updates on every event.
|
||||
|
||||
@@ -7,20 +7,29 @@ package me.bobert.netneutrality.http.server;
|
||||
*/
|
||||
|
||||
import io.javalin.config.RoutesConfig;
|
||||
import io.javalin.http.BadRequestResponse;
|
||||
import io.javalin.http.Context;
|
||||
import io.javalin.http.NotFoundResponse;
|
||||
import io.javalin.http.ServiceUnavailableResponse;
|
||||
import io.javalin.openapi.HttpMethod;
|
||||
import io.javalin.openapi.OpenApi;
|
||||
import io.javalin.openapi.OpenApiContent;
|
||||
import io.javalin.openapi.OpenApiParam;
|
||||
import io.javalin.openapi.OpenApiRequestBody;
|
||||
import io.javalin.openapi.OpenApiResponse;
|
||||
import me.bobert.netneutrality.db.service.GuildService;
|
||||
import me.bobert.netneutrality.db.service.GuildServiceProvider;
|
||||
import me.bobert.netneutrality.http.server.dto.ChannelSummaryResponse;
|
||||
import me.bobert.netneutrality.http.server.dto.ErrorResponse;
|
||||
import me.bobert.netneutrality.http.server.dto.GuildBooleanUpdateRequest;
|
||||
import me.bobert.netneutrality.http.server.dto.GuildConfigResponse;
|
||||
import me.bobert.netneutrality.http.server.dto.GuildLogChannelUpdateRequest;
|
||||
import me.bobert.netneutrality.http.server.dto.GuildOwnerEntryResponse;
|
||||
import me.bobert.netneutrality.http.server.dto.GuildSummaryResponse;
|
||||
import me.bobert.netneutrality.http.server.dto.MemberRolesResponse;
|
||||
import me.bobert.netneutrality.http.server.dto.MemberSummaryResponse;
|
||||
import me.bobert.netneutrality.http.server.dto.OwnerResponse;
|
||||
import me.bobert.netneutrality.http.server.dto.RoleSummaryResponse;
|
||||
import me.bobert.netneutrality.http.server.dto.VoiceChannelSummaryResponse;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
@@ -34,14 +43,15 @@ import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Registers the read-only {@code /guilds/*} endpoints on a {@link RoutesConfig} instance.
|
||||
* Registers the read-only {@code /guilds/*} endpoints, as well as the debug/logging/log-channel
|
||||
* configuration endpoints, on a {@link RoutesConfig} instance.
|
||||
*/
|
||||
public final class GuildRoutes {
|
||||
|
||||
private GuildRoutes() {
|
||||
}
|
||||
|
||||
public static void register(RoutesConfig routes, Supplier<JDA> jdaSupplier) {
|
||||
public static void register(RoutesConfig routes, Supplier<JDA> jdaSupplier, GuildServiceProvider guildServices) {
|
||||
routes.get("/guilds", ctx -> guilds(jdaSupplier, ctx));
|
||||
routes.get("/guilds/owner", ctx -> owner(jdaSupplier, ctx));
|
||||
routes.get("/guilds/owner/{guildId}", ctx -> ownerOf(jdaSupplier, ctx));
|
||||
@@ -51,6 +61,10 @@ public final class GuildRoutes {
|
||||
routes.get("/guilds/members/{guildId}/{userId}/roles", ctx -> memberRoles(jdaSupplier, ctx));
|
||||
routes.get("/guilds/voice-channels/{guildId}", ctx -> voiceChannels(jdaSupplier, ctx));
|
||||
routes.get("/guilds/voice-channels/{guildId}/{channelId}", ctx -> voiceChannel(jdaSupplier, ctx));
|
||||
routes.get("/guilds/config/{guildId}", ctx -> config(jdaSupplier, guildServices, ctx));
|
||||
routes.put("/guilds/debug/{guildId}", ctx -> updateDebug(jdaSupplier, guildServices, ctx));
|
||||
routes.put("/guilds/logging/{guildId}", ctx -> updateLogging(jdaSupplier, guildServices, ctx));
|
||||
routes.put("/guilds/log-channel/{guildId}", ctx -> updateLogChannel(jdaSupplier, guildServices, ctx));
|
||||
}
|
||||
|
||||
@OpenApi(
|
||||
@@ -156,14 +170,15 @@ public final class GuildRoutes {
|
||||
tags = {"Guilds"},
|
||||
pathParams = @io.javalin.openapi.OpenApiParam(name = "guildId", description = "The Discord guild id"),
|
||||
responses = {
|
||||
@OpenApiResponse(status = "200", content = @OpenApiContent(from = ChannelSummaryResponse[].class)),
|
||||
@OpenApiResponse(status = "200", content = @OpenApiContent(from = RoleSummaryResponse[].class)),
|
||||
@OpenApiResponse(status = "404", content = @OpenApiContent(from = ErrorResponse.class))
|
||||
}
|
||||
)
|
||||
private static void roles(Supplier<JDA> jdaSupplier, Context ctx) {
|
||||
ctx.json(
|
||||
guild(jdaSupplier, ctx).getRoles().stream()
|
||||
.map(role -> ordered("channel_id", role.getId(), "channel_name", role.getName()))
|
||||
.filter(role -> !role.isManaged())
|
||||
.map(role -> ordered("role_id", role.getId(), "role_name", role.getName()))
|
||||
.toList()
|
||||
);
|
||||
}
|
||||
@@ -330,6 +345,119 @@ public final class GuildRoutes {
|
||||
return map;
|
||||
}
|
||||
|
||||
@OpenApi(
|
||||
path = "/guilds/config/{guildId}",
|
||||
methods = HttpMethod.GET,
|
||||
summary = "Get a guild's debug/logging configuration",
|
||||
tags = {"Guilds"},
|
||||
pathParams = @OpenApiParam(name = "guildId", description = "The Discord guild id"),
|
||||
responses = {
|
||||
@OpenApiResponse(status = "200", content = @OpenApiContent(from = GuildConfigResponse.class)),
|
||||
@OpenApiResponse(status = "404", content = @OpenApiContent(from = ErrorResponse.class))
|
||||
}
|
||||
)
|
||||
private static void config(Supplier<JDA> jdaSupplier, GuildServiceProvider guildServices, Context ctx) {
|
||||
Guild guild = guild(jdaSupplier, ctx);
|
||||
ctx.json(guildConfig(guild, guildServices));
|
||||
}
|
||||
|
||||
@OpenApi(
|
||||
path = "/guilds/debug/{guildId}",
|
||||
methods = HttpMethod.PUT,
|
||||
summary = "Enable or disable debug/error logging for a guild",
|
||||
tags = {"Guilds"},
|
||||
pathParams = @OpenApiParam(name = "guildId", description = "The Discord guild id"),
|
||||
requestBody = @OpenApiRequestBody(content = @OpenApiContent(from = GuildBooleanUpdateRequest.class)),
|
||||
responses = {
|
||||
@OpenApiResponse(status = "200", content = @OpenApiContent(from = GuildConfigResponse.class)),
|
||||
@OpenApiResponse(status = "400", content = @OpenApiContent(from = ErrorResponse.class)),
|
||||
@OpenApiResponse(status = "404", content = @OpenApiContent(from = ErrorResponse.class))
|
||||
}
|
||||
)
|
||||
private static void updateDebug(Supplier<JDA> jdaSupplier, GuildServiceProvider guildServices, Context ctx) {
|
||||
Guild guild = guild(jdaSupplier, ctx);
|
||||
boolean value = booleanValue(ctx);
|
||||
|
||||
GuildService guildService = guildServices.get(guild.getId());
|
||||
guildService.updateDebugMode(value);
|
||||
|
||||
ctx.json(guildConfig(guild, guildServices));
|
||||
}
|
||||
|
||||
@OpenApi(
|
||||
path = "/guilds/logging/{guildId}",
|
||||
methods = HttpMethod.PUT,
|
||||
summary = "Enable or disable logging for a guild",
|
||||
tags = {"Guilds"},
|
||||
pathParams = @OpenApiParam(name = "guildId", description = "The Discord guild id"),
|
||||
requestBody = @OpenApiRequestBody(content = @OpenApiContent(from = GuildBooleanUpdateRequest.class)),
|
||||
responses = {
|
||||
@OpenApiResponse(status = "200", content = @OpenApiContent(from = GuildConfigResponse.class)),
|
||||
@OpenApiResponse(status = "400", content = @OpenApiContent(from = ErrorResponse.class)),
|
||||
@OpenApiResponse(status = "404", content = @OpenApiContent(from = ErrorResponse.class))
|
||||
}
|
||||
)
|
||||
private static void updateLogging(Supplier<JDA> jdaSupplier, GuildServiceProvider guildServices, Context ctx) {
|
||||
Guild guild = guild(jdaSupplier, ctx);
|
||||
boolean value = booleanValue(ctx);
|
||||
|
||||
GuildService guildService = guildServices.get(guild.getId());
|
||||
guildService.updateLoggingMode(value);
|
||||
|
||||
ctx.json(guildConfig(guild, guildServices));
|
||||
}
|
||||
|
||||
@OpenApi(
|
||||
path = "/guilds/log-channel/{guildId}",
|
||||
methods = HttpMethod.PUT,
|
||||
summary = "Set (or clear) the log channel for a guild",
|
||||
tags = {"Guilds"},
|
||||
pathParams = @OpenApiParam(name = "guildId", description = "The Discord guild id"),
|
||||
requestBody = @OpenApiRequestBody(content = @OpenApiContent(from = GuildLogChannelUpdateRequest.class)),
|
||||
responses = {
|
||||
@OpenApiResponse(status = "200", content = @OpenApiContent(from = GuildConfigResponse.class)),
|
||||
@OpenApiResponse(status = "400", content = @OpenApiContent(from = ErrorResponse.class)),
|
||||
@OpenApiResponse(status = "404", content = @OpenApiContent(from = ErrorResponse.class))
|
||||
}
|
||||
)
|
||||
private static void updateLogChannel(Supplier<JDA> jdaSupplier, GuildServiceProvider guildServices, Context ctx) {
|
||||
Guild guild = guild(jdaSupplier, ctx);
|
||||
String channelId = ctx.bodyAsClass(Map.class).get("value") instanceof String s ? s : null;
|
||||
|
||||
if (channelId != null && !channelId.isBlank() && guild.getTextChannelById(channelId) == null) {
|
||||
throw new BadRequestResponse("Unknown text channel: " + channelId);
|
||||
}
|
||||
|
||||
GuildService guildService = guildServices.get(guild.getId());
|
||||
guildService.updateLogChannel(channelId);
|
||||
|
||||
ctx.json(guildConfig(guild, guildServices));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the {@code value} field of a JSON request body as a boolean, or fails with 400.
|
||||
*/
|
||||
private static boolean booleanValue(Context ctx) {
|
||||
Object value = ctx.bodyAsClass(Map.class).get("value");
|
||||
if (value instanceof Boolean b) {
|
||||
return b;
|
||||
}
|
||||
throw new BadRequestResponse("value must be a boolean");
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the {@code /guilds/config/{guildId}} response for a guild's current configuration.
|
||||
*/
|
||||
private static GuildConfigResponse guildConfig(Guild guild, GuildServiceProvider guildServices) {
|
||||
GuildService guildService = guildServices.get(guild.getId());
|
||||
return new GuildConfigResponse(
|
||||
guild.getId(),
|
||||
guildService.isDebugEnabled(),
|
||||
guildService.isLoggingEnabled(),
|
||||
guildService.getLogChannel()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the JDA client or fails with 503 while it is not ready yet.
|
||||
*/
|
||||
|
||||
@@ -77,7 +77,7 @@ public class WebApi implements Lifecycle {
|
||||
config.routes.before(new ApiKeyFilter(settings));
|
||||
|
||||
config.routes.get("/", ctx -> ctx.html(LIVENESS_HTML));
|
||||
GuildRoutes.register(config.routes, jdaSupplier);
|
||||
GuildRoutes.register(config.routes, jdaSupplier, guildServices);
|
||||
ActionRoutes.register(config.routes, jdaSupplier, shutdownHook);
|
||||
SettingsRoutes.register(config.routes, jdaSupplier, guildServices);
|
||||
StatsRoutes.register(config.routes, jdaSupplier, guildServices);
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package me.bobert.netneutrality.http.server.dto;
|
||||
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
/**
|
||||
* OpenAPI schema for the {@code /guilds/debug/{guildId}} and {@code /guilds/logging/{guildId}}
|
||||
* request bodies.
|
||||
*/
|
||||
public record GuildBooleanUpdateRequest(
|
||||
boolean value
|
||||
) {
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package me.bobert.netneutrality.http.server.dto;
|
||||
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
/**
|
||||
* OpenAPI schema for the {@code /guilds/config/{guildId}} response, as well as the
|
||||
* debug/logging/log-channel update responses.
|
||||
*/
|
||||
public record GuildConfigResponse(
|
||||
String guild_id,
|
||||
boolean debug,
|
||||
boolean logging,
|
||||
String log_channel
|
||||
) {
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package me.bobert.netneutrality.http.server.dto;
|
||||
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
/**
|
||||
* OpenAPI schema for the {@code /guilds/log-channel/{guildId}} request body.
|
||||
*/
|
||||
public record GuildLogChannelUpdateRequest(
|
||||
String value
|
||||
) {
|
||||
}
|
||||
Reference in new issue
Block a user