Skip to content

Commit d800336

Browse files
When a message link is included in a reason, render it as a saved message in the moderation log
1 parent b5cb05b commit d800336

7 files changed

Lines changed: 109 additions & 6 deletions

File tree

loritta-bot-discord/src/main/kotlin/net/perfectdreams/loritta/morenitta/commands/vanilla/administration/AdminUtils.kt

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import net.dv8tion.jda.api.EmbedBuilder
44
import net.dv8tion.jda.api.Permission
55
import net.dv8tion.jda.api.entities.*
66
import net.dv8tion.jda.api.components.buttons.ButtonStyle
7+
import net.dv8tion.jda.api.utils.FileUpload
78
import net.perfectdreams.loritta.cinnamon.discord.interactions.commands.styled
89
import net.perfectdreams.loritta.cinnamon.pudding.tables.servers.moduleconfigs.ModerationPunishmentMessagesConfig
910
import net.perfectdreams.loritta.cinnamon.pudding.tables.servers.moduleconfigs.WarnActions
@@ -24,11 +25,15 @@ import net.perfectdreams.loritta.morenitta.interactions.UnleashedContext
2425
import net.perfectdreams.loritta.morenitta.interactions.commands.LegacyMessageCommandContext
2526
import net.perfectdreams.loritta.morenitta.interactions.vanilla.moderation.BanCommand
2627
import net.perfectdreams.loritta.morenitta.messages.LorittaReply
28+
import net.perfectdreams.loritta.morenitta.messageverify.LoriMessageDataUtils
2729
import net.perfectdreams.loritta.morenitta.platform.discord.legacy.commands.DiscordCommandContext
2830
import net.perfectdreams.loritta.morenitta.platform.discord.legacy.entities.jda.JDAUser
2931
import net.perfectdreams.loritta.morenitta.utils.Constants
3032
import net.perfectdreams.loritta.morenitta.utils.DateUtils
3133
import net.perfectdreams.loritta.morenitta.utils.DiscordUtils
34+
import net.perfectdreams.loritta.morenitta.utils.extensions.await
35+
import net.perfectdreams.loritta.morenitta.utils.extensions.await
36+
import net.perfectdreams.loritta.morenitta.utils.extensions.getGuildMessageChannelById
3237
import net.perfectdreams.loritta.morenitta.utils.stripCodeMarks
3338
import net.perfectdreams.loritta.morenitta.utils.substringIfNeeded
3439
import org.jetbrains.exposed.sql.and
@@ -38,6 +43,7 @@ import java.time.Instant
3843

