Rewrites StatsRepository to be fully async and collapses the ~30 synchronous round-trips into a bounded set of aggregated queries: - Single grouped pass over non-deleted assets computes totals, storage, visibility breakdown, orphans, 7/30-day activity, and all data-completeness counts (missing metadata/thumbnail/preview/phash). - AssetsByType + StorageByType come from one GROUP BY on Type. - UsersByAccessLevel, TotalUsers, and users registered in 30 days come from one GROUP BY on AccessLevel. - MIME breakdown and resolution buckets are now GROUP BY'd in SQL; the resolution bucket key is a translatable CASE expression on the max dimension, so no more loading every asset's dimensions into memory. - AssetsWithNoAlbum / AssetsWithNoPerson use set-based NOT IN anti-joins over the Album.Assets navigation instead of per-row NOT EXISTS. - TopTags uses the Tag.Assets navigation (join table indexed on TagsId). - Drops IDisposable/Dispose() so the transient repo no longer disposes the shared scoped DbContext. - StatsController action is now async. StatsDto shape is unchanged, so the existing .http tests remain valid. Refs #173
32 lines
1.1 KiB
C#
32 lines
1.1 KiB
C#
using Butter.Dtos.Stats;
|
|
using Lactose.Repositories;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
namespace Lactose.Controllers;
|
|
|
|
/// <summary>
|
|
/// Provides aggregate statistics about the MilkyShots instance.
|
|
/// </summary>
|
|
/// <param name="logger">Logger instance.</param>
|
|
/// <param name="statsRepository">Stats repository.</param>
|
|
[ApiController]
|
|
[Route("api/[controller]")]
|
|
[Authorize(Roles = "Curator,Admin")]
|
|
public class StatsController(
|
|
ILogger<StatsController> logger,
|
|
IStatsRepository statsRepository
|
|
) : ControllerBase {
|
|
/// <summary>
|
|
/// Returns comprehensive aggregate statistics about the instance.
|
|
/// </summary>
|
|
/// <param name="cancellationToken">Cancellation token.</param>
|
|
/// <returns>A <see cref="StatsDto"/> with all gathered statistics.</returns>
|
|
[HttpGet]
|
|
public async Task<ActionResult<StatsDto>> Get(CancellationToken cancellationToken) {
|
|
logger.LogTrace("Stats requested");
|
|
var stats = await statsRepository.GetStatsAsync(cancellationToken);
|
|
return Ok(stats);
|
|
}
|
|
}
|