Skip to content

Commit

Permalink
paginatedmessages: interoperate with response autodeletion setting (b…
Browse files Browse the repository at this point in the history
…otlabs-gg#1671)

Currently, commands with paginated responses do not obey the 'delete response after delay' option set using command overrides. The reason is that dcmd (and in turn the YAGPDB command system) does not know about paginated messages -- which are sent manually as opposed to using dcmd's response mechanism -- and so naturally does not delete them.

This commit therefore teaches dcmd about paginated messages by introducing a new type, PaginatedResponse, which implements dcmd.Response. When returned from a command run function, dcmd will then automatically call PaginatedResponse.Send to create and return the paginated message, which interopates with the existing response deletion machinery.
  • Loading branch information
jo3-l authored and ashishjh-bst committed Jun 27, 2024
1 parent a3de7a6 commit 4bb571e
Show file tree
Hide file tree
Showing 12 changed files with 91 additions and 107 deletions.
6 changes: 2 additions & 4 deletions bot/paginatedmessages/paginatedcommand.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,8 @@ func PaginatedCommand(pageArgIndex int, cb PaginatedCommandFunc) dcmd.RunFunc {
return cb(data, nil, page)
}

_, err := CreatePaginatedMessage(data.GuildData.GS.ID, data.GuildData.CS.ID, page, 0, func(p *PaginatedMessage, page int) (*discordgo.MessageEmbed, error) {
return NewPaginatedResponse(data.GuildData.GS.ID, data.GuildData.CS.ID, page, 0, func(p *PaginatedMessage, page int) (*discordgo.MessageEmbed, error) {
return cb(data, p, page)
})

return nil, err
}), nil
}
}
45 changes: 33 additions & 12 deletions bot/paginatedmessages/paginatedinteractions.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package paginatedmessages

import (
"fmt"
"strconv"
"sync"
"time"

"github.com/botlabs-gg/yagpdb/v2/bot/eventsystem"
"github.com/botlabs-gg/yagpdb/v2/common"
"github.com/botlabs-gg/yagpdb/v2/lib/dcmd"
"github.com/botlabs-gg/yagpdb/v2/lib/discordgo"
)

Expand Down Expand Up @@ -93,38 +95,57 @@ func createNavigationButtons(prevDisabled bool, nextDisabled bool) []discordgo.M
}
}

