From 68e6a1183bc53c0a7d35c97569fa63ef8f9c812b Mon Sep 17 00:00:00 2001 From: Aqua-218 Date: Wed, 28 Jan 2026 21:21:24 +0900 Subject: [PATCH 01/15] =?UTF-8?q?pin=E3=82=B3=E3=83=9E=E3=83=B3=E3=83=89?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/internal/bot/command/general/pin.go | 85 +++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 src/internal/bot/command/general/pin.go diff --git a/src/internal/bot/command/general/pin.go b/src/internal/bot/command/general/pin.go new file mode 100644 index 0000000..41cf349 --- /dev/null +++ b/src/internal/bot/command/general/pin.go @@ -0,0 +1,85 @@ +package general + +import ( + "time" + "unibot/internal" + + "github.com/bwmarrin/discordgo" +) + +func LoadPinCommandContext() *discordgo.ApplicationCommand { + perm := int64(discordgo.PermissionManageMessages) + dm := false + contexts := []discordgo.InteractionContextType{discordgo.InteractionContextGuild} + return &discordgo.ApplicationCommand{ + Name: "pin", + Description: "メッセージをピン留めします。", + DefaultMemberPermissions: &perm, + DMPermission: &dm, + Contexts: &contexts, + } +} + +func Pin(ctx *internal.BotContext, s *discordgo.Session, i *discordgo.InteractionCreate) { + config := ctx.Config + + if !hasPinPermission(s, i) { + replyPinError(s, i, config, "権限がありません", "この操作を実行する権限がありません。") + return + } + + showPinModal(s, i) +} + +func showPinModal(s *discordgo.Session, i *discordgo.InteractionCreate) { + _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseModal, + Data: &discordgo.InteractionResponseData{ + CustomID: "pin_message", + Title: "メッセージのピン留め", + Components: []discordgo.MessageComponent{ + discordgo.ActionsRow{Components: []discordgo.MessageComponent{ + discordgo.TextInput{ + CustomID: "message", + Label: "投稿内容", + Style: discordgo.TextInputParagraph, + Placeholder: "投稿内容を入力してください。すでにPinされたメッセージがある場合は上書きされます。", + Required: true, + }, + }}, + }, + }, + }) +} + +func hasPinPermission(s *discordgo.Session, i *discordgo.InteractionCreate) bool { + if i.Member == nil || i.Member.User == nil { + return false + } + perms, err := s.UserChannelPermissions(i.Member.User.ID, i.ChannelID) + if err != nil { + return false + } + return perms&discordgo.PermissionManageMessages != 0 +} + +func replyPinError(s *discordgo.Session, i *discordgo.InteractionCreate, config *internal.Config, title, description string) { + _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Embeds: []*discordgo.MessageEmbed{ + { + Title: title, + Description: description, + Color: config.Colors.Error, + Footer: &discordgo.MessageEmbedFooter{ + Text: "Requested by " + i.Member.DisplayName(), + IconURL: i.Member.AvatarURL(""), + }, + Timestamp: time.Now().Format(time.RFC3339), + }, + }, + Flags: discordgo.MessageFlagsEphemeral, + }, + }) +} From 20b306aeb83cbd578a34d95a754f59f3a4a824eb Mon Sep 17 00:00:00 2001 From: Aqua-218 Date: Wed, 28 Jan 2026 21:21:29 +0900 Subject: [PATCH 02/15] =?UTF-8?q?unpin=E3=82=B3=E3=83=9E=E3=83=B3=E3=83=89?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/internal/bot/command/general/unpin.go | 68 +++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 src/internal/bot/command/general/unpin.go diff --git a/src/internal/bot/command/general/unpin.go b/src/internal/bot/command/general/unpin.go new file mode 100644 index 0000000..c549432 --- /dev/null +++ b/src/internal/bot/command/general/unpin.go @@ -0,0 +1,68 @@ +package general + +import ( + "time" + "unibot/internal" + "unibot/internal/repository" + + "github.com/bwmarrin/discordgo" +) + +func LoadUnpinCommandContext() *discordgo.ApplicationCommand { + perm := int64(discordgo.PermissionManageMessages) + dm := false + contexts := []discordgo.InteractionContextType{discordgo.InteractionContextGuild} + return &discordgo.ApplicationCommand{ + Name: "unpin", + Description: "ピン留めを解除します。", + DefaultMemberPermissions: &perm, + DMPermission: &dm, + Contexts: &contexts, + } +} + +func Unpin(ctx *internal.BotContext, s *discordgo.Session, i *discordgo.InteractionCreate) { + config := ctx.Config + + if !hasPinPermission(s, i) { + replyPinError(s, i, config, "権限がありません", "この操作を実行する権限がありません。") + return + } + + repo := repository.NewPinSettingRepository(ctx.DB) + settings, err := repo.GetByChannelID(i.ChannelID) + if err != nil { + replyPinError(s, i, config, "エラーが発生しました", "ピン留めの解除中にエラーが発生しました。") + return + } + if len(settings) == 0 { + _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Content: "このチャンネルにはピン留めされたメッセージがありません。", + Flags: discordgo.MessageFlagsEphemeral, + }, + }) + return + } + + err = repo.DeleteByChannelID(i.ChannelID) + if err != nil { + replyPinError(s, i, config, "エラーが発生しました", "ピン留めの解除中にエラーが発生しました。") + return + } + + successEmbed := &discordgo.MessageEmbed{ + Title: "ピン留めを解除しました", + Color: config.Colors.Success, + Timestamp: time.Now().Format(time.RFC3339), + } + + _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Embeds: []*discordgo.MessageEmbed{successEmbed}, + Flags: discordgo.MessageFlagsEphemeral, + }, + }) +} From f08166b4328089abeafa8cd6420b70b08f138b14 Mon Sep 17 00:00:00 2001 From: Aqua-218 Date: Wed, 28 Jan 2026 21:21:34 +0900 Subject: [PATCH 03/15] =?UTF-8?q?pin=E9=81=B8=E6=8A=9E=E3=82=B3=E3=83=9E?= =?UTF-8?q?=E3=83=B3=E3=83=89=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bot/command/general/pin_select.go | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 src/internal/bot/command/general/pin_select.go diff --git a/src/internal/bot/command/general/pin_select.go b/src/internal/bot/command/general/pin_select.go new file mode 100644 index 0000000..09ee07b --- /dev/null +++ b/src/internal/bot/command/general/pin_select.go @@ -0,0 +1,109 @@ +package general + +import ( + "time" + "unibot/internal" + "unibot/internal/model" + "unibot/internal/repository" + + "github.com/bwmarrin/discordgo" +) + +func LoadPinSelectCommandContext() *discordgo.ApplicationCommand { + contexts := []discordgo.InteractionContextType{discordgo.InteractionContextGuild} + return &discordgo.ApplicationCommand{ + Name: "Pinするメッセージを選択", + Type: discordgo.MessageApplicationCommand, + Contexts: &contexts, + } +} + +func PinSelect(ctx *internal.BotContext, s *discordgo.Session, i *discordgo.InteractionCreate) { + config := ctx.Config + + if !hasPinPermission(s, i) { + replyPinError(s, i, config, "権限がありません", "この操作を実行する権限がありません。") + return + } + + data := i.ApplicationCommandData() + if data.Resolved == nil || data.Resolved.Messages == nil { + replyPinError(s, i, config, "エラー", "メッセージの取得に失敗しました。") + return + } + + targetMsg, ok := data.Resolved.Messages[data.TargetID] + if !ok || targetMsg == nil { + replyPinError(s, i, config, "エラー", "メッセージの取得に失敗しました。") + return + } + + if targetMsg.Author != nil && targetMsg.Author.Bot { + replyPinError(s, i, config, "エラー", "ボットのメッセージはピン留めできません。") + return + } + + channel, err := s.State.Channel(i.ChannelID) + if err != nil { + channel, _ = s.Channel(i.ChannelID) + } + if channel == nil || channel.Type == discordgo.ChannelTypeDM || channel.Type == discordgo.ChannelTypeGroupDM { + replyPinError(s, i, config, "エラー", "このチャンネルではメッセージをピン留めできません。") + return + } + + repo := repository.NewPinSettingRepository(ctx.DB) + settings, err := repo.GetByChannelID(i.ChannelID) + if err != nil { + replyPinError(s, i, config, "エラー", "ピン留めの取得に失敗しました。") + return + } + if len(settings) > 0 { + replyPinError(s, i, config, "エラー", "このチャンネルには既にピン留めされたメッセージがあります。\n最初にそれを`/unpin`で解除してください。") + return + } + + embed := &discordgo.MessageEmbed{ + Description: targetMsg.Content, + Color: config.Colors.Success, + Footer: &discordgo.MessageEmbedFooter{ + Text: "Pinned Message", + }, + } + + sentMessage, err := s.ChannelMessageSendEmbed(i.ChannelID, embed) + if err != nil { + replyPinError(s, i, config, "エラー", "メッセージの送信に失敗しました。") + return + } + + setting := &model.PinSetting{ + ID: i.ChannelID, + URL: sentMessage.ID, + Title: "Pinned Message", + Content: targetMsg.Content, + GuildID: i.GuildID, + ChannelID: i.ChannelID, + } + + err = repo.Create(setting) + if err != nil { + replyPinError(s, i, config, "エラー", "ピン留めの保存に失敗しました。") + return + } + + successEmbed := &discordgo.MessageEmbed{ + Title: "メッセージをピン留めしました", + Description: "このメッセージは今後ピン留めされます。\nファイルは保存されないのでご注意ください。", + Color: config.Colors.Success, + Timestamp: time.Now().Format(time.RFC3339), + } + + _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Embeds: []*discordgo.MessageEmbed{successEmbed}, + Flags: discordgo.MessageFlagsEphemeral, + }, + }) +} From 7f22aa5fc2eaabb83563736dbee760182480b472 Mon Sep 17 00:00:00 2001 From: Aqua-218 Date: Wed, 28 Jan 2026 21:21:39 +0900 Subject: [PATCH 04/15] =?UTF-8?q?pin=E3=83=A2=E3=83=BC=E3=83=80=E3=83=AB?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/internal/bot/command/general/pin_modal.go | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 src/internal/bot/command/general/pin_modal.go diff --git a/src/internal/bot/command/general/pin_modal.go b/src/internal/bot/command/general/pin_modal.go new file mode 100644 index 0000000..efb71cd --- /dev/null +++ b/src/internal/bot/command/general/pin_modal.go @@ -0,0 +1,131 @@ +package general + +import ( + "time" + "unibot/internal" + "unibot/internal/model" + "unibot/internal/repository" + + "github.com/bwmarrin/discordgo" +) + +// HandlePinModalSubmit はピン留めモーダルの送信を処理する +func HandlePinModalSubmit(ctx *internal.BotContext, s *discordgo.Session, i *discordgo.InteractionCreate) bool { + data := i.ModalSubmitData() + if data.CustomID != "pin_message" { + return false + } + + config := ctx.Config + if !hasPinPermission(s, i) { + replyPinError(s, i, config, "権限がありません", "この操作を実行する権限がありません。") + return true + } + + message := getPinModalValue(data, "message") + if message == "" { + replyPinError(s, i, config, "入力エラー", "投稿内容を入力してください。") + return true + } + + channel, err := s.State.Channel(i.ChannelID) + if err != nil { + channel, _ = s.Channel(i.ChannelID) + } + if channel == nil || channel.Type == discordgo.ChannelTypeDM || channel.Type == discordgo.ChannelTypeGroupDM { + replyPinError(s, i, config, "エラー", "このチャンネルではメッセージを送信できません。") + return true + } + + embed := &discordgo.MessageEmbed{ + Description: message, + Color: config.Colors.Success, + Footer: &discordgo.MessageEmbedFooter{ + Text: "Pinned Message", + }, + } + + sentMessage, err := s.ChannelMessageSendEmbed(i.ChannelID, embed) + if err != nil { + replyPinError(s, i, config, "エラー", "メッセージの送信に失敗しました。") + return true + } + + repo := repository.NewPinSettingRepository(ctx.DB) + setting := &model.PinSetting{ + ID: i.ChannelID, + URL: sentMessage.ID, + Title: "Pinned Message", + Content: message, + GuildID: i.GuildID, + ChannelID: i.ChannelID, + } + + if err := repo.Update(setting); err != nil { + if err := repo.Create(setting); err != nil { + replyPinError(s, i, config, "エラー", "ピン留めの保存に失敗しました。") + return true + } + } + + _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Content: "メッセージをピン留めしました: `" + message + "`", + Flags: discordgo.MessageFlagsEphemeral, + }, + }) + + return true +} + +func getPinModalValue(data discordgo.ModalSubmitInteractionData, customID string) string { + for _, comp := range data.Components { + switch row := comp.(type) { + case *discordgo.ActionsRow: + for _, component := range row.Components { + if input, ok := component.(*discordgo.TextInput); ok { + if input.CustomID == customID { + return input.Value + } + } + if input, ok := component.(discordgo.TextInput); ok { + if input.CustomID == customID { + return input.Value + } + } + } + case discordgo.ActionsRow: + for _, component := range row.Components { + if input, ok := component.(*discordgo.TextInput); ok { + if input.CustomID == customID { + return input.Value + } + } + if input, ok := component.(discordgo.TextInput); ok { + if input.CustomID == customID { + return input.Value + } + } + } + } + } + + return "" +} + +func replyPinSuccess(s *discordgo.Session, i *discordgo.InteractionCreate, config *internal.Config, title string) { + _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Embeds: []*discordgo.MessageEmbed{ + { + Title: title, + Color: config.Colors.Success, + Timestamp: time.Now().Format(time.RFC3339), + }, + }, + Flags: discordgo.MessageFlagsEphemeral, + }, + }) +} From 1a79682e9d9316e6a8dba4b64ba26c5b8065a42d Mon Sep 17 00:00:00 2001 From: Aqua-218 Date: Wed, 28 Jan 2026 21:21:43 +0900 Subject: [PATCH 05/15] =?UTF-8?q?pin=E8=A8=AD=E5=AE=9A=E5=89=8A=E9=99=A4?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/internal/repository/pin_setting.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/internal/repository/pin_setting.go b/src/internal/repository/pin_setting.go index 954ef2b..d67476e 100644 --- a/src/internal/repository/pin_setting.go +++ b/src/internal/repository/pin_setting.go @@ -70,3 +70,8 @@ func (r *PinSettingRepository) Update(pinSetting *model.PinSetting) error { func (r *PinSettingRepository) Delete(id string) error { return r.db.Delete(&model.PinSetting{}, "id = ?", id).Error } + +// ChannelIDでPinSettingを削除する関数 +func (r *PinSettingRepository) DeleteByChannelID(channelID string) error { + return r.db.Delete(&model.PinSetting{}, "channel_id = ?", channelID).Error +} From 38f9e5bdfa5780a39e2ce50f1658499df9afb708 Mon Sep 17 00:00:00 2001 From: Aqua-218 Date: Wed, 28 Jan 2026 21:21:48 +0900 Subject: [PATCH 06/15] =?UTF-8?q?pin=E3=83=A2=E3=83=BC=E3=83=80=E3=83=AB?= =?UTF-8?q?=E5=8F=97=E4=BB=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/internal/bot/handler/interaction.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/internal/bot/handler/interaction.go b/src/internal/bot/handler/interaction.go index 97ea38f..eb35235 100644 --- a/src/internal/bot/handler/interaction.go +++ b/src/internal/bot/handler/interaction.go @@ -4,6 +4,8 @@ import ( "strings" "unibot/internal" "unibot/internal/bot/command" + "unibot/internal/bot/command/general" + "unibot/internal/bot/command/general/schedule" "unibot/internal/bot/messageComponent" "github.com/bwmarrin/discordgo" @@ -16,6 +18,8 @@ func InteractionCreate(ctx *internal.BotContext) func(s *discordgo.Session, i *d handleApplicationCommand(ctx, s, i) case discordgo.InteractionMessageComponent: handleMessageComponent(ctx, s, i) + case discordgo.InteractionModalSubmit: + handleModalSubmit(ctx, s, i) } } } @@ -41,3 +45,12 @@ func handleMessageComponent(ctx *internal.BotContext, s *discordgo.Session, i *d } } +func handleModalSubmit(ctx *internal.BotContext, s *discordgo.Session, i *discordgo.InteractionCreate) { + if schedule.HandleModalSubmit(ctx, s, i) { + return + } + if general.HandlePinModalSubmit(ctx, s, i) { + return + } +} + From 142cceaab49706b9191ba1e836b60ab1e4e6b68b Mon Sep 17 00:00:00 2001 From: Aqua-218 Date: Wed, 28 Jan 2026 21:21:53 +0900 Subject: [PATCH 07/15] =?UTF-8?q?pin=E5=86=8D=E9=80=81=E5=87=A6=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/internal/bot/handler/messageCreate.go | 56 +++++++++++++++++++++-- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/src/internal/bot/handler/messageCreate.go b/src/internal/bot/handler/messageCreate.go index 460a936..3cdb6e2 100644 --- a/src/internal/bot/handler/messageCreate.go +++ b/src/internal/bot/handler/messageCreate.go @@ -3,6 +3,7 @@ package handler import ( "log" "regexp" + "strings" "unibot/internal" "unibot/internal/bot/voice" "unibot/internal/repository" @@ -14,13 +15,16 @@ import ( func MessageCreate(ctx *internal.BotContext) func(s *discordgo.Session, r *discordgo.MessageCreate) { return func(s *discordgo.Session, r *discordgo.MessageCreate) { - // Ignore bot itself - if r.Author.ID == s.State.User.ID { + // Ignore DM + if r.GuildID == "" { return } - // Ignore DM - if r.GuildID == "" { + // ----- Pin ----- + resendPinnedMessage(ctx, s, r) + + // Ignore bot itself + if r.Author.ID == s.State.User.ID { return } @@ -82,6 +86,50 @@ func MessageCreate(ctx *internal.BotContext) func(s *discordgo.Session, r *disco } } +func resendPinnedMessage(ctx *internal.BotContext, s *discordgo.Session, r *discordgo.MessageCreate) { + // 自分のピン留めメッセージの場合は無視 + if r.Author != nil && r.Author.ID == s.State.User.ID { + if len(r.Embeds) == 0 { + return + } + if r.Embeds[0].Footer != nil && strings.Contains(r.Embeds[0].Footer.Text, "Pinned Message") { + return + } + } + + repo := repository.NewPinSettingRepository(ctx.DB) + settings, err := repo.GetByChannelID(r.ChannelID) + if err != nil || len(settings) == 0 { + return + } + + setting := settings[0] + if setting.Content == "" { + return + } + + if setting.URL != "" { + _ = s.ChannelMessageDelete(r.ChannelID, setting.URL) + } + + embed := &discordgo.MessageEmbed{ + Description: setting.Content, + Color: ctx.Config.Colors.Success, + Footer: &discordgo.MessageEmbedFooter{ + Text: "Pinned Message", + }, + } + + sentMessage, err := s.ChannelMessageSendEmbed(r.ChannelID, embed) + if err != nil { + return + } + + setting.URL = sentMessage.ID + setting.Title = "Pinned Message" + _ = repo.Update(setting) +} + // 正規表現パターン var ( codeBlockRegex = regexp.MustCompile("(?s)```(\\w*)\\n.*?```") From fcf63e8985fadfa553cbc000043be39150812a20 Mon Sep 17 00:00:00 2001 From: Aqua-218 Date: Wed, 28 Jan 2026 21:21:57 +0900 Subject: [PATCH 08/15] =?UTF-8?q?pin=E3=82=B3=E3=83=9E=E3=83=B3=E3=83=89?= =?UTF-8?q?=E7=99=BB=E9=8C=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/internal/bot/command/commands.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/internal/bot/command/commands.go b/src/internal/bot/command/commands.go index da2f125..5274263 100644 --- a/src/internal/bot/command/commands.go +++ b/src/internal/bot/command/commands.go @@ -10,7 +10,11 @@ import ( var Commands = []*discordgo.ApplicationCommand{ general.LoadPingCommandContext(), general.LoadAboutCommandContext(), + general.LoadPinCommandContext(), + general.LoadUnpinCommandContext(), + general.LoadPinSelectCommandContext(), general.LoadTtsCommandContext(), general.LoadHelpCommandContext(), + general.LoadScheduleCommandContext(), admin.LoadMaintenanceCommandContext(), } From 5def9fbcb58b41c4e27c847bdfd3c8da85d1b6a0 Mon Sep 17 00:00:00 2001 From: Aqua-218 Date: Wed, 28 Jan 2026 21:22:02 +0900 Subject: [PATCH 09/15] =?UTF-8?q?pin=E3=83=8F=E3=83=B3=E3=83=89=E3=83=A9?= =?UTF-8?q?=E7=99=BB=E9=8C=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/internal/bot/command/registry.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/internal/bot/command/registry.go b/src/internal/bot/command/registry.go index f46c8d1..af2b432 100644 --- a/src/internal/bot/command/registry.go +++ b/src/internal/bot/command/registry.go @@ -11,6 +11,10 @@ import ( var Handlers = map[string]func(*internal.BotContext, *discordgo.Session, *discordgo.InteractionCreate){ "ping": general.Ping, "about": general.About, + "pin": general.Pin, + "unpin": general.Unpin, + "Pinするメッセージを選択": general.PinSelect, + "schedule": general.Schedule, "maintenance": admin.Maintenance, "tts": general.Tts, "help": general.Help, From b7bb44277d0d64c41cba4a365cf239f395685ed0 Mon Sep 17 00:00:00 2001 From: Aqua-218 Date: Wed, 28 Jan 2026 21:55:14 +0900 Subject: [PATCH 10/15] =?UTF-8?q?pin=E3=82=B3=E3=83=9E=E3=83=B3=E3=83=89?= =?UTF-8?q?=E3=81=8B=E3=82=89=E3=82=B9=E3=82=B1=E3=82=B8=E3=83=A5=E3=83=BC?= =?UTF-8?q?=E3=83=AB=E6=A9=9F=E8=83=BD=E3=82=92=E5=89=8A=E9=99=A4=E3=81=97?= =?UTF-8?q?=E3=80=81=E3=83=94=E3=83=B3=E3=82=A8=E3=83=A9=E3=83=BC=E5=BF=9C?= =?UTF-8?q?=E7=AD=94=E3=81=AB=E3=83=AA=E3=82=AF=E3=82=A8=E3=82=B9=E3=83=88?= =?UTF-8?q?=E8=80=85=E6=83=85=E5=A0=B1=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/internal/bot/command/general/pin.go | 14 ++-- src/internal/bot/command/general/pin_modal.go | 67 ++++++++----------- src/internal/bot/command/registry.go | 1 - src/internal/bot/handler/interaction.go | 4 -- src/internal/bot/handler/messageCreate.go | 5 ++ src/internal/repository/pin_setting_test.go | 26 +++++++ 6 files changed, 70 insertions(+), 47 deletions(-) diff --git a/src/internal/bot/command/general/pin.go b/src/internal/bot/command/general/pin.go index 41cf349..6257213 100644 --- a/src/internal/bot/command/general/pin.go +++ b/src/internal/bot/command/general/pin.go @@ -64,6 +64,15 @@ func hasPinPermission(s *discordgo.Session, i *discordgo.InteractionCreate) bool } func replyPinError(s *discordgo.Session, i *discordgo.InteractionCreate, config *internal.Config, title, description string) { + footer := &discordgo.MessageEmbedFooter{Text: "Requested by Unknown"} + if i.Member != nil { + footer.Text = "Requested by " + i.Member.DisplayName() + footer.IconURL = i.Member.AvatarURL("") + } else if i.User != nil { + footer.Text = "Requested by " + i.User.Username + footer.IconURL = i.User.AvatarURL("") + } + _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ @@ -72,10 +81,7 @@ func replyPinError(s *discordgo.Session, i *discordgo.InteractionCreate, config Title: title, Description: description, Color: config.Colors.Error, - Footer: &discordgo.MessageEmbedFooter{ - Text: "Requested by " + i.Member.DisplayName(), - IconURL: i.Member.AvatarURL(""), - }, + Footer: footer, Timestamp: time.Now().Format(time.RFC3339), }, }, diff --git a/src/internal/bot/command/general/pin_modal.go b/src/internal/bot/command/general/pin_modal.go index efb71cd..9316d56 100644 --- a/src/internal/bot/command/general/pin_modal.go +++ b/src/internal/bot/command/general/pin_modal.go @@ -1,7 +1,6 @@ package general import ( - "time" "unibot/internal" "unibot/internal/model" "unibot/internal/repository" @@ -61,11 +60,21 @@ func HandlePinModalSubmit(ctx *internal.BotContext, s *discordgo.Session, i *dis ChannelID: i.ChannelID, } - if err := repo.Update(setting); err != nil { + existing, err := repo.GetByChannelID(i.ChannelID) + if err != nil { + replyPinError(s, i, config, "エラー", "ピン留めの保存に失敗しました。") + return true + } + if len(existing) == 0 { if err := repo.Create(setting); err != nil { replyPinError(s, i, config, "エラー", "ピン留めの保存に失敗しました。") return true } + } else { + if err := repo.Update(setting); err != nil { + replyPinError(s, i, config, "エラー", "ピン留めの保存に失敗しました。") + return true + } } _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ @@ -83,30 +92,12 @@ func getPinModalValue(data discordgo.ModalSubmitInteractionData, customID string for _, comp := range data.Components { switch row := comp.(type) { case *discordgo.ActionsRow: - for _, component := range row.Components { - if input, ok := component.(*discordgo.TextInput); ok { - if input.CustomID == customID { - return input.Value - } - } - if input, ok := component.(discordgo.TextInput); ok { - if input.CustomID == customID { - return input.Value - } - } + if value := getTextInputValue(row.Components, customID); value != "" { + return value } case discordgo.ActionsRow: - for _, component := range row.Components { - if input, ok := component.(*discordgo.TextInput); ok { - if input.CustomID == customID { - return input.Value - } - } - if input, ok := component.(discordgo.TextInput); ok { - if input.CustomID == customID { - return input.Value - } - } + if value := getTextInputValue(row.Components, customID); value != "" { + return value } } } @@ -114,18 +105,18 @@ func getPinModalValue(data discordgo.ModalSubmitInteractionData, customID string return "" } -func replyPinSuccess(s *discordgo.Session, i *discordgo.InteractionCreate, config *internal.Config, title string) { - _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ - Type: discordgo.InteractionResponseChannelMessageWithSource, - Data: &discordgo.InteractionResponseData{ - Embeds: []*discordgo.MessageEmbed{ - { - Title: title, - Color: config.Colors.Success, - Timestamp: time.Now().Format(time.RFC3339), - }, - }, - Flags: discordgo.MessageFlagsEphemeral, - }, - }) +func getTextInputValue(components []discordgo.MessageComponent, customID string) string { + for _, component := range components { + switch input := component.(type) { + case *discordgo.TextInput: + if input.CustomID == customID { + return input.Value + } + case discordgo.TextInput: + if input.CustomID == customID { + return input.Value + } + } + } + return "" } diff --git a/src/internal/bot/command/registry.go b/src/internal/bot/command/registry.go index af2b432..683cdb7 100644 --- a/src/internal/bot/command/registry.go +++ b/src/internal/bot/command/registry.go @@ -14,7 +14,6 @@ var Handlers = map[string]func(*internal.BotContext, *discordgo.Session, *discor "pin": general.Pin, "unpin": general.Unpin, "Pinするメッセージを選択": general.PinSelect, - "schedule": general.Schedule, "maintenance": admin.Maintenance, "tts": general.Tts, "help": general.Help, diff --git a/src/internal/bot/handler/interaction.go b/src/internal/bot/handler/interaction.go index eb35235..d69c69b 100644 --- a/src/internal/bot/handler/interaction.go +++ b/src/internal/bot/handler/interaction.go @@ -5,7 +5,6 @@ import ( "unibot/internal" "unibot/internal/bot/command" "unibot/internal/bot/command/general" - "unibot/internal/bot/command/general/schedule" "unibot/internal/bot/messageComponent" "github.com/bwmarrin/discordgo" @@ -46,9 +45,6 @@ func handleMessageComponent(ctx *internal.BotContext, s *discordgo.Session, i *d } func handleModalSubmit(ctx *internal.BotContext, s *discordgo.Session, i *discordgo.InteractionCreate) { - if schedule.HandleModalSubmit(ctx, s, i) { - return - } if general.HandlePinModalSubmit(ctx, s, i) { return } diff --git a/src/internal/bot/handler/messageCreate.go b/src/internal/bot/handler/messageCreate.go index 3cdb6e2..abb7884 100644 --- a/src/internal/bot/handler/messageCreate.go +++ b/src/internal/bot/handler/messageCreate.go @@ -20,6 +20,11 @@ func MessageCreate(ctx *internal.BotContext) func(s *discordgo.Session, r *disco return } + // Authorが存在しないメッセージは無視 + if r.Author == nil { + return + } + // ----- Pin ----- resendPinnedMessage(ctx, s, r) diff --git a/src/internal/repository/pin_setting_test.go b/src/internal/repository/pin_setting_test.go index 122bd5c..30563a8 100644 --- a/src/internal/repository/pin_setting_test.go +++ b/src/internal/repository/pin_setting_test.go @@ -106,3 +106,29 @@ func TestPinSettingUpdateNonexistent(t *testing.T) { retrieved, _ := repo.GetByID("nonexistent") assert.NotNil(t, retrieved) } + +func TestPinSettingDeleteByChannelID(t *testing.T) { + db := setupTestDB(t) + repo := repository.NewPinSettingRepository(db) + + pin1 := &model.PinSetting{ID: "ch1", GuildID: "guild1", ChannelID: "ch1"} + pin2 := &model.PinSetting{ID: "ch2", GuildID: "guild1", ChannelID: "ch2"} + db.Create(pin1) + db.Create(pin2) + + err := repo.DeleteByChannelID("ch1") + assert.NoError(t, err) + + deleted, _ := repo.GetByID("ch1") + remaining, _ := repo.GetByID("ch2") + assert.Nil(t, deleted) + assert.NotNil(t, remaining) +} + +func TestPinSettingDeleteByChannelIDNonexistent(t *testing.T) { + db := setupTestDB(t) + repo := repository.NewPinSettingRepository(db) + + err := repo.DeleteByChannelID("missing") + assert.NoError(t, err) +} From 162fc71d8f0094c500863f1811780a659d91a371 Mon Sep 17 00:00:00 2001 From: Aqua-218 Date: Thu, 29 Jan 2026 20:54:02 +0900 Subject: [PATCH 11/15] =?UTF-8?q?PinSetting=E3=81=AE=E4=BD=9C=E6=88=90?= =?UTF-8?q?=E3=81=A8=E6=9B=B4=E6=96=B0=E6=99=82=E3=81=AB=E3=82=AE=E3=83=AB?= =?UTF-8?q?=E3=83=89=E3=81=AE=E5=AD=98=E5=9C=A8=E3=82=92=E7=A2=BA=E8=AA=8D?= =?UTF-8?q?=E3=81=99=E3=82=8B=E5=87=A6=E7=90=86=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/internal/repository/pin_setting.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/internal/repository/pin_setting.go b/src/internal/repository/pin_setting.go index d67476e..015bdba 100644 --- a/src/internal/repository/pin_setting.go +++ b/src/internal/repository/pin_setting.go @@ -21,6 +21,9 @@ func NewPinSettingRepository(db *gorm.DB) *PinSettingRepository { // PinSettingを作成する関数 func (r *PinSettingRepository) Create(pinSetting *model.PinSetting) error { + if err := r.ensureGuild(pinSetting); err != nil { + return err + } return r.db.Create(pinSetting).Error } @@ -63,6 +66,9 @@ func (r *PinSettingRepository) List() ([]*model.PinSetting, error) { // PinSettingを更新する関数 func (r *PinSettingRepository) Update(pinSetting *model.PinSetting) error { + if err := r.ensureGuild(pinSetting); err != nil { + return err + } return r.db.Save(pinSetting).Error } @@ -75,3 +81,11 @@ func (r *PinSettingRepository) Delete(id string) error { func (r *PinSettingRepository) DeleteByChannelID(channelID string) error { return r.db.Delete(&model.PinSetting{}, "channel_id = ?", channelID).Error } + +func (r *PinSettingRepository) ensureGuild(pinSetting *model.PinSetting) error { + if pinSetting == nil || pinSetting.GuildID == "" { + return nil + } + guild := model.Guild{DiscordID: pinSetting.GuildID} + return r.db.FirstOrCreate(&guild).Error +} From ab2214acaa0331b0e4c559087b507487aa957187 Mon Sep 17 00:00:00 2001 From: Aqua-218 Date: Wed, 28 Jan 2026 21:22:02 +0900 Subject: [PATCH 12/15] =?UTF-8?q?pin=E3=83=8F=E3=83=B3=E3=83=89=E3=83=A9?= =?UTF-8?q?=E7=99=BB=E9=8C=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/internal/bot/command/registry.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/internal/bot/command/registry.go b/src/internal/bot/command/registry.go index 683cdb7..b2b50df 100644 --- a/src/internal/bot/command/registry.go +++ b/src/internal/bot/command/registry.go @@ -9,12 +9,13 @@ import ( ) var Handlers = map[string]func(*internal.BotContext, *discordgo.Session, *discordgo.InteractionCreate){ - "ping": general.Ping, - "about": general.About, - "pin": general.Pin, - "unpin": general.Unpin, + "ping": general.Ping, + "about": general.About, + "pin": general.Pin, + "unpin": general.Unpin, "Pinするメッセージを選択": general.PinSelect, - "maintenance": admin.Maintenance, - "tts": general.Tts, - "help": general.Help, -} + "schedule": general.Schedule, + "maintenance": admin.Maintenance, + "tts": general.Tts, + "help": general.Help, +} \ No newline at end of file From b03263e59d0bc5ec696595e6d84cffe04d4cc26c Mon Sep 17 00:00:00 2001 From: Aqua-218 Date: Fri, 30 Jan 2026 00:12:41 +0900 Subject: [PATCH 13/15] =?UTF-8?q?=E3=83=94=E3=83=B3=E7=95=99=E3=82=81?= =?UTF-8?q?=E5=87=A6=E7=90=86=E3=81=AE=E6=94=B9=E5=96=84:=20=E6=97=A2?= =?UTF-8?q?=E5=AD=98=E3=81=AE=E3=83=94=E3=83=B3=E7=95=99=E3=82=81=E3=83=A1?= =?UTF-8?q?=E3=83=83=E3=82=BB=E3=83=BC=E3=82=B8=E3=82=92=E7=A2=BA=E8=AA=8D?= =?UTF-8?q?=E3=81=97=E3=80=81=E3=82=A8=E3=83=A9=E3=83=BC=E3=83=8F=E3=83=B3?= =?UTF-8?q?=E3=83=89=E3=83=AA=E3=83=B3=E3=82=B0=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/internal/bot/command/general/pin_modal.go | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/internal/bot/command/general/pin_modal.go b/src/internal/bot/command/general/pin_modal.go index 9316d56..184d4af 100644 --- a/src/internal/bot/command/general/pin_modal.go +++ b/src/internal/bot/command/general/pin_modal.go @@ -36,6 +36,17 @@ func HandlePinModalSubmit(ctx *internal.BotContext, s *discordgo.Session, i *dis return true } + repo := repository.NewPinSettingRepository(ctx.DB) + existing, err := repo.GetByChannelID(i.ChannelID) + if err != nil { + replyPinError(s, i, config, "エラー", "ピン留めの取得に失敗しました。") + return true + } + if len(existing) > 0 { + replyPinError(s, i, config, "エラー", "このチャンネルには既にピン留めされたメッセージがあります。\n最初にそれを`/unpin`で解除してください。") + return true + } + embed := &discordgo.MessageEmbed{ Description: message, Color: config.Colors.Success, @@ -50,7 +61,6 @@ func HandlePinModalSubmit(ctx *internal.BotContext, s *discordgo.Session, i *dis return true } - repo := repository.NewPinSettingRepository(ctx.DB) setting := &model.PinSetting{ ID: i.ChannelID, URL: sentMessage.ID, @@ -60,22 +70,10 @@ func HandlePinModalSubmit(ctx *internal.BotContext, s *discordgo.Session, i *dis ChannelID: i.ChannelID, } - existing, err := repo.GetByChannelID(i.ChannelID) - if err != nil { + if err := repo.Create(setting); err != nil { replyPinError(s, i, config, "エラー", "ピン留めの保存に失敗しました。") return true } - if len(existing) == 0 { - if err := repo.Create(setting); err != nil { - replyPinError(s, i, config, "エラー", "ピン留めの保存に失敗しました。") - return true - } - } else { - if err := repo.Update(setting); err != nil { - replyPinError(s, i, config, "エラー", "ピン留めの保存に失敗しました。") - return true - } - } _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, From e27125eb928c0549013aefb311f582b7a0cc215b Mon Sep 17 00:00:00 2001 From: Aqua-218 Date: Sat, 31 Jan 2026 15:25:38 +0900 Subject: [PATCH 14/15] =?UTF-8?q?schedule=E7=99=BB=E9=8C=B2=E5=89=8A?= =?UTF-8?q?=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/internal/bot/command/commands.go | 1 - src/internal/bot/command/registry.go | 1 - 2 files changed, 2 deletions(-) diff --git a/src/internal/bot/command/commands.go b/src/internal/bot/command/commands.go index 5274263..31824ae 100644 --- a/src/internal/bot/command/commands.go +++ b/src/internal/bot/command/commands.go @@ -15,6 +15,5 @@ var Commands = []*discordgo.ApplicationCommand{ general.LoadPinSelectCommandContext(), general.LoadTtsCommandContext(), general.LoadHelpCommandContext(), - general.LoadScheduleCommandContext(), admin.LoadMaintenanceCommandContext(), } diff --git a/src/internal/bot/command/registry.go b/src/internal/bot/command/registry.go index b2b50df..e57f5d5 100644 --- a/src/internal/bot/command/registry.go +++ b/src/internal/bot/command/registry.go @@ -14,7 +14,6 @@ var Handlers = map[string]func(*internal.BotContext, *discordgo.Session, *discor "pin": general.Pin, "unpin": general.Unpin, "Pinするメッセージを選択": general.PinSelect, - "schedule": general.Schedule, "maintenance": admin.Maintenance, "tts": general.Tts, "help": general.Help, From e07045d67c1099f681e2774af1cc88bb472758aa Mon Sep 17 00:00:00 2001 From: Aqua Date: Tue, 10 Feb 2026 15:20:14 +0000 Subject: [PATCH 15/15] =?UTF-8?q?=E3=83=94=E3=83=B3=E7=95=99=E3=82=81?= =?UTF-8?q?=E3=81=8A=E3=82=88=E3=81=B3=E3=82=A2=E3=83=B3=E3=83=94=E3=83=B3?= =?UTF-8?q?=E5=87=A6=E7=90=86=E3=81=AE=E5=BF=9C=E7=AD=94=E3=82=92Interacti?= =?UTF-8?q?onResponseEdit=E3=81=AB=E5=A4=89=E6=9B=B4=E3=81=97=E3=80=81?= =?UTF-8?q?=E3=82=A8=E3=83=A9=E3=83=BC=E3=83=A1=E3=83=83=E3=82=BB=E3=83=BC?= =?UTF-8?q?=E3=82=B8=E3=81=AE=E8=A1=A8=E7=A4=BA=E3=82=92=E6=94=B9=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/internal/bot/command/general/pin.go | 21 ++++++++----------- src/internal/bot/command/general/pin_modal.go | 16 ++++++++------ .../bot/command/general/pin_select.go | 9 +++----- src/internal/bot/command/general/unpin.go | 19 +++++++---------- 4 files changed, 29 insertions(+), 36 deletions(-) diff --git a/src/internal/bot/command/general/pin.go b/src/internal/bot/command/general/pin.go index 6257213..a574ca4 100644 --- a/src/internal/bot/command/general/pin.go +++ b/src/internal/bot/command/general/pin.go @@ -73,19 +73,16 @@ func replyPinError(s *discordgo.Session, i *discordgo.InteractionCreate, config footer.IconURL = i.User.AvatarURL("") } - _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ - Type: discordgo.InteractionResponseChannelMessageWithSource, - Data: &discordgo.InteractionResponseData{ - Embeds: []*discordgo.MessageEmbed{ - { - Title: title, - Description: description, - Color: config.Colors.Error, - Footer: footer, - Timestamp: time.Now().Format(time.RFC3339), - }, + _, _ = s.InteractionResponseEdit(i.Interaction, &discordgo.WebhookEdit{ + Embeds: &[]*discordgo.MessageEmbed{ + { + Title: title, + Description: description, + Color: config.Colors.Error, + Footer: footer, + Timestamp: time.Now().Format(time.RFC3339), }, - Flags: discordgo.MessageFlagsEphemeral, }, + Flags: discordgo.MessageFlagsEphemeral, }) } diff --git a/src/internal/bot/command/general/pin_modal.go b/src/internal/bot/command/general/pin_modal.go index 184d4af..29ae0ea 100644 --- a/src/internal/bot/command/general/pin_modal.go +++ b/src/internal/bot/command/general/pin_modal.go @@ -15,6 +15,13 @@ func HandlePinModalSubmit(ctx *internal.BotContext, s *discordgo.Session, i *dis return false } + _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseDeferredChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Flags: discordgo.MessageFlagsEphemeral, + }, + }) + config := ctx.Config if !hasPinPermission(s, i) { replyPinError(s, i, config, "権限がありません", "この操作を実行する権限がありません。") @@ -75,12 +82,9 @@ func HandlePinModalSubmit(ctx *internal.BotContext, s *discordgo.Session, i *dis return true } - _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ - Type: discordgo.InteractionResponseChannelMessageWithSource, - Data: &discordgo.InteractionResponseData{ - Content: "メッセージをピン留めしました: `" + message + "`", - Flags: discordgo.MessageFlagsEphemeral, - }, + content := "メッセージをピン留めしました: `" + message + "`" + _, _ = s.InteractionResponseEdit(i.Interaction, &discordgo.WebhookEdit{ + Content: &content, }) return true diff --git a/src/internal/bot/command/general/pin_select.go b/src/internal/bot/command/general/pin_select.go index 09ee07b..b2c4035 100644 --- a/src/internal/bot/command/general/pin_select.go +++ b/src/internal/bot/command/general/pin_select.go @@ -99,11 +99,8 @@ func PinSelect(ctx *internal.BotContext, s *discordgo.Session, i *discordgo.Inte Timestamp: time.Now().Format(time.RFC3339), } - _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ - Type: discordgo.InteractionResponseChannelMessageWithSource, - Data: &discordgo.InteractionResponseData{ - Embeds: []*discordgo.MessageEmbed{successEmbed}, - Flags: discordgo.MessageFlagsEphemeral, - }, + _, _ = s.InteractionResponseEdit(i.Interaction, &discordgo.WebhookEdit{ + Embeds: &[]*discordgo.MessageEmbed{successEmbed}, + Flags: discordgo.MessageFlagsEphemeral, }) } diff --git a/src/internal/bot/command/general/unpin.go b/src/internal/bot/command/general/unpin.go index c549432..f7114e3 100644 --- a/src/internal/bot/command/general/unpin.go +++ b/src/internal/bot/command/general/unpin.go @@ -36,12 +36,10 @@ func Unpin(ctx *internal.BotContext, s *discordgo.Session, i *discordgo.Interact return } if len(settings) == 0 { - _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ - Type: discordgo.InteractionResponseChannelMessageWithSource, - Data: &discordgo.InteractionResponseData{ - Content: "このチャンネルにはピン留めされたメッセージがありません。", - Flags: discordgo.MessageFlagsEphemeral, - }, + content := "このチャンネルにはピン留めされたメッセージがありません。" + _, _ = s.InteractionResponseEdit(i.Interaction, &discordgo.WebhookEdit{ + Content: &content, + Flags: discordgo.MessageFlagsEphemeral, }) return } @@ -58,11 +56,8 @@ func Unpin(ctx *internal.BotContext, s *discordgo.Session, i *discordgo.Interact Timestamp: time.Now().Format(time.RFC3339), } - _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ - Type: discordgo.InteractionResponseChannelMessageWithSource, - Data: &discordgo.InteractionResponseData{ - Embeds: []*discordgo.MessageEmbed{successEmbed}, - Flags: discordgo.MessageFlagsEphemeral, - }, + _, _ = s.InteractionResponseEdit(i.Interaction, &discordgo.WebhookEdit{ + Embeds: &[]*discordgo.MessageEmbed{successEmbed}, + Flags: discordgo.MessageFlagsEphemeral, }) }