diff --git a/Application/Handlers/Events/ClubEventHandler.cs b/Application/Handlers/Events/ClubEventHandler.cs index 535d729..f530869 100644 --- a/Application/Handlers/Events/ClubEventHandler.cs +++ b/Application/Handlers/Events/ClubEventHandler.cs @@ -1,5 +1,4 @@ using MediatR; -using PlayOfferService.Application.Exceptions; using PlayOfferService.Domain.Events; using PlayOfferService.Domain.Events.PlayOffer; using PlayOfferService.Domain.Models; @@ -13,7 +12,7 @@ public class ClubEventHandler : IRequestHandler private readonly ReadEventRepository _readEventRepository; private readonly WriteEventRepository _writeEventRepository; private readonly PlayOfferRepository _playOfferRepository; - + public ClubEventHandler(ClubRepository clubRepository, ReadEventRepository readEventRepository, WriteEventRepository writeEventRepository, PlayOfferRepository playOfferRepository) { _clubRepository = clubRepository; @@ -21,7 +20,7 @@ public ClubEventHandler(ClubRepository clubRepository, ReadEventRepository readE _writeEventRepository = writeEventRepository; _playOfferRepository = playOfferRepository; } - + public async Task Handle(TechnicalClubEvent clubEvent, CancellationToken cancellationToken) { Console.WriteLine("ClubEventHandler received event: " + clubEvent.EventType); @@ -31,7 +30,7 @@ public async Task Handle(TechnicalClubEvent clubEvent, CancellationToken cancell Console.WriteLine("Event already applied, skipping"); return; } - + switch (clubEvent.EventType) { case EventType.TENNIS_CLUB_REGISTERED: @@ -46,8 +45,11 @@ public async Task Handle(TechnicalClubEvent clubEvent, CancellationToken cancell case EventType.TENNIS_CLUB_DELETED: await HandleTennisClubDeletedEvent(clubEvent); break; + case EventType.TENNIS_CLUB_NAME_CHANGED: + await HandleTennisClubNameChangedEvent(clubEvent); + break; } - + await _clubRepository.Update(); await _readEventRepository.AppendEvent(clubEvent); await _readEventRepository.Update(); @@ -56,7 +58,7 @@ public async Task Handle(TechnicalClubEvent clubEvent, CancellationToken cancell private async Task HandleTennisClubDeletedEvent(TechnicalClubEvent clubEvent) { await CreatePlayOfferCancelledEventsByClubId(clubEvent); - + var existingClub = await _clubRepository.GetClubById(clubEvent.EntityId); existingClub!.Apply([clubEvent]); } @@ -70,7 +72,7 @@ private async Task HandleTennisClubUnlockedEvent(TechnicalClubEvent clubEvent) private async Task HandleTennisClubLockedEvent(TechnicalClubEvent clubEvent) { await CreatePlayOfferCancelledEventsByClubId(clubEvent); - + var existingClub = await _clubRepository.GetClubById(clubEvent.EntityId); existingClub!.Apply([clubEvent]); } @@ -81,12 +83,12 @@ private async Task HandleTennisClubRegisteredEvent(TechnicalClubEvent clubEvent) newClub.Apply([clubEvent]); _clubRepository.CreateClub(newClub); } - + private async Task CreatePlayOfferCancelledEventsByClubId(TechnicalClubEvent clubEvent) { // Get all play offers by club id var existingPlayOffer = await _playOfferRepository.GetPlayOffersByIds(null, null, clubEvent.EntityId); - + // Create PlayOfferCancelled events for each play offer foreach (var playOffer in existingPlayOffer) { @@ -100,9 +102,15 @@ private async Task CreatePlayOfferCancelledEventsByClubId(TechnicalClubEvent clu EventData = new PlayOfferCancelledEvent(), CorrelationId = clubEvent.EventId }; - + await _writeEventRepository.AppendEvent(cancelledEvent); } await _writeEventRepository.Update(); } + + private async Task HandleTennisClubNameChangedEvent(TechnicalClubEvent clubEvent) + { + var existingClub = await _clubRepository.GetClubById(clubEvent.EntityId); + existingClub!.Apply([clubEvent]); + } } \ No newline at end of file diff --git a/Application/Handlers/Events/MemberEventHandler.cs b/Application/Handlers/Events/MemberEventHandler.cs index 849ea77..44effb5 100644 --- a/Application/Handlers/Events/MemberEventHandler.cs +++ b/Application/Handlers/Events/MemberEventHandler.cs @@ -13,7 +13,7 @@ public class MemberEventHandler : IRequestHandler private readonly ReadEventRepository _eventRepository; private readonly WriteEventRepository _writeEventRepository; private readonly PlayOfferRepository _playOfferRepository; - + public MemberEventHandler(MemberRepository memberRepository, ReadEventRepository eventRepository, PlayOfferRepository playOfferRepository, WriteEventRepository writeEventRepository) { _memberRepository = memberRepository; @@ -21,7 +21,7 @@ public MemberEventHandler(MemberRepository memberRepository, ReadEventRepository _playOfferRepository = playOfferRepository; _writeEventRepository = writeEventRepository; } - + public async Task Handle(TechnicalMemberEvent memberEvent, CancellationToken cancellationToken) { Console.WriteLine("MemberEventHandler received event: " + memberEvent.EventType); @@ -31,7 +31,7 @@ public async Task Handle(TechnicalMemberEvent memberEvent, CancellationToken can Console.WriteLine("Event already applied, skipping"); return; } - + switch (memberEvent.EventType) { case EventType.MEMBER_REGISTERED: @@ -46,8 +46,14 @@ public async Task Handle(TechnicalMemberEvent memberEvent, CancellationToken can case EventType.MEMBER_DELETED: await HandleMemberDeletedEvent(memberEvent); break; + case EventType.MEMBER_FULL_NAME_CHANGED: + await HandleMemberFullNameChangedEvent(memberEvent); + break; + case EventType.MEMBER_EMAIL_CHANGED: + await HandleMemberEmailChangedEvent(memberEvent); + break; } - + await _memberRepository.Update(); await _eventRepository.AppendEvent(memberEvent); await _eventRepository.Update(); @@ -56,7 +62,7 @@ public async Task Handle(TechnicalMemberEvent memberEvent, CancellationToken can private async Task HandleMemberDeletedEvent(TechnicalMemberEvent memberEvent) { await CreatePlayOfferCancelledEventsByCreatorId(memberEvent); - + var existingMember = await _memberRepository.GetMemberById(memberEvent.EntityId); existingMember!.Apply([memberEvent]); } @@ -70,7 +76,7 @@ private async Task HandleMemberUnlockedEvent(TechnicalMemberEvent memberEvent) private async Task HandleMemberLockedEvent(TechnicalMemberEvent memberEvent) { await CreatePlayOfferCancelledEventsByCreatorId(memberEvent); - + var existingMember = await _memberRepository.GetMemberById(memberEvent.EntityId); existingMember!.Apply([memberEvent]); } @@ -86,7 +92,7 @@ private async Task CreatePlayOfferCancelledEventsByCreatorId(TechnicalMemberEven { // Get all play offers by creator id var existingPlayOffer = await _playOfferRepository.GetPlayOffersByIds(null, memberEvent.EntityId); - + // Create PlayOfferCancelled events for each play offer foreach (var playOffer in existingPlayOffer) { @@ -100,9 +106,21 @@ private async Task CreatePlayOfferCancelledEventsByCreatorId(TechnicalMemberEven EventData = new PlayOfferCancelledEvent(), CorrelationId = memberEvent.EventId }; - + await _writeEventRepository.AppendEvent(cancelledEvent); } await _writeEventRepository.Update(); } + + private async Task HandleMemberFullNameChangedEvent(TechnicalMemberEvent memberEvent) + { + var existingMember = await _memberRepository.GetMemberById(memberEvent.EntityId); + existingMember!.Apply([memberEvent]); + } + + private async Task HandleMemberEmailChangedEvent(TechnicalMemberEvent memberEvent) + { + var existingMember = await _memberRepository.GetMemberById(memberEvent.EntityId); + existingMember!.Apply([memberEvent]); + } } \ No newline at end of file diff --git a/Application/RedisClubStreamService.cs b/Application/RedisClubStreamService.cs index 6cc0b50..a54356c 100644 --- a/Application/RedisClubStreamService.cs +++ b/Application/RedisClubStreamService.cs @@ -1,8 +1,7 @@ -using System.Text.Json.Nodes; using MediatR; using PlayOfferService.Domain.Events; -using PlayOfferService.Domain.Repositories; using StackExchange.Redis; +using System.Text.Json.Nodes; namespace PlayOfferService.Application; @@ -13,8 +12,8 @@ public class RedisClubStreamService : BackgroundService private readonly IDatabase _db; private const string StreamName = "club_service_events.public.DomainEvent"; private const string GroupName = "pos.club.events.group"; - - + + public RedisClubStreamService(IServiceScopeFactory serviceScopeFactory) { _serviceScopeFactory = serviceScopeFactory; @@ -28,13 +27,13 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) { using IServiceScope scope = _serviceScopeFactory.CreateScope(); IMediator mediator = scope.ServiceProvider.GetRequiredService(); - + if (!(await _db.KeyExistsAsync(StreamName)) || - (await _db.StreamGroupInfoAsync(StreamName)).All(x=>x.Name!=GroupName)) + (await _db.StreamGroupInfoAsync(StreamName)).All(x => x.Name != GroupName)) { await _db.StreamCreateConsumerGroupAsync(StreamName, GroupName, "0-0"); } - + var id = string.Empty; while (!_cancellationToken.IsCancellationRequested) @@ -58,24 +57,26 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) } } - + private TechnicalClubEvent? FilterandParseEvent(StreamEntry value) { var dict = value.Values.ToDictionary(x => x.Name.ToString(), x => x.Value.ToString()); var jsonContent = JsonNode.Parse(dict.Values.First()); var eventInfo = jsonContent["payload"]["after"]; - + var eventType = eventInfo["eventType"].GetValue(); var entityType = eventInfo["entityType"].GetValue(); - + if ((eventType != "TENNIS_CLUB_REGISTERED" && eventType != "TENNIS_CLUB_LOCKED" && eventType != "TENNIS_CLUB_UNLOCKED" - && eventType != "TENNIS_CLUB_DELETED") || entityType != "TENNIS_CLUB") + && eventType != "TENNIS_CLUB_DELETED" + && eventType != "TENNIS_CLUB_NAME_CHANGED" + ) || entityType != "TENNIS_CLUB") { return null; } - + return EventParser.ParseEvent(eventInfo); } } \ No newline at end of file diff --git a/Application/RedisMemberStreamService.cs b/Application/RedisMemberStreamService.cs index 9a72278..8f2bdcf 100644 --- a/Application/RedisMemberStreamService.cs +++ b/Application/RedisMemberStreamService.cs @@ -67,10 +67,16 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) var eventType = eventInfo["eventType"].GetValue(); var entityType = eventInfo["entityType"].GetValue(); - if ((eventType != "MEMBER_REGISTERED" + if ( + (eventType != "MEMBER_REGISTERED" && eventType != "MEMBER_DELETED" && eventType != "MEMBER_LOCKED" - && eventType != "MEMBER_UNLOCKED") || entityType != "MEMBER") + && eventType != "MEMBER_UNLOCKED" + && eventType != "MEMBER_EMAIL_CHANGED" + && eventType != "MEMBER_FULL_NAME_CHANGED" + ) + || entityType != "MEMBER" + ) { return null; } diff --git a/Domain/DbReadContext.cs b/Domain/DbReadContext.cs index 351cb4c..9ac7fc2 100644 --- a/Domain/DbReadContext.cs +++ b/Domain/DbReadContext.cs @@ -10,28 +10,28 @@ public class DbReadContext : DbContext public DbReadContext(DbContextOptions options) : base(options) { } - + public DbSet PlayOffers { get; set; } public DbSet Clubs { get; set; } public DbSet Members { get; set; } public DbSet Reservations { get; set; } public DbSet Courts { get; set; } public DbSet AppliedEvents { get; set; } - + protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.ApplyConfiguration(new BaseEventConfiguration()); - + // TODO: Remove before coop testing - var testClub = new Club{Id = Guid.Parse("06b812a7-5131-4510-82ff-bffac33e0f3e"), Status = Status.ACTIVE}; - var testMemberIds = new List {Guid.Parse("40c0981d-e2f8-4af3-ae6c-17f79f3ba8c2"), Guid.Parse("ccc1c8fc-89b5-4026-b190-9d9e7e7bc18d")}; - + var testClub = new Club { Id = Guid.Parse("06b812a7-5131-4510-82ff-bffac33e0f3e"), Name = "Test Club", Status = Status.ACTIVE }; + var testMemberIds = new List { Guid.Parse("40c0981d-e2f8-4af3-ae6c-17f79f3ba8c2"), Guid.Parse("ccc1c8fc-89b5-4026-b190-9d9e7e7bc18d") }; + var testMembers = new List{ new {Id = testMemberIds[0], ClubId = testClub.Id, Status = Status.ACTIVE}, new {Id = testMemberIds[1], ClubId = testClub.Id, Status = Status.ACTIVE} }; - + // Need to directly specify foreign keys for seeding var testPlayOffer = new { @@ -42,7 +42,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) ProposedEndTime = DateTime.UtcNow.AddHours(1), IsCancelled = false }; - + modelBuilder.Entity().HasData(testClub); foreach (var testMember in testMembers) { diff --git a/Domain/Events/Club/ClubNameChangedEvent.cs b/Domain/Events/Club/ClubNameChangedEvent.cs new file mode 100644 index 0000000..4f908a3 --- /dev/null +++ b/Domain/Events/Club/ClubNameChangedEvent.cs @@ -0,0 +1,6 @@ +namespace PlayOfferService.Domain.Events.Club; + +public class ClubNameChangedEvent : DomainEvent +{ + public string Name { get; set; } +} diff --git a/Domain/Events/DomainEvent.cs b/Domain/Events/DomainEvent.cs index e912bc2..6773c77 100644 --- a/Domain/Events/DomainEvent.cs +++ b/Domain/Events/DomainEvent.cs @@ -1,8 +1,9 @@ -using System.Text.Json.Serialization; +using PlayOfferService.Domain.Events.Club; using PlayOfferService.Domain.Events.Court; using PlayOfferService.Domain.Events.Member; using PlayOfferService.Domain.Events.PlayOffer; using PlayOfferService.Domain.Events.Reservation; +using System.Text.Json.Serialization; namespace PlayOfferService.Domain.Events; @@ -11,10 +12,13 @@ namespace PlayOfferService.Domain.Events; [JsonDerivedType(typeof(ClubLockedEvent), typeDiscriminator: "TENNIS_CLUB_LOCKED")] [JsonDerivedType(typeof(ClubUnlockedEvent), typeDiscriminator: "TENNIS_CLUB_UNLOCKED")] [JsonDerivedType(typeof(ClubDeletedEvent), typeDiscriminator: "TENNIS_CLUB_DELETED")] +[JsonDerivedType(typeof(ClubNameChangedEvent), typeDiscriminator: "TENNIS_CLUB_NAME_CHANGED")] [JsonDerivedType(typeof(MemberCreatedEvent), typeDiscriminator: "MEMBER_REGISTERED")] [JsonDerivedType(typeof(MemberLockedEvent), typeDiscriminator: "MEMBER_LOCKED")] [JsonDerivedType(typeof(MemberUnlockedEvent), typeDiscriminator: "MEMBER_UNLOCKED")] [JsonDerivedType(typeof(MemberDeletedEvent), typeDiscriminator: "MEMBER_DELETED")] +[JsonDerivedType(typeof(MemberEmailChangedEvent), typeDiscriminator: "MEMBER_EMAIL_CHANGED")] +[JsonDerivedType(typeof(MemberFullNameChangedEvent), typeDiscriminator: "MEMBER_FULL_NAME_CHANGED")] [JsonDerivedType(typeof(PlayOfferCreatedEvent), typeDiscriminator: "PLAYOFFER_CREATED")] [JsonDerivedType(typeof(PlayOfferJoinedEvent), typeDiscriminator: "PLAYOFFER_JOINED")] [JsonDerivedType(typeof(PlayOfferCancelledEvent), typeDiscriminator: "PLAYOFFER_CANCELLED")] diff --git a/Domain/Events/EventType.cs b/Domain/Events/EventType.cs index a4d6e04..d56fefd 100644 --- a/Domain/Events/EventType.cs +++ b/Domain/Events/EventType.cs @@ -11,10 +11,13 @@ public enum EventType TENNIS_CLUB_LOCKED, TENNIS_CLUB_UNLOCKED, TENNIS_CLUB_DELETED, + TENNIS_CLUB_NAME_CHANGED, MEMBER_REGISTERED, MEMBER_LOCKED, MEMBER_UNLOCKED, MEMBER_DELETED, + MEMBER_EMAIL_CHANGED, + MEMBER_FULL_NAME_CHANGED, ReservationCreatedEvent, ReservationRejectedEvent, ReservationLimitExceeded, diff --git a/Domain/Events/Member/MemberEmailChangedEvent.cs b/Domain/Events/Member/MemberEmailChangedEvent.cs new file mode 100644 index 0000000..bbe8ac3 --- /dev/null +++ b/Domain/Events/Member/MemberEmailChangedEvent.cs @@ -0,0 +1,6 @@ +namespace PlayOfferService.Domain.Events.Member; + +public class MemberEmailChangedEvent : DomainEvent +{ + public string Email { get; set; } +} \ No newline at end of file diff --git a/Domain/Events/Member/MemberFullNameChangedEvent.cs b/Domain/Events/Member/MemberFullNameChangedEvent.cs new file mode 100644 index 0000000..4bb30e4 --- /dev/null +++ b/Domain/Events/Member/MemberFullNameChangedEvent.cs @@ -0,0 +1,8 @@ +using PlayOfferService.Domain.ValueObjects; + +namespace PlayOfferService.Domain.Events.Member; + +public class MemberFullNameChangedEvent : DomainEvent +{ + public FullName FullName { get; set; } +} \ No newline at end of file diff --git a/Domain/Models/Club.cs b/Domain/Models/Club.cs index 84fabae..6c44814 100644 --- a/Domain/Models/Club.cs +++ b/Domain/Models/Club.cs @@ -1,5 +1,6 @@ -using System.ComponentModel.DataAnnotations.Schema; using PlayOfferService.Domain.Events; +using PlayOfferService.Domain.Events.Club; +using System.ComponentModel.DataAnnotations.Schema; namespace PlayOfferService.Domain.Models; @@ -7,6 +8,7 @@ public class Club { [DatabaseGenerated(DatabaseGeneratedOption.None)] public Guid Id { get; set; } + public string Name { get; set; } public Status Status { get; set; } public void Apply(List baseEvents) @@ -16,7 +18,7 @@ public void Apply(List baseEvents) switch (baseEvent.EventType) { case EventType.TENNIS_CLUB_REGISTERED: - ApplyClubCreatedEvent((ClubCreatedEvent) baseEvent.EventData); + ApplyClubCreatedEvent((ClubCreatedEvent)baseEvent.EventData); break; case EventType.TENNIS_CLUB_LOCKED: ApplyClubLockedEvent(); @@ -27,29 +29,38 @@ public void Apply(List baseEvents) case EventType.TENNIS_CLUB_DELETED: ApplyClubDeletedEvent(); break; + case EventType.TENNIS_CLUB_NAME_CHANGED: + ApplyClubNameChangedEvent((ClubNameChangedEvent)baseEvent.EventData); + break; default: throw new ArgumentOutOfRangeException($"{nameof(baseEvent.EventType)} is not supported for the entity Club!"); } } } - + private void ApplyClubCreatedEvent(ClubCreatedEvent domainEvent) { Id = domainEvent.TennisClubId.Id; + Name = domainEvent.Name; } - + private void ApplyClubLockedEvent() { Status = Status.LOCKED; } - + private void ApplyClubUnlockedEvent() { Status = Status.ACTIVE; } - + private void ApplyClubDeletedEvent() { Status = Status.DELETED; } + + private void ApplyClubNameChangedEvent(ClubNameChangedEvent domainEvent) + { + Name = domainEvent.Name; + } } \ No newline at end of file diff --git a/Domain/Models/Member.cs b/Domain/Models/Member.cs index cd75bdf..c548031 100644 --- a/Domain/Models/Member.cs +++ b/Domain/Models/Member.cs @@ -7,17 +7,20 @@ public class Member { public Guid Id { get; set; } public Guid ClubId { get; set; } - + + public string? Email { get; set; } + public string? FirstName { get; set; } + public string? LastName { get; set; } + public Status Status { get; set; } public void Apply(List baseEvents) { foreach (var baseEvent in baseEvents) - { switch (baseEvent.EventType) { case EventType.MEMBER_REGISTERED: - Apply((MemberCreatedEvent) baseEvent.EventData); + Apply((MemberCreatedEvent)baseEvent.EventData); break; case EventType.MEMBER_LOCKED: ApplyMemberLockedEvent(); @@ -28,29 +31,49 @@ public void Apply(List baseEvents) case EventType.MEMBER_DELETED: ApplyMemberDeletedEvent(); break; + case EventType.MEMBER_EMAIL_CHANGED: + ApplyMemberEmailChangedEvent((MemberEmailChangedEvent)baseEvent.EventData); + break; + case EventType.MEMBER_FULL_NAME_CHANGED: + ApplyMemberFullNameChangedEvent((MemberFullNameChangedEvent)baseEvent.EventData); + break; default: - throw new ArgumentOutOfRangeException($"{nameof(baseEvent.EventType)} is not supported for the entity Member!"); + throw new ArgumentOutOfRangeException( + $"{nameof(baseEvent.EventType)} is not supported for the entity Member!"); } - } } - + + private void ApplyMemberEmailChangedEvent(MemberEmailChangedEvent baseEventEventData) + { + Email = baseEventEventData.Email; + } + + private void ApplyMemberFullNameChangedEvent(MemberFullNameChangedEvent baseEventEventData) + { + FirstName = baseEventEventData.FullName.FirstName; + LastName = baseEventEventData.FullName.LastName; + } + private void Apply(MemberCreatedEvent domainEvent) { Id = domainEvent.MemberId.Id; + Email = domainEvent.Email; + FirstName = domainEvent.Name.FirstName; + LastName = domainEvent.Name.LastName; ClubId = domainEvent.TennisClubId.Id; Status = domainEvent.Status; } - + private void ApplyMemberLockedEvent() { Status = Status.LOCKED; } - + private void ApplyMemberUnlockedEvent() { Status = Status.ACTIVE; } - + private void ApplyMemberDeletedEvent() { Status = Status.DELETED; diff --git a/Migrations/20240607112446_memberExpansion.Designer.cs b/Migrations/20240607112446_memberExpansion.Designer.cs new file mode 100644 index 0000000..5cf0c7b --- /dev/null +++ b/Migrations/20240607112446_memberExpansion.Designer.cs @@ -0,0 +1,259 @@ +// +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using PlayOfferService.Domain; + +#nullable disable + +namespace PlayOfferService.Migrations +{ + [DbContext(typeof(DbReadContext))] + [Migration("20240607112446_memberExpansion")] + partial class memberExpansion + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.2") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("PlayOfferService.Domain.Events.BaseEvent", b => + { + b.Property("EventId") + .HasColumnType("uuid") + .HasColumnName("eventId"); + + b.Property("CorrelationId") + .HasColumnType("uuid") + .HasColumnName("correlationId"); + + b.Property("EntityId") + .HasColumnType("uuid") + .HasColumnName("entityId"); + + b.Property("EntityType") + .IsRequired() + .HasColumnType("text") + .HasColumnName("entityType"); + + b.Property("EventData") + .IsRequired() + .HasColumnType("text") + .HasColumnName("eventData"); + + b.Property("EventType") + .IsRequired() + .HasColumnType("text") + .HasColumnName("eventType"); + + b.Property("Timestamp") + .HasColumnType("timestamp with time zone") + .HasColumnName("timestamp"); + + b.HasKey("EventId") + .HasName("pK_events"); + + b.ToTable("events", (string)null); + }); + + modelBuilder.Entity("PlayOfferService.Domain.Models.Club", b => + { + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Status") + .HasColumnType("integer") + .HasColumnName("status"); + + b.HasKey("Id") + .HasName("pK_clubs"); + + b.ToTable("clubs", (string)null); + + b.HasData( + new + { + Id = new Guid("06b812a7-5131-4510-82ff-bffac33e0f3e"), + Name = "Test Club", + Status = 0 + }); + }); + + modelBuilder.Entity("PlayOfferService.Domain.Models.Court", b => + { + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("ClubId") + .HasColumnType("uuid") + .HasColumnName("clubId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.HasKey("Id") + .HasName("pK_courts"); + + b.ToTable("courts", (string)null); + }); + + modelBuilder.Entity("PlayOfferService.Domain.Models.Member", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("ClubId") + .HasColumnType("uuid") + .HasColumnName("clubId"); + + b.Property("Email") + .HasColumnType("text") + .HasColumnName("email"); + + b.Property("FirstName") + .HasColumnType("text") + .HasColumnName("firstName"); + + b.Property("LastName") + .HasColumnType("text") + .HasColumnName("lastName"); + + b.Property("Status") + .HasColumnType("integer") + .HasColumnName("status"); + + b.HasKey("Id") + .HasName("pK_members"); + + b.ToTable("members", (string)null); + + b.HasData( + new + { + Id = new Guid("40c0981d-e2f8-4af3-ae6c-17f79f3ba8c2"), + ClubId = new Guid("06b812a7-5131-4510-82ff-bffac33e0f3e"), + Status = 0 + }, + new + { + Id = new Guid("ccc1c8fc-89b5-4026-b190-9d9e7e7bc18d"), + ClubId = new Guid("06b812a7-5131-4510-82ff-bffac33e0f3e"), + Status = 0 + }); + }); + + modelBuilder.Entity("PlayOfferService.Domain.Models.PlayOffer", b => + { + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AcceptedStartTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("acceptedStartTime"); + + b.Property("ClubId") + .HasColumnType("uuid") + .HasColumnName("clubId"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("creatorId"); + + b.Property("IsCancelled") + .HasColumnType("boolean") + .HasColumnName("isCancelled"); + + b.Property("OpponentId") + .HasColumnType("uuid") + .HasColumnName("opponentId"); + + b.Property("ProposedEndTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("proposedEndTime"); + + b.Property("ProposedStartTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("proposedStartTime"); + + b.Property("ReservationId") + .HasColumnType("uuid") + .HasColumnName("reservationId"); + + b.HasKey("Id") + .HasName("pK_playOffers"); + + b.ToTable("playOffers", (string)null); + + b.HasData( + new + { + Id = new Guid("7d079edb-d4c8-4e63-9c5b-35b80eaa69f6"), + ClubId = new Guid("06b812a7-5131-4510-82ff-bffac33e0f3e"), + CreatorId = new Guid("40c0981d-e2f8-4af3-ae6c-17f79f3ba8c2"), + IsCancelled = false, + ProposedEndTime = new DateTime(2024, 6, 7, 12, 24, 44, 893, DateTimeKind.Utc).AddTicks(6493), + ProposedStartTime = new DateTime(2024, 6, 7, 11, 24, 44, 893, DateTimeKind.Utc).AddTicks(6491) + }); + }); + + modelBuilder.Entity("PlayOfferService.Domain.Models.Reservation", b => + { + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property>("CourtIds") + .IsRequired() + .HasColumnType("uuid[]") + .HasColumnName("courtIds"); + + b.Property("EndTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("endTime"); + + b.Property("IsCancelled") + .HasColumnType("boolean") + .HasColumnName("isCancelled"); + + b.Property>("ParticipantsIds") + .HasColumnType("uuid[]") + .HasColumnName("participantsIds"); + + b.Property("ReservantId") + .HasColumnType("uuid") + .HasColumnName("reservantId"); + + b.Property("StartTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("startTime"); + + b.HasKey("Id") + .HasName("pK_reservations"); + + b.ToTable("reservations", (string)null); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Migrations/20240607112446_memberExpansion.cs b/Migrations/20240607112446_memberExpansion.cs new file mode 100644 index 0000000..9f923d2 --- /dev/null +++ b/Migrations/20240607112446_memberExpansion.cs @@ -0,0 +1,101 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace PlayOfferService.Migrations +{ + /// + public partial class memberExpansion : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DeleteData( + table: "playOffers", + keyColumn: "id", + keyValue: new Guid("c0f37db0-4c51-4bd3-86ab-48d6c78eb9c2")); + + migrationBuilder.AddColumn( + name: "email", + table: "members", + type: "text", + nullable: true); + + migrationBuilder.AddColumn( + name: "firstName", + table: "members", + type: "text", + nullable: true); + + migrationBuilder.AddColumn( + name: "lastName", + table: "members", + type: "text", + nullable: true); + + migrationBuilder.AddColumn( + name: "name", + table: "clubs", + type: "text", + nullable: false, + defaultValue: ""); + + migrationBuilder.UpdateData( + table: "clubs", + keyColumn: "id", + keyValue: new Guid("06b812a7-5131-4510-82ff-bffac33e0f3e"), + column: "name", + value: "Test Club"); + + migrationBuilder.UpdateData( + table: "members", + keyColumn: "id", + keyValue: new Guid("40c0981d-e2f8-4af3-ae6c-17f79f3ba8c2"), + columns: new[] { "email", "firstName", "lastName" }, + values: new object[] { null, null, null }); + + migrationBuilder.UpdateData( + table: "members", + keyColumn: "id", + keyValue: new Guid("ccc1c8fc-89b5-4026-b190-9d9e7e7bc18d"), + columns: new[] { "email", "firstName", "lastName" }, + values: new object[] { null, null, null }); + + migrationBuilder.InsertData( + table: "playOffers", + columns: new[] { "id", "acceptedStartTime", "clubId", "creatorId", "isCancelled", "opponentId", "proposedEndTime", "proposedStartTime", "reservationId" }, + values: new object[] { new Guid("7d079edb-d4c8-4e63-9c5b-35b80eaa69f6"), null, new Guid("06b812a7-5131-4510-82ff-bffac33e0f3e"), new Guid("40c0981d-e2f8-4af3-ae6c-17f79f3ba8c2"), false, null, new DateTime(2024, 6, 7, 12, 24, 44, 893, DateTimeKind.Utc).AddTicks(6493), new DateTime(2024, 6, 7, 11, 24, 44, 893, DateTimeKind.Utc).AddTicks(6491), null }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DeleteData( + table: "playOffers", + keyColumn: "id", + keyValue: new Guid("7d079edb-d4c8-4e63-9c5b-35b80eaa69f6")); + + migrationBuilder.DropColumn( + name: "email", + table: "members"); + + migrationBuilder.DropColumn( + name: "firstName", + table: "members"); + + migrationBuilder.DropColumn( + name: "lastName", + table: "members"); + + migrationBuilder.DropColumn( + name: "name", + table: "clubs"); + + migrationBuilder.InsertData( + table: "playOffers", + columns: new[] { "id", "acceptedStartTime", "clubId", "creatorId", "isCancelled", "opponentId", "proposedEndTime", "proposedStartTime", "reservationId" }, + values: new object[] { new Guid("c0f37db0-4c51-4bd3-86ab-48d6c78eb9c2"), null, new Guid("06b812a7-5131-4510-82ff-bffac33e0f3e"), new Guid("40c0981d-e2f8-4af3-ae6c-17f79f3ba8c2"), false, null, new DateTime(2024, 6, 6, 19, 10, 3, 28, DateTimeKind.Utc).AddTicks(4637), new DateTime(2024, 6, 6, 18, 10, 3, 28, DateTimeKind.Utc).AddTicks(4634), null }); + } + } +} diff --git a/Migrations/DbReadContextModelSnapshot.cs b/Migrations/DbReadContextModelSnapshot.cs index ff39f79..f30a568 100644 --- a/Migrations/DbReadContextModelSnapshot.cs +++ b/Migrations/DbReadContextModelSnapshot.cs @@ -68,6 +68,11 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("uuid") .HasColumnName("id"); + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + b.Property("Status") .HasColumnType("integer") .HasColumnName("status"); @@ -81,6 +86,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) new { Id = new Guid("06b812a7-5131-4510-82ff-bffac33e0f3e"), + Name = "Test Club", Status = 0 }); }); @@ -117,6 +123,18 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("uuid") .HasColumnName("clubId"); + b.Property("Email") + .HasColumnType("text") + .HasColumnName("email"); + + b.Property("FirstName") + .HasColumnType("text") + .HasColumnName("firstName"); + + b.Property("LastName") + .HasColumnType("text") + .HasColumnName("lastName"); + b.Property("Status") .HasColumnType("integer") .HasColumnName("status"); @@ -187,12 +205,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasData( new { - Id = new Guid("c0f37db0-4c51-4bd3-86ab-48d6c78eb9c2"), + Id = new Guid("7d079edb-d4c8-4e63-9c5b-35b80eaa69f6"), ClubId = new Guid("06b812a7-5131-4510-82ff-bffac33e0f3e"), CreatorId = new Guid("40c0981d-e2f8-4af3-ae6c-17f79f3ba8c2"), IsCancelled = false, - ProposedEndTime = new DateTime(2024, 6, 6, 19, 10, 3, 28, DateTimeKind.Utc).AddTicks(4637), - ProposedStartTime = new DateTime(2024, 6, 6, 18, 10, 3, 28, DateTimeKind.Utc).AddTicks(4634) + ProposedEndTime = new DateTime(2024, 6, 7, 12, 24, 44, 893, DateTimeKind.Utc).AddTicks(6493), + ProposedStartTime = new DateTime(2024, 6, 7, 11, 24, 44, 893, DateTimeKind.Utc).AddTicks(6491) }); }); diff --git a/PlayOfferService.Tests/IntegrationTests/ClubEventHandlerTest.cs b/PlayOfferService.Tests/IntegrationTests/ClubEventHandlerTest.cs index ac4a084..e9850e8 100644 --- a/PlayOfferService.Tests/IntegrationTests/ClubEventHandlerTest.cs +++ b/PlayOfferService.Tests/IntegrationTests/ClubEventHandlerTest.cs @@ -14,21 +14,23 @@ public async Task ClubSetup() new() { Id = Guid.Parse("8aa54411-32fe-4b4c-a017-aa9710cb3bfa"), + Name = "Test Club 1", Status = Status.ACTIVE }, new() { Id = Guid.Parse("2db387f0-5792-4cb5-91a6-6317437b3432"), + Name = "Test Club 2", Status = Status.ACTIVE } }; - + foreach (var club in existingClubs) { TestClubRepository.CreateClub(club); } await TestClubRepository.Update(); - + var existingPlayOffers = new List { new() @@ -50,15 +52,15 @@ public async Task ClubSetup() IsCancelled = false }, }; - + foreach (var playOffer in existingPlayOffers) { TestPlayOfferRepository.CreatePlayOffer(playOffer); } - + await TestPlayOfferRepository.Update(); } - + [Test] public async Task ClubCreatedEvent_ProjectionTest() { @@ -72,16 +74,17 @@ public async Task ClubCreatedEvent_ProjectionTest() EventType = EventType.TENNIS_CLUB_REGISTERED, EventData = new ClubCreatedEvent { - TennisClubId = new TennisClubId {Id = clubId} + TennisClubId = new TennisClubId { Id = clubId }, + Name = "Test Club", } }; - + //When await Mediator.Send(clubCreationEvent); - + //Then var projectedClub = await TestClubRepository.GetClubById(clubId); - + Assert.That(projectedClub, Is.Not.Null); Assert.Multiple(() => { @@ -89,7 +92,7 @@ public async Task ClubCreatedEvent_ProjectionTest() Assert.That(projectedClub.Status, Is.EqualTo(Status.ACTIVE)); }); } - + [Test] public async Task ClubLockedEvent_ProjectionTest() { @@ -102,23 +105,23 @@ public async Task ClubLockedEvent_ProjectionTest() EventType = EventType.TENNIS_CLUB_LOCKED, EventData = new ClubLockedEvent() }; - + //When await Mediator.Send(clubLockedEvent); - + //Then var projectedClub = await TestClubRepository.GetClubById(Guid.Parse("8aa54411-32fe-4b4c-a017-aa9710cb3bfa")); - + Assert.That(projectedClub, Is.Not.Null); Assert.Multiple(() => { Assert.That(projectedClub!.Id, Is.EqualTo(Guid.Parse("8aa54411-32fe-4b4c-a017-aa9710cb3bfa"))); Assert.That(projectedClub.Status, Is.EqualTo(Status.LOCKED)); }); - + var playOfferEvents = await TestWriteEventRepository.GetEventByEntityId(Guid.Parse("d9afd6dd-8836-47dd-86be-3467a7db0fe5")); Assert.That(playOfferEvents, Has.Count.EqualTo(1)); - + Assert.Multiple(() => { Assert.That(playOfferEvents.First().EntityId, Is.EqualTo(Guid.Parse("d9afd6dd-8836-47dd-86be-3467a7db0fe5"))); @@ -126,7 +129,7 @@ public async Task ClubLockedEvent_ProjectionTest() Assert.That(playOfferEvents.First().CorrelationId, Is.EqualTo(Guid.Parse("ee90c3ee-3b4b-4ccb-8933-739795a7253a"))); }); } - + [Test] public async Task ClubUnlockedEvent_ProjectionTest() { @@ -153,7 +156,7 @@ public async Task ClubUnlockedEvent_ProjectionTest() Assert.That(projectedClub.Status, Is.EqualTo(Status.ACTIVE)); }); } - + [Test] public async Task ClubDeletedEvent_ProjectionTest() { @@ -179,10 +182,10 @@ public async Task ClubDeletedEvent_ProjectionTest() Assert.That(projectedClub!.Id, Is.EqualTo(Guid.Parse("2db387f0-5792-4cb5-91a6-6317437b3432"))); Assert.That(projectedClub.Status, Is.EqualTo(Status.DELETED)); }); - + var playOfferEvents = await TestWriteEventRepository.GetEventByEntityId(Guid.Parse("9ee6d9d7-d4a6-4904-a20b-be026de53c4f")); Assert.That(playOfferEvents, Has.Count.EqualTo(1)); - + Assert.Multiple(() => { Assert.That(playOfferEvents.First().EntityId, Is.EqualTo(Guid.Parse("9ee6d9d7-d4a6-4904-a20b-be026de53c4f"))); diff --git a/PlayOfferService.Tests/IntegrationTests/ClubRepositoryTest.cs b/PlayOfferService.Tests/IntegrationTests/ClubRepositoryTest.cs index 9ad3d36..a636bae 100644 --- a/PlayOfferService.Tests/IntegrationTests/ClubRepositoryTest.cs +++ b/PlayOfferService.Tests/IntegrationTests/ClubRepositoryTest.cs @@ -11,6 +11,7 @@ public async Task ClubSetup() var existingClub = new Club { Id = Guid.Parse("67bc285f-1b28-40f9-8b9e-564b3d9c1297"), + Name = "Test Club", Status = Status.ACTIVE }; TestClubRepository.CreateClub(existingClub); @@ -22,28 +23,28 @@ public async Task GetExistingClubByIdTest() { //Given var clubId = Guid.Parse("67bc285f-1b28-40f9-8b9e-564b3d9c1297"); - + //When var club = await TestClubRepository.GetClubById(clubId); - + //Then Assert.That(club, Is.Not.Null); Assert.That(club!.Id, Is.EqualTo(clubId)); } - + [Test] public async Task GetNonExistingClubByIdTest() { //Given var clubId = Guid.NewGuid(); - + //When var club = await TestClubRepository.GetClubById(clubId); - + //Then Assert.That(club, Is.Null); } - + [Test] public async Task CreateClubTest() { @@ -52,13 +53,14 @@ public async Task CreateClubTest() var newClub = new Club { Id = clubId, + Name = "Test Club", Status = Status.ACTIVE }; - + //When TestClubRepository.CreateClub(newClub); await TestClubRepository.Update(); - + //Then var club = await TestClubRepository.GetClubById(clubId); Assert.That(club, Is.Not.Null); diff --git a/PlayOfferService.Tests/IntegrationTests/MemberEventHandlerTest.cs b/PlayOfferService.Tests/IntegrationTests/MemberEventHandlerTest.cs index 2e0cc07..1f287e4 100644 --- a/PlayOfferService.Tests/IntegrationTests/MemberEventHandlerTest.cs +++ b/PlayOfferService.Tests/IntegrationTests/MemberEventHandlerTest.cs @@ -61,7 +61,7 @@ public async Task MemberSetup() await TestPlayOfferRepository.Update(); } - + [Test] public async Task MemberCreatedEvent_ProjectionTest() { @@ -75,17 +75,18 @@ public async Task MemberCreatedEvent_ProjectionTest() EventType = EventType.MEMBER_REGISTERED, EventData = new MemberCreatedEvent { - MemberId = new MemberId{Id=memberId}, - TennisClubId = new TennisClubId{Id=Guid.Parse("bf7f59db-e2bf-4a4f-95fe-baeabe948b81")} + MemberId = new MemberId { Id = memberId }, + Name = new FullName { FirstName = "Test", LastName = "Member" }, + TennisClubId = new TennisClubId { Id = Guid.Parse("bf7f59db-e2bf-4a4f-95fe-baeabe948b81") } } }; - + //When await Mediator.Send(memberCreatedEvent); - + //Then var projectedMember = await TestMemberRepository.GetMemberById(memberId); - + Assert.That(projectedMember, Is.Not.Null); Assert.Multiple(() => { @@ -94,7 +95,7 @@ public async Task MemberCreatedEvent_ProjectionTest() Assert.That(projectedMember.Status, Is.EqualTo(Status.ACTIVE)); }); } - + [Test] public async Task MemberLockEvent_ProjectionTest() { @@ -107,12 +108,13 @@ public async Task MemberLockEvent_ProjectionTest() EventType = EventType.MEMBER_LOCKED, EventData = new MemberLockedEvent() }; - + //When await Mediator.Send(memberLockEvent); - + //Then var projectedMember = await TestMemberRepository.GetMemberById(Guid.Parse("971c48ff-42f4-4dc5-94ad-42e3c155b07b")); + Assert.That(projectedMember, Is.Not.Null); Assert.Multiple(() => { @@ -130,7 +132,7 @@ public async Task MemberLockEvent_ProjectionTest() Assert.That(playOfferEvents.First().CorrelationId, Is.EqualTo(Guid.Parse("d1f2c32e-77b3-4e3b-a632-7ea710e93b44"))); }); } - + [Test] public async Task MemberUnlockEvent_ProjectionTest() { @@ -144,13 +146,13 @@ public async Task MemberUnlockEvent_ProjectionTest() EventType = EventType.MEMBER_UNLOCKED, EventData = new MemberUnlockedEvent() }; - + //When await Mediator.Send(memberUnlockEvent); - + //Then var projectedMember = await TestMemberRepository.GetMemberById(existingMember.Id); - + Assert.That(projectedMember, Is.Not.Null); Assert.Multiple(() => { @@ -158,7 +160,7 @@ public async Task MemberUnlockEvent_ProjectionTest() Assert.That(projectedMember.Status, Is.EqualTo(Status.ACTIVE)); }); } - + [Test] public async Task MemberDeletedEvent_ProjectionTest() { @@ -171,10 +173,10 @@ public async Task MemberDeletedEvent_ProjectionTest() EventType = EventType.MEMBER_DELETED, EventData = new MemberDeletedEvent() }; - + //When await Mediator.Send(memberDeleteEvent); - + //Then var projectedMember = await TestMemberRepository.GetMemberById(Guid.Parse("c559d8ad-67be-4739-afb0-94460d7bb100")); diff --git a/PlayOfferService.Tests/UnitTests/ClubUnitTest.cs b/PlayOfferService.Tests/UnitTests/ClubUnitTest.cs index 14cef99..7e9fcab 100644 --- a/PlayOfferService.Tests/UnitTests/ClubUnitTest.cs +++ b/PlayOfferService.Tests/UnitTests/ClubUnitTest.cs @@ -1,4 +1,5 @@ using PlayOfferService.Domain.Events; +using PlayOfferService.Domain.Events.Club; using PlayOfferService.Domain.Models; using PlayOfferService.Domain.ValueObjects; @@ -20,7 +21,7 @@ public void ApplyClubCreatedEventTest() EventType = EventType.TENNIS_CLUB_REGISTERED, EventData = new ClubCreatedEvent { - TennisClubId = new TennisClubId{Id=clubId} + TennisClubId = new TennisClubId { Id = clubId } } }; @@ -81,7 +82,7 @@ public void ApplyClubUnlockEventTest() // Then Assert.That(club.Status, Is.EqualTo(Status.ACTIVE)); } - + [Test] public void ApplyClubDeletedEventTest() { @@ -105,4 +106,33 @@ public void ApplyClubDeletedEventTest() // Then Assert.That(club.Status, Is.EqualTo(Status.DELETED)); } + + [Test] + public void ApplyClubNameChangedEventTest() + { + // Given + var club = new Club + { + Id = Guid.NewGuid(), + Name = "Test Club" + }; + var clubEvents = new List + { + new() + { + EventType = EventType.TENNIS_CLUB_NAME_CHANGED, + EventData = new ClubNameChangedEvent + { + Name = "New Club Name" + } + } + }; + + // When + club.Apply(clubEvents); + + // Then + Assert.That(club.Name, Is.EqualTo("New Club Name")); + } + } \ No newline at end of file diff --git a/PlayOfferService.Tests/UnitTests/MemberUnitTest.cs b/PlayOfferService.Tests/UnitTests/MemberUnitTest.cs index c57d8d7..a18c9ea 100644 --- a/PlayOfferService.Tests/UnitTests/MemberUnitTest.cs +++ b/PlayOfferService.Tests/UnitTests/MemberUnitTest.cs @@ -22,21 +22,22 @@ public void ApplyMemberCreatedEventTest() EventType = EventType.MEMBER_REGISTERED, EventData = new MemberCreatedEvent { - MemberId = new MemberId{Id=memberId}, - TennisClubId = new TennisClubId{Id=clubId} + MemberId = new MemberId { Id = memberId }, + Name = new FullName { FirstName = "John", LastName = "Doe" }, + TennisClubId = new TennisClubId { Id = clubId } } }; - + // When var member = new Member(); member.Apply([memberCreationEvent]); - + // Then Assert.That(member.Id, Is.EqualTo(memberId)); Assert.That(member.ClubId, Is.EqualTo(clubId)); Assert.That(member.Status, Is.EqualTo(Status.ACTIVE)); } - + [Test] public void ApplyMemberLockEventTest() { @@ -54,14 +55,14 @@ public void ApplyMemberLockEventTest() EventData = new MemberLockedEvent() } }; - + // When member.Apply(memberEvents); - + // Then Assert.That(member.Status, Is.EqualTo(Status.LOCKED)); } - + [Test] public void ApplyMemberUnlockEventTest() { @@ -79,14 +80,14 @@ public void ApplyMemberUnlockEventTest() EventData = new MemberUnlockedEvent() } }; - + // When member.Apply(memberEvents); - + // Then Assert.That(member.Status, Is.EqualTo(Status.ACTIVE)); } - + [Test] public void ApplyMemberDeleteEventTest() { @@ -104,11 +105,74 @@ public void ApplyMemberDeleteEventTest() EventData = new MemberDeletedEvent() } }; - + // When member.Apply(memberEvents); - + // Then Assert.That(member.Status, Is.EqualTo(Status.DELETED)); } + + [Test] + public void ApplyMemberNameChangedEventTest() + { + // Given + var member = new Member + { + Id = Guid.NewGuid(), + FirstName = "John", + LastName = "Doe" + }; + + var memberEvents = new List + { + new() + { + EventType = EventType.MEMBER_FULL_NAME_CHANGED, + EventData = new MemberFullNameChangedEvent + { + FullName = new FullName { FirstName = "Jane", LastName = "Doe" } + } + } + }; + + // When + member.Apply(memberEvents); + + // Then + Assert.That(member.FirstName, Is.EqualTo("Jane")); + Assert.That(member.LastName, Is.EqualTo("Doe")); + } + + [Test] + public void ApplyMemberEmailChangedEvent() + { + // Given + var member = new Member + { + Id = Guid.NewGuid(), + FirstName = "John", + LastName = "Doe", + Email = "test@test.test" + }; + + var memberEvents = new List + { + new() + { + EventType = EventType.MEMBER_EMAIL_CHANGED, + EventData = new MemberEmailChangedEvent + { + Email = "changedEmail@com.com" + } + + } + }; + + //When + member.Apply(memberEvents); + + //Then + Assert.That(member.Email, Is.EqualTo("changedEmail@com.com")); + } } \ No newline at end of file