diff --git a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditional.java b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditional.java index 941d786e1b7f5896114707c8ef9b737648d5d9c9..ba54237abaf2618e751858037e5ac73efd2cae43 100644 --- a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditional.java +++ b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditional.java @@ -26,6 +26,8 @@ public interface AccountRepositoryAdditional { boolean deleteAccount(UUID accountId); + boolean deleteProfile(UUID profileId); + boolean foundExistingNotOwnUsername(UUID accountId, String username); PendingAccountByAuthenticationProvider findSameAuthenticationProviderInPendingAccount(AuthenticationProvider authProvider); diff --git a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java index 17e055652127a8076f0cd26803229f59ae444a4c..be11888af9af727ae3fe13a85f82acc1612795bb 100644 --- a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java +++ b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java @@ -593,4 +593,51 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio return false; } + public boolean deleteProfile(UUID profileId) { + CassandraBatchOperations batchOperations = cassandraTemplate.batchOps(); + Profile existingProfile = profileRepository.findByProfileId(profileId); + if (existingProfile == null) { + logger.error("Error deleting profile. Existing profile with the provided id {} was not found.", profileId); + return false; + } + List existingAccountsForProfile = accountByProfileIdRepository + .findAllByProfileId(profileId); + WriteResult wr = null; + try { + deleteProfileAccountsWhenDeletingProfile(profileId, batchOperations, existingAccountsForProfile); + if (existingProfile.getAuthenticationProviders() != null) { + deleteAuthenticationProvidersFromProfile(batchOperations, existingProfile.getProfileId(), + existingProfile.getAuthenticationProviders()); + } + deleteProfileData(batchOperations, existingProfile); + wr = batchOperations.execute(); + } catch (IllegalArgumentException | IllegalStateException e) { + logger.info("Exception while deleting account."); + logger.debug("Exception while deleting account: {} ...", e.getMessage()); + return false; + } + if (wr != null && wr.wasApplied()) { + return true; + } + return false; + } + + private void deleteProfileAccountsWhenDeletingProfile(UUID profileId, CassandraBatchOperations batchOperations, + List existingAccountsForProfile) { + for (AccountByProfileId accountByProfileId : existingAccountsForProfile) { + Account existingAccount = accountRepository.findByAccountId(accountByProfileId.getAccountId()); + Set existingCommunicationProvidersSet = new HashSet(); + if (existingAccount.getCommunicationProviders() != null) { + existingCommunicationProvidersSet = new HashSet( + existingAccount.getCommunicationProviders()); + } + deleteAccountData(batchOperations, existingAccount); + deleteCommunicationProvidersFromAccount(batchOperations, existingAccount, + existingCommunicationProvidersSet); + deleteProfileByAuthenticationProvider(batchOperations, profileId, + AuthenticationProvider.createAuthenticationProviderFromStrings( + existingAccount.getAuthenticationProviderType(), + existingAccount.getAuthenticationProvider())); + } + } } diff --git a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java index c3cb47e8e463dba2443e6b063486dda214a0cd16..c6b55390f80fb7c123a418dee98d84e266a8580c 100644 --- a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java +++ b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java @@ -28,6 +28,7 @@ import biz.nynja.account.grpc.CreatePendingAccountRequest; import biz.nynja.account.grpc.CreatePendingAccountResponse; import biz.nynja.account.grpc.DeleteAccountRequest; import biz.nynja.account.grpc.StatusResponse; +import biz.nynja.account.grpc.DeleteProfileRequest; import biz.nynja.account.grpc.ErrorResponse; import biz.nynja.account.grpc.ErrorResponse.Cause; import biz.nynja.account.models.Account; @@ -440,4 +441,30 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas responseObserver.onCompleted(); return; } + + @Override + public void deleteProfile(DeleteProfileRequest request, StreamObserver responseObserver) { + logger.debug("Deleting profile: {}", request); + if ((request.getProfileId() == null) || (request.getProfileId().isEmpty())) { + responseObserver.onNext(StatusResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.MISSING_PROFILE_ID)).build()); + responseObserver.onCompleted(); + return; + } + + boolean wasProfileDeleted = accountRepositoryAdditional.deleteProfile(UUID.fromString(request.getProfileId())); + if (wasProfileDeleted) { + logger.info("The profile was deleted successfully."); + responseObserver.onNext(StatusResponse.newBuilder() + .setStatus("SUCCESS").build()); + responseObserver.onCompleted(); + return; + } + + logger.info("Error deleting profile."); + responseObserver.onNext(StatusResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.ERROR_DELETING_PROFILE)).build()); + responseObserver.onCompleted(); + return; + } } \ No newline at end of file diff --git a/src/test/java/biz/nynja/account/services/AccountServiceTests.java b/src/test/java/biz/nynja/account/services/AccountServiceTests.java index 96c314bcb524811602d60ddd0ce46ab296b0e2bb..f5b60b405b31aa0dbf946bb3c77071ca551c454d 100644 --- a/src/test/java/biz/nynja/account/services/AccountServiceTests.java +++ b/src/test/java/biz/nynja/account/services/AccountServiceTests.java @@ -37,7 +37,10 @@ import biz.nynja.account.grpc.AuthenticationType; import biz.nynja.account.grpc.CompletePendingAccountCreationRequest; import biz.nynja.account.grpc.CreatePendingAccountRequest; import biz.nynja.account.grpc.CreatePendingAccountResponse; +import biz.nynja.account.grpc.DeleteAccountRequest; +import biz.nynja.account.grpc.DeleteProfileRequest; import biz.nynja.account.grpc.ErrorResponse.Cause; +import biz.nynja.account.grpc.StatusResponse; import biz.nynja.account.grpc.UpdateAccountRequest; import biz.nynja.account.grpc.UpdateProfileRequest; import biz.nynja.account.grpc.UpdateProfileResponse; @@ -54,6 +57,7 @@ import biz.nynja.account.repositories.AccountRepository; import biz.nynja.account.repositories.AccountRepositoryAdditional; import biz.nynja.account.models.PendingAccount; import biz.nynja.account.repositories.PendingAccountRepository; +import biz.nynja.account.repositories.ProfileRepository; import biz.nynja.account.utils.GrpcServerTestBase; import biz.nynja.account.utils.Util; @@ -120,6 +124,9 @@ public class AccountServiceTests extends GrpcServerTestBase { @MockBean private AccountRepository accountRepository; + @MockBean + private ProfileRepository profileRepository; + @MockBean private PendingAccountRepository pendingAccountRepository; @@ -621,4 +628,89 @@ public class AccountServiceTests extends GrpcServerTestBase { respose.getError().getCause().equals(Cause.ERROR_CREATING_ACCOUNT)); } + + @Test + public void testDeleteAccountOK() throws ExecutionException, InterruptedException { + final DeleteAccountRequest request = DeleteAccountRequest.newBuilder().setAccountId(Util.ACCOUNT_ID.toString()) + .build(); + given(accountRepositoryAdditional.deleteAccount(Util.ACCOUNT_ID)).willReturn(true); + final AccountServiceGrpc.AccountServiceBlockingStub accountServiceBlockingStub = AccountServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + final StatusResponse reply = accountServiceBlockingStub.deleteAccount(request); + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain status '%s'", "SUCCESS"), reply.getStatus().equals("SUCCESS")); + } + + @Test + public void testDeleteAccountMissingAccountId() throws ExecutionException, InterruptedException { + final DeleteAccountRequest request = DeleteAccountRequest.newBuilder().build(); + final AccountServiceGrpc.AccountServiceBlockingStub accountServiceBlockingStub = AccountServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + final StatusResponse reply = accountServiceBlockingStub.deleteAccount(request); + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", Cause.MISSING_ACCOUNT_ID), + reply.getError().getCause().equals(Cause.MISSING_ACCOUNT_ID)); + } + + @Test + public void testDeleteAccountAccountIdNotFound() throws ExecutionException, InterruptedException { + final DeleteAccountRequest request = DeleteAccountRequest.newBuilder() + .setAccountId(Util.ACCOUNT_ID_NOT_FOUND.toString()).build(); + given(accountRepository.findByAccountId(Util.ACCOUNT_ID_NOT_FOUND)).willReturn(null); + final AccountServiceGrpc.AccountServiceBlockingStub accountServiceBlockingStub = AccountServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + final StatusResponse reply = accountServiceBlockingStub.deleteAccount(request); + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", Cause.ERROR_DELETING_ACCOUNT), + reply.getError().getCause().equals(Cause.ERROR_DELETING_ACCOUNT)); + } + + @Test + public void testDeleteAccountNoCorrespondingProfileFound() throws ExecutionException, InterruptedException { + final DeleteAccountRequest request = DeleteAccountRequest.newBuilder().setAccountId(Util.ACCOUNT_ID.toString()) + .build(); + given(profileRepository.findByProfileId(Util.PROFILE_ID)).willReturn(null); + final AccountServiceGrpc.AccountServiceBlockingStub accountServiceBlockingStub = AccountServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + final StatusResponse reply = accountServiceBlockingStub.deleteAccount(request); + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", Cause.ERROR_DELETING_ACCOUNT), + reply.getError().getCause().equals(Cause.ERROR_DELETING_ACCOUNT)); + } + + @Test + public void testDeleteProfileOK() throws ExecutionException, InterruptedException { + final DeleteProfileRequest request = DeleteProfileRequest.newBuilder().setProfileId(Util.PROFILE_ID.toString()) + .build(); + given(accountRepositoryAdditional.deleteProfile(Util.PROFILE_ID)).willReturn(true); + final AccountServiceGrpc.AccountServiceBlockingStub accountServiceBlockingStub = AccountServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + final StatusResponse reply = accountServiceBlockingStub.deleteProfile(request); + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain status '%s'", "SUCCESS"), reply.getStatus().equals("SUCCESS")); + } + + @Test + public void testDeleteProfileMissingProfileId() throws ExecutionException, InterruptedException { + final DeleteProfileRequest request = DeleteProfileRequest.newBuilder().build(); + final AccountServiceGrpc.AccountServiceBlockingStub accountServiceBlockingStub = AccountServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + final StatusResponse reply = accountServiceBlockingStub.deleteProfile(request); + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", Cause.MISSING_PROFILE_ID), + reply.getError().getCause().equals(Cause.MISSING_PROFILE_ID)); + } + + @Test + public void testDeleteProfileProfileIdNotFound() throws ExecutionException, InterruptedException { + final DeleteProfileRequest request = DeleteProfileRequest.newBuilder() + .setProfileId(Util.PROFILE_ID_NOT_FOUND.toString()).build(); + given(profileRepository.findByProfileId(Util.PROFILE_ID_NOT_FOUND)).willReturn(null); + final AccountServiceGrpc.AccountServiceBlockingStub accountServiceBlockingStub = AccountServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + final StatusResponse reply = accountServiceBlockingStub.deleteProfile(request); + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", Cause.ERROR_DELETING_PROFILE), + reply.getError().getCause().equals(Cause.ERROR_DELETING_PROFILE)); + } } diff --git a/src/test/java/biz/nynja/account/utils/Util.java b/src/test/java/biz/nynja/account/utils/Util.java index afbb24fb876b884f71dea409ff3cf3bba2b5d827..a7897de0ad58bb1b9d6ccc96a100b103cecfab51 100644 --- a/src/test/java/biz/nynja/account/utils/Util.java +++ b/src/test/java/biz/nynja/account/utils/Util.java @@ -31,6 +31,7 @@ public class Util { public static final UUID PROFILE_ID = UUID.fromString("12352345-e89b-43d3-d156-456732452200"); public static final UUID ACCOUNT_ID = UUID.fromString("44532732-12b3-132d-e156-223732152200"); public static final UUID ACCOUNT_ID_NOT_FOUND = UUID.fromString("44532732-12b3-132d-e156-223732152202"); + public static final UUID PROFILE_ID_NOT_FOUND = UUID.fromString("12352345-e89b-43d3-d156-456732452202"); public static final String ACCOUNT_MARK = "AccountMark"; public static final String UPDATED_ACCOUNT_MARK = "PRIVATE"; public static final String AUTHENTICATION_PROVIDER = "Provider";