Skip to content

Commit

Permalink
feat(sa): adjust delete technical user logic
Browse files Browse the repository at this point in the history
Refs: #950
  • Loading branch information
Phil91 committed Aug 29, 2024
1 parent dab75e5 commit f142193
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,11 @@ public async Task<int> DeleteOwnCompanyServiceAccountAsync(Guid serviceAccountId
var userStatus = UserStatusId.DELETED;
switch (result)
{
case { IsDimServiceAccount: true, DimServiceAccountWasCreated: true }:
case { IsDimServiceAccount: true, CreationProcessInProgress: false }:
userStatus = await CreateDeletionProcess(serviceAccountId, result).ConfigureAwait(ConfigureAwaitOptions.None);
break;
case { IsDimServiceAccount: true, DimServiceAccountWasCreated: false }:
HandleCreationProcessSkip(result);
break;
case { IsDimServiceAccount: true, CreationProcessInProgress: true }:
throw ConflictException.Create(AdministrationServiceAccountErrors.TECHNICAL_USER_CREATION_IN_PROGRESS);
default:
if (!string.IsNullOrWhiteSpace(result.ClientClientId))
{
Expand All @@ -153,21 +152,6 @@ public async Task<int> DeleteOwnCompanyServiceAccountAsync(Guid serviceAccountId
return await portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None);
}

private void HandleCreationProcessSkip(OwnServiceAccountData result)
{
if (result.ProcessData != null)
{
portalRepositories.GetInstance<IProcessStepRepository>().AttachAndModifyProcessSteps(result.ProcessData.ProcessStepIds.Select(x => new ValueTuple<Guid, Action<ProcessStep>?, Action<ProcessStep>>(
x,
ps => ps.ProcessStepStatusId = ProcessStepStatusId.TODO,
ps =>
{
ps.ProcessStepStatusId = ProcessStepStatusId.SKIPPED;
ps.Message = "Skipped due to service account deletion";
})));
}
}

private void ModifyConnectorForDeleteServiceAccount(Guid serviceAccountId, OwnServiceAccountData result)
{
if (result.ConnectorId != null)
Expand All @@ -186,7 +170,7 @@ private void ModifyConnectorForDeleteServiceAccount(Guid serviceAccountId, OwnSe

private async Task<UserStatusId> CreateDeletionProcess(Guid serviceAccountId, OwnServiceAccountData result)
{
var processId = result.ProcessData?.ProcessId ?? throw ConflictException.Create(AdministrationServiceAccountErrors.SERVICE_ACCOUNT_NOT_LINKED_TO_PROCESS, [new("serviceAccountId", serviceAccountId.ToString())]);
var processId = result.ProcessId ?? throw ConflictException.Create(AdministrationServiceAccountErrors.SERVICE_ACCOUNT_NOT_LINKED_TO_PROCESS, [new("serviceAccountId", serviceAccountId.ToString())]);

var processData = await portalRepositories.GetInstance<IProcessStepRepository>()
.GetProcessDataForServiceAccountDeletionCallback(processId, null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ public class AdministrationServiceAccountErrorMessageContainer : IErrorMessageCo
{ AdministrationServiceAccountErrors.SERVICE_INACTIVE_CONFLICT, "serviceAccount {serviceAccountId} is already INACTIVE"},
{ AdministrationServiceAccountErrors.SERVICE_CLIENTID_NOT_NULL_CONFLICT, "clientClientId of serviceAccount {serviceAccountId} should not be null"},
{ AdministrationServiceAccountErrors.SERVICE_ACCOUNT_NOT_LINKED_TO_PROCESS, "Service Account {serviceAccountId} is not linked to a process" },
{ AdministrationServiceAccountErrors.SERVICE_ACCOUNT_PENDING_PROCESS_STEPS, "Service Account {serviceAccountId} has pending process steps {processStepTypeIds}"}
{ AdministrationServiceAccountErrors.SERVICE_ACCOUNT_PENDING_PROCESS_STEPS, "Service Account {serviceAccountId} has pending process steps {processStepTypeIds}"},
{ AdministrationServiceAccountErrors.TECHNICAL_USER_CREATION_IN_PROGRESS, "Technical user can't be deleted because the creation progress is still running"}
}.ToImmutableDictionary(x => (int)x.Key, x => x.Value);

public Type Type { get => typeof(AdministrationServiceAccountErrors); }
Expand All @@ -60,5 +61,6 @@ public enum AdministrationServiceAccountErrors
SERVICE_INACTIVE_CONFLICT,
SERVICE_CLIENTID_NOT_NULL_CONFLICT,
SERVICE_ACCOUNT_NOT_LINKED_TO_PROCESS,
SERVICE_ACCOUNT_PENDING_PROCESS_STEPS
SERVICE_ACCOUNT_PENDING_PROCESS_STEPS,
TECHNICAL_USER_CREATION_IN_PROGRESS
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ public record OwnServiceAccountData(
ConnectorStatusId? StatusId,
OfferSubscriptionStatusId? OfferStatusId,
bool IsDimServiceAccount,
bool DimServiceAccountWasCreated,
ProcessData? ProcessData
bool CreationProcessInProgress,
Guid? ProcessId
);

public record ProcessData(Guid ProcessId, IEnumerable<Guid> ProcessStepIds);
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public void AttachAndModifyCompanyServiceAccount(
portalDbContext.CompanyServiceAccounts
.Where(serviceAccount =>
serviceAccount.Id == serviceAccountId &&
(serviceAccount.Identity!.UserStatusId == UserStatusId.ACTIVE || serviceAccount.Identity!.UserStatusId == UserStatusId.PENDING) &&
serviceAccount.Identity!.UserStatusId == UserStatusId.ACTIVE &&
(serviceAccount.CompaniesLinkedServiceAccount!.Owners == companyId || serviceAccount.CompaniesLinkedServiceAccount!.Provider == companyId))
.Select(sa => new OwnServiceAccountData(
sa.Identity!.IdentityAssignedRoles.Select(r => r.UserRoleId),
Expand All @@ -109,14 +109,11 @@ public void AttachAndModifyCompanyServiceAccount(
sa.Connector!.StatusId,
sa.OfferSubscription!.OfferSubscriptionStatusId,
sa.CompanyServiceAccountKindId == CompanyServiceAccountKindId.EXTERNAL,
sa.DimUserCreationData != null,
sa.DimUserCreationData == null ? null : new ProcessData(
sa.DimUserCreationData.ProcessId,
sa.DimUserCreationData!.Process!.ProcessSteps
.Where(ps =>
sa.DimUserCreationData!.Process!.ProcessSteps
.Any(ps =>
ps.ProcessStepStatusId == ProcessStepStatusId.TODO &&
processStepsToFilter.Contains(ps.ProcessStepTypeId))
.Select(x => x.Id))))
processStepsToFilter.Contains(ps.ProcessStepTypeId)),
sa.DimUserCreationData == null ? null : sa.DimUserCreationData!.ProcessId))
.SingleOrDefaultAsync();

public Task<CompanyServiceAccountDetailedData?> GetOwnCompanyServiceAccountDetailedDataUntrackedAsync(Guid serviceAccountId, Guid companyId) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -550,14 +550,13 @@ public async Task DeleteOwnCompanyServiceAccountAsync_WithInvalidConnectorStatus
}

[Theory]
[InlineData(true, false, false, false)]
[InlineData(false, false, true, false)]
[InlineData(false, true, true, false)]
[InlineData(true, false, true, false)]
[InlineData(false, false, false, false)]
[InlineData(false, true, false, false)]
[InlineData(false, true, false, true)]
public async Task DeleteOwnCompanyServiceAccountAsync_WithoutClient_CallsExpected(bool withClient, bool isDimServiceAccount, bool withServiceAccount, bool withCreationStepsInTodo)
[InlineData(true, false, false)]
[InlineData(false, false, true)]
[InlineData(false, true, true)]
[InlineData(true, false, true)]
[InlineData(false, false, false)]
[InlineData(false, true, false)]
public async Task DeleteOwnCompanyServiceAccountAsync_WithoutClient_CallsExpected(bool withClient, bool isDimServiceAccount, bool withServiceAccount)
{
// Arrange
var identity = _fixture.Build<Identity>()
Expand All @@ -568,7 +567,7 @@ public async Task DeleteOwnCompanyServiceAccountAsync_WithoutClient_CallsExpecte
.With(x => x.CompanyServiceAccountId, ValidServiceAccountId)
.Create();
var processId = Guid.NewGuid();
SetupDeleteOwnCompanyServiceAccount(withServiceAccount, isDimServiceAccount, withClient, connector, identity, processId, withCreationStepsInTodo);
SetupDeleteOwnCompanyServiceAccount(withServiceAccount, isDimServiceAccount, withClient, connector, identity, processId);
var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService);

// Act
Expand All @@ -577,11 +576,10 @@ public async Task DeleteOwnCompanyServiceAccountAsync_WithoutClient_CallsExpecte
// Assert
if (isDimServiceAccount)
{
A.CallTo(() => _processStepRepository.CreateProcessStepRange(A<IEnumerable<(ProcessStepTypeId ProcessStepTypeId, ProcessStepStatusId ProcessStepStatusId, Guid ProcessId)>>.That.Matches(x => x.Count() == 1 && x.First().ProcessStepTypeId == ProcessStepTypeId.DELETE_DIM_TECHNICAL_USER && x.First().ProcessStepStatusId == ProcessStepStatusId.TODO && x.First().ProcessId == processId))).MustHaveHappened(withCreationStepsInTodo ? 0 : 1, Times.Exactly);
A.CallTo(() => _processStepRepository.AttachAndModifyProcessSteps(A<IEnumerable<(Guid, Action<ProcessStep>?, Action<ProcessStep>)>>._)).MustHaveHappened(withCreationStepsInTodo ? 1 : 0, Times.Exactly);
A.CallTo(() => _processStepRepository.CreateProcessStepRange(A<IEnumerable<(ProcessStepTypeId ProcessStepTypeId, ProcessStepStatusId ProcessStepStatusId, Guid ProcessId)>>.That.Matches(x => x.Count() == 1 && x.First().ProcessStepTypeId == ProcessStepTypeId.DELETE_DIM_TECHNICAL_USER && x.First().ProcessStepStatusId == ProcessStepStatusId.TODO && x.First().ProcessId == processId))).MustHaveHappenedOnceExactly();
A.CallTo(() => _userRepository.AttachAndModifyIdentity(A<Guid>._, A<Action<Identity>>._, A<Action<Identity>>._)).MustHaveHappenedOnceExactly();
A.CallTo(() => _provisioningManager.DeleteCentralClientAsync(A<string>._)).MustNotHaveHappened();
identity.UserStatusId.Should().Be(withCreationStepsInTodo ? UserStatusId.DELETED : UserStatusId.PENDING_DELETION);
identity.UserStatusId.Should().Be(UserStatusId.PENDING_DELETION);
}
else if (withClient)
{
Expand All @@ -601,6 +599,29 @@ public async Task DeleteOwnCompanyServiceAccountAsync_WithoutClient_CallsExpecte
A.CallTo(() => _userRolesRepository.DeleteCompanyUserAssignedRoles(A<IEnumerable<(Guid, Guid)>>.That.IsSameSequenceAs(validServiceAccountUserRoleIds))).MustHaveHappenedOnceExactly();
}

[Fact]
public async Task DeleteOwnCompanyServiceAccountAsync_WithCreationProcessInProgress_ThrowsException()
{
// Arrange
var identity = _fixture.Build<Identity>()
.With(x => x.Id, ValidServiceAccountId)
.With(x => x.UserStatusId, UserStatusId.ACTIVE)
.Create();
var connector = _fixture.Build<Connector>()
.With(x => x.CompanyServiceAccountId, ValidServiceAccountId)
.Create();
var processId = Guid.NewGuid();
SetupDeleteOwnCompanyServiceAccount(true, true, true, connector, identity, processId, true);
var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService);
Task Act() => sut.DeleteOwnCompanyServiceAccountAsync(ValidServiceAccountId);

// Act
var ex = await Assert.ThrowsAsync<ConflictException>(Act);

// Assert
ex.Message.Should().Be("TECHNICAL_USER_CREATION_IN_PROGRESS");
}

#endregion

#region GetServiceAccountRolesAsync
Expand Down Expand Up @@ -802,7 +823,7 @@ private void SetupDeleteOwnCompanyServiceAccount(bool withServiceAccount, bool i
{
var serviceAccount = new CompanyServiceAccount(Guid.NewGuid(), Guid.NewGuid(), "test-sa", "test", CompanyServiceAccountTypeId.OWN, CompanyServiceAccountKindId.INTERNAL);
A.CallTo(() => _serviceAccountRepository.GetOwnCompanyServiceAccountWithIamServiceAccountRolesAsync(ValidServiceAccountId, ValidCompanyId, A<IEnumerable<ProcessStepTypeId>>._))
.Returns(new OwnServiceAccountData(_userRoleIds, serviceAccount.Id, serviceAccount.Version, withServiceAccount ? ValidConnectorId : null, withClient ? ClientId : null, ConnectorStatusId.INACTIVE, OfferSubscriptionStatusId.PENDING, isDimServiceAccount, !withCreateStepsInTodo, processId == null ? null : new ProcessData(processId.Value, withCreateStepsInTodo ? Enumerable.Repeat(Guid.NewGuid(), 1) : Enumerable.Empty<Guid>())));
.Returns(new OwnServiceAccountData(_userRoleIds, serviceAccount.Id, serviceAccount.Version, withServiceAccount ? ValidConnectorId : null, withClient ? ClientId : null, ConnectorStatusId.INACTIVE, OfferSubscriptionStatusId.PENDING, isDimServiceAccount, withCreateStepsInTodo, processId));
A.CallTo(() => _serviceAccountRepository.GetOwnCompanyServiceAccountWithIamServiceAccountRolesAsync(A<Guid>.That.Not.Matches(x => x == ValidServiceAccountId), A<Guid>._, A<IEnumerable<ProcessStepTypeId>>._))
.Returns<OwnServiceAccountData?>(null);

Expand Down

0 comments on commit f142193

Please sign in to comment.