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

Allow sending push notifications to multiple identities and with dynamic text #939

Merged
merged 19 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@ private async Task ExecuteDeletion(IdentityAddress identityAddress, Cancellation

private async Task NotifyIdentityAboutStartingDeletion(IdentityAddress identityAddress, CancellationToken cancellationToken)
{
await _pushNotificationSender.SendNotification(identityAddress, new DeletionStartsPushNotification(), cancellationToken);
await _pushNotificationSender.SendNotification(
new DeletionStartsPushNotification(),
SendPushNotificationFilter.AllDevicesOf(identityAddress),
cancellationToken);
}

private async Task Delete(IdentityAddress identityAddress)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Backbone.DevelopmentKit.Identity.ValueObjects;
using Backbone.Job.IdentityDeletion.Workers;
using Backbone.Modules.Devices.Application.Identities.Commands.TriggerRipeDeletionProcesses;
using Backbone.Modules.Devices.Application.Infrastructure.PushNotifications.DeletionProcess;
using Backbone.Modules.Relationships.Application.Relationships.Queries.FindRelationshipsOfIdentity;
using CSharpFunctionalExtensions;
using FakeItEasy;
Expand Down Expand Up @@ -74,7 +75,11 @@ public async Task Sends_push_notification_to_each_deleted_identity()
// Assert
foreach (var identityAddress in new[] { identityAddress1, identityAddress2, identityAddress3 })
{
A.CallTo(() => mockPushNotificationSender.SendNotification(identityAddress, A<IPushNotification>._, A<CancellationToken>._)).MustHaveHappenedOnceExactly();
A.CallTo(() => mockPushNotificationSender.SendNotification(
A<DeletionStartsPushNotification>._,
A<SendPushNotificationFilter>.That.Matches(f => f.IncludedIdentities.Contains(identityAddress)),
A<CancellationToken>._)
).MustHaveHappenedOnceExactly();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
using System.Text.RegularExpressions;
using Backbone.BuildingBlocks.API.Extensions;
using Backbone.BuildingBlocks.Application.Abstractions.Exceptions;
using Backbone.BuildingBlocks.Domain;
using Backbone.BuildingBlocks.Domain.Errors;
using Backbone.BuildingBlocks.Domain.Exceptions;
using Backbone.BuildingBlocks.Infrastructure.Exceptions;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using Backbone.DevelopmentKit.Identity.ValueObjects;

namespace Backbone.BuildingBlocks.Application.PushNotifications;

public interface IPushNotificationSender
{
Task SendNotification(IdentityAddress recipient, IPushNotification notification, CancellationToken cancellationToken);
Task SendFilteredNotification(IdentityAddress recipient, IPushNotification notification, IEnumerable<string> excludedDevices, CancellationToken cancellationToken);
Task SendNotification(IPushNotification notification, SendPushNotificationFilter filter, CancellationToken cancellationToken);

Task SendNotification(IPushNotification notification, SendPushNotificationFilter filter, Dictionary<string, NotificationText> notificationTexts,
CancellationToken cancellationToken);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace Backbone.BuildingBlocks.Application.PushNotifications;

public record NotificationText(string Title, string Body);
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Backbone.DevelopmentKit.Identity.ValueObjects;

namespace Backbone.BuildingBlocks.Application.PushNotifications;

public record SendPushNotificationFilter
{
private SendPushNotificationFilter()
{
}

public List<DeviceId> ExcludedDevices { get; set; } = [];
public List<IdentityAddress> IncludedIdentities { get; set; } = [];

public static SendPushNotificationFilter AllDevicesOf(params IdentityAddress[] recipientAddresses)
{
return new SendPushNotificationFilter
{
IncludedIdentities = [.. recipientAddresses]
};
}

public static SendPushNotificationFilter AllDevicesOfExcept(IdentityAddress recipientAddress, params DeviceId[] deviceIds)
{
return new SendPushNotificationFilter
{
IncludedIdentities = [recipientAddress],
ExcludedDevices = [.. deviceIds]
};
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Backbone.BuildingBlocks.Domain.Errors;

namespace Backbone.BuildingBlocks.Domain;
namespace Backbone.BuildingBlocks.Domain.Exceptions;

public class DomainException : Exception
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Backbone.BuildingBlocks.Domain;
using Backbone.BuildingBlocks.Domain.Exceptions;
using FluentAssertions;
using FluentAssertions.Specialized;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.UserContext;
using Backbone.BuildingBlocks.Domain;
using Backbone.BuildingBlocks.Domain.Exceptions;
using Backbone.DevelopmentKit.Identity.ValueObjects;
using Backbone.Modules.Devices.Application.Infrastructure.Persistence.Repository;
using Backbone.Modules.Devices.Domain.Entities.Identities;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus;
using Backbone.BuildingBlocks.Application.PushNotifications;
using Backbone.DevelopmentKit.Identity.ValueObjects;
using Backbone.Modules.Devices.Application.Infrastructure.PushNotifications.Datawallet;
using Backbone.Modules.Devices.Domain.DomainEvents.Incoming.DatawalletModificationCreated;

Expand All @@ -17,6 +18,9 @@ public DatawalletModifiedDomainEventHandler(IPushNotificationSender pushSenderSe
public async Task Handle(DatawalletModifiedDomainEvent domainEvent)
{
var notification = new DatawalletModificationsCreatedPushNotification(domainEvent.ModifiedByDevice);
await _pushSenderService.SendFilteredNotification(domainEvent.Identity, notification, [domainEvent.ModifiedByDevice], CancellationToken.None);
await _pushSenderService.SendNotification(
notification,
SendPushNotificationFilter.AllDevicesOfExcept(IdentityAddress.ParseUnsafe(domainEvent.Identity), DeviceId.Parse(domainEvent.ModifiedByDevice)),
CancellationToken.None);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ public async Task Handle(ExternalEventCreatedDomainEvent @event)
var identity = await _identitiesRepository.FindByAddress(@event.Owner, CancellationToken.None) ?? throw new NotFoundException(nameof(Identity));

if (identity.Status != IdentityStatus.ToBeDeleted)
await _pushSenderService.SendNotification(@event.Owner, new ExternalEventCreatedPushNotification(), CancellationToken.None);
await _pushSenderService.SendNotification(
new ExternalEventCreatedPushNotification(),
SendPushNotificationFilter.AllDevicesOf(@event.Owner),
CancellationToken.None
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ public IdentityDeletionProcessStartedDomainEventHandler(IPushNotificationSender

public async Task Handle(IdentityDeletionProcessStartedDomainEvent @event)
{
await _pushNotificationSender.SendNotification(@event.Address, new DeletionProcessStartedPushNotification(), CancellationToken.None);
await _pushNotificationSender.SendNotification(new DeletionProcessStartedPushNotification(), SendPushNotificationFilter.AllDevicesOf(@event.Address), CancellationToken.None);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Backbone.BuildingBlocks.Application.Abstractions.Exceptions;
using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.UserContext;
using Backbone.BuildingBlocks.Application.PushNotifications;
using Backbone.BuildingBlocks.Domain;
using Backbone.BuildingBlocks.Domain.Exceptions;
using Backbone.Modules.Devices.Application.Infrastructure.Persistence.Repository;
using Backbone.Modules.Devices.Application.Infrastructure.PushNotifications.DeletionProcess;
using Backbone.Modules.Devices.Domain.Entities.Identities;
Expand Down Expand Up @@ -43,7 +43,11 @@ public async Task<ApproveDeletionProcessResponse> Handle(ApproveDeletionProcessC

var daysUntilDeletion = deletionProcess.GracePeriodEndsAt.Value.DaysUntilDate();

await _notificationSender.SendNotification(identity.Address, new DeletionProcessApprovedNotification(daysUntilDeletion), cancellationToken);
await _notificationSender.SendNotification(
new DeletionProcessApprovedPushNotification(daysUntilDeletion),
SendPushNotificationFilter.AllDevicesOf(identity.Address),
cancellationToken
);

return new ApproveDeletionProcessResponse(deletionProcess);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Backbone.BuildingBlocks.Application.Abstractions.Exceptions;
using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.UserContext;
using Backbone.BuildingBlocks.Application.PushNotifications;
using Backbone.BuildingBlocks.Domain;
using Backbone.BuildingBlocks.Domain.Exceptions;
using Backbone.Modules.Devices.Application.Infrastructure.Persistence.Repository;
using Backbone.Modules.Devices.Application.Infrastructure.PushNotifications.DeletionProcess;
using Backbone.Modules.Devices.Domain.Entities.Identities;
Expand Down Expand Up @@ -38,7 +38,11 @@ public async Task<CancelDeletionProcessAsOwnerResponse> Handle(CancelDeletionPro

await _identitiesRepository.Update(identity, cancellationToken);

await _notificationSender.SendNotification(identity.Address, new DeletionProcessCancelledByOwnerNotification(), cancellationToken);
await _notificationSender.SendNotification(
new DeletionProcessCancelledByOwnerPushNotification(),
SendPushNotificationFilter.AllDevicesOf(identity.Address),
cancellationToken
);

return new CancelDeletionProcessAsOwnerResponse(deletionProcess);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ public async Task<CancelDeletionAsSupportResponse> Handle(CancelDeletionAsSuppor

await _identitiesRepository.Update(identity, cancellationToken);

await _notificationSender.SendNotification(identity.Address, new DeletionProcessCancelledBySupportNotification(), cancellationToken);
await _notificationSender.SendNotification(
new DeletionProcessCancelledBySupportPushNotification(),
SendPushNotificationFilter.AllDevicesOf(identity.Address),
cancellationToken
);

return new CancelDeletionAsSupportResponse(deletionProcess);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using Backbone.BuildingBlocks.Application.Abstractions.Exceptions;
using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.UserContext;
using Backbone.BuildingBlocks.Domain;
using Backbone.BuildingBlocks.Domain.Exceptions;
using Backbone.Modules.Devices.Application.Infrastructure.Persistence.Repository;
using Backbone.Modules.Devices.Domain.Entities.Identities;
using MediatR;

namespace Backbone.Modules.Devices.Application.Identities.Commands.RejectDeletionProcess;

public class Handler : IRequestHandler<RejectDeletionProcessCommand, RejectDeletionProcessResponse>
{
private readonly IIdentitiesRepository _identitiesRepository;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,26 +61,35 @@ public async Task Handle(SendDeletionProcessApprovalRemindersCommand request, Ca

private async Task SendReminder3(Identity identity, double daysUntilApprovalPeriodEnds, IdentityDeletionProcessId deletionProcessId, CancellationToken cancellationToken)
{
await _pushNotificationSender.SendNotification(identity.Address, new DeletionProcessWaitingForApprovalReminderPushNotification((int)Math.Ceiling(daysUntilApprovalPeriodEnds)),
cancellationToken);
await _pushNotificationSender.SendNotification(
new DeletionProcessWaitingForApprovalReminderPushNotification((int)Math.Ceiling(daysUntilApprovalPeriodEnds)),
SendPushNotificationFilter.AllDevicesOf(identity.Address),
cancellationToken
);
identity.DeletionProcessApprovalReminder3Sent();
await _identitiesRepository.Update(identity, cancellationToken);
_logger.ApprovalReminder3Sent(deletionProcessId);
}

private async Task SendReminder2(Identity identity, double daysUntilApprovalPeriodEnds, IdentityDeletionProcessId deletionProcessId, CancellationToken cancellationToken)
{
await _pushNotificationSender.SendNotification(identity.Address, new DeletionProcessWaitingForApprovalReminderPushNotification((int)Math.Ceiling(daysUntilApprovalPeriodEnds)),
cancellationToken);
await _pushNotificationSender.SendNotification(
new DeletionProcessWaitingForApprovalReminderPushNotification((int)Math.Ceiling(daysUntilApprovalPeriodEnds)),
SendPushNotificationFilter.AllDevicesOf(identity.Address),
cancellationToken
);
identity.DeletionProcessApprovalReminder2Sent();
await _identitiesRepository.Update(identity, cancellationToken);
_logger.ApprovalReminder2Sent(deletionProcessId);
}

private async Task SendReminder1(Identity identity, double daysUntilApprovalPeriodEnds, IdentityDeletionProcessId deletionProcessId, CancellationToken cancellationToken)
{
await _pushNotificationSender.SendNotification(identity.Address, new DeletionProcessWaitingForApprovalReminderPushNotification((int)Math.Ceiling(daysUntilApprovalPeriodEnds)),
cancellationToken);
await _pushNotificationSender.SendNotification(
new DeletionProcessWaitingForApprovalReminderPushNotification((int)Math.Ceiling(daysUntilApprovalPeriodEnds)),
SendPushNotificationFilter.AllDevicesOf(identity.Address),
cancellationToken
);
identity.DeletionProcessApprovalReminder1Sent();
await _identitiesRepository.Update(identity, cancellationToken);
_logger.ApprovalReminder1Sent(deletionProcessId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,23 +66,35 @@ public async Task Handle(SendDeletionProcessGracePeriodRemindersCommand request,

private async Task SendReminder3(Identity identity, double daysUntilGracePeriodEnds, IdentityDeletionProcessId deletionProcessId, CancellationToken cancellationToken)
{
await _pushSender.SendNotification(identity.Address, new DeletionProcessGracePeriodReminderPushNotification((int)Math.Ceiling(daysUntilGracePeriodEnds)), cancellationToken);
await _pushSender.SendNotification(
new DeletionProcessGracePeriodReminderPushNotification((int)Math.Ceiling(daysUntilGracePeriodEnds)),
SendPushNotificationFilter.AllDevicesOf(identity.Address),
cancellationToken
);
identity.DeletionGracePeriodReminder3Sent();
await _identitiesRepository.Update(identity, cancellationToken);
_logger.Reminder3Sent(deletionProcessId);
}

private async Task SendReminder2(Identity identity, double daysUntilGracePeriodEnds, IdentityDeletionProcessId deletionProcessId, CancellationToken cancellationToken)
{
await _pushSender.SendNotification(identity.Address, new DeletionProcessGracePeriodReminderPushNotification((int)Math.Ceiling(daysUntilGracePeriodEnds)), cancellationToken);
await _pushSender.SendNotification(
new DeletionProcessGracePeriodReminderPushNotification((int)Math.Ceiling(daysUntilGracePeriodEnds)),
SendPushNotificationFilter.AllDevicesOf(identity.Address),
cancellationToken
);
identity.DeletionGracePeriodReminder2Sent();
await _identitiesRepository.Update(identity, cancellationToken);
_logger.Reminder2Sent(deletionProcessId);
}

private async Task SendReminder1(Identity identity, double daysUntilGracePeriodEnds, IdentityDeletionProcessId deletionProcessId, CancellationToken cancellationToken)
{
await _pushSender.SendNotification(identity.Address, new DeletionProcessGracePeriodReminderPushNotification((int)Math.Ceiling(daysUntilGracePeriodEnds)), cancellationToken);
await _pushSender.SendNotification(
new DeletionProcessGracePeriodReminderPushNotification((int)Math.Ceiling(daysUntilGracePeriodEnds)),
SendPushNotificationFilter.AllDevicesOf(identity.Address),
cancellationToken
);
identity.DeletionGracePeriodReminder1Sent();
await _identitiesRepository.Update(identity, cancellationToken);
_logger.Reminder1Sent(deletionProcessId);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Backbone.BuildingBlocks.Application.Abstractions.Exceptions;
using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.UserContext;
using Backbone.BuildingBlocks.Application.PushNotifications;
using Backbone.BuildingBlocks.Domain;
using Backbone.BuildingBlocks.Domain.Exceptions;
using Backbone.Modules.Devices.Application.Infrastructure.Persistence.Repository;
using Backbone.Modules.Devices.Application.Infrastructure.PushNotifications.DeletionProcess;
using Backbone.Modules.Devices.Domain;
Expand Down Expand Up @@ -38,7 +38,11 @@ public async Task<StartDeletionProcessAsOwnerResponse> Handle(StartDeletionProce
throw new DomainException(DomainErrors.OnlyOneActiveDeletionProcessAllowed());
}

await _notificationSender.SendNotification(identity.Address, new DeletionProcessStartedPushNotification(), cancellationToken);
await _notificationSender.SendNotification(
new DeletionProcessStartedPushNotification(),
SendPushNotificationFilter.AllDevicesOf(identity.Address),
cancellationToken
);

return new StartDeletionProcessAsOwnerResponse(deletionProcess);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
using Backbone.BuildingBlocks.Domain;
using Backbone.BuildingBlocks.Domain.Exceptions;
using Backbone.Modules.Devices.Application.Infrastructure.Persistence.Repository;
using Backbone.Modules.Devices.Domain.Entities.Identities;
using MediatR;

namespace Backbone.Modules.Devices.Application.Identities.Commands.TriggerRipeDeletionProcesses;

public class Handler : IRequestHandler<TriggerRipeDeletionProcessesCommand, TriggerRipeDeletionProcessesResponse>
{
private readonly IIdentitiesRepository _identitiesRepository;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public interface IIdentitiesRepository
Task<DbPaginationResult<Device>> FindAllDevicesOfIdentity(IdentityAddress identity, IEnumerable<DeviceId> ids, PaginationFilter paginationFilter, CancellationToken cancellationToken);
Task<Device?> GetDeviceById(DeviceId deviceId, CancellationToken cancellationToken, bool track = false);
Task Update(Device device, CancellationToken cancellationToken);
Task<T[]> FindDevices<T>(Expression<Func<Device, bool>> filter, Expression<Func<Device, T>> selector, CancellationToken cancellationToken, bool track = false);

#endregion

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ public interface IPnsRegistrationsRepository
{
Task Add(PnsRegistration registration, CancellationToken cancellationToken);
Task Update(PnsRegistration registration, CancellationToken cancellationToken);
Task<IEnumerable<PnsRegistration>> FindWithAddress(IdentityAddress address, CancellationToken cancellationToken, bool track = false);
Task<PnsRegistration?> FindByDeviceId(DeviceId deviceId, CancellationToken cancellationToken, bool track = false);
Task Delete(List<DeviceId> deviceIds, CancellationToken cancellationToken);
Task<PnsRegistration[]> FindByDeviceIds(DeviceId[] deviceIds, CancellationToken cancellationToken, bool track = false);
Task<int> Delete(List<DeviceId> deviceIds, CancellationToken cancellationToken);
Task Delete(Expression<Func<PnsRegistration, bool>> filter, CancellationToken cancellationToken);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

namespace Backbone.Modules.Devices.Application.Infrastructure.PushNotifications.DeletionProcess;

public record DeletionProcessApprovedNotification(int DaysUntilDeletion) : IPushNotification;
public record DeletionProcessApprovedPushNotification(int DaysUntilDeletion) : IPushNotification;
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

namespace Backbone.Modules.Devices.Application.Infrastructure.PushNotifications.DeletionProcess;

public record DeletionProcessCancelledByOwnerNotification : IPushNotification;
public record DeletionProcessCancelledByOwnerPushNotification : IPushNotification;
Loading