// Copyright © 2023 OpenIM open source community. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package database import ( "context" "time" "github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/db/pagination" "github.com/openimsdk/tools/db/tx" "github.com/redis/go-redis/v9" "git.imall.cloud/openim/chat/pkg/common/constant" "git.imall.cloud/openim/chat/pkg/common/db/cache" admindb "git.imall.cloud/openim/chat/pkg/common/db/model/admin" "git.imall.cloud/openim/chat/pkg/common/db/model/chat" "git.imall.cloud/openim/chat/pkg/common/db/table/admin" chatdb "git.imall.cloud/openim/chat/pkg/common/db/table/chat" ) type ChatDatabaseInterface interface { GetUser(ctx context.Context, userID string) (account *chatdb.Account, err error) UpdateUseInfo(ctx context.Context, userID string, attribute map[string]any, updateCred, delCred []*chatdb.Credential) (err error) FindAttribute(ctx context.Context, userIDs []string) ([]*chatdb.Attribute, error) FindAttributeByAccount(ctx context.Context, accounts []string) ([]*chatdb.Attribute, error) TakeAttributeByPhone(ctx context.Context, areaCode string, phoneNumber string) (*chatdb.Attribute, error) TakeAttributeByEmail(ctx context.Context, Email string) (*chatdb.Attribute, error) TakeAttributeByAccount(ctx context.Context, account string) (*chatdb.Attribute, error) TakeAttributeByUserID(ctx context.Context, userID string) (*chatdb.Attribute, error) TakeAccount(ctx context.Context, userID string) (*chatdb.Account, error) TakeCredentialByAccount(ctx context.Context, account string) (*chatdb.Credential, error) TakeCredentialsByUserID(ctx context.Context, userID string) ([]*chatdb.Credential, error) TakeLastVerifyCode(ctx context.Context, account string) (*chatdb.VerifyCode, error) Search(ctx context.Context, normalUser int32, keyword string, genders int32, startTime, endTime *time.Time, pagination pagination.Pagination) (int64, []*chatdb.Attribute, error) SearchWithRealNameAuth(ctx context.Context, normalUser int32, keyword string, genders int32, startTime, endTime *time.Time, realNameKeyword string, idCardKeyword string, pagination pagination.Pagination) (total int64, attributes []*chatdb.Attribute, err error) // 搜索用户(支持实名信息搜索) SearchUser(ctx context.Context, keyword string, userIDs []string, genders []int32, pagination pagination.Pagination) (int64, []*chatdb.Attribute, error) CountVerifyCodeRange(ctx context.Context, account string, start time.Time, end time.Time) (int64, error) AddVerifyCode(ctx context.Context, verifyCode *chatdb.VerifyCode, fn func() error) error UpdateVerifyCodeIncrCount(ctx context.Context, id string) error DelVerifyCode(ctx context.Context, id string) error RegisterUser(ctx context.Context, register *chatdb.Register, account *chatdb.Account, attribute *chatdb.Attribute, credentials []*chatdb.Credential) error LoginRecord(ctx context.Context, record *chatdb.UserLoginRecord, verifyCodeID *string) error UpdatePassword(ctx context.Context, userID string, password string) error UpdatePasswordAndDeleteVerifyCode(ctx context.Context, userID string, password string, codeID string) error NewUserCountTotal(ctx context.Context, before *time.Time) (int64, error) UserLoginCountTotal(ctx context.Context, before *time.Time) (int64, error) UserLoginCountRangeEverydayTotal(ctx context.Context, start *time.Time, end *time.Time) (map[string]int64, int64, error) CountTodayRegisteredUsers(ctx context.Context) (int64, error) CountTodayActiveUsers(ctx context.Context) (int64, error) GetLatestLoginIP(ctx context.Context, userID string) (string, error) // 获取用户最新登录IP SearchUserLoginRecords(ctx context.Context, userID, ip string, pagination pagination.Pagination) (int64, []*chatdb.UserLoginRecord, error) // 查询用户登录记录(支持按用户ID或IP查询) DelUserAccount(ctx context.Context, userIDs []string) error // 敏感词相关方法 GetSensitiveWords(ctx context.Context) ([]*chatdb.SensitiveWord, error) CheckSensitiveWords(ctx context.Context, content string) ([]*chatdb.SensitiveWord, bool, error) FilterContent(ctx context.Context, content string) (string, []*chatdb.SensitiveWord, bool, error) GetSensitiveWordConfig(ctx context.Context) (*chatdb.SensitiveWordConfig, error) // 敏感词管理相关方法 CreateSensitiveWord(ctx context.Context, word *chatdb.SensitiveWord) error UpdateSensitiveWord(ctx context.Context, id string, data map[string]any) error DeleteSensitiveWord(ctx context.Context, ids []string) error GetSensitiveWord(ctx context.Context, id string) (*chatdb.SensitiveWord, error) SearchSensitiveWords(ctx context.Context, keyword string, action int32, status int32, pagination pagination.Pagination) (int64, []*chatdb.SensitiveWord, error) BatchAddSensitiveWords(ctx context.Context, words []*chatdb.SensitiveWord) error BatchUpdateSensitiveWords(ctx context.Context, updates map[string]map[string]any) error BatchDeleteSensitiveWords(ctx context.Context, ids []string) error // 敏感词分组管理 CreateSensitiveWordGroup(ctx context.Context, group *chatdb.SensitiveWordGroup) error UpdateSensitiveWordGroup(ctx context.Context, id string, data map[string]any) error DeleteSensitiveWordGroup(ctx context.Context, ids []string) error GetSensitiveWordGroup(ctx context.Context, id string) (*chatdb.SensitiveWordGroup, error) GetAllSensitiveWordGroups(ctx context.Context) ([]*chatdb.SensitiveWordGroup, error) // 敏感词配置管理 UpdateSensitiveWordConfig(ctx context.Context, config *chatdb.SensitiveWordConfig) error // 敏感词日志管理 GetSensitiveWordLogs(ctx context.Context, userID, groupID string, pagination pagination.Pagination) (int64, []*chatdb.SensitiveWordLog, error) DeleteSensitiveWordLogs(ctx context.Context, ids []string) error // 敏感词统计 GetSensitiveWordStats(ctx context.Context) (map[string]int64, error) GetSensitiveWordLogStats(ctx context.Context, startTime, endTime time.Time) (map[string]int64, error) // 收藏相关方法 CreateFavorite(ctx context.Context, favorite *chatdb.Favorite) error GetFavorite(ctx context.Context, favoriteID string) (*chatdb.Favorite, error) GetFavoritesByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*chatdb.Favorite, error) GetFavoritesByUserIDAndType(ctx context.Context, userID string, favoriteType int32, pagination pagination.Pagination) (int64, []*chatdb.Favorite, error) SearchFavoritesByKeyword(ctx context.Context, userID string, keyword string, pagination pagination.Pagination) (int64, []*chatdb.Favorite, error) UpdateFavorite(ctx context.Context, favoriteID string, data map[string]any) error DeleteFavorite(ctx context.Context, favoriteIDs []string) error DeleteFavoritesByUserID(ctx context.Context, userID string) error CountFavoritesByUserID(ctx context.Context, userID string) (int64, error) GetFavoritesByTags(ctx context.Context, userID string, tags []string, pagination pagination.Pagination) (int64, []*chatdb.Favorite, error) // 定时任务相关方法 CreateScheduledTask(ctx context.Context, task *chatdb.ScheduledTask) error GetScheduledTask(ctx context.Context, taskID string) (*chatdb.ScheduledTask, error) GetScheduledTasksByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*chatdb.ScheduledTask, error) GetAllScheduledTasks(ctx context.Context, pagination pagination.Pagination) (int64, []*chatdb.ScheduledTask, error) UpdateScheduledTask(ctx context.Context, taskID string, data map[string]any) error DeleteScheduledTask(ctx context.Context, taskIDs []string) error // 系统配置相关方法 CreateSystemConfig(ctx context.Context, config *chatdb.SystemConfig) error GetSystemConfig(ctx context.Context, key string) (*chatdb.SystemConfig, error) GetSystemConfigsByKeys(ctx context.Context, keys []string) ([]*chatdb.SystemConfig, error) GetAllSystemConfigs(ctx context.Context, pagination pagination.Pagination) (int64, []*chatdb.SystemConfig, error) UpdateSystemConfig(ctx context.Context, key string, data map[string]any) error UpdateSystemConfigValue(ctx context.Context, key string, value string) error UpdateSystemConfigEnabled(ctx context.Context, key string, enabled bool) error DeleteSystemConfig(ctx context.Context, keys []string) error GetEnabledSystemConfigs(ctx context.Context) ([]*chatdb.SystemConfig, error) GetAppSystemConfigs(ctx context.Context) ([]*chatdb.SystemConfig, error) // 获取所有 show_in_app=true 且 enabled=true 的配置 // 钱包相关方法 GetWallet(ctx context.Context, userID string) (*chatdb.Wallet, error) // 获取钱包信息 GetWalletsByUserIDs(ctx context.Context, userIDs []string) ([]*chatdb.Wallet, error) // 根据用户ID列表批量获取钱包 GetWalletsPage(ctx context.Context, pagination pagination.Pagination) (int64, []*chatdb.Wallet, error) // 分页获取钱包列表 GetWalletsPageByRealNameAuthAuditStatus(ctx context.Context, auditStatus int32, userID string, pagination pagination.Pagination) (int64, []*chatdb.Wallet, error) // 按实名认证审核状态分页查询钱包(支持用户ID搜索) CreateWallet(ctx context.Context, wallet *chatdb.Wallet) error // 创建钱包 UpdateWalletBalance(ctx context.Context, userID string, balance int64) error // 更新钱包余额 IncrementWalletBalance(ctx context.Context, userID string, amount int64) (beforeBalance int64, afterBalance int64, err error) // 原子更新余额,返回更新前后的余额 UpdateWalletPaymentPassword(ctx context.Context, userID string, paymentPassword string) error // 更新支付密码 UpdateWalletWithdrawAccount(ctx context.Context, userID string, withdrawAccount string) error // 更新提款账号(兼容旧接口) UpdateWalletWithdrawAccountWithType(ctx context.Context, userID string, withdrawAccount string, accountType int32) error // 更新提款账号(带类型) UpdateWalletRealNameAuth(ctx context.Context, userID string, realNameAuth chatdb.RealNameAuth) error // 更新实名认证信息 GetWalletBalanceRecords(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*chatdb.WalletBalanceRecord, error) // 获取钱包余额变动记录 GetWalletBalanceRecordsByUserIDAndType(ctx context.Context, userID string, recordType int32, pagination pagination.Pagination) (int64, []*chatdb.WalletBalanceRecord, error) // 根据类型获取钱包余额变动记录 CreateWalletBalanceRecord(ctx context.Context, record *chatdb.WalletBalanceRecord) error // 创建余额变动记录 // 提现相关方法 CreateWithdraw(ctx context.Context, withdraw *chatdb.Withdraw) error // 创建提现记录 GetWithdraw(ctx context.Context, withdrawID string) (*chatdb.Withdraw, error) // 获取提现记录 GetWithdrawsByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*chatdb.Withdraw, error) // 获取用户的提现记录列表 GetWithdrawsByStatus(ctx context.Context, status int32, pagination pagination.Pagination) (int64, []*chatdb.Withdraw, error) // 根据状态获取提现记录列表 UpdateWithdrawStatus(ctx context.Context, withdrawID string, status int32, auditorID string, auditRemark string) error // 更新提现状态(审核) GetWithdrawsPage(ctx context.Context, pagination pagination.Pagination) (int64, []*chatdb.Withdraw, error) // 获取提现记录列表(分页) // 提现申请相关方法 CreateWithdrawApplication(ctx context.Context, application *chatdb.WithdrawApplication) error // 创建提现申请 GetWithdrawApplication(ctx context.Context, applicationID string) (*chatdb.WithdrawApplication, error) // 获取提现申请 GetWithdrawApplicationsByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*chatdb.WithdrawApplication, error) // 获取用户的提现申请列表 GetWithdrawApplicationsByStatus(ctx context.Context, status int32, pagination pagination.Pagination) (int64, []*chatdb.WithdrawApplication, error) // 根据状态获取提现申请列表 UpdateWithdrawApplicationStatus(ctx context.Context, applicationID string, status int32, auditorID string, auditRemark string) error // 更新提现申请状态(审核) GetWithdrawApplicationsPage(ctx context.Context, pagination pagination.Pagination) (int64, []*chatdb.WithdrawApplication, error) // 获取提现申请列表(分页) UpdateWithdrawApplication(ctx context.Context, applicationID string, data map[string]any) error // 更新提现申请 } func NewChatDatabase(cli *mongoutil.Client, rdb redis.UniversalClient) (ChatDatabaseInterface, error) { register, err := chat.NewRegister(cli.GetDB()) if err != nil { return nil, err } account, err := chat.NewAccount(cli.GetDB()) if err != nil { return nil, err } attribute, err := chat.NewAttribute(cli.GetDB()) if err != nil { return nil, err } credential, err := chat.NewCredential(cli.GetDB()) if err != nil { return nil, err } userLoginRecord, err := chat.NewUserLoginRecord(cli.GetDB()) if err != nil { return nil, err } verifyCode, err := chat.NewVerifyCode(cli.GetDB()) if err != nil { return nil, err } forbiddenAccount, err := admindb.NewForbiddenAccount(cli.GetDB()) if err != nil { return nil, err } sensitiveWord, err := chat.NewSensitiveWord(cli.GetDB()) if err != nil { return nil, err } favorite, err := chat.NewFavorite(cli.GetDB()) if err != nil { return nil, err } scheduledTask, err := chat.NewScheduledTask(cli.GetDB()) if err != nil { return nil, err } systemConfig, err := chat.NewSystemConfig(cli.GetDB()) if err != nil { return nil, err } wallet, err := chat.NewWallet(cli.GetDB()) if err != nil { return nil, err } walletBalanceRecord, err := chat.NewWalletBalanceRecord(cli.GetDB()) if err != nil { return nil, err } withdraw, err := chat.NewWithdraw(cli.GetDB()) if err != nil { return nil, err } withdrawApplication, err := chat.NewWithdrawApplication(cli.GetDB()) if err != nil { return nil, err } var userLoginIPCache cache.UserLoginIPInterface if rdb != nil { userLoginIPCache = cache.NewUserLoginIPInterface(rdb) } return &ChatDatabase{ tx: cli.GetTx(), register: register, account: account, attribute: attribute, credential: credential, userLoginRecord: userLoginRecord, verifyCode: verifyCode, forbiddenAccount: forbiddenAccount, sensitiveWord: sensitiveWord, favorite: favorite, scheduledTask: scheduledTask, systemConfig: systemConfig, wallet: wallet, walletBalanceRecord: walletBalanceRecord, withdraw: withdraw, withdrawApplication: withdrawApplication, userLoginIPCache: userLoginIPCache, }, nil } type ChatDatabase struct { tx tx.Tx register chatdb.RegisterInterface account chatdb.AccountInterface attribute chatdb.AttributeInterface credential chatdb.CredentialInterface userLoginRecord chatdb.UserLoginRecordInterface verifyCode chatdb.VerifyCodeInterface forbiddenAccount admin.ForbiddenAccountInterface sensitiveWord chatdb.SensitiveWordInterface favorite chatdb.FavoriteInterface scheduledTask chatdb.ScheduledTaskInterface systemConfig chatdb.SystemConfigInterface wallet chatdb.WalletInterface walletBalanceRecord chatdb.WalletBalanceRecordInterface withdraw chatdb.WithdrawInterface withdrawApplication chatdb.WithdrawApplicationInterface userLoginIPCache cache.UserLoginIPInterface // 用户登录IP缓存(可选,如果为nil则不使用缓存) } func (o *ChatDatabase) GetUser(ctx context.Context, userID string) (account *chatdb.Account, err error) { return o.account.Take(ctx, userID) } func (o *ChatDatabase) UpdateUseInfo(ctx context.Context, userID string, attribute map[string]any, updateCred, delCred []*chatdb.Credential) (err error) { return o.tx.Transaction(ctx, func(ctx context.Context) error { if err = o.attribute.Update(ctx, userID, attribute); err != nil { return err } for _, credential := range updateCred { if err = o.credential.CreateOrUpdateAccount(ctx, credential); err != nil { return err } } if err = o.credential.DeleteByUserIDType(ctx, delCred...); err != nil { return err } return nil }) } func (o *ChatDatabase) FindAttribute(ctx context.Context, userIDs []string) ([]*chatdb.Attribute, error) { return o.attribute.Find(ctx, userIDs) } func (o *ChatDatabase) FindAttributeByAccount(ctx context.Context, accounts []string) ([]*chatdb.Attribute, error) { return o.attribute.FindAccount(ctx, accounts) } func (o *ChatDatabase) TakeAttributeByPhone(ctx context.Context, areaCode string, phoneNumber string) (*chatdb.Attribute, error) { return o.attribute.TakePhone(ctx, areaCode, phoneNumber) } func (o *ChatDatabase) TakeAttributeByEmail(ctx context.Context, email string) (*chatdb.Attribute, error) { return o.attribute.TakeEmail(ctx, email) } func (o *ChatDatabase) TakeAttributeByAccount(ctx context.Context, account string) (*chatdb.Attribute, error) { return o.attribute.TakeAccount(ctx, account) } func (o *ChatDatabase) TakeAttributeByUserID(ctx context.Context, userID string) (*chatdb.Attribute, error) { return o.attribute.Take(ctx, userID) } func (o *ChatDatabase) TakeLastVerifyCode(ctx context.Context, account string) (*chatdb.VerifyCode, error) { return o.verifyCode.TakeLast(ctx, account) } func (o *ChatDatabase) TakeAccount(ctx context.Context, userID string) (*chatdb.Account, error) { return o.account.Take(ctx, userID) } func (o *ChatDatabase) TakeCredentialByAccount(ctx context.Context, account string) (*chatdb.Credential, error) { return o.credential.TakeAccount(ctx, account) } func (o *ChatDatabase) TakeCredentialsByUserID(ctx context.Context, userID string) ([]*chatdb.Credential, error) { return o.credential.Find(ctx, userID) } func (o *ChatDatabase) Search(ctx context.Context, normalUser int32, keyword string, genders int32, startTime, endTime *time.Time, pagination pagination.Pagination) (total int64, attributes []*chatdb.Attribute, err error) { var forbiddenIDs []string if int(normalUser) == constant.NormalUser { forbiddenIDs, err = o.forbiddenAccount.FindAllIDs(ctx) if err != nil { return 0, nil, err } } total, totalUser, err := o.attribute.SearchNormalUser(ctx, keyword, forbiddenIDs, genders, startTime, endTime, pagination) if err != nil { return 0, nil, err } return total, totalUser, nil } // SearchWithRealNameAuth 搜索用户(支持实名信息搜索) func (o *ChatDatabase) SearchWithRealNameAuth(ctx context.Context, normalUser int32, keyword string, genders int32, startTime, endTime *time.Time, realNameKeyword string, idCardKeyword string, pagination pagination.Pagination) (total int64, attributes []*chatdb.Attribute, err error) { // 如果提供了实名信息搜索关键词,先查询钱包获取userIDs var realNameAuthUserIDs []string if realNameKeyword != "" || idCardKeyword != "" { realNameAuthUserIDs, err = o.wallet.SearchByRealNameAuth(ctx, realNameKeyword, idCardKeyword) if err != nil { return 0, nil, err } // 如果没有找到匹配的用户,直接返回空结果 if len(realNameAuthUserIDs) == 0 { return 0, []*chatdb.Attribute{}, nil } } var forbiddenIDs []string if int(normalUser) == constant.NormalUser { forbiddenIDs, err = o.forbiddenAccount.FindAllIDs(ctx) if err != nil { return 0, nil, err } } // 如果提供了实名信息搜索,需要在用户ID列表中过滤 if len(realNameAuthUserIDs) > 0 { // 修改 SearchNormalUser 方法,支持传入额外的 userIDs 过滤条件 // 或者创建一个新的方法 // 这里我们修改 SearchNormalUser 来支持这个功能 total, totalUser, err := o.attribute.SearchNormalUserWithUserIDs(ctx, keyword, forbiddenIDs, genders, startTime, endTime, realNameAuthUserIDs, pagination) if err != nil { return 0, nil, err } return total, totalUser, nil } // 没有实名信息搜索,使用原来的方法 return o.Search(ctx, normalUser, keyword, genders, startTime, endTime, pagination) } func (o *ChatDatabase) SearchUser(ctx context.Context, keyword string, userIDs []string, genders []int32, pagination pagination.Pagination) (int64, []*chatdb.Attribute, error) { return o.attribute.SearchUser(ctx, keyword, userIDs, genders, pagination) } func (o *ChatDatabase) CountVerifyCodeRange(ctx context.Context, account string, start time.Time, end time.Time) (int64, error) { return o.verifyCode.RangeNum(ctx, account, start, end) } func (o *ChatDatabase) AddVerifyCode(ctx context.Context, verifyCode *chatdb.VerifyCode, fn func() error) error { return o.tx.Transaction(ctx, func(ctx context.Context) error { if err := o.verifyCode.Add(ctx, []*chatdb.VerifyCode{verifyCode}); err != nil { return err } if fn != nil { return fn() } return nil }) } func (o *ChatDatabase) UpdateVerifyCodeIncrCount(ctx context.Context, id string) error { return o.verifyCode.Incr(ctx, id) } func (o *ChatDatabase) DelVerifyCode(ctx context.Context, id string) error { return o.verifyCode.Delete(ctx, id) } func (o *ChatDatabase) RegisterUser(ctx context.Context, register *chatdb.Register, account *chatdb.Account, attribute *chatdb.Attribute, credentials []*chatdb.Credential) error { return o.tx.Transaction(ctx, func(ctx context.Context) error { if err := o.register.Create(ctx, register); err != nil { return err } if err := o.account.Create(ctx, account); err != nil { return err } if err := o.attribute.Create(ctx, attribute); err != nil { return err } if err := o.credential.Create(ctx, credentials...); err != nil { return err } return nil }) } func (o *ChatDatabase) LoginRecord(ctx context.Context, record *chatdb.UserLoginRecord, verifyCodeID *string) error { return o.tx.Transaction(ctx, func(ctx context.Context) error { if err := o.userLoginRecord.Create(ctx, record); err != nil { return err } // 创建登录记录后,更新缓存(保证缓存一致性) if o.userLoginIPCache != nil && record.UserID != "" { // 先删除旧缓存,然后设置新缓存 // 使用新IP更新缓存,这样下次查询时可以直接从缓存获取 _ = o.userLoginIPCache.SetLatestLoginIP(ctx, record.UserID, record.IP) } if verifyCodeID != nil { if err := o.verifyCode.Delete(ctx, *verifyCodeID); err != nil { return err } } return nil }) } func (o *ChatDatabase) UpdatePassword(ctx context.Context, userID string, password string) error { return o.account.UpdatePassword(ctx, userID, password) } func (o *ChatDatabase) UpdatePasswordAndDeleteVerifyCode(ctx context.Context, userID string, password string, codeID string) error { return o.tx.Transaction(ctx, func(ctx context.Context) error { if err := o.account.UpdatePassword(ctx, userID, password); err != nil { return err } if codeID == "" { return nil } if err := o.verifyCode.Delete(ctx, codeID); err != nil { return err } return nil }) } func (o *ChatDatabase) NewUserCountTotal(ctx context.Context, before *time.Time) (int64, error) { return o.register.CountTotal(ctx, before) } func (o *ChatDatabase) UserLoginCountTotal(ctx context.Context, before *time.Time) (int64, error) { return o.userLoginRecord.CountTotal(ctx, before) } func (o *ChatDatabase) UserLoginCountRangeEverydayTotal(ctx context.Context, start *time.Time, end *time.Time) (map[string]int64, int64, error) { return o.userLoginRecord.CountRangeEverydayTotal(ctx, start, end) } func (o *ChatDatabase) CountTodayRegisteredUsers(ctx context.Context) (int64, error) { return o.register.CountToday(ctx) } func (o *ChatDatabase) CountTodayActiveUsers(ctx context.Context) (int64, error) { return o.userLoginRecord.CountTodayActiveUsers(ctx) } func (o *ChatDatabase) GetLatestLoginIP(ctx context.Context, userID string) (string, error) { // 如果启用了缓存,先尝试从缓存获取 if o.userLoginIPCache != nil { ip, found, err := o.userLoginIPCache.GetLatestLoginIP(ctx, userID) if err != nil { // 缓存查询出错,降级到数据库查询 return o.userLoginRecord.GetLatestLoginIP(ctx, userID) } // 如果缓存命中,直接返回(即使IP为空字符串,也表示用户确实没有IP) if found { return ip, nil } // 缓存未命中,从数据库查询 ip, err = o.userLoginRecord.GetLatestLoginIP(ctx, userID) if err != nil { return "", err } // 将查询结果写入缓存(即使为空也缓存,避免频繁查询数据库) _ = o.userLoginIPCache.SetLatestLoginIP(ctx, userID, ip) return ip, nil } // 未启用缓存,直接从数据库查询 return o.userLoginRecord.GetLatestLoginIP(ctx, userID) } func (o *ChatDatabase) SearchUserLoginRecords(ctx context.Context, userID, ip string, pagination pagination.Pagination) (int64, []*chatdb.UserLoginRecord, error) { return o.userLoginRecord.Search(ctx, userID, ip, pagination) } func (o *ChatDatabase) DelUserAccount(ctx context.Context, userIDs []string) error { return o.tx.Transaction(ctx, func(ctx context.Context) error { if err := o.register.Delete(ctx, userIDs); err != nil { return err } if err := o.account.Delete(ctx, userIDs); err != nil { return err } if err := o.attribute.Delete(ctx, userIDs); err != nil { return err } return nil }) } // ==================== 敏感词相关方法实现 ==================== // GetSensitiveWords 获取所有启用的敏感词 func (o *ChatDatabase) GetSensitiveWords(ctx context.Context) ([]*chatdb.SensitiveWord, error) { return o.sensitiveWord.GetEnabledSensitiveWords(ctx) } // CheckSensitiveWords 检测敏感词 func (o *ChatDatabase) CheckSensitiveWords(ctx context.Context, content string) ([]*chatdb.SensitiveWord, bool, error) { words, err := o.sensitiveWord.CheckSensitiveWords(ctx, content) hasSensitive := len(words) > 0 return words, hasSensitive, err } // FilterContent 过滤内容 func (o *ChatDatabase) FilterContent(ctx context.Context, content string) (string, []*chatdb.SensitiveWord, bool, error) { filteredContent, words, err := o.sensitiveWord.FilterContent(ctx, content) hasSensitive := len(words) > 0 return filteredContent, words, hasSensitive, err } // GetSensitiveWordConfig 获取敏感词配置 func (o *ChatDatabase) GetSensitiveWordConfig(ctx context.Context) (*chatdb.SensitiveWordConfig, error) { return o.sensitiveWord.GetSensitiveWordConfig(ctx) } // ==================== 敏感词管理相关方法实现 ==================== func (o *ChatDatabase) CreateSensitiveWord(ctx context.Context, word *chatdb.SensitiveWord) error { return o.sensitiveWord.CreateSensitiveWord(ctx, word) } func (o *ChatDatabase) UpdateSensitiveWord(ctx context.Context, id string, data map[string]any) error { return o.sensitiveWord.UpdateSensitiveWord(ctx, id, data) } func (o *ChatDatabase) DeleteSensitiveWord(ctx context.Context, ids []string) error { return o.sensitiveWord.DeleteSensitiveWord(ctx, ids) } func (o *ChatDatabase) GetSensitiveWord(ctx context.Context, id string) (*chatdb.SensitiveWord, error) { return o.sensitiveWord.GetSensitiveWord(ctx, id) } func (o *ChatDatabase) SearchSensitiveWords(ctx context.Context, keyword string, action int32, status int32, pagination pagination.Pagination) (int64, []*chatdb.SensitiveWord, error) { return o.sensitiveWord.SearchSensitiveWords(ctx, keyword, action, status, pagination) } func (o *ChatDatabase) BatchAddSensitiveWords(ctx context.Context, words []*chatdb.SensitiveWord) error { return o.sensitiveWord.BatchCreateSensitiveWords(ctx, words) } func (o *ChatDatabase) BatchUpdateSensitiveWords(ctx context.Context, updates map[string]map[string]any) error { return o.sensitiveWord.BatchUpdateSensitiveWords(ctx, updates) } func (o *ChatDatabase) BatchDeleteSensitiveWords(ctx context.Context, ids []string) error { return o.sensitiveWord.BatchDeleteSensitiveWords(ctx, ids) } // ==================== 敏感词分组管理实现 ==================== func (o *ChatDatabase) CreateSensitiveWordGroup(ctx context.Context, group *chatdb.SensitiveWordGroup) error { return o.sensitiveWord.CreateSensitiveWordGroup(ctx, group) } func (o *ChatDatabase) UpdateSensitiveWordGroup(ctx context.Context, id string, data map[string]any) error { return o.sensitiveWord.UpdateSensitiveWordGroup(ctx, id, data) } func (o *ChatDatabase) DeleteSensitiveWordGroup(ctx context.Context, ids []string) error { return o.sensitiveWord.DeleteSensitiveWordGroup(ctx, ids) } func (o *ChatDatabase) GetSensitiveWordGroup(ctx context.Context, id string) (*chatdb.SensitiveWordGroup, error) { return o.sensitiveWord.GetSensitiveWordGroup(ctx, id) } func (o *ChatDatabase) GetAllSensitiveWordGroups(ctx context.Context) ([]*chatdb.SensitiveWordGroup, error) { return o.sensitiveWord.GetAllSensitiveWordGroups(ctx) } // ==================== 敏感词配置管理实现 ==================== func (o *ChatDatabase) UpdateSensitiveWordConfig(ctx context.Context, config *chatdb.SensitiveWordConfig) error { return o.sensitiveWord.UpdateSensitiveWordConfig(ctx, config) } // ==================== 敏感词日志管理实现 ==================== func (o *ChatDatabase) GetSensitiveWordLogs(ctx context.Context, userID, groupID string, pagination pagination.Pagination) (int64, []*chatdb.SensitiveWordLog, error) { return o.sensitiveWord.GetSensitiveWordLogs(ctx, userID, groupID, pagination) } func (o *ChatDatabase) DeleteSensitiveWordLogs(ctx context.Context, ids []string) error { return o.sensitiveWord.DeleteSensitiveWordLogs(ctx, ids) } // ==================== 敏感词统计实现 ==================== func (o *ChatDatabase) GetSensitiveWordStats(ctx context.Context) (map[string]int64, error) { return o.sensitiveWord.GetSensitiveWordStats(ctx) } func (o *ChatDatabase) GetSensitiveWordLogStats(ctx context.Context, startTime, endTime time.Time) (map[string]int64, error) { return o.sensitiveWord.GetSensitiveWordLogStats(ctx, startTime, endTime) } // ==================== 收藏相关方法实现 ==================== func (o *ChatDatabase) CreateFavorite(ctx context.Context, favorite *chatdb.Favorite) error { return o.favorite.Create(ctx, favorite) } func (o *ChatDatabase) GetFavorite(ctx context.Context, favoriteID string) (*chatdb.Favorite, error) { return o.favorite.Take(ctx, favoriteID) } func (o *ChatDatabase) GetFavoritesByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*chatdb.Favorite, error) { return o.favorite.FindByUserID(ctx, userID, pagination) } func (o *ChatDatabase) GetFavoritesByUserIDAndType(ctx context.Context, userID string, favoriteType int32, pagination pagination.Pagination) (int64, []*chatdb.Favorite, error) { return o.favorite.FindByUserIDAndType(ctx, userID, favoriteType, pagination) } func (o *ChatDatabase) SearchFavoritesByKeyword(ctx context.Context, userID string, keyword string, pagination pagination.Pagination) (int64, []*chatdb.Favorite, error) { return o.favorite.SearchByKeyword(ctx, userID, keyword, pagination) } func (o *ChatDatabase) UpdateFavorite(ctx context.Context, favoriteID string, data map[string]any) error { return o.favorite.Update(ctx, favoriteID, data) } func (o *ChatDatabase) DeleteFavorite(ctx context.Context, favoriteIDs []string) error { return o.favorite.Delete(ctx, favoriteIDs) } func (o *ChatDatabase) DeleteFavoritesByUserID(ctx context.Context, userID string) error { return o.favorite.DeleteByUserID(ctx, userID) } func (o *ChatDatabase) CountFavoritesByUserID(ctx context.Context, userID string) (int64, error) { return o.favorite.CountByUserID(ctx, userID) } func (o *ChatDatabase) GetFavoritesByTags(ctx context.Context, userID string, tags []string, pagination pagination.Pagination) (int64, []*chatdb.Favorite, error) { return o.favorite.FindByTags(ctx, userID, tags, pagination) } // ==================== 定时任务相关方法实现 ==================== func (o *ChatDatabase) CreateScheduledTask(ctx context.Context, task *chatdb.ScheduledTask) error { return o.scheduledTask.Create(ctx, task) } func (o *ChatDatabase) GetScheduledTask(ctx context.Context, taskID string) (*chatdb.ScheduledTask, error) { return o.scheduledTask.Take(ctx, taskID) } func (o *ChatDatabase) GetScheduledTasksByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*chatdb.ScheduledTask, error) { return o.scheduledTask.FindByUserID(ctx, userID, pagination) } func (o *ChatDatabase) GetAllScheduledTasks(ctx context.Context, pagination pagination.Pagination) (int64, []*chatdb.ScheduledTask, error) { return o.scheduledTask.FindAll(ctx, pagination) } func (o *ChatDatabase) UpdateScheduledTask(ctx context.Context, taskID string, data map[string]any) error { return o.scheduledTask.Update(ctx, taskID, data) } func (o *ChatDatabase) DeleteScheduledTask(ctx context.Context, taskIDs []string) error { return o.scheduledTask.Delete(ctx, taskIDs) } // ==================== 系统配置相关方法实现 ==================== func (o *ChatDatabase) CreateSystemConfig(ctx context.Context, config *chatdb.SystemConfig) error { return o.systemConfig.Create(ctx, config) } func (o *ChatDatabase) GetSystemConfig(ctx context.Context, key string) (*chatdb.SystemConfig, error) { return o.systemConfig.Take(ctx, key) } func (o *ChatDatabase) GetSystemConfigsByKeys(ctx context.Context, keys []string) ([]*chatdb.SystemConfig, error) { return o.systemConfig.FindByKeys(ctx, keys) } func (o *ChatDatabase) GetAllSystemConfigs(ctx context.Context, pagination pagination.Pagination) (int64, []*chatdb.SystemConfig, error) { return o.systemConfig.FindAll(ctx, pagination) } func (o *ChatDatabase) UpdateSystemConfig(ctx context.Context, key string, data map[string]any) error { return o.systemConfig.Update(ctx, key, data) } func (o *ChatDatabase) UpdateSystemConfigValue(ctx context.Context, key string, value string) error { return o.systemConfig.UpdateValue(ctx, key, value) } func (o *ChatDatabase) UpdateSystemConfigEnabled(ctx context.Context, key string, enabled bool) error { return o.systemConfig.UpdateEnabled(ctx, key, enabled) } func (o *ChatDatabase) DeleteSystemConfig(ctx context.Context, keys []string) error { return o.systemConfig.Delete(ctx, keys) } func (o *ChatDatabase) GetEnabledSystemConfigs(ctx context.Context) ([]*chatdb.SystemConfig, error) { return o.systemConfig.GetEnabledConfigs(ctx) } func (o *ChatDatabase) GetAppSystemConfigs(ctx context.Context) ([]*chatdb.SystemConfig, error) { return o.systemConfig.GetAppConfigs(ctx) } func (o *ChatDatabase) GetWallet(ctx context.Context, userID string) (*chatdb.Wallet, error) { return o.wallet.Take(ctx, userID) } func (o *ChatDatabase) GetWalletsByUserIDs(ctx context.Context, userIDs []string) ([]*chatdb.Wallet, error) { return o.wallet.Find(ctx, userIDs) } func (o *ChatDatabase) GetWalletsPage(ctx context.Context, pagination pagination.Pagination) (int64, []*chatdb.Wallet, error) { return o.wallet.Page(ctx, pagination) } func (o *ChatDatabase) GetWalletsPageByRealNameAuthAuditStatus(ctx context.Context, auditStatus int32, userID string, pagination pagination.Pagination) (int64, []*chatdb.Wallet, error) { return o.wallet.PageByRealNameAuthAuditStatus(ctx, auditStatus, userID, pagination) } func (o *ChatDatabase) UpdateWalletBalance(ctx context.Context, userID string, balance int64) error { return o.wallet.UpdateBalance(ctx, userID, balance) } func (o *ChatDatabase) IncrementWalletBalance(ctx context.Context, userID string, amount int64) (beforeBalance int64, afterBalance int64, err error) { return o.wallet.IncrementBalance(ctx, userID, amount) } func (o *ChatDatabase) UpdateWalletPaymentPassword(ctx context.Context, userID string, paymentPassword string) error { return o.wallet.UpdatePaymentPassword(ctx, userID, paymentPassword) } func (o *ChatDatabase) UpdateWalletWithdrawAccount(ctx context.Context, userID string, withdrawAccount string) error { return o.wallet.UpdateWithdrawAccount(ctx, userID, withdrawAccount) } func (o *ChatDatabase) UpdateWalletWithdrawAccountWithType(ctx context.Context, userID string, withdrawAccount string, accountType int32) error { return o.wallet.UpdateWithdrawAccountWithType(ctx, userID, withdrawAccount, accountType) } func (o *ChatDatabase) UpdateWalletRealNameAuth(ctx context.Context, userID string, realNameAuth chatdb.RealNameAuth) error { return o.wallet.UpdateRealNameAuth(ctx, userID, realNameAuth) } func (o *ChatDatabase) CreateWallet(ctx context.Context, wallet *chatdb.Wallet) error { return o.wallet.Create(ctx, wallet) } func (o *ChatDatabase) GetWalletBalanceRecords(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*chatdb.WalletBalanceRecord, error) { return o.walletBalanceRecord.FindByUserID(ctx, userID, pagination) } func (o *ChatDatabase) GetWalletBalanceRecordsByUserIDAndType(ctx context.Context, userID string, recordType int32, pagination pagination.Pagination) (int64, []*chatdb.WalletBalanceRecord, error) { return o.walletBalanceRecord.FindByUserIDAndType(ctx, userID, recordType, pagination) } func (o *ChatDatabase) CreateWalletBalanceRecord(ctx context.Context, record *chatdb.WalletBalanceRecord) error { return o.walletBalanceRecord.Create(ctx, record) } // ==================== 提现相关方法 ==================== func (o *ChatDatabase) CreateWithdraw(ctx context.Context, withdraw *chatdb.Withdraw) error { return o.withdraw.Create(ctx, withdraw) } func (o *ChatDatabase) GetWithdraw(ctx context.Context, withdrawID string) (*chatdb.Withdraw, error) { return o.withdraw.Take(ctx, withdrawID) } func (o *ChatDatabase) GetWithdrawsByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*chatdb.Withdraw, error) { return o.withdraw.FindByUserID(ctx, userID, pagination) } func (o *ChatDatabase) GetWithdrawsByStatus(ctx context.Context, status int32, pagination pagination.Pagination) (int64, []*chatdb.Withdraw, error) { return o.withdraw.FindByStatus(ctx, status, pagination) } func (o *ChatDatabase) UpdateWithdrawStatus(ctx context.Context, withdrawID string, status int32, auditorID string, auditRemark string) error { return o.withdraw.UpdateStatus(ctx, withdrawID, status, auditorID, auditRemark) } func (o *ChatDatabase) GetWithdrawsPage(ctx context.Context, pagination pagination.Pagination) (int64, []*chatdb.Withdraw, error) { return o.withdraw.Page(ctx, pagination) } // ==================== 提现申请相关方法 ==================== func (o *ChatDatabase) CreateWithdrawApplication(ctx context.Context, application *chatdb.WithdrawApplication) error { return o.withdrawApplication.Create(ctx, application) } func (o *ChatDatabase) GetWithdrawApplication(ctx context.Context, applicationID string) (*chatdb.WithdrawApplication, error) { return o.withdrawApplication.Take(ctx, applicationID) } func (o *ChatDatabase) GetWithdrawApplicationsByUserID(ctx context.Context, userID string, pagination pagination.Pagination) (int64, []*chatdb.WithdrawApplication, error) { return o.withdrawApplication.FindByUserID(ctx, userID, pagination) } func (o *ChatDatabase) GetWithdrawApplicationsByStatus(ctx context.Context, status int32, pagination pagination.Pagination) (int64, []*chatdb.WithdrawApplication, error) { return o.withdrawApplication.FindByStatus(ctx, status, pagination) } func (o *ChatDatabase) UpdateWithdrawApplicationStatus(ctx context.Context, applicationID string, status int32, auditorID string, auditRemark string) error { return o.withdrawApplication.UpdateStatus(ctx, applicationID, status, auditorID, auditRemark) } func (o *ChatDatabase) GetWithdrawApplicationsPage(ctx context.Context, pagination pagination.Pagination) (int64, []*chatdb.WithdrawApplication, error) { return o.withdrawApplication.Page(ctx, pagination) } func (o *ChatDatabase) UpdateWithdrawApplication(ctx context.Context, applicationID string, data map[string]any) error { return o.withdrawApplication.Update(ctx, applicationID, data) }