Handler.cs 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. using Application.Abstractions.Data;
  2. using Application.Abstractions.Messaging;
  3. using Microsoft.EntityFrameworkCore;
  4. using SharedKernel.Results;
  5. namespace Application.Features.Api.Developers.Stats.UsageStats;
  6. internal sealed class Handler(IAppDbContext db) : IQueryHandler<Query, Result<Response>>
  7. {
  8. private const int DefaultDays = 7;
  9. private const int MaxDays = 90;
  10. public async Task<Result<Response>> Handle(Query request, CancellationToken ct)
  11. {
  12. var days = Math.Clamp(request.Days <= 0 ? DefaultDays : request.Days, 1, MaxDays);
  13. var since = DateTime.UtcNow.AddDays(-days);
  14. // 본인 소유 앱 + 본인 PAT 만 집계
  15. var ownedAppIDs = await db.ApiApplication
  16. .Where(c => c.OwnerMemberID == request.OwnerMemberID)
  17. .Select(c => c.ID)
  18. .ToListAsync(ct);
  19. var ownedPatIDs = await db.ApiPersonalAccessToken
  20. .Where(c => c.OwnerMemberID == request.OwnerMemberID)
  21. .Select(c => c.ID)
  22. .ToListAsync(ct);
  23. var raw = await db.ApiRequestLog
  24. .Where(c => c.RequestedAt >= since &&
  25. ((c.ApplicationID != null && ownedAppIDs.Contains(c.ApplicationID.Value)) ||
  26. (c.PatID != null && ownedPatIDs.Contains(c.PatID.Value))))
  27. .GroupBy(c => new { Date = DateOnly.FromDateTime(c.RequestedAt) })
  28. .Select(g => new DailyUsage(
  29. g.Key.Date,
  30. g.Count(),
  31. g.Count(c => c.StatusCode >= 400),
  32. (int)g.Average(c => (double)c.ResponseMs)
  33. ))
  34. .OrderBy(c => c.Date)
  35. .ToListAsync(ct);
  36. return Result.Success(new Response(raw));
  37. }
  38. }