From 19557bcb9c6533349ea9f97abd0f262fb7cc8564 Mon Sep 17 00:00:00 2001 From: Duncan Casteleyn <10881109+DuncanCasteleyn@users.noreply.github.com> Date: Sat, 8 Aug 2026 14:53:02 +0200 Subject: [PATCH 1/3] feat(logging): configure attachment cache channel --- README.md | 10 ++++--- .../logging/AttachmentCacheProperties.kt | 12 +++++++++ .../logging/AttachmentProxyCreator.kt | 6 ++--- .../logging/AttachmentCachePropertiesTest.kt | 27 +++++++++++++++++++ 4 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 src/main/kotlin/be/duncanc/discordmodbot/logging/AttachmentCacheProperties.kt create mode 100644 src/test/kotlin/be/duncanc/discordmodbot/logging/AttachmentCachePropertiesTest.kt diff --git a/README.md b/README.md index 6865834c..e191d442 100644 --- a/README.md +++ b/README.md @@ -18,10 +18,11 @@ For environment variables, convert property names to uppercase and replace `.`/` These are bound from `discord-mod-bot.*` and the application will fail to start if they are missing. -| Property | Environment Variable | Required | Description | -|-----------------------------|-----------------------------|----------|------------------------------------------------------------------| -| `discord-mod-bot.owner-id` | `DISCORD_MOD_BOT_OWNER_ID` | Yes | Discord user ID for the bot owner (used for owner-only actions). | -| `discord-mod-bot.bot-token` | `DISCORD_MOD_BOT_BOT_TOKEN` | Yes | Discord bot token used to connect to the Discord gateway. | +| Property | Environment Variable | Required | Description | +|-------------------------------------------|----------------------------------------------|----------|------------------------------------------------------------------| +| `discord-mod-bot.owner-id` | `DISCORD_MOD_BOT_OWNER_ID` | Yes | Discord user ID for the bot owner (used for owner-only actions). | +| `discord-mod-bot.bot-token` | `DISCORD_MOD_BOT_BOT_TOKEN` | Yes | Discord bot token used to connect to the Discord gateway. | +| `discord-mod-bot.attachment-cache.channel-id` | `DISCORD_MOD_BOT_ATTACHMENT_CACHE_CHANNEL_ID` | Yes | Discord text channel used to cache attachments. | ### Default runtime properties @@ -44,6 +45,7 @@ These defaults are defined in `src/main/resources/application.properties`. ```bash export DISCORD_MOD_BOT_OWNER_ID=123456789012345678 export DISCORD_MOD_BOT_BOT_TOKEN=your-token-here +export DISCORD_MOD_BOT_ATTACHMENT_CACHE_CHANNEL_ID=310006048595509248 export SPRING_DATASOURCE_URL=jdbc:mariadb://127.0.0.1:3306/discordmodbot export SPRING_DATASOURCE_USERNAME=spring export SPRING_DATASOURCE_PASSWORD=test diff --git a/src/main/kotlin/be/duncanc/discordmodbot/logging/AttachmentCacheProperties.kt b/src/main/kotlin/be/duncanc/discordmodbot/logging/AttachmentCacheProperties.kt new file mode 100644 index 00000000..fa2b0c03 --- /dev/null +++ b/src/main/kotlin/be/duncanc/discordmodbot/logging/AttachmentCacheProperties.kt @@ -0,0 +1,12 @@ +package be.duncanc.discordmodbot.logging + +import jakarta.validation.constraints.Positive +import org.springframework.boot.context.properties.ConfigurationProperties +import org.springframework.validation.annotation.Validated + +@ConfigurationProperties("discord-mod-bot.attachment-cache") +@Validated +class AttachmentCacheProperties( + @field:Positive + val channelId: Long = throw IllegalStateException("attachment cache channel ID not configured") +) diff --git a/src/main/kotlin/be/duncanc/discordmodbot/logging/AttachmentProxyCreator.kt b/src/main/kotlin/be/duncanc/discordmodbot/logging/AttachmentProxyCreator.kt index d848928c..0f084632 100644 --- a/src/main/kotlin/be/duncanc/discordmodbot/logging/AttachmentProxyCreator.kt +++ b/src/main/kotlin/be/duncanc/discordmodbot/logging/AttachmentProxyCreator.kt @@ -21,10 +21,10 @@ import java.util.concurrent.TimeUnit */ @Component class AttachmentProxyCreator( - private val attachmentProxyRepository: AttachmentProxyRepository + private val attachmentProxyRepository: AttachmentProxyRepository, + private val attachmentCacheProperties: AttachmentCacheProperties ) { companion object { - private const val CACHE_CHANNEL = 310006048595509248L private val LOG = LoggerFactory.getLogger(AttachmentProxyCreator::class.java) } @@ -57,7 +57,7 @@ class AttachmentProxyCreator( val outputStream = ByteArrayOutputStream() IOUtils.copy(inputStream, outputStream) - event.jda.getTextChannelById(CACHE_CHANNEL) + event.jda.getTextChannelById(attachmentCacheProperties.channelId) ?.sendFiles( FileUpload.fromData(outputStream.toByteArray(), attachment.fileName) ) diff --git a/src/test/kotlin/be/duncanc/discordmodbot/logging/AttachmentCachePropertiesTest.kt b/src/test/kotlin/be/duncanc/discordmodbot/logging/AttachmentCachePropertiesTest.kt new file mode 100644 index 00000000..970489f3 --- /dev/null +++ b/src/test/kotlin/be/duncanc/discordmodbot/logging/AttachmentCachePropertiesTest.kt @@ -0,0 +1,27 @@ +package be.duncanc.discordmodbot.logging + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import org.springframework.boot.context.properties.EnableConfigurationProperties +import org.springframework.boot.test.context.runner.ApplicationContextRunner +import org.springframework.context.annotation.Configuration + +class AttachmentCachePropertiesTest { + + private val contextRunner = ApplicationContextRunner() + .withUserConfiguration(AttachmentCachePropertiesConfiguration::class.java) + + @Test + fun `custom channel ID is bound from properties`() { + contextRunner + .withPropertyValues("discord-mod-bot.attachment-cache.channel-id=123456789012345678") + .run { context -> + val properties = context.getBean(AttachmentCacheProperties::class.java) + assertEquals(123456789012345678L, properties.channelId) + } + } + + @Configuration + @EnableConfigurationProperties(AttachmentCacheProperties::class) + class AttachmentCachePropertiesConfiguration +} From fb15a63bf64b06c984d5c90496ca1a5c8a1d3699 Mon Sep 17 00:00:00 2001 From: Duncan Casteleyn <10881109+DuncanCasteleyn@users.noreply.github.com> Date: Sun, 16 Aug 2026 14:53:10 +0200 Subject: [PATCH 2/3] fix: resolve failure logging issue --- .../logging/AttachmentProxyCreator.kt | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/main/kotlin/be/duncanc/discordmodbot/logging/AttachmentProxyCreator.kt b/src/main/kotlin/be/duncanc/discordmodbot/logging/AttachmentProxyCreator.kt index 0f084632..77811595 100644 --- a/src/main/kotlin/be/duncanc/discordmodbot/logging/AttachmentProxyCreator.kt +++ b/src/main/kotlin/be/duncanc/discordmodbot/logging/AttachmentProxyCreator.kt @@ -57,21 +57,29 @@ class AttachmentProxyCreator( val outputStream = ByteArrayOutputStream() IOUtils.copy(inputStream, outputStream) - event.jda.getTextChannelById(attachmentCacheProperties.channelId) - ?.sendFiles( + val channel = event.jda.getTextChannelById(attachmentCacheProperties.channelId) + if (channel == null) { + LOG.error( + "The configured attachment cache channel could not be found: {}", + attachmentCacheProperties.channelId + ) + hadFailures = true + } else { + channel.sendFiles( FileUpload.fromData(outputStream.toByteArray(), attachment.fileName) ) - ?.addContent(originalMessage.jumpUrl) - ?.map { message -> - message.attachments.map { messageAttachment -> - "[${messageAttachment.fileName}](${messageAttachment.url})" + .addContent(originalMessage.jumpUrl) + .map { message -> + message.attachments.map { messageAttachment -> + "[${messageAttachment.fileName}](${messageAttachment.url})" + } + } + .submit() + .get(30, TimeUnit.SECONDS) + .let { + attachments.addAll(it) } - } - ?.submit() - ?.get(30, TimeUnit.SECONDS) - ?.let { - attachments.addAll(it) - } + } } } else { LOG.warn("The file was larger than 8MB.") From 432daf97168cae06cb530d3c73907658a919b2ae Mon Sep 17 00:00:00 2001 From: Duncan Casteleyn <10881109+DuncanCasteleyn@users.noreply.github.com> Date: Sun, 16 Aug 2026 15:16:16 +0200 Subject: [PATCH 3/3] fix(logging): resolve attachment cache channel before downloads --- .../logging/AttachmentProxyCreator.kt | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/main/kotlin/be/duncanc/discordmodbot/logging/AttachmentProxyCreator.kt b/src/main/kotlin/be/duncanc/discordmodbot/logging/AttachmentProxyCreator.kt index 77811595..707f2cc8 100644 --- a/src/main/kotlin/be/duncanc/discordmodbot/logging/AttachmentProxyCreator.kt +++ b/src/main/kotlin/be/duncanc/discordmodbot/logging/AttachmentProxyCreator.kt @@ -50,21 +50,21 @@ class AttachmentProxyCreator( var hadFailures = false val originalMessage = event.message - originalMessage.attachments.forEach { attachment -> - try { - if (attachment.size < 8 shl 20) { //8MB - attachment.proxy.download().get(30, TimeUnit.SECONDS).let { inputStream: InputStream -> - val outputStream = ByteArrayOutputStream() - IOUtils.copy(inputStream, outputStream) + val channel = event.jda.getTextChannelById(attachmentCacheProperties.channelId) + if (channel == null) { + LOG.error( + "The configured attachment cache channel could not be found: {}", + attachmentCacheProperties.channelId + ) + hadFailures = true + } else { + originalMessage.attachments.forEach { attachment -> + try { + if (attachment.size < 8 shl 20) { //8MB + attachment.proxy.download().get(30, TimeUnit.SECONDS).let { inputStream: InputStream -> + val outputStream = ByteArrayOutputStream() + IOUtils.copy(inputStream, outputStream) - val channel = event.jda.getTextChannelById(attachmentCacheProperties.channelId) - if (channel == null) { - LOG.error( - "The configured attachment cache channel could not be found: {}", - attachmentCacheProperties.channelId - ) - hadFailures = true - } else { channel.sendFiles( FileUpload.fromData(outputStream.toByteArray(), attachment.fileName) ) @@ -80,14 +80,14 @@ class AttachmentProxyCreator( attachments.addAll(it) } } + } else { + LOG.warn("The file was larger than 8MB.") + hadFailures = true } - } else { - LOG.warn("The file was larger than 8MB.") + } catch (e: Exception) { + LOG.info("An exception occurred when retrieving one of the attachments", e) hadFailures = true } - } catch (e: Exception) { - LOG.info("An exception occurred when retrieving one of the attachments", e) - hadFailures = true } } val attachmentProxy = when {