From c7683fdc1027add616c1bbdb52ed5e141d542943 Mon Sep 17 00:00:00 2001 From: Stanimir Penkov Date: Thu, 20 Sep 2018 12:46:09 +0300 Subject: [PATCH 1/4] NY-3567: Endpoint for Delete Profile - implementation for deleting profile Signed-off-by: Stanimir Penkov --- .../AccountRepositoryAdditional.java | 2 + .../AccountRepositoryAdditionalImpl.java | 50 +++++++++++++++++++ .../account/services/AccountServiceImpl.java | 26 ++++++++++ 3 files changed, 78 insertions(+) diff --git a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditional.java b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditional.java index 941d786..ba54237 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 17e0556..d4b30db 100644 --- a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java +++ b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java @@ -593,4 +593,54 @@ 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) { + boolean applied = wr.wasApplied(); + if (applied) { + 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 c3cb47e..a63f549 100644 --- a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java +++ b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java @@ -28,6 +28,8 @@ 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.DeletionResponse; import biz.nynja.account.grpc.ErrorResponse; import biz.nynja.account.grpc.ErrorResponse.Cause; import biz.nynja.account.models.Account; @@ -440,4 +442,28 @@ 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(DeletionResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.MISSING_PROFILE_ID)).build()); + responseObserver.onCompleted(); + return; + } + + boolean wasProfileDeleted = accountRepositoryAdditional.deleteProfile(UUID.fromString(request.getProfileId())); + if (wasProfileDeleted) { + responseObserver.onNext(DeletionResponse.newBuilder() + .setDeletionDetails("The profile was successfully deleted.").build()); + responseObserver.onCompleted(); + return; + } + + responseObserver.onNext(DeletionResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.ERROR_DELETING_PROFILE)).build()); + responseObserver.onCompleted(); + return; + } } \ No newline at end of file -- GitLab From 7ebdaf99f9fe6c3e4228c66b573caa7695a1d5d6 Mon Sep 17 00:00:00 2001 From: Stanimir Penkov Date: Thu, 20 Sep 2018 17:01:16 +0300 Subject: [PATCH 2/4] NY-3567: Code Review Feedback Signed-off-by: Stanimir Penkov --- .../repositories/AccountRepositoryAdditionalImpl.java | 7 ++----- .../nynja/account/services/AccountServiceImpl.java | 11 +++++------ 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java index d4b30db..be11888 100644 --- a/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java +++ b/src/main/java/biz/nynja/account/repositories/AccountRepositoryAdditionalImpl.java @@ -616,11 +616,8 @@ public class AccountRepositoryAdditionalImpl implements AccountRepositoryAdditio logger.debug("Exception while deleting account: {} ...", e.getMessage()); return false; } - if (wr != null) { - boolean applied = wr.wasApplied(); - if (applied) { - return true; - } + if (wr != null && wr.wasApplied()) { + return true; } return false; } diff --git a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java index a63f549..71bc3b0 100644 --- a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java +++ b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java @@ -29,7 +29,6 @@ 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.DeletionResponse; import biz.nynja.account.grpc.ErrorResponse; import biz.nynja.account.grpc.ErrorResponse.Cause; import biz.nynja.account.models.Account; @@ -444,10 +443,10 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas } @Override - public void deleteProfile(DeleteProfileRequest request, StreamObserver responseObserver) { + public void deleteProfile(DeleteProfileRequest request, StreamObserver responseObserver) { logger.debug("Deleting profile: {}", request); if ((request.getProfileId() == null) || (request.getProfileId().isEmpty())) { - responseObserver.onNext(DeletionResponse.newBuilder() + responseObserver.onNext(StatusResponse.newBuilder() .setError(ErrorResponse.newBuilder().setCause(Cause.MISSING_PROFILE_ID)).build()); responseObserver.onCompleted(); return; @@ -455,13 +454,13 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas boolean wasProfileDeleted = accountRepositoryAdditional.deleteProfile(UUID.fromString(request.getProfileId())); if (wasProfileDeleted) { - responseObserver.onNext(DeletionResponse.newBuilder() - .setDeletionDetails("The profile was successfully deleted.").build()); + responseObserver.onNext(StatusResponse.newBuilder() + .setStatus("SUCCESS").build()); responseObserver.onCompleted(); return; } - responseObserver.onNext(DeletionResponse.newBuilder() + responseObserver.onNext(StatusResponse.newBuilder() .setError(ErrorResponse.newBuilder().setCause(Cause.ERROR_DELETING_PROFILE)).build()); responseObserver.onCompleted(); return; -- GitLab From dfe0cac8bdc7718d1ff1e1b09c537877e09bacd2 Mon Sep 17 00:00:00 2001 From: Stanimir Penkov Date: Fri, 21 Sep 2018 16:15:33 +0300 Subject: [PATCH 3/4] NY-3570: Unit Tests Signed-off-by: Stanimir Penkov --- .../account/services/AccountServiceTests.java | 92 +++++++++++++++++++ .../java/biz/nynja/account/utils/Util.java | 1 + 2 files changed, 93 insertions(+) diff --git a/src/test/java/biz/nynja/account/services/AccountServiceTests.java b/src/test/java/biz/nynja/account/services/AccountServiceTests.java index 96c314b..f5b60b4 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 afbb24f..a7897de 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"; -- GitLab From d762c00c92c394d04eae2859b91cd2472d89b9e7 Mon Sep 17 00:00:00 2001 From: Stanimir Penkov Date: Tue, 25 Sep 2018 14:30:02 +0300 Subject: [PATCH 4/4] NY-3567: Code Review Feedback Signed-off-by: Stanimir Penkov --- .../java/biz/nynja/account/services/AccountServiceImpl.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java index 71bc3b0..c6b5539 100644 --- a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java +++ b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java @@ -454,12 +454,14 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas 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(); -- GitLab