feat: Add register command

This commit is contained in:
Siwoo Jeon 2025-06-19 21:12:07 +09:00
parent 71fa0b506a
commit 05f7bd07b7
Signed by: migan
GPG key ID: 036E9A8C5E8E48DA
9 changed files with 206 additions and 9 deletions

View file

@ -12,16 +12,18 @@ DATABASE_AUTH_SOURCE= # 기본 값: admin
## 필수 값 ## 필수 값
DATABASE_NAME= DATABASE_NAME=
## 데이터베이스 마이그레이션용
PREVIOUS_DATABASE_URL=
# 봇 # 봇
BOT_TOKEN= BOT_TOKEN=
BOT_PREFIX= BOT_PREFIX=
BOT_OWNER_ID= BOT_OWNER_ID=
# 서비스
SERVICE_PRIVACY_POLICY_URL=
SERVICE_TERM_OF_SERVICE_URL=
# 챗봇 # 챗봇
CHATBOT_GEMINI_TOKEN= CHATBOT_GEMINI_TOKEN=
CHATBOT_GEMINI_PROMPT_PATH= CHATBOT_GEMINI_PROMPT_PATH=
CHATBOT_GEMINI_MODEL= # 기본 값은 gemini-2.5-flash CHATBOT_GEMINI_MODEL= # 기본 값은 gemini-2.5-flash
CHATBOT_TRAIN_USER_ID= # 필수 아님 CHATBOT_TRAIN_USER_ID= # 필수 아님

View file