3944
object AdminUtils {
4045
private val LOCALE_PREFIX = "commands.category.moderation"
46+
val DISCORD_MESSAGE_LINK_REGEX = Regex("""https?://(?:(?:ptb|canary)\.)?discord\.com/channels/(\d+)/(\d+)/(\d+)""")
4147
val PUNISHMENT_EXAMPLES_KEY = LocaleKeyData("$LOCALE_PREFIX.punishmentExamples")
4248
val ROLE_TOO_LOW_KEY = LocaleKeyData("$LOCALE_PREFIX.roleTooLow")
4349
val ROLE_TOO_LOW_HOW_TO_FIX_KEY = LocaleKeyData("$LOCALE_PREFIX.roleTooLowHowToFix")
@@ -90,6 +96,44 @@ object AdminUtils {
9096
return warnActions
9197
}
9298

99+
/**
100+
* Parses Discord message links from the [reason] string, fetches the linked messages from the [guild],
101+
* renders them as signed images, and returns them as [FileUpload]s ready to be attached to messages.
102+
*
103+
* Only messages from the same [guild] are processed. Messages that are inaccessible or already deleted are skipped.
104+
*/
105+
suspend fun renderLinkedMessagesFromReason(loritta: LorittaBot, guild: Guild, requester: Member, reason: String): List<FileUpload> {
106+
val fileUploads = mutableListOf<FileUpload>()
107+
val discordMessageLinks = DISCORD_MESSAGE_LINK_REGEX.findAll(reason)
108+
109+
for (match in discordMessageLinks) {
110+
val linkGuildId = match.groupValues[1].toLongOrNull() ?: continue
111+
val linkChannelId = match.groupValues[2].toLongOrNull() ?: continue
112+
val linkMessageId = match.groupValues[3].toLongOrNull() ?: continue
113+
114+
// Only process messages from the same guild
115+
if (linkGuildId != guild.idLong) continue
116+
117+
try {
118+
val channel = guild.getGuildMessageChannelById(linkChannelId) ?: continue
119+
120+
// Could the user be able to access it?
121+
if (!requester.hasPermission(channel, Permission.VIEW_CHANNEL))
122+
continue
123+
124+
val linkedMessage = channel.retrieveMessageById(linkMessageId).await()
125+
val savedMessage = LoriMessageDataUtils.convertMessageToSavedMessage(linkedMessage)
126+
val renderedImage = LoriMessageDataUtils.createSignedRenderedSavedMessage(loritta, savedMessage, true)
127+
val fileName = LoriMessageDataUtils.createFileNameForSavedMessageImage(savedMessage)
128+
fileUploads.add(FileUpload.fromData(renderedImage, fileName))
129+
} catch (e: Exception) {
130+
// Message might not be accessible or already deleted, skip
131+
}
132+
}
133+
134+
return fileUploads
135+
}
136+
93137
@Deprecated("Please use InteraKTions Unleashed")
94138
suspend fun checkAndRetrieveAllValidUsersFromMessages(context: CommandContext): UserMatchesResult? {
95139
val split = context.rawArgs

loritta-bot-discord/src/main/kotlin/net/perfectdreams/loritta/morenitta/commands/vanilla/administration/BanCommand.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import net.perfectdreams.loritta.i18n.I18nKeysData
1313
import net.perfectdreams.loritta.morenitta.LorittaBot
1414
import net.perfectdreams.loritta.morenitta.utils.MessageUtils
1515
import net.perfectdreams.loritta.morenitta.utils.extensions.getGuildMessageChannelById
16+
import net.perfectdreams.loritta.morenitta.utils.extensions.retrieveMemberOrNull
1617
import java.util.concurrent.TimeUnit
1718

1819
class BanCommand {
@@ -58,7 +59,18 @@ class BanCommand {
5859
generationErrorMessageI18nKey = I18nKeysData.InvalidMessages.MemberModerationBan
5960
)
6061

61-
textChannel.sendMessage(message).queue()
62+
runBlocking {
63+
val punisherMember = guild.retrieveMemberOrNull(punisher)
64+
val linkedMessageImages = if (punisherMember != null)
65+
AdminUtils.renderLinkedMessagesFromReason(loritta, guild, punisherMember, reason)
66+
else emptyList()
67+
68+
val sendAction = textChannel.sendMessage(message)
69+
if (linkedMessageImages.isNotEmpty()) {
70+
sendAction.addFiles(linkedMessageImages)
71+
}
72+
sendAction.queue()
73+
}
6274
}
6375
}
6476
}

loritta-bot-discord/src/main/kotlin/net/perfectdreams/loritta/morenitta/commands/vanilla/administration/KickCommand.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import net.perfectdreams.loritta.i18n.I18nKeysData
1313
import net.perfectdreams.loritta.morenitta.LorittaBot
1414
import net.perfectdreams.loritta.morenitta.utils.MessageUtils
1515
import net.perfectdreams.loritta.morenitta.utils.extensions.getGuildMessageChannelById
16+
import net.perfectdreams.loritta.morenitta.utils.extensions.retrieveMemberOrNull
1617

1718
class KickCommand {
1819
companion object {
@@ -57,7 +58,18 @@ class KickCommand {
5758
)
5859

5960
message?.let {
60-
textChannel.sendMessage(it).queue()
61+
runBlocking {
62+
val punisherMember = guild.retrieveMemberOrNull(punisher)
63+
val linkedMessageImages = if (punisherMember != null)
64+
AdminUtils.renderLinkedMessagesFromReason(loritta, guild, punisherMember, reason)
65+
else emptyList()
66+
67+
val sendAction = textChannel.sendMessage(it)
68+
if (linkedMessageImages.isNotEmpty()) {
69+
sendAction.addFiles(linkedMessageImages)
70+
}
71+
sendAction.queue()
72+
}
6173
}
6274
}
6375
}

