Big refactoring #77

Merged
flecomte merged 166 commits from refactoring-component-and-immutable into master 2021-03-24 19:06:07 +01:00
27 changed files with 492 additions and 420 deletions
Showing only changes of commit 667339979b - Show all commits

View File

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

View File

@@ -14,6 +14,7 @@ import io.ktor.response.respond
import io.ktor.routing.Route import io.ktor.routing.Route
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object FindArticleVersions {
@Location("/articles/{article}/versions") @Location("/articles/{article}/versions")
class ArticleVersionsRequest( class ArticleVersionsRequest(
val article: ArticleForView, val article: ArticleForView,
@@ -27,11 +28,9 @@ class ArticleVersionsRequest(
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)
@@ -39,3 +38,4 @@ fun Route.findArticleVersions(repo: ArticleRepository, voter: ArticleVoter) {
.let { call.respond(it) } .let { call.respond(it) }
} }
} }
}

View File

@@ -8,11 +8,14 @@ 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
@KtorExperimentalLocationsAPI
object FindArticles {
@Location("/articles") @Location("/articles")
class ArticlesRequest( class ArticlesRequest(
page: Int = 1, page: Int = 1,
@@ -45,3 +48,4 @@ fun Route.findArticles(repo: ArticleRepository, voter: ArticleVoter) {
.let { call.respond(it) } .let { call.respond(it) }
} }
} }
}

View File

@@ -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
object GetOneArticle {
@Location("/articles/{articleId}") @Location("/articles/{articleId}")
class ArticleRequest(val articleId: UUID) : KoinComponent { 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(
@@ -54,8 +53,6 @@ class ArticleRequest(val articleId: UUID) : KoinComponent {
} }
} }
@KtorExperimentalAPI
@KtorExperimentalLocationsAPI
fun Route.getOneArticle(viewManager: ArticleViewManager, voter: ArticleVoter) { fun Route.getOneArticle(viewManager: ArticleViewManager, voter: ArticleVoter) {
get<ArticleRequest> { get<ArticleRequest> {
voter.assert { canView(it.article, citizenOrNull) } voter.assert { canView(it.article, citizenOrNull) }
@@ -72,3 +69,4 @@ fun Route.getOneArticle(viewManager: ArticleViewManager, voter: ArticleVoter) {
} }
} }
} }
}

View File

@@ -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
object UpsertArticle {
@Location("/articles") @Location("/articles")
class PostArticleRequest { class UpsertArticleRequest {
class Input( class Input(
val id: UUID?, val id: UUID?,
val title: String, val title: String,
@@ -38,7 +39,6 @@ class PostArticleRequest {
) )
} }
@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(
@@ -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))
} }
} }
}

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

View File

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

View File

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

View File

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

View File

@@ -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,14 +13,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
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object Login {
@Location("/login") @Location("/login")
class LoginRequest class LoginRequest
@KtorExperimentalLocationsAPI
@KtorExperimentalAPI
fun Route.authLogin(userRepo: UserRepository) { fun Route.authLogin(userRepo: UserRepository) {
post<LoginRequest> { post<LoginRequest> {
try { try {
@@ -33,3 +31,4 @@ fun Route.authLogin(userRepo: UserRepository) {
} }
} }
} }
}

View File

@@ -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,10 +18,10 @@ 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
object Register {
@Location("/register") @Location("/register")
class RegisterRequest { class RegisterRequest {
data class Input( data class Input(
@@ -44,8 +44,6 @@ class RegisterRequest {
} }
} }
@KtorExperimentalLocationsAPI
@KtorExperimentalAPI
fun Route.authRegister(citizenRepo: CitizenRepository) { 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),
@@ -70,3 +68,4 @@ fun Route.authRegister(citizenRepo: CitizenRepository) {
} }
} }
} }
}

View File

