From 11e77a9605c323bc2cf36abfbb82435fef504384 Mon Sep 17 00:00:00 2001 From: Harrishan Date: Mon, 18 Nov 2024 18:27:42 +0100 Subject: [PATCH 1/8] feat: add `deleteAccount` method in `UserViewModel` to manage user data deletion --- .../periodpals/model/user/UserModel.kt | 2 ++ .../model/user/UserModelSupabase.kt | 11 +++++++++++ .../periodpals/model/user/UserViewModel.kt | 19 +++++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/app/src/main/java/com/android/periodpals/model/user/UserModel.kt b/app/src/main/java/com/android/periodpals/model/user/UserModel.kt index 2139b733b..bcdf94047 100644 --- a/app/src/main/java/com/android/periodpals/model/user/UserModel.kt +++ b/app/src/main/java/com/android/periodpals/model/user/UserModel.kt @@ -32,4 +32,6 @@ interface UserRepository { onSuccess: (UserDto) -> Unit, onFailure: (Exception) -> Unit ) + + suspend fun deleteUserProfile(onSuccess: () -> Unit, onFailure: (Exception) -> Unit) } diff --git a/app/src/main/java/com/android/periodpals/model/user/UserModelSupabase.kt b/app/src/main/java/com/android/periodpals/model/user/UserModelSupabase.kt index 23738ef89..644392c81 100644 --- a/app/src/main/java/com/android/periodpals/model/user/UserModelSupabase.kt +++ b/app/src/main/java/com/android/periodpals/model/user/UserModelSupabase.kt @@ -74,4 +74,15 @@ class UserRepositorySupabase(private val supabase: SupabaseClient) : UserReposit onFailure(e) } } + + override suspend fun deleteUserProfile(onSuccess: () -> Unit, onFailure: (Exception) -> Unit) { + try { + withContext(Dispatchers.Main) { supabase.postgrest[USERS].delete() } + Log.d(TAG, "deleteUserProfile: Success") + onSuccess() + } catch (e: Exception) { + Log.d(TAG, "deleteUserProfile: fail to delete user profile: ${e.message}") + onFailure(e) + } + } } diff --git a/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt b/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt index 8e85780ac..cce2278a5 100644 --- a/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt +++ b/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt @@ -77,4 +77,23 @@ class UserViewModel(private val userRepository: UserRepositorySupabase) : ViewMo }) } } + + fun deleteAccount(onSuccess: () -> Unit, onFailure: (Exception) -> Unit) { + viewModelScope.launch { + try { + userRepository.deleteUserProfile( + onSuccess = { + Log.d(TAG, "deleteAccount: Success") + _user.value = null + onSuccess() + }, + onFailure = { exception -> + Log.d(TAG, "deleteAccount : fail to delete user: ${exception.message}") + onFailure(exception) + }) + } catch (e: Exception) { + onFailure(e) + } + } + } } From 0afdb60e5631762d1fb88aa27e012acbdccb903f Mon Sep 17 00:00:00 2001 From: Harrishan Date: Mon, 18 Nov 2024 19:49:35 +0100 Subject: [PATCH 2/8] test: Add unit tests for delete account function - Added unit tests for `deleteUser` in `UserRepositorySupabaseTest`. - Updated `UserViewModelTest` with tests for account deletion. - Renamed `deleteAccount` to `deleteUser` in `UserViewModel` for consistency with other methods. --- .../periodpals/model/user/UserViewModel.kt | 7 +++++- .../model/user/UserModelSupabaseTest.kt | 24 +++++++++++++++++++ .../model/user/UserViewModelTest.kt | 23 ++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt b/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt index cce2278a5..ee9fe883c 100644 --- a/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt +++ b/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt @@ -78,7 +78,12 @@ class UserViewModel(private val userRepository: UserRepositorySupabase) : ViewMo } } - fun deleteAccount(onSuccess: () -> Unit, onFailure: (Exception) -> Unit) { + fun deleteUser( + onSuccess: () -> Unit = { Log.d(TAG, "deleteAccount success callback") }, + onFailure: (Exception) -> Unit = { e: Exception -> + Log.d(TAG, "deleteAccount failure callback: $e") + } + ) { viewModelScope.launch { try { userRepository.deleteUserProfile( diff --git a/app/src/test/java/com/android/periodpals/model/user/UserModelSupabaseTest.kt b/app/src/test/java/com/android/periodpals/model/user/UserModelSupabaseTest.kt index 874b9f24e..12577d0eb 100644 --- a/app/src/test/java/com/android/periodpals/model/user/UserModelSupabaseTest.kt +++ b/app/src/test/java/com/android/periodpals/model/user/UserModelSupabaseTest.kt @@ -138,4 +138,28 @@ class UserRepositorySupabaseTest { assert(result) } } + + @Test + fun deleteUserProfileIsSuccessful() { + var result = false + + runTest { + val userRepositorySupabase = UserRepositorySupabase(supabaseClientSuccess) + userRepositorySupabase.deleteUserProfile( + { result = true }, { fail("should not call onFailure") }) + assert(result) + } + } + + @Test + fun deleteUserProfileHasFailed() { + var result = false + + runTest { + val userRepositorySupabase = UserRepositorySupabase(supabaseClientFailure) + userRepositorySupabase.deleteUserProfile( + { fail("should not call onSuccess") }, { result = true }) + assert(result) + } + } } diff --git a/app/src/test/java/com/android/periodpals/model/user/UserViewModelTest.kt b/app/src/test/java/com/android/periodpals/model/user/UserViewModelTest.kt index 54a6c5f39..e4ef66ec3 100644 --- a/app/src/test/java/com/android/periodpals/model/user/UserViewModelTest.kt +++ b/app/src/test/java/com/android/periodpals/model/user/UserViewModelTest.kt @@ -79,4 +79,27 @@ class UserViewModelTest { assertNull(userViewModel.user.value) } + + @Test + fun deleteUserIsSuccessful() = runTest { + doAnswer { it.getArgument<() -> Unit>(0)() } + .`when`(userModel) + .deleteUserProfile(any<() -> Unit>(), any<(Exception) -> Unit>()) + + userViewModel.deleteUser() + + assertNull(userViewModel.user.value) + } + + @Test + fun deleteUserHasFailed() = runTest { + val expected = userViewModel.user.value + doAnswer { it.getArgument<(Exception) -> Unit>(1)(Exception("failed")) } + .`when`(userModel) + .deleteUserProfile(any<() -> Unit>(), any<(Exception) -> Unit>()) + + userViewModel.deleteUser() + + assertEquals(expected, userViewModel.user.value) + } } From 3f04deae87f135d6ed35cacf29a2633672573331 Mon Sep 17 00:00:00 2001 From: Harrishan Date: Mon, 18 Nov 2024 20:00:25 +0100 Subject: [PATCH 3/8] fix: write documentation for delete user function in `UserModel` and `UserViewModel` --- .../java/com/android/periodpals/model/user/UserModel.kt | 6 ++++++ .../com/android/periodpals/model/user/UserViewModel.kt | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/app/src/main/java/com/android/periodpals/model/user/UserModel.kt b/app/src/main/java/com/android/periodpals/model/user/UserModel.kt index bcdf94047..90877bacd 100644 --- a/app/src/main/java/com/android/periodpals/model/user/UserModel.kt +++ b/app/src/main/java/com/android/periodpals/model/user/UserModel.kt @@ -33,5 +33,11 @@ interface UserRepository { onFailure: (Exception) -> Unit ) + /** + * Deletes the user profile from the database. + * + * @param onSuccess Callback function to be called on success. + * @param onFailure Callback function to be called when there is an exception. + */ suspend fun deleteUserProfile(onSuccess: () -> Unit, onFailure: (Exception) -> Unit) } diff --git a/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt b/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt index ee9fe883c..e7f9d7040 100644 --- a/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt +++ b/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt @@ -78,6 +78,13 @@ class UserViewModel(private val userRepository: UserRepositorySupabase) : ViewMo } } + /** + * Deletes the user profile. + * + * @param onSuccess Callback function to be called when the user profile is successfully deleted. + * @param onFailure Callback function to be called when there is an error deleting the user + * profile. + */ fun deleteUser( onSuccess: () -> Unit = { Log.d(TAG, "deleteAccount success callback") }, onFailure: (Exception) -> Unit = { e: Exception -> From 4a1a8ca875123f6f65109f952f0e323a7efd31e2 Mon Sep 17 00:00:00 2001 From: Harrishan Date: Mon, 18 Nov 2024 20:05:10 +0100 Subject: [PATCH 4/8] fix: run ktfmtFormat --- .../com/android/periodpals/model/user/UserModel.kt | 12 ++++++------ .../android/periodpals/model/user/UserViewModel.kt | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/android/periodpals/model/user/UserModel.kt b/app/src/main/java/com/android/periodpals/model/user/UserModel.kt index 90877bacd..fab8aa687 100644 --- a/app/src/main/java/com/android/periodpals/model/user/UserModel.kt +++ b/app/src/main/java/com/android/periodpals/model/user/UserModel.kt @@ -33,11 +33,11 @@ interface UserRepository { onFailure: (Exception) -> Unit ) - /** - * Deletes the user profile from the database. - * - * @param onSuccess Callback function to be called on success. - * @param onFailure Callback function to be called when there is an exception. - */ + /** + * Deletes the user profile from the database. + * + * @param onSuccess Callback function to be called on success. + * @param onFailure Callback function to be called when there is an exception. + */ suspend fun deleteUserProfile(onSuccess: () -> Unit, onFailure: (Exception) -> Unit) } diff --git a/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt b/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt index e7f9d7040..cd194b2ad 100644 --- a/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt +++ b/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt @@ -78,13 +78,13 @@ class UserViewModel(private val userRepository: UserRepositorySupabase) : ViewMo } } - /** - * Deletes the user profile. - * - * @param onSuccess Callback function to be called when the user profile is successfully deleted. - * @param onFailure Callback function to be called when there is an error deleting the user - * profile. - */ + /** + * Deletes the user profile. + * + * @param onSuccess Callback function to be called when the user profile is successfully deleted. + * @param onFailure Callback function to be called when there is an error deleting the user + * profile. + */ fun deleteUser( onSuccess: () -> Unit = { Log.d(TAG, "deleteAccount success callback") }, onFailure: (Exception) -> Unit = { e: Exception -> From 12f384d80b419791d3da242a886c1ee960b2b6a1 Mon Sep 17 00:00:00 2001 From: Harrishan Date: Wed, 20 Nov 2024 21:34:39 +0100 Subject: [PATCH 5/8] fix: add `idUser` parameter to `deleteUserProfile` method to filter the users by ID. - Updated `deleteUserProfile` method in `UserRepositorySupabase` to include `userId` parameter for identifying the user to delete. - Adjusted unit tests in `UserRepositorySupabaseTest` to pass `userId` parameter. - Updated documentation for `deleteUserProfile` method to reflect the new parameter. --- .../com/android/periodpals/model/user/UserModel.kt | 7 ++++++- .../android/periodpals/model/user/UserModelSupabase.kt | 10 ++++++++-- .../com/android/periodpals/model/user/UserViewModel.kt | 3 +++ .../periodpals/model/user/UserModelSupabaseTest.kt | 5 +++-- .../android/periodpals/model/user/UserViewModelTest.kt | 8 ++++---- 5 files changed, 24 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/android/periodpals/model/user/UserModel.kt b/app/src/main/java/com/android/periodpals/model/user/UserModel.kt index fab8aa687..9463ee25b 100644 --- a/app/src/main/java/com/android/periodpals/model/user/UserModel.kt +++ b/app/src/main/java/com/android/periodpals/model/user/UserModel.kt @@ -36,8 +36,13 @@ interface UserRepository { /** * Deletes the user profile from the database. * + * @param idUser The ID of the user profile to be deleted. * @param onSuccess Callback function to be called on success. * @param onFailure Callback function to be called when there is an exception. */ - suspend fun deleteUserProfile(onSuccess: () -> Unit, onFailure: (Exception) -> Unit) + suspend fun deleteUserProfile( + idUser: String, + onSuccess: () -> Unit, + onFailure: (Exception) -> Unit + ) } diff --git a/app/src/main/java/com/android/periodpals/model/user/UserModelSupabase.kt b/app/src/main/java/com/android/periodpals/model/user/UserModelSupabase.kt index 644392c81..833e34458 100644 --- a/app/src/main/java/com/android/periodpals/model/user/UserModelSupabase.kt +++ b/app/src/main/java/com/android/periodpals/model/user/UserModelSupabase.kt @@ -75,9 +75,15 @@ class UserRepositorySupabase(private val supabase: SupabaseClient) : UserReposit } } - override suspend fun deleteUserProfile(onSuccess: () -> Unit, onFailure: (Exception) -> Unit) { + override suspend fun deleteUserProfile( + idUser: String, + onSuccess: () -> Unit, + onFailure: (Exception) -> Unit + ) { try { - withContext(Dispatchers.Main) { supabase.postgrest[USERS].delete() } + withContext(Dispatchers.Main) { + supabase.postgrest[USERS].delete() { filter { eq("user_id", idUser) } } + } Log.d(TAG, "deleteUserProfile: Success") onSuccess() } catch (e: Exception) { diff --git a/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt b/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt index cd194b2ad..3f93ae22e 100644 --- a/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt +++ b/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt @@ -81,11 +81,13 @@ class UserViewModel(private val userRepository: UserRepositorySupabase) : ViewMo /** * Deletes the user profile. * + * @param idUser The ID of the user profile to be deleted. * @param onSuccess Callback function to be called when the user profile is successfully deleted. * @param onFailure Callback function to be called when there is an error deleting the user * profile. */ fun deleteUser( + idUser: String, onSuccess: () -> Unit = { Log.d(TAG, "deleteAccount success callback") }, onFailure: (Exception) -> Unit = { e: Exception -> Log.d(TAG, "deleteAccount failure callback: $e") @@ -94,6 +96,7 @@ class UserViewModel(private val userRepository: UserRepositorySupabase) : ViewMo viewModelScope.launch { try { userRepository.deleteUserProfile( + idUser, onSuccess = { Log.d(TAG, "deleteAccount: Success") _user.value = null diff --git a/app/src/test/java/com/android/periodpals/model/user/UserModelSupabaseTest.kt b/app/src/test/java/com/android/periodpals/model/user/UserModelSupabaseTest.kt index 12577d0eb..65e763533 100644 --- a/app/src/test/java/com/android/periodpals/model/user/UserModelSupabaseTest.kt +++ b/app/src/test/java/com/android/periodpals/model/user/UserModelSupabaseTest.kt @@ -27,6 +27,7 @@ class UserRepositorySupabaseTest { val imageUrl = "test_image" val description = "test_description" val dob = "test_dob" + val id = "test_id" } private val defaultUserDto: UserDto = UserDto(name, imageUrl, description, dob) @@ -146,7 +147,7 @@ class UserRepositorySupabaseTest { runTest { val userRepositorySupabase = UserRepositorySupabase(supabaseClientSuccess) userRepositorySupabase.deleteUserProfile( - { result = true }, { fail("should not call onFailure") }) + id, { result = true }, { fail("should not call onFailure") }) assert(result) } } @@ -158,7 +159,7 @@ class UserRepositorySupabaseTest { runTest { val userRepositorySupabase = UserRepositorySupabase(supabaseClientFailure) userRepositorySupabase.deleteUserProfile( - { fail("should not call onSuccess") }, { result = true }) + id, { fail("should not call onSuccess") }, { result = true }) assert(result) } } diff --git a/app/src/test/java/com/android/periodpals/model/user/UserViewModelTest.kt b/app/src/test/java/com/android/periodpals/model/user/UserViewModelTest.kt index e4ef66ec3..30d6b31bf 100644 --- a/app/src/test/java/com/android/periodpals/model/user/UserViewModelTest.kt +++ b/app/src/test/java/com/android/periodpals/model/user/UserViewModelTest.kt @@ -84,9 +84,9 @@ class UserViewModelTest { fun deleteUserIsSuccessful() = runTest { doAnswer { it.getArgument<() -> Unit>(0)() } .`when`(userModel) - .deleteUserProfile(any<() -> Unit>(), any<(Exception) -> Unit>()) + .deleteUserProfile(any(), any<() -> Unit>(), any<(Exception) -> Unit>()) - userViewModel.deleteUser() + userViewModel.deleteUser("test_id") assertNull(userViewModel.user.value) } @@ -96,9 +96,9 @@ class UserViewModelTest { val expected = userViewModel.user.value doAnswer { it.getArgument<(Exception) -> Unit>(1)(Exception("failed")) } .`when`(userModel) - .deleteUserProfile(any<() -> Unit>(), any<(Exception) -> Unit>()) + .deleteUserProfile(any(), any<() -> Unit>(), any<(Exception) -> Unit>()) - userViewModel.deleteUser() + userViewModel.deleteUser("test_id") assertEquals(expected, userViewModel.user.value) } From cc7f0b13315a0db23ae2b555085566fa9eb7fe27 Mon Sep 17 00:00:00 2001 From: Harrishan Date: Wed, 20 Nov 2024 22:01:02 +0100 Subject: [PATCH 6/8] fix: correct the index parameter of `getArgument` method for delete tests in `UserViewModelTest` --- .../com/android/periodpals/model/user/UserViewModelTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/test/java/com/android/periodpals/model/user/UserViewModelTest.kt b/app/src/test/java/com/android/periodpals/model/user/UserViewModelTest.kt index 30d6b31bf..fb0f31108 100644 --- a/app/src/test/java/com/android/periodpals/model/user/UserViewModelTest.kt +++ b/app/src/test/java/com/android/periodpals/model/user/UserViewModelTest.kt @@ -82,7 +82,7 @@ class UserViewModelTest { @Test fun deleteUserIsSuccessful() = runTest { - doAnswer { it.getArgument<() -> Unit>(0)() } + doAnswer { it.getArgument<() -> Unit>(1)() } .`when`(userModel) .deleteUserProfile(any(), any<() -> Unit>(), any<(Exception) -> Unit>()) @@ -94,7 +94,7 @@ class UserViewModelTest { @Test fun deleteUserHasFailed() = runTest { val expected = userViewModel.user.value - doAnswer { it.getArgument<(Exception) -> Unit>(1)(Exception("failed")) } + doAnswer { it.getArgument<(Exception) -> Unit>(2)(Exception("failed")) } .`when`(userModel) .deleteUserProfile(any(), any<() -> Unit>(), any<(Exception) -> Unit>()) From 76887ff8eef67adc0ef154f38e825e0da68ed127 Mon Sep 17 00:00:00 2001 From: Harrishan Date: Thu, 21 Nov 2024 12:11:18 +0100 Subject: [PATCH 7/8] fix: remove redundant try-catch in `deleteUserProfile` of `UserViewModel` --- .../periodpals/model/user/UserViewModel.kt | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt b/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt index 3f93ae22e..9a450c87c 100644 --- a/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt +++ b/app/src/main/java/com/android/periodpals/model/user/UserViewModel.kt @@ -94,21 +94,17 @@ class UserViewModel(private val userRepository: UserRepositorySupabase) : ViewMo } ) { viewModelScope.launch { - try { - userRepository.deleteUserProfile( - idUser, - onSuccess = { - Log.d(TAG, "deleteAccount: Success") - _user.value = null - onSuccess() - }, - onFailure = { exception -> - Log.d(TAG, "deleteAccount : fail to delete user: ${exception.message}") - onFailure(exception) - }) - } catch (e: Exception) { - onFailure(e) - } + userRepository.deleteUserProfile( + idUser, + onSuccess = { + Log.d(TAG, "deleteAccount: Success") + _user.value = null + onSuccess() + }, + onFailure = { exception -> + Log.d(TAG, "deleteAccount : fail to delete user: ${exception.message}") + onFailure(exception) + }) } } } From 8e6a7bb78cad10a3245a6337a8c5efb0e795fe6f Mon Sep 17 00:00:00 2001 From: Harrishan Date: Thu, 21 Nov 2024 12:29:27 +0100 Subject: [PATCH 8/8] feat: add a new data class where sensitive datas are shared to all view models --- .../com/android/periodpals/model/shared/SharedData.kt | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 app/src/main/java/com/android/periodpals/model/shared/SharedData.kt diff --git a/app/src/main/java/com/android/periodpals/model/shared/SharedData.kt b/app/src/main/java/com/android/periodpals/model/shared/SharedData.kt new file mode 100644 index 000000000..ab7fdff22 --- /dev/null +++ b/app/src/main/java/com/android/periodpals/model/shared/SharedData.kt @@ -0,0 +1,8 @@ +package com.android.periodpals.model.shared + +/** + * Data class for shared data among view models. + * + * @property userId The ID of the user. + */ +data class SharedData(val userId: String)