Big refactoring #77
@@ -7,28 +7,15 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategy
|
|||||||
import com.fasterxml.jackson.databind.SerializationFeature
|
import com.fasterxml.jackson.databind.SerializationFeature
|
||||||
import com.fasterxml.jackson.datatype.joda.JodaModule
|
import com.fasterxml.jackson.datatype.joda.JodaModule
|
||||||
import com.github.jasync.sql.db.postgresql.exceptions.GenericDatabaseException
|
import com.github.jasync.sql.db.postgresql.exceptions.GenericDatabaseException
|
||||||
import component.auth.jwt.jwtInstallation
|
|
||||||
import fr.dcproject.application.Env.PROD
|
import fr.dcproject.application.Env.PROD
|
||||||
import fr.dcproject.component.article.routes.findArticleVersions
|
import fr.dcproject.component.article.routes.installArticleRoutes
|
||||||
import fr.dcproject.component.article.routes.findArticles
|
|
||||||
import fr.dcproject.component.article.routes.getOneArticle
|
|
||||||
import fr.dcproject.component.article.routes.upsertArticle
|
|
||||||
import fr.dcproject.component.auth.ForbiddenException
|
import fr.dcproject.component.auth.ForbiddenException
|
||||||
import fr.dcproject.component.auth.routes.authLogin
|
import fr.dcproject.component.auth.jwt.jwtInstallation
|
||||||
import fr.dcproject.component.auth.routes.authPasswordless
|
import fr.dcproject.component.auth.routes.installAuthRoutes
|
||||||
import fr.dcproject.component.auth.routes.authRegister
|
|
||||||
import fr.dcproject.component.auth.user
|
import fr.dcproject.component.auth.user
|
||||||
import fr.dcproject.component.citizen.routes.changeMyPassword
|
import fr.dcproject.component.citizen.routes.installCitizenRoutes
|
||||||
import fr.dcproject.component.citizen.routes.findCitizen
|
import fr.dcproject.component.comment.article.routes.installCommentArticleRoutes
|
||||||
import fr.dcproject.component.citizen.routes.getCurrentCitizen
|
import fr.dcproject.component.comment.generic.routes.installCommentRoutes
|
||||||
import fr.dcproject.component.citizen.routes.getOneCitizen
|
|
||||||
import fr.dcproject.component.comment.article.routes.createCommentArticle
|
|
||||||
import fr.dcproject.component.comment.article.routes.getArticleComments
|
|
||||||
import fr.dcproject.component.comment.article.routes.getCitizenArticleComments
|
|
||||||
import fr.dcproject.component.comment.generic.routes.createCommentChildren
|
|
||||||
import fr.dcproject.component.comment.generic.routes.editComment
|
|
||||||
import fr.dcproject.component.comment.generic.routes.getChildrenComments
|
|
||||||
import fr.dcproject.component.comment.generic.routes.getOneComment
|
|
||||||
import fr.dcproject.component.follow.routes.article.FollowArticle.followArticle
|
import fr.dcproject.component.follow.routes.article.FollowArticle.followArticle
|
||||||
import fr.dcproject.component.follow.routes.article.GetFollowArticle.getFollowArticle
|
import fr.dcproject.component.follow.routes.article.GetFollowArticle.getFollowArticle
|
||||||
import fr.dcproject.component.follow.routes.article.GetMyFollowsArticle.getMyFollowsArticle
|
import fr.dcproject.component.follow.routes.article.GetMyFollowsArticle.getMyFollowsArticle
|
||||||
@@ -86,14 +73,14 @@ import io.ktor.routing.Routing
|
|||||||
import io.ktor.server.jetty.EngineMain
|
import io.ktor.server.jetty.EngineMain
|
||||||
import io.ktor.util.KtorExperimentalAPI
|
import io.ktor.util.KtorExperimentalAPI
|
||||||
import io.ktor.websocket.WebSockets
|
import io.ktor.websocket.WebSockets
|
||||||
|
import java.time.Duration
|
||||||
|
import java.util.concurrent.CompletionException
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import org.eclipse.jetty.util.log.Slf4jLog
|
import org.eclipse.jetty.util.log.Slf4jLog
|
||||||
import org.koin.core.qualifier.named
|
import org.koin.core.qualifier.named
|
||||||
import org.koin.ktor.ext.Koin
|
import org.koin.ktor.ext.Koin
|
||||||
import org.koin.ktor.ext.get
|
import org.koin.ktor.ext.get
|
||||||
import org.slf4j.event.Level
|
import org.slf4j.event.Level
|
||||||
import java.time.Duration
|
|
||||||
import java.util.concurrent.CompletionException
|
|
||||||
|
|
||||||
fun main(args: Array<String>): Unit = EngineMain.main(args)
|
fun main(args: Array<String>): Unit = EngineMain.main(args)
|
||||||
|
|
||||||
@@ -158,30 +145,13 @@ fun Application.module(env: Env = PROD) {
|
|||||||
|
|
||||||
install(Routing.Feature) {
|
install(Routing.Feature) {
|
||||||
// trace { application.log.trace(it.buildText()) }
|
// trace { application.log.trace(it.buildText()) }
|
||||||
|
installArticleRoutes()
|
||||||
|
installAuthRoutes()
|
||||||
|
installCitizenRoutes()
|
||||||
|
installCommentArticleRoutes()
|
||||||
|
installCommentRoutes()
|
||||||
|
|
||||||
authenticate(optional = true) {
|
authenticate(optional = true) {
|
||||||
/* Article */
|
|
||||||
findArticles(get(), get())
|
|
||||||
getOneArticle(get(), get())
|
|
||||||
upsertArticle(get(), get(), get())
|
|
||||||
findArticleVersions(get(), get())
|
|
||||||
/* Citizen */
|
|
||||||
findCitizen(get(), get())
|
|
||||||
getOneCitizen(get())
|
|
||||||
getCurrentCitizen(get())
|
|
||||||
changeMyPassword(get(), get())
|
|
||||||
/* Comment */
|
|
||||||
editComment(get(), get())
|
|
||||||
getOneComment(get(), get())
|
|
||||||
createCommentChildren(get(), get())
|
|
||||||
getChildrenComments(get(), get())
|
|
||||||
/* Comment Article */
|
|
||||||
getArticleComments(get(), get())
|
|
||||||
createCommentArticle(get(), get())
|
|
||||||
getCitizenArticleComments(get(), get())
|
|
||||||
/* Auth */
|
|
||||||
authLogin(get())
|
|
||||||
authRegister(get())
|
|
||||||
authPasswordless(get())
|
|
||||||
/* Workgroup */
|
/* Workgroup */
|
||||||
getWorkgroups(get(), get())
|
getWorkgroups(get(), get())
|
||||||
getWorkgroup(get(), get())
|
getWorkgroup(get(), get())
|
||||||
|
|||||||
@@ -14,28 +14,28 @@ import io.ktor.response.respond
|
|||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
@Location("/articles/{article}/versions")
|
object FindArticleVersions {
|
||||||
class ArticleVersionsRequest(
|
@Location("/articles/{article}/versions")
|
||||||
|
class ArticleVersionsRequest(
|
||||||
val article: ArticleForView,
|
val article: ArticleForView,
|
||||||
page: Int = 1,
|
page: Int = 1,
|
||||||
limit: Int = 50,
|
limit: Int = 50,
|
||||||
val sort: String? = null,
|
val sort: String? = null,
|
||||||
val direction: RepositoryI.Direction? = null,
|
val direction: RepositoryI.Direction? = null,
|
||||||
val search: String? = null
|
val search: String? = null
|
||||||
) {
|
) {
|
||||||
val page: Int = if (page < 1) 1 else page
|
val page: Int = if (page < 1) 1 else page
|
||||||
val limit: Int = if (limit > 50) 50 else if (limit < 1) 1 else limit
|
val limit: Int = if (limit > 50) 50 else if (limit < 1) 1 else limit
|
||||||
}
|
}
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
private fun ArticleRepository.findVersions(request: ArticleVersionsRequest) =
|
||||||
private fun ArticleRepository.findVersions(request: ArticleVersionsRequest) =
|
|
||||||
findVersionsByVersionId(request.page, request.limit, request.article.versionId)
|
findVersionsByVersionId(request.page, request.limit, request.article.versionId)
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
fun Route.findArticleVersions(repo: ArticleRepository, voter: ArticleVoter) {
|
||||||
fun Route.findArticleVersions(repo: ArticleRepository, voter: ArticleVoter) {
|
|
||||||
get<ArticleVersionsRequest> {
|
get<ArticleVersionsRequest> {
|
||||||
repo.findVersions(it)
|
repo.findVersions(it)
|
||||||
.apply { voter.assert { canView(it.article, citizenOrNull) } }
|
.apply { voter.assert { canView(it.article, citizenOrNull) } }
|
||||||
.let { call.respond(it) }
|
.let { call.respond(it) }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,13 +8,16 @@ import fr.dcproject.voter.assert
|
|||||||
import fr.postgresjson.connexion.Paginated
|
import fr.postgresjson.connexion.Paginated
|
||||||
import fr.postgresjson.repository.RepositoryI
|
import fr.postgresjson.repository.RepositoryI
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
|
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
|
||||||
|
|
||||||
@Location("/articles")
|
@KtorExperimentalLocationsAPI
|
||||||
class ArticlesRequest(
|
object FindArticles {
|
||||||
|
@Location("/articles")
|
||||||
|
class ArticlesRequest(
|
||||||
page: Int = 1,
|
page: Int = 1,
|
||||||
limit: Int = 50,
|
limit: Int = 50,
|
||||||
val sort: String? = null,
|
val sort: String? = null,
|
||||||
@@ -22,12 +25,12 @@ class ArticlesRequest(
|
|||||||
val search: String? = null,
|
val search: String? = null,
|
||||||
val createdBy: String? = null,
|
val createdBy: String? = null,
|
||||||
val workgroup: String? = null
|
val workgroup: String? = null
|
||||||
) {
|
) {
|
||||||
val page: Int = if (page < 1) 1 else page
|
val page: Int = if (page < 1) 1 else page
|
||||||
val limit: Int = if (limit > 50) 50 else if (limit < 1) 1 else limit
|
val limit: Int = if (limit > 50) 50 else if (limit < 1) 1 else limit
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ArticleRepository.findArticles(request: ArticlesRequest): Paginated<ArticleForListing> {
|
private fun ArticleRepository.findArticles(request: ArticlesRequest): Paginated<ArticleForListing> {
|
||||||
return find(
|
return find(
|
||||||
request.page,
|
request.page,
|
||||||
request.limit,
|
request.limit,
|
||||||
@@ -36,12 +39,13 @@ private fun ArticleRepository.findArticles(request: ArticlesRequest): Paginated<
|
|||||||
request.search,
|
request.search,
|
||||||
ArticleRepository.Filter(createdById = request.createdBy, workgroupId = request.workgroup)
|
ArticleRepository.Filter(createdById = request.createdBy, workgroupId = request.workgroup)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Route.findArticles(repo: ArticleRepository, voter: ArticleVoter) {
|
fun Route.findArticles(repo: ArticleRepository, voter: ArticleVoter) {
|
||||||
get<ArticlesRequest> {
|
get<ArticlesRequest> {
|
||||||
repo.findArticles(it)
|
repo.findArticles(it)
|
||||||
.apply { voter.assert { canView(result, citizenOrNull) } }
|
.apply { voter.assert { canView(result, citizenOrNull) } }
|
||||||
.let { call.respond(it) }
|
.let { call.respond(it) }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import fr.dcproject.component.article.ArticleForView
|
|||||||
import fr.dcproject.component.article.ArticleRepository
|
import fr.dcproject.component.article.ArticleRepository
|
||||||
import fr.dcproject.component.article.ArticleViewManager
|
import fr.dcproject.component.article.ArticleViewManager
|
||||||
import fr.dcproject.component.article.ArticleVoter
|
import fr.dcproject.component.article.ArticleVoter
|
||||||
import fr.dcproject.component.article.routes.ArticleRequest.Output
|
import fr.dcproject.component.article.routes.GetOneArticle.ArticleRequest.Output
|
||||||
import fr.dcproject.component.auth.citizenOrNull
|
import fr.dcproject.component.auth.citizenOrNull
|
||||||
import fr.dcproject.dto.CreatedAt
|
import fr.dcproject.dto.CreatedAt
|
||||||
import fr.dcproject.dto.Opinionable
|
import fr.dcproject.dto.Opinionable
|
||||||
@@ -19,18 +19,17 @@ 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 io.ktor.util.KtorExperimentalAPI
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.koin.core.KoinComponent
|
import org.koin.core.KoinComponent
|
||||||
import org.koin.core.inject
|
import org.koin.core.inject
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
@Location("/articles/{articleId}")
|
object GetOneArticle {
|
||||||
class ArticleRequest(val articleId: UUID) : KoinComponent {
|
@Location("/articles/{articleId}")
|
||||||
|
class ArticleRequest(val articleId: UUID) : KoinComponent {
|
||||||
val repo: ArticleRepository by inject()
|
val repo: ArticleRepository by inject()
|
||||||
|
|
||||||
@KtorExperimentalAPI
|
|
||||||
val article: ArticleForView = repo.findById(articleId) ?: throw NotFoundException("Article $articleId not found")
|
val article: ArticleForView = repo.findById(articleId) ?: throw NotFoundException("Article $articleId not found")
|
||||||
|
|
||||||
class Output(
|
class Output(
|
||||||
@@ -52,11 +51,9 @@ class ArticleRequest(val articleId: UUID) : KoinComponent {
|
|||||||
val createdBy = article.createdBy
|
val createdBy = article.createdBy
|
||||||
val workgroup = article.workgroup // TODO change to workgroup DTO
|
val workgroup = article.workgroup // TODO change to workgroup DTO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@KtorExperimentalAPI
|
fun Route.getOneArticle(viewManager: ArticleViewManager, voter: ArticleVoter) {
|
||||||
@KtorExperimentalLocationsAPI
|
|
||||||
fun Route.getOneArticle(viewManager: ArticleViewManager, voter: ArticleVoter) {
|
|
||||||
get<ArticleRequest> {
|
get<ArticleRequest> {
|
||||||
voter.assert { canView(it.article, citizenOrNull) }
|
voter.assert { canView(it.article, citizenOrNull) }
|
||||||
|
|
||||||
@@ -71,4 +68,5 @@ fun Route.getOneArticle(viewManager: ArticleViewManager, voter: ArticleVoter) {
|
|||||||
viewManager.addView(call.request.local.remoteHost, it.article, citizenOrNull)
|
viewManager.addView(call.request.local.remoteHost, it.article, citizenOrNull)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import fr.dcproject.component.article.ArticleForUpdate
|
|||||||
import fr.dcproject.component.article.ArticleForView
|
import fr.dcproject.component.article.ArticleForView
|
||||||
import fr.dcproject.component.article.ArticleRepository
|
import fr.dcproject.component.article.ArticleRepository
|
||||||
import fr.dcproject.component.article.ArticleVoter
|
import fr.dcproject.component.article.ArticleVoter
|
||||||
import fr.dcproject.component.article.routes.PostArticleRequest.Input
|
import fr.dcproject.component.article.routes.UpsertArticle.UpsertArticleRequest.Input
|
||||||
import fr.dcproject.component.auth.citizen
|
import fr.dcproject.component.auth.citizen
|
||||||
import fr.dcproject.component.auth.citizenOrNull
|
import fr.dcproject.component.auth.citizenOrNull
|
||||||
import fr.dcproject.component.workgroup.WorkgroupRef
|
import fr.dcproject.component.workgroup.WorkgroupRef
|
||||||
@@ -23,8 +23,9 @@ import io.ktor.routing.Route
|
|||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
@Location("/articles")
|
object UpsertArticle {
|
||||||
class PostArticleRequest {
|
@Location("/articles")
|
||||||
|
class UpsertArticleRequest {
|
||||||
class Input(
|
class Input(
|
||||||
val id: UUID?,
|
val id: UUID?,
|
||||||
val title: String,
|
val title: String,
|
||||||
@@ -36,10 +37,9 @@ class PostArticleRequest {
|
|||||||
val versionId: UUID?,
|
val versionId: UUID?,
|
||||||
val workgroup: WorkgroupRef? = null
|
val workgroup: WorkgroupRef? = null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
fun Route.upsertArticle(repo: ArticleRepository, workgroupRepository: WorkgroupRepository, voter: ArticleVoter) {
|
||||||
fun Route.upsertArticle(repo: ArticleRepository, workgroupRepository: WorkgroupRepository, voter: ArticleVoter) {
|
|
||||||
suspend fun ApplicationCall.convertRequestToEntity(): ArticleForUpdate = receive<Input>().run {
|
suspend fun ApplicationCall.convertRequestToEntity(): ArticleForUpdate = receive<Input>().run {
|
||||||
ArticleForUpdate(
|
ArticleForUpdate(
|
||||||
id = id ?: UUID.randomUUID(),
|
id = id ?: UUID.randomUUID(),
|
||||||
@@ -55,15 +55,12 @@ fun Route.upsertArticle(repo: ArticleRepository, workgroupRepository: WorkgroupR
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
post<PostArticleRequest> {
|
post<UpsertArticleRequest> {
|
||||||
val article = call.convertRequestToEntity()
|
val article = call.convertRequestToEntity()
|
||||||
|
|
||||||
voter.assert { canUpsert(article, citizenOrNull) }
|
voter.assert { canUpsert(article, citizenOrNull) }
|
||||||
|
|
||||||
val newArticle: ArticleForView = repo.upsert(article) ?: error("Article not updated")
|
val newArticle: ArticleForView = repo.upsert(article) ?: error("Article not updated")
|
||||||
|
|
||||||
call.respond(newArticle)
|
call.respond(newArticle)
|
||||||
|
|
||||||
raiseEvent(ArticleUpdate.event, ArticleUpdate(newArticle))
|
raiseEvent(ArticleUpdate.event, ArticleUpdate(newArticle))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
21
src/main/kotlin/component/article/routes/install.kt
Normal file
21
src/main/kotlin/component/article/routes/install.kt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package fr.dcproject.component.article.routes
|
||||||
|
|
||||||
|
import fr.dcproject.component.article.routes.FindArticleVersions.findArticleVersions
|
||||||
|
import fr.dcproject.component.article.routes.FindArticles.findArticles
|
||||||
|
import fr.dcproject.component.article.routes.GetOneArticle.getOneArticle
|
||||||
|
import fr.dcproject.component.article.routes.UpsertArticle.upsertArticle
|
||||||
|
import io.ktor.auth.authenticate
|
||||||
|
import io.ktor.locations.KtorExperimentalLocationsAPI
|
||||||
|
import io.ktor.routing.Routing
|
||||||
|
import io.ktor.util.KtorExperimentalAPI
|
||||||
|
import org.koin.ktor.ext.get
|
||||||
|
|
||||||
|
@KtorExperimentalLocationsAPI
|
||||||
|
fun Routing.installArticleRoutes() {
|
||||||
|
authenticate(optional = true) {
|
||||||
|
findArticles(get(), get())
|
||||||
|
findArticleVersions(get(), get())
|
||||||
|
getOneArticle(get(), get())
|
||||||
|
upsertArticle(get(), get(), get())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ import com.sendgrid.helpers.mail.objects.Email
|
|||||||
import fr.dcproject.component.citizen.CitizenRepository
|
import fr.dcproject.component.citizen.CitizenRepository
|
||||||
import fr.dcproject.component.citizen.CitizenWithEmail
|
import fr.dcproject.component.citizen.CitizenWithEmail
|
||||||
import fr.dcproject.component.citizen.CitizenWithUserI
|
import fr.dcproject.component.citizen.CitizenWithUserI
|
||||||
import fr.dcproject.makeToken
|
import fr.dcproject.component.auth.jwt.makeToken
|
||||||
import fr.dcproject.messages.Mailer
|
import fr.dcproject.messages.Mailer
|
||||||
import io.ktor.http.URLBuilder
|
import io.ktor.http.URLBuilder
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package fr.dcproject
|
package fr.dcproject.component.auth.jwt
|
||||||
|
|
||||||
import com.auth0.jwt.JWT
|
import com.auth0.jwt.JWT
|
||||||
import fr.dcproject.component.auth.UserI
|
import fr.dcproject.component.auth.UserI
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
package component.auth.jwt
|
package fr.dcproject.component.auth.jwt
|
||||||
|
|
||||||
import fr.dcproject.component.auth.User
|
import fr.dcproject.component.auth.User
|
||||||
import fr.dcproject.component.auth.UserRepository
|
import fr.dcproject.component.auth.UserRepository
|
||||||
import fr.dcproject.component.auth.jwt.JwtConfig
|
|
||||||
import io.ktor.application.ApplicationCall
|
import io.ktor.application.ApplicationCall
|
||||||
import io.ktor.auth.Authentication
|
import io.ktor.auth.Authentication
|
||||||
import io.ktor.auth.jwt.jwt
|
import io.ktor.auth.jwt.jwt
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package fr.dcproject.component.auth.routes
|
|||||||
|
|
||||||
import com.fasterxml.jackson.databind.exc.MismatchedInputException
|
import com.fasterxml.jackson.databind.exc.MismatchedInputException
|
||||||
import fr.dcproject.component.auth.UserRepository
|
import fr.dcproject.component.auth.UserRepository
|
||||||
import fr.dcproject.makeToken
|
import fr.dcproject.component.auth.jwt.makeToken
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
import io.ktor.auth.UserPasswordCredential
|
import io.ktor.auth.UserPasswordCredential
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
@@ -13,15 +13,13 @@ import io.ktor.request.receive
|
|||||||
import io.ktor.response.respond
|
import io.ktor.response.respond
|
||||||
import io.ktor.response.respondText
|
import io.ktor.response.respondText
|
||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
import io.ktor.util.KtorExperimentalAPI
|
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
@Location("/login")
|
object Login {
|
||||||
class LoginRequest
|
@Location("/login")
|
||||||
|
class LoginRequest
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
fun Route.authLogin(userRepo: UserRepository) {
|
||||||
@KtorExperimentalAPI
|
|
||||||
fun Route.authLogin(userRepo: UserRepository) {
|
|
||||||
post<LoginRequest> {
|
post<LoginRequest> {
|
||||||
try {
|
try {
|
||||||
val credentials = call.receive<UserPasswordCredential>()
|
val credentials = call.receive<UserPasswordCredential>()
|
||||||
@@ -32,4 +30,5 @@ fun Route.authLogin(userRepo: UserRepository) {
|
|||||||
call.respond(HttpStatusCode.BadRequest, "You must be send name and password to the request")
|
call.respond(HttpStatusCode.BadRequest, "You must be send name and password to the request")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ package fr.dcproject.component.auth.routes
|
|||||||
import com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException
|
import com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException
|
||||||
import fr.dcproject.component.auth.User
|
import fr.dcproject.component.auth.User
|
||||||
import fr.dcproject.component.auth.UserI
|
import fr.dcproject.component.auth.UserI
|
||||||
import fr.dcproject.component.auth.routes.RegisterRequest.Input
|
import fr.dcproject.component.auth.routes.Register.RegisterRequest.Input
|
||||||
import fr.dcproject.component.citizen.Citizen
|
import fr.dcproject.component.citizen.Citizen
|
||||||
import fr.dcproject.component.citizen.CitizenI
|
import fr.dcproject.component.citizen.CitizenI
|
||||||
import fr.dcproject.component.citizen.CitizenRepository
|
import fr.dcproject.component.citizen.CitizenRepository
|
||||||
import fr.dcproject.makeToken
|
import fr.dcproject.component.auth.jwt.makeToken
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
import io.ktor.features.BadRequestException
|
import io.ktor.features.BadRequestException
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
@@ -18,12 +18,12 @@ import io.ktor.request.receive
|
|||||||
import io.ktor.response.respond
|
import io.ktor.response.respond
|
||||||
import io.ktor.response.respondText
|
import io.ktor.response.respondText
|
||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
import io.ktor.util.KtorExperimentalAPI
|
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
@Location("/register")
|
object Register {
|
||||||
class RegisterRequest {
|
@Location("/register")
|
||||||
|
class RegisterRequest {
|
||||||
data class Input(
|
data class Input(
|
||||||
val name: Name,
|
val name: Name,
|
||||||
val email: String,
|
val email: String,
|
||||||
@@ -42,11 +42,9 @@ class RegisterRequest {
|
|||||||
val plainPassword: String? = null
|
val plainPassword: String? = null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
fun Route.authRegister(citizenRepo: CitizenRepository) {
|
||||||
@KtorExperimentalAPI
|
|
||||||
fun Route.authRegister(citizenRepo: CitizenRepository) {
|
|
||||||
fun Input.toCitizen(): Citizen = Citizen(
|
fun Input.toCitizen(): Citizen = Citizen(
|
||||||
name = CitizenI.Name(name.firstName, name.lastName, name.civility),
|
name = CitizenI.Name(name.firstName, name.lastName, name.civility),
|
||||||
birthday = birthday,
|
birthday = birthday,
|
||||||
@@ -69,4 +67,5 @@ fun Route.authRegister(citizenRepo: CitizenRepository) {
|
|||||||
call.respond(HttpStatusCode.BadRequest)
|
call.respond(HttpStatusCode.BadRequest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package fr.dcproject.component.auth.routes
|
package fr.dcproject.component.auth.routes
|
||||||
|
|
||||||
import fr.dcproject.component.auth.PasswordlessAuth
|
import fr.dcproject.component.auth.PasswordlessAuth
|
||||||
import fr.dcproject.component.auth.routes.PasswordlessRequest.Input
|
import fr.dcproject.component.auth.routes.Sso.PasswordlessRequest.Input
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.locations.KtorExperimentalLocationsAPI
|
import io.ktor.locations.KtorExperimentalLocationsAPI
|
||||||
@@ -10,20 +10,18 @@ import io.ktor.locations.post
|
|||||||
import io.ktor.request.receive
|
import io.ktor.request.receive
|
||||||
import io.ktor.response.respond
|
import io.ktor.response.respond
|
||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
import io.ktor.util.KtorExperimentalAPI
|
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
@Location("/auth/passwordless")
|
object Sso {
|
||||||
class PasswordlessRequest {
|
@Location("/auth/passwordless")
|
||||||
|
class PasswordlessRequest {
|
||||||
data class Input(val email: String, val url: String)
|
data class Input(val email: String, val url: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send an email to the citizen with a link to automatically connect
|
* Send an email to the citizen with a link to automatically connect
|
||||||
*/
|
*/
|
||||||
@KtorExperimentalLocationsAPI
|
fun Route.authPasswordless(passwordlessAuth: PasswordlessAuth) {
|
||||||
@KtorExperimentalAPI
|
|
||||||
fun Route.authPasswordless(passwordlessAuth: PasswordlessAuth) {
|
|
||||||
post<PasswordlessRequest> {
|
post<PasswordlessRequest> {
|
||||||
call.receive<Input>().run {
|
call.receive<Input>().run {
|
||||||
try {
|
try {
|
||||||
@@ -34,4 +32,5 @@ fun Route.authPasswordless(passwordlessAuth: PasswordlessAuth) {
|
|||||||
call.respond(HttpStatusCode.NoContent)
|
call.respond(HttpStatusCode.NoContent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
19
src/main/kotlin/component/auth/routes/install.kt
Normal file
19
src/main/kotlin/component/auth/routes/install.kt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package fr.dcproject.component.auth.routes
|
||||||
|
|
||||||
|
import fr.dcproject.component.auth.routes.Login.authLogin
|
||||||
|
import fr.dcproject.component.auth.routes.Register.authRegister
|
||||||
|
import fr.dcproject.component.auth.routes.Sso.authPasswordless
|
||||||
|
import io.ktor.auth.authenticate
|
||||||
|
import io.ktor.locations.KtorExperimentalLocationsAPI
|
||||||
|
import io.ktor.routing.Routing
|
||||||
|
import io.ktor.util.KtorExperimentalAPI
|
||||||
|
import org.koin.ktor.ext.get
|
||||||
|
|
||||||
|
@KtorExperimentalLocationsAPI
|
||||||
|
fun Routing.installAuthRoutes() {
|
||||||
|
authenticate(optional = true) {
|
||||||
|
authLogin(get())
|
||||||
|
authRegister(get())
|
||||||
|
authPasswordless(get())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,14 +18,13 @@ import io.ktor.response.respond
|
|||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
|
object ChangeMyPassword {
|
||||||
@Location("/citizens/{citizen}/password/change")
|
@Location("/citizens/{citizen}/password/change")
|
||||||
class ChangePasswordCitizenRequest(val citizen: Citizen) {
|
class ChangePasswordCitizenRequest(val citizen: Citizen) {
|
||||||
data class Input(val oldPassword: String, val newPassword: String)
|
data class Input(val oldPassword: String, val newPassword: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
fun Route.changeMyPassword(voter: CitizenVoter, userRepository: UserRepository) {
|
||||||
fun Route.changeMyPassword(voter: CitizenVoter, userRepository: UserRepository) {
|
|
||||||
put<ChangePasswordCitizenRequest> {
|
put<ChangePasswordCitizenRequest> {
|
||||||
voter.assert { canChangePassword(it.citizen, citizenOrNull) }
|
voter.assert { canChangePassword(it.citizen, citizenOrNull) }
|
||||||
try {
|
try {
|
||||||
@@ -44,4 +43,5 @@ fun Route.changeMyPassword(voter: CitizenVoter, userRepository: UserRepository)
|
|||||||
call.respond(HttpStatusCode.BadRequest, "Request format is not correct")
|
call.respond(HttpStatusCode.BadRequest, "Request format is not correct")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,23 +13,24 @@ import io.ktor.response.respond
|
|||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
@Location("/citizens")
|
object FindCitizens {
|
||||||
class CitizensRequest(
|
@Location("/citizens")
|
||||||
|
class CitizensRequest(
|
||||||
page: Int = 1,
|
page: Int = 1,
|
||||||
limit: Int = 50,
|
limit: Int = 50,
|
||||||
val sort: String? = null,
|
val sort: String? = null,
|
||||||
val direction: RepositoryI.Direction? = null,
|
val direction: RepositoryI.Direction? = null,
|
||||||
val search: String? = null
|
val search: String? = null
|
||||||
) {
|
) {
|
||||||
val page: Int = if (page < 1) 1 else page
|
val page: Int = if (page < 1) 1 else page
|
||||||
val limit: Int = if (limit > 50) 50 else if (limit < 1) 1 else limit
|
val limit: Int = if (limit > 50) 50 else if (limit < 1) 1 else limit
|
||||||
}
|
}
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
fun Route.findCitizen(voter: CitizenVoter, repo: CitizenRepository) {
|
||||||
fun Route.findCitizen(voter: CitizenVoter, repo: CitizenRepository) {
|
|
||||||
get<CitizensRequest> {
|
get<CitizensRequest> {
|
||||||
val citizens = repo.find(it.page, it.limit, it.sort, it.direction, it.search)
|
val citizens = repo.find(it.page, it.limit, it.sort, it.direction, it.search)
|
||||||
voter.assert { canView(citizens.result, citizenOrNull) }
|
voter.assert { canView(citizens.result, citizenOrNull) }
|
||||||
call.respond(citizens)
|
call.respond(citizens)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,11 +13,11 @@ import io.ktor.response.respond
|
|||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
@Location("/citizens/current")
|
object GetCurrentCitizen {
|
||||||
class CurrentCitizenRequest
|
@Location("/citizens/current")
|
||||||
|
class CurrentCitizenRequest
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
fun Route.getCurrentCitizen(voter: CitizenVoter) {
|
||||||
fun Route.getCurrentCitizen(voter: CitizenVoter) {
|
|
||||||
get<CurrentCitizenRequest> {
|
get<CurrentCitizenRequest> {
|
||||||
val currentUser = citizenOrNull
|
val currentUser = citizenOrNull
|
||||||
if (currentUser === null) {
|
if (currentUser === null) {
|
||||||
@@ -27,4 +27,5 @@ fun Route.getCurrentCitizen(voter: CitizenVoter) {
|
|||||||
call.respond(citizen)
|
call.respond(citizen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,14 +12,15 @@ import io.ktor.response.respond
|
|||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
@Location("/citizens/{citizen}")
|
object GetOneCitizen {
|
||||||
class CitizenRequest(val citizen: Citizen)
|
@Location("/citizens/{citizen}")
|
||||||
|
class CitizenRequest(val citizen: Citizen)
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
fun Route.getOneCitizen(voter: CitizenVoter) {
|
||||||
fun Route.getOneCitizen(voter: CitizenVoter) {
|
|
||||||
get<CitizenRequest> {
|
get<CitizenRequest> {
|
||||||
voter.assert { canView(it.citizen, citizenOrNull) }
|
voter.assert { canView(it.citizen, citizenOrNull) }
|
||||||
|
|
||||||
call.respond(it.citizen)
|
call.respond(it.citizen)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
24
src/main/kotlin/component/citizen/routes/install.kt
Normal file
24
src/main/kotlin/component/citizen/routes/install.kt
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package fr.dcproject.component.citizen.routes
|
||||||
|
|
||||||
|
import fr.dcproject.component.auth.routes.Login.authLogin
|
||||||
|
import fr.dcproject.component.auth.routes.Register.authRegister
|
||||||
|
import fr.dcproject.component.auth.routes.Sso.authPasswordless
|
||||||
|
import fr.dcproject.component.citizen.routes.ChangeMyPassword.changeMyPassword
|
||||||
|
import fr.dcproject.component.citizen.routes.FindCitizens.findCitizen
|
||||||
|
import fr.dcproject.component.citizen.routes.GetCurrentCitizen.getCurrentCitizen
|
||||||
|
import fr.dcproject.component.citizen.routes.GetOneCitizen.getOneCitizen
|
||||||
|
import io.ktor.auth.authenticate
|
||||||
|
import io.ktor.locations.KtorExperimentalLocationsAPI
|
||||||
|
import io.ktor.routing.Routing
|
||||||
|
import io.ktor.util.KtorExperimentalAPI
|
||||||
|
import org.koin.ktor.ext.get
|
||||||
|
|
||||||
|
@KtorExperimentalLocationsAPI
|
||||||
|
fun Routing.installCitizenRoutes() {
|
||||||
|
authenticate(optional = true) {
|
||||||
|
findCitizen(get(), get())
|
||||||
|
getOneCitizen(get())
|
||||||
|
getCurrentCitizen(get())
|
||||||
|
changeMyPassword(get(), get())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,10 +18,11 @@ import io.ktor.response.respond
|
|||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
@Location("/articles/{article}/comments")
|
object CreateCommentArticle {
|
||||||
class PostArticleCommentRequest(
|
@Location("/articles/{article}/comments")
|
||||||
|
class PostArticleCommentRequest(
|
||||||
val article: ArticleForView
|
val article: ArticleForView
|
||||||
) {
|
) {
|
||||||
class Comment(
|
class Comment(
|
||||||
val content: String
|
val content: String
|
||||||
)
|
)
|
||||||
@@ -33,10 +34,9 @@ class PostArticleCommentRequest(
|
|||||||
content = content
|
content = content
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
fun Route.createCommentArticle(repo: CommentArticleRepository, voter: CommentVoter) {
|
||||||
fun Route.createCommentArticle(repo: CommentArticleRepository, voter: CommentVoter) {
|
|
||||||
post<PostArticleCommentRequest> {
|
post<PostArticleCommentRequest> {
|
||||||
it.getComment(call).let { comment ->
|
it.getComment(call).let { comment ->
|
||||||
voter.assert { canCreate(comment, citizenOrNull) }
|
voter.assert { canCreate(comment, citizenOrNull) }
|
||||||
@@ -44,4 +44,5 @@ fun Route.createCommentArticle(repo: CommentArticleRepository, voter: CommentVot
|
|||||||
call.respond(HttpStatusCode.Created, comment)
|
call.respond(HttpStatusCode.Created, comment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,21 +14,21 @@ import io.ktor.response.respond
|
|||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
@Location("/articles/{article}/comments")
|
object GetArticleComments {
|
||||||
class ArticleCommentsRequest(
|
@Location("/articles/{article}/comments")
|
||||||
|
class ArticleCommentsRequest(
|
||||||
val article: ArticleRef,
|
val article: ArticleRef,
|
||||||
page: Int = 1,
|
page: Int = 1,
|
||||||
limit: Int = 50,
|
limit: Int = 50,
|
||||||
val search: String? = null,
|
val search: String? = null,
|
||||||
sort: String = CommentArticleRepository.Sort.CREATED_AT.sql
|
sort: String = CommentArticleRepository.Sort.CREATED_AT.sql
|
||||||
) {
|
) {
|
||||||
val page: Int = if (page < 1) 1 else page
|
val page: Int = if (page < 1) 1 else page
|
||||||
val limit: Int = if (limit > 50) 50 else if (limit < 1) 1 else limit
|
val limit: Int = if (limit > 50) 50 else if (limit < 1) 1 else limit
|
||||||
val sort: CommentArticleRepository.Sort = CommentArticleRepository.Sort.fromString(sort) ?: CommentArticleRepository.Sort.CREATED_AT
|
val sort: CommentArticleRepository.Sort = CommentArticleRepository.Sort.fromString(sort) ?: CommentArticleRepository.Sort.CREATED_AT
|
||||||
}
|
}
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
fun Route.getArticleComments(repo: CommentArticleRepository, voter: CommentVoter) {
|
||||||
fun Route.getArticleComments(repo: CommentArticleRepository, voter: CommentVoter) {
|
|
||||||
get<ArticleCommentsRequest> {
|
get<ArticleCommentsRequest> {
|
||||||
val comment = repo.findByTarget(it.article, it.page, it.limit, it.sort)
|
val comment = repo.findByTarget(it.article, it.page, it.limit, it.sort)
|
||||||
if (comment.result.isNotEmpty()) {
|
if (comment.result.isNotEmpty()) {
|
||||||
@@ -36,4 +36,5 @@ fun Route.getArticleComments(repo: CommentArticleRepository, voter: CommentVoter
|
|||||||
}
|
}
|
||||||
call.respond(HttpStatusCode.OK, comment)
|
call.respond(HttpStatusCode.OK, comment)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,15 +13,16 @@ import io.ktor.response.respond
|
|||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
@Location("/citizens/{citizen}/comments/articles")
|
object GetCitizenArticleComments {
|
||||||
class CitizenCommentArticleRequest(val citizen: Citizen)
|
@Location("/citizens/{citizen}/comments/articles")
|
||||||
|
class CitizenCommentArticleRequest(val citizen: Citizen)
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
fun Route.getCitizenArticleComments(repo: CommentArticleRepository, voter: CommentVoter) {
|
||||||
fun Route.getCitizenArticleComments(repo: CommentArticleRepository, voter: CommentVoter) {
|
|
||||||
get<CitizenCommentArticleRequest> {
|
get<CitizenCommentArticleRequest> {
|
||||||
repo.findByCitizen(it.citizen).let { comments ->
|
repo.findByCitizen(it.citizen).let { comments ->
|
||||||
voter.assert { canView(comments.result, citizenOrNull) }
|
voter.assert { canView(comments.result, citizenOrNull) }
|
||||||
call.respond(comments)
|
call.respond(comments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
18
src/main/kotlin/component/comment/article/routes/install.kt
Normal file
18
src/main/kotlin/component/comment/article/routes/install.kt
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package fr.dcproject.component.comment.article.routes
|
||||||
|
|
||||||
|
import fr.dcproject.component.comment.article.routes.CreateCommentArticle.createCommentArticle
|
||||||
|
import fr.dcproject.component.comment.article.routes.GetArticleComments.getArticleComments
|
||||||
|
import fr.dcproject.component.comment.article.routes.GetCitizenArticleComments.getCitizenArticleComments
|
||||||
|
import io.ktor.auth.authenticate
|
||||||
|
import io.ktor.locations.KtorExperimentalLocationsAPI
|
||||||
|
import io.ktor.routing.Routing
|
||||||
|
import org.koin.ktor.ext.get
|
||||||
|
|
||||||
|
@KtorExperimentalLocationsAPI
|
||||||
|
fun Routing.installCommentArticleRoutes() {
|
||||||
|
authenticate(optional = true) {
|
||||||
|
getArticleComments(get(), get())
|
||||||
|
createCommentArticle(get(), get())
|
||||||
|
getCitizenArticleComments(get(), get())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,14 +19,13 @@ import io.ktor.routing.Route
|
|||||||
import io.ktor.util.KtorExperimentalAPI
|
import io.ktor.util.KtorExperimentalAPI
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
@Location("/comments/{comment}/children")
|
object CreateCommentChildren {
|
||||||
class CreateCommentChildrenRequest(val comment: CommentRef) {
|
@Location("/comments/{comment}/children")
|
||||||
|
class CreateCommentChildrenRequest(val comment: CommentRef) {
|
||||||
class Input(val content: String)
|
class Input(val content: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
@KtorExperimentalAPI
|
fun Route.createCommentChildren(repo: CommentRepository, voter: CommentVoter) {
|
||||||
@KtorExperimentalLocationsAPI
|
|
||||||
fun Route.createCommentChildren(repo: CommentRepository, voter: CommentVoter) {
|
|
||||||
post<CreateCommentChildrenRequest> {
|
post<CreateCommentChildrenRequest> {
|
||||||
val parent = repo.findById(it.comment.id) ?: throw NotFoundException("Comment not found")
|
val parent = repo.findById(it.comment.id) ?: throw NotFoundException("Comment not found")
|
||||||
val newComment = CommentForUpdate(
|
val newComment = CommentForUpdate(
|
||||||
@@ -40,4 +39,5 @@ fun Route.createCommentChildren(repo: CommentRepository, voter: CommentVoter) {
|
|||||||
|
|
||||||
call.respond(HttpStatusCode.Created, newComment)
|
call.respond(HttpStatusCode.Created, newComment)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -14,15 +14,13 @@ import io.ktor.locations.put
|
|||||||
import io.ktor.request.receiveText
|
import io.ktor.request.receiveText
|
||||||
import io.ktor.response.respond
|
import io.ktor.response.respond
|
||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
import io.ktor.util.KtorExperimentalAPI
|
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
@Location("/comments/{comment}")
|
object EditComment {
|
||||||
class EditCommentRequest(val comment: CommentRef)
|
@Location("/comments/{comment}")
|
||||||
|
class EditCommentRequest(val comment: CommentRef)
|
||||||
|
|
||||||
@KtorExperimentalAPI
|
fun Route.editComment(repo: CommentRepository, voter: CommentVoter) {
|
||||||
@KtorExperimentalLocationsAPI
|
|
||||||
fun Route.editComment(repo: CommentRepository, voter: CommentVoter) {
|
|
||||||
put<EditCommentRequest> {
|
put<EditCommentRequest> {
|
||||||
val comment = repo.findById(it.comment.id) ?: throw NotFoundException("Comment not found")
|
val comment = repo.findById(it.comment.id) ?: throw NotFoundException("Comment not found")
|
||||||
voter.assert { canUpdate(comment, citizenOrNull) }
|
voter.assert { canUpdate(comment, citizenOrNull) }
|
||||||
@@ -32,4 +30,5 @@ fun Route.editComment(repo: CommentRepository, voter: CommentVoter) {
|
|||||||
|
|
||||||
call.respond(HttpStatusCode.OK, comment)
|
call.respond(HttpStatusCode.OK, comment)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,20 +15,19 @@ import io.ktor.util.KtorExperimentalAPI
|
|||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
@Location("/comments/{comment}/children")
|
object GetCommentChildren {
|
||||||
class CommentChildrenRequest(
|
@Location("/comments/{comment}/children")
|
||||||
|
class CommentChildrenRequest(
|
||||||
val comment: UUID,
|
val comment: UUID,
|
||||||
page: Int = 1,
|
page: Int = 1,
|
||||||
limit: Int = 50,
|
limit: Int = 50,
|
||||||
val search: String? = null
|
val search: String? = null
|
||||||
) {
|
) {
|
||||||
val page: Int = if (page < 1) 1 else page
|
val page: Int = if (page < 1) 1 else page
|
||||||
val limit: Int = if (limit > 50) 50 else if (limit < 1) 1 else limit
|
val limit: Int = if (limit > 50) 50 else if (limit < 1) 1 else limit
|
||||||
}
|
}
|
||||||
|
|
||||||
@KtorExperimentalAPI
|
fun Route.getChildrenComments(repo: CommentRepository, voter: CommentVoter) {
|
||||||
@KtorExperimentalLocationsAPI
|
|
||||||
fun Route.getChildrenComments(repo: CommentRepository, voter: CommentVoter) {
|
|
||||||
get<CommentChildrenRequest> {
|
get<CommentChildrenRequest> {
|
||||||
val comments =
|
val comments =
|
||||||
repo.findByParent(
|
repo.findByParent(
|
||||||
@@ -41,4 +40,5 @@ fun Route.getChildrenComments(repo: CommentRepository, voter: CommentVoter) {
|
|||||||
|
|
||||||
call.respond(HttpStatusCode.OK, comments)
|
call.respond(HttpStatusCode.OK, comments)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,16 +16,16 @@ import io.ktor.routing.Route
|
|||||||
import io.ktor.util.KtorExperimentalAPI
|
import io.ktor.util.KtorExperimentalAPI
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
@Location("/comments/{comment}")
|
object GetOneComment {
|
||||||
class CommentRequest(val comment: CommentRef)
|
@Location("/comments/{comment}")
|
||||||
|
class CommentRequest(val comment: CommentRef)
|
||||||
|
|
||||||
@KtorExperimentalAPI
|
fun Route.getOneComment(repo: CommentRepository, voter: CommentVoter) {
|
||||||
@KtorExperimentalLocationsAPI
|
|
||||||
fun Route.getOneComment(repo: CommentRepository, voter: CommentVoter) {
|
|
||||||
get<CommentRequest> {
|
get<CommentRequest> {
|
||||||
val comment = repo.findById(it.comment.id) ?: throw NotFoundException("Comment ${it.comment.id} not found")
|
val comment = repo.findById(it.comment.id) ?: throw NotFoundException("Comment ${it.comment.id} not found")
|
||||||
voter.assert { canView(comment, citizenOrNull) }
|
voter.assert { canView(comment, citizenOrNull) }
|
||||||
|
|
||||||
call.respond(HttpStatusCode.OK, comment)
|
call.respond(HttpStatusCode.OK, comment)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
20
src/main/kotlin/component/comment/generic/routes/install.kt
Normal file
20
src/main/kotlin/component/comment/generic/routes/install.kt
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package fr.dcproject.component.comment.generic.routes
|
||||||
|
|
||||||
|
import fr.dcproject.component.comment.generic.routes.CreateCommentChildren.createCommentChildren
|
||||||
|
import fr.dcproject.component.comment.generic.routes.EditComment.editComment
|
||||||
|
import fr.dcproject.component.comment.generic.routes.GetCommentChildren.getChildrenComments
|
||||||
|
import fr.dcproject.component.comment.generic.routes.GetOneComment.getOneComment
|
||||||
|
import io.ktor.auth.authenticate
|
||||||
|
import io.ktor.locations.KtorExperimentalLocationsAPI
|
||||||
|
import io.ktor.routing.Routing
|
||||||
|
import org.koin.ktor.ext.get
|
||||||
|
|
||||||
|
@KtorExperimentalLocationsAPI
|
||||||
|
fun Routing.installCommentRoutes() {
|
||||||
|
authenticate(optional = true) {
|
||||||
|
editComment(get(), get())
|
||||||
|
getOneComment(get(), get())
|
||||||
|
createCommentChildren(get(), get())
|
||||||
|
getChildrenComments(get(), get())
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user