复制项目

This commit is contained in:
kim.dev.6789
2026-01-14 22:35:45 +08:00
parent 305d526110
commit b7f8db7d08
297 changed files with 81784 additions and 0 deletions

View File

@@ -0,0 +1,422 @@
// 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"
"strings"
"time"
"git.imall.cloud/openim/chat/pkg/common/db/table/chat"
"github.com/openimsdk/tools/db/mongoutil"
"github.com/openimsdk/tools/db/pagination"
"github.com/openimsdk/tools/errs"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func NewSensitiveWord(db *mongo.Database) (chat.SensitiveWordInterface, error) {
coll := db.Collection("sensitive_words")
_, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{
{
Keys: bson.D{
{Key: "word", Value: 1},
},
Options: options.Index().SetUnique(true),
},
{
Keys: bson.D{
{Key: "status", Value: 1},
},
},
})
if err != nil {
return nil, errs.Wrap(err)
}
// 创建配置集合
configColl := db.Collection("sensitive_word_configs")
_, err = configColl.Indexes().CreateOne(context.Background(), mongo.IndexModel{
Keys: bson.D{
{Key: "enable_filter", Value: 1},
},
})
if err != nil {
return nil, errs.Wrap(err)
}
// 检查并初始化默认配置
ctx := context.Background()
count, err := configColl.CountDocuments(ctx, bson.M{})
if err != nil {
return nil, errs.Wrap(err)
}
if count == 0 {
// 创建默认配置
defaultConfig := &chat.SensitiveWordConfig{
ID: "default",
EnableFilter: true,
FilterMode: 1,
ReplaceChar: "***",
WhitelistUsers: []string{},
WhitelistGroups: []string{},
LogEnabled: true,
AutoApprove: false,
UpdateTime: time.Now(),
}
_, err = configColl.InsertOne(ctx, defaultConfig)
if err != nil {
return nil, errs.Wrap(err)
}
}
return &SensitiveWord{coll: coll, configColl: configColl}, nil
}
type SensitiveWord struct {
coll *mongo.Collection
configColl *mongo.Collection
}
// ==================== 敏感词管理 ====================
func (o *SensitiveWord) CreateSensitiveWord(ctx context.Context, word *chat.SensitiveWord) error {
word.CreateTime = time.Now()
word.UpdateTime = time.Now()
return mongoutil.InsertMany(ctx, o.coll, []*chat.SensitiveWord{word})
}
func (o *SensitiveWord) UpdateSensitiveWord(ctx context.Context, id string, data map[string]any) error {
data["update_time"] = time.Now()
return mongoutil.UpdateOne(ctx, o.coll, bson.M{"_id": id}, bson.M{"$set": data}, false)
}
func (o *SensitiveWord) DeleteSensitiveWord(ctx context.Context, ids []string) error {
return mongoutil.DeleteMany(ctx, o.coll, bson.M{"_id": bson.M{"$in": ids}})
}
func (o *SensitiveWord) GetSensitiveWord(ctx context.Context, id string) (*chat.SensitiveWord, error) {
return mongoutil.FindOne[*chat.SensitiveWord](ctx, o.coll, bson.M{"_id": id})
}
func (o *SensitiveWord) SearchSensitiveWords(ctx context.Context, keyword string, action int32, status int32, pagination pagination.Pagination) (int64, []*chat.SensitiveWord, error) {
filter := bson.M{}
if keyword != "" {
filter["word"] = bson.M{"$regex": keyword, "$options": "i"}
}
if action > 0 {
filter["action"] = action
}
if status > 0 {
filter["status"] = status
}
return mongoutil.FindPage[*chat.SensitiveWord](ctx, o.coll, filter, pagination)
}
func (o *SensitiveWord) GetAllSensitiveWords(ctx context.Context) ([]*chat.SensitiveWord, error) {
return mongoutil.Find[*chat.SensitiveWord](ctx, o.coll, bson.M{})
}
func (o *SensitiveWord) GetEnabledSensitiveWords(ctx context.Context) ([]*chat.SensitiveWord, error) {
return mongoutil.Find[*chat.SensitiveWord](ctx, o.coll, bson.M{"status": chat.SensitiveStatusEnabled})
}
// ==================== 敏感词检测和过滤 ====================
func (o *SensitiveWord) CheckSensitiveWords(ctx context.Context, content string) ([]*chat.SensitiveWord, error) {
words, err := o.GetEnabledSensitiveWords(ctx)
if err != nil {
return nil, err
}
var matchedWords []*chat.SensitiveWord
contentLower := strings.ToLower(content)
for _, word := range words {
if strings.Contains(contentLower, strings.ToLower(word.Word)) {
matchedWords = append(matchedWords, word)
}
}
return matchedWords, nil
}
func (o *SensitiveWord) FilterContent(ctx context.Context, content string) (string, []*chat.SensitiveWord, error) {
words, err := o.CheckSensitiveWords(ctx, content)
if err != nil {
return content, nil, err
}
if len(words) == 0 {
return content, words, nil
}
filteredContent := content
for _, word := range words {
replaceChar := "***"
filteredContent = strings.ReplaceAll(filteredContent, word.Word, replaceChar)
}
return filteredContent, words, nil
}
// ==================== 敏感词日志管理 ====================
func (o *SensitiveWord) CreateSensitiveWordLog(ctx context.Context, log *chat.SensitiveWordLog) error {
log.CreateTime = time.Now()
return mongoutil.InsertMany(ctx, o.coll.Database().Collection("sensitive_word_logs"), []*chat.SensitiveWordLog{log})
}
func (o *SensitiveWord) GetSensitiveWordLogs(ctx context.Context, userID, groupID string, pagination pagination.Pagination) (int64, []*chat.SensitiveWordLog, error) {
filter := bson.M{}
if userID != "" {
filter["user_id"] = userID
}
if groupID != "" {
filter["group_id"] = groupID
}
coll := o.coll.Database().Collection("sensitive_word_logs")
return mongoutil.FindPage[*chat.SensitiveWordLog](ctx, coll, filter, pagination)
}
func (o *SensitiveWord) DeleteSensitiveWordLogs(ctx context.Context, ids []string) error {
coll := o.coll.Database().Collection("sensitive_word_logs")
return mongoutil.DeleteMany(ctx, coll, bson.M{"_id": bson.M{"$in": ids}})
}
// ==================== 敏感词分组管理 ====================
func (o *SensitiveWord) CreateSensitiveWordGroup(ctx context.Context, group *chat.SensitiveWordGroup) error {
group.CreateTime = time.Now()
group.UpdateTime = time.Now()
return mongoutil.InsertMany(ctx, o.coll.Database().Collection("sensitive_word_groups"), []*chat.SensitiveWordGroup{group})
}
func (o *SensitiveWord) UpdateSensitiveWordGroup(ctx context.Context, id string, data map[string]any) error {
data["update_time"] = time.Now()
coll := o.coll.Database().Collection("sensitive_word_groups")
return mongoutil.UpdateOne(ctx, coll, bson.M{"_id": id}, bson.M{"$set": data}, false)
}
func (o *SensitiveWord) DeleteSensitiveWordGroup(ctx context.Context, ids []string) error {
coll := o.coll.Database().Collection("sensitive_word_groups")
return mongoutil.DeleteMany(ctx, coll, bson.M{"_id": bson.M{"$in": ids}})
}
func (o *SensitiveWord) GetSensitiveWordGroup(ctx context.Context, id string) (*chat.SensitiveWordGroup, error) {
coll := o.coll.Database().Collection("sensitive_word_groups")
return mongoutil.FindOne[*chat.SensitiveWordGroup](ctx, coll, bson.M{"_id": id})
}
func (o *SensitiveWord) GetAllSensitiveWordGroups(ctx context.Context) ([]*chat.SensitiveWordGroup, error) {
coll := o.coll.Database().Collection("sensitive_word_groups")
return mongoutil.Find[*chat.SensitiveWordGroup](ctx, coll, bson.M{})
}
// ==================== 敏感词配置管理 ====================
func (o *SensitiveWord) GetSensitiveWordConfig(ctx context.Context) (*chat.SensitiveWordConfig, error) {
// 查找配置(默认配置已在初始化时创建)
config, err := mongoutil.FindOne[*chat.SensitiveWordConfig](ctx, o.configColl, bson.M{})
if err != nil {
return nil, err
}
return config, nil
}
func (o *SensitiveWord) UpdateSensitiveWordConfig(ctx context.Context, config *chat.SensitiveWordConfig) error {
config.UpdateTime = time.Now()
if config.ID == "" {
config.ID = "default"
}
filter := bson.M{"_id": config.ID}
fmt.Println("UpdateSensitiveWordConfig", "_________55", config, o.configColl.Name())
err := mongoutil.UpdateOne(ctx, o.configColl, filter, bson.M{"$set": config}, true)
fmt.Println("UpdateSensitiveWordConfig", "_________44", config)
if err != nil {
return err
}
return nil
}
func (o *SensitiveWord) IsFilterEnabled(ctx context.Context) (bool, error) {
config, err := o.GetSensitiveWordConfig(ctx)
if err != nil {
return false, err
}
return config.EnableFilter, nil
}
func (o *SensitiveWord) GetFilterMode(ctx context.Context) (int32, error) {
// 简化实现,返回默认值
return 1, nil
}
func (o *SensitiveWord) GetReplaceChar(ctx context.Context) (string, error) {
config, err := o.GetSensitiveWordConfig(ctx)
if err != nil {
return "***", err
}
if config.ReplaceChar == "" {
return "***", nil
}
return config.ReplaceChar, nil
}
func (o *SensitiveWord) IsUserInWhitelist(ctx context.Context, userID string) (bool, error) {
config, err := o.GetSensitiveWordConfig(ctx)
if err != nil {
return false, err
}
for _, id := range config.WhitelistUsers {
if id == userID {
return true, nil
}
}
return false, nil
}
func (o *SensitiveWord) IsGroupInWhitelist(ctx context.Context, groupID string) (bool, error) {
config, err := o.GetSensitiveWordConfig(ctx)
if err != nil {
return false, err
}
for _, id := range config.WhitelistGroups {
if id == groupID {
return true, nil
}
}
return false, nil
}
// ==================== 批量操作 ====================
func (o *SensitiveWord) BatchCreateSensitiveWords(ctx context.Context, words []*chat.SensitiveWord) error {
now := time.Now()
for _, word := range words {
word.CreateTime = now
word.UpdateTime = now
}
return mongoutil.InsertMany(ctx, o.coll, words)
}
func (o *SensitiveWord) BatchUpdateSensitiveWords(ctx context.Context, updates map[string]map[string]any) error {
for id, data := range updates {
data["update_time"] = time.Now()
err := mongoutil.UpdateOne(ctx, o.coll, bson.M{"_id": id}, bson.M{"$set": data}, false)
if err != nil {
return err
}
}
return nil
}
func (o *SensitiveWord) BatchDeleteSensitiveWords(ctx context.Context, ids []string) error {
return mongoutil.DeleteMany(ctx, o.coll, bson.M{"_id": bson.M{"$in": ids}})
}
// ==================== 统计信息 ====================
func (o *SensitiveWord) GetSensitiveWordStats(ctx context.Context) (map[string]int64, error) {
stats := make(map[string]int64)
// 总数
total, err := mongoutil.Count(ctx, o.coll, bson.M{})
if err != nil {
return nil, err
}
stats["total"] = total
// 启用数量
enabled, err := mongoutil.Count(ctx, o.coll, bson.M{"status": chat.SensitiveStatusEnabled})
if err != nil {
return nil, err
}
stats["enabled"] = enabled
// 禁用数量
disabled, err := mongoutil.Count(ctx, o.coll, bson.M{"status": chat.SensitiveStatusDisabled})
if err != nil {
return nil, err
}
stats["disabled"] = disabled
// 替换模式数量
replace, err := mongoutil.Count(ctx, o.coll, bson.M{"action": chat.SensitiveActionReplace})
if err != nil {
return nil, err
}
stats["replace"] = replace
// 拦截模式数量
block, err := mongoutil.Count(ctx, o.coll, bson.M{"action": chat.SensitiveActionBlock})
if err != nil {
return nil, err
}
stats["block"] = block
return stats, nil
}
func (o *SensitiveWord) GetSensitiveWordLogStats(ctx context.Context, startTime, endTime time.Time) (map[string]int64, error) {
stats := make(map[string]int64)
coll := o.coll.Database().Collection("sensitive_word_logs")
filter := bson.M{
"create_time": bson.M{
"$gte": startTime,
"$lte": endTime,
},
}
// 总数
total, err := mongoutil.Count(ctx, coll, filter)
if err != nil {
return nil, err
}
stats["total"] = total
// 替换数量
replaceFilter := bson.M{}
for k, v := range filter {
replaceFilter[k] = v
}
replaceFilter["action"] = chat.SensitiveActionReplace
replace, err := mongoutil.Count(ctx, coll, replaceFilter)
if err != nil {
return nil, err
}
stats["replace"] = replace
// 拦截数量
blockFilter := bson.M{}
for k, v := range filter {
blockFilter[k] = v
}
blockFilter["action"] = chat.SensitiveActionBlock
block, err := mongoutil.Count(ctx, coll, blockFilter)
if err != nil {
return nil, err
}
stats["block"] = block
return stats, nil
}