- Replaced instances of the previous messaging system with LiteCqrs across various application components, enhancing the CQRS implementation. - Updated dependency injection to register LiteCqrs services and behaviors, streamlining command and query handling. - Adjusted multiple command and query handlers to align with the new messaging framework, ensuring consistent functionality and improved maintainability. - Added LiteCqrs package reference in the project file for better dependency management.
70 lines
2.5 KiB
C#
70 lines
2.5 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using PnvPanel.Application.Auth;
|
|
using PnvPanel.Application.Common.Interfaces;
|
|
using LiteCqrs;
|
|
using PnvPanel.Application.Common.Models;
|
|
using PnvPanel.Domain.Audit;
|
|
using PnvPanel.Domain.Support;
|
|
|
|
namespace PnvPanel.Application.Admin.Maintenance;
|
|
|
|
public sealed class DeleteClosedTicketsCommandHandler(
|
|
IAppDbContext dbContext,
|
|
IFileStorage fileStorage,
|
|
ICurrentUser currentUser
|
|
) : ICommandHandler<DeleteClosedTicketsCommand, Result<int>>
|
|
{
|
|
public async Task<Result<int>> Handle(
|
|
DeleteClosedTicketsCommand command,
|
|
CancellationToken cancellationToken
|
|
)
|
|
{
|
|
if (currentUser.UserId is not { } adminId)
|
|
return Result.Failure<int>(AuthErrors.Unauthorized);
|
|
|
|
var ticketIds = await dbContext
|
|
.SupportTickets.AsNoTracking()
|
|
.Where(t => t.Status == TicketStatus.Closed)
|
|
.Select(t => t.Id)
|
|
.ToListAsync(cancellationToken);
|
|
|
|
if (ticketIds.Count == 0)
|
|
return Result.Success(0);
|
|
|
|
// Тикет/комментарий/вложение — плоские сущности без FK-каскада (см. SupportTicket), поэтому
|
|
// порядок удаления важен: вложения (+ файлы на диске) -> комментарии -> тикеты.
|
|
var comments = await dbContext
|
|
.TicketComments.Where(c => ticketIds.Contains(c.TicketId))
|
|
.ToListAsync(cancellationToken);
|
|
var commentIds = comments.Select(c => c.Id).ToList();
|
|
|
|
var attachments = await dbContext
|
|
.TicketAttachments.Where(a => commentIds.Contains(a.CommentId))
|
|
.ToListAsync(cancellationToken);
|
|
|
|
foreach (var attachment in attachments)
|
|
await fileStorage.DeleteAsync(attachment.StoredFileName, cancellationToken);
|
|
|
|
dbContext.TicketAttachments.RemoveRange(attachments);
|
|
dbContext.TicketComments.RemoveRange(comments);
|
|
|
|
var tickets = await dbContext
|
|
.SupportTickets.Where(t => ticketIds.Contains(t.Id))
|
|
.ToListAsync(cancellationToken);
|
|
dbContext.SupportTickets.RemoveRange(tickets);
|
|
|
|
dbContext.AuditLogs.Add(
|
|
AuditLog.Create(
|
|
adminId,
|
|
"ClosedTicketsCleanedUp",
|
|
"SupportTicket",
|
|
"bulk",
|
|
metadata: $"{{\"count\":{ticketIds.Count}}}",
|
|
AuditSource.Web
|
|
)
|
|
);
|
|
|
|
return Result.Success(ticketIds.Count);
|
|
}
|
|
}
|