Skip to content

Commit

Permalink
Admin API for sending announcements to specific identities (#1034)
Browse files Browse the repository at this point in the history
* feat: added optional property recipients and validation rule
added some bruno http request files

* fix: declared the property Recipients as nullable

* fix: validation rule of Recipients

* fix: validation of property Recipients

* feat: added AnnouncementRecipient + Migration + Handler update

* feat: added AnnouncementRecipient Migration

* feat: added announcement-recipients, updated outgoing/incoming domain-event, updated push-service

* feat: return recipients in admin-api on get request

* feat: added Announcement Recipient IdentityDeleter

* chore: removed pubspec.lock

* fix: fixed AnnouncementRecipient + PushService usage per PnsHandle

* test: added CreateAnnouncement Handler Tests

* test: added AnnouncementRecipient Anonymize IdentityDeleter Tests

* test: added AnonymizeRecipient tests

* fix: updated docker file

* fix: updated docker-file

* chore: added debug-logging

* chore: added some debug statement

* chore: debug - check database-migrator logs

* chore: debug - fixed the check database-migrator-test log cmd

* chore: added new migration as error seen in logs regarding AnnouncementsDbContext

* fix: added announcement-recipient migration for sqlserver + postgres db

* fix: another attempt to get the database-migrator-test logs

* chore: try to log exiting ci-seed-database-1 container

* chore: try to log exiting ci-seed-database-1 container

* fix: replaced DistinctBy (can't be translated to SQL by EF Core)

* chore: removed debug log

* fix: added AnnouncementsModule

* fix: added missing DOCKERFILE project reference

* fix: added missing DOCKERFILE project reference

* fix: updated regarding PR remarks

* fix: use change-tracker announcements

* fix: updated regarding PR remarks

* test: new AnonymizeRecipient Handler UnitTest

* chore: added ValidId check

* fix: failed test

* chore: cleanup

* fix: remove didDomainName from appsettings.json files and add it to appsettings.override.json files

* feat: delete recipients instead of anonymizing them

* refactor: simplify CreateAnnouncement Handler

* chore: add `FromBody` attribute

* refactor: simplify application logic by adding a default value to the `Recipients` property of the CreateAnnouncementCommand

* fix: don't catch and rethrow exceptions in SseServerClient

* refactor: simplify validation

* fix: fix migration errors

* fix: return simple string instead of an object in AnnouncementDTO.cs

* chore: delete redundant tests

* chore: delete unused repository method

* chore: don't unclude navigation properties when deleting recipients

* chore: cleanup

* refactor: move extension method to correct place

* refactor: simplify AnnouncementCreatedDomainEventHandler

* chore: restore original order of members of PushService

* refactor: filter for distinct handles in PushService instead of in the repository

* test: fix invalidId tests

* chore: remove redundant query parameters from bruno files

---------

Co-authored-by: Eric Brunner <[email protected]>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Jan 28, 2025
1 parent b34229e commit cbdb115
Show file tree
Hide file tree
Showing 48 changed files with 792 additions and 55 deletions.
29 changes: 29 additions & 0 deletions Applications/AdminApi/http/Announcements/Announcements.bru
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
meta {
name: /Announcements
type: http
seq: 1
}

post {
url: {{baseUrl}}/Announcements
body: json
auth: none
}

body:json {
{
"severity": 1,
"texts": [
{
"language": "en",
"title": "System Maintenance V2",
"body": "The system will be undergoing maintenance on Saturday."
}
],
"expiresAt": "2023-12-31T23:59:59Z",
"recipients": [
"did:e:localhost:dids:8234cca0160ff05c785636",
"did:e:localhost:dids:5b8640b14cc9796fbf8d0d"
]
}
}
11 changes: 11 additions & 0 deletions Applications/AdminApi/http/Announcements/List Announcements.bru
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
meta {
name: /Announcements
type: http
seq: 2
}

get {
url: {{baseUrl}}/Announcements
body: none
auth: none
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public AnnouncementsController(IMediator mediator) : base(mediator)
}

[HttpPost]
public async Task<IActionResult> CreateAnnouncement(CreateAnnouncementCommand request, CancellationToken cancellationToken)
public async Task<IActionResult> CreateAnnouncement([FromBody] CreateAnnouncementCommand request, CancellationToken cancellationToken)
{
var response = await _mediator.Send(request, cancellationToken);
return Created(response);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@
}
},
"Modules": {
"Announcements": {
"Infrastructure": {
"SqlDatabase": {
"Provider": "Postgres",
"ConnectionString": "User ID=postgres;Password=admin;Server=localhost;Port=5432;Database=enmeshed;" // postgres
// "ConnectionString": "Server=localhost;Database=enmeshed;User Id=sa;Password=Passw0rd;TrustServerCertificate=True" // sqlserver
}
}
},
"Quotas": {
"Infrastructure": {
"SqlDatabase": {
Expand Down
2 changes: 0 additions & 2 deletions Applications/ConsumerApi/src/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@
},
"Devices": {
"Application": {
"DidDomainName": "localhost",
"Pagination": {
"DefaultPageSize": 50,
"MaxPageSize": 200
Expand All @@ -79,7 +78,6 @@
},
"Messages": {
"Application": {
"DidDomainName": "localhost",
"MaxNumberOfUnreceivedMessagesFromOneSender": 20,
"Pagination": {
"DefaultPageSize": 50,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
meta {
name: /Announcements
type: http
seq: 1
}

get {
url: {{baseUrl}}/Announcements
body: none
auth: inherit
}

params:query {
language: en
}
6 changes: 3 additions & 3 deletions Applications/ConsumerApi/src/http/Tokens/List Tokens.bru
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ get {
}

params:query {
~ids: TOKsjPynl0FHYJzHnkIo
~PageNumber: 1
~PageSize: 1
ids: TOKsjPynl0FHYJzHnkIo
PageNumber: 1
PageSize: 1
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@
}
},
"Modules": {
"Announcements": {
"Infrastructure": {
"SqlDatabase": {
"Provider": "Postgres",
"ConnectionString": "User ID=postgres;Password=admin;Server=localhost;Port=5432;Database=enmeshed;" // postgres
// "ConnectionString": "Server=localhost;Database=enmeshed;User Id=sa;Password=Passw0rd;TrustServerCertificate=True" // sqlserver
}
}
},
"Challenges": {
"Infrastructure": {
"SqlDatabase": {
Expand Down Expand Up @@ -80,6 +89,9 @@
}
},
"Tokens": {
"Application": {
"DidDomainName": "localhost"
},
"Infrastructure": {
"SqlDatabase": {
"Provider": "Postgres",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,33 @@ WORKDIR /src
COPY ["Directory.Build.props", "."]
COPY ["Applications/IdentityDeletionJobs/src/Job.IdentityDeletion/Job.IdentityDeletion.csproj", "Applications/IdentityDeletionJobs/src/Job.IdentityDeletion/"]
COPY ["BuildingBlocks/src/BuildingBlocks.API/BuildingBlocks.API.csproj", "BuildingBlocks/src/BuildingBlocks.API/"]
COPY ["Modules/Devices/src/Devices.Domain/Devices.Domain.csproj", "Modules/Devices/src/Devices.Domain/"]
COPY ["BuildingBlocks/src/BuildingBlocks.Domain/BuildingBlocks.Domain.csproj", "BuildingBlocks/src/BuildingBlocks.Domain/"]
COPY ["BuildingBlocks/src/Tooling/Tooling.csproj", "BuildingBlocks/src/Tooling/"]
COPY ["BuildingBlocks/src/DevelopmentKit.Identity/DevelopmentKit.Identity.csproj", "BuildingBlocks/src/DevelopmentKit.Identity/"]
COPY ["Modules/Devices/src/Devices.Infrastructure/Devices.Infrastructure.csproj", "Modules/Devices/src/Devices.Infrastructure/"]
COPY ["BuildingBlocks/src/BuildingBlocks.Infrastructure/BuildingBlocks.Infrastructure.csproj", "BuildingBlocks/src/BuildingBlocks.Infrastructure/"]
COPY ["BuildingBlocks/src/BuildingBlocks.Application.Abstractions/BuildingBlocks.Application.Abstractions.csproj", "BuildingBlocks/src/BuildingBlocks.Application.Abstractions/"]
COPY ["Modules/Devices/src/Devices.Application/Devices.Application.csproj", "Modules/Devices/src/Devices.Application/"]
COPY ["BuildingBlocks/src/BuildingBlocks.Application/BuildingBlocks.Application.csproj", "BuildingBlocks/src/BuildingBlocks.Application/"]
COPY ["Common/src/Common.Infrastructure/Common.Infrastructure.csproj", "Common/src/Common.Infrastructure/"]
COPY ["BuildingBlocks/src/Crypto/Crypto.csproj", "BuildingBlocks/src/Crypto/"]
COPY ["Infrastructure/Infrastructure.csproj", "Infrastructure/"]
COPY ["Modules/Announcements/src/Announcements.Domain/Announcements.Domain.csproj", "Modules/Announcements/src/Announcements.Domain/"]
COPY ["Modules/Announcements/src/Announcements.Application/Announcements.Application.csproj", "Modules/Announcements/src/Announcements.Application/"]
COPY ["Modules/Announcements/src/Announcements.ConsumerApi/Announcements.ConsumerApi.csproj", "Modules/Announcements/src/Announcements.ConsumerApi/"]
COPY ["Modules/Announcements/src/Announcements.Infrastructure.Database.Postgres/Announcements.Infrastructure.Database.Postgres.csproj", "Modules/Announcements/src/Announcements.Infrastructure.Database.Postgres/"]
COPY ["Modules/Announcements/src/Announcements.Infrastructure/Announcements.Infrastructure.csproj", "Modules/Announcements/src/Announcements.Infrastructure/"]
COPY ["Modules/Announcements/src/Announcements.Infrastructure.Database.SqlServer/Announcements.Infrastructure.Database.SqlServer.csproj", "Modules/Announcements/src/Announcements.Infrastructure.Database.SqlServer/"]
COPY ["Modules/Challenges/src/Challenges.Application/Challenges.Application.csproj", "Modules/Challenges/src/Challenges.Application/"]
COPY ["Modules/Challenges/src/Challenges.Domain/Challenges.Domain.csproj", "Modules/Challenges/src/Challenges.Domain/"]
COPY ["Modules/Challenges/src/Challenges.ConsumerApi/Challenges.ConsumerApi.csproj", "Modules/Challenges/src/Challenges.ConsumerApi/"]
COPY ["Modules/Challenges/src/Challenges.Infrastructure.Database.Postgres/Challenges.Infrastructure.Database.Postgres.csproj", "Modules/Challenges/src/Challenges.Infrastructure.Database.Postgres/"]
COPY ["Modules/Challenges/src/Challenges.Infrastructure/Challenges.Infrastructure.csproj", "Modules/Challenges/src/Challenges.Infrastructure/"]
COPY ["Modules/Challenges/src/Challenges.Infrastructure.Database.SqlServer/Challenges.Infrastructure.Database.SqlServer.csproj", "Modules/Challenges/src/Challenges.Infrastructure.Database.SqlServer/"]
COPY ["Modules/Devices/src/Devices.Domain/Devices.Domain.csproj", "Modules/Devices/src/Devices.Domain/"]
COPY ["Modules/Devices/src/Devices.Infrastructure/Devices.Infrastructure.csproj", "Modules/Devices/src/Devices.Infrastructure/"]
COPY ["Modules/Devices/src/Devices.Application/Devices.Application.csproj", "Modules/Devices/src/Devices.Application/"]
COPY ["Modules/Devices/src/Devices.ConsumerApi/Devices.ConsumerApi.csproj", "Modules/Devices/src/Devices.ConsumerApi/"]
COPY ["Modules/Devices/src/Devices.Infrastructure.Database.Postgres/Devices.Infrastructure.Database.Postgres.csproj", "Modules/Devices/src/Devices.Infrastructure.Database.Postgres/"]
COPY ["Modules/Devices/src/Devices.Infrastructure.Database.SqlServer/Devices.Infrastructure.Database.SqlServer.csproj", "Modules/Devices/src/Devices.Infrastructure.Database.SqlServer/"]
COPY ["Modules/Files/src/Files.Application/Files.Application.csproj", "Modules/Files/src/Files.Application/"]
COPY ["Modules/Files/src/Files.Domain/Files.Domain.csproj", "Modules/Files/src/Files.Domain/"]
COPY ["Modules/Files/src/Files.ConsumerApi/Files.ConsumerApi.csproj", "Modules/Files/src/Files.ConsumerApi/"]
Expand Down Expand Up @@ -62,9 +71,6 @@ COPY ["Modules/Tokens/src/Tokens.ConsumerApi/Tokens.ConsumerApi.csproj", "Module
COPY ["Modules/Tokens/src/Tokens.Infrastructure.Database.Postgres/Tokens.Infrastructure.Database.Postgres.csproj", "Modules/Tokens/src/Tokens.Infrastructure.Database.Postgres/"]
COPY ["Modules/Tokens/src/Tokens.Infrastructure/Tokens.Infrastructure.csproj", "Modules/Tokens/src/Tokens.Infrastructure/"]
COPY ["Modules/Tokens/src/Tokens.Infrastructure.Database.SqlServer/Tokens.Infrastructure.Database.SqlServer.csproj", "Modules/Tokens/src/Tokens.Infrastructure.Database.SqlServer/"]
COPY ["Modules/Devices/src/Devices.ConsumerApi/Devices.ConsumerApi.csproj", "Modules/Devices/src/Devices.ConsumerApi/"]
COPY ["Modules/Devices/src/Devices.Infrastructure.Database.Postgres/Devices.Infrastructure.Database.Postgres.csproj", "Modules/Devices/src/Devices.Infrastructure.Database.Postgres/"]
COPY ["Modules/Devices/src/Devices.Infrastructure.Database.SqlServer/Devices.Infrastructure.Database.SqlServer.csproj", "Modules/Devices/src/Devices.Infrastructure.Database.SqlServer/"]

RUN dotnet restore /p:ContinuousIntegrationBuild=true "Applications/IdentityDeletionJobs/src/Job.IdentityDeletion/Job.IdentityDeletion.csproj"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
<ProjectReference Include="..\..\..\..\BuildingBlocks\src\BuildingBlocks.Infrastructure\BuildingBlocks.Infrastructure.csproj" />
<ProjectReference Include="..\..\..\..\BuildingBlocks\src\Tooling\Tooling.csproj" />
<ProjectReference Include="..\..\..\..\Infrastructure\Infrastructure.csproj" />
<ProjectReference Include="..\..\..\..\Modules\Announcements\src\Announcements.Application\Announcements.Application.csproj" />
<ProjectReference Include="..\..\..\..\Modules\Announcements\src\Announcements.ConsumerApi\Announcements.ConsumerApi.csproj" />
<ProjectReference Include="..\..\..\..\Modules\Challenges\src\Challenges.Application\Challenges.Application.csproj" />
<ProjectReference Include="..\..\..\..\Modules\Challenges\src\Challenges.ConsumerApi\Challenges.ConsumerApi.csproj" />
<ProjectReference Include="..\..\..\..\Modules\Files\src\Files.Application\Files.Application.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Backbone.BuildingBlocks.Application.Identities;
using Backbone.BuildingBlocks.Application.QuotaCheck;
using Backbone.Infrastructure.EventBus;
using Backbone.Modules.Announcements.ConsumerApi;
using Backbone.Modules.Challenges.ConsumerApi;
using Backbone.Modules.Devices.ConsumerApi;
using Backbone.Modules.Devices.Infrastructure.PushNotifications;
Expand Down Expand Up @@ -93,6 +94,7 @@ public static IHostBuilder CreateHostBuilder(string[] args)
services.AddTransient(typeof(IHostedService), worker);

services
.AddModule<AnnouncementsModule>(configuration)
.AddModule<DevicesModule>(configuration)
.AddModule<RelationshipsModule>(configuration)
.AddModule<ChallengesModule>(configuration)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using Backbone.BuildingBlocks.Application.Identities;

namespace Backbone.Job.IdentityDeletion;

public static class ServicesExtensions
{
public static IServiceCollection RegisterIdentityDeleters(this IServiceCollection services)
{
services.AddTransient<IIdentityDeleter, Modules.Announcements.Application.Announcements.IdentityDeleter>();
services.AddTransient<IIdentityDeleter, Modules.Challenges.Application.Identities.IdentityDeleter>();
services.AddTransient<IIdentityDeleter, Modules.Devices.Application.Identities.IdentityDeleter>();
services.AddTransient<IIdentityDeleter, Modules.Files.Application.Identities.IdentityDeleter>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public async Task Logs_that_data_was_deleted()

var auditLogEntriesForDeletedData = auditLogEntries.Where(e => e.MessageKey == MessageKey.DataDeleted).ToList();

auditLogEntriesForDeletedData.Should().HaveCount(13);
auditLogEntriesForDeletedData.Should().HaveCount(14);

auditLogEntriesForDeletedData.Should().AllSatisfy(e =>
{
Expand All @@ -65,6 +65,7 @@ public async Task Logs_that_data_was_deleted()
deletedAggregates.Should().Contain("SyncRuns");
deletedAggregates.Should().Contain("Datawallets");
deletedAggregates.Should().Contain("Tokens");
deletedAggregates.Should().Contain("AnnouncementRecipients");
}

[Fact]
Expand Down Expand Up @@ -147,6 +148,11 @@ public async Task Deletes_relationship_templates()
templatesAfterAct.Should().BeEmpty();
}

private T GetService<T>() where T : notnull
{
return _host.Services.CreateScope().ServiceProvider.GetRequiredService<T>();
}

#region Seeders

private async Task<Message> SeedDatabaseWithMessage(Relationship relationship, Identity from, Identity to)
Expand Down Expand Up @@ -216,9 +222,4 @@ private async Task<Identity> SeedDatabaseWithIdentity()
}

#endregion

private T GetService<T>() where T : notnull
{
return _host.Services.CreateScope().ServiceProvider.GetRequiredService<T>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ public static IRuleBuilderOptions<T, TProperty> In<T, TProperty>(this IRuleBuild
return ruleBuilder
.Must(x => (bool)method.Invoke(null, [x])!)
.WithErrorCode(GenericApplicationErrors.Validation.InvalidPropertyValue().Code)
.WithMessage("The ID is not valid. Check length, prefix and the used characters.");
.WithMessage("'{PropertyName}': The ID or Address is not valid. Check length, prefix and the used characters.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Backbone.Tooling.Extensions;

public static class IEnumerableExtensions
{
public static bool IsEmpty<T>(this IEnumerable<T> items)
{
return !items.Any();
}
}
5 changes: 0 additions & 5 deletions BuildingBlocks/src/Tooling/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,4 @@ public static byte[] GetBytes(this string text)
{
return Encoding.UTF8.GetBytes(text);
}

public static bool IsEmpty<T>(this IEnumerable<T> items)
{
return !items.Any();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ public static void ShouldHaveValidationErrorForId<T>(this TestValidationResult<T
{
var errorsForProperty = testValidationResult.ShouldHaveValidationErrorFor(propertyWithInvalidId);
errorsForProperty.Should().Contain(r =>
r.ErrorCode == "error.platform.validation.invalidPropertyValue" && r.ErrorMessage == "The ID is not valid. Check length, prefix and the used characters.");
r.ErrorCode == "error.platform.validation.invalidPropertyValue" && r.ErrorMessage.Contains("The ID or Address is not valid. Check length, prefix and the used characters."));
}

public static void ShouldHaveValidationErrorForIdInCollection<T>(this TestValidationResult<T> testValidationResult, string collectionWithInvalidId, int indexWithInvalidId)
{
var errorsForProperty = testValidationResult.ShouldHaveValidationErrorFor($"{collectionWithInvalidId}[{indexWithInvalidId}]");
errorsForProperty.Should().Contain(r =>
r.ErrorCode == "error.platform.validation.invalidPropertyValue" && r.ErrorMessage == "The ID is not valid. Check length, prefix and the used characters.");
r.ErrorCode == "error.platform.validation.invalidPropertyValue" && r.ErrorMessage.Contains("The ID or Address is not valid. Check length, prefix and the used characters."));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ public class CreateAnnouncementCommand : IRequest<AnnouncementDTO>
public required AnnouncementSeverity Severity { get; set; }
public required List<CreateAnnouncementCommandText> Texts { get; set; }
public DateTime? ExpiresAt { get; set; }

public List<string> Recipients { get; set; } = [];
}

public class CreateAnnouncementCommandText
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Backbone.Modules.Announcements.Application.Announcements.DTOs;
using Backbone.DevelopmentKit.Identity.ValueObjects;
using Backbone.Modules.Announcements.Application.Announcements.DTOs;
using Backbone.Modules.Announcements.Application.Infrastructure.Persistence.Repository;
using Backbone.Modules.Announcements.Domain.Entities;
using MediatR;
Expand All @@ -16,9 +17,11 @@ public Handler(IAnnouncementsRepository announcementsRepository)

public async Task<AnnouncementDTO> Handle(CreateAnnouncementCommand request, CancellationToken cancellationToken)
{
var announcementRecipients = request.Recipients.Select(r => new AnnouncementRecipient(IdentityAddress.Parse(r)));

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);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using Backbone.BuildingBlocks.Application.Abstractions.Exceptions;
using Backbone.BuildingBlocks.Application.Extensions;
using Backbone.BuildingBlocks.Application.FluentValidation;
using Backbone.DevelopmentKit.Identity.ValueObjects;
using Backbone.Modules.Announcements.Domain.Entities;
using FluentValidation;

Expand All @@ -14,7 +16,12 @@ public Validator()
.WithErrorCode(GenericApplicationErrors.Validation.InvalidPropertyValue().Code)
.WithMessage("There must be a text for English.");

RuleFor(x => x.Recipients.Count)
.LessThanOrEqualTo(100)
.WithErrorCode(GenericApplicationErrors.Validation.InvalidPropertyValue().Code);

RuleForEach(x => x.Texts).SetValidator(new CreateAnnouncementCommandTextValidator());
RuleForEach(x => x.Recipients).ValidId<CreateAnnouncementCommand, IdentityAddress>();
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using MediatR;

namespace Backbone.Modules.Announcements.Application.Announcements.Commands.DeleteAnnouncementRecipients;

public record DeleteAnnouncementRecipientsCommand : IRequest
{
public DeleteAnnouncementRecipientsCommand(string identityAddress)
{
IdentityAddress = identityAddress;
}

public string IdentityAddress { get; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Backbone.DevelopmentKit.Identity.ValueObjects;
using Backbone.Modules.Announcements.Application.Infrastructure.Persistence.Repository;
using MediatR;

namespace Backbone.Modules.Announcements.Application.Announcements.Commands.DeleteAnnouncementRecipients;

public class Handler : IRequestHandler<DeleteAnnouncementRecipientsCommand>
{
private readonly IAnnouncementsRepository _announcementsRepository;

public Handler(IAnnouncementsRepository announcementsRepository)
{
_announcementsRepository = announcementsRepository;
}

public async Task Handle(DeleteAnnouncementRecipientsCommand request, CancellationToken cancellationToken)
{
var parsedIdentityAddress = IdentityAddress.Parse(request.IdentityAddress);

await _announcementsRepository.DeleteRecipients(r => r.Address == parsedIdentityAddress, cancellationToken);
}
}
Loading

0 comments on commit cbdb115

Please sign in to comment.