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> {
decode { values, _ ->
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")
}
}

View File

@@ -17,7 +17,8 @@ val ApplicationCall.citizen: CitizenEntity
get() = attributes.computeIfAbsent(citizenAttributeKey) {
runBlocking {
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 { 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(),
functionsDirectory = config.sqlFiles.resolve("functions")
).createRequester() }
).createRequester()
}
// TODO: create generic declaration
single { UserRepository(get()) }

View File

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

View File

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

View File

@@ -46,5 +46,6 @@ class SsoManager(
class EmailNotFound(val email: String) : Exception() {
override val message: String = "No Citizen with this email : $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>> {
return requester.run {
getFunction("find_comments_by_parent")
.select(page, limit,
.select(
page, limit,
"parent_id" to parentId
)
}
@@ -57,7 +58,8 @@ abstract class Comment <T : TargetI>(override var requester: Requester) : Reposi
): Paginated<CommentEntity<T>> {
return requester.run {
getFunction("find_comments_by_target")
.select(page, limit,
.select(
page, limit,
"target_id" to targetId
)
}
@@ -96,7 +98,8 @@ class CommentGeneric(requester: Requester) : Comment<TargetRef>(requester) {
): Paginated<CommentEntity<TargetRef>> {
return requester.run {
getFunction("find_comments_by_citizen")
.select(page, limit,
.select(
page, limit,
"created_by_id" to citizen.id
)
}
@@ -117,7 +120,8 @@ class CommentArticle(requester: Requester) : Comment<ArticleRef>(requester) {
): Paginated<CommentEntity<ArticleRef>> {
return requester.run {
getFunction("find_comments_by_citizen")
.select(page, limit,
.select(
page, limit,
"created_by_id" to citizen.id,
"reference" to TargetI.getReference(ArticleRef::class)
)
@@ -139,7 +143,8 @@ class CommentConstitution(requester: Requester) : Comment<ConstitutionEntity>(re
): Paginated<CommentEntity<ConstitutionEntity>> {
return requester.run {
getFunction("find_comments_by_citizen")
.select(page, limit,
.select(
page, limit,
"created_by_id" to citizen.id,
"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>> {
return requester.run {
getFunction("find_follows_by_citizen")
.select(page, limit,
.select(
page, limit,
"created_by_id" to citizenId
)
}
@@ -60,7 +61,8 @@ class FollowArticle(requester: Requester) : Follow<ArticleEntity>(requester) {
): Paginated<FollowEntity<ArticleEntity>> {
return requester.run {
getFunction("find_follows_article_by_citizen")
.select(page, limit,
.select(
page, limit,
"created_by_id" to citizenId
)
}
@@ -75,7 +77,8 @@ class FollowConstitution(requester: Requester) : Follow<ConstitutionEntity>(requ
): Paginated<FollowEntity<ConstitutionEntity>> {
return requester.run {
getFunction("find_follows_constitution_by_citizen")
.select(page, limit,
.select(
page, limit,
"created_by_id" to citizenId
)
}

View File

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

View File

@@ -20,22 +20,44 @@ import fr.dcproject.repository.Article as ArticleRepository
@KtorExperimentalLocationsAPI
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 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 limit: Int = if (limit > 50) 50 else if (limit < 1) 1 else limit
}
@Location("/articles") class PostArticleRequest
@Location("/articles")
class PostArticleRequest
}
@KtorExperimentalLocationsAPI
fun Route.article(repo: ArticleRepository) {
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)
call.respond(articles)
}

View File

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

View File

@@ -24,13 +24,26 @@ import fr.dcproject.repository.User as UserRepository
@KtorExperimentalLocationsAPI
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 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}/password/change") class ChangePasswordCitizenRequest(val citizen: Citizen) {
@Location("/citizens/{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)
}
}

View File

@@ -20,7 +20,8 @@ import fr.dcproject.repository.CommentGeneric as CommentRepository
@KtorExperimentalLocationsAPI
object CommentPaths {
// 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")
class CommentChildrenRequest(

View File

@@ -31,7 +31,9 @@ object CommentArticlePaths {
val page: Int = if (page < 1) 1 else page
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

View File

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

View File

@@ -19,13 +19,26 @@ import fr.dcproject.repository.Constitution as ConstitutionRepository
@KtorExperimentalLocationsAPI
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 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") class PostConstitutionRequest
@Location("/constitutions/{constitution}")
class ConstitutionRequest(val constitution: ConstitutionEntity)
@Location("/constitutions/{constitution}/follow")
class ConstitutionFollowRequest(val constitution: ConstitutionEntity)
@Location("/constitutions")
class PostConstitutionRequest
}
@KtorExperimentalLocationsAPI

View File

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

View File

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

View File

@@ -19,10 +19,13 @@ import fr.dcproject.repository.VoteConstitution as VoteConstitutionRepository
@KtorExperimentalLocationsAPI
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)
}
@Location("/citizens/{citizen}/votes/constitutions") class CitizenVoteConstitutionRequest(val citizen: Citizen)
@Location("/citizens/{citizen}/votes/constitutions")
class CitizenVoteConstitutionRequest(val citizen: Citizen)
}
@KtorExperimentalLocationsAPI

View File

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

View File

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