Skip to content

Commit

Permalink
Consumer API: Return end of approval period as part of an identity de…
Browse files Browse the repository at this point in the history
…letion process (#667)

* feat: add ApprovalPeriodEndsAt property to deletion process

* chore: change identity deletion grace period and approval period lengths

---------

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
tnotheis and mergify[bot] authored May 23, 2024
1 parent fe00b2d commit 6eeb796
Show file tree
Hide file tree
Showing 14 changed files with 79 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,29 @@ public IdentityDeletionProcessDetailsDTO(IdentityDeletionProcess process)
.ToList();
Status = process.Status;
CreatedAt = process.CreatedAt;
ApprovalPeriodEndsAt = process.ApprovalPeriodEndsAt;

ApprovalReminder1SentAt = process.ApprovalReminder1SentAt;
ApprovalReminder2SentAt = process.ApprovalReminder2SentAt;
ApprovalReminder3SentAt = process.ApprovalReminder3SentAt;

ApprovedAt = process.ApprovedAt;
ApprovedByDevice = process.ApprovedByDevice;

GracePeriodEndsAt = process.GracePeriodEndsAt;

GracePeriodReminder1SentAt = process.GracePeriodReminder1SentAt;
GracePeriodReminder2SentAt = process.GracePeriodReminder2SentAt;
GracePeriodReminder3SentAt = process.GracePeriodReminder3SentAt;
}


