CrewInvitation.cs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. using System.ComponentModel.DataAnnotations;
  2. using System.ComponentModel.DataAnnotations.Schema;
  3. using Domain.Entities.Donations.ValueObject;
  4. using Domain.Entities.Members;
  5. namespace Domain.Entities.Donations;
  6. public class CrewInvitation
  7. {
  8. public const int ExpirationHours = 24;
  9. [ForeignKey(nameof(CrewID))]
  10. public virtual Crew? Crew { get; private set; }
  11. [ForeignKey(nameof(TargetMemberID))]
  12. public virtual Member? TargetMember { get; private set; }
  13. [ForeignKey(nameof(InvitedByMemberID))]
  14. public virtual Member? InvitedByMember { get; private set; }
  15. [Key]
  16. public int ID { get; private set; }
  17. public int CrewID { get; private set; }
  18. public int TargetMemberID { get; private set; }
  19. public int InvitedByMemberID { get; private set; }
  20. public string Nickname { get; private set; } = default!;
  21. public string? Role { get; private set; }
  22. public int SortOrder { get; private set; }
  23. public CrewInviteStatus Status { get; private set; } = CrewInviteStatus.Pending;
  24. public DateTime InvitedAt { get; private set; } = DateTime.UtcNow;
  25. public DateTime ExpiresAt { get; private set; } = DateTime.UtcNow.AddHours(ExpirationHours);
  26. public DateTime? RespondedAt { get; private set; }
  27. private CrewInvitation() { }
  28. public static CrewInvitation Create(
  29. int crewID,
  30. int targetMemberID,
  31. int invitedByMemberID,
  32. string nickname,
  33. string? role = null,
  34. int sortOrder = 0
  35. ) {
  36. if (string.IsNullOrWhiteSpace(nickname))
  37. {
  38. throw new ArgumentException("Nickname is required.", nameof(nickname));
  39. }
  40. var now = DateTime.UtcNow;
  41. return new CrewInvitation
  42. {
  43. CrewID = crewID,
  44. TargetMemberID = targetMemberID,
  45. InvitedByMemberID = invitedByMemberID,
  46. Nickname = nickname,
  47. Role = role,
  48. SortOrder = sortOrder,
  49. Status = CrewInviteStatus.Pending,
  50. InvitedAt = now,
  51. ExpiresAt = now.AddHours(ExpirationHours)
  52. };
  53. }
  54. public void Accept()
  55. {
  56. if (Status != CrewInviteStatus.Pending)
  57. {
  58. throw new InvalidOperationException($"Cannot accept invitation in {Status} state.");
  59. }
  60. if (DateTime.UtcNow > ExpiresAt)
  61. {
  62. throw new InvalidOperationException("Invitation has expired.");
  63. }
  64. Status = CrewInviteStatus.Accepted;
  65. RespondedAt = DateTime.UtcNow;
  66. }
  67. public void Decline()
  68. {
  69. if (Status != CrewInviteStatus.Pending)
  70. {
  71. throw new InvalidOperationException($"Cannot decline invitation in {Status} state.");
  72. }
  73. Status = CrewInviteStatus.Declined;
  74. RespondedAt = DateTime.UtcNow;
  75. }
  76. public void MarkExpired()
  77. {
  78. if (Status != CrewInviteStatus.Pending)
  79. {
  80. return;
  81. }
  82. Status = CrewInviteStatus.Expired;
  83. RespondedAt = DateTime.UtcNow;
  84. }
  85. public bool IsExpired() => Status == CrewInviteStatus.Pending && DateTime.UtcNow > ExpiresAt;
  86. }