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
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> {
decode { values, _ ->
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.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<ChangePasswordCitizenRequest> {
ac.assert { canChangePassword(it.citizen, citizenOrNull) }
try {
val content = call.receive<ChangePasswordCitizenRequest.Input>()
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<ChangePasswordCitizenRequest.Input>()
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")
}
}
}
}

View File

@@ -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<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)
}

View File

@@ -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())
}

View File

@@ -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<CitizenCommentArticleRequest> {

View File

@@ -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<GetCitizenCommentConstitutionRequest> {

View File

@@ -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<CitizenFollowArticleRequest> {

View File

@@ -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<T : TargetRef>(requester: Requester) : OpinionC
* Find opinions of one citizen filtered by target ids
*/
fun findCitizenOpinionsByTargets(
citizen: CitizenEntity,
citizen: CitizenI,
targets: List<UUID>
): 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.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<String>) : KoinComponent {
class CitizenOpinions(citizen: UUID, id: List<String>) {
val citizen = CitizenRef(citizen)
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.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<T : TargetI>(override var requester: Requester)
}
fun findCitizenVotesByTargets(
citizen: CitizenEntity,
citizen: CitizenI,
targets: List<UUID>
): List<VoteEntity<*>> {
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) {
fun findByCitizen(
citizen: CitizenEntity,
citizen: CitizenI,
page: Int = 1,
limit: Int = 50
): 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.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<String>) {
class CitizenVotesRequest(citizen: UUID, id: List<String>) {
val citizen = CitizenRef(citizen)
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.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<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)
}
}