public string Id { get; set; }
public List<IdentityDeletionProcessAuditLogEntryDTO> AuditLog { get; set; }
public DeletionProcessStatus Status { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime ApprovalPeriodEndsAt { get; set; }


public DateTime? ApprovalReminder1SentAt { get; set; }
public DateTime? ApprovalReminder2SentAt { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,17 @@ public IdentityDeletionProcessOverviewDTO(IdentityDeletionProcess process)
Id = process.Id;
Status = process.Status;
CreatedAt = process.CreatedAt;
ApprovalPeriodEndsAt = process.ApprovalPeriodEndsAt;

ApprovalReminder1SentAt = process.ApprovalReminder1SentAt;
ApprovalReminder2SentAt = process.ApprovalReminder2SentAt;
ApprovalReminder3SentAt = process.ApprovalReminder3SentAt;

ApprovedAt = process.ApprovedAt;
ApprovedByDevice = process.ApprovedByDevice;

GracePeriodEndsAt = process.GracePeriodEndsAt;

GracePeriodReminder1SentAt = process.GracePeriodReminder1SentAt;
GracePeriodReminder2SentAt = process.GracePeriodReminder2SentAt;
GracePeriodReminder3SentAt = process.GracePeriodReminder3SentAt;
Expand All @@ -24,6 +29,7 @@ public IdentityDeletionProcessOverviewDTO(IdentityDeletionProcess process)
public string Id { get; set; }
public DeletionProcessStatus Status { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime ApprovalPeriodEndsAt { get; set; }

public DateTime? ApprovalReminder1SentAt { get; set; }
public DateTime? ApprovalReminder2SentAt { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ public async Task Handle(SendDeletionProcessApprovalRemindersCommand request, Ca
foreach (var identity in identities)
{
var deletionProcess = identity.GetDeletionProcessInStatus(DeletionProcessStatus.WaitingForApproval) ?? throw new NotFoundException(nameof(IdentityDeletionProcess));
var endOfApprovalPeriod = deletionProcess.GetEndOfApprovalPeriod();
var daysUntilApprovalPeriodEnds = (endOfApprovalPeriod - SystemTime.UtcNow).Days;
var daysUntilApprovalPeriodEnds = (deletionProcess.ApprovalPeriodEndsAt - SystemTime.UtcNow).Days;

if (deletionProcess.ApprovalReminder3SentAt != null)
{
Expand Down Expand Up @@ -77,6 +76,7 @@ private async Task SendReminder2(Identity identity, int daysUntilApprovalPeriodE
await _identitiesRepository.Update(identity, cancellationToken);
_logger.ApprovalReminder2Sent(identity.Address, deletionProcessId);
}

private async Task SendReminder1(Identity identity, int daysUntilApprovalPeriodEnds, IdentityDeletionProcessId deletionProcessId, CancellationToken cancellationToken)
{
await _pushNotificationSender.SendNotification(identity.Address, new DeletionProcessWaitingForApprovalReminderPushNotification(daysUntilApprovalPeriodEnds), cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,56 @@ namespace Backbone.Modules.Devices.Domain.Entities.Identities;

public class IdentityDeletionConfiguration
{
public static int MaxApprovalTime { get; set; } = 10;
public static int LengthOfGracePeriod { get; set; } = 30;
public static int LengthOfApprovalPeriod { get; } = 7;
public static int LengthOfGracePeriod { get; } = 14;

public static GracePeriodNotificationConfiguration GracePeriodNotification1 { get; set; } = new()
public static GracePeriodNotificationConfiguration GracePeriodNotification1 { get; } = new()
{
Time = 20
Time = 12
};

public static GracePeriodNotificationConfiguration GracePeriodNotification2 { get; set; } = new()
public static GracePeriodNotificationConfiguration GracePeriodNotification2 { get; } = new()
{
Time = 10
};

public static GracePeriodNotificationConfiguration GracePeriodNotification3 { get; set; } = new()
public static GracePeriodNotificationConfiguration GracePeriodNotification3 { get; } = new()
{
Time = 5
};

public static ApprovalReminderNotificationConfiguration ApprovalReminder1 { get; set; } = new()
public static ApprovalReminderNotificationConfiguration ApprovalReminder1 { get; } = new()
{
Time = 10
Time = 6
};

public static ApprovalReminderNotificationConfiguration ApprovalReminder2 { get; set; } = new()
public static ApprovalReminderNotificationConfiguration ApprovalReminder2 { get; } = new()
{
Time = 5
Time = 4
};

public static ApprovalReminderNotificationConfiguration ApprovalReminder3 { get; set; } = new()
public static ApprovalReminderNotificationConfiguration ApprovalReminder3 { get; } = new()
{
Time = 2
};

public static DeletionStartsNotification DeletionStartsNotification { get; set; } = new()
public static DeletionStartsNotification DeletionStartsNotification { get; } = new()
{
Text = "The grace period for the deletion of your identity has expired. The deletion starts now."
};
}

public class GracePeriodNotificationConfiguration
{
public int Time { get; set; }
public int Time { get; init; }
}

public class ApprovalReminderNotificationConfiguration
{
public int Time { get; set; }
public int Time { get; init; }
}

public class DeletionStartsNotification
{
public string Text { get; set; } = "";
public string Text { get; init; } = "";
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ private IdentityDeletionProcess(IdentityAddress createdBy, DeviceId createdByDev
public DeletionProcessStatus Status { get; private set; }
public DateTime DeletionStartedAt { get; private set; }
public DateTime CreatedAt { get; }
public DateTime ApprovalPeriodEndsAt => CreatedAt.AddDays(IdentityDeletionConfiguration.LengthOfApprovalPeriod);

public DateTime? ApprovalReminder1SentAt { get; private set; }
public DateTime? ApprovalReminder2SentAt { get; private set; }
Expand All @@ -60,7 +61,7 @@ private IdentityDeletionProcess(IdentityAddress createdBy, DeviceId createdByDev
public DateTime? GracePeriodReminder2SentAt { get; private set; }
public DateTime? GracePeriodReminder3SentAt { get; private set; }

public bool HasApprovalPeriodExpired => Status == DeletionProcessStatus.WaitingForApproval && SystemTime.UtcNow >= GetEndOfApprovalPeriod();
public bool HasApprovalPeriodExpired => Status == DeletionProcessStatus.WaitingForApproval && SystemTime.UtcNow >= ApprovalPeriodEndsAt;

public bool HasGracePeriodExpired => Status == DeletionProcessStatus.Approved && SystemTime.UtcNow >= GracePeriodEndsAt;

Expand All @@ -87,11 +88,6 @@ public bool IsActive()
return Status is DeletionProcessStatus.Approved or DeletionProcessStatus.WaitingForApproval or DeletionProcessStatus.Deleting;
}

public DateTime GetEndOfApprovalPeriod()
{
return CreatedAt.AddDays(IdentityDeletionConfiguration.MaxApprovalTime);
}

public void ApprovalReminder1Sent(IdentityAddress address)
{
ApprovalReminder1SentAt = SystemTime.UtcNow;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public async Task Happy_path()
&& i.Status == IdentityStatus.ToBeDeleted
&& i.TierId == Tier.QUEUED_FOR_DELETION.Id
&& i.DeletionProcesses.FirstOrDefault(d => d.Status == DeletionProcessStatus.Approved)!.ApprovedAt == DateTime.Parse("2000-01-01")
&& i.DeletionProcesses.FirstOrDefault(d => d.Status == DeletionProcessStatus.Approved)!.GracePeriodEndsAt == DateTime.Parse("2000-01-31")
&& i.DeletionProcesses.FirstOrDefault(d => d.Status == DeletionProcessStatus.Approved)!.GracePeriodEndsAt == DateTime.Parse("2000-01-15")
&& i.DeletionProcesses.FirstOrDefault(d => d.Status == DeletionProcessStatus.Approved)!.ApprovedByDevice == device.Id
), A<CancellationToken>._))
.MustHaveHappenedOnceExactly();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public async Task Sends_second_reminder()
var identity = TestDataGenerator.CreateIdentityWithDeletionProcessWaitingForApproval(deletionProcessStartedAt: DateTime.Parse("2000-01-01"));
identity.DeletionProcessApprovalReminder1Sent();

var utcNow = DateTime.Parse("2000-01-06");
var utcNow = DateTime.Parse("2000-01-04");
SystemTime.Set(utcNow);

var mockIdentitiesRepository = A.Fake<IIdentitiesRepository>();
Expand Down Expand Up @@ -103,7 +103,7 @@ public async Task Sends_third_reminder()
identity.DeletionProcessApprovalReminder1Sent();
identity.DeletionProcessApprovalReminder2Sent();

var utcNow = DateTime.Parse("2000-01-09");
var utcNow = DateTime.Parse("2000-01-06");
SystemTime.Set(utcNow);

var mockIdentitiesRepository = A.Fake<IIdentitiesRepository>();
Expand Down Expand Up @@ -133,7 +133,7 @@ public async Task Does_not_send_reminder_1_when_2_has_to_be_sent_as_well()
// Arrange
var identity = TestDataGenerator.CreateIdentityWithDeletionProcessWaitingForApproval(deletionProcessStartedAt: DateTime.Parse("2000-01-01"));

var utcNow = DateTime.Parse("2000-01-06");
var utcNow = DateTime.Parse("2000-01-04");
SystemTime.Set(utcNow);

var mockIdentitiesRepository = A.Fake<IIdentitiesRepository>();
Expand Down Expand Up @@ -164,7 +164,7 @@ public async Task Does_not_send_reminder_1_and_2_when_3_has_to_be_sent_as_well()
// Arrange
var identity = TestDataGenerator.CreateIdentityWithDeletionProcessWaitingForApproval(deletionProcessStartedAt: DateTime.Parse("2000-01-01"));

var utcNow = DateTime.Parse("2000-01-09");
var utcNow = DateTime.Parse("2000-01-06");
SystemTime.Set(utcNow);

var mockIdentitiesRepository = A.Fake<IIdentitiesRepository>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public async Task Sends_first_reminder()
// Arrange
var identity = TestDataGenerator.CreateIdentityWithApprovedDeletionProcess(approvalDate: DateTime.Parse("2000-01-01"));

var utcNow = DateTime.Parse("2000-01-11");
var utcNow = DateTime.Parse("2000-01-03");
SystemTime.Set(utcNow);

var mockIdentitiesRepository = A.Fake<IIdentitiesRepository>();
Expand Down Expand Up @@ -71,7 +71,7 @@ public async Task Sends_second_reminder()
var identity = TestDataGenerator.CreateIdentityWithApprovedDeletionProcess(approvalDate: DateTime.Parse("2000-01-01"));
identity.DeletionGracePeriodReminder1Sent();

var utcNow = DateTime.Parse("2000-01-21");
var utcNow = DateTime.Parse("2000-01-05");
SystemTime.Set(utcNow);

var mockIdentitiesRepository = A.Fake<IIdentitiesRepository>();
Expand Down Expand Up @@ -103,7 +103,7 @@ public async Task Sends_third_reminder()
identity.DeletionGracePeriodReminder1Sent();
identity.DeletionGracePeriodReminder2Sent();

var utcNow = DateTime.Parse("2000-01-26");
var utcNow = DateTime.Parse("2000-01-10");
SystemTime.Set(utcNow);

var mockIdentitiesRepository = A.Fake<IIdentitiesRepository>();
Expand Down Expand Up @@ -133,7 +133,7 @@ public async Task Does_not_send_reminder_1_when_2_has_to_be_sent_as_well()
// Arrange
var identity = TestDataGenerator.CreateIdentityWithApprovedDeletionProcess(approvalDate: DateTime.Parse("2000-01-01"));

var utcNow = DateTime.Parse("2000-01-21");
var utcNow = DateTime.Parse("2000-01-05");
SystemTime.Set(utcNow);

var mockIdentitiesRepository = A.Fake<IIdentitiesRepository>();
Expand Down Expand Up @@ -162,7 +162,7 @@ public async Task Does_not_send_reminder_1_when_2_has_to_be_sent_as_well()
public async Task Does_not_send_reminder_1_and_2_when_3_has_to_be_sent_as_well()
{
// Arrange
var identity = TestDataGenerator.CreateIdentityWithApprovedDeletionProcess(approvalDate: DateTime.Parse("2000-01-01"));
var identity = TestDataGenerator.CreateIdentityWithApprovedDeletionProcess(approvalDate: DateTime.Parse("2000-01-09"));

var utcNow = DateTime.Parse("2000-01-26");
SystemTime.Set(utcNow);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public void Approve_deletion_process_waiting_for_approval()

// Assert
identity.Status.Should().Be(IdentityStatus.ToBeDeleted);
identity.DeletionGracePeriodEndsAt.Should().Be(DateTime.Parse("2000-01-31"));
identity.DeletionGracePeriodEndsAt.Should().Be(DateTime.Parse("2000-01-15"));
identity.TierId.Should().Be(Tier.QUEUED_FOR_DELETION.Id);
var deletionProcess = identity.DeletionProcesses.FirstOrDefault(d => d.Status == DeletionProcessStatus.Approved)!;
AssertAuditLogEntryWasCreated(deletionProcess);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,9 @@ public void Cancel_deletion_process_that_is_past_due_approval()
var identity = TestDataGenerator.CreateIdentity();
identity.StartDeletionProcessAsSupport();

var utcNow = DateTime.Parse("2020-01-11T00:00:00");
var utcNow = DateTime.Parse("2020-01-08T00:00:00");
SystemTime.Set(utcNow);

IdentityDeletionConfiguration.MaxApprovalTime = 10;

// Act
var result = identity.CancelStaleDeletionProcess();

Expand All @@ -70,9 +68,7 @@ public void Canceling_stale_deletion_process_creates_audit_log_entry_when_execut
// Arrange
SystemTime.Set(DateTime.Parse("2020-01-01T00:00:00"));
var identity = TestDataGenerator.CreateIdentityWithDeletionProcessWaitingForApproval();
SystemTime.Set(DateTime.Parse("2020-01-11T00:00:00"));

IdentityDeletionConfiguration.MaxApprovalTime = 10;
SystemTime.Set(DateTime.Parse("2020-01-08T00:00:00"));

// Act
var result = identity.CancelStaleDeletionProcess();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Backbone.Tooling;
using Backbone.UnitTestTools.Extensions;
using FluentAssertions;
using Xunit;
using static Backbone.Modules.Devices.Domain.Tests.TestDataGenerator;

namespace Backbone.Modules.Devices.Domain.Tests.Identities;

public class DeletionProcessApprovalPeriodEndsAtTests
{
[Fact]
public void Deletion_process_ApprovalPeriodEndsAt_returns_expected_date()
{
// Arrange
SystemTime.Set("2024-01-01");

var identity = CreateIdentityWithDeletionProcessWaitingForApproval();
var deletionProcess = identity.DeletionProcesses[0];

// Act
var approvalPeriodEndsAt = deletionProcess.ApprovalPeriodEndsAt;

// Assert
approvalPeriodEndsAt.Should().Be("2024-01-08");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using Backbone.Tooling;
using FluentAssertions;
using Xunit;
using static Backbone.UnitTestTools.Data.TestDataGenerator;

namespace Backbone.Modules.Devices.Domain.Tests.Identities;

Expand Down Expand Up @@ -107,22 +106,6 @@ public void DeletionProcessApprovalReminder3Sent_fails_when_no_deletion_process_
acting.Should().Throw<DomainException>().Which.Code.Should().Be("error.platform.validation.device.deletionProcessIsNotInRequiredStatus");
}

[Fact]
public void GetEndOfApprovalPeriod_returns_expected_date()
{
// Arrange
SystemTime.Set(DateTime.Parse("2000-01-01"));
IdentityDeletionConfiguration.MaxApprovalTime = 10;

var deletionProcess = IdentityDeletionProcess.StartAsOwner(CreateRandomIdentityAddress(), CreateRandomDeviceId());

// Act
var endOfApprovalPeriod = deletionProcess.GetEndOfApprovalPeriod();

// Assert
endOfApprovalPeriod.Should().Be(DateTime.Parse("2000-01-11"));
}

private static void AssertAuditLogEntryWasCreated(IdentityDeletionProcess deletionProcess)
{
deletionProcess.AuditLog.Should().HaveCount(2);
Expand Down
Loading

0 comments on commit 6eeb796

Please sign in to comment.