CrewSessionStart.cs 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. using Application.Abstractions.Hub;
  2. using Application.Abstractions.Notification;
  3. using Domain.Entities.Notifications.ValueObject;
  4. using Infrastructure.Hubs;
  5. using Web.Api.Common;
  6. using MediatR;
  7. using Microsoft.AspNetCore.SignalR;
  8. namespace Web.Api.Endpoints.Donation;
  9. /// <summary>크루 방송 시작 — 세션 생성 + 크루원에게 초대 알림</summary>
  10. internal sealed class CrewSessionStart : IEndpoint
  11. {
  12. public void MapEndpoint(IEndpointRouteBuilder app)
  13. {
  14. app.MapPost("api/crew/session/start", async (
  15. Application.Features.Api.Crew.StartSession.Command body,
  16. ISender sender,
  17. IHubContext<AppHub, IAppHubClient> appHub,
  18. INotificationService notificationService,
  19. Application.Abstractions.Data.IAppDbContext db,
  20. CancellationToken ct
  21. ) => {
  22. var result = await sender.Send(body, ct);
  23. if (result.IsFailure)
  24. {
  25. return CustomResults.Problem(result);
  26. }
  27. var data = result.Value;
  28. // 크루원들에게 초대 알림 발송
  29. var consents = await Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions
  30. .ToListAsync(
  31. Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions
  32. .AsNoTracking(db.CrewSessionConsent)
  33. .Where(c => c.CrewSessionID == data.CrewSessionID)
  34. .Join(db.CrewMember, c => c.CrewMemberID, m => m.ID, (c, m) => new { m.MemberID, m.Nickname }),
  35. ct
  36. );
  37. foreach (var member in consents)
  38. {
  39. await notificationService.SendAsync(
  40. member.MemberID,
  41. NotificationType.CrewInvitation,
  42. "크루 방송 초대",
  43. $"크루 방송 '{body.Title}'에 초대되었습니다. 참여 동의를 해주세요.",
  44. $"/crew/consent/{data.CrewSessionID}",
  45. "CrewSession", data.CrewSessionID, null, ct
  46. );
  47. // AppHub 실시간 푸시
  48. await appHub.Clients.Group($"member:{member.MemberID}").ReceiveCrewInvitation(new
  49. {
  50. CrewSessionID = data.CrewSessionID,
  51. Title = body.Title,
  52. CrewID = body.CrewID
  53. });
  54. }
  55. return ApiResponse.Ok(data);
  56. })
  57. .WithTags("Crew")
  58. .RequireAuthorization();
  59. }
  60. }