func CreatePaginatedMessage(guildID, channelID int64, initPage, maxPages int, pagerFunc PagerFunc) (*PaginatedMessage, error) {
func NewPaginatedResponse(guildID, channelID int64, initPage, maxPages int, pagerFunc PagerFunc) *PaginatedResponse {
if initPage < 1 {
initPage = 1
}

return &PaginatedResponse{
guildID: guildID,
channelID: channelID,
initPage: initPage,
maxPages: maxPages,
pagerFunc: pagerFunc,
}
}

type PaginatedResponse struct {
guildID int64
channelID int64
initPage, maxPages int
pagerFunc PagerFunc
}

var _ dcmd.Response = (*PaginatedResponse)(nil)

func (p *PaginatedResponse) Send(*dcmd.Data) ([]*discordgo.Message, error) {
pm := &PaginatedMessage{
GuildID: guildID,
ChannelID: channelID,
CurrentPage: initPage,
MaxPage: maxPages,
GuildID: p.guildID,
ChannelID: p.channelID,
CurrentPage: p.initPage,
MaxPage: p.maxPages,
lastUpdateTime: time.Now(),
stopCh: make(chan bool),
Navigate: pagerFunc,
Navigate: p.pagerFunc,
}

embed, err := pagerFunc(pm, initPage)
embed, err := p.pagerFunc(pm, p.initPage)
if err != nil {
return nil, err
return nil, fmt.Errorf("generating first page of paginated response: %s", err)
}

footer := "Page " + strconv.Itoa(initPage)
footer := "Page " + strconv.Itoa(p.initPage)
nextButtonDisabled := false
if pm.MaxPage > 0 {
footer += "/" + strconv.Itoa(pm.MaxPage)
nextButtonDisabled = initPage >= pm.MaxPage
nextButtonDisabled = p.initPage >= pm.MaxPage
}
embed.Footer = &discordgo.MessageEmbedFooter{
Text: footer,
}
embed.Timestamp = time.Now().Format(time.RFC3339)

msg, err := common.BotSession.ChannelMessageSendComplex(channelID, &discordgo.MessageSend{
msg, err := common.BotSession.ChannelMessageSendComplex(p.channelID, &discordgo.MessageSend{
Embeds: []*discordgo.MessageEmbed{embed},
Components: createNavigationButtons(true, nextButtonDisabled),
})
Expand All @@ -140,7 +161,7 @@ func CreatePaginatedMessage(guildID, channelID int64, initPage, maxPages int, pa
menusLock.Unlock()

go pm.paginationTicker()
return pm, nil
return []*discordgo.Message{msg}, nil
}

func (p *PaginatedMessage) HandlePageButtonClick(ic *discordgo.InteractionCreate, pageMod int) {
Expand Down
11 changes: 2 additions & 9 deletions commands/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,8 @@ For more in depth help and information you should visit https://docs.yagpdb.xyz/
}

helpEmbeds = append([]*discordgo.MessageEmbed{firstPage}, helpEmbeds...)

_, err = paginatedmessages.CreatePaginatedMessage(0, channel.ID, 1, len(helpEmbeds), func(p *paginatedmessages.PaginatedMessage, page int) (*discordgo.MessageEmbed, error) {
return paginatedmessages.NewPaginatedResponse(0, channel.ID, 1, len(helpEmbeds), func(p *paginatedmessages.PaginatedMessage, page int) (*discordgo.MessageEmbed, error) {
embed := helpEmbeds[page-1]
return embed, nil
})
if err != nil {
return "Something went wrong, make sure you don't have the bot blocked or your DMs closed!", err

}

return nil, nil
}), nil
}
12 changes: 4 additions & 8 deletions logs/plugin_bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ var cmdUsernames = &commands.YAGCommand{
gID = parsed.GuildData.GS.ID
}

_, err := paginatedmessages.CreatePaginatedMessage(gID, parsed.ChannelID, 1, 0, func(p *paginatedmessages.PaginatedMessage, page int) (*discordgo.MessageEmbed, error) {
return paginatedmessages.NewPaginatedResponse(gID, parsed.ChannelID, 1, 0, func(p *paginatedmessages.PaginatedMessage, page int) (*discordgo.MessageEmbed, error) {
target := parsed.Author
if parsed.Args[0].Value != nil {
target = parsed.Args[0].Value.(*discordgo.User)
Expand Down Expand Up @@ -317,9 +317,7 @@ var cmdUsernames = &commands.YAGCommand{
}

return embed, nil
})

return nil, err
}), nil
},
}

Expand Down Expand Up @@ -347,7 +345,7 @@ var cmdNicknames = &commands.YAGCommand{
return "Nickname logging is disabled on this server", nil
}

_, err = paginatedmessages.CreatePaginatedMessage(parsed.GuildData.GS.ID, parsed.ChannelID, 1, 0, func(p *paginatedmessages.PaginatedMessage, page int) (*discordgo.MessageEmbed, error) {
return paginatedmessages.NewPaginatedResponse(parsed.GuildData.GS.ID, parsed.ChannelID, 1, 0, func(p *paginatedmessages.PaginatedMessage, page int) (*discordgo.MessageEmbed, error) {

offset := (page - 1) * 15

Expand Down Expand Up @@ -377,9 +375,7 @@ var cmdNicknames = &commands.YAGCommand{
}

return embed, nil
})

return nil, err
}), nil
},
}

Expand Down
4 changes: 2 additions & 2 deletions moderation/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -896,8 +896,8 @@ var ModerationCommands = []*commands.YAGCommand{
if parsed.Context().Value(paginatedmessages.CtxKeyNoPagination) != nil {
return PaginateWarnings(parsed)(nil, page)
}
_, err = paginatedmessages.CreatePaginatedMessage(parsed.GuildData.GS.ID, parsed.GuildData.CS.ID, page, 0, PaginateWarnings(parsed))
return nil, err

return paginatedmessages.NewPaginatedResponse(parsed.GuildData.GS.ID, parsed.GuildData.CS.ID, page, 0, PaginateWarnings(parsed)), nil
},
},
{
Expand Down
6 changes: 2 additions & 4 deletions reputation/plugin_bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,11 +427,9 @@ var cmds = []*commands.YAGCommand{
return topRepPager(parsed.GuildData.GS.ID, nil, page)
}

_, err := paginatedmessages.CreatePaginatedMessage(parsed.GuildData.GS.ID, parsed.ChannelID, page, 0, func(p *paginatedmessages.PaginatedMessage, page int) (*discordgo.MessageEmbed, error) {
return paginatedmessages.NewPaginatedResponse(parsed.GuildData.GS.ID, parsed.ChannelID, page, 0, func(p *paginatedmessages.PaginatedMessage, page int) (*discordgo.MessageEmbed, error) {
return topRepPager(parsed.GuildData.GS.ID, p, page)
})

return nil, err
}), nil
},
},
}
Expand Down
31 changes: 12 additions & 19 deletions stdcommands/define/define.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,27 +45,20 @@ var Command = &commands.YAGCommand{
}

