From 095dd2933c361092bedea62b6fa8ee8cc6736c11 Mon Sep 17 00:00:00 2001 From: Eric Brunner Date: Fri, 10 Jan 2025 12:28:40 +0100 Subject: [PATCH] feat: added AnnouncementRecipient + Migration + Handler update --- .../Announcements/Create Announcements.bru | 29 ---- .../Announcements.Application.csproj | 1 + .../Commands/CreateAnnouncement/Handler.cs | 40 ++++- .../IAnnouncementRecipientsRepository.cs | 9 + .../Entities/Announcement.cs | 6 +- .../Entities/AnnouncementRecipient.cs | 29 ++++ ...31_AddingAnnouncementRecipient.Designer.cs | 158 ++++++++++++++++++ ...50110112331_AddingAnnouncementRecipient.cs | 80 +++++++++ .../AnnouncementsDbContextModelSnapshot.cs | 66 +++++++- .../Database/AnnouncementsDbContext.cs | 3 + .../Database/IServiceCollectionExtensions.cs | 1 + .../AnnouncementRecipientsRepository.cs | 33 ++++ .../Entities/Identities/Identity.cs | 5 + 13 files changed, 427 insertions(+), 33 deletions(-) delete mode 100644 Applications/ConsumerApi/src/http/Announcements/Create Announcements.bru create mode 100644 Modules/Announcements/src/Announcements.Application/Infrastructure/Persistence/Repository/IAnnouncementRecipientsRepository.cs create mode 100644 Modules/Announcements/src/Announcements.Domain/Entities/AnnouncementRecipient.cs create mode 100644 Modules/Announcements/src/Announcements.Infrastructure.Database.Postgres/Migrations/20250110112331_AddingAnnouncementRecipient.Designer.cs create mode 100644 Modules/Announcements/src/Announcements.Infrastructure.Database.Postgres/Migrations/20250110112331_AddingAnnouncementRecipient.cs create mode 100644 Modules/Announcements/src/Announcements.Infrastructure/Persistence/Repository/AnnouncementRecipientsRepository.cs diff --git a/Applications/ConsumerApi/src/http/Announcements/Create Announcements.bru b/Applications/ConsumerApi/src/http/Announcements/Create Announcements.bru deleted file mode 100644 index 15fa93a4f5..0000000000 --- a/Applications/ConsumerApi/src/http/Announcements/Create Announcements.bru +++ /dev/null @@ -1,29 +0,0 @@ -meta { - name: /Announcements - type: http - seq: 2 -} - -post { - url: {{baseUrl}}/Announcements - body: json - auth: inherit -} - -body:json { - { - "severity": 1, - "texts": [ - { - "language": "en", - "title": "System Maintenance", - "body": "The system will be undergoing maintenance on Saturday." - } - ], - "expiresAt": "2023-12-31T23:59:59Z", - "recipients": [ - "1", - "2" - ] - } -} diff --git a/Modules/Announcements/src/Announcements.Application/Announcements.Application.csproj b/Modules/Announcements/src/Announcements.Application/Announcements.Application.csproj index e7edb86307..1e32ef8bf6 100644 --- a/Modules/Announcements/src/Announcements.Application/Announcements.Application.csproj +++ b/Modules/Announcements/src/Announcements.Application/Announcements.Application.csproj @@ -2,6 +2,7 @@ + diff --git a/Modules/Announcements/src/Announcements.Application/Announcements/Commands/CreateAnnouncement/Handler.cs b/Modules/Announcements/src/Announcements.Application/Announcements/Commands/CreateAnnouncement/Handler.cs index 304bf3a4f4..f9923d1585 100644 --- a/Modules/Announcements/src/Announcements.Application/Announcements/Commands/CreateAnnouncement/Handler.cs +++ b/Modules/Announcements/src/Announcements.Application/Announcements/Commands/CreateAnnouncement/Handler.cs @@ -1,24 +1,60 @@ using Backbone.Modules.Announcements.Application.Announcements.DTOs; using Backbone.Modules.Announcements.Application.Infrastructure.Persistence.Repository; using Backbone.Modules.Announcements.Domain.Entities; +using Backbone.Modules.Devices.Application.Infrastructure.Persistence.Repository; +using Backbone.Modules.Devices.Domain.Entities.Identities; using MediatR; +using Microsoft.Extensions.Logging; namespace Backbone.Modules.Announcements.Application.Announcements.Commands.CreateAnnouncement; public class Handler : IRequestHandler { + private readonly IAnnouncementRecipientsRepository _announcementRecipientRepository; private readonly IAnnouncementsRepository _announcementsRepository; + private readonly IIdentitiesRepository _identityRepository; + private readonly ILogger _logger; - public Handler(IAnnouncementsRepository announcementsRepository) + public Handler(IAnnouncementsRepository announcementsRepository, ILogger logger, IIdentitiesRepository identityRepository, + IAnnouncementRecipientsRepository announcementRecipientRepository) { _announcementsRepository = announcementsRepository; + _logger = logger; + _identityRepository = identityRepository; + _announcementRecipientRepository = announcementRecipientRepository; } public async Task Handle(CreateAnnouncementCommand request, CancellationToken cancellationToken) { + List announcementRecipients = []; + + if (request.Recipients != null && request.Recipients.Count != 0) + { + var requestRecipients = request.Recipients.OrderBy(address => address).ToList(); + + var recipients = (await _identityRepository.Find(Identity.ContainsAddressValue(requestRecipients), cancellationToken)).ToArray(); + var foundRecipients = recipients.Select(r => r.Address.Value).OrderBy(address => address).ToList(); + + if (!foundRecipients.SequenceEqual(requestRecipients)) + { + _logger.LogError("Not all recipients were found in the database. \r\n" + + "Request Recipients: {recipients}. \r\n" + + "Found Recipients: {foundRecipients}", + string.Join(',', requestRecipients), + string.Join(',', foundRecipients)); + } + + announcementRecipients = requestRecipients.Select(address => new AnnouncementRecipient(address)).ToList(); + + foreach (var announcementRecipient in announcementRecipients) + { + await _announcementRecipientRepository.Add(announcementRecipient, cancellationToken); + } + } + var texts = request.Texts.Select(t => new AnnouncementText(AnnouncementLanguage.Parse(t.Language), t.Title, t.Body)).ToList(); - var announcement = new Announcement(request.Severity, texts, request.ExpiresAt); + var announcement = new Announcement(request.Severity, texts, request.ExpiresAt, announcementRecipients); await _announcementsRepository.Add(announcement, cancellationToken); diff --git a/Modules/Announcements/src/Announcements.Application/Infrastructure/Persistence/Repository/IAnnouncementRecipientsRepository.cs b/Modules/Announcements/src/Announcements.Application/Infrastructure/Persistence/Repository/IAnnouncementRecipientsRepository.cs new file mode 100644 index 0000000000..c4ad8f7cb7 --- /dev/null +++ b/Modules/Announcements/src/Announcements.Application/Infrastructure/Persistence/Repository/IAnnouncementRecipientsRepository.cs @@ -0,0 +1,9 @@ +using Backbone.Modules.Announcements.Domain.Entities; + +namespace Backbone.Modules.Announcements.Application.Infrastructure.Persistence.Repository; + +public interface IAnnouncementRecipientsRepository +{ + Task Add(AnnouncementRecipient announcementRecipient, CancellationToken cancellationToken); + Task> FindAll(CancellationToken cancellationToken); +} diff --git a/Modules/Announcements/src/Announcements.Domain/Entities/Announcement.cs b/Modules/Announcements/src/Announcements.Domain/Entities/Announcement.cs index 3c4c491940..453831929e 100644 --- a/Modules/Announcements/src/Announcements.Domain/Entities/Announcement.cs +++ b/Modules/Announcements/src/Announcements.Domain/Entities/Announcement.cs @@ -12,15 +12,17 @@ private Announcement() // This constructor is for EF Core only; initializing the properties with null is therefore not a problem Id = null!; Texts = null!; + Recipients = null!; } - public Announcement(AnnouncementSeverity severity, List texts, DateTime? expiresAt) + public Announcement(AnnouncementSeverity severity, List texts, DateTime? expiresAt, List recipients) { Id = AnnouncementId.New(); CreatedAt = SystemTime.UtcNow; ExpiresAt = expiresAt; Severity = severity; Texts = texts; + Recipients = recipients; RaiseDomainEvent(new AnnouncementCreatedDomainEvent(this)); } @@ -31,6 +33,8 @@ public Announcement(AnnouncementSeverity severity, List texts, public AnnouncementSeverity Severity { get; } public List Texts { get; } + + public List Recipients { get; } } public enum AnnouncementSeverity diff --git a/Modules/Announcements/src/Announcements.Domain/Entities/AnnouncementRecipient.cs b/Modules/Announcements/src/Announcements.Domain/Entities/AnnouncementRecipient.cs new file mode 100644 index 0000000000..70db090400 --- /dev/null +++ b/Modules/Announcements/src/Announcements.Domain/Entities/AnnouncementRecipient.cs @@ -0,0 +1,29 @@ +using Backbone.BuildingBlocks.Domain; +using Backbone.Tooling; + +namespace Backbone.Modules.Announcements.Domain.Entities; + +public class AnnouncementRecipient : Entity +{ + // ReSharper disable once UnusedMember.Local + public AnnouncementRecipient() + { + // This constructor is for EF Core only; initializing the properties with null is therefore not a problem + Id = null!; + AnnouncementId = null!; + Address = null!; + } + + public AnnouncementRecipient(string address) + { + Id = null!; // will be set by EF Core (primary key) + AnnouncementId = null!; // will be set by EF Core (back navigation property) + Address = address; + CreatedAt = SystemTime.UtcNow; + } + + public string Id { get; set; } + public AnnouncementId AnnouncementId { get; } + public string Address { get; set; } + public DateTime CreatedAt { get; set; } +} diff --git a/Modules/Announcements/src/Announcements.Infrastructure.Database.Postgres/Migrations/20250110112331_AddingAnnouncementRecipient.Designer.cs b/Modules/Announcements/src/Announcements.Infrastructure.Database.Postgres/Migrations/20250110112331_AddingAnnouncementRecipient.Designer.cs new file mode 100644 index 0000000000..15eee3bdf3 --- /dev/null +++ b/Modules/Announcements/src/Announcements.Infrastructure.Database.Postgres/Migrations/20250110112331_AddingAnnouncementRecipient.Designer.cs @@ -0,0 +1,158 @@ +// +using System; +using Backbone.Modules.Announcements.Infrastructure.Persistence.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Backbone.Modules.Announcements.Infrastructure.Database.Postgres.Migrations +{ + [DbContext(typeof(AnnouncementsDbContext))] + [Migration("20250110112331_AddingAnnouncementRecipient")] + partial class AddingAnnouncementRecipient + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("Announcements") + .HasAnnotation("ProductVersion", "9.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Backbone.BuildingBlocks.Domain.Events.DomainEvent", b => + { + b.Property("DomainEventId") + .HasColumnType("text"); + + b.Property("AnnouncementRecipientId") + .HasColumnType("text"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("DomainEventId"); + + b.HasIndex("AnnouncementRecipientId"); + + b.ToTable("DomainEvent", "Announcements"); + }); + + modelBuilder.Entity("Backbone.Modules.Announcements.Domain.Entities.Announcement", b => + { + b.Property("Id") + .HasMaxLength(20) + .IsUnicode(false) + .HasColumnType("character(20)") + .IsFixedLength(); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Severity") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("Announcements", "Announcements"); + }); + + modelBuilder.Entity("Backbone.Modules.Announcements.Domain.Entities.AnnouncementRecipient", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Address") + .IsRequired() + .HasColumnType("text"); + + b.Property("AnnouncementId1") + .HasMaxLength(20) + .IsUnicode(false) + .HasColumnType("character(20)") + .IsFixedLength(); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("AnnouncementId1"); + + b.ToTable("AnnouncementRecipients", "Announcements"); + }); + + modelBuilder.Entity("Backbone.Modules.Announcements.Domain.Entities.AnnouncementText", b => + { + b.Property("AnnouncementId") + .HasMaxLength(20) + .IsUnicode(false) + .HasColumnType("character(20)") + .IsFixedLength(); + + b.Property("Language") + .HasMaxLength(2) + .IsUnicode(false) + .HasColumnType("character(2)") + .IsFixedLength(); + + b.Property("Body") + .IsRequired() + .HasColumnType("text"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("AnnouncementId", "Language"); + + b.ToTable("AnnouncementText", "Announcements"); + }); + + modelBuilder.Entity("Backbone.BuildingBlocks.Domain.Events.DomainEvent", b => + { + b.HasOne("Backbone.Modules.Announcements.Domain.Entities.AnnouncementRecipient", null) + .WithMany("DomainEvents") + .HasForeignKey("AnnouncementRecipientId"); + }); + + modelBuilder.Entity("Backbone.Modules.Announcements.Domain.Entities.AnnouncementRecipient", b => + { + b.HasOne("Backbone.Modules.Announcements.Domain.Entities.Announcement", null) + .WithMany("Recipients") + .HasForeignKey("AnnouncementId1"); + }); + + modelBuilder.Entity("Backbone.Modules.Announcements.Domain.Entities.AnnouncementText", b => + { + b.HasOne("Backbone.Modules.Announcements.Domain.Entities.Announcement", null) + .WithMany("Texts") + .HasForeignKey("AnnouncementId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Backbone.Modules.Announcements.Domain.Entities.Announcement", b => + { + b.Navigation("Recipients"); + + b.Navigation("Texts"); + }); + + modelBuilder.Entity("Backbone.Modules.Announcements.Domain.Entities.AnnouncementRecipient", b => + { + b.Navigation("DomainEvents"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Modules/Announcements/src/Announcements.Infrastructure.Database.Postgres/Migrations/20250110112331_AddingAnnouncementRecipient.cs b/Modules/Announcements/src/Announcements.Infrastructure.Database.Postgres/Migrations/20250110112331_AddingAnnouncementRecipient.cs new file mode 100644 index 0000000000..e20798d899 --- /dev/null +++ b/Modules/Announcements/src/Announcements.Infrastructure.Database.Postgres/Migrations/20250110112331_AddingAnnouncementRecipient.cs @@ -0,0 +1,80 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Backbone.Modules.Announcements.Infrastructure.Database.Postgres.Migrations +{ + /// + public partial class AddingAnnouncementRecipient : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AnnouncementRecipients", + schema: "Announcements", + columns: table => new + { + Id = table.Column(type: "text", nullable: false), + Address = table.Column(type: "text", nullable: false), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + AnnouncementId1 = table.Column(type: "character(20)", unicode: false, fixedLength: true, maxLength: 20, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AnnouncementRecipients", x => x.Id); + table.ForeignKey( + name: "FK_AnnouncementRecipients_Announcements_AnnouncementId1", + column: x => x.AnnouncementId1, + principalSchema: "Announcements", + principalTable: "Announcements", + principalColumn: "Id"); + }); + + migrationBuilder.CreateTable( + name: "DomainEvent", + schema: "Announcements", + columns: table => new + { + DomainEventId = table.Column(type: "text", nullable: false), + CreationDate = table.Column(type: "timestamp with time zone", nullable: false), + AnnouncementRecipientId = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_DomainEvent", x => x.DomainEventId); + table.ForeignKey( + name: "FK_DomainEvent_AnnouncementRecipients_AnnouncementRecipientId", + column: x => x.AnnouncementRecipientId, + principalSchema: "Announcements", + principalTable: "AnnouncementRecipients", + principalColumn: "Id"); + }); + + migrationBuilder.CreateIndex( + name: "IX_AnnouncementRecipients_AnnouncementId1", + schema: "Announcements", + table: "AnnouncementRecipients", + column: "AnnouncementId1"); + + migrationBuilder.CreateIndex( + name: "IX_DomainEvent_AnnouncementRecipientId", + schema: "Announcements", + table: "DomainEvent", + column: "AnnouncementRecipientId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "DomainEvent", + schema: "Announcements"); + + migrationBuilder.DropTable( + name: "AnnouncementRecipients", + schema: "Announcements"); + } + } +} diff --git a/Modules/Announcements/src/Announcements.Infrastructure.Database.Postgres/Migrations/AnnouncementsDbContextModelSnapshot.cs b/Modules/Announcements/src/Announcements.Infrastructure.Database.Postgres/Migrations/AnnouncementsDbContextModelSnapshot.cs index 323ea7b3b8..f45e57afe9 100644 --- a/Modules/Announcements/src/Announcements.Infrastructure.Database.Postgres/Migrations/AnnouncementsDbContextModelSnapshot.cs +++ b/Modules/Announcements/src/Announcements.Infrastructure.Database.Postgres/Migrations/AnnouncementsDbContextModelSnapshot.cs @@ -18,11 +18,29 @@ protected override void BuildModel(ModelBuilder modelBuilder) #pragma warning disable 612, 618 modelBuilder .HasDefaultSchema("Announcements") - .HasAnnotation("ProductVersion", "8.0.10") + .HasAnnotation("ProductVersion", "9.0.0") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + modelBuilder.Entity("Backbone.BuildingBlocks.Domain.Events.DomainEvent", b => + { + b.Property("DomainEventId") + .HasColumnType("text"); + + b.Property("AnnouncementRecipientId") + .HasColumnType("text"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("DomainEventId"); + + b.HasIndex("AnnouncementRecipientId"); + + b.ToTable("DomainEvent", "Announcements"); + }); + modelBuilder.Entity("Backbone.Modules.Announcements.Domain.Entities.Announcement", b => { b.Property("Id") @@ -45,6 +63,31 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Announcements", "Announcements"); }); + modelBuilder.Entity("Backbone.Modules.Announcements.Domain.Entities.AnnouncementRecipient", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Address") + .IsRequired() + .HasColumnType("text"); + + b.Property("AnnouncementId1") + .HasMaxLength(20) + .IsUnicode(false) + .HasColumnType("character(20)") + .IsFixedLength(); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("AnnouncementId1"); + + b.ToTable("AnnouncementRecipients", "Announcements"); + }); + modelBuilder.Entity("Backbone.Modules.Announcements.Domain.Entities.AnnouncementText", b => { b.Property("AnnouncementId") @@ -72,6 +115,20 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("AnnouncementText", "Announcements"); }); + modelBuilder.Entity("Backbone.BuildingBlocks.Domain.Events.DomainEvent", b => + { + b.HasOne("Backbone.Modules.Announcements.Domain.Entities.AnnouncementRecipient", null) + .WithMany("DomainEvents") + .HasForeignKey("AnnouncementRecipientId"); + }); + + modelBuilder.Entity("Backbone.Modules.Announcements.Domain.Entities.AnnouncementRecipient", b => + { + b.HasOne("Backbone.Modules.Announcements.Domain.Entities.Announcement", null) + .WithMany("Recipients") + .HasForeignKey("AnnouncementId1"); + }); + modelBuilder.Entity("Backbone.Modules.Announcements.Domain.Entities.AnnouncementText", b => { b.HasOne("Backbone.Modules.Announcements.Domain.Entities.Announcement", null) @@ -83,8 +140,15 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Backbone.Modules.Announcements.Domain.Entities.Announcement", b => { + b.Navigation("Recipients"); + b.Navigation("Texts"); }); + + modelBuilder.Entity("Backbone.Modules.Announcements.Domain.Entities.AnnouncementRecipient", b => + { + b.Navigation("DomainEvents"); + }); #pragma warning restore 612, 618 } } diff --git a/Modules/Announcements/src/Announcements.Infrastructure/Persistence/Database/AnnouncementsDbContext.cs b/Modules/Announcements/src/Announcements.Infrastructure/Persistence/Database/AnnouncementsDbContext.cs index bd2461fbbd..3cd143ec07 100644 --- a/Modules/Announcements/src/Announcements.Infrastructure/Persistence/Database/AnnouncementsDbContext.cs +++ b/Modules/Announcements/src/Announcements.Infrastructure/Persistence/Database/AnnouncementsDbContext.cs @@ -21,6 +21,7 @@ public AnnouncementsDbContext(DbContextOptions options, } public virtual DbSet Announcements { get; set; } = null!; + public virtual DbSet AnnouncementRecipients { get; set; } = null!; protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) { @@ -37,6 +38,8 @@ protected override void OnModelCreating(ModelBuilder builder) builder.HasDefaultSchema("Announcements"); + builder.Entity(entity => { entity.HasKey(e => e.Id); }); + builder.ApplyConfigurationsFromAssembly(typeof(AnnouncementsDbContext).Assembly); } } diff --git a/Modules/Announcements/src/Announcements.Infrastructure/Persistence/Database/IServiceCollectionExtensions.cs b/Modules/Announcements/src/Announcements.Infrastructure/Persistence/Database/IServiceCollectionExtensions.cs index eec4784f91..53fc349169 100644 --- a/Modules/Announcements/src/Announcements.Infrastructure/Persistence/Database/IServiceCollectionExtensions.cs +++ b/Modules/Announcements/src/Announcements.Infrastructure/Persistence/Database/IServiceCollectionExtensions.cs @@ -52,6 +52,7 @@ public static void AddDatabase(this IServiceCollection services, DbOptions optio }); services.AddTransient(); + services.AddTransient(); } public class DbOptions diff --git a/Modules/Announcements/src/Announcements.Infrastructure/Persistence/Repository/AnnouncementRecipientsRepository.cs b/Modules/Announcements/src/Announcements.Infrastructure/Persistence/Repository/AnnouncementRecipientsRepository.cs new file mode 100644 index 0000000000..1c9ec64e81 --- /dev/null +++ b/Modules/Announcements/src/Announcements.Infrastructure/Persistence/Repository/AnnouncementRecipientsRepository.cs @@ -0,0 +1,33 @@ +using Backbone.BuildingBlocks.Application.Extensions; +using Backbone.Modules.Announcements.Application.Infrastructure.Persistence.Repository; +using Backbone.Modules.Announcements.Domain.Entities; +using Backbone.Modules.Announcements.Infrastructure.Persistence.Database; +using Microsoft.EntityFrameworkCore; + +namespace Backbone.Modules.Announcements.Infrastructure.Persistence.Repository; + +public class AnnouncementRecipientsRepository : IAnnouncementRecipientsRepository +{ + private readonly DbSet _announcementRecipients; + private readonly AnnouncementsDbContext _dbContext; + private readonly IQueryable _readOnlyAnnouncementRecipients; + + public AnnouncementRecipientsRepository(AnnouncementsDbContext dbContext) + { + _dbContext = dbContext; + _announcementRecipients = dbContext.AnnouncementRecipients; + _readOnlyAnnouncementRecipients = dbContext.AnnouncementRecipients.AsNoTracking(); + } + + public Task Add(AnnouncementRecipient announcementRecipient, CancellationToken cancellationToken) + { + _announcementRecipients.Add(announcementRecipient); + + return _dbContext.SaveChangesAsync(cancellationToken); + } + + public Task> FindAll(CancellationToken cancellationToken) + { + return _readOnlyAnnouncementRecipients.IncludeAll(_dbContext).ToListAsync(cancellationToken); + } +} diff --git a/Modules/Devices/src/Devices.Domain/Entities/Identities/Identity.cs b/Modules/Devices/src/Devices.Domain/Entities/Identities/Identity.cs index ab8a1387be..daae658c6d 100644 --- a/Modules/Devices/src/Devices.Domain/Entities/Identities/Identity.cs +++ b/Modules/Devices/src/Devices.Domain/Entities/Identities/Identity.cs @@ -329,6 +329,11 @@ public static Expression> HasAddress(IdentityAddress addres return i => i.Address == address.ToString(); } + public static Expression> ContainsAddressValue(IEnumerable recipients) + { + return i => recipients.Contains(i.Address.Value); + } + public static Expression> IsReadyForDeletion() { return i => i.Status == IdentityStatus.ToBeDeleted && i.DeletionGracePeriodEndsAt != null && i.DeletionGracePeriodEndsAt < SystemTime.UtcNow;