From e2c85c1ccbc7266c4b6ecb9254ad2d12c9abc819 Mon Sep 17 00:00:00 2001 From: Siwoo Jeon Date: Fri, 28 Mar 2025 21:49:47 +0900 Subject: [PATCH] feat: Add learn command --- commands/discommand.go | 8 ++ commands/learn.go | 215 +++++++++++++++++++++++++++++++++++++++ configs/config.go | 7 +- configs/version.go | 3 + go.mod | 1 + go.sum | 2 + handler/messageCreate.go | 2 +- utils/regexp.go | 5 + 8 files changed, 239 insertions(+), 4 deletions(-) create mode 100644 commands/learn.go create mode 100644 configs/version.go create mode 100644 utils/regexp.go diff --git a/commands/discommand.go b/commands/discommand.go index ddc1bd2..0652bc6 100644 --- a/commands/discommand.go +++ b/commands/discommand.go @@ -1,6 +1,8 @@ package commands import ( + // "fmt" + "github.com/bwmarrin/discordgo" ) @@ -16,6 +18,7 @@ type Command struct { *discordgo.ApplicationCommand Aliases []string DetailedDescription *DetailedDescription + discommand *DiscommandStruct } type DiscommandStruct struct { @@ -35,17 +38,22 @@ func new() *DiscommandStruct { go discommand.loadCommands(HelpCommand) go discommand.loadCommands(DataLengthCommand) + go discommand.loadCommands(LearnCommand) go discommand.addMessageRun(HelpCommand.Name, HelpCommand.helpMessageRun) go discommand.addMessageRun(DataLengthCommand.Name, DataLengthCommand.dataLengthMessageRun) + go discommand.addMessageRun(LearnCommand.Name, LearnCommand.learnMessageRun) go discommand.addChatInputRun(DataLengthCommand.Name, DataLengthCommand.dataLenghChatInputRun) + go discommand.addChatInputRun(LearnCommand.Name, LearnCommand.learnChatInputRun) return &discommand } func (d *DiscommandStruct) loadCommands(command *Command) { d.Commands[command.Name] = command d.Aliases[command.Name] = command.Name + // fmt.Println(command.Name) + command.discommand = d for _, alias := range command.Aliases { d.Aliases[alias] = command.Name diff --git a/commands/learn.go b/commands/learn.go new file mode 100644 index 0000000..98d4de1 --- /dev/null +++ b/commands/learn.go @@ -0,0 +1,215 @@ +package commands + +import ( + "context" + "fmt" + "strings" + "time" + + "git.wh64.net/muffin/goMuffin/configs" + "git.wh64.net/muffin/goMuffin/databases" + "git.wh64.net/muffin/goMuffin/utils" + "github.com/bwmarrin/discordgo" + + "github.com/LoperLee/golang-hangul-toolkit/hangul" +) + +var LearnCommand *Command = &Command{ + ApplicationCommand: &discordgo.ApplicationCommand{ + Type: discordgo.ChatApplicationCommand, + Name: "배워", + Description: "단어를 가르치는 명령ㅇ어에요.", + Options: []*discordgo.ApplicationCommandOption{ + { + Type: discordgo.ApplicationCommandOptionString, + Name: "단어", + Description: "등록할 단어를 입력해주세요.", + Required: true, + }, + { + Type: discordgo.ApplicationCommandOptionString, + Name: "대답", + Description: "해당 단어의 대답을 입력해주세요.", + Required: true, + }, + }, + }, + Aliases: []string{"공부"}, + DetailedDescription: &DetailedDescription{ + Usage: "머핀아 배워 (등록할 단어) (대답)", + Examples: []string{"머핀아 배워 안녕 안녕!", + "머핀아 배워 \"야 죽을래?\" \"아니요 ㅠㅠㅠ\"", + "머핀아 배워 미간은_누구야? 이봇의_개발자요", + }, + }, +} + +func addPrefix(arr []string) (newArr []string) { + for _, item := range arr { + newArr = append(newArr, "- "+item) + } + return +} + +func (c *Command) learnRun(s *discordgo.Session, m any) { + var userId, command, result string + + igCommands := []string{} + switch m := m.(type) { + case *discordgo.MessageCreate: + userId = m.Author.ID + matches := utils.ExtractQuotedText.FindAllStringSubmatch(strings.TrimPrefix(m.Content, configs.Config.Bot.Prefix), 2) + + if len(matches) < 2 { + content := strings.TrimPrefix(m.Content, configs.Config.Bot.Prefix) + command = strings.Split(content, " ")[1] + result = strings.Split(content, " ")[2] + + if command == "" || result == "" { + s.ChannelMessageSendEmbedReply(m.ChannelID, &discordgo.MessageEmbed{ + Title: "❌ 오류", + Description: "올바르지 않ㅇ은 용법이에요.", + Fields: []*discordgo.MessageEmbedField{ + { + Name: "사용법", + Value: utils.InlineCode(c.DetailedDescription.Usage), + Inline: true, + }, + { + Name: "예시", + Value: strings.Join(addPrefix(c.DetailedDescription.Examples), "\n"), + }, + }, + Color: int(utils.EFail), + }, m.Reference()) + return + } + } else { + command = matches[0][1] + result = matches[1][1] + } + + case *discordgo.InteractionCreate: + s.InteractionRespond(m.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseDeferredChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Flags: discordgo.MessageFlagsEphemeral, + }, + }) + + userId = m.Member.User.ID + + optsMap := map[string]*discordgo.ApplicationCommandInteractionDataOption{} + for _, opt := range m.ApplicationCommandData().Options { + optsMap[opt.Name] = opt + } + + if opt, ok := optsMap["단어"]; ok { + command = opt.StringValue() + } + + if opt, ok := optsMap["대답"]; ok { + result = opt.StringValue() + } + } + + for _, command := range c.discommand.Commands { + igCommands = append(igCommands, command.Name) + igCommands = append(igCommands, command.Aliases...) + } + + ignores := []string{"미간", "Migan", "migan", "간미"} + ignores = append(ignores, igCommands...) + + disallows := []string{ + "@everyone", + "@here", + "<@" + configs.Config.Bot.OwnerId + ">"} + + for _, ig := range ignores { + if strings.Contains(command, ig) { + embed := &discordgo.MessageEmbed{ + Title: "❌ 오류", + Description: "해ㄷ당 단어는 배우기 껄끄ㄹ럽네요.", + Color: int(utils.EFail), + } + + switch m := m.(type) { + case *discordgo.MessageCreate: + s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference()) + case *discordgo.InteractionCreate: + s.InteractionResponseEdit(m.Interaction, &discordgo.WebhookEdit{ + Embeds: &[]*discordgo.MessageEmbed{embed}, + }) + } + return + } + } + + for _, di := range disallows { + if strings.Contains(result, di) { + embed := &discordgo.MessageEmbed{ + Title: "❌ 오류", + Description: "해당 단ㅇ어의 대답으로 하기 좀 그렇ㄴ네요.", + Color: int(utils.EFail), + } + + switch m := m.(type) { + case *discordgo.MessageCreate: + s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference()) + case *discordgo.InteractionCreate: + s.InteractionResponseEdit(m.Interaction, &discordgo.WebhookEdit{ + Embeds: &[]*discordgo.MessageEmbed{embed}, + }) + } + } + } + + _, err := databases.Learns.InsertOne(context.TODO(), databases.InsertLearn{ + Command: command, + Result: result, + UserId: userId, + CreatedAt: time.Now(), + }) + if err != nil { + fmt.Println(err) + embed := &discordgo.MessageEmbed{ + Title: "❌ 오류", + Description: "단어를 배우는데 오류가 생겼어요.", + Color: int(utils.EFail), + } + + switch m := m.(type) { + case *discordgo.MessageCreate: + s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference()) + case *discordgo.InteractionCreate: + s.InteractionResponseEdit(m.Interaction, &discordgo.WebhookEdit{ + Embeds: &[]*discordgo.MessageEmbed{embed}, + }) + } + return + } + + embed := &discordgo.MessageEmbed{ + Title: "✅ 성공", + Description: hangul.GetJosa(command, hangul.EUL_REUL) + " 배웠어요.", + Color: int(utils.ESuccess), + } + + switch m := m.(type) { + case *discordgo.MessageCreate: + s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference()) + case *discordgo.InteractionCreate: + s.InteractionResponseEdit(m.Interaction, &discordgo.WebhookEdit{ + Embeds: &[]*discordgo.MessageEmbed{embed}, + }) + } +} + +func (c *Command) learnMessageRun(s *discordgo.Session, m *discordgo.MessageCreate) { + c.learnRun(s, m) +} + +func (c *Command) learnChatInputRun(s *discordgo.Session, i *discordgo.InteractionCreate) { + c.learnRun(s, i) +} diff --git a/configs/config.go b/configs/config.go index b0aaabe..588a707 100644 --- a/configs/config.go +++ b/configs/config.go @@ -8,11 +8,11 @@ import ( "github.com/joho/godotenv" ) -var MUFFIN_VERSION = "0.0.0-gopher_canary.250326a" type botConfig struct { - Token string - Prefix string + Token string + Prefix string + OwnerId string } type trainConfig struct { @@ -41,6 +41,7 @@ func loadConfig() *MuffinConfig { func setConfig(config *MuffinConfig) { config.Bot.Prefix = os.Getenv("BOT_PREFIX") config.Bot.Token = os.Getenv("BOT_TOKEN") + config.Bot.OwnerId = os.Getenv("BOT_OWNER_ID") config.Train.UserID = os.Getenv("TRAIN_USER_ID") diff --git a/configs/version.go b/configs/version.go new file mode 100644 index 0000000..96e13a3 --- /dev/null +++ b/configs/version.go @@ -0,0 +1,3 @@ +package configs + +var MUFFIN_VERSION = "0.0.0-gopher_canary.250328a" diff --git a/go.mod b/go.mod index 18f215b..6e50464 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module git.wh64.net/muffin/goMuffin go 1.23.2 require ( + github.com/LoperLee/golang-hangul-toolkit v1.1.0 github.com/bwmarrin/discordgo v0.28.1 github.com/joho/godotenv v1.5.1 go.mongodb.org/mongo-driver/v2 v2.1.0 diff --git a/go.sum b/go.sum index 3328691..223c5a0 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/LoperLee/golang-hangul-toolkit v1.1.0 h1:JEyLpLyA2hDQwWY9oCprHClnKIdkYVOSJzAat2uFX/A= +github.com/LoperLee/golang-hangul-toolkit v1.1.0/go.mod h1:CDbZ23/IL4v2ovWIOb7xDEiFcSc0pIIbbYTpg+gP+Sk= github.com/bwmarrin/discordgo v0.28.1 h1:gXsuo2GBO7NbR6uqmrrBDplPUx2T3nzu775q/Rd1aG4= github.com/bwmarrin/discordgo v0.28.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= diff --git a/handler/messageCreate.go b/handler/messageCreate.go index a42b3f6..1401949 100644 --- a/handler/messageCreate.go +++ b/handler/messageCreate.go @@ -25,7 +25,7 @@ func MessageCreate(s *discordgo.Session, m *discordgo.MessageCreate) { if strings.HasPrefix(m.Content, config.Bot.Prefix) { content := strings.TrimPrefix(m.Content, config.Bot.Prefix) - command := commands.Discommand.Aliases[content] + command := commands.Discommand.Aliases[strings.Split(content, " ")[0]] if m.Author.ID == config.Train.UserID { if _, err := databases.Texts.InsertOne(context.TODO(), databases.InsertText{ diff --git a/utils/regexp.go b/utils/regexp.go new file mode 100644 index 0000000..3a2a85b --- /dev/null +++ b/utils/regexp.go @@ -0,0 +1,5 @@ +package utils + +import "regexp" + +var ExtractQuotedText *regexp.Regexp = regexp.MustCompile("[\"'`](.*?)[\"'`]")