From fdd4742b2874274d6158b042fd64d89fb4ded898 Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Sat, 6 Feb 2021 00:23:36 +0100 Subject: [PATCH] Remove converter for Citizen Add receiveOrBadRequest --- src/main/kotlin/application/Converters.kt | 8 ------ .../citizen/routes/ChangeMyPassword.kt | 27 +++++++++---------- .../component/citizen/routes/GetOneCitizen.kt | 13 ++++++--- .../component/citizen/routes/install.kt | 2 +- .../routes/GetCitizenArticleComments.kt | 6 ++++- .../routes/GetCitizenCommentConstitution.kt | 6 ++++- .../routes/article/GetMyFollowsArticle.kt | 6 ++++- .../component/opinion/OpinionRepository.kt | 3 ++- .../opinion/routes/GetCitizenOpinions.kt | 4 ++- .../component/vote/VoteRepositoryAbs.kt | 5 ++-- .../component/vote/routes/GetCitizenVotes.kt | 4 ++- .../vote/routes/GetCitizenVotesOnArticle.kt | 8 ++++-- src/main/kotlin/utils/Request.kt | 25 +++++++++++++++++ 13 files changed, 80 insertions(+), 37 deletions(-) create mode 100644 src/main/kotlin/utils/Request.kt diff --git a/src/main/kotlin/application/Converters.kt b/src/main/kotlin/application/Converters.kt index 2717741..71f5fd7 100644 --- a/src/main/kotlin/application/Converters.kt +++ b/src/main/kotlin/application/Converters.kt @@ -44,14 +44,6 @@ val converters: ConverterDeclaration = { // TODO remove converters of entities - convert { - decode { values, _ -> - val id = values.singleOrNull()?.let { UUID.fromString(it) } - ?: throw InternalError("Cannot convert $values to UUID") - get().findById(id) ?: throw NotFoundException("Citizen $values not found") - } - } - convert { decode { values, _ -> val id = values.singleOrNull()?.let { UUID.fromString(it) } diff --git a/src/main/kotlin/component/citizen/routes/ChangeMyPassword.kt b/src/main/kotlin/component/citizen/routes/ChangeMyPassword.kt index 249596a..fbbff6c 100644 --- a/src/main/kotlin/component/citizen/routes/ChangeMyPassword.kt +++ b/src/main/kotlin/component/citizen/routes/ChangeMyPassword.kt @@ -6,42 +6,39 @@ import fr.dcproject.component.auth.citizen import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.citizen.Citizen import fr.dcproject.component.citizen.CitizenAccessControl +import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.security.assert +import fr.dcproject.utils.receiveOrBadRequest import io.ktor.application.call import io.ktor.auth.UserPasswordCredential +import io.ktor.features.BadRequestException import io.ktor.http.HttpStatusCode import io.ktor.locations.KtorExperimentalLocationsAPI import io.ktor.locations.Location import io.ktor.locations.put import io.ktor.request.receive +import io.ktor.request.receiveOrNull import io.ktor.response.respond import io.ktor.routing.Route +import java.util.UUID @KtorExperimentalLocationsAPI object ChangeMyPassword { @Location("/citizens/{citizen}/password/change") - class ChangePasswordCitizenRequest(val citizen: Citizen) { + class ChangePasswordCitizenRequest(citizen: UUID) { + val citizen = CitizenRef(citizen) data class Input(val oldPassword: String, val newPassword: String) } fun Route.changeMyPassword(ac: CitizenAccessControl, userRepository: UserRepository) { put { ac.assert { canChangePassword(it.citizen, citizenOrNull) } - try { - val content = call.receive() - val currentUser = userRepository.findByCredentials(UserPasswordCredential(citizen.user.username, content.oldPassword)) - val user = it.citizen.user - if (currentUser == null || currentUser.id != user.id) { - call.respond(HttpStatusCode.BadRequest, "Bad password") - } else { - user.plainPassword = content.newPassword - userRepository.changePassword(user) + val content = call.receiveOrBadRequest() + userRepository.findByCredentials(UserPasswordCredential(citizen.user.username, content.oldPassword)) ?: throw BadRequestException("Bad Password") + citizen.user.plainPassword = content.newPassword + userRepository.changePassword(citizen.user) - call.respond(HttpStatusCode.Created) - } - } catch (e: MissingKotlinParameterException) { - call.respond(HttpStatusCode.BadRequest, "Request format is not correct") - } + call.respond(HttpStatusCode.Created) } } } diff --git a/src/main/kotlin/component/citizen/routes/GetOneCitizen.kt b/src/main/kotlin/component/citizen/routes/GetOneCitizen.kt index 3a92903..32f8b35 100644 --- a/src/main/kotlin/component/citizen/routes/GetOneCitizen.kt +++ b/src/main/kotlin/component/citizen/routes/GetOneCitizen.kt @@ -3,22 +3,29 @@ package fr.dcproject.component.citizen.routes import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.citizen.Citizen import fr.dcproject.component.citizen.CitizenAccessControl +import fr.dcproject.component.citizen.CitizenRef +import fr.dcproject.component.citizen.CitizenRepository import fr.dcproject.security.assert import io.ktor.application.call +import io.ktor.features.NotFoundException import io.ktor.locations.KtorExperimentalLocationsAPI import io.ktor.locations.Location import io.ktor.locations.get import io.ktor.response.respond import io.ktor.routing.Route +import java.util.UUID @KtorExperimentalLocationsAPI object GetOneCitizen { @Location("/citizens/{citizen}") - class CitizenRequest(val citizen: Citizen) + class CitizenRequest(citizen: UUID) { + val citizen = CitizenRef(citizen) + } - fun Route.getOneCitizen(ac: CitizenAccessControl) { + fun Route.getOneCitizen(ac: CitizenAccessControl, citizenRepository: CitizenRepository) { get { - ac.assert { canView(it.citizen, citizenOrNull) } + val citizen = citizenRepository.findById(it.citizen.id) ?: throw NotFoundException("Citizen not found ${it.citizen.id}") + ac.assert { canView(citizen, citizenOrNull) } call.respond(it.citizen) } diff --git a/src/main/kotlin/component/citizen/routes/install.kt b/src/main/kotlin/component/citizen/routes/install.kt index 1b1d00b..c639b2e 100644 --- a/src/main/kotlin/component/citizen/routes/install.kt +++ b/src/main/kotlin/component/citizen/routes/install.kt @@ -13,7 +13,7 @@ import org.koin.ktor.ext.get fun Routing.installCitizenRoutes() { authenticate(optional = true) { findCitizen(get(), get()) - getOneCitizen(get()) + getOneCitizen(get(), get()) getCurrentCitizen(get()) changeMyPassword(get(), get()) } diff --git a/src/main/kotlin/component/comment/article/routes/GetCitizenArticleComments.kt b/src/main/kotlin/component/comment/article/routes/GetCitizenArticleComments.kt index 8536e1d..da1c213 100644 --- a/src/main/kotlin/component/comment/article/routes/GetCitizenArticleComments.kt +++ b/src/main/kotlin/component/comment/article/routes/GetCitizenArticleComments.kt @@ -2,6 +2,7 @@ package fr.dcproject.component.comment.article.routes import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.citizen.Citizen +import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.component.comment.article.CommentArticleRepository import fr.dcproject.component.comment.generic.CommentAccessControl import fr.dcproject.security.assert @@ -11,11 +12,14 @@ import io.ktor.locations.Location import io.ktor.locations.get import io.ktor.response.respond import io.ktor.routing.Route +import java.util.UUID @KtorExperimentalLocationsAPI object GetCitizenArticleComments { @Location("/citizens/{citizen}/comments/articles") - class CitizenCommentArticleRequest(val citizen: Citizen) + class CitizenCommentArticleRequest(citizen: UUID) { + val citizen = CitizenRef(citizen) + } fun Route.getCitizenArticleComments(repo: CommentArticleRepository, ac: CommentAccessControl) { get { diff --git a/src/main/kotlin/component/comment/constitution/routes/GetCitizenCommentConstitution.kt b/src/main/kotlin/component/comment/constitution/routes/GetCitizenCommentConstitution.kt index afd1cd1..1bb0f75 100644 --- a/src/main/kotlin/component/comment/constitution/routes/GetCitizenCommentConstitution.kt +++ b/src/main/kotlin/component/comment/constitution/routes/GetCitizenCommentConstitution.kt @@ -2,6 +2,7 @@ package fr.dcproject.component.comment.constitution.routes import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.citizen.Citizen +import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.component.comment.constitution.CommentConstitutionRepository import fr.dcproject.component.comment.generic.CommentAccessControl import fr.dcproject.security.assert @@ -11,11 +12,14 @@ import io.ktor.locations.Location import io.ktor.locations.get import io.ktor.response.respond import io.ktor.routing.Route +import java.util.UUID @KtorExperimentalLocationsAPI object GetCitizenCommentConstitution { @Location("/citizens/{citizen}/comments/constitutions") - class GetCitizenCommentConstitutionRequest(val citizen: Citizen) + class GetCitizenCommentConstitutionRequest(citizen: UUID) { + val citizen = CitizenRef(citizen) + } fun Route.getCitizenCommentConstitution(repo: CommentConstitutionRepository, ac: CommentAccessControl) { get { diff --git a/src/main/kotlin/component/follow/routes/article/GetMyFollowsArticle.kt b/src/main/kotlin/component/follow/routes/article/GetMyFollowsArticle.kt index 6aaa267..201a242 100644 --- a/src/main/kotlin/component/follow/routes/article/GetMyFollowsArticle.kt +++ b/src/main/kotlin/component/follow/routes/article/GetMyFollowsArticle.kt @@ -2,6 +2,7 @@ package fr.dcproject.component.follow.routes.article import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.citizen.Citizen +import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.component.follow.FollowAccessControl import fr.dcproject.component.follow.FollowArticleRepository import fr.dcproject.security.assert @@ -11,11 +12,14 @@ import io.ktor.locations.Location import io.ktor.locations.get import io.ktor.response.respond import io.ktor.routing.Route +import java.util.UUID @KtorExperimentalLocationsAPI object GetMyFollowsArticle { @Location("/citizens/{citizen}/follows/articles") - class CitizenFollowArticleRequest(val citizen: Citizen) + class CitizenFollowArticleRequest(citizen: UUID) { + val citizen = CitizenRef(citizen) + } fun Route.getMyFollowsArticle(repo: FollowArticleRepository, ac: FollowAccessControl) { get { diff --git a/src/main/kotlin/component/opinion/OpinionRepository.kt b/src/main/kotlin/component/opinion/OpinionRepository.kt index 5f1ea11..6fa1cc3 100644 --- a/src/main/kotlin/component/opinion/OpinionRepository.kt +++ b/src/main/kotlin/component/opinion/OpinionRepository.kt @@ -3,6 +3,7 @@ package fr.dcproject.component.opinion import com.fasterxml.jackson.core.type.TypeReference import fr.dcproject.common.entity.TargetRef import fr.dcproject.component.article.ArticleRef +import fr.dcproject.component.citizen.CitizenI import fr.dcproject.component.opinion.entity.OpinionForUpdate import fr.postgresjson.connexion.Paginated import fr.postgresjson.connexion.Requester @@ -75,7 +76,7 @@ abstract class OpinionRepository(requester: Requester) : OpinionC * Find opinions of one citizen filtered by target ids */ fun findCitizenOpinionsByTargets( - citizen: CitizenEntity, + citizen: CitizenI, targets: List ): List> { val typeReference = object : TypeReference>>() {} diff --git a/src/main/kotlin/component/opinion/routes/GetCitizenOpinions.kt b/src/main/kotlin/component/opinion/routes/GetCitizenOpinions.kt index 65449c6..bc06c88 100644 --- a/src/main/kotlin/component/opinion/routes/GetCitizenOpinions.kt +++ b/src/main/kotlin/component/opinion/routes/GetCitizenOpinions.kt @@ -2,6 +2,7 @@ package fr.dcproject.component.opinion.routes import fr.dcproject.component.article.ArticleRef import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.component.opinion.OpinionAccessControl import fr.dcproject.component.opinion.entity.Opinion import fr.dcproject.security.assert @@ -23,7 +24,8 @@ object GetCitizenOpinions { * Get all Opinion of citizen on targets by target ids */ @Location("/citizens/{citizen}/opinions") - class CitizenOpinions(val citizen: CitizenEntity, id: List) : KoinComponent { + class CitizenOpinions(citizen: UUID, id: List) { + val citizen = CitizenRef(citizen) val id: List = id.toUUID() } diff --git a/src/main/kotlin/component/vote/VoteRepositoryAbs.kt b/src/main/kotlin/component/vote/VoteRepositoryAbs.kt index 584a7ed..cdc33fb 100644 --- a/src/main/kotlin/component/vote/VoteRepositoryAbs.kt +++ b/src/main/kotlin/component/vote/VoteRepositoryAbs.kt @@ -4,6 +4,7 @@ import com.fasterxml.jackson.core.type.TypeReference import fr.dcproject.common.entity.TargetI import fr.dcproject.common.entity.TargetRef import fr.dcproject.component.article.ArticleForView +import fr.dcproject.component.citizen.CitizenI import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.component.comment.generic.CommentForView import fr.dcproject.component.constitution.Constitution @@ -52,7 +53,7 @@ abstract class VoteRepositoryAbs(override var requester: Requester) } fun findCitizenVotesByTargets( - citizen: CitizenEntity, + citizen: CitizenI, targets: List ): List> { val typeReference = object : TypeReference>>() {} @@ -73,7 +74,7 @@ class VoteRepository(requester: Requester) : VoteRepositoryAbs(reques class VoteArticleRepository(requester: Requester) : VoteRepositoryAbs(requester) { fun findByCitizen( - citizen: CitizenEntity, + citizen: CitizenI, page: Int = 1, limit: Int = 50 ): Paginated> = diff --git a/src/main/kotlin/component/vote/routes/GetCitizenVotes.kt b/src/main/kotlin/component/vote/routes/GetCitizenVotes.kt index e044dcf..d2cb3ae 100644 --- a/src/main/kotlin/component/vote/routes/GetCitizenVotes.kt +++ b/src/main/kotlin/component/vote/routes/GetCitizenVotes.kt @@ -2,6 +2,7 @@ package fr.dcproject.component.vote.routes import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.citizen.Citizen +import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.component.vote.VoteAccessControl import fr.dcproject.component.vote.VoteRepository import fr.dcproject.security.assert @@ -17,7 +18,8 @@ import java.util.UUID @KtorExperimentalLocationsAPI object GetCitizenVotes { @Location("/citizens/{citizen}/votes") - class CitizenVotesRequest(val citizen: Citizen, id: List) { + class CitizenVotesRequest(citizen: UUID, id: List) { + val citizen = CitizenRef(citizen) val id: List = id.toUUID() } diff --git a/src/main/kotlin/component/vote/routes/GetCitizenVotesOnArticle.kt b/src/main/kotlin/component/vote/routes/GetCitizenVotesOnArticle.kt index 5661f7c..96488d2 100644 --- a/src/main/kotlin/component/vote/routes/GetCitizenVotesOnArticle.kt +++ b/src/main/kotlin/component/vote/routes/GetCitizenVotesOnArticle.kt @@ -2,6 +2,7 @@ package fr.dcproject.component.vote.routes import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.citizen.Citizen +import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.component.vote.VoteAccessControl import fr.dcproject.component.vote.VoteArticleRepository import fr.dcproject.routes.PaginatedRequest @@ -13,16 +14,19 @@ import io.ktor.locations.Location import io.ktor.locations.get import io.ktor.response.respond import io.ktor.routing.Route +import java.util.UUID @KtorExperimentalLocationsAPI object GetCitizenVotesOnArticle { @Location("/citizens/{citizen}/votes/articles") class CitizenVoteArticleRequest( - val citizen: Citizen, + citizen: UUID, page: Int = 1, limit: Int = 50, val search: String? = null - ) : PaginatedRequestI by PaginatedRequest(page, limit) + ) : PaginatedRequestI by PaginatedRequest(page, limit) { + val citizen = CitizenRef(citizen) + } fun Route.getCitizenVotesOnArticle(repo: VoteArticleRepository, ac: VoteAccessControl) { get { diff --git a/src/main/kotlin/utils/Request.kt b/src/main/kotlin/utils/Request.kt new file mode 100644 index 0000000..06d01a3 --- /dev/null +++ b/src/main/kotlin/utils/Request.kt @@ -0,0 +1,25 @@ +package fr.dcproject.utils + +import com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException +import io.ktor.application.ApplicationCall +import io.ktor.application.log +import io.ktor.features.BadRequestException +import io.ktor.request.receive +import kotlin.reflect.KType +import kotlin.reflect.typeOf + + +/** + * Receives content for this request. + * @param type instance of `KClass` specifying type to be received. + * @return instance of [T] received from this call, or `null` if content cannot be transformed to the requested type.. + */ +@OptIn(ExperimentalStdlibApi::class) +public suspend inline fun ApplicationCall.receiveOrBadRequest(message: String = "Bad Request, wrong body request"): T { + return try { + receive(typeOf()) + } catch (cause: MissingKotlinParameterException) { + application.log.debug("Conversion failed, throw bad exeption", cause) + throw BadRequestException(message, cause) + } +} \ No newline at end of file