- 将 AlertRule 和 ExternalSystem 实体改为使用 JsonData 存储业务字段 - 移除独立的 ExternalSystemCredential 表,凭证信息合并到 ExternalSystem.JsonData - 添加强类型视图 Data 属性用于访问 JsonData 中的业务数据 - 更新数据库配置将字段存储改为 jsonb 类型并调整索引策略 - 重构告警评估器使用 JsonData 强类型视图读取规则数据 - 更新连接器凭证解析器从 JsonData 中获取凭证信息 - 在 appsettings.json 中添加 monitoring 模块配置 - 将 monitoring 模块集成到主应用程序中并注册服务 - 更新相关处理器使用新的数据模型结构
109 lines
3.7 KiB
C#
109 lines
3.7 KiB
C#
using System.Text.RegularExpressions;
|
|
using BuildFlow.Shared.Domain.Exceptions;
|
|
using IM.Application.Chat.DTOs;
|
|
using IM.Application.Chat.Queries;
|
|
using IM.Domain.Common;
|
|
using IM.Infrastructure.Mongo;
|
|
using IM.Infrastructure.Persistence;
|
|
using MediatR;
|
|
using MongoDB.Bson;
|
|
using MongoDB.Entities;
|
|
|
|
namespace IM.Application.Chat.Handlers;
|
|
|
|
/// <summary>
|
|
/// 历史消息搜索处理器。基于 MongoDB 对消息正文、发送者名称和文件名进行模糊检索。
|
|
/// </summary>
|
|
public class SearchMessagesQueryHandler(
|
|
ImDbContext db,
|
|
IUserInfoService userInfoService) : IRequestHandler<SearchMessagesQuery, MessageHistoryDto>
|
|
{
|
|
public async Task<MessageHistoryDto> Handle(SearchMessagesQuery request, CancellationToken ct)
|
|
{
|
|
var isParticipant = await db.ConversationParticipants
|
|
.AnyAsync(p => p.ConversationId == request.ConversationId && p.UserId == request.UserId, ct);
|
|
|
|
if (!isParticipant)
|
|
{
|
|
throw new UnauthorizedException("无权搜索该会话的消息");
|
|
}
|
|
|
|
var keyword = request.Keyword.Trim();
|
|
if (keyword.Length == 0)
|
|
{
|
|
return new MessageHistoryDto([], false);
|
|
}
|
|
|
|
var escaped = Regex.Escape(keyword);
|
|
var regex = new BsonRegularExpression(escaped, "i");
|
|
|
|
var messages = await DB.Default.Find<MessageDocument>()
|
|
.Match(f => f.And(
|
|
f.Eq(m => m.ConversationId, request.ConversationId),
|
|
f.Or(
|
|
f.Regex(m => m.Content, regex),
|
|
f.Regex(m => m.SenderName, regex),
|
|
f.Regex("Metadata.FileName", regex))))
|
|
.Sort(m => m.CreatedAt, Order.Descending)
|
|
.Limit(request.Limit)
|
|
.ExecuteAsync(ct);
|
|
|
|
var dtos = await ToMessageDtosAsync(messages, ct);
|
|
return new MessageHistoryDto(dtos, false);
|
|
}
|
|
|
|
private async Task<List<MessageDto>> ToMessageDtosAsync(List<MessageDocument> messages, CancellationToken ct)
|
|
{
|
|
var senderIds = messages
|
|
.Where(m => string.IsNullOrEmpty(m.SenderAvatar))
|
|
.Select(m => m.SenderId)
|
|
.Distinct()
|
|
.ToList();
|
|
|
|
var users = senderIds.Count > 0
|
|
? await userInfoService.GetUsersAsync(senderIds, ct)
|
|
: new Dictionary<string, (string Username, string? Avatar)>();
|
|
|
|
return messages.Select(m =>
|
|
{
|
|
var avatar = m.SenderAvatar;
|
|
if (string.IsNullOrEmpty(avatar))
|
|
{
|
|
avatar = users.GetValueOrDefault(m.SenderId.ToString()).Avatar;
|
|
}
|
|
|
|
return new MessageDto(
|
|
m.ID,
|
|
m.ConversationId,
|
|
m.SenderId,
|
|
m.SenderName,
|
|
avatar,
|
|
m.ContentType,
|
|
m.Content,
|
|
m.Metadata != null ? new MessageMetadataDto(
|
|
m.Metadata.FileName,
|
|
m.Metadata.FileSize,
|
|
m.Metadata.FileUrl,
|
|
m.Metadata.ImageUrl,
|
|
m.Metadata.ImageWidth,
|
|
m.Metadata.ImageHeight,
|
|
m.Metadata.EmojiCode)
|
|
{
|
|
BucketName = m.Metadata.BucketName,
|
|
ObjectKey = m.Metadata.ObjectKey,
|
|
ContentType = m.Metadata.ContentType
|
|
} : null,
|
|
m.ReplyToId,
|
|
m.CreatedAt,
|
|
m.MentionUserIds,
|
|
m.MentionAll,
|
|
m.IsRecalled,
|
|
m.RecalledAt,
|
|
m.RecalledBy,
|
|
m.ForwardFromMessageId,
|
|
m.ForwardFromSenderName,
|
|
m.ForwardFromConversationId);
|
|
}).ToList();
|
|
}
|
|
}
|