From b87945352563a99aaf87d44090998075e86e200e Mon Sep 17 00:00:00 2001 From: Jose Rojo <6jarv91@gmail.com> Date: Tue, 9 Apr 2024 18:01:29 +0200 Subject: [PATCH 1/3] Message updated/deleted WIP --- cmd/jarvbot/commands.go | 4 +-- cmd/jarvbot/config.go | 5 ++++ cmd/jarvbot/main.go | 16 +++++++--- cmd/jarvbot/modding.go | 65 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 84 insertions(+), 6 deletions(-) diff --git a/cmd/jarvbot/commands.go b/cmd/jarvbot/commands.go index b94c5ff..8fb1a2b 100644 --- a/cmd/jarvbot/commands.go +++ b/cmd/jarvbot/commands.go @@ -226,7 +226,7 @@ func answerAddCommand(ds *discordgo.Session, mc *discordgo.MessageCreate, ctx co commandBody := commandPrefixRegex.ReplaceAllString(mc.Content, "") key := strings.TrimSpace(commandPrefixRegex.FindString(commandBody)) if key == "" { - ds.ChannelMessageSend(mc.ChannelID, errorMessage("Could not get the key from the command body")) + ds.ChannelMessageSend(mc.ChannelID, diff("Could not get the key from the command body", "- ")) return false } response := commandPrefixRegex.ReplaceAllString(commandBody, "") @@ -242,7 +242,7 @@ func answerAddGlobalCommand(ds *discordgo.Session, mc *discordgo.MessageCreate, commandBody := commandPrefixRegex.ReplaceAllString(mc.Content, "") key := strings.TrimSpace(commandPrefixRegex.FindString(commandBody)) if key == "" { - ds.ChannelMessageSend(mc.ChannelID, errorMessage("Could not get the key from the command body")) + ds.ChannelMessageSend(mc.ChannelID, diff("Could not get the key from the command body", "- ")) return false } response := commandPrefixRegex.ReplaceAllString(commandBody, "") diff --git a/cmd/jarvbot/config.go b/cmd/jarvbot/config.go index cd64682..e33e981 100644 --- a/cmd/jarvbot/config.go +++ b/cmd/jarvbot/config.go @@ -13,6 +13,11 @@ var warnMessageMinLength = 1 var warnMessageMaxLength = 320 const avatarTargetSize = "1024" +const maxMessageCount = 25 + +// https://discord.com/branding +const colorYellow = 0xFEE75C +const colorRed = 0xED4245 const serverPropCustomTimeoutRoleName = "custom_timeout_role_name" const serverPropAnnounceHere = "announce_here" diff --git a/cmd/jarvbot/main.go b/cmd/jarvbot/main.go index 25bd637..1810a24 100644 --- a/cmd/jarvbot/main.go +++ b/cmd/jarvbot/main.go @@ -6,6 +6,7 @@ import ( "log" "os" "os/signal" + "strings" "syscall" "github.com/bwmarrin/discordgo" @@ -75,6 +76,8 @@ func initDiscordSession() *discordgo.Session { backgroundCtx := context.Background() ds.AddHandler(onMessageCreated(backgroundCtx)) + ds.AddHandler(onMessageUpdated(backgroundCtx)) + ds.AddHandler(onMessageDeleted(backgroundCtx)) ds.AddHandler(onMessageReacted(backgroundCtx)) ds.AddHandler(onMessageUnreacted(backgroundCtx)) @@ -83,6 +86,7 @@ func initDiscordSession() *discordgo.Session { ds.Identify.Intents |= discordgo.IntentGuildMessages ds.Identify.Intents |= discordgo.IntentGuildMessageReactions ds.Identify.Intents |= discordgo.IntentDirectMessages + ds.State.MaxMessageCount = maxMessageCount // Open a websocket connection to Discord and begin listening. err = ds.Open() @@ -161,15 +165,19 @@ func initSlashCommands(ds *discordgo.Session) func() { } } -// for single line strings only! -func errorMessage(body string) string { - return "```diff\n- " + body + "\n```" +func diff(body, prefix string) string { + lines := strings.Split(body, "\n") + var formattedBody string + for _, line := range lines { + formattedBody += prefix + line + "\n" + } + return "```diff\n" + formattedBody + "```" } func notifyIfErr(context string, err error, ds *discordgo.Session) { if err != nil { msg := "ERROR [" + context + "]: " + err.Error() log.Println(msg) - sendDirectMessage(adminID, errorMessage(msg), ds) + sendDirectMessage(adminID, diff(msg, "- "), ds) } } diff --git a/cmd/jarvbot/modding.go b/cmd/jarvbot/modding.go index 57f65e2..634972c 100644 --- a/cmd/jarvbot/modding.go +++ b/cmd/jarvbot/modding.go @@ -8,6 +8,44 @@ import ( "github.com/bwmarrin/discordgo" ) +func onMessageDeleted(ctx context.Context) func(ds *discordgo.Session, mc *discordgo.MessageDelete) { + return func(ds *discordgo.Session, mc *discordgo.MessageDelete) { + if mc.BeforeDelete != nil { + ds.ChannelMessageSendEmbed( + mc.ChannelID, + &discordgo.MessageEmbed{ + Author: &discordgo.MessageEmbedAuthor{ + Name: mc.BeforeDelete.Author.Username, + IconURL: mc.BeforeDelete.Author.AvatarURL(""), + }, + Color: colorRed, + Title: "Message deleted", + Description: messageToString(mc.BeforeDelete), + }, + ) + } + } +} + +func onMessageUpdated(ctx context.Context) func(ds *discordgo.Session, mc *discordgo.MessageUpdate) { + return func(ds *discordgo.Session, mc *discordgo.MessageUpdate) { + if mc.BeforeUpdate != nil { + ds.ChannelMessageSendEmbed( + mc.ChannelID, + &discordgo.MessageEmbed{ + Author: &discordgo.MessageEmbedAuthor{ + Name: mc.Author.Username, + IconURL: mc.Author.AvatarURL(""), + }, + Color: colorYellow, + Title: "Message edited", + Description: messageUpdatedToString(mc.BeforeUpdate, mc.Message), + }, + ) + } + } +} + type UserWarning struct { ID int `db:"UserWarning"` UserID string `db:"DiscordUserID"` @@ -89,3 +127,30 @@ func answerWarnings(ds *discordgo.Session, ic *discordgo.InteractionCreate) { fileRespond(ds, ic, "Damn that user has been warned a lot", fmt.Sprintf("%s_warnings.txt", user.Username), responseMsg) } } + +func messageToString(m *discordgo.Message) string { + str := "In channel: <#" + m.ChannelID + ">" + if m.Author != nil { + str += "\nAuthor: " + m.Author.Mention() + } + if m.Content != "" { + str += "\nContent:\n" + m.Content + } + if m.Attachments != nil && len(m.Attachments) > 0 { + str += "\nAttachments:" + for _, a := range m.Attachments { + str += "\n" + a.URL + } + } + return str +} + +func messageUpdatedToString(from, to *discordgo.Message) string { + str := "In channel: <#" + from.ChannelID + ">" + if from.Author != nil { + str += "\nAuthor: " + from.Author.Mention() + } + str += diff(from.Content, "- ") + str += diff(to.Content, "+ ") + return str +} From 337bd278b3f7e39509d3b0ee05f8090f4cb417fb Mon Sep 17 00:00:00 2001 From: Jarv <6jarv91@gmail.com> Date: Tue, 9 Apr 2024 23:28:43 +0200 Subject: [PATCH 2/3] Message logs MVP --- cmd/jarvbot/commands.go | 36 ++++++++++++++++++++++++++++-------- cmd/jarvbot/config.go | 2 ++ cmd/jarvbot/modding.go | 23 ++++++++++++++++++----- 3 files changed, 48 insertions(+), 13 deletions(-) diff --git a/cmd/jarvbot/commands.go b/cmd/jarvbot/commands.go index 8fb1a2b..ad6d9bb 100644 --- a/cmd/jarvbot/commands.go +++ b/cmd/jarvbot/commands.go @@ -67,15 +67,16 @@ var commands = map[string]command{ "!sniper_shoot": notSpammable(answerSniperShoot), "!pp": notSpammable(answerPP), // only available for discord mods - "!roleids": modOnly(answerRoleIDs), - "!react4roles": modOnly(answerMakeReact4RolesMsg), - "!addcommand": modOnly(answerAddCommand), - "!removecommand": modOnly(answerRemoveCommand), + "!roleids": guildOnly((answerRoleIDs)), + "!react4roles": guildOnly((answerMakeReact4RolesMsg)), + "!addcommand": guildOnly((answerAddCommand)), + "!removecommand": guildOnly((answerRemoveCommand)), "!listcommands": modOnly(answerListCommands), - "!allowspamming": modOnly(answerAllowSpamming), - "!preventspamming": modOnly(answerPreventSpamming), - "!setcustomtimeoutrole": modOnly(answerSetCustomTimeoutRole), - "!announcehere": modOnly(answerAnnounceHere), + "!allowspamming": guildOnly(modOnly(answerAllowSpamming)), + "!preventspamming": guildOnly(modOnly(answerPreventSpamming)), + "!setcustomtimeoutrole": guildOnly(modOnly(answerSetCustomTimeoutRole)), + "!announcehere": guildOnly(modOnly(answerAnnounceHere)), + "!messagelogs": guildOnly(modOnly(answerMessageLogs)), // only available for the bot owner "!addglobalcommand": adminOnly(answerAddGlobalCommand), "!removeglobalcommand": adminOnly(answerRemoveGlobalCommand), @@ -220,6 +221,15 @@ func answerAnnounceHere(ds *discordgo.Session, mc *discordgo.MessageCreate, ctx return err == nil } +func answerMessageLogs(ds *discordgo.Session, mc *discordgo.MessageCreate, ctx context.Context) bool { + err := serverDS.setServerProperty(mc.GuildID, serverPropMessageLogs, mc.ChannelID) + notifyIfErr("answerMessageLogs", err, ds) + if err == nil { + ds.ChannelMessageSend(mc.ChannelID, "Okay! Will send message logs in this channel") + } + return err == nil +} + // ---------- Simple command stuff ---------- func answerAddCommand(ds *discordgo.Session, mc *discordgo.MessageCreate, ctx context.Context) bool { @@ -365,6 +375,16 @@ func modOnly(wrapped command) command { } } +func guildOnly(wrapped command) command { + return func(ds *discordgo.Session, mc *discordgo.MessageCreate, ctx context.Context) bool { + if mc.GuildID == globalGuildID { + ds.ChannelMessageSend(mc.ChannelID, notAGuildMessage) + return false + } + return wrapped(ds, mc, ctx) + } +} + func notSpammable(wrapped command) command { return func(ds *discordgo.Session, mc *discordgo.MessageCreate, ctx context.Context) bool { if !isAdmin(mc.Author.ID) { diff --git a/cmd/jarvbot/config.go b/cmd/jarvbot/config.go index e33e981..4c2341f 100644 --- a/cmd/jarvbot/config.go +++ b/cmd/jarvbot/config.go @@ -21,6 +21,7 @@ const colorRed = 0xED4245 const serverPropCustomTimeoutRoleName = "custom_timeout_role_name" const serverPropAnnounceHere = "announce_here" +const serverPropMessageLogs = "message_logs" const defaultTimeoutRoleName = "Shadow Realm" const shootMisfireChance = 0.2 @@ -43,6 +44,7 @@ const react4RolesCRON = "0 0 * * 6" // Messages const userMustBeAdminMessage = "Only the bot's admin can do that" const userMustBeModMessage = "Only a mod can do that" +const notAGuildMessage = "This command can only be used on a server" const commandReceivedMessage = "Gotcha!" const commandSuccessMessage = "Successfully donette!" const commandWithTwoArgumentsError = "Something went wrong, please make sure to use the command with the following format: '!command (...) (...)'" diff --git a/cmd/jarvbot/modding.go b/cmd/jarvbot/modding.go index 634972c..96a98d0 100644 --- a/cmd/jarvbot/modding.go +++ b/cmd/jarvbot/modding.go @@ -10,9 +10,18 @@ import ( func onMessageDeleted(ctx context.Context) func(ds *discordgo.Session, mc *discordgo.MessageDelete) { return func(ds *discordgo.Session, mc *discordgo.MessageDelete) { - if mc.BeforeDelete != nil { + if mc.BeforeDelete != nil && mc.BeforeDelete.Author != nil { + // dont mind if the bot messages get deleted + if mc.BeforeDelete.Author.ID == ds.State.User.ID { + return + } + + logsChannelID, err := serverDS.getServerProperty(mc.GuildID, serverPropMessageLogs) + if err != nil { + return + } ds.ChannelMessageSendEmbed( - mc.ChannelID, + logsChannelID, &discordgo.MessageEmbed{ Author: &discordgo.MessageEmbedAuthor{ Name: mc.BeforeDelete.Author.Username, @@ -29,9 +38,13 @@ func onMessageDeleted(ctx context.Context) func(ds *discordgo.Session, mc *disco func onMessageUpdated(ctx context.Context) func(ds *discordgo.Session, mc *discordgo.MessageUpdate) { return func(ds *discordgo.Session, mc *discordgo.MessageUpdate) { - if mc.BeforeUpdate != nil { + if mc.BeforeUpdate != nil && mc.Author != nil { + logsChannelID, err := serverDS.getServerProperty(mc.GuildID, serverPropMessageLogs) + if err != nil { + return + } ds.ChannelMessageSendEmbed( - mc.ChannelID, + logsChannelID, &discordgo.MessageEmbed{ Author: &discordgo.MessageEmbedAuthor{ Name: mc.Author.Username, @@ -134,7 +147,7 @@ func messageToString(m *discordgo.Message) string { str += "\nAuthor: " + m.Author.Mention() } if m.Content != "" { - str += "\nContent:\n" + m.Content + str += "```" + m.Content + "```" } if m.Attachments != nil && len(m.Attachments) > 0 { str += "\nAttachments:" From d444c026ada05983994163475247063d13c9a641 Mon Sep 17 00:00:00 2001 From: Jarv <6jarv91@gmail.com> Date: Tue, 9 Apr 2024 23:29:56 +0200 Subject: [PATCH 3/3] Version change --- cmd/jarvbot/commands.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/jarvbot/commands.go b/cmd/jarvbot/commands.go index ad6d9bb..51fe15d 100644 --- a/cmd/jarvbot/commands.go +++ b/cmd/jarvbot/commands.go @@ -45,7 +45,7 @@ func onMessageCreated(ctx context.Context) func(ds *discordgo.Session, mc *disco // the command key must be lowercased var commands = map[string]command{ // public - "!version": simpleTextResponse("v3.3.3"), + "!version": simpleTextResponse("v3.4.0"), "!source": simpleTextResponse("Source code: https://github.com/j4rv/discord-bot"), "!genshindailycheckin": answerGenshinDailyCheckIn, "!genshindailycheckinstop": answerGenshinDailyCheckInStop,