@ -187,12 +187,15 @@ func (d *DiscommandStruct) ChatInputRun(name string, s *discordgo.Session, inter
} }
} }
func (d *DiscommandStruct) ComponentRun(s *discordgo.Session, i *discordgo.InteractionCreate) { func (d *DiscommandStruct) ComponentRun(s *discordgo.Session, inter *discordgo.InteractionCreate) {
i := &utils.InteractionCreate{
InteractionCreate: inter,
Session: s,
}
i.InteractionCreate.User = utils.GetInteractionUser(inter)
data := &ComponentContext{ data := &ComponentContext{
Inter: &utils.InteractionCreate{ Inter: i,
InteractionCreate: i,
Session: s,
},
} }
for _, c := range d.Components { for _, c := range d.Components {

70
commands/register.go Normal file
View file

@ -0,0 +1,70 @@
package commands
import (
"fmt"
"git.wh64.net/muffin/goMuffin/configs"
"git.wh64.net/muffin/goMuffin/databases"
"git.wh64.net/muffin/goMuffin/utils"
"github.com/bwmarrin/discordgo"
)
var RegisterCommand *Command = &Command{
ApplicationCommand: &discordgo.ApplicationCommand{
Name: "가입",
Description: "이 봇에 가입해요.",
},
DetailedDescription: &DetailedDescription{
Usage: fmt.Sprintf("%s가입", configs.Config.Bot.Prefix),
},
Category: General,
RegisterMessageCommand: true,
RegisterApplicationCommand: true,
MessageRun: func(ctx *MsgContext) {
registerRun(ctx.Msg, ctx.Msg.Author.ID, ctx.Msg.Session.State.User.Username)
},
ChatInputRun: func(ctx *ChatInputContext) {
registerRun(ctx.Inter, ctx.Inter.User.ID, ctx.Inter.Session.State.User.Username)
},
}
func registerRun(m any, userId, botName string) {
if databases.Database.IsUser(userId) {
utils.NewMessageSender(m).
AddComponents(utils.GetErrorContainer(discordgo.TextDisplay{Content: fmt.Sprintf("당신은 이미 가입되어있어요. 만약 탈퇴를 원하시면 %s탈퇴를 이용해주세요.", configs.Config.Bot.Prefix)})).
SetComponentsV2(true).
SetReply(true).
Send()
return
}
utils.NewMessageSender(m).
AddComponents(discordgo.Container{
Components: []discordgo.MessageComponent{
discordgo.TextDisplay{
Content: fmt.Sprintf("### %s 가입\n해당 서비스에 가입하실려면 [개인정보처리방침](%s)과 [서비스 이용약관](%s)에 동의해야해요.",
botName,
configs.Config.Service.PrivacyPolicyURL,
configs.Config.Service.TermOfServiceURL,
),
},
discordgo.ActionsRow{
Components: []discordgo.MessageComponent{
discordgo.Button{
CustomID: utils.MakeServiceAgree(userId),
Label: "동의 후 가입",
Style: discordgo.SuccessButton,
},
discordgo.Button{
CustomID: utils.MakeServiceDisagree(userId),
Label: "취소",
Style: discordgo.DangerButton,
},
},
},
},
}).
SetComponentsV2(true).
SetReply(true).
Send()
}

73
components/register.go Normal file
View file

@ -0,0 +1,73 @@
package components
import (
"context"
"fmt"
"log"
"strings"
"time"
"git.wh64.net/muffin/goMuffin/commands"
"git.wh64.net/muffin/goMuffin/databases"
"git.wh64.net/muffin/goMuffin/utils"
"github.com/bwmarrin/discordgo"
)
var RegisterComponent *commands.Component = &commands.Component{
Parse: func(ctx *commands.ComponentContext) bool {
customId := ctx.Inter.MessageComponentData().CustomID
if !strings.HasPrefix(customId, utils.ServiceAgree) && !strings.HasPrefix(customId, utils.ServiceDisagree) {
return false
}
if ctx.Inter.User.ID != utils.GetServicesUserId(customId) {
return false
}
return true
},
Run: func(ctx *commands.ComponentContext) {
ctx.Inter.DeferUpdate()
customId := ctx.Inter.MessageComponentData().CustomID
flags := discordgo.MessageFlagsIsComponentsV2
switch {
case strings.HasPrefix(customId, utils.ServiceAgree):
_, err := databases.Database.Users.InsertOne(context.TODO(), databases.InsertUser{
UserId: ctx.Inter.User.ID,
CreatedAt: time.Now(),
})
if err != nil {
log.Println(err)
ctx.Inter.EditReply(&utils.InteractionEdit{
Flags: &flags,
Components: &[]discordgo.MessageComponent{
utils.GetErrorContainer(discordgo.TextDisplay{
Content: "가입을 하다가 오류가 생겼어요.",
}),
},
})
return
}
ctx.Inter.EditReply(&utils.InteractionEdit{
Flags: &flags,
Components: &[]discordgo.MessageComponent{
utils.GetSuccessContainer(discordgo.TextDisplay{
Content: fmt.Sprintf("가입을 했어요. 이제 %s의 모든 기능을 사용할 수 있어요.", ctx.Inter.Session.State.User.Username),
}),
},
})
return
case strings.HasPrefix(customId, utils.ServiceDisagree):
ctx.Inter.EditReply(&utils.InteractionEdit{
Flags: &flags,
Components: &[]discordgo.MessageComponent{
utils.GetDeclineContainer(discordgo.TextDisplay{
Content: "가입을 거부했어요.",
}),
},
})
return
}
},
}

View file

@ -40,11 +40,17 @@ type databaseConfig struct {
Port int Port int
} }
type serviceConfig struct {
PrivacyPolicyURL string
TermOfServiceURL string
}
// MuffinConfig for Muffin bot // MuffinConfig for Muffin bot
type MuffinConfig struct { type MuffinConfig struct {
Bot botConfig Bot botConfig
Database databaseConfig Database databaseConfig
Chatbot chatbotConfig Chatbot chatbotConfig
Service serviceConfig
// Deprecated: Use Chatbot.Train // Deprecated: Use Chatbot.Train
Train trainConfig Train trainConfig
@ -111,4 +117,9 @@ func setConfig(config *MuffinConfig) {
} }
config.Train = config.Chatbot.Train config.Train = config.Chatbot.Train
config.Service = serviceConfig{
PrivacyPolicyURL: getRequiredValue("SERVICE_PRIVACY_POLICY_URL"),
TermOfServiceURL: getRequiredValue("SERVICE_TERM_OF_SERVICE_URL"),
}
} }

View file

@ -32,9 +32,11 @@ func init() {
go commands.Discommand.LoadCommand(commands.ReloadPromptCommand) go commands.Discommand.LoadCommand(commands.ReloadPromptCommand)
go commands.Discommand.LoadCommand(commands.SwitchModeCommand) go commands.Discommand.LoadCommand(commands.SwitchModeCommand)
go commands.Discommand.LoadCommand(commands.ChatCommand) go commands.Discommand.LoadCommand(commands.ChatCommand)
go commands.Discommand.LoadCommand(commands.RegisterCommand)
go commands.Discommand.LoadComponent(components.DeleteLearnedDataComponent) go commands.Discommand.LoadComponent(components.DeleteLearnedDataComponent)
go commands.Discommand.LoadComponent(components.PaginationEmbedComponent) go commands.Discommand.LoadComponent(components.PaginationEmbedComponent)
go commands.Discommand.LoadComponent(components.RegisterComponent)
go commands.Discommand.LoadModal(modals.PaginationEmbedModal) go commands.Discommand.LoadModal(modals.PaginationEmbedModal)
} }

View file

@ -16,6 +16,9 @@ const (
PaginationEmbedNext = "#muffin-pages/next$" PaginationEmbedNext = "#muffin-pages/next$"
PaginationEmbedModal = "#muffin-pages/modal$" PaginationEmbedModal = "#muffin-pages/modal$"
PaginationEmbedSetPage = "#muffin-pages/modal/set$" PaginationEmbedSetPage = "#muffin-pages/modal/set$"
ServiceAgree = "#muffin/serviceAgree@"
ServiceDisagree = "#muffin/serviceDisagree@"
) )
func MakeDeleteLearnedData(id string, number int, userId string) string { func MakeDeleteLearnedData(id string, number int, userId string) string {
@ -73,3 +76,22 @@ func GetPaginationEmbedId(customId string) string {
func GetPaginationEmbedUserId(id string) string { func GetPaginationEmbedUserId(id string) string {
return RegexpPaginationEmbedId.FindAllStringSubmatch(id, 1)[0][1] return RegexpPaginationEmbedId.FindAllStringSubmatch(id, 1)[0][1]
} }
func MakeServiceAgree(userId string) string {
return fmt.Sprintf("%s%s", ServiceAgree, userId)
}
func MakeServiceDisagree(userId string) string {
return fmt.Sprintf("%s%s", ServiceDisagree, userId)
}
func GetServicesUserId(customId string) string {
switch {
case strings.HasPrefix(customId, ServiceAgree):
return customId[len(ServiceAgree):]
case strings.HasPrefix(customId, ServiceDisagree):
return customId[len(ServiceDisagree):]
default:
return customId
}
}

View file

@ -25,6 +25,19 @@ func GetErrorContainer(components ...discordgo.MessageComponent) *discordgo.Cont
return c return c
} }
func GetDeclineContainer(components ...discordgo.MessageComponent) *discordgo.Container {
c := &discordgo.Container{
Components: []discordgo.MessageComponent{
discordgo.TextDisplay{
Content: "### ❌ 거부",
},
},
}
c.Components = append(c.Components, components...)
return c
}
func GetSuccessContainer(components ...discordgo.MessageComponent) *discordgo.Container { func GetSuccessContainer(components ...discordgo.MessageComponent) *discordgo.Container {
c := &discordgo.Container{ c := &discordgo.Container{
Components: []discordgo.MessageComponent{ Components: []discordgo.MessageComponent{

View file

@ -53,6 +53,7 @@ func GetInteractionOptions(i *discordgo.InteractionCreate) map[string]*discordgo
return optsMap return optsMap
} }
// NOTE: It's only can ApplicationCommand
func GetInteractionUser(i *discordgo.InteractionCreate) *discordgo.User { func GetInteractionUser(i *discordgo.InteractionCreate) *discordgo.User {
if i.Member != nil { if i.Member != nil {
return i.Member.User return i.Member.User