SPMS_API/SPMS.Infrastructure/Persistence/Repositories/MessageRepository.cs
SEAN 0eacf25eb3 improvement: 메시지 상세/프리뷰 응답 강화 (#226)
- MessageInfoResponseDto에 service_name, service_code, created_by_name, latest_send_status 추가
- MessagePreviewRequestDto/ResponseDto에 JsonPropertyName snake_case 적용
- MessagePreviewResponseDto에 link_type 필드 추가
- Repository에 GetByMessageCodeWithDetailsAsync (Navigation Include), GetSendStatsAsync 추가
- MessageService.GetInfoAsync에서 서비스/작성자/발송상태 매핑
- MessageService.PreviewAsync에서 link_type 반환

Closes #226
2026-02-25 14:43:29 +09:00

126 lines
4.4 KiB
C#

using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using SPMS.Domain.Entities;
using SPMS.Domain.Enums;
using SPMS.Domain.Interfaces;
namespace SPMS.Infrastructure.Persistence.Repositories;
public class MessageRepository : Repository<Message>, IMessageRepository
{
public MessageRepository(AppDbContext context) : base(context) { }
public async Task<Message?> GetByMessageCodeAsync(string messageCode)
{
return await _dbSet
.FirstOrDefaultAsync(m => m.MessageCode == messageCode && !m.IsDeleted);
}
public async Task<Message?> GetByMessageCodeAndServiceAsync(string messageCode, long serviceId)
{
return await _dbSet
.FirstOrDefaultAsync(m => m.MessageCode == messageCode && m.ServiceId == serviceId && !m.IsDeleted);
}
public async Task<int> GetTodaySequenceAsync(long serviceId)
{
var todayStart = DateTime.UtcNow.Date;
var todayEnd = todayStart.AddDays(1);
return await _dbSet
.CountAsync(m => m.ServiceId == serviceId
&& m.CreatedAt >= todayStart
&& m.CreatedAt < todayEnd);
}
public async Task<(IReadOnlyList<Message> Items, int TotalCount)> GetPagedByServiceAsync(
long serviceId, int page, int size,
Expression<Func<Message, bool>>? predicate = null)
{
var query = _dbSet
.Where(m => m.ServiceId == serviceId && !m.IsDeleted);
if (predicate != null)
query = query.Where(predicate);
var totalCount = await query.CountAsync();
var items = await query
.OrderByDescending(m => m.CreatedAt)
.Skip((page - 1) * size)
.Take(size)
.ToListAsync();
return (items, totalCount);
}
public async Task<Message?> GetByMessageCodeWithDetailsAsync(string messageCode, long serviceId)
{
return await _dbSet
.Include(m => m.Service)
.Include(m => m.CreatedByAdmin)
.FirstOrDefaultAsync(m => m.MessageCode == messageCode && m.ServiceId == serviceId && !m.IsDeleted);
}
public async Task<(int TotalSendCount, int SuccessCount)> GetSendStatsAsync(long messageId)
{
var stats = await _context.PushSendLogs
.Where(l => l.MessageId == messageId)
.GroupBy(_ => 1)
.Select(g => new
{
Total = g.Count(),
Success = g.Count(l => l.Status == PushResult.Success)
})
.FirstOrDefaultAsync();
return stats != null ? (stats.Total, stats.Success) : (0, 0);
}
public async Task<(IReadOnlyList<MessageListProjection> Items, int TotalCount)> GetPagedForListAsync(
long? serviceId, int page, int size,
string? keyword = null, bool? isActive = null, string? sendStatus = null)
{
var query = _dbSet.Where(m => !m.IsDeleted);
if (serviceId.HasValue)
query = query.Where(m => m.ServiceId == serviceId.Value);
if (!string.IsNullOrWhiteSpace(keyword))
query = query.Where(m => m.Title.Contains(keyword) || m.Body.Contains(keyword));
if (isActive.HasValue)
query = query.Where(m => m.IsDeleted != isActive.Value);
var projected = query.Select(m => new MessageListProjection
{
MessageCode = m.MessageCode,
Title = m.Title,
IsActive = !m.IsDeleted,
CreatedAt = m.CreatedAt,
ServiceName = m.Service.ServiceName,
ServiceCode = m.Service.ServiceCode,
TotalSendCount = _context.PushSendLogs.Count(l => l.MessageId == m.Id),
SuccessCount = _context.PushSendLogs.Count(l => l.MessageId == m.Id && l.Status == PushResult.Success)
});
// 발송 상태 필터
if (sendStatus == "complete")
projected = projected.Where(p => p.SuccessCount > 0);
else if (sendStatus == "failed")
projected = projected.Where(p => p.TotalSendCount > 0 && p.SuccessCount == 0);
else if (sendStatus == "pending")
projected = projected.Where(p => p.TotalSendCount == 0);
var totalCount = await projected.CountAsync();
var items = await projected
.OrderByDescending(p => p.CreatedAt)
.Skip((page - 1) * size)
.Take(size)
.ToListAsync();
return (items, totalCount);
}
}