Skip to content

Commit

Permalink
feat: auto migration to supergroup, improved welcome message (#165)
Browse files Browse the repository at this point in the history
  • Loading branch information
nekomeowww authored Jul 24, 2023
1 parent 0e42267 commit c4089b7
Show file tree
Hide file tree
Showing 11 changed files with 374 additions and 16 deletions.
130 changes: 130 additions & 0 deletions internal/bots/telegram/handlers/chatmigrate/chatmigrate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package chatmigrate

import (
"fmt"

tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
"github.com/nekomeowww/fo"
"go.uber.org/fx"
"go.uber.org/zap"

"github.com/nekomeowww/insights-bot/internal/models/chathistories"
"github.com/nekomeowww/insights-bot/internal/models/logs"
"github.com/nekomeowww/insights-bot/internal/models/tgchats"
"github.com/nekomeowww/insights-bot/pkg/bots/tgbot"
"github.com/nekomeowww/insights-bot/pkg/logger"
)

func NewModules() fx.Option {
return fx.Options(
fx.Provide(NewHandlers()),
)
}

type NewHandlersParams struct {
fx.In

TgChats *tgchats.Model
ChatHistories *chathistories.Model
Logs *logs.Model
Logger *logger.Logger
}

type Handlers struct {
tgchats *tgchats.Model
chatHistories *chathistories.Model
logs *logs.Model
logger *logger.Logger
}

func NewHandlers() func(param NewHandlersParams) *Handlers {
return func(param NewHandlersParams) *Handlers {
return &Handlers{
tgchats: param.TgChats,
chatHistories: param.ChatHistories,
logs: param.Logs,
logger: param.Logger,
}
}
}

func (h *Handlers) Install(dispatcher *tgbot.Dispatcher) {
dispatcher.OnChatMigrationFrom(tgbot.NewHandler(h.handleChatMigrationFrom))
}

func (h *Handlers) handleChatMigrationFrom(c *tgbot.Context) (tgbot.Response, error) {
if c.Update.Message == nil {
return nil, nil
}
if c.Update.Message.MigrateFromChatID == 0 {
return nil, nil
}

fromChatID := c.Update.Message.MigrateFromChatID
toChatID := c.Update.Message.Chat.ID

may := fo.
NewMay0().
Use(fo.WithLogFuncHandler(func(a ...any) {
h.logger.Error(fmt.Sprint(a...))
}))

may.Invoke(func() error {
err := h.tgchats.MigrateFeatureFlagsOfChatFromChatIDToChatID(fromChatID, toChatID)
if err != nil {
return fmt.Errorf("failed to migrate all feature flags of chat from chat id %d to chat id %d: %w", fromChatID, toChatID, err)
}

return nil
}())
may.Invoke(func() error {
err := h.tgchats.MigrateOptionOfChatFromChatIDToChatID(fromChatID, toChatID)
if err != nil {
return fmt.Errorf("failed to migrate all options of chat from chat id %d to chat id %d: %w", fromChatID, toChatID, err)
}

return nil
}())
may.Invoke(func() error {
err := h.tgchats.MigrateSubscribersOfChatFromChatIDToChatID(fromChatID, toChatID)
if err != nil {
return fmt.Errorf("failed to migrate all subscribers of chat from chat id %d to chat id %d: %w", fromChatID, toChatID, err)
}

return nil
}())
may.Invoke(func() error {
err := h.chatHistories.MigrateChatHistoriesOfChatFromChatIDToChatID(fromChatID, toChatID)
if err != nil {
return fmt.Errorf("failed to migrate all chat histories of chat from chat id %d to chat id %d: %w", fromChatID, toChatID, err)
}

return nil
}())
may.Invoke(func() error {
err := h.logs.MigrateLogsOfChatFromChatIDToChatID(fromChatID, toChatID)
if err != nil {
return fmt.Errorf("failed to migrate all logs of chat from chat id %d to chat id %d: %w", fromChatID, toChatID, err)
}

return nil
}())

h.logger.Info(fmt.Sprintf("成功将群组 %d 的所有数据迁移到群组 %d", fromChatID, toChatID), zap.Int64("from_chat_id", fromChatID), zap.Int64("to_chat_id", toChatID))

message := tgbotapi.NewMessage(toChatID,
fmt.Sprintf(""+
"%s @%s 监测到您的群组已从 <b>群组(group)</b> 升级为了 <b>超级群组(supergroup)</b>,届时"+
",群组的 ID 将会发生变更,<b>现已自动将过去的历史记录和数据留存自动迁移到了新的群组 ID 名下</b>,"+
"之前的设置将会保留并继续沿用,不过需要注意的是,由于 Telegram 官方的限制,迁移事件前的消息 ID 将无"+
"法与今后发送的消息 ID 相兼容,所以当下一次总结消息时将不会包含在迁移事件发生前所发送的消息,由此带来"+
"的不便敬请谅解。",
tgbot.FullNameFromFirstAndLastName(c.Bot.Self.FirstName, c.Bot.Self.LastName),
c.Bot.Self.UserName,
))
message.ParseMode = tgbotapi.ModeHTML

c.Bot.MaySend(message)

return nil, nil
}
10 changes: 7 additions & 3 deletions internal/bots/telegram/handlers/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package handlers
import (
"go.uber.org/fx"

"github.com/nekomeowww/insights-bot/internal/bots/telegram/handlers/chatmigrate"
"github.com/nekomeowww/insights-bot/internal/bots/telegram/handlers/recap"
"github.com/nekomeowww/insights-bot/internal/bots/telegram/handlers/summarize"
"github.com/nekomeowww/insights-bot/internal/bots/telegram/handlers/welcome"
Expand All @@ -15,6 +16,7 @@ func NewModules() fx.Option {
fx.Options(recap.NewModules()),
fx.Options(summarize.NewModules()),
fx.Options(welcome.NewModules()),
fx.Options(chatmigrate.NewModules()),
)
}

Expand All @@ -23,9 +25,10 @@ type NewHandlersParam struct {

Dispatcher *tgbot.Dispatcher

RecapHandlers *recap.Handlers
SummarizeHandlers *summarize.Handlers
WelcomeHandlers *welcome.Handlers
RecapHandlers *recap.Handlers
SummarizeHandlers *summarize.Handlers
WelcomeHandlers *welcome.Handlers
ChatMigrationHandlers *chatmigrate.Handlers
}

type Handlers struct {
Expand All @@ -41,6 +44,7 @@ func NewHandlers() func(param NewHandlersParam) *Handlers {
param.SummarizeHandlers,
param.RecapHandlers,
param.WelcomeHandlers,
param.ChatMigrationHandlers,
},
}
}
Expand Down
20 changes: 19 additions & 1 deletion internal/bots/telegram/handlers/welcome/welcome.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"go.uber.org/fx"

