mirror of
https://github.com/truewhile/MeBox.git
synced 2026-09-29 03:26:37 +08:00
140 lines
4.1 KiB
Go
140 lines
4.1 KiB
Go
package service
|
||
|
||
import (
|
||
"context"
|
||
"errors"
|
||
"strings"
|
||
|
||
"gorm.io/gorm"
|
||
|
||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||
)
|
||
|
||
func (s *TelegramBotService) telegramBinding(ctx context.Context, telegramUserID int) *model.TelegramBinding {
|
||
if telegramUserID == 0 {
|
||
return nil
|
||
}
|
||
var binding model.TelegramBinding
|
||
err := s.repo.DB.WithContext(ctx).Where("telegram_user_id = ?", int64(telegramUserID)).First(&binding).Error
|
||
if err != nil {
|
||
return nil
|
||
}
|
||
return &binding
|
||
}
|
||
|
||
func (s *TelegramBotService) unbindTelegramUser(ctx context.Context, telegramUserID int) error {
|
||
if s == nil || s.repo == nil || s.repo.DB == nil || telegramUserID == 0 {
|
||
return nil
|
||
}
|
||
return s.repo.DB.WithContext(ctx).Unscoped().
|
||
Where("telegram_user_id = ?", int64(telegramUserID)).
|
||
Delete(&model.TelegramBinding{}).Error
|
||
}
|
||
|
||
func (s *TelegramBotService) upsertTelegramBinding(ctx context.Context, msg *TelegramMessage, userID string) error {
|
||
name := strings.TrimSpace(msg.From.FirstName)
|
||
if msg.From.Username != "" {
|
||
name = "@" + strings.TrimSpace(msg.From.Username)
|
||
}
|
||
telegramUserID := int64(msg.From.ID)
|
||
return s.repo.DB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||
var existing model.TelegramBinding
|
||
err := tx.Where("telegram_user_id = ?", telegramUserID).First(&existing).Error
|
||
if err == nil {
|
||
if err := s.replaceTelegramAccountBindingTx(ctx, tx, userID, telegramUserID); err != nil {
|
||
return err
|
||
}
|
||
if err := tx.Model(&existing).Updates(map[string]any{
|
||
"telegram_name": name,
|
||
"chat_id": telegramBindingChatIDForMessage(msg, &existing),
|
||
"user_id": userID,
|
||
}).Error; telegramBindingUniqueErr(err) {
|
||
return errTelegramAccountAlreadyBound
|
||
} else if err != nil {
|
||
return err
|
||
}
|
||
return nil
|
||
}
|
||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||
return err
|
||
}
|
||
if err := tx.Unscoped().Where("telegram_user_id = ?", telegramUserID).Delete(&model.TelegramBinding{}).Error; err != nil {
|
||
return err
|
||
}
|
||
if err := s.replaceTelegramAccountBindingTx(ctx, tx, userID, telegramUserID); err != nil {
|
||
return err
|
||
}
|
||
err = tx.Create(&model.TelegramBinding{
|
||
TelegramUserID: telegramUserID,
|
||
TelegramName: name,
|
||
ChatID: telegramBindingChatIDForMessage(msg, nil),
|
||
UserID: userID,
|
||
}).Error
|
||
if telegramBindingUniqueErr(err) {
|
||
return errTelegramAccountAlreadyBound
|
||
}
|
||
return err
|
||
})
|
||
}
|
||
|
||
func telegramBindingChatIDForMessage(msg *TelegramMessage, existing *model.TelegramBinding) int64 {
|
||
if msg == nil {
|
||
if existing != nil {
|
||
return existing.ChatID
|
||
}
|
||
return 0
|
||
}
|
||
if msg.Chat.Type == "" || msg.Chat.Type == "private" {
|
||
return int64(msg.Chat.ID)
|
||
}
|
||
if existing != nil && existing.ChatID > 0 {
|
||
return existing.ChatID
|
||
}
|
||
return int64(msg.From.ID)
|
||
}
|
||
|
||
func telegramPrivateChatIDFromBinding(binding model.TelegramBinding) int64 {
|
||
if binding.ChatID > 0 {
|
||
return binding.ChatID
|
||
}
|
||
return binding.TelegramUserID
|
||
}
|
||
|
||
func (s *TelegramBotService) replaceTelegramAccountBindingTx(ctx context.Context, tx *gorm.DB, userID string, telegramUserID int64) error {
|
||
return tx.WithContext(ctx).Unscoped().
|
||
Where("user_id = ? AND telegram_user_id <> ?", userID, telegramUserID).
|
||
Delete(&model.TelegramBinding{}).Error
|
||
}
|
||
|
||
func telegramBindingUniqueErr(err error) bool {
|
||
if err == nil {
|
||
return false
|
||
}
|
||
msg := strings.ToLower(err.Error())
|
||
return strings.Contains(msg, "idx_telegram_bindings_user_id_active") ||
|
||
strings.Contains(msg, "telegram_bindings.user_id") ||
|
||
(strings.Contains(msg, "unique") && strings.Contains(msg, "telegram_bindings"))
|
||
}
|
||
|
||
func parseStartCredentials(args []string) (string, string) {
|
||
if len(args) >= 2 {
|
||
return strings.TrimSpace(args[0]), strings.TrimSpace(strings.Join(args[1:], " "))
|
||
}
|
||
if len(args) == 1 {
|
||
raw := strings.TrimSpace(args[0])
|
||
for _, sep := range []string{"-", ":", ":"} {
|
||
if parts := strings.SplitN(raw, sep, 2); len(parts) == 2 {
|
||
return strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1])
|
||
}
|
||
}
|
||
}
|
||
return "", ""
|
||
}
|
||
|
||
func userNameOrFallback(user *model.User) string {
|
||
if user == nil || strings.TrimSpace(user.Username) == "" {
|
||
return "未知用户"
|
||
}
|
||
return user.Username
|
||
}
|