Remove converter for Citizen

Add receiveOrBadRequest
This commit is contained in:
2021-02-06 00:23:36 +01:00
parent 0bbe37c6d5
commit fdd4742b28
13 changed files with 80 additions and 37 deletions

View File

@@ -44,14 +44,6 @@ val converters: ConverterDeclaration = {
// TODO remove converters of entities // TODO remove converters of entities
convert<Citizen> {
decode { values, _ ->
val id = values.singleOrNull()?.let { UUID.fromString(it) }
?: throw InternalError("Cannot convert $values to UUID")
get<CitizenRepository>().findById(id) ?: throw NotFoundException("Citizen $values not found")
}
}
convert<OpinionChoice> { convert<OpinionChoice> {
decode { values, _ -> decode { values, _ ->
val id = values.singleOrNull()?.let { UUID.fromString(it) } val id = values.singleOrNull()?.let { UUID.fromString(it) }

View File

@@ -6,42 +6,39 @@ import fr.dcproject.component.auth.citizen
import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.auth.citizenOrNull
import fr.dcproject.component.citizen.Citizen import fr.dcproject.component.citizen.Citizen
import fr.dcproject.component.citizen.CitizenAccessControl import fr.dcproject.component.citizen.CitizenAccessControl
import fr.dcproject.component.citizen.CitizenRef
import fr.dcproject.security.assert import fr.dcproject.security.assert
import fr.dcproject.utils.receiveOrBadRequest
import io.ktor.application.call import io.ktor.application.call
import io.ktor.auth.UserPasswordCredential import io.ktor.auth.UserPasswordCredential
import io.ktor.features.BadRequestException
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.locations.KtorExperimentalLocationsAPI import io.ktor.locations.KtorExperimentalLocationsAPI
import io.ktor.locations.Location import io.ktor.locations.Location
import io.ktor.locations.put import io.ktor.locations.put
import io.ktor.request.receive import io.ktor.request.receive
import io.ktor.request.receiveOrNull
import io.ktor.response.respond import io.ktor.response.respond
import io.ktor.routing.Route import io.ktor.routing.Route
import java.util.UUID
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object ChangeMyPassword { object ChangeMyPassword {
@Location("/citizens/{citizen}/password/change") @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) data class Input(val oldPassword: String, val newPassword: String)
} }
fun Route.changeMyPassword(ac: CitizenAccessControl, userRepository: UserRepository) { fun Route.changeMyPassword(ac: CitizenAccessControl, userRepository: UserRepository) {
put<ChangePasswordCitizenRequest> { put<ChangePasswordCitizenRequest> {
ac.assert { canChangePassword(it.citizen, citizenOrNull) } ac.assert { canChangePassword(it.citizen, citizenOrNull) }
try { val content = call.receiveOrBadRequest<ChangePasswordCitizenRequest.Input>()
val content = call.receive<ChangePasswordCitizenRequest.Input>() userRepository.findByCredentials(UserPasswordCredential(citizen.user.username, content.oldPassword)) ?: throw BadRequestException("Bad Password")
val currentUser = userRepository.findByCredentials(UserPasswordCredential(citizen.user.username, content.oldPassword)) citizen.user.plainPassword = content.newPassword
val user = it.citizen.user userRepository.changePassword(citizen.user)
if (currentUser == null || currentUser.id != user.id) {
call.respond(HttpStatusCode.BadRequest, "Bad password")
} else {
user.plainPassword = content.newPassword
userRepository.changePassword(user)
call.respond(HttpStatusCode.Created) call.respond(HttpStatusCode.Created)
}
} catch (e: MissingKotlinParameterException) {
call.respond(HttpStatusCode.BadRequest, "Request format is not correct")
}
} }
} }
} }

View File

@@ -3,22 +3,29 @@ package fr.dcproject.component.citizen.routes
import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.auth.citizenOrNull
import fr.dcproject.component.citizen.Citizen import fr.dcproject.component.citizen.Citizen
import fr.dcproject.component.citizen.CitizenAccessControl import fr.dcproject.component.citizen.CitizenAccessControl
import fr.dcproject.component.citizen.CitizenRef
import fr.dcproject.component.citizen.CitizenRepository
import fr.dcproject.security.assert import fr.dcproject.security.assert
import io.ktor.application.call import io.ktor.application.call
import io.ktor.features.NotFoundException
import io.ktor.locations.KtorExperimentalLocationsAPI import io.ktor.locations.KtorExperimentalLocationsAPI
import io.ktor.locations.Location import io.ktor.locations.Location
import io.ktor.locations.get import io.ktor.locations.get
import io.ktor.response.respond import io.ktor.response.respond
import io.ktor.routing.Route import io.ktor.routing.Route
import java.util.UUID
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object GetOneCitizen { object GetOneCitizen {
@Location("/citizens/{citizen}") @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<CitizenRequest> { get<CitizenRequest> {
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) call.respond(it.citizen)
} }

View File

@@ -13,7 +13,7 @@ import org.koin.ktor.ext.get
fun Routing.installCitizenRoutes() { fun Routing.installCitizenRoutes() {
authenticate(optional = true) { authenticate(optional = true) {
findCitizen(get(), get()) findCitizen(get(), get())
getOneCitizen(get()) getOneCitizen(get(), get())
getCurrentCitizen(get()) getCurrentCitizen(get())
changeMyPassword(get(), get()) changeMyPassword(get(), get())
} }

View File

@@ -2,6 +2,7 @@ package fr.dcproject.component.comment.article.routes
import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.auth.citizenOrNull
import fr.dcproject.component.citizen.Citizen import fr.dcproject.component.citizen.Citizen
import fr.dcproject.component.citizen.CitizenRef
import fr.dcproject.component.comment.article.CommentArticleRepository import fr.dcproject.component.comment.article.CommentArticleRepository
import fr.dcproject.component.comment.generic.CommentAccessControl import fr.dcproject.component.comment.generic.CommentAccessControl
import fr.dcproject.security.assert import fr.dcproject.security.assert
@@ -11,11 +12,14 @@ import io.ktor.locations.Location
import io.ktor.locations.get import io.ktor.locations.get
import io.ktor.response.respond import io.ktor.response.respond
import io.ktor.routing.Route import io.ktor.routing.Route
import java.util.UUID
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object GetCitizenArticleComments { object GetCitizenArticleComments {
@Location("/citizens/{citizen}/comments/articles") @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) { fun Route.getCitizenArticleComments(repo: CommentArticleRepository, ac: CommentAccessControl) {
get<CitizenCommentArticleRequest> { get<CitizenCommentArticleRequest> {

View File

@@ -2,6 +2,7 @@ package fr.dcproject.component.comment.constitution.routes
import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.auth.citizenOrNull
import fr.dcproject.component.citizen.Citizen import fr.dcproject.component.citizen.Citizen
import fr.dcproject.component.citizen.CitizenRef
import fr.dcproject.component.comment.constitution.CommentConstitutionRepository import fr.dcproject.component.comment.constitution.CommentConstitutionRepository
import fr.dcproject.component.comment.generic.CommentAccessControl import fr.dcproject.component.comment.generic.CommentAccessControl
import fr.dcproject.security.assert import fr.dcproject.security.assert
@@ -11,11 +12,14 @@ import io.ktor.locations.Location
import io.ktor.locations.get import io.ktor.locations.get
import io.ktor.response.respond import io.ktor.response.respond
import io.ktor.routing.Route import io.ktor.routing.Route
import java.util.UUID
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object GetCitizenCommentConstitution { object GetCitizenCommentConstitution {
@Location("/citizens/{citizen}/comments/constitutions") @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) { fun Route.getCitizenCommentConstitution(repo: CommentConstitutionRepository, ac: CommentAccessControl) {
get<GetCitizenCommentConstitutionRequest> { get<GetCitizenCommentConstitutionRequest> {

View File

@@ -2,6 +2,7 @@ package fr.dcproject.component.follow.routes.article
import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.auth.citizenOrNull
import fr.dcproject.component.citizen.Citizen import fr.dcproject.component.citizen.Citizen
import fr.dcproject.component.citizen.CitizenRef
import fr.dcproject.component.follow.FollowAccessControl import fr.dcproject.component.follow.FollowAccessControl
import fr.dcproject.component.follow.FollowArticleRepository import fr.dcproject.component.follow.FollowArticleRepository
import fr.dcproject.security.assert import fr.dcproject.security.assert
@@ -11,11 +12,14 @@ import io.ktor.locations.Location
import io.ktor.locations.get import io.ktor.locations.get
import io.ktor.response.respond import io.ktor.response.respond
import io.ktor.routing.Route import io.ktor.routing.Route
import java.util.UUID
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object GetMyFollowsArticle { object GetMyFollowsArticle {
@Location("/citizens/{citizen}/follows/articles") @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) { fun Route.getMyFollowsArticle(repo: FollowArticleRepository, ac: FollowAccessControl) {
get<CitizenFollowArticleRequest> { get<CitizenFollowArticleRequest> {

View File

@@ -3,6 +3,7 @@ package fr.dcproject.component.opinion
import com.fasterxml.jackson.core.type.TypeReference import com.fasterxml.jackson.core.type.TypeReference
import fr.dcproject.common.entity.TargetRef import fr.dcproject.common.entity.TargetRef
import fr.dcproject.component.article.ArticleRef import fr.dcproject.component.article.ArticleRef
import fr.dcproject.component.citizen.CitizenI
import fr.dcproject.component.opinion.entity.OpinionForUpdate import fr.dcproject.component.opinion.entity.OpinionForUpdate
import fr.postgresjson.connexion.Paginated import fr.postgresjson.connexion.Paginated
import fr.postgresjson.connexion.Requester import fr.postgresjson.connexion.Requester
@@ -75,7 +76,7 @@ abstract class OpinionRepository<T : TargetRef>(requester: Requester) : OpinionC
* Find opinions of one citizen filtered by target ids * Find opinions of one citizen filtered by target ids
*/ */
fun findCitizenOpinionsByTargets( fun findCitizenOpinionsByTargets(
citizen: CitizenEntity, citizen: CitizenI,
targets: List<UUID> targets: List<UUID>
): List<OpinionEntity<T>> { ): List<OpinionEntity<T>> {
val typeReference = object : TypeReference<List<OpinionEntity<T>>>() {} val typeReference = object : TypeReference<List<OpinionEntity<T>>>() {}

View File

@@ -2,6 +2,7 @@ package fr.dcproject.component.opinion.routes
import fr.dcproject.component.article.ArticleRef import fr.dcproject.component.article.ArticleRef
import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.auth.citizenOrNull
import fr.dcproject.component.citizen.CitizenRef
import fr.dcproject.component.opinion.OpinionAccessControl import fr.dcproject.component.opinion.OpinionAccessControl
import fr.dcproject.component.opinion.entity.Opinion import fr.dcproject.component.opinion.entity.Opinion
import fr.dcproject.security.assert import fr.dcproject.security.assert
@@ -23,7 +24,8 @@ object GetCitizenOpinions {
* Get all Opinion of citizen on targets by target ids * Get all Opinion of citizen on targets by target ids
*/ */
@Location("/citizens/{citizen}/opinions") @Location("/citizens/{citizen}/opinions")
class CitizenOpinions(val citizen: CitizenEntity, id: List<String>) : KoinComponent { class CitizenOpinions(citizen: UUID, id: List<String>) {
val citizen = CitizenRef(citizen)
val id: List<UUID> = id.toUUID() val id: List<UUID> = id.toUUID()
} }

View File

@@ -4,6 +4,7 @@ import com.fasterxml.jackson.core.type.TypeReference
import fr.dcproject.common.entity.TargetI import fr.dcproject.common.entity.TargetI
import fr.dcproject.common.entity.TargetRef import fr.dcproject.common.entity.TargetRef
import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.article.ArticleForView
import fr.dcproject.component.citizen.CitizenI
import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.component.citizen.CitizenRef
import fr.dcproject.component.comment.generic.CommentForView import fr.dcproject.component.comment.generic.CommentForView
import fr.dcproject.component.constitution.Constitution import fr.dcproject.component.constitution.Constitution
@@ -52,7 +53,7 @@ abstract class VoteRepositoryAbs<T : TargetI>(override var requester: Requester)
} }
fun findCitizenVotesByTargets( fun findCitizenVotesByTargets(
citizen: CitizenEntity, citizen: CitizenI,
targets: List<UUID> targets: List<UUID>
): List<VoteEntity<*>> { ): List<VoteEntity<*>> {
val typeReference = object : TypeReference<List<VoteEntity<TargetRef>>>() {} val typeReference = object : TypeReference<List<VoteEntity<TargetRef>>>() {}
@@ -73,7 +74,7 @@ class VoteRepository(requester: Requester) : VoteRepositoryAbs<TargetRef>(reques
class VoteArticleRepository(requester: Requester) : VoteRepositoryAbs<ArticleForView>(requester) { class VoteArticleRepository(requester: Requester) : VoteRepositoryAbs<ArticleForView>(requester) {
fun findByCitizen( fun findByCitizen(
citizen: CitizenEntity, citizen: CitizenI,
page: Int = 1, page: Int = 1,
limit: Int = 50 limit: Int = 50
): Paginated<VoteEntity<ArticleForView>> = ): Paginated<VoteEntity<ArticleForView>> =

View File

@@ -2,6 +2,7 @@ package fr.dcproject.component.vote.routes
import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.auth.citizenOrNull
import fr.dcproject.component.citizen.Citizen import fr.dcproject.component.citizen.Citizen
import fr.dcproject.component.citizen.CitizenRef
import fr.dcproject.component.vote.VoteAccessControl import fr.dcproject.component.vote.VoteAccessControl
import fr.dcproject.component.vote.VoteRepository import fr.dcproject.component.vote.VoteRepository
import fr.dcproject.security.assert import fr.dcproject.security.assert
@@ -17,7 +18,8 @@ import java.util.UUID
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object GetCitizenVotes { object GetCitizenVotes {
@Location("/citizens/{citizen}/votes") @Location("/citizens/{citizen}/votes")
class CitizenVotesRequest(val citizen: Citizen, id: List<String>) { class CitizenVotesRequest(citizen: UUID, id: List<String>) {
val citizen = CitizenRef(citizen)
val id: List<UUID> = id.toUUID() val id: List<UUID> = id.toUUID()
} }

View File

@@ -2,6 +2,7 @@ package fr.dcproject.component.vote.routes
import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.auth.citizenOrNull
import fr.dcproject.component.citizen.Citizen import fr.dcproject.component.citizen.Citizen
import fr.dcproject.component.citizen.CitizenRef
import fr.dcproject.component.vote.VoteAccessControl import fr.dcproject.component.vote.VoteAccessControl
import fr.dcproject.component.vote.VoteArticleRepository import fr.dcproject.component.vote.VoteArticleRepository
import fr.dcproject.routes.PaginatedRequest import fr.dcproject.routes.PaginatedRequest
@@ -13,16 +14,19 @@ import io.ktor.locations.Location
import io.ktor.locations.get import io.ktor.locations.get
import io.ktor.response.respond import io.ktor.response.respond
import io.ktor.routing.Route import io.ktor.routing.Route
import java.util.UUID
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object GetCitizenVotesOnArticle { object GetCitizenVotesOnArticle {
@Location("/citizens/{citizen}/votes/articles") @Location("/citizens/{citizen}/votes/articles")
class CitizenVoteArticleRequest( class CitizenVoteArticleRequest(
val citizen: Citizen, citizen: UUID,
page: Int = 1, page: Int = 1,
limit: Int = 50, limit: Int = 50,
val search: String? = null 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) { fun Route.getCitizenVotesOnArticle(repo: VoteArticleRepository, ac: VoteAccessControl) {
get<CitizenVoteArticleRequest> { get<CitizenVoteArticleRequest> {

View File

@@ -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 <reified T : Any> ApplicationCall.receiveOrBadRequest(message: String = "Bad Request, wrong body request"): T {
return try {
receive<T>(typeOf<T>())
} catch (cause: MissingKotlinParameterException) {
application.log.debug("Conversion failed, throw bad exeption", cause)
throw BadRequestException(message, cause)
}
}