From 3b3e1b4a17c10387899893739df330d50108a74b Mon Sep 17 00:00:00 2001 From: Shade Date: Fri, 22 Nov 2024 19:22:08 +0400 Subject: [PATCH] Form Patching Support --- .../creditcard/CreditCardRepository.kt | 2 + .../impl/CreditCardRepositoryImpl.kt | 25 ++++++++ .../repository/password/PasswordRepository.kt | 4 +- .../password/impl/PasswordRepositoryImpl.kt | 30 ++++++++- .../forms/passwordmgnt/CreditCardForm.kt | 9 ++- .../kotlin/ui/screens/PasswordMgntScreen.kt | 2 +- .../viewmodel/PasswordMgntScreenModel.kt | 63 +++++++++++++------ 7 files changed, 110 insertions(+), 25 deletions(-) diff --git a/src/main/kotlin/repository/creditcard/CreditCardRepository.kt b/src/main/kotlin/repository/creditcard/CreditCardRepository.kt index 13869ed..d14e3be 100644 --- a/src/main/kotlin/repository/creditcard/CreditCardRepository.kt +++ b/src/main/kotlin/repository/creditcard/CreditCardRepository.kt @@ -14,4 +14,6 @@ interface CreditCardRepository { suspend fun save(creditCardDto: CreditCardDto): Result + suspend fun update(id: UUID, user: String, creditCardDto: CreditCardDto): Result + } \ No newline at end of file diff --git a/src/main/kotlin/repository/creditcard/impl/CreditCardRepositoryImpl.kt b/src/main/kotlin/repository/creditcard/impl/CreditCardRepositoryImpl.kt index 0da4a73..a4221bc 100644 --- a/src/main/kotlin/repository/creditcard/impl/CreditCardRepositoryImpl.kt +++ b/src/main/kotlin/repository/creditcard/impl/CreditCardRepositoryImpl.kt @@ -17,6 +17,7 @@ import repository.creditcard.CreditCard import repository.creditcard.CreditCardRepository import repository.creditcard.CreditCardTable import repository.creditcard.projection.CreditCardSummary +import java.time.LocalDateTime import java.util.* class CreditCardRepositoryImpl( @@ -92,6 +93,30 @@ class CreditCardRepositoryImpl( } } + override suspend fun update(id: UUID, user: String, creditCardDto: CreditCardDto): Result { + return try { + return transaction(db) { + CreditCard.findById(id)?.let { + it.owner = creditCardDto.owner + it.name = creditCardDto.name + it.number = creditCardDto.number + it.cvc = creditCardDto.cvc + it.pin = creditCardDto.pin + it.notes = creditCardDto.notes + it.expiryDate = creditCardDto.expiryDate + it.lastUpdateDateTime = LocalDateTime.now() + it.lastUpdatedBy = user + it.version += 1 + } + }.let { + Result.Success(true) + } + } catch (e: Exception) { + logger.error(e.message, e) + Result.Error(DatabaseError.fromException(e).extractMessage()) + } + } + private fun toSort(sort: CredentialSort): Expression<*> { return when (sort) { CredentialSort.NAME -> CreditCardTable.name diff --git a/src/main/kotlin/repository/password/PasswordRepository.kt b/src/main/kotlin/repository/password/PasswordRepository.kt index 2818a18..aa7ce7e 100644 --- a/src/main/kotlin/repository/password/PasswordRepository.kt +++ b/src/main/kotlin/repository/password/PasswordRepository.kt @@ -4,7 +4,7 @@ import core.models.Result import core.models.criteria.CredentialSearchCriteria import core.models.dto.PasswordDto import repository.password.projection.PasswordSummary -import java.util.UUID +import java.util.* interface PasswordRepository { @@ -14,4 +14,6 @@ interface PasswordRepository { suspend fun save(password: PasswordDto): Result + suspend fun update(id: UUID, user: String, password: PasswordDto): Result + } \ No newline at end of file diff --git a/src/main/kotlin/repository/password/impl/PasswordRepositoryImpl.kt b/src/main/kotlin/repository/password/impl/PasswordRepositoryImpl.kt index 31352ec..9cf3e3c 100644 --- a/src/main/kotlin/repository/password/impl/PasswordRepositoryImpl.kt +++ b/src/main/kotlin/repository/password/impl/PasswordRepositoryImpl.kt @@ -16,6 +16,7 @@ import repository.password.Password import repository.password.PasswordRepository import repository.password.PasswordsTable import repository.password.projection.PasswordSummary +import java.time.LocalDateTime import java.util.* class PasswordRepositoryImpl( @@ -56,7 +57,11 @@ class PasswordRepositoryImpl( query.orderBy(toSort(searchCriteria.sort), toOrder(searchCriteria.sort)).map { resultRow -> PasswordSummary( id = resultRow[PasswordsTable.id].value, - name = resultRow[PasswordsTable.name].replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }, + name = resultRow[PasswordsTable.name].replaceFirstChar { + if (it.isLowerCase()) it.titlecase( + Locale.getDefault() + ) else it.toString() + }, username = resultRow[PasswordsTable.username], email = resultRow[PasswordsTable.email], favorite = resultRow[PasswordsTable.favorite] @@ -92,6 +97,29 @@ class PasswordRepositoryImpl( } } + override suspend fun update(id: UUID, user: String, password: PasswordDto): Result { + return try { + return transaction(db) { + Password.findById(id)?.let { + it.username = password.userName?.lowercase() + it.email = password.email + it.password = password.password + it.name = password.name.lowercase() + it.website = password.website + it.websiteIcon = password.icon + it.lastUpdatedBy = user + it.lastUpdateDateTime = LocalDateTime.now() + it.version += 1 + } + }.let { + Result.Success(true) + } + } catch (e: Exception) { + logger.error(e.message, e) + Result.Error(DatabaseError.fromException(e).extractMessage()) + } + } + private fun toSort(sort: CredentialSort): Expression<*> { return when (sort) { CredentialSort.NAME -> PasswordsTable.name diff --git a/src/main/kotlin/ui/components/forms/passwordmgnt/CreditCardForm.kt b/src/main/kotlin/ui/components/forms/passwordmgnt/CreditCardForm.kt index 9c059fc..991e96f 100644 --- a/src/main/kotlin/ui/components/forms/passwordmgnt/CreditCardForm.kt +++ b/src/main/kotlin/ui/components/forms/passwordmgnt/CreditCardForm.kt @@ -20,6 +20,7 @@ import com.dokar.sonner.Toaster import com.dokar.sonner.rememberToasterState import core.form.validation.FormValidator import core.models.FormType +import core.models.FormType.CREATION import core.models.UiState import kotlinx.coroutines.delay import repository.creditcard.CreditCard @@ -142,8 +143,8 @@ class CreditCardForm(creditCard: CreditCard?, formType: FormType) : Screen { ) { Header( creditCardButtonShown = false, - notesButtonShown = (formType == FormType.CREATION), - title = if (formType == FormType.CREATION) "Create Credit Card" else "Update Credit Card" + notesButtonShown = (formType == CREATION), + title = if (formType == CREATION) "Create Credit Card" else "Update Credit Card" ) } @@ -330,11 +331,13 @@ class CreditCardForm(creditCard: CreditCard?, formType: FormType) : Screen { Footer( { screenModel.saveCreditCard( + _creditCard?.id?.value, toCreditCardDto( formValidator, screenModel.getAuthenticatedUser(), selectedItem?.id!! - ) + ), + formType ) }, { navigator?.popUntil { screen: Screen -> screen.key == SecVaultScreen().key } }, diff --git a/src/main/kotlin/ui/screens/PasswordMgntScreen.kt b/src/main/kotlin/ui/screens/PasswordMgntScreen.kt index 62e9db8..7f4af60 100644 --- a/src/main/kotlin/ui/screens/PasswordMgntScreen.kt +++ b/src/main/kotlin/ui/screens/PasswordMgntScreen.kt @@ -47,7 +47,7 @@ class PasswordMgntScreen(password: Password?, formType: FormType) : Screen { formValidator, screenModel, isFormValid, - onSaveClick = { password: PasswordDto -> screenModel.savePassword(password) }, + onSaveClick = { password: PasswordDto -> screenModel.savePassword(_password?.id?.value, password, _formType) }, onCancelClick = { navigator?.pop() }, _formType ) diff --git a/src/main/kotlin/viewmodel/PasswordMgntScreenModel.kt b/src/main/kotlin/viewmodel/PasswordMgntScreenModel.kt index aff1b53..8257964 100644 --- a/src/main/kotlin/viewmodel/PasswordMgntScreenModel.kt +++ b/src/main/kotlin/viewmodel/PasswordMgntScreenModel.kt @@ -3,6 +3,7 @@ package viewmodel import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.screenModelScope import core.AppState +import core.models.FormType import core.models.Result import core.models.UiState import core.models.dto.CreditCardDto @@ -17,6 +18,7 @@ import repository.creditcard.CreditCardRepository import repository.password.PasswordRepository import repository.user.User import repository.user.UserRepository +import java.util.* class PasswordMgntScreenModel( private val passwordRepository: PasswordRepository, @@ -29,30 +31,30 @@ class PasswordMgntScreenModel( private val _passwordState = MutableStateFlow>(UiState.Idle) val passwordState: StateFlow> = _passwordState.asStateFlow() - fun savePassword(password: PasswordDto) { - screenModelScope.launch(dispatcher) { - _passwordState.value = UiState.Loading - - when (val result = passwordRepository.save(password)) { - is Result.Success -> _passwordState.value = UiState.Success(result.data) - is Result.Error -> _passwordState.value = UiState.Error(result.message) - } - } + fun savePassword(id: UUID?, password: PasswordDto, formType: FormType) { + saveOrUpdate( + id = id, + dto = password, + formType = formType, + saveAction = passwordRepository::save, + updateAction = passwordRepository::update, + stateUpdater = { _passwordState.value = it } + ) } - fun saveCreditCard(creditCardDto: CreditCardDto) { - screenModelScope.launch(dispatcher) { - _passwordState.value = UiState.Loading - - when (val result = creditCardRepository.save(creditCardDto)) { - is Result.Success -> _passwordState.value = UiState.Success(result.data) - is Result.Error -> _passwordState.value = UiState.Error(result.message) - } - } + fun saveCreditCard(id: UUID?, creditCardDto: CreditCardDto, formType: FormType) { + saveOrUpdate( + id = id, + dto = creditCardDto, + formType = formType, + saveAction = creditCardRepository::save, + updateAction = creditCardRepository::update, + stateUpdater = { _passwordState.value = it } + ) } fun fetchUsers(): List { - return userRepository.findAll(); + return userRepository.findAll() } fun getAuthenticatedUser(): User { @@ -63,4 +65,27 @@ class PasswordMgntScreenModel( _passwordState.value = UiState.Idle } + private fun saveOrUpdate( + id: UUID?, + dto: T, + formType: FormType, + saveAction: suspend (T) -> Result, + updateAction: suspend (UUID, String, T) -> Result, + stateUpdater: (UiState) -> Unit + ) { + screenModelScope.launch(dispatcher) { + stateUpdater(UiState.Loading) + + val result = when (formType) { + FormType.CREATION -> saveAction(dto) + FormType.MODIFIATION -> updateAction(id!!, appState.userName, dto) + } + + when (result) { + is Result.Success -> stateUpdater(UiState.Success(result.data)) + is Result.Error -> stateUpdater(UiState.Error(result.message)) + } + } + } + } \ No newline at end of file