if paginatedView {
_, err := paginatedmessages.CreatePaginatedMessage(
data.GuildData.GS.ID, data.ChannelID, 1, len(qResp.Results), func(p *paginatedmessages.PaginatedMessage, page int) (*discordgo.MessageEmbed, error) {
i := page - 1

paginatedEmbed := embedCreator(qResp.Results, i)
return paginatedEmbed, nil
})
if err != nil {
return "Something went wrong", nil
}
} else {
result := qResp.Results[0]

cmdResp := fmt.Sprintf("**%s**: %s\n*%s*\n*(<%s>)*", result.Word, result.Definition, result.Example, result.Permalink)
if len(qResp.Results) > 1 {
cmdResp += fmt.Sprintf(" *%d more results*", len(qResp.Results)-1)
}
return cmdResp, nil
return paginatedmessages.NewPaginatedResponse(data.GuildData.GS.ID, data.ChannelID, 1, len(qResp.Results), func(p *paginatedmessages.PaginatedMessage, page int) (*discordgo.MessageEmbed, error) {
i := page - 1

paginatedEmbed := embedCreator(qResp.Results, i)
return paginatedEmbed, nil
}), nil
}

return nil, nil
result := qResp.Results[0]
cmdResp := fmt.Sprintf("**%s**: %s\n*%s*\n*(<%s>)*", result.Word, result.Definition, result.Example, result.Permalink)
if len(qResp.Results) > 1 {
cmdResp += fmt.Sprintf(" *%d more results*", len(qResp.Results)-1)
}
return cmdResp, nil
},
}

Expand Down
48 changes: 23 additions & 25 deletions stdcommands/dictionary/dictionary.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ var Command = &commands.YAGCommand{
SlashCommandEnabled: true,
RunFunc: func(data *dcmd.Data) (interface{}, error) {
query := strings.ToLower(data.Args[0].Str())
url := "https://api.dictionaryapi.dev/api/v2/entries/en/"+url.QueryEscape(query)
url := "https://api.dictionaryapi.dev/api/v2/entries/en/" + url.QueryEscape(query)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
Expand Down Expand Up @@ -68,15 +68,13 @@ var Command = &commands.YAGCommand{
return createDictionaryDefinitionEmbed(dictionary, &dictionary.Meanings[0]), nil
}

_, err = paginatedmessages.CreatePaginatedMessage(data.GuildData.GS.ID, data.ChannelID, 1, len(dictionary.Meanings), func(p *paginatedmessages.PaginatedMessage, page int) (*discordgo.MessageEmbed, error) {
return paginatedmessages.NewPaginatedResponse(data.GuildData.GS.ID, data.ChannelID, 1, len(dictionary.Meanings), func(p *paginatedmessages.PaginatedMessage, page int) (*discordgo.MessageEmbed, error) {
if page > len(dictionary.Meanings) {
return nil, paginatedmessages.ErrNoResults
}

return createDictionaryDefinitionEmbed(dictionary, &dictionary.Meanings[page-1]), nil
})

return nil, err
}), nil
},
}

Expand All @@ -90,18 +88,18 @@ func createDictionaryDefinitionEmbed(res *DictionaryResponse, def *Meaning) *dis
Timestamp: time.Now().Format(time.RFC3339),
}

