From fa0035e8b5af8db2825b7bbd5611add0e9789d94 Mon Sep 17 00:00:00 2001 From: barbararochazup Date: Thu, 6 May 2021 12:17:45 -0300 Subject: [PATCH 1/5] adding custom validator to duplicated entities Signed-off-by: barbararochazup --- .../moove/application/CircleService.kt | 7 ++- .../moove/application/WorkspaceService.kt | 7 ++- .../circle/request/CreateCircleRequest.kt | 4 ++ .../request/CreateWorkspaceRequest.kt | 5 ++ .../moove/commons/validator/Unique.kt | 16 ++++++ .../commons/validator/UniqueValidator.kt | 23 ++++++++ .../validator/UniqueValueFieldService.kt | 7 +++ .../domain/repository/CircleRepository.kt | 2 + .../domain/repository/WorkspaceRepository.kt | 2 + .../repository/JdbcCircleRepository.kt | 26 +++++++++ .../repository/JdbcWorkspaceRepository.kt | 56 +++++++++---------- 11 files changed, 125 insertions(+), 30 deletions(-) create mode 100644 moove/commons/src/main/kotlin/io/charlescd/moove/commons/validator/Unique.kt create mode 100644 moove/commons/src/main/kotlin/io/charlescd/moove/commons/validator/UniqueValidator.kt create mode 100644 moove/commons/src/main/kotlin/io/charlescd/moove/commons/validator/UniqueValueFieldService.kt diff --git a/moove/application/src/main/kotlin/io/charlescd/moove/application/CircleService.kt b/moove/application/src/main/kotlin/io/charlescd/moove/application/CircleService.kt index 440aade3b2..c82be3df47 100644 --- a/moove/application/src/main/kotlin/io/charlescd/moove/application/CircleService.kt +++ b/moove/application/src/main/kotlin/io/charlescd/moove/application/CircleService.kt @@ -18,6 +18,7 @@ package io.charlescd.moove.application +import io.charlescd.moove.commons.validator.UniqueValueFieldService import io.charlescd.moove.domain.* import io.charlescd.moove.domain.exceptions.BusinessException import io.charlescd.moove.domain.exceptions.NotFoundException @@ -26,7 +27,7 @@ import java.util.* import javax.inject.Named @Named -class CircleService(private val circleRepository: CircleRepository) { +class CircleService(private val circleRepository: CircleRepository):UniqueValueFieldService { fun save(circle: Circle): Circle { return this.circleRepository.save(circle) @@ -100,4 +101,8 @@ class CircleService(private val circleRepository: CircleRepository) { verifyLimitReached(sumPercentage, circle.percentage!!) } } + + override fun fieldValueExists(value: String, fieldName: String): Boolean { + TODO("Not yet implemented") + } } diff --git a/moove/application/src/main/kotlin/io/charlescd/moove/application/WorkspaceService.kt b/moove/application/src/main/kotlin/io/charlescd/moove/application/WorkspaceService.kt index 23ffc75c50..c59baf5f47 100644 --- a/moove/application/src/main/kotlin/io/charlescd/moove/application/WorkspaceService.kt +++ b/moove/application/src/main/kotlin/io/charlescd/moove/application/WorkspaceService.kt @@ -18,6 +18,7 @@ package io.charlescd.moove.application +import io.charlescd.moove.commons.validator.UniqueValueFieldService import io.charlescd.moove.domain.* import io.charlescd.moove.domain.exceptions.NotFoundException import io.charlescd.moove.domain.repository.UserRepository @@ -28,7 +29,7 @@ import javax.inject.Named class WorkspaceService( private val workspaceRepository: WorkspaceRepository, private val userRepository: UserRepository -) { +): UniqueValueFieldService { fun find(workspaceId: String): Workspace { return this.workspaceRepository.find(workspaceId) @@ -64,4 +65,8 @@ class WorkspaceService( fun findAllUsers(workspaceId: String, name: String?, email: String?, pageRequest: PageRequest): Page { return this.userRepository.findByWorkspace(workspaceId, name, email, pageRequest) } + + override fun fieldValueExists(value: String, fieldName: String): Boolean { + return this.workspaceRepository.existsByParam(fieldName, value); + } } diff --git a/moove/application/src/main/kotlin/io/charlescd/moove/application/circle/request/CreateCircleRequest.kt b/moove/application/src/main/kotlin/io/charlescd/moove/application/circle/request/CreateCircleRequest.kt index adbfcb34a7..3cb21abbf3 100644 --- a/moove/application/src/main/kotlin/io/charlescd/moove/application/circle/request/CreateCircleRequest.kt +++ b/moove/application/src/main/kotlin/io/charlescd/moove/application/circle/request/CreateCircleRequest.kt @@ -18,7 +18,10 @@ package io.charlescd.moove.application.circle.request +import io.charlescd.moove.application.CircleService +import io.charlescd.moove.application.WorkspaceService import io.charlescd.moove.commons.extension.toJsonNode +import io.charlescd.moove.commons.validator.Unique import io.charlescd.moove.domain.Circle import io.charlescd.moove.domain.MatcherTypeEnum import io.charlescd.moove.domain.User @@ -34,6 +37,7 @@ class CreateCircleRequest( @field:NotBlank @field:Size(min = 1, max = 64, message = "Name minimum size is 1 and maximum is 64.") + @Unique(message = "Circle already registered", fieldName="name", service = CircleService::class) val name: String, @field:Valid diff --git a/moove/application/src/main/kotlin/io/charlescd/moove/application/workspace/request/CreateWorkspaceRequest.kt b/moove/application/src/main/kotlin/io/charlescd/moove/application/workspace/request/CreateWorkspaceRequest.kt index 4c0dbc29d0..855cb7dd3d 100644 --- a/moove/application/src/main/kotlin/io/charlescd/moove/application/workspace/request/CreateWorkspaceRequest.kt +++ b/moove/application/src/main/kotlin/io/charlescd/moove/application/workspace/request/CreateWorkspaceRequest.kt @@ -16,6 +16,9 @@ package io.charlescd.moove.application.workspace.request +import io.charlescd.moove.application.WorkspaceService +import io.charlescd.moove.commons.validator.Unique + import io.charlescd.moove.domain.User import io.charlescd.moove.domain.Workspace import java.time.LocalDateTime @@ -24,9 +27,11 @@ import javax.validation.constraints.NotNull import javax.validation.constraints.Size data class CreateWorkspaceRequest( + @field:NotNull @field:NotBlank @field:Size(min = 1, max = 64, message = "Name minimum size is 1 and maximum is 64.") + @Unique(message = "Workspace already registered", fieldName="name", service = WorkspaceService::class) val name: String ) { fun toWorkspace(id: String, author: User) = Workspace( diff --git a/moove/commons/src/main/kotlin/io/charlescd/moove/commons/validator/Unique.kt b/moove/commons/src/main/kotlin/io/charlescd/moove/commons/validator/Unique.kt new file mode 100644 index 0000000000..d9aa9b82d0 --- /dev/null +++ b/moove/commons/src/main/kotlin/io/charlescd/moove/commons/validator/Unique.kt @@ -0,0 +1,16 @@ +package io.charlescd.moove.commons.validator + +import javax.validation.Constraint +import javax.validation.Payload +import kotlin.reflect.KClass + +@Target(AnnotationTarget.FIELD) +@MustBeDocumented +@Constraint(validatedBy = [UniqueValidator::class]) +annotation class Unique( + val message: String = "Value already registered", + val groups: Array> = [], + val payload: Array> = [], + val fieldName: String = "", + val service: KClass +) diff --git a/moove/commons/src/main/kotlin/io/charlescd/moove/commons/validator/UniqueValidator.kt b/moove/commons/src/main/kotlin/io/charlescd/moove/commons/validator/UniqueValidator.kt new file mode 100644 index 0000000000..e6e10857cc --- /dev/null +++ b/moove/commons/src/main/kotlin/io/charlescd/moove/commons/validator/UniqueValidator.kt @@ -0,0 +1,23 @@ +package io.charlescd.moove.commons.validator + +import org.springframework.beans.factory.annotation.Autowired +import javax.validation.ConstraintValidator +import javax.validation.ConstraintValidatorContext + +class UniqueValidator : ConstraintValidator { + + @Autowired + lateinit var uniqueValueFieldService: UniqueValueFieldService + + private var fieldName: String? = null + + override fun initialize(unique: Unique) { + fieldName = unique.fieldName + } + + override fun isValid(value: String?, p1: ConstraintValidatorContext?): Boolean { + return !uniqueValueFieldService.fieldValueExists(value!!, this.fieldName!!) + } + + +} diff --git a/moove/commons/src/main/kotlin/io/charlescd/moove/commons/validator/UniqueValueFieldService.kt b/moove/commons/src/main/kotlin/io/charlescd/moove/commons/validator/UniqueValueFieldService.kt new file mode 100644 index 0000000000..666d756c47 --- /dev/null +++ b/moove/commons/src/main/kotlin/io/charlescd/moove/commons/validator/UniqueValueFieldService.kt @@ -0,0 +1,7 @@ +package io.charlescd.moove.commons.validator + +interface UniqueValueFieldService { + + @Throws(UnsupportedOperationException::class) + fun fieldValueExists(value: String, fieldName: String): Boolean +} diff --git a/moove/domain/src/main/kotlin/io/charlescd/moove/domain/repository/CircleRepository.kt b/moove/domain/src/main/kotlin/io/charlescd/moove/domain/repository/CircleRepository.kt index b79c40ce3b..fcb6723ee0 100644 --- a/moove/domain/src/main/kotlin/io/charlescd/moove/domain/repository/CircleRepository.kt +++ b/moove/domain/src/main/kotlin/io/charlescd/moove/domain/repository/CircleRepository.kt @@ -55,4 +55,6 @@ interface CircleRepository { fun countPercentageByWorkspaceId(workspaceId: String): Int fun findCirclesPercentage(workspaceId: String, name: String?, active: Boolean, pageRequest: PageRequest?): Page + + fun existsByParam(paramName: String, paramValue: String ): Boolean } diff --git a/moove/domain/src/main/kotlin/io/charlescd/moove/domain/repository/WorkspaceRepository.kt b/moove/domain/src/main/kotlin/io/charlescd/moove/domain/repository/WorkspaceRepository.kt index 6c18fb9c85..0596e242b6 100644 --- a/moove/domain/src/main/kotlin/io/charlescd/moove/domain/repository/WorkspaceRepository.kt +++ b/moove/domain/src/main/kotlin/io/charlescd/moove/domain/repository/WorkspaceRepository.kt @@ -33,6 +33,8 @@ interface WorkspaceRepository { fun exists(id: String): Boolean + fun existsByParam(paramName: String, paramValue: String ): Boolean + fun associateUserGroupAndPermissions(workspaceId: String, userGroupId: String, permissions: List) fun disassociateUserGroupAndPermissions(workspaceId: String, userGroupId: String) diff --git a/moove/infrastructure/src/main/kotlin/io/charlescd/moove/infrastructure/repository/JdbcCircleRepository.kt b/moove/infrastructure/src/main/kotlin/io/charlescd/moove/infrastructure/repository/JdbcCircleRepository.kt index af315613cd..19b8d87a26 100644 --- a/moove/infrastructure/src/main/kotlin/io/charlescd/moove/infrastructure/repository/JdbcCircleRepository.kt +++ b/moove/infrastructure/src/main/kotlin/io/charlescd/moove/infrastructure/repository/JdbcCircleRepository.kt @@ -121,6 +121,32 @@ class JdbcCircleRepository( deleteCircleById(id) } + override fun existsByParam(paramName: String, paramValue: String ): Boolean { + return checkIfCircleExistsByParam(paramName, paramValue) + } + + private fun checkIfCircleExistsByParam(paramName: String, paramValue: String ): Boolean { + + val baseCountQuery = """ + SELECT count(*) AS total + FROM circles + WHERE 1 = 1 + """ + val countStatement = StringBuilder(baseCountQuery) + .appendln("AND circles.$paramName= ?") + .toString() + return applyCountQuery( + countStatement, arrayOf(paramValue)) + } + + private fun applyCountQuery(statement: String, params: Array): Boolean { + val count = this.jdbcTemplate.queryForObject( + statement, + params + ) { rs, _ -> rs.getInt(1) } + return count != null && count >= 1 + } + private fun createParametersArray(name: String?, active: Boolean?, workspaceId: String, pageRequest: PageRequest? = null): Array { val parameters = ArrayList() if (active != null && !active) parameters.add(workspaceId) diff --git a/moove/infrastructure/src/main/kotlin/io/charlescd/moove/infrastructure/repository/JdbcWorkspaceRepository.kt b/moove/infrastructure/src/main/kotlin/io/charlescd/moove/infrastructure/repository/JdbcWorkspaceRepository.kt index ccfedd606b..49d012fb7e 100644 --- a/moove/infrastructure/src/main/kotlin/io/charlescd/moove/infrastructure/repository/JdbcWorkspaceRepository.kt +++ b/moove/infrastructure/src/main/kotlin/io/charlescd/moove/infrastructure/repository/JdbcWorkspaceRepository.kt @@ -79,6 +79,12 @@ class JdbcWorkspaceRepository( LEFT JOIN users user_group_member ON user_groups_users.user_id = user_group_member.id WHERE 1 = 1 """ + + const val BASE_COUNT_QUERY_STATEMENT = """ + SELECT count(*) AS total + FROM workspaces + WHERE 1 = 1 + """ } override fun save(workspace: Workspace): Workspace { @@ -103,6 +109,10 @@ class JdbcWorkspaceRepository( return checkIfWorkspaceExists(id) } + override fun existsByParam(paramName: String, paramValue: String ): Boolean { + return checkIfWorkspaceExistsByParam(paramName, paramValue) + } + override fun associateUserGroupAndPermissions(workspaceId: String, userGroupId: String, permissions: List) { createAssociation(workspaceId, userGroupId, permissions) } @@ -212,28 +222,9 @@ class JdbcWorkspaceRepository( } } - private fun executePageQuery( - statement: StringBuilder, - pageRequest: PageRequest - ): Set? { - return this.jdbcTemplate.query( - statement.toString(), - arrayOf(pageRequest.size, pageRequest.offset()), - workspaceExtractor - ) - } - private fun executeCountQuery(name: String?): Int? { - - val statement = StringBuilder( - """ - SELECT COUNT(*) - FROM workspaces w - WHERE 1 = 1 - """ - ) + val statement = StringBuilder(BASE_COUNT_QUERY_STATEMENT) name?.let { statement.appendln("AND w.name ILIKE ?") } - return this.jdbcTemplate.queryForObject( statement.toString(), createParametersArray(name) @@ -243,17 +234,26 @@ class JdbcWorkspaceRepository( } private fun checkIfWorkspaceExists(id: String): Boolean { - val countStatement = """ - SELECT count(*) AS total - FROM workspaces - WHERE workspaces.id = ? - """ + val countStatement = StringBuilder(BASE_COUNT_QUERY_STATEMENT) + .appendln("AND workspaces.id = ?") + .toString() + return applyCountQuery( + countStatement, arrayOf(id)) + } + private fun checkIfWorkspaceExistsByParam(paramName: String, paramValue: String ): Boolean { + val countStatement = StringBuilder(BASE_COUNT_QUERY_STATEMENT) + .appendln("AND workspaces.$paramName= ?") + .toString() + return applyCountQuery( + countStatement, arrayOf(paramValue)) + } + + private fun applyCountQuery(statement: String, params: Array): Boolean { val count = this.jdbcTemplate.queryForObject( - countStatement, - arrayOf(id) + statement, + params ) { rs, _ -> rs.getInt(1) } - return count != null && count >= 1 } From 0e545e14c2c6604bbac5e58b092a1e40622633c0 Mon Sep 17 00:00:00 2001 From: barbararochazup Date: Wed, 12 May 2021 16:47:10 -0300 Subject: [PATCH 2/5] refactor duplicated entities Signed-off-by: barbararochazup --- .../moove/api/MooveExceptionHandler.kt | 2 +- .../moove/application/CircleService.kt | 10 ++++---- .../moove/application/WorkspaceService.kt | 13 +++++------ .../circle/request/CreateCircleRequest.kt | 5 ---- .../request/CreateWorkspaceRequest.kt | 4 ---- .../CharlesCommonsAutoConfiguration.kt | 4 ++-- .../moove/commons/validator/Unique.kt | 16 ------------- .../commons/validator/UniqueValidator.kt | 23 ------------------- .../validator/UniqueValueFieldService.kt | 7 ------ .../charlescd/moove/domain/MooveErrorCode.kt | 4 +++- .../domain/repository/CircleRepository.kt | 2 +- .../domain/repository/WorkspaceRepository.kt | 4 ++-- .../repository/JdbcCircleRepository.kt | 13 ++++------- .../repository/JdbcWorkspaceRepository.kt | 23 ++++++++++--------- .../main/resources/locale/messages.properties | 2 ++ 15 files changed, 38 insertions(+), 94 deletions(-) delete mode 100644 moove/commons/src/main/kotlin/io/charlescd/moove/commons/validator/Unique.kt delete mode 100644 moove/commons/src/main/kotlin/io/charlescd/moove/commons/validator/UniqueValidator.kt delete mode 100644 moove/commons/src/main/kotlin/io/charlescd/moove/commons/validator/UniqueValueFieldService.kt diff --git a/moove/api/src/main/kotlin/io/charlescd/moove/api/MooveExceptionHandler.kt b/moove/api/src/main/kotlin/io/charlescd/moove/api/MooveExceptionHandler.kt index 99519a5929..b697be9f20 100644 --- a/moove/api/src/main/kotlin/io/charlescd/moove/api/MooveExceptionHandler.kt +++ b/moove/api/src/main/kotlin/io/charlescd/moove/api/MooveExceptionHandler.kt @@ -59,7 +59,7 @@ class MooveExceptionHandler(private val messageSource: MessageSource) { @ResponseBody fun exceptions(ex: Exception): ErrorMessageResponse { this.logger.error(ex.message, ex) - return ErrorMessageResponse.of(MooveErrorCode.INTERNAL_SERVER_ERROR, ex.message!!) + return ErrorMessageResponse.of(MooveErrorCode.INTERNAL_SERVER_ERROR, ex.message?.also { ex.message }?: "Internal Server Error") } @ExceptionHandler(BadRequestClientException::class) diff --git a/moove/application/src/main/kotlin/io/charlescd/moove/application/CircleService.kt b/moove/application/src/main/kotlin/io/charlescd/moove/application/CircleService.kt index c82be3df47..cd31295fc3 100644 --- a/moove/application/src/main/kotlin/io/charlescd/moove/application/CircleService.kt +++ b/moove/application/src/main/kotlin/io/charlescd/moove/application/CircleService.kt @@ -18,7 +18,6 @@ package io.charlescd.moove.application -import io.charlescd.moove.commons.validator.UniqueValueFieldService import io.charlescd.moove.domain.* import io.charlescd.moove.domain.exceptions.BusinessException import io.charlescd.moove.domain.exceptions.NotFoundException @@ -27,9 +26,12 @@ import java.util.* import javax.inject.Named @Named -class CircleService(private val circleRepository: CircleRepository):UniqueValueFieldService { +class CircleService(private val circleRepository: CircleRepository) { fun save(circle: Circle): Circle { + if(this.circleRepository.existsByNameAndWorkspaceId(circle.name, circle.workspaceId)) { + throw BusinessException.of(MooveErrorCode.DUPLICATED_CIRCLE_NAME_ERROR) + } return this.circleRepository.save(circle) } @@ -101,8 +103,4 @@ class CircleService(private val circleRepository: CircleRepository):UniqueValueF verifyLimitReached(sumPercentage, circle.percentage!!) } } - - override fun fieldValueExists(value: String, fieldName: String): Boolean { - TODO("Not yet implemented") - } } diff --git a/moove/application/src/main/kotlin/io/charlescd/moove/application/WorkspaceService.kt b/moove/application/src/main/kotlin/io/charlescd/moove/application/WorkspaceService.kt index 29bd5e8b1c..0d76c3a9f3 100644 --- a/moove/application/src/main/kotlin/io/charlescd/moove/application/WorkspaceService.kt +++ b/moove/application/src/main/kotlin/io/charlescd/moove/application/WorkspaceService.kt @@ -18,8 +18,8 @@ package io.charlescd.moove.application -import io.charlescd.moove.commons.validator.UniqueValueFieldService import io.charlescd.moove.domain.* +import io.charlescd.moove.domain.exceptions.BusinessException import io.charlescd.moove.domain.exceptions.NotFoundException import io.charlescd.moove.domain.repository.UserRepository import io.charlescd.moove.domain.repository.WorkspaceRepository @@ -29,7 +29,7 @@ import javax.inject.Named class WorkspaceService( private val workspaceRepository: WorkspaceRepository, private val userRepository: UserRepository -): UniqueValueFieldService { +) { fun find(workspaceId: String): Workspace { return this.workspaceRepository.find(workspaceId) @@ -46,7 +46,10 @@ class WorkspaceService( } } - fun save(workspace: Workspace): Workspace { + fun save( workspace: Workspace): Workspace { + if(this.workspaceRepository.existsByName(workspace.name)) { + throw BusinessException.of(MooveErrorCode.DUPLICATED_WORKSPACE_NAME_ERROR) + } return this.workspaceRepository.save(workspace) } @@ -65,8 +68,4 @@ class WorkspaceService( fun findAllUsers(workspaceId: String, name: String?, email: String?, pageRequest: PageRequest): Page { return this.userRepository.findByWorkspace(workspaceId, name, email, pageRequest) } - - override fun fieldValueExists(value: String, fieldName: String): Boolean { - return this.workspaceRepository.existsByParam(fieldName, value); - } } diff --git a/moove/application/src/main/kotlin/io/charlescd/moove/application/circle/request/CreateCircleRequest.kt b/moove/application/src/main/kotlin/io/charlescd/moove/application/circle/request/CreateCircleRequest.kt index 3cb21abbf3..5f9b3dd0bb 100644 --- a/moove/application/src/main/kotlin/io/charlescd/moove/application/circle/request/CreateCircleRequest.kt +++ b/moove/application/src/main/kotlin/io/charlescd/moove/application/circle/request/CreateCircleRequest.kt @@ -18,10 +18,7 @@ package io.charlescd.moove.application.circle.request -import io.charlescd.moove.application.CircleService -import io.charlescd.moove.application.WorkspaceService import io.charlescd.moove.commons.extension.toJsonNode -import io.charlescd.moove.commons.validator.Unique import io.charlescd.moove.domain.Circle import io.charlescd.moove.domain.MatcherTypeEnum import io.charlescd.moove.domain.User @@ -37,9 +34,7 @@ class CreateCircleRequest( @field:NotBlank @field:Size(min = 1, max = 64, message = "Name minimum size is 1 and maximum is 64.") - @Unique(message = "Circle already registered", fieldName="name", service = CircleService::class) val name: String, - @field:Valid val rules: NodePart diff --git a/moove/application/src/main/kotlin/io/charlescd/moove/application/workspace/request/CreateWorkspaceRequest.kt b/moove/application/src/main/kotlin/io/charlescd/moove/application/workspace/request/CreateWorkspaceRequest.kt index 855cb7dd3d..7eb1f4ceed 100644 --- a/moove/application/src/main/kotlin/io/charlescd/moove/application/workspace/request/CreateWorkspaceRequest.kt +++ b/moove/application/src/main/kotlin/io/charlescd/moove/application/workspace/request/CreateWorkspaceRequest.kt @@ -16,9 +16,6 @@ package io.charlescd.moove.application.workspace.request -import io.charlescd.moove.application.WorkspaceService -import io.charlescd.moove.commons.validator.Unique - import io.charlescd.moove.domain.User import io.charlescd.moove.domain.Workspace import java.time.LocalDateTime @@ -31,7 +28,6 @@ data class CreateWorkspaceRequest( @field:NotNull @field:NotBlank @field:Size(min = 1, max = 64, message = "Name minimum size is 1 and maximum is 64.") - @Unique(message = "Workspace already registered", fieldName="name", service = WorkspaceService::class) val name: String ) { fun toWorkspace(id: String, author: User) = Workspace( diff --git a/moove/commons/src/main/kotlin/io/charlescd/moove/commons/configuration/CharlesCommonsAutoConfiguration.kt b/moove/commons/src/main/kotlin/io/charlescd/moove/commons/configuration/CharlesCommonsAutoConfiguration.kt index 7039cb0fe0..245702b8ca 100644 --- a/moove/commons/src/main/kotlin/io/charlescd/moove/commons/configuration/CharlesCommonsAutoConfiguration.kt +++ b/moove/commons/src/main/kotlin/io/charlescd/moove/commons/configuration/CharlesCommonsAutoConfiguration.kt @@ -16,13 +16,13 @@ package io.charlescd.moove.commons.configuration -import java.time.Clock -import javax.annotation.PostConstruct import org.modelmapper.ModelMapper import org.slf4j.LoggerFactory import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration +import java.time.Clock +import javax.annotation.PostConstruct private val modelMapper = ModelMapper() diff --git a/moove/commons/src/main/kotlin/io/charlescd/moove/commons/validator/Unique.kt b/moove/commons/src/main/kotlin/io/charlescd/moove/commons/validator/Unique.kt deleted file mode 100644 index d9aa9b82d0..0000000000 --- a/moove/commons/src/main/kotlin/io/charlescd/moove/commons/validator/Unique.kt +++ /dev/null @@ -1,16 +0,0 @@ -package io.charlescd.moove.commons.validator - -import javax.validation.Constraint -import javax.validation.Payload -import kotlin.reflect.KClass - -@Target(AnnotationTarget.FIELD) -@MustBeDocumented -@Constraint(validatedBy = [UniqueValidator::class]) -annotation class Unique( - val message: String = "Value already registered", - val groups: Array> = [], - val payload: Array> = [], - val fieldName: String = "", - val service: KClass -) diff --git a/moove/commons/src/main/kotlin/io/charlescd/moove/commons/validator/UniqueValidator.kt b/moove/commons/src/main/kotlin/io/charlescd/moove/commons/validator/UniqueValidator.kt deleted file mode 100644 index e6e10857cc..0000000000 --- a/moove/commons/src/main/kotlin/io/charlescd/moove/commons/validator/UniqueValidator.kt +++ /dev/null @@ -1,23 +0,0 @@ -package io.charlescd.moove.commons.validator - -import org.springframework.beans.factory.annotation.Autowired -import javax.validation.ConstraintValidator -import javax.validation.ConstraintValidatorContext - -class UniqueValidator : ConstraintValidator { - - @Autowired - lateinit var uniqueValueFieldService: UniqueValueFieldService - - private var fieldName: String? = null - - override fun initialize(unique: Unique) { - fieldName = unique.fieldName - } - - override fun isValid(value: String?, p1: ConstraintValidatorContext?): Boolean { - return !uniqueValueFieldService.fieldValueExists(value!!, this.fieldName!!) - } - - -} diff --git a/moove/commons/src/main/kotlin/io/charlescd/moove/commons/validator/UniqueValueFieldService.kt b/moove/commons/src/main/kotlin/io/charlescd/moove/commons/validator/UniqueValueFieldService.kt deleted file mode 100644 index 666d756c47..0000000000 --- a/moove/commons/src/main/kotlin/io/charlescd/moove/commons/validator/UniqueValueFieldService.kt +++ /dev/null @@ -1,7 +0,0 @@ -package io.charlescd.moove.commons.validator - -interface UniqueValueFieldService { - - @Throws(UnsupportedOperationException::class) - fun fieldValueExists(value: String, fieldName: String): Boolean -} diff --git a/moove/domain/src/main/kotlin/io/charlescd/moove/domain/MooveErrorCode.kt b/moove/domain/src/main/kotlin/io/charlescd/moove/domain/MooveErrorCode.kt index 5c108ab792..5733f764ca 100644 --- a/moove/domain/src/main/kotlin/io/charlescd/moove/domain/MooveErrorCode.kt +++ b/moove/domain/src/main/kotlin/io/charlescd/moove/domain/MooveErrorCode.kt @@ -64,5 +64,7 @@ enum class MooveErrorCode(val key: String) { LIMIT_OF_PERCENTAGE_CIRCLES_EXCEEDED("limit.of.percentage.circles.exceeded"), IDM_UNEXPECTED_ERROR("idm.unexpected.error"), DUPLICATED_COMPONENT_NAME_ERROR("duplicated.component.name.error"), - DEPLOYMENT_CONFIGURATION_ALREADY_REGISTERED("deployment.configuration.already.registered") + DEPLOYMENT_CONFIGURATION_ALREADY_REGISTERED("deployment.configuration.already.registered"), + DUPLICATED_WORKSPACE_NAME_ERROR("duplicated.workspace.name.error"), + DUPLICATED_CIRCLE_NAME_ERROR("duplicated.circe.name.error") } diff --git a/moove/domain/src/main/kotlin/io/charlescd/moove/domain/repository/CircleRepository.kt b/moove/domain/src/main/kotlin/io/charlescd/moove/domain/repository/CircleRepository.kt index fcb6723ee0..9c60ae6e51 100644 --- a/moove/domain/src/main/kotlin/io/charlescd/moove/domain/repository/CircleRepository.kt +++ b/moove/domain/src/main/kotlin/io/charlescd/moove/domain/repository/CircleRepository.kt @@ -56,5 +56,5 @@ interface CircleRepository { fun findCirclesPercentage(workspaceId: String, name: String?, active: Boolean, pageRequest: PageRequest?): Page - fun existsByParam(paramName: String, paramValue: String ): Boolean + fun existsByNameAndWorkspaceId(name: String, workspaceId: String): Boolean } diff --git a/moove/domain/src/main/kotlin/io/charlescd/moove/domain/repository/WorkspaceRepository.kt b/moove/domain/src/main/kotlin/io/charlescd/moove/domain/repository/WorkspaceRepository.kt index bad7526a53..cd712a40ec 100644 --- a/moove/domain/src/main/kotlin/io/charlescd/moove/domain/repository/WorkspaceRepository.kt +++ b/moove/domain/src/main/kotlin/io/charlescd/moove/domain/repository/WorkspaceRepository.kt @@ -33,9 +33,9 @@ interface WorkspaceRepository { fun exists(id: String): Boolean - fun existsByParam(paramName: String, paramValue: String ): Boolean - fun associateUserGroupAndPermissions(workspaceId: String, userGroupId: String, permissions: List) fun disassociateUserGroupAndPermissions(workspaceId: String, userGroupId: String) + + fun existsByName(name: String): Boolean } diff --git a/moove/infrastructure/src/main/kotlin/io/charlescd/moove/infrastructure/repository/JdbcCircleRepository.kt b/moove/infrastructure/src/main/kotlin/io/charlescd/moove/infrastructure/repository/JdbcCircleRepository.kt index 19b8d87a26..1cfc7ee7cb 100644 --- a/moove/infrastructure/src/main/kotlin/io/charlescd/moove/infrastructure/repository/JdbcCircleRepository.kt +++ b/moove/infrastructure/src/main/kotlin/io/charlescd/moove/infrastructure/repository/JdbcCircleRepository.kt @@ -20,6 +20,7 @@ package io.charlescd.moove.infrastructure.repository import io.charlescd.moove.domain.* import io.charlescd.moove.domain.repository.CircleRepository + import io.charlescd.moove.infrastructure.repository.mapper.CircleExtractor import io.charlescd.moove.infrastructure.repository.mapper.CircleHistoryExtractor import io.charlescd.moove.infrastructure.repository.mapper.CircleMetricExtractor @@ -121,22 +122,18 @@ class JdbcCircleRepository( deleteCircleById(id) } - override fun existsByParam(paramName: String, paramValue: String ): Boolean { - return checkIfCircleExistsByParam(paramName, paramValue) - } - - private fun checkIfCircleExistsByParam(paramName: String, paramValue: String ): Boolean { - + override fun existsByNameAndWorkspaceId(name: String, workspaceId: String): Boolean { val baseCountQuery = """ SELECT count(*) AS total FROM circles WHERE 1 = 1 """ val countStatement = StringBuilder(baseCountQuery) - .appendln("AND circles.$paramName= ?") + .appendln("AND circles.workspace_id = ?") + .appendln("AND circles.name = ?") .toString() return applyCountQuery( - countStatement, arrayOf(paramValue)) + countStatement, arrayOf(workspaceId, name)) } private fun applyCountQuery(statement: String, params: Array): Boolean { diff --git a/moove/infrastructure/src/main/kotlin/io/charlescd/moove/infrastructure/repository/JdbcWorkspaceRepository.kt b/moove/infrastructure/src/main/kotlin/io/charlescd/moove/infrastructure/repository/JdbcWorkspaceRepository.kt index a85a4accfd..e51e93b889 100644 --- a/moove/infrastructure/src/main/kotlin/io/charlescd/moove/infrastructure/repository/JdbcWorkspaceRepository.kt +++ b/moove/infrastructure/src/main/kotlin/io/charlescd/moove/infrastructure/repository/JdbcWorkspaceRepository.kt @@ -86,6 +86,7 @@ class JdbcWorkspaceRepository( """ } + override fun save(workspace: Workspace): Workspace { createWorkspace(workspace) return find(workspace.id).get() @@ -108,8 +109,12 @@ class JdbcWorkspaceRepository( return checkIfWorkspaceExists(id) } - override fun existsByParam(paramName: String, paramValue: String ): Boolean { - return checkIfWorkspaceExistsByParam(paramName, paramValue) + override fun existsByName(name: String): Boolean { + val countStatement = StringBuilder(BASE_COUNT_QUERY_STATEMENT) + .appendln("AND workspaces.name= ?") + .toString() + return applyCountQuery( + countStatement, arrayOf(name)) } override fun associateUserGroupAndPermissions(workspaceId: String, userGroupId: String, permissions: List) { @@ -206,14 +211,6 @@ class JdbcWorkspaceRepository( countStatement, arrayOf(id)) } - private fun checkIfWorkspaceExistsByParam(paramName: String, paramValue: String ): Boolean { - val countStatement = StringBuilder(BASE_COUNT_QUERY_STATEMENT) - .appendln("AND workspaces.$paramName= ?") - .toString() - return applyCountQuery( - countStatement, arrayOf(paramValue)) - } - private fun applyCountQuery(statement: String, params: Array): Boolean { val count = this.jdbcTemplate.queryForObject( statement, @@ -256,7 +253,9 @@ class JdbcWorkspaceRepository( ) } - private fun createWorkspace(workspace: Workspace) { + + private fun createWorkspace( + workspace: Workspace) { val statement = "INSERT INTO workspaces(" + "id, " + "name, " + @@ -296,4 +295,6 @@ class JdbcWorkspaceRepository( userGroupId ) } + + } diff --git a/moove/web/src/main/resources/locale/messages.properties b/moove/web/src/main/resources/locale/messages.properties index 04b0b59976..7319f6ca2e 100644 --- a/moove/web/src/main/resources/locale/messages.properties +++ b/moove/web/src/main/resources/locale/messages.properties @@ -44,3 +44,5 @@ villager.unexpected.error=An unexpected error occurred. idm.unexpected.error=An unexpected error occurred when trying to reach your identity manager. duplicated.component.name.error=You can not save two components with the same name. deployment.configuration.already.registered=Deployment configuration can not be registered, because it is already configuration on workspace. +duplicated.workspace.name.error=You can not save two workspace with the same name. +duplicated.circle.name.error=You can not save two circle with the same name. From f278a1ffe06d11a0c017cac4e6e749ed5bbf7668 Mon Sep 17 00:00:00 2001 From: barbararochazup Date: Wed, 12 May 2021 17:08:42 -0300 Subject: [PATCH 3/5] fixing lint Signed-off-by: barbararochazup --- .../kotlin/io/charlescd/moove/api/MooveExceptionHandler.kt | 2 +- .../kotlin/io/charlescd/moove/application/CircleService.kt | 2 +- .../io/charlescd/moove/application/WorkspaceService.kt | 4 ++-- .../application/circle/request/CreateCircleRequest.kt | 2 -- .../workspace/request/CreateWorkspaceRequest.kt | 1 - .../configuration/CharlesCommonsAutoConfiguration.kt | 4 ++-- .../infrastructure/repository/JdbcCircleRepository.kt | 1 - .../infrastructure/repository/JdbcWorkspaceRepository.kt | 7 ++----- 8 files changed, 8 insertions(+), 15 deletions(-) diff --git a/moove/api/src/main/kotlin/io/charlescd/moove/api/MooveExceptionHandler.kt b/moove/api/src/main/kotlin/io/charlescd/moove/api/MooveExceptionHandler.kt index b697be9f20..84268adb2d 100644 --- a/moove/api/src/main/kotlin/io/charlescd/moove/api/MooveExceptionHandler.kt +++ b/moove/api/src/main/kotlin/io/charlescd/moove/api/MooveExceptionHandler.kt @@ -59,7 +59,7 @@ class MooveExceptionHandler(private val messageSource: MessageSource) { @ResponseBody fun exceptions(ex: Exception): ErrorMessageResponse { this.logger.error(ex.message, ex) - return ErrorMessageResponse.of(MooveErrorCode.INTERNAL_SERVER_ERROR, ex.message?.also { ex.message }?: "Internal Server Error") + return ErrorMessageResponse.of(MooveErrorCode.INTERNAL_SERVER_ERROR, ex.message?.also { ex.message } ?: "Internal Server Error") } @ExceptionHandler(BadRequestClientException::class) diff --git a/moove/application/src/main/kotlin/io/charlescd/moove/application/CircleService.kt b/moove/application/src/main/kotlin/io/charlescd/moove/application/CircleService.kt index cd31295fc3..afe5f7621d 100644 --- a/moove/application/src/main/kotlin/io/charlescd/moove/application/CircleService.kt +++ b/moove/application/src/main/kotlin/io/charlescd/moove/application/CircleService.kt @@ -29,7 +29,7 @@ import javax.inject.Named class CircleService(private val circleRepository: CircleRepository) { fun save(circle: Circle): Circle { - if(this.circleRepository.existsByNameAndWorkspaceId(circle.name, circle.workspaceId)) { + if (this.circleRepository.existsByNameAndWorkspaceId(circle.name, circle.workspaceId)) { throw BusinessException.of(MooveErrorCode.DUPLICATED_CIRCLE_NAME_ERROR) } return this.circleRepository.save(circle) diff --git a/moove/application/src/main/kotlin/io/charlescd/moove/application/WorkspaceService.kt b/moove/application/src/main/kotlin/io/charlescd/moove/application/WorkspaceService.kt index 0d76c3a9f3..34e8694458 100644 --- a/moove/application/src/main/kotlin/io/charlescd/moove/application/WorkspaceService.kt +++ b/moove/application/src/main/kotlin/io/charlescd/moove/application/WorkspaceService.kt @@ -46,8 +46,8 @@ class WorkspaceService( } } - fun save( workspace: Workspace): Workspace { - if(this.workspaceRepository.existsByName(workspace.name)) { + fun save(workspace: Workspace): Workspace { + if (this.workspaceRepository.existsByName(workspace.name)) { throw BusinessException.of(MooveErrorCode.DUPLICATED_WORKSPACE_NAME_ERROR) } return this.workspaceRepository.save(workspace) diff --git a/moove/application/src/main/kotlin/io/charlescd/moove/application/circle/request/CreateCircleRequest.kt b/moove/application/src/main/kotlin/io/charlescd/moove/application/circle/request/CreateCircleRequest.kt index 5f9b3dd0bb..961fdf28bd 100644 --- a/moove/application/src/main/kotlin/io/charlescd/moove/application/circle/request/CreateCircleRequest.kt +++ b/moove/application/src/main/kotlin/io/charlescd/moove/application/circle/request/CreateCircleRequest.kt @@ -31,13 +31,11 @@ import javax.validation.constraints.NotNull import javax.validation.constraints.Size class CreateCircleRequest( - @field:NotBlank @field:Size(min = 1, max = 64, message = "Name minimum size is 1 and maximum is 64.") val name: String, @field:Valid val rules: NodePart - ) { fun toDomain(user: User, workspaceId: String) = Circle( id = UUID.randomUUID().toString(), diff --git a/moove/application/src/main/kotlin/io/charlescd/moove/application/workspace/request/CreateWorkspaceRequest.kt b/moove/application/src/main/kotlin/io/charlescd/moove/application/workspace/request/CreateWorkspaceRequest.kt index 7eb1f4ceed..4c0dbc29d0 100644 --- a/moove/application/src/main/kotlin/io/charlescd/moove/application/workspace/request/CreateWorkspaceRequest.kt +++ b/moove/application/src/main/kotlin/io/charlescd/moove/application/workspace/request/CreateWorkspaceRequest.kt @@ -24,7 +24,6 @@ import javax.validation.constraints.NotNull import javax.validation.constraints.Size data class CreateWorkspaceRequest( - @field:NotNull @field:NotBlank @field:Size(min = 1, max = 64, message = "Name minimum size is 1 and maximum is 64.") diff --git a/moove/commons/src/main/kotlin/io/charlescd/moove/commons/configuration/CharlesCommonsAutoConfiguration.kt b/moove/commons/src/main/kotlin/io/charlescd/moove/commons/configuration/CharlesCommonsAutoConfiguration.kt index 245702b8ca..7039cb0fe0 100644 --- a/moove/commons/src/main/kotlin/io/charlescd/moove/commons/configuration/CharlesCommonsAutoConfiguration.kt +++ b/moove/commons/src/main/kotlin/io/charlescd/moove/commons/configuration/CharlesCommonsAutoConfiguration.kt @@ -16,13 +16,13 @@ package io.charlescd.moove.commons.configuration +import java.time.Clock +import javax.annotation.PostConstruct import org.modelmapper.ModelMapper import org.slf4j.LoggerFactory import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration -import java.time.Clock -import javax.annotation.PostConstruct private val modelMapper = ModelMapper() diff --git a/moove/infrastructure/src/main/kotlin/io/charlescd/moove/infrastructure/repository/JdbcCircleRepository.kt b/moove/infrastructure/src/main/kotlin/io/charlescd/moove/infrastructure/repository/JdbcCircleRepository.kt index 1cfc7ee7cb..8e63ab1bde 100644 --- a/moove/infrastructure/src/main/kotlin/io/charlescd/moove/infrastructure/repository/JdbcCircleRepository.kt +++ b/moove/infrastructure/src/main/kotlin/io/charlescd/moove/infrastructure/repository/JdbcCircleRepository.kt @@ -20,7 +20,6 @@ package io.charlescd.moove.infrastructure.repository import io.charlescd.moove.domain.* import io.charlescd.moove.domain.repository.CircleRepository - import io.charlescd.moove.infrastructure.repository.mapper.CircleExtractor import io.charlescd.moove.infrastructure.repository.mapper.CircleHistoryExtractor import io.charlescd.moove.infrastructure.repository.mapper.CircleMetricExtractor diff --git a/moove/infrastructure/src/main/kotlin/io/charlescd/moove/infrastructure/repository/JdbcWorkspaceRepository.kt b/moove/infrastructure/src/main/kotlin/io/charlescd/moove/infrastructure/repository/JdbcWorkspaceRepository.kt index f02848d013..bcb0453d2c 100644 --- a/moove/infrastructure/src/main/kotlin/io/charlescd/moove/infrastructure/repository/JdbcWorkspaceRepository.kt +++ b/moove/infrastructure/src/main/kotlin/io/charlescd/moove/infrastructure/repository/JdbcWorkspaceRepository.kt @@ -86,7 +86,6 @@ class JdbcWorkspaceRepository( """ } - override fun save(workspace: Workspace): Workspace { createWorkspace(workspace) return find(workspace.id).get() @@ -254,9 +253,9 @@ class JdbcWorkspaceRepository( ) } - private fun createWorkspace( - workspace: Workspace) { + workspace: Workspace + ) { val statement = "INSERT INTO workspaces(" + "id, " + "name, " + @@ -296,6 +295,4 @@ class JdbcWorkspaceRepository( userGroupId ) } - - } From a01fb123a05d511323be89d6f7698efc6708ed79 Mon Sep 17 00:00:00 2001 From: barbararochazup Date: Thu, 13 May 2021 10:35:46 -0300 Subject: [PATCH 4/5] fix messages and adding tests Signed-off-by: barbararochazup --- .../CreateWorkspaceInteractorImplTest.groovy | 25 ++++++++++++++++++- .../main/resources/locale/messages.properties | 4 +-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/moove/application/src/test/groovy/io/charlescd/moove/application/workspace/impl/CreateWorkspaceInteractorImplTest.groovy b/moove/application/src/test/groovy/io/charlescd/moove/application/workspace/impl/CreateWorkspaceInteractorImplTest.groovy index 0e2f1e8ecc..b84ee36988 100644 --- a/moove/application/src/test/groovy/io/charlescd/moove/application/workspace/impl/CreateWorkspaceInteractorImplTest.groovy +++ b/moove/application/src/test/groovy/io/charlescd/moove/application/workspace/impl/CreateWorkspaceInteractorImplTest.groovy @@ -24,9 +24,10 @@ import io.charlescd.moove.application.WorkspaceService import io.charlescd.moove.application.workspace.CreateWorkspaceInteractor import io.charlescd.moove.application.workspace.request.CreateWorkspaceRequest import io.charlescd.moove.domain.Circle -import io.charlescd.moove.domain.User +import io.charlescd.moove.domain.MooveErrorCode import io.charlescd.moove.domain.Workspace import io.charlescd.moove.domain.WorkspaceStatusEnum +import io.charlescd.moove.domain.exceptions.BusinessException import io.charlescd.moove.domain.exceptions.NotFoundException import io.charlescd.moove.domain.repository.CircleRepository import io.charlescd.moove.domain.repository.SystemTokenRepository @@ -72,6 +73,27 @@ class CreateWorkspaceInteractorImplTest extends Specification { ex.resourceName == "user" } + def 'when workspace name exist, should throw exception'() { + given: + def authorization = TestUtils.authorization + def author = TestUtils.user + def expectedWorkspace = TestUtils.workspace + def createWorkspaceRequest = new CreateWorkspaceRequest(expectedWorkspace.name) + + when: + createWorkspaceInteractor.execute(createWorkspaceRequest, authorization, null) + + then: + 1 * managementUserSecurityService.getUserEmail(authorization) >> author.email + 1 * userRepository.findByEmail(author.email) >> Optional.of(author) + 1 * workspaceRepository.existsByName(expectedWorkspace.name) >> true + + + def ex = thrown(BusinessException) + ex.errorCode == MooveErrorCode.DUPLICATED_WORKSPACE_NAME_ERROR + + } + def 'should create workspace successfully using authorization'() { given: def authorization = TestUtils.authorization @@ -84,6 +106,7 @@ class CreateWorkspaceInteractorImplTest extends Specification { then: 1 * managementUserSecurityService.getUserEmail(authorization) >> author.email 1 * userRepository.findByEmail(author.email) >> Optional.of(author) + 1 * workspaceRepository.existsByName(expectedWorkspace.name) >> false 1 * workspaceRepository.save(_) >> { arguments -> def workspace = arguments[0] assert workspace instanceof Workspace diff --git a/moove/web/src/main/resources/locale/messages.properties b/moove/web/src/main/resources/locale/messages.properties index 31491c549c..ec9e894560 100644 --- a/moove/web/src/main/resources/locale/messages.properties +++ b/moove/web/src/main/resources/locale/messages.properties @@ -44,5 +44,5 @@ villager.unexpected.error=An unexpected error occurred. idm.unexpected.error=An unexpected error occurred when trying to reach your identity manager. duplicated.component.name.error=You can not save two components with the same name. deployment.configuration.already.registered=Deployment configuration can not be registered, because it is already configuration on workspace. -duplicated.workspace.name.error=You can not save two workspace with the same name. -duplicated.circle.name.error=You can not save two circle with the same name. +duplicated.workspace.name.error=You can not save two workspaces with the same name. +duplicated.circle.name.error=You can not save two circles with the same name. From 34d7a19120feef7ac4ffefdecc1b749fb89cfa5a Mon Sep 17 00:00:00 2001 From: barbararochazup Date: Thu, 13 May 2021 17:24:08 -0300 Subject: [PATCH 5/5] add pt-br message Signed-off-by: barbararochazup --- moove/web/src/main/resources/locale/messages_pt_BR.properties | 2 ++ 1 file changed, 2 insertions(+) diff --git a/moove/web/src/main/resources/locale/messages_pt_BR.properties b/moove/web/src/main/resources/locale/messages_pt_BR.properties index ee47162769..08cc442726 100644 --- a/moove/web/src/main/resources/locale/messages_pt_BR.properties +++ b/moove/web/src/main/resources/locale/messages_pt_BR.properties @@ -41,3 +41,5 @@ villager.registry.integration.error=Conexão com o Villager falhou. Não é poss villager.unexpected.error=Um erro inesperado ocorreu. idm.unexpected.error=Um erro inesperado ocorreu ao tentar acessar o seu identity manager. duplicated.component.name.error=Não é possível salvar dois componentes com o mesmo nome. +duplicated.workspace.name.error=Não é possível salvar dois workspaces com o mesmo nome. +duplicated.circle.name.error=Não é possível salvar dois círculos com o mesmo nome.