@@ -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,9 +10,9 @@ 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
object Sso {
@Location("/auth/passwordless") @Location("/auth/passwordless")
class PasswordlessRequest { class PasswordlessRequest {
data class Input(val email: String, val url: String) data class Input(val email: String, val url: String)
@@ -21,8 +21,6 @@ class PasswordlessRequest {
/** /**
* 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
@KtorExperimentalAPI
fun Route.authPasswordless(passwordlessAuth: PasswordlessAuth) { fun Route.authPasswordless(passwordlessAuth: PasswordlessAuth) {
post<PasswordlessRequest> { post<PasswordlessRequest> {
call.receive<Input>().run { call.receive<Input>().run {
@@ -35,3 +33,4 @@ fun Route.authPasswordless(passwordlessAuth: PasswordlessAuth) {
} }
} }
} }
}

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

View File

@@ -18,13 +18,12 @@ 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) }
@@ -45,3 +44,4 @@ fun Route.changeMyPassword(voter: CitizenVoter, userRepository: UserRepository)
} }
} }
} }
}

View File

@@ -13,6 +13,7 @@ import io.ktor.response.respond
import io.ktor.routing.Route import io.ktor.routing.Route
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object FindCitizens {
@Location("/citizens") @Location("/citizens")
class CitizensRequest( class CitizensRequest(
page: Int = 1, page: Int = 1,
@@ -25,7 +26,6 @@ class CitizensRequest(
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)
@@ -33,3 +33,4 @@ fun Route.findCitizen(voter: CitizenVoter, repo: CitizenRepository) {
call.respond(citizens) call.respond(citizens)
} }
} }
}

View File

@@ -13,10 +13,10 @@ import io.ktor.response.respond
import io.ktor.routing.Route import io.ktor.routing.Route
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object GetCurrentCitizen {
@Location("/citizens/current") @Location("/citizens/current")
class CurrentCitizenRequest class CurrentCitizenRequest
@KtorExperimentalLocationsAPI
fun Route.getCurrentCitizen(voter: CitizenVoter) { fun Route.getCurrentCitizen(voter: CitizenVoter) {
get<CurrentCitizenRequest> { get<CurrentCitizenRequest> {
val currentUser = citizenOrNull val currentUser = citizenOrNull
@@ -28,3 +28,4 @@ fun Route.getCurrentCitizen(voter: CitizenVoter) {
} }
} }
} }
}

View File

@@ -12,10 +12,10 @@ import io.ktor.response.respond
import io.ktor.routing.Route import io.ktor.routing.Route
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object GetOneCitizen {
@Location("/citizens/{citizen}") @Location("/citizens/{citizen}")
class CitizenRequest(val citizen: 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) }
@@ -23,3 +23,4 @@ fun Route.getOneCitizen(voter: CitizenVoter) {
call.respond(it.citizen) call.respond(it.citizen)
} }
} }
}

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

View File

@@ -18,6 +18,7 @@ import io.ktor.response.respond
import io.ktor.routing.Route import io.ktor.routing.Route
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object CreateCommentArticle {
@Location("/articles/{article}/comments") @Location("/articles/{article}/comments")
class PostArticleCommentRequest( class PostArticleCommentRequest(
val article: ArticleForView val article: ArticleForView
@@ -35,7 +36,6 @@ class PostArticleCommentRequest(
} }
} }
@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 ->
@@ -45,3 +45,4 @@ fun Route.createCommentArticle(repo: CommentArticleRepository, voter: CommentVot
} }
} }
} }
}

View File

@@ -14,6 +14,7 @@ import io.ktor.response.respond
import io.ktor.routing.Route import io.ktor.routing.Route
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object GetArticleComments {
@Location("/articles/{article}/comments") @Location("/articles/{article}/comments")
class ArticleCommentsRequest( class ArticleCommentsRequest(
val article: ArticleRef, val article: ArticleRef,
@@ -27,7 +28,6 @@ class ArticleCommentsRequest(
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)
@@ -37,3 +37,4 @@ fun Route.getArticleComments(repo: CommentArticleRepository, voter: CommentVoter
call.respond(HttpStatusCode.OK, comment) call.respond(HttpStatusCode.OK, comment)
} }
} }
}

View File

@@ -13,10 +13,10 @@ import io.ktor.response.respond
import io.ktor.routing.Route import io.ktor.routing.Route
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object GetCitizenArticleComments {
@Location("/citizens/{citizen}/comments/articles") @Location("/citizens/{citizen}/comments/articles")
class CitizenCommentArticleRequest(val citizen: Citizen) 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 ->
@@ -25,3 +25,4 @@ fun Route.getCitizenArticleComments(repo: CommentArticleRepository, voter: Comme
} }
} }
} }
}

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

View File

@@ -19,13 +19,12 @@ import io.ktor.routing.Route
import io.ktor.util.KtorExperimentalAPI import io.ktor.util.KtorExperimentalAPI
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object CreateCommentChildren {
@Location("/comments/{comment}/children") @Location("/comments/{comment}/children")
class CreateCommentChildrenRequest(val comment: CommentRef) { class CreateCommentChildrenRequest(val comment: CommentRef) {
class Input(val content: String) class Input(val content: String)
} }
@KtorExperimentalAPI
@KtorExperimentalLocationsAPI
fun Route.createCommentChildren(repo: CommentRepository, voter: CommentVoter) { 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")
@@ -41,3 +40,4 @@ fun Route.createCommentChildren(repo: CommentRepository, voter: CommentVoter) {
call.respond(HttpStatusCode.Created, newComment) call.respond(HttpStatusCode.Created, newComment)
} }
} }
}

View File

@@ -14,14 +14,12 @@ 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
object EditComment {
@Location("/comments/{comment}") @Location("/comments/{comment}")
class EditCommentRequest(val comment: CommentRef) class EditCommentRequest(val comment: CommentRef)
@KtorExperimentalAPI
@KtorExperimentalLocationsAPI
fun Route.editComment(repo: CommentRepository, voter: CommentVoter) { 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")
@@ -33,3 +31,4 @@ fun Route.editComment(repo: CommentRepository, voter: CommentVoter) {
call.respond(HttpStatusCode.OK, comment) call.respond(HttpStatusCode.OK, comment)
} }
} }
}

View File

@@ -15,6 +15,7 @@ import io.ktor.util.KtorExperimentalAPI
import java.util.UUID import java.util.UUID
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object GetCommentChildren {
@Location("/comments/{comment}/children") @Location("/comments/{comment}/children")
class CommentChildrenRequest( class CommentChildrenRequest(
val comment: UUID, val comment: UUID,
@@ -26,8 +27,6 @@ class CommentChildrenRequest(
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
@KtorExperimentalLocationsAPI
fun Route.getChildrenComments(repo: CommentRepository, voter: CommentVoter) { fun Route.getChildrenComments(repo: CommentRepository, voter: CommentVoter) {
get<CommentChildrenRequest> { get<CommentChildrenRequest> {
val comments = val comments =
@@ -42,3 +41,4 @@ fun Route.getChildrenComments(repo: CommentRepository, voter: CommentVoter) {
call.respond(HttpStatusCode.OK, comments) call.respond(HttpStatusCode.OK, comments)
} }
} }
}

View File

@@ -16,11 +16,10 @@ import io.ktor.routing.Route
import io.ktor.util.KtorExperimentalAPI import io.ktor.util.KtorExperimentalAPI
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object GetOneComment {
@Location("/comments/{comment}") @Location("/comments/{comment}")
class CommentRequest(val comment: CommentRef) class CommentRequest(val comment: CommentRef)
@KtorExperimentalAPI
@KtorExperimentalLocationsAPI
fun Route.getOneComment(repo: CommentRepository, voter: CommentVoter) { 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")
@@ -29,3 +28,4 @@ fun Route.getOneComment(repo: CommentRepository, voter: CommentVoter) {
call.respond(HttpStatusCode.OK, comment) call.respond(HttpStatusCode.OK, comment)
} }
} }
}

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