diff --git a/.env.example b/.env.example index 3e8b368..26dee23 100644 --- a/.env.example +++ b/.env.example @@ -12,16 +12,18 @@ DATABASE_AUTH_SOURCE= # 기본 값: admin ## 필수 값 DATABASE_NAME= -## 데이터베이스 마이그레이션용 -PREVIOUS_DATABASE_URL= - # 봇 BOT_TOKEN= BOT_PREFIX= BOT_OWNER_ID= + +# 서비스 +SERVICE_PRIVACY_POLICY_URL= +SERVICE_TERM_OF_SERVICE_URL= + # 챗봇 CHATBOT_GEMINI_TOKEN= CHATBOT_GEMINI_PROMPT_PATH= CHATBOT_GEMINI_MODEL= # 기본 값은 gemini-2.5-flash -CHATBOT_TRAIN_USER_ID= # 필수 아님 \ No newline at end of file +CHATBOT_TRAIN_USER_ID= # 필수값 아님 \ No newline at end of file diff --git a/commands/discommand.go b/commands/discommand.go index b550888..539b25b 100644 --- a/commands/discommand.go +++ b/commands/discommand.go @@ -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{ - Inter: &utils.InteractionCreate{ - InteractionCreate: i, - Session: s, - }, + Inter: i, } for _, c := range d.Components { diff --git a/commands/register.go b/commands/register.go new file mode 100644 index 0000000..e8b21f2 --- /dev/null +++ b/commands/register.go @@ -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() +} diff --git a/components/register.go b/components/register.go new file mode 100644 index 0000000..4298be5 --- /dev/null +++ b/components/register.go @@ -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 + } + }, +} diff --git a/configs/config.go b/configs/config.go index 21e272d..7b52389 100644 --- a/configs/config.go +++ b/configs/config.go @@ -40,11 +40,17 @@ type databaseConfig struct { Port int } +type serviceConfig struct { + PrivacyPolicyURL string + TermOfServiceURL string +} + // MuffinConfig for Muffin bot type MuffinConfig struct { Bot botConfig Database databaseConfig Chatbot chatbotConfig + Service serviceConfig // Deprecated: Use Chatbot.Train Train trainConfig @@ -111,4 +117,9 @@ func setConfig(config *MuffinConfig) { } config.Train = config.Chatbot.Train + + config.Service = serviceConfig{ + PrivacyPolicyURL: getRequiredValue("SERVICE_PRIVACY_POLICY_URL"), + TermOfServiceURL: getRequiredValue("SERVICE_TERM_OF_SERVICE_URL"), + } } diff --git a/main.go b/main.go index 1869ee5..73b8bfd 100644 --- a/main.go +++ b/main.go @@ -32,9 +32,11 @@ func init() { go commands.Discommand.LoadCommand(commands.ReloadPromptCommand) go commands.Discommand.LoadCommand(commands.SwitchModeCommand) go commands.Discommand.LoadCommand(commands.ChatCommand) + go commands.Discommand.LoadCommand(commands.RegisterCommand) go commands.Discommand.LoadComponent(components.DeleteLearnedDataComponent) go commands.Discommand.LoadComponent(components.PaginationEmbedComponent) + go commands.Discommand.LoadComponent(components.RegisterComponent) go commands.Discommand.LoadModal(modals.PaginationEmbedModal) } diff --git a/utils/customIds.go b/utils/customIds.go index 8cff163..b135a54 100644 --- a/utils/customIds.go +++ b/utils/customIds.go @@ -16,6 +16,9 @@ const ( PaginationEmbedNext = "#muffin-pages/next$" PaginationEmbedModal = "#muffin-pages/modal$" PaginationEmbedSetPage = "#muffin-pages/modal/set$" + + ServiceAgree = "#muffin/serviceAgree@" + ServiceDisagree = "#muffin/serviceDisagree@" ) func MakeDeleteLearnedData(id string, number int, userId string) string { @@ -73,3 +76,22 @@ func GetPaginationEmbedId(customId string) string { func GetPaginationEmbedUserId(id string) string { 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 + } +} diff --git a/utils/embed.go b/utils/embed.go index 861d260..946466f 100644 --- a/utils/embed.go +++ b/utils/embed.go @@ -25,6 +25,19 @@ func GetErrorContainer(components ...discordgo.MessageComponent) *discordgo.Cont 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 { c := &discordgo.Container{ Components: []discordgo.MessageComponent{ diff --git a/utils/interactions.go b/utils/interactions.go index 3f0dda7..4fd9acd 100644 --- a/utils/interactions.go +++ b/utils/interactions.go @@ -53,6 +53,7 @@ func GetInteractionOptions(i *discordgo.InteractionCreate) map[string]*discordgo return optsMap } +// NOTE: It's only can ApplicationCommand func GetInteractionUser(i *discordgo.InteractionCreate) *discordgo.User { if i.Member != nil { return i.Member.User