using Application.Abstractions.Data; using Web.Api.Common; using MediatR; using Microsoft.EntityFrameworkCore; namespace Web.Api.Endpoints.Widget; /// WidgetToken + configID 기반 후원 목표 진행 상태 (위젯 초기 로드용, 인증 불필요). /// configID 미지정 시 활성 첫 번째 자동 선택. internal sealed class GoalProgressByToken : IEndpoint { public void MapEndpoint(IEndpointRouteBuilder app) { app.MapGet("api/widget/goal/by-token/{widgetToken}", async ( string widgetToken, int? configID, IAppDbContext db, ISender sender, CancellationToken ct ) => { var channelID = await db.Channel.AsNoTracking() .Where(c => c.WidgetToken == widgetToken && c.IsActive) .Select(c => c.ID) .FirstOrDefaultAsync(ct); if (channelID == 0) { return ApiResponse.Ok((object?)null); } int? targetGoalConfigID; if (configID.HasValue) { targetGoalConfigID = await db.DonationGoalConfig.AsNoTracking() .Where(g => g.ChannelID == channelID && g.ID == configID.Value) .Select(g => (int?)g.ID) .FirstOrDefaultAsync(ct); } else { targetGoalConfigID = await db.DonationGoalConfig.AsNoTracking() .Where(g => g.ChannelID == channelID && g.IsActive) .OrderByDescending(g => g.ID) .Select(g => (int?)g.ID) .FirstOrDefaultAsync(ct); } if (targetGoalConfigID is null) { return ApiResponse.Ok((object?)null); } var result = await sender.Send(new Application.Features.Api.DonationGoal.GetProgress.Query(channelID, targetGoalConfigID.Value), ct); if (result.IsFailure) { return ApiResponse.Ok((object?)null); } var data = result.Value; return ApiResponse.Ok(new { goalConfigID = data.GoalConfigID, title = data.Title, startAmount = data.StartAmount, targetAmount = data.TargetAmount, currentAmount = data.CurrentAmount, percent = data.Percent }); }) .WithTags("Widget") .AllowAnonymous(); } }