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;