RemoteTestDonate.cs 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. using Application.Abstractions.Hub;
  2. using Infrastructure.Hubs;
  3. using Web.Api.Common;
  4. using Web.Api.Extensions;
  5. using MediatR;
  6. using Microsoft.AspNetCore.SignalR;
  7. using System.Security.Claims;
  8. namespace Web.Api.Endpoints.Donation;
  9. /// <summary>리모콘 — 테스트 후원 (Wallet/PG 우회, IsTest 플래그로 통계 반영 여부 결정)</summary>
  10. internal sealed class RemoteTestDonate : IEndpoint
  11. {
  12. public void MapEndpoint(IEndpointRouteBuilder app)
  13. {
  14. app.MapPost("api/donation/remote/test-donate", async (
  15. TestDonateRequest body,
  16. ClaimsPrincipal user,
  17. ISender sender,
  18. IHubContext<DonationHub, IDonationHubClient> donationHub,
  19. Application.Abstractions.Data.IAppDbContext db,
  20. CancellationToken ct
  21. ) => {
  22. var memberID = user.GetRequiredMemberID();
  23. var command = new Application.Features.Api.DonationRemote.TestDonate.Command(
  24. WidgetToken: body.WidgetToken,
  25. SendName: body.SendName,
  26. Amount: body.Amount,
  27. Message: body.Message,
  28. CrewMemberID: body.CrewMemberID,
  29. IsTest: body.IsTest,
  30. RequesterMemberID: memberID
  31. );
  32. var result = await sender.Send(command, ct);
  33. if (result.IsFailure)
  34. {
  35. return CustomResults.Problem(result);
  36. }
  37. var data = result.Value;
  38. // SignalR broadcast — Alert 위젯
  39. var alertPayload = new
  40. {
  41. alertID = data.AlertID,
  42. donationID = data.DonationID,
  43. correlationID = data.CorrelationID,
  44. sponsorMemberID = memberID,
  45. sendName = data.SendName,
  46. amount = data.Amount,
  47. netAmount = data.NetAmount,
  48. message = data.Message,
  49. channelID = data.ChannelID,
  50. channelName = data.ChannelName,
  51. crewMemberID = data.CrewMemberID,
  52. crewMemberNickname = data.CrewMemberNickname,
  53. isTest = data.IsTest,
  54. createdAt = DateTime.UtcNow
  55. };
  56. await donationHub.Clients.Group(data.WidgetToken).ReceiveAlert(alertPayload);
  57. // ⚠️ Goal/Rank/Crew broadcast는 알림 재생 종료 시점(DonationHub.AlertCompleted)에 처리됨
  58. // 크루 후원이고 활성 세션이 있는 경우 — 크루 위젯 갱신
  59. if (data.CrewSessionID.HasValue && data.CrewMemberID.HasValue)
  60. {
  61. var rankResult = await sender.Send(
  62. new Application.Features.Api.Crew.GetCrewRanking.Query(data.CrewSessionID.Value), ct
  63. );
  64. if (rankResult.IsSuccess)
  65. {
  66. await donationHub.Clients.Group(data.WidgetToken).ReceiveCrewUpdate(new
  67. {
  68. rankResult.Value.List,
  69. rankResult.Value.TotalAmount
  70. });
  71. }
  72. }
  73. return ApiResponse.Ok(data);
  74. })
  75. .WithTags("DonationRemote")
  76. .RequireAuthorization();
  77. }
  78. public sealed record TestDonateRequest(
  79. string WidgetToken,
  80. string SendName,
  81. int Amount,
  82. string? Message,
  83. int? CrewMemberID,
  84. bool IsTest
  85. );
  86. }