feat: set page in list

This commit is contained in:
Siwoo Jeon 2025-05-17 11:33:43 +09:00
parent c3955f213b
commit 2e90e14116
Signed by: migan
GPG key ID: 036E9A8C5E8E48DA
10 changed files with 281 additions and 29 deletions

View file

@ -7,9 +7,12 @@ import (
"github.com/bwmarrin/discordgo"
)
type modalRun func(ctx *ModalContext)
type messageRun func(ctx *MsgContext)
type chatInputRun func(ctx *ChatInputContext)
type componentRun func(ctx *ComponentContext)
type modalParse func(ctx *ModalContext) bool
type componentParse func(ctx *ComponentContext) bool
type Category string
@ -32,6 +35,7 @@ type DiscommandStruct struct {
Commands map[string]*Command
Components []*Component
Aliases map[string]string
Modals []*Modal
}
type MsgContext struct {
@ -53,24 +57,38 @@ type ComponentContext struct {
Component *Component
}
type ModalContext struct {
Inter *utils.InteractionCreate
Modal *Modal
}
type Component struct {
Parse componentParse
Run componentRun
}
type Modal struct {
Parse modalParse
Run modalRun
}
const (
Chatting Category = "채팅"
General Category = "일반"
)
var commandMutex sync.Mutex
var componentMutex sync.Mutex
var (
commandMutex sync.Mutex
componentMutex sync.Mutex
modalMutex sync.Mutex
)
func new() *DiscommandStruct {
discommand := DiscommandStruct{
Commands: map[string]*Command{},
Aliases: map[string]string{},
Components: []*Component{},
Modals: []*Modal{},
}
return &discommand
}
@ -92,6 +110,12 @@ func (d *DiscommandStruct) LoadComponent(c *Component) {
d.Components = append(d.Components, c)
}
func (d *DiscommandStruct) LoadModal(m *Modal) {
defer modalMutex.Unlock()
modalMutex.Lock()
d.Modals = append(d.Modals, m)
}
func (d *DiscommandStruct) MessageRun(name string, s *discordgo.Session, m *discordgo.MessageCreate, args []string) {
if command, ok := d.Commands[name]; ok {
command.MessageRun(&MsgContext{s, m, &args, command})
@ -109,18 +133,42 @@ func (d *DiscommandStruct) ChatInputRun(name string, s *discordgo.Session, i *di
}
func (d *DiscommandStruct) ComponentRun(s *discordgo.Session, i *discordgo.InteractionCreate) {
for _, c := range d.Components {
if (!c.Parse(&ComponentContext{s, &utils.InteractionCreate{
data := &ComponentContext{
Session: s,
Inter: &utils.InteractionCreate{
InteractionCreate: i,
Session: s,
}, c})) {
},
}
for _, c := range d.Components {
data.Component = c
if !c.Parse(data) {
continue
}
c.Run(&ComponentContext{s, &utils.InteractionCreate{
c.Run(data)
break
}
}
func (d *DiscommandStruct) ModalRun(s *discordgo.Session, i *discordgo.InteractionCreate) {
data := &ModalContext{
Inter: &utils.InteractionCreate{
InteractionCreate: i,
Session: s,
}, c})
},
}
for _, m := range d.Modals {
data.Modal = m
if !m.Parse(data) {
continue
}
m.Run(data)
break
}
}

View file

@ -129,7 +129,6 @@ func learnedDataListRun(s *discordgo.Session, m any, args *[]string) {
}
if match := utils.RegexpLearnQueryResult.FindStringSubmatch(query); match != nil {
fmt.Println(match[1])
filter = append(filter, bson.E{
Key: "result",
Value: bson.M{
@ -139,7 +138,6 @@ func learnedDataListRun(s *discordgo.Session, m any, args *[]string) {
}
if match := utils.RegexpLearnQueryLength.FindStringSubmatch(query); match != nil {
fmt.Println(1)
var err error
length, err = strconv.Atoi(match[1])
fmt.Printf("err: %v\n", err)

View file

@ -15,13 +15,12 @@ var PaginationEmbedComponent *commands.Component = &commands.Component{
if i.MessageComponentData().ComponentType == discordgo.ButtonComponent {
customId := i.MessageComponentData().CustomID
if !strings.HasPrefix(customId, utils.PaginationEmbedPrev) && !strings.HasPrefix(customId, utils.PaginationEmbedNext) {
if !strings.HasPrefix(customId, utils.PaginationEmbedPrev) && !strings.HasPrefix(customId, utils.PaginationEmbedNext) && !strings.HasPrefix(customId, utils.PaginationEmbedPages) {
return false
}
id := utils.GetPaginationEmbedId(customId)
userId := utils.GetPaginationEmbedUserId(id)
if i.Member.User.ID != userId {
return false
}
@ -41,8 +40,10 @@ var PaginationEmbedComponent *commands.Component = &commands.Component{
if strings.HasPrefix(customId, utils.PaginationEmbedPrev) {
p.Prev(ctx.Inter)
} else {
} else if strings.HasPrefix(customId, utils.PaginationEmbedNext) {
p.Next(ctx.Inter)
} else {
p.ShowModal(ctx.Inter)
}
},
}

View file

@ -7,7 +7,7 @@ import (
"git.wh64.net/muffin/goMuffin/utils"
)
const MUFFIN_VERSION = "5.1.0-gopher_dev.250516a"
const MUFFIN_VERSION = "5.1.0-gopher_dev.250517a"
var updatedString string = utils.RegexpDecimals.FindAllStringSubmatch(MUFFIN_VERSION, -1)[3][0]

View file

@ -11,5 +11,7 @@ func InteractionCreate(s *discordgo.Session, i *discordgo.InteractionCreate) {
return
} else if i.Type == discordgo.InteractionMessageComponent {
commands.Discommand.ComponentRun(s, i)
} else if i.Type == discordgo.InteractionModalSubmit {
commands.Discommand.ModalRun(s, i)
}
}

View file

@ -14,6 +14,7 @@ import (
"git.wh64.net/muffin/goMuffin/configs"
"git.wh64.net/muffin/goMuffin/databases"
"git.wh64.net/muffin/goMuffin/handler"
"git.wh64.net/muffin/goMuffin/modals"
"git.wh64.net/muffin/goMuffin/scripts"
"github.com/bwmarrin/discordgo"
"github.com/devproje/commando"
@ -77,6 +78,8 @@ func main() {
go commands.Discommand.LoadComponent(components.DeleteLearnedDataComponent)
go commands.Discommand.LoadComponent(components.PaginationEmbedComponent)
go commands.Discommand.LoadModal(modals.PaginationEmbedModal)
go dg.AddHandler(handler.MessageCreate)
go dg.AddHandler(handler.InteractionCreate)

66
modals/paginationEmbed.go Normal file
View file

@ -0,0 +1,66 @@
package modals
import (
"strconv"
"strings"
"git.wh64.net/muffin/goMuffin/commands"
"git.wh64.net/muffin/goMuffin/utils"
"github.com/bwmarrin/discordgo"
)
var PaginationEmbedModal *commands.Modal = &commands.Modal{
Parse: func(ctx *commands.ModalContext) bool {
i := ctx.Inter
data := i.ModalSubmitData()
customId := data.CustomID
if data.Components[0].Type() != discordgo.ActionsRowComponent {
return false
}
if !strings.HasPrefix(customId, utils.PaginationEmbedModal) {
return false
}
id := utils.GetPaginationEmbedId(customId)
userId := utils.GetPaginationEmbedUserId(id)
if i.Member.User.ID != userId {
return false
}
if utils.GetPaginationEmbed(id) == nil {
return false
}
cmp := data.Components[0].(*discordgo.ActionsRow).Components[0].(*discordgo.TextInput)
if _, err := strconv.Atoi(cmp.Value); err != nil {
i.Reply(&discordgo.InteractionResponseData{
Embeds: []*discordgo.MessageEmbed{
{
Title: "❌ 오류",
Description: "해당 값은 숫자여야해요.",
Color: utils.EmbedFail,
},
},
Flags: discordgo.MessageFlagsEphemeral,
})
return false
}
return true
},
Run: func(ctx *commands.ModalContext) {
data := ctx.Inter.ModalSubmitData()
customId := data.CustomID
id := utils.GetPaginationEmbedId(customId)
p := utils.GetPaginationEmbed(id)
cmp := data.Components[0].(*discordgo.ActionsRow).Components[0].(*discordgo.TextInput)
page, _ := strconv.Atoi(cmp.Value)
p.Set(ctx.Inter, page)
},
}

View file

@ -13,9 +13,11 @@ const (
DeleteLearnedDataUserId = "#muffin/deleteLearnedData@"
DeleteLearnedDataCancel = "#muffin/deleteLearnedData/cancel@"
PaginationEmbedPrev = "#muffin-pages/prev$"
PaginationEmbedPages = "#muffin-pages/pages$"
PaginationEmbedNext = "#muffin-pages/next$"
PaginationEmbedPrev = "#muffin-pages/prev$"
PaginationEmbedPages = "#muffin-pages/pages$"
PaginationEmbedNext = "#muffin-pages/next$"
PaginationEmbedModal = "#muffin-pages/modal$"
PaginationEmbedSetPage = "#muffin-pages/modal/set$"
)
func MakeDeleteLearnedData(id string, number int) string {
@ -49,21 +51,36 @@ func MakePaginationEmbedPrev(id string) string {
return fmt.Sprintf("%s%s", PaginationEmbedPrev, id)
}
func MakePaginationEmbedPages(id string, total, current int) string {
return fmt.Sprintf("%s%s/%d/%d", PaginationEmbedPages, id, total, current)
func MakePaginationEmbedPages(id string) string {
return fmt.Sprintf("%s%s", PaginationEmbedPages, id)
}
func MakePaginationEmbedNext(id string) string {
return fmt.Sprintf("%s%s", PaginationEmbedNext, id)
}
func MakePaginationEmbedModal(id string) string {
return fmt.Sprintf("%s%s", PaginationEmbedModal, id)
}
func MakePaginationEmbedSetPage(id string) string {
return fmt.Sprintf("%s%s", PaginationEmbedSetPage, id)
}
func GetPaginationEmbedId(customId string) string {
if strings.HasPrefix(customId, PaginationEmbedPrev) {
switch {
case strings.HasPrefix(customId, PaginationEmbedPrev):
return customId[len(PaginationEmbedPrev):]
} else if strings.HasPrefix(customId, PaginationEmbedPages) {
case strings.HasPrefix(customId, PaginationEmbedPages):
return customId[len(PaginationEmbedPages):]
} else {
case strings.HasPrefix(customId, PaginationEmbedNext):
return customId[len(PaginationEmbedNext):]
case strings.HasPrefix(customId, PaginationEmbedModal):
return customId[len(PaginationEmbedModal):]
case strings.HasPrefix(customId, PaginationEmbedSetPage):
return customId[len(PaginationEmbedSetPage):]
default:
return customId
}
}

View file

@ -1,6 +1,20 @@
package utils
import "github.com/bwmarrin/discordgo"
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"github.com/bwmarrin/discordgo"
)
type ModalData struct {
CustomId string `json:"custom_id"`
Title string `json:"title"`
Components []discordgo.MessageComponent `json:"components"`
}
// InteractionCreate custom data of discordgo.InteractionCreate
type InteractionCreate struct {
@ -62,3 +76,44 @@ func (i *InteractionCreate) Update(data *discordgo.InteractionResponseData) {
Data: data,
})
}
func (i *InteractionCreate) ShowModal(data *ModalData) error {
var reqData struct {
Type discordgo.InteractionResponseType `json:"type"`
Data ModalData `json:"data"`
}
reqData.Type = discordgo.InteractionResponseModal
reqData.Data = *data
bin, err := json.Marshal(reqData)
if err != nil {
return err
}
buf := bytes.NewBuffer(bin)
req, err := http.NewRequest("POST", discordgo.EndpointInteractionResponse(i.ID, i.Token), buf)
if err != nil {
return err
}
req.Header.Add("Authorization", i.Session.Identify.Token)
req.Header.Add("Content-Type", "application/json")
resp, err := i.Session.Client.Do(req)
if err != nil {
return err
}
respBin, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
if resp.StatusCode != 200 {
return fmt.Errorf("%s", string(respBin))
}
defer resp.Body.Close()
return nil
}

View file

@ -14,13 +14,18 @@ type PaginationEmbed struct {
Current int
Total int
id string
s *discordgo.Session
desc string
}
var PaginationEmbeds = make(map[string]*PaginationEmbed)
func makeComponents(id string, current, total int) *[]discordgo.MessageComponent {
disabled := false
if total == 1 {
disabled = true
}
return &[]discordgo.MessageComponent{
discordgo.ActionsRow{
Components: []discordgo.MessageComponent{
@ -28,19 +33,19 @@ func makeComponents(id string, current, total int) *[]discordgo.MessageComponent
Style: discordgo.PrimaryButton,
Label: "이전",
CustomID: MakePaginationEmbedPrev(id),
Disabled: false,
Disabled: disabled,
},
discordgo.Button{
Style: discordgo.SecondaryButton,
Label: fmt.Sprintf("(%d/%d)", current, total),
CustomID: MakePaginationEmbedPages(id, current, total),
Disabled: true,
CustomID: MakePaginationEmbedPages(id),
Disabled: disabled,
},
discordgo.Button{
Style: discordgo.PrimaryButton,
Label: "다음",
CustomID: MakePaginationEmbedNext(id),
Disabled: false,
Disabled: disabled,
},
},
},
@ -76,8 +81,6 @@ func StartPaginationEmbed(s *discordgo.Session, m any, e *discordgo.MessageEmbed
Current: 1,
Total: len(data),
id: id,
s: s,
desc: defaultDesc,
}
if len(data) <= 0 {
@ -160,3 +163,62 @@ func (p *PaginationEmbed) Next(i *InteractionCreate) {
Components: *makeComponents(p.id, p.Current, p.Total),
})
}
func (p *PaginationEmbed) Set(i *InteractionCreate, page int) {
if page <= 0 {
i.Reply(&discordgo.InteractionResponseData{
Embeds: []*discordgo.MessageEmbed{
{
Title: "❌ 오류",
Description: "해당 값은 0보다 커야해요.",
Color: EmbedFail,
},
},
Flags: discordgo.MessageFlagsEphemeral,
})
return
}
if page >= p.Total {
i.Reply(&discordgo.InteractionResponseData{
Embeds: []*discordgo.MessageEmbed{
{
Title: "❌ 오류",
Description: "해당 값은 총 페이지의 수보다 작아야해요.",
Color: EmbedFail,
},
},
Flags: discordgo.MessageFlagsEphemeral,
})
return
}
p.Current = page
p.Embed.Description = makeDesc(p.desc, p.Data[p.Current-1])
i.Update(&discordgo.InteractionResponseData{
Embeds: []*discordgo.MessageEmbed{p.Embed},
Components: *makeComponents(p.id, p.Current, p.Total),
})
}
func (p *PaginationEmbed) ShowModal(i *InteractionCreate) {
i.ShowModal(&ModalData{
CustomId: MakePaginationEmbedModal(p.id),
Title: fmt.Sprintf("%s의 리스트", i.Session.State.User.Username),
Components: []discordgo.MessageComponent{
discordgo.ActionsRow{
Components: []discordgo.MessageComponent{
discordgo.TextInput{
CustomID: MakePaginationEmbedSetPage(p.id),
Label: "페이지",
Style: discordgo.TextInputShort,
Placeholder: "이동할 페이지를 여기에 적어주세요.",
Required: true,
},
},
},
},
})
}