Big refactoring #77
@@ -8,22 +8,31 @@ import com.fasterxml.jackson.databind.SerializationFeature
|
||||
import com.fasterxml.jackson.datatype.joda.JodaModule
|
||||
import com.github.jasync.sql.db.postgresql.exceptions.GenericDatabaseException
|
||||
import fr.dcproject.application.Env.PROD
|
||||
import fr.dcproject.component.article.articleKoinModule
|
||||
import fr.dcproject.component.article.routes.installArticleRoutes
|
||||
import fr.dcproject.component.auth.ForbiddenException
|
||||
import fr.dcproject.component.auth.authKoinModule
|
||||
import fr.dcproject.component.auth.jwt.jwtInstallation
|
||||
import fr.dcproject.component.auth.routes.installAuthRoutes
|
||||
import fr.dcproject.component.auth.user
|
||||
import fr.dcproject.component.citizen.citizenKoinModule
|
||||
import fr.dcproject.component.citizen.routes.installCitizenRoutes
|
||||
import fr.dcproject.component.comment.article.routes.installCommentArticleRoutes
|
||||
import fr.dcproject.component.comment.commentKoinModule
|
||||
import fr.dcproject.component.comment.constitution.routes.installCommentConstitutionRoutes
|
||||
import fr.dcproject.component.comment.generic.routes.installCommentRoutes
|
||||
import fr.dcproject.component.constitution.constitutionKoinModule
|
||||
import fr.dcproject.component.constitution.routes.installConstitutionRoutes
|
||||
import fr.dcproject.component.follow.followKoinModule
|
||||
import fr.dcproject.component.follow.routes.article.installFollowArticleRoutes
|
||||
import fr.dcproject.component.follow.routes.constitution.installFollowConstitutionRoutes
|
||||
import fr.dcproject.component.opinion.opinionKoinModule
|
||||
import fr.dcproject.component.opinion.routes.installOpinionRoutes
|
||||
import fr.dcproject.component.views.ConfigViews
|
||||
import fr.dcproject.component.views.viewKoinModule
|
||||
import fr.dcproject.component.vote.routes.installVoteRoutes
|
||||
import fr.dcproject.component.vote.voteKoinModule
|
||||
import fr.dcproject.component.workgroup.routes.installWorkgroupRoutes
|
||||
import fr.dcproject.component.workgroup.workgroupKoinModule
|
||||
import fr.dcproject.event.EventNotification
|
||||
import fr.dcproject.event.EventSubscriber
|
||||
import fr.dcproject.routes.definition
|
||||
@@ -78,7 +87,21 @@ enum class Env { PROD, TEST, CUCUMBER }
|
||||
fun Application.module(env: Env = PROD) {
|
||||
install(Koin) {
|
||||
Slf4jLog()
|
||||
modules(KoinModule)
|
||||
modules(
|
||||
listOf(
|
||||
KoinModule,
|
||||
articleKoinModule,
|
||||
authKoinModule,
|
||||
citizenKoinModule,
|
||||
commentKoinModule,
|
||||
constitutionKoinModule,
|
||||
followKoinModule,
|
||||
opinionKoinModule,
|
||||
viewKoinModule,
|
||||
voteKoinModule,
|
||||
workgroupKoinModule,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
install(CallLogging) {
|
||||
@@ -94,8 +117,6 @@ fun Application.module(env: Env = PROD) {
|
||||
}
|
||||
}
|
||||
|
||||
ConfigViews.createEsIndexForViews(get())
|
||||
|
||||
install(WebSockets) {
|
||||
pingPeriod = Duration.ofSeconds(60) // Disabled (null) by default
|
||||
timeout = Duration.ofSeconds(15)
|
||||
|
||||
@@ -8,30 +8,6 @@ import com.fasterxml.jackson.databind.module.SimpleModule
|
||||
import com.fasterxml.jackson.datatype.joda.JodaModule
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import com.rabbitmq.client.ConnectionFactory
|
||||
import fr.dcproject.component.article.ArticleAccessControl
|
||||
import fr.dcproject.component.article.ArticleForView
|
||||
import fr.dcproject.component.article.ArticleRepository
|
||||
import fr.dcproject.component.article.ArticleViewManager
|
||||
import fr.dcproject.component.auth.PasswordlessAuth
|
||||
import fr.dcproject.component.auth.UserRepository
|
||||
import fr.dcproject.component.citizen.CitizenAccessControl
|
||||
import fr.dcproject.component.citizen.CitizenRepository
|
||||
import fr.dcproject.component.comment.article.CommentArticleRepository
|
||||
import fr.dcproject.component.comment.constitution.CommentConstitutionRepository
|
||||
import fr.dcproject.component.comment.generic.CommentAccessControl
|
||||
import fr.dcproject.component.constitution.ConstitutionAccessControl
|
||||
import fr.dcproject.component.constitution.ConstitutionRepository
|
||||
import fr.dcproject.component.follow.FollowAccessControl
|
||||
import fr.dcproject.component.opinion.OpinionAccessControl
|
||||
import fr.dcproject.component.opinion.OpinionChoiceAccessControl
|
||||
import fr.dcproject.component.opinion.OpinionChoiceRepository
|
||||
import fr.dcproject.component.vote.VoteAccessControl
|
||||
import fr.dcproject.component.vote.VoteArticleRepository
|
||||
import fr.dcproject.component.vote.VoteCommentRepository
|
||||
import fr.dcproject.component.vote.VoteConstitutionRepository
|
||||
import fr.dcproject.component.vote.VoteRepository
|
||||
import fr.dcproject.component.workgroup.WorkgroupAccessControl
|
||||
import fr.dcproject.component.workgroup.WorkgroupRepository
|
||||
import fr.dcproject.event.publisher.Publisher
|
||||
import fr.dcproject.messages.Mailer
|
||||
import fr.dcproject.messages.NotificationEmailSender
|
||||
@@ -43,14 +19,8 @@ import io.ktor.client.features.websocket.WebSockets
|
||||
import io.ktor.util.KtorExperimentalAPI
|
||||
import io.lettuce.core.RedisClient
|
||||
import io.lettuce.core.api.async.RedisAsyncCommands
|
||||
import org.apache.http.HttpHost
|
||||
import org.elasticsearch.client.RestClient
|
||||
import org.koin.core.qualifier.named
|
||||
import org.koin.dsl.module
|
||||
import fr.dcproject.component.comment.generic.CommentRepository as CommentGenericRepository
|
||||
import fr.dcproject.component.follow.FollowArticleRepository as FollowArticleRepository
|
||||
import fr.dcproject.component.follow.FollowConstitutionRepository as FollowConstitutionRepository
|
||||
import fr.dcproject.component.opinion.OpinionRepositoryArticle as OpinionArticleRepository
|
||||
|
||||
@KtorExperimentalAPI
|
||||
val KoinModule = module {
|
||||
@@ -105,50 +75,9 @@ val KoinModule = module {
|
||||
).createRequester()
|
||||
}
|
||||
|
||||
// Repositories
|
||||
single { UserRepository(get()) }
|
||||
single { ArticleRepository(get()) }
|
||||
single { CitizenRepository(get()) }
|
||||
single { ConstitutionRepository(get()) }
|
||||
single { FollowArticleRepository(get()) }
|
||||
single { FollowConstitutionRepository(get()) }
|
||||
single { CommentGenericRepository(get()) }
|
||||
single { CommentArticleRepository(get()) }
|
||||
single { CommentConstitutionRepository(get()) }
|
||||
single { VoteRepository(get()) }
|
||||
single { VoteArticleRepository(get()) }
|
||||
single { VoteConstitutionRepository(get()) }
|
||||
single { VoteCommentRepository(get()) }
|
||||
single { OpinionChoiceRepository(get()) }
|
||||
single { OpinionArticleRepository(get()) }
|
||||
single { WorkgroupRepository(get()) }
|
||||
|
||||
// AccessControl
|
||||
single { ArticleAccessControl(get()) }
|
||||
single { CitizenAccessControl() }
|
||||
single { CommentAccessControl() }
|
||||
single { WorkgroupAccessControl() }
|
||||
single { ConstitutionAccessControl() }
|
||||
single { VoteAccessControl() }
|
||||
single { FollowAccessControl() }
|
||||
single { OpinionAccessControl() }
|
||||
single { OpinionChoiceAccessControl() }
|
||||
|
||||
// Elasticsearch Client
|
||||
single<RestClient> {
|
||||
RestClient.builder(
|
||||
HttpHost.create(Configuration.elasticsearch)
|
||||
).build()
|
||||
}
|
||||
|
||||
single { ArticleViewManager<ArticleForView>(get()) }
|
||||
|
||||
// Mailer
|
||||
single { Mailer(Configuration.sendGridKey) }
|
||||
|
||||
// Used to send a connexion link by email
|
||||
single { PasswordlessAuth(get<Mailer>(), Configuration.domain, get()) }
|
||||
|
||||
single { Publisher(get(), get(), exchangeName = Configuration.exchangeNotificationName) }
|
||||
|
||||
single { NotificationEmailSender(get<Mailer>(), Configuration.domain, get(), get()) }
|
||||
|
||||
8
src/main/kotlin/component/article/KoinModule.kt
Normal file
8
src/main/kotlin/component/article/KoinModule.kt
Normal file
@@ -0,0 +1,8 @@
|
||||
package fr.dcproject.component.article
|
||||
|
||||
import org.koin.dsl.module
|
||||
|
||||
val articleKoinModule = module {
|
||||
single { ArticleRepository(get()) }
|
||||
single { ArticleAccessControl(get()) }
|
||||
}
|
||||
11
src/main/kotlin/component/auth/KoinModule.kt
Normal file
11
src/main/kotlin/component/auth/KoinModule.kt
Normal file
@@ -0,0 +1,11 @@
|
||||
package fr.dcproject.component.auth
|
||||
|
||||
import fr.dcproject.application.Configuration
|
||||
import fr.dcproject.messages.Mailer
|
||||
import org.koin.dsl.module
|
||||
|
||||
val authKoinModule = module {
|
||||
single { UserRepository(get()) }
|
||||
// Used to send a connexion link by email
|
||||
single { PasswordlessAuth(get<Mailer>(), Configuration.domain, get()) }
|
||||
}
|
||||
8
src/main/kotlin/component/citizen/KoinModule.kt
Normal file
8
src/main/kotlin/component/citizen/KoinModule.kt
Normal file
@@ -0,0 +1,8 @@
|
||||
package fr.dcproject.component.citizen
|
||||
|
||||
import org.koin.dsl.module
|
||||
|
||||
val citizenKoinModule = module {
|
||||
single { CitizenRepository(get()) }
|
||||
single { CitizenAccessControl() }
|
||||
}
|
||||
14
src/main/kotlin/component/comment/KoinModule.kt
Normal file
14
src/main/kotlin/component/comment/KoinModule.kt
Normal file
@@ -0,0 +1,14 @@
|
||||
package fr.dcproject.component.comment
|
||||
|
||||
import fr.dcproject.component.comment.article.CommentArticleRepository
|
||||
import fr.dcproject.component.comment.constitution.CommentConstitutionRepository
|
||||
import fr.dcproject.component.comment.generic.CommentAccessControl
|
||||
import fr.dcproject.component.comment.generic.CommentRepository
|
||||
import org.koin.dsl.module
|
||||
|
||||
val commentKoinModule = module {
|
||||
single { CommentRepository(get()) }
|
||||
single { CommentArticleRepository(get()) }
|
||||
single { CommentConstitutionRepository(get()) }
|
||||
single { CommentAccessControl() }
|
||||
}
|
||||
8
src/main/kotlin/component/constitution/KoinModule.kt
Normal file
8
src/main/kotlin/component/constitution/KoinModule.kt
Normal file
@@ -0,0 +1,8 @@
|
||||
package fr.dcproject.component.constitution
|
||||
|
||||
import org.koin.dsl.module
|
||||
|
||||
val constitutionKoinModule = module {
|
||||
single { ConstitutionRepository(get()) }
|
||||
single { ConstitutionAccessControl() }
|
||||
}
|
||||
9
src/main/kotlin/component/follow/KoinModule.kt
Normal file
9
src/main/kotlin/component/follow/KoinModule.kt
Normal file
@@ -0,0 +1,9 @@
|
||||
package fr.dcproject.component.follow
|
||||
|
||||
import org.koin.dsl.module
|
||||
|
||||
val followKoinModule = module {
|
||||
single { FollowArticleRepository(get()) }
|
||||
single { FollowConstitutionRepository(get()) }
|
||||
single { FollowAccessControl() }
|
||||
}
|
||||
11
src/main/kotlin/component/opinion/KoinModule.kt
Normal file
11
src/main/kotlin/component/opinion/KoinModule.kt
Normal file
@@ -0,0 +1,11 @@
|
||||
package fr.dcproject.component.opinion
|
||||
|
||||
import org.koin.dsl.module
|
||||
|
||||
val opinionKoinModule = module {
|
||||
single { OpinionChoiceRepository(get()) }
|
||||
single { OpinionRepositoryArticle(get()) }
|
||||
|
||||
single { OpinionAccessControl() }
|
||||
single { OpinionChoiceAccessControl() }
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
package fr.dcproject.component.views
|
||||
|
||||
import org.elasticsearch.client.Request
|
||||
import org.elasticsearch.client.RestClient
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
object ConfigViews {
|
||||
private fun waitElasticsearchIsUp(client: RestClient) {
|
||||
val logger: Logger = LoggerFactory.getLogger("fr.dcproject.elasticsearch")
|
||||
val request = Request("GET", "/_cluster/health")
|
||||
repeat(5 * 60 / 2) { // 5 minutes
|
||||
runCatching {
|
||||
client.performRequest(request).statusLine.statusCode
|
||||
}.onSuccess {
|
||||
if (it == 200) {
|
||||
logger.debug("Elasticsearch is Ready! Continue...")
|
||||
return
|
||||
} else {
|
||||
logger.debug("sleep 2s and retry...")
|
||||
Thread.sleep(2000)
|
||||
}
|
||||
}.onFailure {
|
||||
logger.debug("${it.message}, sleep 2s and retry...")
|
||||
Thread.sleep(2000)
|
||||
}
|
||||
}
|
||||
error("Elasticsearch is not ready")
|
||||
}
|
||||
|
||||
fun createEsIndexForViews(client: RestClient) {
|
||||
waitElasticsearchIsUp(client)
|
||||
|
||||
/* Create index if not exist */
|
||||
client.run {
|
||||
if (performRequest(Request("HEAD", "/views?include_type_name=false")).statusLine.statusCode == 404) {
|
||||
Request(
|
||||
"PUT",
|
||||
"/views?include_type_name=false"
|
||||
).apply {
|
||||
//language=JSON
|
||||
setJsonEntity(
|
||||
"""
|
||||
{
|
||||
"settings": {
|
||||
"number_of_shards": 5
|
||||
},
|
||||
"mappings": {
|
||||
"properties": {
|
||||
"logged": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"type": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"user_ref": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"version_id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"ip": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"citizen_id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"view_at": {
|
||||
"type": "date"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
}.let {
|
||||
performRequest(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
src/main/kotlin/component/views/KoinModule.kt
Normal file
19
src/main/kotlin/component/views/KoinModule.kt
Normal file
@@ -0,0 +1,19 @@
|
||||
package fr.dcproject.component.views
|
||||
|
||||
import fr.dcproject.application.Configuration
|
||||
import fr.dcproject.component.article.ArticleForView
|
||||
import fr.dcproject.component.article.ArticleViewManager
|
||||
import org.apache.http.HttpHost
|
||||
import org.elasticsearch.client.RestClient
|
||||
import org.koin.dsl.module
|
||||
|
||||
val viewKoinModule = module {
|
||||
// Elasticsearch Client
|
||||
val esClient = RestClient.builder(
|
||||
HttpHost.create(Configuration.elasticsearch)
|
||||
).build().apply {
|
||||
createEsIndexForViews()
|
||||
}
|
||||
|
||||
single { ArticleViewManager<ArticleForView>(esClient) }
|
||||
}
|
||||
58
src/main/kotlin/component/views/createEsIndexForViews.kt
Normal file
58
src/main/kotlin/component/views/createEsIndexForViews.kt
Normal file
@@ -0,0 +1,58 @@
|
||||
package fr.dcproject.component.views
|
||||
|
||||
import fr.dcproject.utils.waitElasticsearchIsUp
|
||||
import org.elasticsearch.client.Request
|
||||
import org.elasticsearch.client.RestClient
|
||||
|
||||
fun RestClient.createEsIndexForViews() {
|
||||
waitElasticsearchIsUp()
|
||||
|
||||
/* Create index if not exist */
|
||||
if (performRequest(Request("HEAD", "/views?include_type_name=false")).statusLine.statusCode == 404) {
|
||||
Request(
|
||||
"PUT",
|
||||
"/views?include_type_name=false"
|
||||
).apply {
|
||||
//language=JSON
|
||||
setJsonEntity(
|
||||
"""
|
||||
{
|
||||
"settings": {
|
||||
"number_of_shards": 5
|
||||
},
|
||||
"mappings": {
|
||||
"properties": {
|
||||
"logged": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"type": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"user_ref": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"version_id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"ip": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"citizen_id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"view_at": {
|
||||
"type": "date"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
}.let {
|
||||
performRequest(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
12
src/main/kotlin/component/vote/KoinModule.kt
Normal file
12
src/main/kotlin/component/vote/KoinModule.kt
Normal file
@@ -0,0 +1,12 @@
|
||||
package fr.dcproject.component.vote
|
||||
|
||||
import org.koin.dsl.module
|
||||
|
||||
val voteKoinModule = module {
|
||||
single { VoteRepository(get()) }
|
||||
single { VoteArticleRepository(get()) }
|
||||
single { VoteConstitutionRepository(get()) }
|
||||
single { VoteCommentRepository(get()) }
|
||||
|
||||
single { VoteAccessControl() }
|
||||
}
|
||||
8
src/main/kotlin/component/workgroup/KoinModule.kt
Normal file
8
src/main/kotlin/component/workgroup/KoinModule.kt
Normal file
@@ -0,0 +1,8 @@
|
||||
package fr.dcproject.component.workgroup
|
||||
|
||||
import org.koin.dsl.module
|
||||
|
||||
val workgroupKoinModule = module {
|
||||
single { WorkgroupRepository(get()) }
|
||||
single { WorkgroupAccessControl() }
|
||||
}
|
||||
28
src/main/kotlin/utils/waitElastic.kt
Normal file
28
src/main/kotlin/utils/waitElastic.kt
Normal file
@@ -0,0 +1,28 @@
|
||||
package fr.dcproject.utils
|
||||
|
||||
import org.elasticsearch.client.Request
|
||||
import org.elasticsearch.client.RestClient
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
fun RestClient.waitElasticsearchIsUp() {
|
||||
val logger: Logger = LoggerFactory.getLogger("fr.dcproject.elasticsearch")
|
||||
val request = Request("GET", "/_cluster/health")
|
||||
repeat(5 * 60 / 2) { // 5 minutes
|
||||
runCatching {
|
||||
performRequest(request).statusLine.statusCode
|
||||
}.onSuccess {
|
||||
if (it == 200) {
|
||||
logger.debug("Elasticsearch is Ready! Continue...")
|
||||
return
|
||||
} else {
|
||||
logger.debug("sleep 2s and retry...")
|
||||
Thread.sleep(2000)
|
||||
}
|
||||
}.onFailure {
|
||||
logger.debug("${it.message}, sleep 2s and retry...")
|
||||
Thread.sleep(2000)
|
||||
}
|
||||
}
|
||||
error("Elasticsearch is not ready")
|
||||
}
|
||||
Reference in New Issue
Block a user