From 07648a5992a5c59f8750ec475424e5a723e09547 Mon Sep 17 00:00:00 2001 From: Ike Kottlowski Date: Wed, 21 Jan 2026 18:00:33 -0500 Subject: [PATCH] feat: add delete by GranteeId and allow for multiple grantors to be contacted. --- .../Commands/DeleteEmergencyAccessCommand.cs | 69 ++++++++++++++----- .../IDeleteEmergencyAccessCommand.cs | 7 ++ 2 files changed, 59 insertions(+), 17 deletions(-) diff --git a/src/Core/Auth/UserFeatures/EmergencyAccess/Commands/DeleteEmergencyAccessCommand.cs b/src/Core/Auth/UserFeatures/EmergencyAccess/Commands/DeleteEmergencyAccessCommand.cs index a6cbe42886..94dc1cb75f 100644 --- a/src/Core/Auth/UserFeatures/EmergencyAccess/Commands/DeleteEmergencyAccessCommand.cs +++ b/src/Core/Auth/UserFeatures/EmergencyAccess/Commands/DeleteEmergencyAccessCommand.cs @@ -14,18 +14,18 @@ public class DeleteEmergencyAccessCommand( /// public async Task DeleteByIdGrantorIdAsync(Guid emergencyAccessId, Guid grantorId) { - var emergencyAccess = await _emergencyAccessRepository.GetDetailsByIdGrantorIdAsync(emergencyAccessId, grantorId); + var emergencyAccessDetails = await _emergencyAccessRepository.GetDetailsByIdGrantorIdAsync(emergencyAccessId, grantorId); - if (emergencyAccess == null || emergencyAccess.GrantorId != grantorId) + if (emergencyAccessDetails == null || emergencyAccessDetails.GrantorId != grantorId) { throw new BadRequestException("Emergency Access not valid."); } - await _emergencyAccessRepository.DeleteAsync(emergencyAccess); + var (grantorEmails, granteeEmails) = await DeleteEmergencyAccessAsync([emergencyAccessDetails]); // Send notification email to grantor - await SendEmergencyAccessRemoveGranteesEmailAsync(emergencyAccess.GrantorEmail, [emergencyAccess.GranteeName]); - return emergencyAccess; + await SendEmergencyAccessRemoveGranteesEmailAsync(grantorEmails, granteeEmails); + return emergencyAccessDetails; } /// @@ -33,34 +33,69 @@ public class DeleteEmergencyAccessCommand( { var emergencyAccessDetails = await _emergencyAccessRepository.GetManyDetailsByGrantorIdAsync(grantorId); + // if there is nothing return an empty array and do not send an email + if (emergencyAccessDetails == null || emergencyAccessDetails.Count == 0) + { + return emergencyAccessDetails; + } + + var (grantorEmails, granteeEmails) = await DeleteEmergencyAccessAsync(emergencyAccessDetails); + + // Send notification email to grantor + await SendEmergencyAccessRemoveGranteesEmailAsync(grantorEmails, granteeEmails); ; + + return emergencyAccessDetails; + } + + /// + public async Task?> DeleteAllByGranteeIdAsync(Guid granteeId) + { + var emergencyAccessDetails = await _emergencyAccessRepository.GetManyDetailsByGranteeIdAsync(granteeId); + // if there is nothing return an empty array if (emergencyAccessDetails == null || emergencyAccessDetails.Count == 0) { return emergencyAccessDetails; } - foreach (var details in emergencyAccessDetails) - { - var emergencyAccess = details.ToEmergencyAccess(); - await _emergencyAccessRepository.DeleteAsync(emergencyAccess); - } + var (grantorEmails, granteeEmails) = await DeleteEmergencyAccessAsync(emergencyAccessDetails); - // Send notification email to grantor - await SendEmergencyAccessRemoveGranteesEmailAsync( - emergencyAccessDetails.FirstOrDefault()?.GrantorEmail ?? string.Empty, - [.. emergencyAccessDetails.Select(e => e.GranteeName)]); + // Send notification email to grantor(s) + await SendEmergencyAccessRemoveGranteesEmailAsync(grantorEmails, granteeEmails); return emergencyAccessDetails; } - private async Task SendEmergencyAccessRemoveGranteesEmailAsync(string grantorEmail, string[] granteeNames) + private async Task<(HashSet grantorEmails, HashSet granteeEmails)> DeleteEmergencyAccessAsync(IEnumerable emergencyAccessDetails) + { + var grantorEmails = new HashSet(); + var granteeEmails = new HashSet(); + + foreach (var details in emergencyAccessDetails) + { + var emergencyAccess = details.ToEmergencyAccess(); + await _emergencyAccessRepository.DeleteAsync(emergencyAccess); + granteeEmails.Add(details.GranteeEmail ?? string.Empty); + grantorEmails.Add(details.GrantorEmail); + } + + return (grantorEmails, granteeEmails); + } + + /// + /// Sends an email notification to the grantor about removed grantees. + /// + /// The email addresses of the grantors to notify when deleting by grantee + /// The formatted identifiers of the removed grantees to include in the email + /// + private async Task SendEmergencyAccessRemoveGranteesEmailAsync(IEnumerable grantorEmails, IEnumerable formattedGranteeIdentifiers) { var email = new EmergencyAccessRemoveGranteesMail { - ToEmails = [grantorEmail], + ToEmails = grantorEmails, View = new EmergencyAccessRemoveGranteesMailView { - RemovedGranteeNames = granteeNames + RemovedGranteeEmails = formattedGranteeIdentifiers } }; diff --git a/src/Core/Auth/UserFeatures/EmergencyAccess/Interfaces/IDeleteEmergencyAccessCommand.cs b/src/Core/Auth/UserFeatures/EmergencyAccess/Interfaces/IDeleteEmergencyAccessCommand.cs index 2b6337d2d4..efdd864d60 100644 --- a/src/Core/Auth/UserFeatures/EmergencyAccess/Interfaces/IDeleteEmergencyAccessCommand.cs +++ b/src/Core/Auth/UserFeatures/EmergencyAccess/Interfaces/IDeleteEmergencyAccessCommand.cs @@ -25,4 +25,11 @@ public interface IDeleteEmergencyAccessCommand /// The ID of the grantor user whose emergency access records should be deleted. /// A collection of the deleted emergency access records. Task?> DeleteAllByGrantorIdAsync(Guid grantorId); + + /// + /// Deletes all emergency access records for the specified grantee. + /// + /// The ID of the grantee user whose emergency access records should be deleted. + /// A collection of the deleted emergency access records. + Task?> DeleteAllByGranteeIdAsync(Guid granteeId); }