"github.com/nekomeowww/insights-bot/internal/models/chathistories"
"github.com/nekomeowww/insights-bot/internal/models/logs"
"github.com/nekomeowww/insights-bot/internal/models/tgchats"
"github.com/nekomeowww/insights-bot/pkg/bots/tgbot"
"github.com/nekomeowww/insights-bot/pkg/logger"
Expand All @@ -25,12 +26,14 @@ type NewHandlersParams struct {

TgChats *tgchats.Model
ChatHistories *chathistories.Model
Logs *logs.Model
Logger *logger.Logger
}

type Handlers struct {
tgchats *tgchats.Model
chatHistories *chathistories.Model
logs *logs.Model
logger *logger.Logger
}

Expand All @@ -39,6 +42,7 @@ func NewHandlers() func(param NewHandlersParams) *Handlers {
return &Handlers{
tgchats: param.TgChats,
chatHistories: param.ChatHistories,
logs: param.Logs,
logger: param.Logger,
}
}
Expand Down Expand Up @@ -101,6 +105,14 @@ func (h *Handlers) handleBotLeftChat(chatID int64) {
return fmt.Errorf("failed to delete all chat histories by chat id %d: %w", chatID, err)
}

return nil
}())
may.Invoke(func() error {
err := h.logs.PruneAllLogsContentForChatID(chatID)
if err != nil {
return fmt.Errorf("failed to prune all related content for chat id %d: %w", chatID, err)
}

return nil
}())
}
Expand All @@ -109,11 +121,17 @@ func (h *Handlers) handleBotJoinChat(c *tgbot.Context) {
msg := tgbotapi.NewMessage(c.Update.MyChatMember.Chat.ID, fmt.Sprintf(""+
"欢迎使用 @%s!\n\n"+
"- 如果要让我帮忙阅读网页文章,请直接使用开箱即用的命令 /smr@%s <code>要阅读"+
"的链接</code>;\n"+
"的链接</code>;\n\n"+
"- 如果想要我帮忙总结本群组的聊天记录,请以<b>管理员</b>身份将"+
"我配置为本群组的管理员(可以关闭所有权限),然后在<b>非匿名和非其他身份的身"+
"份</b>下(推荐,否则容易出现权限识别错误的情况)发送 /configure_recap@%s "+
"来开始配置本群组的聊天回顾功能。\n\n"+
"- 如果你在授权 Bot 管理员之后希望 Bot 将已经记录的消息全数移除,可以通过撤销"+
" Bot 的管理员权限来触发 Bot 的历史数据自动清理(如果该部分代码在分岔后未经修"+
"改)。\n"+
"- 如果你的群组尚未是超级群组(supergroup),那么消息链接引用将不会按照预期工"+
"作,如果你需要使用消息链接引用功能,请通过短时间内将群组开放为公共群组并还原回"+
"私有群组,或通过其他操作将本群组升级为超级群组后,该功能方可正常运作。\n\n"+
"如果还有疑问的话也可以执行帮助命令 /help@%s 来查看支持的命令,或者前往 Bot "+
"所在的开源仓库提交 Issue。\n\n"+
"祝你使用愉快!"+
Expand Down
21 changes: 21 additions & 0 deletions internal/models/chathistories/chat_histories.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/nekomeowww/insights-bot/pkg/bots/tgbot"
"github.com/nekomeowww/insights-bot/pkg/linkprev"
"github.com/nekomeowww/insights-bot/pkg/logger"
"github.com/nekomeowww/insights-bot/pkg/types/telegram"
)

type FromPlatform int
Expand Down Expand Up @@ -306,6 +307,26 @@ func (m *Model) DeleteAllChatHistoriesByChatID(chatID int64) error {
return nil
}

func (m *Model) MigrateChatHistoriesOfChatFromChatIDToChatID(fromChatID, toChatID int64) error {
affectedRows, err := m.ent.ChatHistories.
Update().
Where(chathistories.ChatID(fromChatID)).
SetChatID(toChatID).
SetChatType(string(telegram.ChatTypeSuperGroup)).
Save(context.Background())
if err != nil {
return err
}

m.logger.Info("successfully migrated options of chat",
zap.Int64("from_chat_id", fromChatID),
zap.Int64("to_chat_id", toChatID),
zap.Int("affected_rows", affectedRows),
)

return nil
}

func (m *Model) FindLastOneHourChatHistories(chatID int64) ([]*ent.ChatHistories, error) {
return m.FindChatHistoriesByTimeBefore(chatID, time.Hour)
}
Expand Down
78 changes: 78 additions & 0 deletions internal/models/logs/logs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package logs

import (
"context"

"github.com/nekomeowww/insights-bot/ent/logchathistoriesrecap"
"github.com/nekomeowww/insights-bot/internal/configs"
"github.com/nekomeowww/insights-bot/internal/datastore"
"github.com/nekomeowww/insights-bot/pkg/logger"
"go.uber.org/fx"
"go.uber.org/zap"
)

type NewModelParams struct {
fx.In

Config *configs.Config
Ent *datastore.Ent
Digger *datastore.AutoRecapTimeCapsuleDigger
Logger *logger.Logger
}

type Model struct {
config *configs.Config
ent *datastore.Ent
logger *logger.Logger
digger *datastore.AutoRecapTimeCapsuleDigger
}

func NewModel() func(NewModelParams) (*Model, error) {
return func(param NewModelParams) (*Model, error) {
return &Model{
config: param.Config,
ent: param.Ent,
logger: param.Logger,
digger: param.Digger,
}, nil
}
}

func (m *Model) PruneAllLogsContentForChatID(chatID int64) error {
err := m.ent.LogChatHistoriesRecap.
Update().
Where(
logchathistoriesrecap.ChatIDEQ(chatID),
).
SetRecapInputs("").
SetRecapOutputs("").
Exec(context.TODO())

if err != nil {
return err
}

return nil
}

func (m *Model) MigrateLogsOfChatFromChatIDToChatID(fromChatID int64, toChatID int64) error {
affectedRows, err := m.ent.LogChatHistoriesRecap.
Update().
Where(
logchathistoriesrecap.ChatIDEQ(fromChatID),
).
SetChatID(toChatID).
Save(context.TODO())

if err != nil {
return err
}

m.logger.Info("successfully migrated options of chat",
zap.Int64("from_chat_id", fromChatID),
zap.Int64("to_chat_id", toChatID),
zap.Int("affected_rows", affectedRows),
)

return nil
}
2 changes: 2 additions & 0 deletions internal/models/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"go.uber.org/fx"

"github.com/nekomeowww/insights-bot/internal/models/chathistories"
"github.com/nekomeowww/insights-bot/internal/models/logs"
"github.com/nekomeowww/insights-bot/internal/models/smr"
"github.com/nekomeowww/insights-bot/internal/models/tgchats"
)
Expand All @@ -13,5 +14,6 @@ func NewModules() fx.Option {
fx.Provide(chathistories.NewModel()),
fx.Provide(tgchats.NewModel()),
fx.Provide(smr.NewModel()),
fx.Provide(logs.NewModel()),
)
}
20 changes: 20 additions & 0 deletions internal/models/tgchats/auto_recaps_subscribers.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/nekomeowww/insights-bot/ent"
"github.com/nekomeowww/insights-bot/ent/telegramchatautorecapssubscribers"
"go.uber.org/zap"
)

func (m *Model) FindOneAutoRecapsSubscriber(chatID int64, userID int64) (*ent.TelegramChatAutoRecapsSubscribers, error) {
Expand Down Expand Up @@ -83,3 +84,22 @@ func (m *Model) DeleteAllSubscribersByChatID(chatID int64) error {

return nil
}

func (m *Model) MigrateSubscribersOfChatFromChatIDToChatID(fromChatID int64, toChatID int64) error {
affectedRows, err := m.ent.TelegramChatAutoRecapsSubscribers.
Update().
Where(telegramchatautorecapssubscribers.ChatID(fromChatID)).
SetChatID(toChatID).
Save(context.Background())
if err != nil {
return err
}

m.logger.Info("successfully migrated options of chat",
zap.Int64("from_chat_id", fromChatID),
zap.Int64("to_chat_id", toChatID),
zap.Int("affected_rows", affectedRows),
)

return nil
}
Loading

0 comments on commit c4089b7

Please sign in to comment.