| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667 |
- using Application.Abstractions.Data;
- using Application.Abstractions.Hub;
- using Domain.Entities.Donations.ValueObject;
- using Infrastructure.Hubs;
- using Web.Api.Common;
- using Web.Api.Extensions;
- using Microsoft.AspNetCore.SignalR;
- using Microsoft.EntityFrameworkCore;
- using System.Security.Claims;
- namespace Web.Api.Endpoints.Donation;
- /// <summary>리모콘 — 큐 순서 변경 (두 알림 위치 swap, 위젯+리모콘 broadcast)</summary>
- internal sealed class RemoteReorder : IEndpoint
- {
- public sealed record Request(string WidgetToken, int AlertIDA, int AlertIDB);
- public void MapEndpoint(IEndpointRouteBuilder app)
- {
- app.MapPost("api/donation/remote/reorder", async (
- Request request,
- ClaimsPrincipal user,
- IAppDbContext db,
- IHubContext<DonationHub, IDonationHubClient> donationHub,
- CancellationToken ct
- ) => {
- var memberID = user.GetRequiredMemberID();
- if (string.IsNullOrWhiteSpace(request.WidgetToken) || request.AlertIDA == request.AlertIDB)
- {
- return ApiResponse.Fail(StatusCodes.Status400BadRequest, "잘못된 요청입니다.");
- }
- // 권한 확인 — 본인 채널의 WidgetToken 만 reorder 가능
- var channel = await db.Channel.AsNoTracking()
- .Where(c => c.WidgetToken == request.WidgetToken)
- .Select(c => new { c.ID, c.MemberID })
- .FirstOrDefaultAsync(ct);
- if (channel is null || channel.MemberID != memberID)
- {
- return ApiResponse.Fail(StatusCodes.Status403Forbidden, "권한이 없습니다.");
- }
- // 방어적 검증 — 두 alertID 가 본 채널의 Queued 상태인지 확인 (재생/완료/스킵 항목 순서 조작 차단)
- var alerts = await db.DonationAlert.AsNoTracking()
- .Where(a => (a.ID == request.AlertIDA || a.ID == request.AlertIDB) && a.Donation!.ChannelID == channel.ID)
- .Select(a => new { a.ID, a.Status })
- .ToListAsync(ct);
- if (alerts.Count != 2 || alerts.Any(a => a.Status != AlertStatus.Queued))
- {
- return ApiResponse.Fail(StatusCodes.Status400BadRequest, "대기 중인 알림만 순서 변경이 가능합니다.");
- }
- // Widget+Remote 양쪽 그룹에 swap broadcast — 클라이언트가 자기 큐/표시 순서 swap
- await donationHub.Clients.Group(request.WidgetToken).ReceiveQueueReorder(new
- {
- swap = new[] { request.AlertIDA, request.AlertIDB }
- });
- return ApiResponse.Ok();
- })
- .WithTags("DonationRemote")
- .RequireAuthorization();
- }
- }
|