diff --git a/bot/functions.go b/bot/functions.go index ed23036..cd122fd 100644 --- a/bot/functions.go +++ b/bot/functions.go @@ -25,7 +25,7 @@ const ( // calls go-archiver with a []string of URLs parsed from the message. // It then returns an embed with the resulting archived URLs, func (bot *ArchiverBot) handleArchiveRequest(r *discordgo.MessageReactionAdd, newSnapshot bool) ( - embeds []*discordgo.MessageEmbed, errs []error) { + messagesToSend []*discordgo.MessageSend, errs []error) { typingStop := make(chan bool, 1) go bot.typeInChannel(typingStop, r.ChannelID) @@ -33,9 +33,13 @@ func (bot *ArchiverBot) handleArchiveRequest(r *discordgo.MessageReactionAdd, ne // If true, this is a DM if r.GuildID == "" { typingStop <- true - return []*discordgo.MessageEmbed{ + return []*discordgo.MessageSend{ { - Description: "Use `/archive` or the `Get snapshot` menu item on the message instead of adding a reaction.", + Embeds: []*discordgo.MessageEmbed{ + { + Description: "Use `/archive` or the `Get snapshot` menu item on the message instead of adding a reaction.", + }, + }, }, }, errs } @@ -44,20 +48,20 @@ func (bot *ArchiverBot) handleArchiveRequest(r *discordgo.MessageReactionAdd, ne if sc.ArchiveEnabled.Valid && !sc.ArchiveEnabled.Bool { log.Info("URLs were not archived because automatic archive is not enabled") typingStop <- true - return embeds, errs + return messagesToSend, errs } // Do a lookup for the full guild object guild, gErr := bot.DG.Guild(r.GuildID) if gErr != nil { typingStop <- true - return embeds, []error{fmt.Errorf("unable to look up server by id: %v", r.GuildID)} + return messagesToSend, []error{fmt.Errorf("unable to look up server by id: %v", r.GuildID)} } message, err := bot.DG.ChannelMessage(r.ChannelID, r.MessageID) if err != nil { typingStop <- true - return embeds, []error{fmt.Errorf("unable to look up message by id: %v", r.MessageID)} + return messagesToSend, []error{fmt.Errorf("unable to look up message by id: %v", r.MessageID)} } originalUrl := message.Content @@ -71,7 +75,7 @@ func (bot *ArchiverBot) handleArchiveRequest(r *discordgo.MessageReactionAdd, ne // If the URL still has 'web.archive.org', then we failed to ge the original URL fail, _ := regexp.MatchString(archiveDomain, originalUrl) if fail { - return embeds, errs + return messagesToSend, errs } // The suffix turned out to be a real URL @@ -110,7 +114,7 @@ func (bot *ArchiverBot) handleArchiveRequest(r *discordgo.MessageReactionAdd, ne } } - embeds, errs = bot.buildArchiveReply(archivedLinks, messageUrls, sc) + messagesToSend, errs = bot.buildArchiveReply(archivedLinks, messageUrls, sc) // Create a call to Archiver API event tx := bot.DB.Create(&ArchiveEventEvent{ @@ -128,21 +132,25 @@ func (bot *ArchiverBot) handleArchiveRequest(r *discordgo.MessageReactionAdd, ne } typingStop <- true - return embeds, errs + return messagesToSend, errs } // handleArchiveCommand takes a discordgo.InteractionCreate and // calls go-archiver with a []string of URLs parsed from the message. // It then returns an embed with the resulting archived URLs, func (bot *ArchiverBot) handleArchiveCommand(i *discordgo.InteractionCreate) ( - embeds []*discordgo.MessageEmbed, errs []error) { + messagesToSend []*discordgo.MessageSend, errs []error) { message := &discordgo.Message{} var archives []ArchiveEvent commandInput := i.Interaction.ApplicationCommandData() if len(commandInput.Options) > 1 { - embeds = append(embeds, &discordgo.MessageEmbed{ - Title: "Too many options submitted", + messagesToSend = append(messagesToSend, &discordgo.MessageSend{ + Embeds: []*discordgo.MessageEmbed{ + { + Title: "Too many options submitted", + }, + }, }) } else { messageUrls, errs := bot.extractMessageUrls(commandInput.Options[0].StringValue()) @@ -180,7 +188,7 @@ func (bot *ArchiverBot) handleArchiveCommand(i *discordgo.InteractionCreate) ( } } - embeds, errs = bot.buildArchiveReply(archivedLinks, messageUrls, sc) + messagesToSend, errs = bot.buildArchiveReply(archivedLinks, messageUrls, sc) for _, err := range errs { if err != nil { @@ -207,21 +215,25 @@ func (bot *ArchiverBot) handleArchiveCommand(i *discordgo.InteractionCreate) ( } } - return embeds, errs + return messagesToSend, errs } // handleArchiveMessage takes a discordgo.InteractionCreate and // calls go-archiver with a []string of URLs parsed from the message. // It then returns an embed with the resulting archived URLs, func (bot *ArchiverBot) handleArchiveMessage(i *discordgo.InteractionCreate) ( - embeds []*discordgo.MessageEmbed, errs []error) { + messagesToSend []*discordgo.MessageSend, errs []error) { message := &discordgo.Message{} var archives []ArchiveEvent commandData := i.Interaction.ApplicationCommandData() if len(commandData.Options) > 1 { - embeds = append(embeds, &discordgo.MessageEmbed{ - Title: "Too many options submitted", + messagesToSend = append(messagesToSend, &discordgo.MessageSend{ + Embeds: []*discordgo.MessageEmbed{ + { + Title: "Too many options submitted", + }, + }, }) } else { for _, message := range commandData.Resolved.Messages { @@ -260,7 +272,7 @@ func (bot *ArchiverBot) handleArchiveMessage(i *discordgo.InteractionCreate) ( } } - embeds, errs = bot.buildArchiveReply(archivedLinks, messageUrls, sc) + messagesToSend, errs = bot.buildArchiveReply(archivedLinks, messageUrls, sc) for _, err := range errs { if err != nil { @@ -288,7 +300,7 @@ func (bot *ArchiverBot) handleArchiveMessage(i *discordgo.InteractionCreate) ( } } - return embeds, errs + return messagesToSend, errs } // extractMessageUrls takes a string and returns a slice of URLs parsed from the string @@ -399,7 +411,20 @@ func (bot *ArchiverBot) executeArchiveEventRequest(archiveEvents *[]ArchiveEvent } // executeArchiveRequest takes a slice of ArchiveEvents and returns a slice of strings of successfully archived links -func (bot *ArchiverBot) buildArchiveReply(archivedLinks []string, messageUrls []string, sc ServerConfig) (embeds []*discordgo.MessageEmbed, errs []error) { +func (bot *ArchiverBot) buildArchiveReply(archivedLinks []string, messageUrls []string, sc ServerConfig) (messagesToSend []*discordgo.MessageSend, errs []error) { + var embeds []*discordgo.MessageEmbed + + components := []discordgo.MessageComponent{ + discordgo.ActionsRow{ + Components: []discordgo.MessageComponent{ + discordgo.Button{ + Label: "Request new snapshot", + Style: discordgo.PrimaryButton, + CustomID: globals.Retry}, + }, + }, + } + for i := 0; i < len(archivedLinks); i++ { originalUrl := messageUrls[i] link := archivedLinks[i] @@ -470,9 +495,16 @@ func (bot *ArchiverBot) buildArchiveReply(archivedLinks []string, messageUrls [] embed.Footer = &discordgo.MessageEmbedFooter{ Text: "⚙️ Customize this message with /settings", } + + embeds = append(embeds, &embed) } - embeds = append(embeds, &embed) } - return embeds, errs + reply := &discordgo.MessageSend{ + Embeds: embeds, + Components: components, + } + + messagesToSend = append(messagesToSend, reply) + return messagesToSend, errs } diff --git a/bot/handlers.go b/bot/handlers.go index fc257ed..35555fd 100644 --- a/bot/handlers.go +++ b/bot/handlers.go @@ -169,7 +169,7 @@ func (bot *ArchiverBot) MessageReactionAddHandler(s *discordgo.Session, r *disco return } - for _, reply := range replies { + for _, messagesToSend := range replies { if r.MessageReaction.GuildID != "" { g, err := bot.DG.Guild(r.MessageReaction.GuildID) if err != nil { @@ -184,7 +184,7 @@ func (bot *ArchiverBot) MessageReactionAddHandler(s *discordgo.Session, r *disco ServerName: g.Name, }) } - err := bot.sendArchiveResponse(m, reply) + err := bot.sendArchiveResponse(m, messagesToSend) if err != nil { log.Errorf("problem sending message: %v", err) } @@ -258,19 +258,19 @@ func (bot *ArchiverBot) InteractionHandler(s *discordgo.Session, i *discordgo.In }) } - embeds, errs := bot.handleArchiveCommand(i) + messagesToSend, errs := bot.handleArchiveCommand(i) for _, err := range errs { if err != nil { log.Errorf("problem handling archive command request: %v", err) } } - if len(embeds) == 0 { + if len(messagesToSend) == 0 { log.Warn("no embeds were generated") return } - for index, embed := range embeds { + for index, message := range messagesToSend { if len(errs) > 0 { if errs[index] != nil { guild.Name = "None" @@ -298,7 +298,7 @@ func (bot *ArchiverBot) InteractionHandler(s *discordgo.Session, i *discordgo.In }) } - err := bot.sendArchiveCommandResponse(i.Interaction, embed) + err := bot.sendArchiveCommandResponse(i.Interaction, message) if err != nil { log.Errorf("problem sending message: %v", err) } @@ -539,7 +539,7 @@ func (bot *ArchiverBot) InteractionHandler(s *discordgo.Session, i *discordgo.In }, }) if interactionErr != nil { - log.Errorf("error responding to archive message reply interaction, err: %v", interactionErr) + log.Errorf("error responding to archive message messagesToSend interaction, err: %v", interactionErr) } // We trick handleArchiveRequest by giving it a fake message reaction @@ -559,11 +559,11 @@ func (bot *ArchiverBot) InteractionHandler(s *discordgo.Session, i *discordgo.In // This is necessary because the type is unknown if embeds == nil { - log.Warn("retry used but no reply was generated") + log.Warn("retry used but no messagesToSend was generated") return } - for index, reply := range embeds { + for index, messagesToSend := range embeds { m := discordgo.Message{ Member: &discordgo.Member{ User: &discordgo.User{ @@ -587,7 +587,7 @@ func (bot *ArchiverBot) InteractionHandler(s *discordgo.Session, i *discordgo.In ServerName: guild.Name, }) - err := bot.sendArchiveResponse(&m, reply) + err := bot.sendArchiveResponse(&m, messagesToSend) if err != nil { log.Errorf("problem sending message: %v", err) } diff --git a/bot/messaging.go b/bot/messaging.go index 9914cb2..84bf315 100644 --- a/bot/messaging.go +++ b/bot/messaging.go @@ -10,51 +10,52 @@ import ( ) // sendArchiveResponse sends the message with a result from archive.org -func (bot *ArchiverBot) sendArchiveResponse(message *discordgo.Message, embed *discordgo.MessageEmbed) error { +func (bot *ArchiverBot) sendArchiveResponse(userMessage *discordgo.Message, messagesToSend *discordgo.MessageSend) error { username := "" - user, err := bot.DG.User(message.Member.User.ID) + user, err := bot.DG.User(userMessage.Member.User.ID) if err != nil { - log.Errorf("unable to look up user with ID %v, err: %v", message.Member.User.ID, err) + log.Errorf("unable to look up user with ID %v, err: %v", userMessage.Member.User.ID, err) username = "unknown" } else { username = user.Username } - if message.GuildID != "" { + var guild *discordgo.Guild + if userMessage.GuildID != "" { + var gErr error // Do a lookup for the full guild object - guild, gErr := bot.DG.Guild(message.GuildID) + guild, gErr = bot.DG.Guild(userMessage.GuildID) if gErr != nil { return gErr } bot.createMessageEvent(MessageEvent{ AuthorId: user.ID, AuthorUsername: user.Username, - MessageId: message.ID, - ChannelId: message.ChannelID, - ServerID: message.GuildID, + MessageId: userMessage.ID, + ChannelId: userMessage.ChannelID, + ServerID: userMessage.GuildID, }) log.Debugf("sending archive message response in %s(%s), calling user: %s(%s)", - guild.Name, guild.ID, username, message.Member.User.ID) + guild.Name, guild.ID, username, userMessage.Member.User.ID) } - send := &discordgo.MessageSend{ - Embeds: []*discordgo.MessageEmbed{ - embed, - }, + botMessage, err := bot.DG.ChannelMessageSendComplex(userMessage.ChannelID, messagesToSend) + // For some reason, this message is absent a Guild ID, so we copy from the previous message + if guild.ID != "" { + botMessage.GuildID = guild.ID } - _, err = bot.DG.ChannelMessageSendComplex(message.ChannelID, send) if err != nil { log.Errorf("problem sending message: %v", err) return err } - go bot.removeRetryButtonAfterSleep(message) + go bot.removeRetryButtonAfterSleep(botMessage) return nil } // sendArchiveResponse sends the message with a result from archive.org -func (bot *ArchiverBot) sendArchiveCommandResponse(i *discordgo.Interaction, embed *discordgo.MessageEmbed) error { +func (bot *ArchiverBot) sendArchiveCommandResponse(i *discordgo.Interaction, message *discordgo.MessageSend) error { username := "" var user *discordgo.User var err error @@ -87,14 +88,20 @@ func (bot *ArchiverBot) sendArchiveCommandResponse(i *discordgo.Interaction, emb guild.Name, guild.ID, username, user.ID) } - _, err = bot.DG.InteractionResponseEdit(i, &discordgo.WebhookEdit{ - Embeds: []*discordgo.MessageEmbed{ - embed, - }, + interactionMessage, err := bot.DG.InteractionResponseEdit(i, &discordgo.WebhookEdit{ + Embeds: message.Embeds, + Components: message.Components, }) + // For some reason, this message is absent a Guild ID, so we copy from the previous message + if i.GuildID != "" { + interactionMessage.GuildID = i.GuildID + } + if err != nil { log.Errorf("problem sending message: %v", err) + } else { + go bot.removeRetryButtonAfterSleep(interactionMessage) } return nil } @@ -103,7 +110,7 @@ func (bot *ArchiverBot) removeRetryButtonAfterSleep(message *discordgo.Message) var guild *discordgo.Guild var gErr error guild, gErr = bot.DG.Guild(message.GuildID) - if gErr != nil { + if gErr != nil || guild.ID == "" { log.Errorf("unable to look up server by id: %v", message.GuildID) message.GuildID = "" guild = &discordgo.Guild{ @@ -140,7 +147,8 @@ func (bot *ArchiverBot) removeRetryButtonAfterSleep(message *discordgo.Message) log.Debugf("removing retry button (waited %vs) for message ID %s in channel %s, guild: %s(%s)", sleep, message.ID, message.ChannelID, sc.Name, sc.DiscordId) - _, err := bot.DG.ChannelMessageEditComplex(&me) + reply, err := bot.DG.ChannelMessageEditComplex(&me) + reply = reply if err != nil { log.Errorf("unable to remove retry button on message id %v, server: %s(%s): %v, ", message.ID, message.GuildID, guild.Name, err)