if(len(res.SourceUrls) > 0) {
embed.URL = res.SourceUrls[0];
if len(res.SourceUrls) > 0 {
embed.URL = res.SourceUrls[0]
}
var description = "";

var description = ""
for _, d := range def.Definitions {
if(len(description) + len(d.Definition) + len(d.Example) > 2000) {
if len(description)+len(d.Definition)+len(d.Example) > 2000 {
// if all definitions along with examples cannot be fit into the description, skip remaining definitions.
break;
break
}
description = fmt.Sprintf("%s\n- %s", description, capitalizeSentences(normalizeOutput(d.Definition)));
if d.Example != ""{
description = fmt.Sprintf("%s\n- %s", description, capitalizeSentences(normalizeOutput(d.Definition)))
if d.Example != "" {
var example = capitalizeSentences(normalizeOutput(d.Example))
if !hasEndOfSentenceSymbol(example) {
example = example + "." // add period if no other symbol that ends the sentence is present
Expand All @@ -110,7 +108,7 @@ func createDictionaryDefinitionEmbed(res *DictionaryResponse, def *Meaning) *dis
}
}

embed.Description = common.CutStringShort(description, 2048);
embed.Description = common.CutStringShort(description, 2048)

if res.Origin != "" {
embed.Fields = append(embed.Fields, &discordgo.MessageEmbedField{
Expand All @@ -123,20 +121,20 @@ func createDictionaryDefinitionEmbed(res *DictionaryResponse, def *Meaning) *dis
if len(res.Phonetics) != 0 {
var pronunciation = &discordgo.MessageEmbedField{
Name: "Pronunciation",
Value: "",
Value: "",
Inline: true,
}
for _, v := range res.Phonetics {
if(v.Audio != ""){
if(v.Text == ""){
v.Text = res.Word;
for _, v := range res.Phonetics {
if v.Audio != "" {
if v.Text == "" {
v.Text = res.Word
}
pronunciation.Value = fmt.Sprintf("%s\n🔊[%s](%s)", pronunciation.Value, normalizeOutput(v.Text), v.Audio)
}else {
} else {
pronunciation.Value = fmt.Sprintf("%s\n%s", pronunciation.Value, normalizeOutput(v.Text))
}
}
embed.Fields = append(embed.Fields, pronunciation )
embed.Fields = append(embed.Fields, pronunciation)
}

if def.PartOfSpeech != "" {
Expand Down Expand Up @@ -208,8 +206,8 @@ func hasEndOfSentenceSymbol(s string) bool {
}

type Phonetic struct {
Text string `json:"text"`
Audio string `json:"audio"`
Text string `json:"text"`
Audio string `json:"audio"`
}

type Definition struct {
Expand All @@ -227,9 +225,9 @@ type Meaning struct {
}

type DictionaryResponse struct {
Origin string `json:"origin,omitempty"`
Origin string `json:"origin,omitempty"`
Word string `json:"word"`
Phonetics []Phonetic `json:"phonetics"`
Meanings []Meaning `json:"meanings"`
SourceUrls []string `json:"sourceUrls"`
SourceUrls []string `json:"sourceUrls"`
}
8 changes: 2 additions & 6 deletions stdcommands/forex/forex.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,14 @@ var Command = &commands.YAGCommand{

// If the currency isn't supported by API.
if !toExist || !fromExist {
_, err = paginatedmessages.CreatePaginatedMessage(
return paginatedmessages.NewPaginatedResponse(
data.GuildData.GS.ID, data.ChannelID, 1, maxPages, func(p *paginatedmessages.PaginatedMessage, page int) (*discordgo.MessageEmbed, error) {
embed, err := errEmbed(currenciesResult, page)
if err != nil {
return nil, err
}
return embed, nil
})
if err != nil {
return nil, err
}
return nil, nil
}), nil
}

err = requestAPI(fmt.Sprintf("https://api.frankfurter.app/latest?amount=%.3f&from=%s&to=%s", amount, from, to), &exchangeRateResult)
Expand Down
13 changes: 4 additions & 9 deletions stdcommands/howlongtobeat/howlongtobeat.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ var (
hltbHostPath = "api/search"
)

//Command var needs a comment for lint :)
// Command var needs a comment for lint :)
var Command = &commands.YAGCommand{
CmdCategory: commands.CategoryFun,
Name: "HowLongToBeat",
Expand Down Expand Up @@ -91,23 +91,18 @@ var Command = &commands.YAGCommand{
hltbEmbed := embedCreator(games, 0, paginatedView)

if paginatedView {
_, err := paginatedmessages.CreatePaginatedMessage(
return paginatedmessages.NewPaginatedResponse(
data.GuildData.GS.ID, data.ChannelID, 1, len(games), func(p *paginatedmessages.PaginatedMessage, page int) (*discordgo.MessageEmbed, error) {
i := page - 1
sort.SliceStable(games, func(i, j int) bool {
return games[i].JaroWinklerSimilarity > games[j].JaroWinklerSimilarity
})
paginatedEmbed := embedCreator(games, i, paginatedView)
return paginatedEmbed, nil
})
if err != nil {
return "Something went wrong", nil
}
} else {
return hltbEmbed, nil
}), nil
}

return nil, nil
return hltbEmbed, nil
},
}

Expand Down
Loading

0 comments on commit 4bb571e

Please sign in to comment.