Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Abl 174 admin api send announcements to specify identities - Intermediate #1018

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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",
"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
}
1 change: 1 addition & 0 deletions Applications/AdminApi/src/AdminApi/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"Modules": {
"Announcements": {
"Application": {
"DidDomainName": "localhost",
"Pagination": {
"DefaultPageSize": 50,
"MaxPageSize": 200
Expand Down
4 changes: 2 additions & 2 deletions Applications/AdminUi/apps/admin_ui/pubspec.lock
jkoenig134 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -556,10 +556,10 @@ packages:
dependency: "direct dev"
description:
name: very_good_analysis
sha256: "1fb637c0022034b1f19ea2acb42a3603cbd8314a470646a59a2fb01f5f3a8629"
sha256: "62d2b86d183fb81b2edc22913d9f155d26eb5cf3855173adb1f59fac85035c63"
url: "https://pub.dev"
source: hosted
version: "6.0.0"
version: "7.0.0"
vm_service:
dependency: transitive
description:
Expand Down
1 change: 1 addition & 0 deletions Applications/ConsumerApi/src/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"Modules": {
"Announcements": {
"Application": {
"DidDomainName": "localhost",
"Pagination": {
"DefaultPageSize": 50,
"MaxPageSize": 200
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
meta {
name: /Announcements
type: http
seq: 1
}

get {
url: {{baseUrl}}/Announcements
body: none
auth: inherit
}
8 changes: 4 additions & 4 deletions Applications/ConsumerApi/src/http/Tokens/List Tokens.bru
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ meta {
}

get {
url: {{baseUrl}}/Tokens
url: {{baseUrl}}/Tokens?ids=TOKsjPynl0FHYJzHnkIo&PageNumber=1&PageSize=1
body: none
auth: inherit
}

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 @@ -20,6 +20,7 @@
<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\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
@@ -1,18 +1,21 @@
using Backbone.BuildingBlocks.Application.Identities;
using Backbone.Modules.Challenges.Application.Identities;

namespace Backbone.Job.IdentityDeletion;

public static class ServicesExtensions
{
public static IServiceCollection RegisterIdentityDeleters(this IServiceCollection services)
{
services.AddTransient<IIdentityDeleter, Modules.Challenges.Application.Identities.IdentityDeleter>();
services.AddTransient<IIdentityDeleter, IdentityDeleter>();
services.AddTransient<IIdentityDeleter, Modules.Devices.Application.Identities.IdentityDeleter>();
services.AddTransient<IIdentityDeleter, Modules.Files.Application.Identities.IdentityDeleter>();
services.AddTransient<IIdentityDeleter, Modules.Messages.Application.Identities.IdentityDeleter>();
services.AddTransient<IIdentityDeleter, Modules.Quotas.Application.Identities.IdentityDeleter>();
services.AddTransient<IIdentityDeleter, Modules.Relationships.Application.Identities.IdentityDeleter>();
services.AddTransient<IIdentityDeleter, Modules.Synchronization.Application.Identities.IdentityDeleter>();
services.AddTransient<IIdentityDeleter, Modules.Tokens.Application.Identities.IdentityDeleter>();
services.AddTransient<IIdentityDeleter, Modules.Announcements.Application.Identities.IdentityDeleter>();

return services;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"Modules": {
"Announcements": {
"Application": {
"DidDomainName": "localhost",
"Pagination": {
"DefaultPageSize": 50,
"MaxPageSize": 200
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

<ItemGroup>
<ProjectReference Include="..\..\..\..\BuildingBlocks\src\BuildingBlocks.Application\BuildingBlocks.Application.csproj" />
<ProjectReference Include="..\..\..\Devices\src\Devices.Application\Devices.Application.csproj" />
<ProjectReference Include="..\Announcements.Domain\Announcements.Domain.csproj" />
</ItemGroup>

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.AnonymizeRecipient;

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

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

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

public class Handler : IRequestHandler<AnonymizeRecipientForIdentityCommand>
{
private readonly IAnnouncementRecipientRepository _announcementRecipientRepository;
private readonly ApplicationOptions _applicationOptions;

public Handler(IAnnouncementRecipientRepository announcementRecipientRepository, IOptions<ApplicationOptions> applicationOptions)
{
_announcementRecipientRepository = announcementRecipientRepository;
_applicationOptions = applicationOptions.Value;
}

public async Task Handle(AnonymizeRecipientForIdentityCommand request, CancellationToken cancellationToken)
{
var announcementRecipients = await _announcementRecipientRepository.FindAllForIdentityAddress(IdentityAddress.Parse(request.IdentityAddress), cancellationToken);

foreach (var announcementRecipient in announcementRecipients)
{
announcementRecipient.Anonymize(_applicationOptions.DidDomainName);
}

await _announcementRecipientRepository.Update(announcementRecipients, cancellationToken);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Backbone.BuildingBlocks.Application.Extensions;
using Backbone.DevelopmentKit.Identity.ValueObjects;
using FluentValidation;

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

public class Validator : AbstractValidator<AnonymizeRecipientForIdentityCommand>
{
public Validator()
{
RuleFor(c => c.IdentityAddress)
.ValidId<AnonymizeRecipientForIdentityCommand, IdentityAddress>();
}
}
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,24 +1,59 @@
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 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<CreateAnnouncementCommand, AnnouncementDTO>
{
private readonly IAnnouncementsRepository _announcementsRepository;
private readonly IIdentitiesRepository _identityRepository;
private readonly ILogger<Handler> _logger;

public Handler(IAnnouncementsRepository announcementsRepository)
public Handler(IAnnouncementsRepository announcementsRepository, ILogger<Handler> logger, IIdentitiesRepository identityRepository)
{
_announcementsRepository = announcementsRepository;
_logger = logger;
_identityRepository = identityRepository;
}

public async Task<AnnouncementDTO> Handle(CreateAnnouncementCommand request, CancellationToken cancellationToken)
{
List<AnnouncementRecipient> announcementRecipients = [];

if (request.Recipients != null && request.Recipients.Count != 0)
{
var requestRecipients = request.Recipients.OrderBy(address => address).ToList();

var requestRecipientsAsIdentityAddresses = requestRecipients.Select(IdentityAddress.Parse).ToList();
var foundRecipients = (await _identityRepository.Find(Identity.HasAddress(requestRecipientsAsIdentityAddresses), cancellationToken)).ToArray();
var foundRecipientAddresses = foundRecipients.Select(r => r.Address.Value).OrderBy(address => address).ToList();
var notFoundRecipientAddresses = requestRecipients.Except(foundRecipientAddresses).ToList();

if (notFoundRecipientAddresses.Count > 0)
{
_logger.LogError("Not all recipients were found in the database. \r\n" +
"Request Recipients: {requestRecipients}. \r\n" +
"Not Found Recipients: {notFoundRecipientAddresses}",
string.Join(',', requestRecipients),
string.Join(',', notFoundRecipientAddresses));
}

foreach (var recipient in foundRecipients)
{
announcementRecipients.AddRange(recipient.Devices.Select(recipientDevice =>
new AnnouncementRecipient(recipientDevice.Id.Value, recipient.Address.Value)));
}
}

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
Expand Up @@ -14,6 +14,11 @@ public Validator()
.WithErrorCode(GenericApplicationErrors.Validation.InvalidPropertyValue().Code)
.WithMessage("There must be a text for English.");

RuleFor(x => x.Recipients)
.Must(x => x is null or { Count: <= 100 })
.WithErrorCode(GenericApplicationErrors.Validation.InvalidPropertyValue().Code)
.WithMessage("The maximum number of recipients is 100.");

RuleForEach(x => x.Texts).SetValidator(new CreateAnnouncementCommandTextValidator());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,26 @@ public AnnouncementDTO(Announcement announcement)
ExpiresAt = announcement.ExpiresAt;
Severity = announcement.Severity;
Texts = announcement.Texts.Select(t => new AnnouncementTextDTO(t));
Recipients = announcement.Recipients.Select(r => new AnnouncementRecipientDTO(r));
}

public string Id { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime? ExpiresAt { get; set; }
public AnnouncementSeverity Severity { get; set; }
public IEnumerable<AnnouncementTextDTO> Texts { get; set; }
public IEnumerable<AnnouncementRecipientDTO> Recipients { get; set; }
}

public record AnnouncementRecipientDTO
{
public AnnouncementRecipientDTO(AnnouncementRecipient announcementRecipient)
{
DeviceId = announcementRecipient.DeviceId;
Address = announcementRecipient.Address;
}

public string DeviceId { get; set; }
public string Address { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ public class ApplicationOptions
{
[Required]
public PaginationOptions Pagination { get; set; } = new();

[Required]
[MinLength(3)]
[MaxLength(45)]
public string DidDomainName { get; set; } = null!;
}

public class PaginationOptions
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Backbone.BuildingBlocks.Application.Identities;
using Backbone.DevelopmentKit.Identity.ValueObjects;
using Backbone.Modules.Announcements.Application.Announcements.Commands.AnonymizeRecipient;
using MediatR;

namespace Backbone.Modules.Announcements.Application.Identities;

public class IdentityDeleter : IIdentityDeleter
{
private readonly IDeletionProcessLogger _deletionProcessLogger;
private readonly IMediator _mediator;

public IdentityDeleter(IMediator mediator, IDeletionProcessLogger deletionProcessLogger)
{
_mediator = mediator;
_deletionProcessLogger = deletionProcessLogger;
}

public async Task Delete(IdentityAddress identityAddress)
{
await _mediator.Send(new AnonymizeRecipientForIdentityCommand(identityAddress));
await _deletionProcessLogger.LogDeletion(identityAddress, "AnnouncementRecipients");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Backbone.DevelopmentKit.Identity.ValueObjects;
using Backbone.Modules.Announcements.Domain.Entities;

namespace Backbone.Modules.Announcements.Application.Infrastructure.Persistence.Repository;

public interface IAnnouncementRecipientRepository
{
Task<List<AnnouncementRecipient>> FindAllForIdentityAddress(IdentityAddress identityAddress, CancellationToken cancellationToken);
Task Update(List<AnnouncementRecipient> announcementRecipients, CancellationToken cancellationToken);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

<ItemGroup>
<ProjectReference Include="..\..\..\..\BuildingBlocks\src\BuildingBlocks.Domain\BuildingBlocks.Domain.csproj" />
<ProjectReference Include="..\..\..\..\BuildingBlocks\src\DevelopmentKit.Identity\DevelopmentKit.Identity.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ public AnnouncementCreatedDomainEvent(Announcement announcement) : base($"{annou
Id = announcement.Id.Value;
Severity = announcement.Severity.ToString();
Texts = announcement.Texts.Select(t => new AnnouncementCreatedDomainEventText(t)).ToList();
Recipients = announcement.Recipients.Select(r => r.Address).ToList();
}

public string Id { get; }
public string Severity { get; }
public List<AnnouncementCreatedDomainEventText> Texts { get; }
public List<string> Recipients { get; }
}

public class AnnouncementCreatedDomainEventText
Expand Down
Loading
Loading