loritta-bot-discord/src/main/kotlin/net/perfectdreams/loritta/morenitta/commands/vanilla/administration/MuteCommand.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,13 @@ class MuteCommand {
115115
I18nKeysData.InvalidMessages.MemberModerationMute
116116
)
117117

118-
textChannel.sendMessage(message).queue()
118+
val linkedMessageImages = AdminUtils.renderLinkedMessagesFromReason(context.loritta, context.guild, context.member, reason)
119+
120+
val sendAction = textChannel.sendMessage(message)
121+
if (linkedMessageImages.isNotEmpty()) {
122+
sendAction.addFiles(linkedMessageImages)
123+
}
124+
sendAction.queue()
119125
}
120126
}
121127
}

loritta-bot-discord/src/main/kotlin/net/perfectdreams/loritta/morenitta/commands/vanilla/administration/UnbanCommand.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import net.perfectdreams.loritta.i18n.I18nKeysData
1111
import net.perfectdreams.loritta.morenitta.LorittaBot
1212
import net.perfectdreams.loritta.morenitta.utils.MessageUtils
1313
import net.perfectdreams.loritta.morenitta.utils.extensions.getGuildMessageChannelById
14+
import net.perfectdreams.loritta.morenitta.utils.extensions.retrieveMemberOrNull
1415

1516
class UnbanCommand {
1617
companion object {
@@ -43,7 +44,18 @@ class UnbanCommand {
4344
generationErrorMessageI18nKey = I18nKeysData.InvalidMessages.MemberModerationUnban
4445
)
4546

46-
textChannel.sendMessage(message).queue()
47+
runBlocking {
48+
val punisherMember = guild.retrieveMemberOrNull(punisher)
49+
val linkedMessageImages = if (punisherMember != null)
50+
AdminUtils.renderLinkedMessagesFromReason(loritta, guild, punisherMember, reason)
51+
else emptyList()
52+
53+
val sendAction = textChannel.sendMessage(message)
54+
if (linkedMessageImages.isNotEmpty()) {
55+
sendAction.addFiles(linkedMessageImages)
56+
}
57+
sendAction.queue()
58+
}
4759
}
4860
}
4961
}

loritta-bot-discord/src/main/kotlin/net/perfectdreams/loritta/morenitta/commands/vanilla/administration/UnmuteCommand.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,18 @@ class UnmuteCommand {
4646
generationErrorMessageI18nKey = I18nKeysData.InvalidMessages.MemberModerationUnmute
4747
)
4848

49-
textChannel.sendMessage(message).queue()
49+
runBlocking {
50+
val punisherMember = guild.retrieveMemberOrNull(punisher)
51+
val linkedMessageImages = if (punisherMember != null)
52+
AdminUtils.renderLinkedMessagesFromReason(loritta, guild, punisherMember, reason)
53+
else emptyList()
54+
55+
val sendAction = textChannel.sendMessage(message)
56+
if (linkedMessageImages.isNotEmpty()) {
57+
sendAction.addFiles(linkedMessageImages)
58+
}
59+
sendAction.queue()
60+
}
5061
}
5162
}
5263
}

loritta-bot-discord/src/main/kotlin/net/perfectdreams/loritta/morenitta/interactions/vanilla/moderation/WarnCommand.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,13 @@ class WarnCommand(val loritta: LorittaBot) : SlashCommandDeclarationWrapper {
128128
generationErrorMessageI18nKey = I18nKeysData.InvalidMessages.MemberModerationWarn
129129
)
130130

131-
textChannel.sendMessage(message).queue()
131+
val linkedMessageImages = AdminUtils.renderLinkedMessagesFromReason(context.loritta, context.guild, context.member, reason)
132+
133+
val sendAction = textChannel.sendMessage(message)
134+
if (linkedMessageImages.isNotEmpty()) {
135+
sendAction.addFiles(linkedMessageImages)
136+
}
137+
sendAction.queue()
132138
}
133139
}
134140
}

0 commit comments

Comments
 (0)