// 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 chat import ( "context" "fmt" "time" "go.mongodb.org/mongo-driver/bson/primitive" "git.imall.cloud/openim/chat/pkg/common/db/table/chat" "git.imall.cloud/openim/chat/pkg/common/mctx" chatpb "git.imall.cloud/openim/chat/pkg/protocol/chat" "github.com/google/uuid" ) // ==================== 敏感词管理相关 RPC ==================== // AddSensitiveWord 添加敏感词 func (o *chatSvr) AddSensitiveWord(ctx context.Context, req *chatpb.AddSensitiveWordReq) (*chatpb.AddSensitiveWordResp, error) { // 检查管理员权限 if _, err := mctx.CheckAdmin(ctx); err != nil { return nil, err } // 创建敏感词对象 word := &chat.SensitiveWord{ ID: uuid.New().String(), Word: req.Word, Level: req.Level, Type: req.Type, Action: req.Action, Status: req.Status, Creator: getAdminUserID(ctx), Updater: getAdminUserID(ctx), CreateTime: time.Now(), UpdateTime: time.Now(), Remark: req.Remark, } // 保存到数据库 err := o.Database.CreateSensitiveWord(ctx, word) if err != nil { return nil, err } return &chatpb.AddSensitiveWordResp{}, nil } // UpdateSensitiveWord 更新敏感词 func (o *chatSvr) UpdateSensitiveWord(ctx context.Context, req *chatpb.UpdateSensitiveWordReq) (*chatpb.UpdateSensitiveWordResp, error) { // 检查管理员权限 if _, err := mctx.CheckAdmin(ctx); err != nil { return nil, err } // 构建更新数据 data := make(map[string]any) if req.Word != "" { data["word"] = req.Word } if req.Level > 0 { data["level"] = req.Level } if req.Type > 0 { data["type"] = req.Type } if req.Action > 0 { data["action"] = req.Action } if req.Status >= 0 { data["status"] = req.Status } if req.Remark != "" { data["remark"] = req.Remark } data["updater"] = getAdminUserID(ctx) // 更新数据库 err := o.Database.UpdateSensitiveWord(ctx, req.Id, data) if err != nil { return nil, err } return &chatpb.UpdateSensitiveWordResp{}, nil } // DeleteSensitiveWord 删除敏感词 func (o *chatSvr) DeleteSensitiveWord(ctx context.Context, req *chatpb.DeleteSensitiveWordReq) (*chatpb.DeleteSensitiveWordResp, error) { // 检查管理员权限 if _, err := mctx.CheckAdmin(ctx); err != nil { return nil, err } // 删除数据 err := o.Database.DeleteSensitiveWord(ctx, req.Ids) if err != nil { return nil, err } return &chatpb.DeleteSensitiveWordResp{}, nil } // GetSensitiveWord 获取敏感词 func (o *chatSvr) GetSensitiveWord(ctx context.Context, req *chatpb.GetSensitiveWordReq) (*chatpb.GetSensitiveWordResp, error) { // 检查管理员权限 if _, err := mctx.CheckAdmin(ctx); err != nil { return nil, err } // 查询数据 word, err := o.Database.GetSensitiveWord(ctx, req.Id) if err != nil { return nil, err } return &chatpb.GetSensitiveWordResp{ Word: convertToSensitiveWordDetailInfo(word), }, nil } // SearchSensitiveWords 搜索敏感词 func (o *chatSvr) SearchSensitiveWords(ctx context.Context, req *chatpb.SearchSensitiveWordsReq) (*chatpb.SearchSensitiveWordsResp, error) { // 检查管理员权限 if _, err := mctx.CheckAdmin(ctx); err != nil { return nil, err } // 搜索数据 total, words, err := o.Database.SearchSensitiveWords(ctx, req.Keyword, req.Action, req.Status, req.Pagination) if err != nil { return nil, err } // 转换结果 var wordInfos []*chatpb.SensitiveWordDetailInfo for _, word := range words { wordInfos = append(wordInfos, convertToSensitiveWordDetailInfo(word)) } return &chatpb.SearchSensitiveWordsResp{ Total: uint32(total), Words: wordInfos, }, nil } // BatchAddSensitiveWords 批量添加敏感词 func (o *chatSvr) BatchAddSensitiveWords(ctx context.Context, req *chatpb.BatchAddSensitiveWordsReq) (*chatpb.BatchAddSensitiveWordsResp, error) { // 检查管理员权限 if _, err := mctx.CheckAdmin(ctx); err != nil { return nil, err } // 转换为数据库模型 var words []*chat.SensitiveWord now := time.Now() adminID := getAdminUserID(ctx) for _, wordInfo := range req.Words { words = append(words, &chat.SensitiveWord{ ID: uuid.New().String(), Word: wordInfo.Word, Level: wordInfo.Level, Type: wordInfo.Type, Action: wordInfo.Action, Status: wordInfo.Status, Creator: adminID, Updater: adminID, CreateTime: now, UpdateTime: now, Remark: wordInfo.Remark, }) } // 批量保存 err := o.Database.BatchAddSensitiveWords(ctx, words) if err != nil { return nil, err } return &chatpb.BatchAddSensitiveWordsResp{}, nil } // BatchUpdateSensitiveWords 批量更新敏感词 func (o *chatSvr) BatchUpdateSensitiveWords(ctx context.Context, req *chatpb.BatchUpdateSensitiveWordsReq) (*chatpb.BatchUpdateSensitiveWordsResp, error) { // 检查管理员权限 if _, err := mctx.CheckAdmin(ctx); err != nil { return nil, err } // 转换为数据库模型 updates := make(map[string]map[string]any) adminID := getAdminUserID(ctx) for id, wordInfo := range req.Updates { data := make(map[string]any) if wordInfo.Word != "" { data["word"] = wordInfo.Word } if wordInfo.Level > 0 { data["level"] = wordInfo.Level } if wordInfo.Type > 0 { data["type"] = wordInfo.Type } if wordInfo.Action > 0 { data["action"] = wordInfo.Action } if wordInfo.Status >= 0 { data["status"] = wordInfo.Status } if wordInfo.Remark != "" { data["remark"] = wordInfo.Remark } data["updater"] = adminID updates[id] = data } // 批量更新 err := o.Database.BatchUpdateSensitiveWords(ctx, updates) if err != nil { return nil, err } return &chatpb.BatchUpdateSensitiveWordsResp{}, nil } // BatchDeleteSensitiveWords 批量删除敏感词 func (o *chatSvr) BatchDeleteSensitiveWords(ctx context.Context, req *chatpb.BatchDeleteSensitiveWordsReq) (*chatpb.BatchDeleteSensitiveWordsResp, error) { // 检查管理员权限 if _, err := mctx.CheckAdmin(ctx); err != nil { return nil, err } // 批量删除 err := o.Database.BatchDeleteSensitiveWords(ctx, req.Ids) if err != nil { return nil, err } return &chatpb.BatchDeleteSensitiveWordsResp{}, nil } // ==================== 敏感词分组管理相关 RPC ==================== // AddSensitiveWordGroup 添加敏感词分组 func (o *chatSvr) AddSensitiveWordGroup(ctx context.Context, req *chatpb.AddSensitiveWordGroupReq) (*chatpb.AddSensitiveWordGroupResp, error) { // 检查管理员权限 if _, err := mctx.CheckAdmin(ctx); err != nil { return nil, err } // 创建分组对象 group := &chat.SensitiveWordGroup{ ID: primitive.NewObjectID(), Name: req.Name, Remark: req.Remark, CreateTime: time.Now(), UpdateTime: time.Now(), } // 保存到数据库 err := o.Database.CreateSensitiveWordGroup(ctx, group) if err != nil { return nil, err } return &chatpb.AddSensitiveWordGroupResp{}, nil } // UpdateSensitiveWordGroup 更新敏感词分组 func (o *chatSvr) UpdateSensitiveWordGroup(ctx context.Context, req *chatpb.UpdateSensitiveWordGroupReq) (*chatpb.UpdateSensitiveWordGroupResp, error) { // 检查管理员权限 if _, err := mctx.CheckAdmin(ctx); err != nil { return nil, err } // 构建更新数据 data := make(map[string]any) if req.Name != "" { data["name"] = req.Name } if req.Remark != "" { data["remark"] = req.Remark } // 更新数据库 err := o.Database.UpdateSensitiveWordGroup(ctx, req.Id, data) if err != nil { return nil, err } return &chatpb.UpdateSensitiveWordGroupResp{}, nil } // DeleteSensitiveWordGroup 删除敏感词分组 func (o *chatSvr) DeleteSensitiveWordGroup(ctx context.Context, req *chatpb.DeleteSensitiveWordGroupReq) (*chatpb.DeleteSensitiveWordGroupResp, error) { // 检查管理员权限 if _, err := mctx.CheckAdmin(ctx); err != nil { return nil, err } // 删除数据 err := o.Database.DeleteSensitiveWordGroup(ctx, req.Ids) if err != nil { return nil, err } return &chatpb.DeleteSensitiveWordGroupResp{}, nil } // GetSensitiveWordGroup 获取敏感词分组 func (o *chatSvr) GetSensitiveWordGroup(ctx context.Context, req *chatpb.GetSensitiveWordGroupReq) (*chatpb.GetSensitiveWordGroupResp, error) { // 检查管理员权限 if _, err := mctx.CheckAdmin(ctx); err != nil { return nil, err } // 查询数据 group, err := o.Database.GetSensitiveWordGroup(ctx, req.Id) if err != nil { return nil, err } return &chatpb.GetSensitiveWordGroupResp{ Group: convertToSensitiveWordGroupInfo(group), }, nil } // GetAllSensitiveWordGroups 获取所有敏感词分组 func (o *chatSvr) GetAllSensitiveWordGroups(ctx context.Context, req *chatpb.GetAllSensitiveWordGroupsReq) (*chatpb.GetAllSensitiveWordGroupsResp, error) { // 检查管理员权限 if _, err := mctx.CheckAdmin(ctx); err != nil { return nil, err } // 查询数据 groups, err := o.Database.GetAllSensitiveWordGroups(ctx) if err != nil { return nil, err } // 转换结果 var groupInfos []*chatpb.SensitiveWordGroupInfo for _, group := range groups { groupInfos = append(groupInfos, convertToSensitiveWordGroupInfo(group)) } return &chatpb.GetAllSensitiveWordGroupsResp{ Groups: groupInfos, }, nil } // ==================== 敏感词配置管理相关 RPC ==================== // GetSensitiveWordConfig 获取敏感词配置 func (o *chatSvr) GetSensitiveWordConfig(ctx context.Context, req *chatpb.GetSensitiveWordConfigReq) (*chatpb.GetSensitiveWordConfigResp, error) { fmt.Println("GetSensitiveWordConfig", "_________11", req) // 检查管理员权限 if _, err := mctx.CheckAdmin(ctx); err != nil { fmt.Println("GetSensitiveWordConfig", "_________22", err) return nil, err } fmt.Println("GetSensitiveWordConfig", "_________33") // 查询数据 config, err := o.Database.GetSensitiveWordConfig(ctx) if err != nil { fmt.Println("GetSensitiveWordConfig", "_________44", err) return nil, err } return &chatpb.GetSensitiveWordConfigResp{ Config: convertToSensitiveWordConfigInfo(config), }, nil } // UpdateSensitiveWordConfig 更新敏感词配置 func (o *chatSvr) UpdateSensitiveWordConfig(ctx context.Context, req *chatpb.UpdateSensitiveWordConfigReq) (*chatpb.UpdateSensitiveWordConfigResp, error) { // 检查管理员权限 if _, err := mctx.CheckAdmin(ctx); err != nil { return nil, err } // 转换为数据库模型 config := &chat.SensitiveWordConfig{ ID: req.Config.Id, EnableFilter: req.Config.EnableFilter, FilterMode: req.Config.FilterMode, ReplaceChar: req.Config.ReplaceChar, WhitelistUsers: req.Config.WhitelistUsers, WhitelistGroups: req.Config.WhitelistGroups, LogEnabled: req.Config.LogEnabled, AutoApprove: req.Config.AutoApprove, UpdateTime: time.Now(), } // 更新数据库 err := o.Database.UpdateSensitiveWordConfig(ctx, config) if err != nil { return nil, err } return &chatpb.UpdateSensitiveWordConfigResp{}, nil } // ==================== 敏感词日志管理相关 RPC ==================== // GetSensitiveWordLogs 获取敏感词日志 func (o *chatSvr) GetSensitiveWordLogs(ctx context.Context, req *chatpb.GetSensitiveWordLogsReq) (*chatpb.GetSensitiveWordLogsResp, error) { // 检查管理员权限 if _, err := mctx.CheckAdmin(ctx); err != nil { return nil, err } // 查询数据 total, logs, err := o.Database.GetSensitiveWordLogs(ctx, req.UserId, req.GroupId, req.Pagination) if err != nil { return nil, err } // 转换结果 var logInfos []*chatpb.SensitiveWordLogInfo for _, log := range logs { logInfos = append(logInfos, convertToSensitiveWordLogInfo(log)) } return &chatpb.GetSensitiveWordLogsResp{ Total: uint32(total), Logs: logInfos, }, nil } // DeleteSensitiveWordLogs 删除敏感词日志 func (o *chatSvr) DeleteSensitiveWordLogs(ctx context.Context, req *chatpb.DeleteSensitiveWordLogsReq) (*chatpb.DeleteSensitiveWordLogsResp, error) { // 检查管理员权限 if _, err := mctx.CheckAdmin(ctx); err != nil { return nil, err } // 删除数据 err := o.Database.DeleteSensitiveWordLogs(ctx, req.Ids) if err != nil { return nil, err } return &chatpb.DeleteSensitiveWordLogsResp{}, nil } // ==================== 敏感词统计相关 RPC ==================== // GetSensitiveWordStats 获取敏感词统计 func (o *chatSvr) GetSensitiveWordStats(ctx context.Context, req *chatpb.GetSensitiveWordStatsReq) (*chatpb.GetSensitiveWordStatsResp, error) { // 检查管理员权限 if _, err := mctx.CheckAdmin(ctx); err != nil { return nil, err } // 查询数据 stats, err := o.Database.GetSensitiveWordStats(ctx) if err != nil { return nil, err } return &chatpb.GetSensitiveWordStatsResp{ Stats: &chatpb.SensitiveWordStatsInfo{ Total: stats["total"], Enabled: stats["enabled"], Disabled: stats["disabled"], Replace: stats["replace"], Block: stats["block"], }, }, nil } // GetSensitiveWordLogStats 获取敏感词日志统计 func (o *chatSvr) GetSensitiveWordLogStats(ctx context.Context, req *chatpb.GetSensitiveWordLogStatsReq) (*chatpb.GetSensitiveWordLogStatsResp, error) { // 检查管理员权限 if _, err := mctx.CheckAdmin(ctx); err != nil { return nil, err } // 查询数据 startTime := time.Unix(req.StartTime, 0) endTime := time.Unix(req.EndTime, 0) stats, err := o.Database.GetSensitiveWordLogStats(ctx, startTime, endTime) if err != nil { return nil, err } return &chatpb.GetSensitiveWordLogStatsResp{ Stats: &chatpb.SensitiveWordLogStatsInfo{ Total: stats["total"], Replace: stats["replace"], Block: stats["block"], }, }, nil } // ==================== 辅助函数 ==================== // getAdminUserID 获取当前管理员用户ID func getAdminUserID(ctx context.Context) string { userID, _ := mctx.CheckAdmin(ctx) return userID } // convertToSensitiveWordDetailInfo 转换为敏感词详细信息 func convertToSensitiveWordDetailInfo(word *chat.SensitiveWord) *chatpb.SensitiveWordDetailInfo { return &chatpb.SensitiveWordDetailInfo{ Id: word.ID, Word: word.Word, Level: word.Level, Type: word.Type, Action: word.Action, Status: word.Status, Creator: word.Creator, Updater: word.Updater, CreateTime: word.CreateTime.UnixMilli(), UpdateTime: word.UpdateTime.UnixMilli(), Remark: word.Remark, } } // convertToSensitiveWordGroupInfo 转换为敏感词分组信息 func convertToSensitiveWordGroupInfo(group *chat.SensitiveWordGroup) *chatpb.SensitiveWordGroupInfo { return &chatpb.SensitiveWordGroupInfo{ Id: group.ID.Hex(), Name: group.Name, Remark: group.Remark, CreateTime: group.CreateTime.UnixMilli(), UpdateTime: group.UpdateTime.UnixMilli(), } } // convertToSensitiveWordConfigInfo 转换为敏感词配置信息 func convertToSensitiveWordConfigInfo(config *chat.SensitiveWordConfig) *chatpb.SensitiveWordConfigInfo { return &chatpb.SensitiveWordConfigInfo{ Id: config.ID, EnableFilter: config.EnableFilter, FilterMode: config.FilterMode, ReplaceChar: config.ReplaceChar, WhitelistUsers: config.WhitelistUsers, WhitelistGroups: config.WhitelistGroups, LogEnabled: config.LogEnabled, AutoApprove: config.AutoApprove, UpdateTime: config.UpdateTime.UnixMilli(), } } // convertToSensitiveWordLogInfo 转换为敏感词日志信息 func convertToSensitiveWordLogInfo(log *chat.SensitiveWordLog) *chatpb.SensitiveWordLogInfo { return &chatpb.SensitiveWordLogInfo{ Id: log.ID.Hex(), UserId: log.UserID, GroupId: log.GroupID, Content: log.Content, MatchedWords: log.MatchedWords, Action: log.Action, ProcessedText: log.ProcessedText, CreateTime: log.CreateTime.UnixMilli(), } }