Clean code

This commit is contained in:
2020-01-28 22:35:50 +01:00
parent 813d6857e9
commit 41a98f23b8
24 changed files with 169 additions and 69 deletions

View File

@@ -78,7 +78,8 @@ fun Application.module(env: Env = PROD) {
convert<Article> { convert<Article> {
decode { values, _ -> decode { values, _ ->
values.singleOrNull()?.let { values.singleOrNull()?.let {
get<RepositoryArticle>().findById(UUID.fromString(it)) ?: throw InternalError("Article $values not found") get<RepositoryArticle>().findById(UUID.fromString(it))
?: throw InternalError("Article $values not found")
} ?: throw NotFoundException("Article $values not found") } ?: throw NotFoundException("Article $values not found")
} }
} }

View File

@@ -17,7 +17,8 @@ val ApplicationCall.citizen: CitizenEntity
get() = attributes.computeIfAbsent(citizenAttributeKey) { get() = attributes.computeIfAbsent(citizenAttributeKey) {
runBlocking { runBlocking {
val user = authentication.principal<UserI>() ?: throw ForbiddenException() val user = authentication.principal<UserI>() ?: throw ForbiddenException()
GlobalContext.get().koin.get<CitizenRepository>().findByUser(user) ?: throw ForbiddenException("Citizen not found for this user id \"${user.id}\"") GlobalContext.get().koin.get<CitizenRepository>().findByUser(user)
?: throw ForbiddenException("Citizen not found for this user id \"${user.id}\"")
} }
} }

View File

@@ -27,12 +27,22 @@ val Module = module {
single { config } single { config }
single { Connection(host = config.host, port = config.port, database = config.database, username = config.username, password = config.password) } single {
Connection(
host = config.host,
port = config.port,
database = config.database,
username = config.username,
password = config.password
)
}
single { Requester.RequesterFactory( single {
Requester.RequesterFactory(
connection = get(), connection = get(),
functionsDirectory = config.sqlFiles.resolve("functions") functionsDirectory = config.sqlFiles.resolve("functions")
).createRequester() } ).createRequester()
}
// TODO: create generic declaration // TODO: create generic declaration
single { UserRepository(get()) } single { UserRepository(get()) }

View File

@@ -1,4 +1,5 @@
package fr.dcproject.entity package fr.dcproject.entity
import fr.postgresjson.entity.immutable.* import fr.postgresjson.entity.immutable.*
import fr.postgresjson.entity.mutable.EntityDeletedAt import fr.postgresjson.entity.mutable.EntityDeletedAt
import fr.postgresjson.entity.mutable.EntityDeletedAtImp import fr.postgresjson.entity.mutable.EntityDeletedAtImp
@@ -62,6 +63,7 @@ interface ArticleSimpleI :
Votable { Votable {
var title: String var title: String
} }
interface ArticleBasicI : interface ArticleBasicI :
ArticleSimpleI { ArticleSimpleI {
var anonymous: Boolean var anonymous: Boolean

View File

@@ -1,4 +1,5 @@
package fr.dcproject.entity package fr.dcproject.entity
import java.util.* import java.util.*
class Follow<T : TargetI>( class Follow<T : TargetI>(

View File

@@ -46,5 +46,6 @@ class SsoManager(
class EmailNotFound(val email: String) : Exception() { class EmailNotFound(val email: String) : Exception() {
override val message: String = "No Citizen with this email : $email" override val message: String = "No Citizen with this email : $email"
} }
private fun noEmail(email: String): Nothing = throw EmailNotFound(email) private fun noEmail(email: String): Nothing = throw EmailNotFound(email)
} }

View File

@@ -36,7 +36,8 @@ abstract class Comment <T : TargetI>(override var requester: Requester) : Reposi
): Paginated<CommentEntity<T>> { ): Paginated<CommentEntity<T>> {
return requester.run { return requester.run {
getFunction("find_comments_by_parent") getFunction("find_comments_by_parent")
.select(page, limit, .select(
page, limit,
"parent_id" to parentId "parent_id" to parentId
) )
} }
@@ -57,7 +58,8 @@ abstract class Comment <T : TargetI>(override var requester: Requester) : Reposi
): Paginated<CommentEntity<T>> { ): Paginated<CommentEntity<T>> {
return requester.run { return requester.run {
getFunction("find_comments_by_target") getFunction("find_comments_by_target")
.select(page, limit, .select(
page, limit,
"target_id" to targetId "target_id" to targetId
) )
} }
@@ -96,7 +98,8 @@ class CommentGeneric(requester: Requester) : Comment<TargetRef>(requester) {
): Paginated<CommentEntity<TargetRef>> { ): Paginated<CommentEntity<TargetRef>> {
return requester.run { return requester.run {
getFunction("find_comments_by_citizen") getFunction("find_comments_by_citizen")
.select(page, limit, .select(
page, limit,
"created_by_id" to citizen.id "created_by_id" to citizen.id
) )
} }
@@ -117,7 +120,8 @@ class CommentArticle(requester: Requester) : Comment<ArticleRef>(requester) {
): Paginated<CommentEntity<ArticleRef>> { ): Paginated<CommentEntity<ArticleRef>> {
return requester.run { return requester.run {
getFunction("find_comments_by_citizen") getFunction("find_comments_by_citizen")
.select(page, limit, .select(
page, limit,
"created_by_id" to citizen.id, "created_by_id" to citizen.id,
"reference" to TargetI.getReference(ArticleRef::class) "reference" to TargetI.getReference(ArticleRef::class)
) )
@@ -139,7 +143,8 @@ class CommentConstitution(requester: Requester) : Comment<ConstitutionEntity>(re
): Paginated<CommentEntity<ConstitutionEntity>> { ): Paginated<CommentEntity<ConstitutionEntity>> {
return requester.run { return requester.run {
getFunction("find_comments_by_citizen") getFunction("find_comments_by_citizen")
.select(page, limit, .select(
page, limit,
"created_by_id" to citizen.id, "created_by_id" to citizen.id,
"reference" to TargetI.getReference(ConstitutionEntity::class) "reference" to TargetI.getReference(ConstitutionEntity::class)
) )

View File

@@ -25,7 +25,8 @@ open class Follow <T : TargetI>(override var requester: Requester) : RepositoryI
): Paginated<FollowEntity<T>> { ): Paginated<FollowEntity<T>> {
return requester.run { return requester.run {
getFunction("find_follows_by_citizen") getFunction("find_follows_by_citizen")
.select(page, limit, .select(
page, limit,
"created_by_id" to citizenId "created_by_id" to citizenId
) )
} }
@@ -60,7 +61,8 @@ class FollowArticle(requester: Requester) : Follow<ArticleEntity>(requester) {
): Paginated<FollowEntity<ArticleEntity>> { ): Paginated<FollowEntity<ArticleEntity>> {
return requester.run { return requester.run {
getFunction("find_follows_article_by_citizen") getFunction("find_follows_article_by_citizen")
.select(page, limit, .select(
page, limit,
"created_by_id" to citizenId "created_by_id" to citizenId
) )
} }
@@ -75,7 +77,8 @@ class FollowConstitution(requester: Requester) : Follow<ConstitutionEntity>(requ
): Paginated<FollowEntity<ConstitutionEntity>> { ): Paginated<FollowEntity<ConstitutionEntity>> {
return requester.run { return requester.run {
getFunction("find_follows_constitution_by_citizen") getFunction("find_follows_constitution_by_citizen")
.select(page, limit, .select(
page, limit,
"created_by_id" to citizenId "created_by_id" to citizenId
) )
} }

View File

@@ -36,10 +36,12 @@ open class Vote <T : TargetI>(override var requester: Requester) : RepositoryI {
): Paginated<VoteEntity<T>> { ): Paginated<VoteEntity<T>> {
return requester.run { return requester.run {
getFunction("find_votes_by_citizen") getFunction("find_votes_by_citizen")
.select(page, limit, typeReference, mapOf( .select(
page, limit, typeReference, mapOf(
"created_by_id" to citizenId, "created_by_id" to citizenId,
"reference" to target "reference" to target
)) )
)
} }
} }
@@ -50,10 +52,12 @@ open class Vote <T : TargetI>(override var requester: Requester) : RepositoryI {
val typeReference = object : TypeReference<List<VoteEntity<TargetRef>>>() {} val typeReference = object : TypeReference<List<VoteEntity<TargetRef>>>() {}
return requester.run { return requester.run {
getFunction("find_citizen_votes_by_target_ids") getFunction("find_citizen_votes_by_target_ids")
.select(typeReference, mapOf( .select(
typeReference, mapOf(
"citizen_id" to citizen.id, "citizen_id" to citizen.id,
"ids" to targets "ids" to targets
)) )
)
} }
} }
} }

View File

@@ -20,22 +20,44 @@ import fr.dcproject.repository.Article as ArticleRepository
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object ArticlesPaths { object ArticlesPaths {
@Location("/articles") class ArticlesRequest(page: Int = 1, limit: Int = 50, val sort: String? = null, val direction: RepositoryI.Direction? = null, val search: String? = null, val createdBy: String? = null) { @Location("/articles")
class ArticlesRequest(
page: Int = 1,
limit: Int = 50,
val sort: String? = null,
val direction: RepositoryI.Direction? = null,
val search: String? = null,
val createdBy: 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
} }
@Location("/articles/{article}") class ArticleRequest(val article: ArticleEntity)
@Location("/articles/{article}/versions") class ArticleVersionsRequest(val article: ArticleEntity, page: Int = 1, limit: Int = 50, val sort: String? = null, val direction: RepositoryI.Direction? = null, val search: String? = null) { @Location("/articles/{article}")
class ArticleRequest(val article: ArticleEntity)
@Location("/articles/{article}/versions")
class ArticleVersionsRequest(
val article: ArticleEntity,
page: Int = 1,
limit: Int = 50,
val sort: String? = null,
val direction: RepositoryI.Direction? = 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
} }
@Location("/articles") class PostArticleRequest
@Location("/articles")
class PostArticleRequest
} }
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
fun Route.article(repo: ArticleRepository) { fun Route.article(repo: ArticleRepository) {
get<ArticlesPaths.ArticlesRequest> { get<ArticlesPaths.ArticlesRequest> {
val articles = repo.find(it.page, it.limit, it.sort, it.direction, it.search, Filter(createdById = it.createdBy)) val articles =
repo.find(it.page, it.limit, it.sort, it.direction, it.search, Filter(createdById = it.createdBy))
assertCan(VIEW, articles.result) assertCan(VIEW, articles.result)
call.respond(articles) call.respond(articles)
} }

View File

@@ -26,9 +26,14 @@ import fr.dcproject.repository.User as UserRepository
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object AuthPaths { object AuthPaths {
@Location("/login") class LoginRequest @Location("/login")
@Location("/register") class RegisterRequest class LoginRequest
@Location("/sso") class SsoRequest {
@Location("/register")
class RegisterRequest
@Location("/sso")
class SsoRequest {
data class Content(val email: String, val url: String) data class Content(val email: String, val url: String)
} }
} }

View File

@@ -24,13 +24,26 @@ import fr.dcproject.repository.User as UserRepository
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object CitizenPaths { object CitizenPaths {
@Location("/citizens") class CitizensRequest(page: Int = 1, limit: Int = 50, val sort: String? = null, val direction: Direction? = null, val search: String? = null) { @Location("/citizens")
class CitizensRequest(
page: Int = 1,
limit: Int = 50,
val sort: String? = null,
val direction: Direction? = 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
} }
@Location("/citizens/{citizen}") class CitizenRequest(val citizen: Citizen)
@Location("/citizens/current") class CurrentCitizenRequest @Location("/citizens/{citizen}")
@Location("/citizens/{citizen}/password/change") class ChangePasswordCitizenRequest(val citizen: Citizen) { class CitizenRequest(val citizen: Citizen)
@Location("/citizens/current")
class CurrentCitizenRequest
@Location("/citizens/{citizen}/password/change")
class ChangePasswordCitizenRequest(val citizen: Citizen) {
data class Content(val password: String) data class Content(val password: String)
} }
} }

View File

@@ -20,7 +20,8 @@ import fr.dcproject.repository.CommentGeneric as CommentRepository
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object CommentPaths { object CommentPaths {
// TODO: change UUID by entity converter // TODO: change UUID by entity converter
@Location("/comments/{comment}") class CommentRequest(val comment: UUID) @Location("/comments/{comment}")
class CommentRequest(val comment: UUID)
@Location("/comments/{comment}/children") @Location("/comments/{comment}/children")
class CommentChildrenRequest( class CommentChildrenRequest(

View File

@@ -31,7 +31,9 @@ object CommentArticlePaths {
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
} }
@Location("/citizens/{citizen}/comments/articles") class CitizenCommentArticleRequest(val citizen: Citizen)
@Location("/citizens/{citizen}/comments/articles")
class CitizenCommentArticleRequest(val citizen: Citizen)
} }
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI

View File

@@ -20,8 +20,11 @@ import fr.dcproject.repository.CommentConstitution as CommentConstitutionReposit
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object CommentConstitutionPaths { object CommentConstitutionPaths {
@Location("/constitutions/{constitution}/comments") class ConstitutionCommentRequest(val constitution: ConstitutionEntity) @Location("/constitutions/{constitution}/comments")
@Location("/citizens/{citizen}/comments/constitutions") class CitizenCommentConstitutionRequest(val citizen: Citizen) class ConstitutionCommentRequest(val constitution: ConstitutionEntity)
@Location("/citizens/{citizen}/comments/constitutions")
class CitizenCommentConstitutionRequest(val citizen: Citizen)
} }
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI

View File

@@ -19,13 +19,26 @@ import fr.dcproject.repository.Constitution as ConstitutionRepository
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object ConstitutionPaths { object ConstitutionPaths {
@Location("/constitutions") class ConstitutionsRequest(page: Int = 1, limit: Int = 50, val sort: String? = null, val direction: RepositoryI.Direction? = null, val search: String? = null) { @Location("/constitutions")
class ConstitutionsRequest(
page: Int = 1,
limit: Int = 50,
val sort: String? = null,
val direction: RepositoryI.Direction? = 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
} }
@Location("/constitutions/{constitution}") class ConstitutionRequest(val constitution: ConstitutionEntity)
@Location("/constitutions/{constitution}/follow") class ConstitutionFollowRequest(val constitution: ConstitutionEntity) @Location("/constitutions/{constitution}")
@Location("/constitutions") class PostConstitutionRequest class ConstitutionRequest(val constitution: ConstitutionEntity)
@Location("/constitutions/{constitution}/follow")
class ConstitutionFollowRequest(val constitution: ConstitutionEntity)
@Location("/constitutions")
class PostConstitutionRequest
} }
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI

View File

@@ -15,8 +15,11 @@ import fr.dcproject.repository.FollowArticle as FollowArticleRepository
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object FollowArticlePaths { object FollowArticlePaths {
@Location("/articles/{article}/follows") class ArticleFollowRequest(val article: ArticleEntity) @Location("/articles/{article}/follows")
@Location("/citizens/{citizen}/follows/articles") class CitizenFollowArticleRequest(val citizen: Citizen) class ArticleFollowRequest(val article: ArticleEntity)
@Location("/citizens/{citizen}/follows/articles")
class CitizenFollowArticleRequest(val citizen: Citizen)
} }
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI

View File

@@ -15,8 +15,11 @@ import fr.dcproject.repository.FollowConstitution as FollowConstitutionRepositor
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object FollowConstitutionPaths { object FollowConstitutionPaths {
@Location("/constitutions/{constitution}/follow") class ConstitutionFollowRequest(val constitution: ConstitutionEntity) @Location("/constitutions/{constitution}/follow")
@Location("/citizens/{citizen}/follows/constitutions") class CitizenFollowConstitutionRequest(val citizen: Citizen) class ConstitutionFollowRequest(val constitution: ConstitutionEntity)
@Location("/citizens/{citizen}/follows/constitutions")
class CitizenFollowConstitutionRequest(val citizen: Citizen)
} }
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI

View File

@@ -19,10 +19,13 @@ import fr.dcproject.repository.VoteConstitution as VoteConstitutionRepository
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object VoteConstitutionPaths { object VoteConstitutionPaths {
@Location("/constitutions/{constitution}/vote") class ConstitutionVoteRequest(val constitution: ConstitutionEntity) { @Location("/constitutions/{constitution}/vote")
class ConstitutionVoteRequest(val constitution: ConstitutionEntity) {
data class Content(var note: Int) data class Content(var note: Int)
} }
@Location("/citizens/{citizen}/votes/constitutions") class CitizenVoteConstitutionRequest(val citizen: Citizen)
@Location("/citizens/{citizen}/votes/constitutions")
class CitizenVoteConstitutionRequest(val citizen: Citizen)
} }
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI

View File

@@ -50,7 +50,8 @@ class CitizenVoter : Voter {
if (action == Action.UPDATE && if (action == Action.UPDATE &&
user is UserI && user is UserI &&
subject is CitizenBasicI && subject is CitizenBasicI &&
subject.user.id == user.id) { subject.user.id == user.id
) {
return Vote.GRANTED return Vote.GRANTED
} }

View File

@@ -78,7 +78,10 @@ class AuthorizationVoter {
override val key = AttributeKey<AuthorizationVoter>("Voter") override val key = AttributeKey<AuthorizationVoter>("Voter")
@KtorExperimentalAPI @KtorExperimentalAPI
override fun install(pipeline: ApplicationCallPipeline, configure: Configuration.() -> Unit): AuthorizationVoter { override fun install(
pipeline: ApplicationCallPipeline,
configure: Configuration.() -> Unit
): AuthorizationVoter {
val configuration = Configuration().apply(configure) val configuration = Configuration().apply(configure)
pipeline.intercept(ApplicationCallPipeline.Features) { pipeline.intercept(ApplicationCallPipeline.Features) {