Big refactoring #77
3
.idea/codeStyles/Project.xml
generated
3
.idea/codeStyles/Project.xml
generated
@@ -18,6 +18,8 @@
|
|||||||
<package name="" alias="true" withSubpackages="true" />
|
<package name="" alias="true" withSubpackages="true" />
|
||||||
</value>
|
</value>
|
||||||
</option>
|
</option>
|
||||||
|
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
|
||||||
|
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
|
||||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
</JetCodeStyleSettings>
|
</JetCodeStyleSettings>
|
||||||
<PostgresCodeStyleSettings version="2">
|
<PostgresCodeStyleSettings version="2">
|
||||||
@@ -25,6 +27,7 @@
|
|||||||
<option name="KEYWORD_CASE" value="1" />
|
<option name="KEYWORD_CASE" value="1" />
|
||||||
<option name="IDENTIFIER_CASE" value="1" />
|
<option name="IDENTIFIER_CASE" value="1" />
|
||||||
<option name="TYPE_CASE" value="1" />
|
<option name="TYPE_CASE" value="1" />
|
||||||
|
<option name="CUSTOM_TYPE_CASE" value="1" />
|
||||||
<option name="ALIAS_CASE" value="1" />
|
<option name="ALIAS_CASE" value="1" />
|
||||||
</PostgresCodeStyleSettings>
|
</PostgresCodeStyleSettings>
|
||||||
<codeStyleSettings language="kotlin">
|
<codeStyleSettings language="kotlin">
|
||||||
|
|||||||
3
.idea/misc.xml
generated
3
.idea/misc.xml
generated
@@ -10,4 +10,7 @@
|
|||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="corretto-11" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="corretto-11" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
</component>
|
</component>
|
||||||
|
<component name="TaskProjectConfiguration">
|
||||||
|
<server type="GitHub" url="https://github.com" />
|
||||||
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -36,9 +36,11 @@ class ArticleForUpdate(
|
|||||||
tags: List<String> = emptyList(),
|
tags: List<String> = emptyList(),
|
||||||
val draft: Boolean = false,
|
val draft: Boolean = false,
|
||||||
val createdBy: CitizenRef,
|
val createdBy: CitizenRef,
|
||||||
val workgroup: WorkgroupRef? = null
|
val workgroup: WorkgroupRef? = null,
|
||||||
) : ArticleRefVersioning(id) {
|
versionId: UUID?
|
||||||
|
) : ArticleRefVersioning(id, versionId = versionId ?: UUID.randomUUID()) {
|
||||||
val tags: List<String> = tags.distinct()
|
val tags: List<String> = tags.distinct()
|
||||||
|
val isNew = versionId == null
|
||||||
}
|
}
|
||||||
|
|
||||||
open class ArticleSimple(
|
open class ArticleSimple(
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import fr.dcproject.event.raiseEvent
|
|||||||
import fr.dcproject.repository.Article.Filter
|
import fr.dcproject.repository.Article.Filter
|
||||||
import fr.dcproject.repository.Workgroup as WorkgroupRepository
|
import fr.dcproject.repository.Workgroup as WorkgroupRepository
|
||||||
import fr.dcproject.security.voter.ArticleVoter.Action.CREATE
|
import fr.dcproject.security.voter.ArticleVoter.Action.CREATE
|
||||||
|
import fr.dcproject.security.voter.ArticleVoter.Action.UPDATE
|
||||||
import fr.dcproject.security.voter.ArticleVoter.Action.VIEW
|
import fr.dcproject.security.voter.ArticleVoter.Action.VIEW
|
||||||
import fr.dcproject.views.ArticleViewManager
|
import fr.dcproject.views.ArticleViewManager
|
||||||
import fr.ktorVoter.assertCan
|
import fr.ktorVoter.assertCan
|
||||||
@@ -81,18 +82,17 @@ object ArticlesPaths {
|
|||||||
|
|
||||||
suspend fun getNewArticle(call: ApplicationCall): ArticleForUpdate = call.receive<Article>().run {
|
suspend fun getNewArticle(call: ApplicationCall): ArticleForUpdate = call.receive<Article>().run {
|
||||||
ArticleForUpdate(
|
ArticleForUpdate(
|
||||||
id ?: UUID.randomUUID(),
|
id = id ?: UUID.randomUUID(),
|
||||||
title,
|
title = title,
|
||||||
anonymous,
|
anonymous = anonymous,
|
||||||
content,
|
content = content,
|
||||||
description,
|
description = description,
|
||||||
tags,
|
tags = tags,
|
||||||
draft,
|
draft = draft,
|
||||||
createdBy = call.citizen,
|
createdBy = call.citizen,
|
||||||
workgroup = if (workgroup != null) workgroupRepository.findById(workgroup.id) as WorkgroupSimple<CitizenRef> else null
|
workgroup = if (workgroup != null) workgroupRepository.findById(workgroup.id) as WorkgroupSimple<CitizenRef> else null,
|
||||||
).also {
|
versionId = versionId
|
||||||
it.versionId = versionId ?: UUID.randomUUID()
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,7 +134,11 @@ fun Route.article(repo: ArticleRepository, viewManager: ArticleViewManager) {
|
|||||||
|
|
||||||
post<ArticlesPaths.PostArticleRequest> {
|
post<ArticlesPaths.PostArticleRequest> {
|
||||||
it.getNewArticle(call).also { article ->
|
it.getNewArticle(call).also { article ->
|
||||||
|
if(article.isNew) {
|
||||||
assertCan(CREATE, article)
|
assertCan(CREATE, article)
|
||||||
|
} else {
|
||||||
|
assertCan(UPDATE, article)
|
||||||
|
}
|
||||||
val newArticle = repo.upsert(article) ?: error("Article not updated")
|
val newArticle = repo.upsert(article) ?: error("Article not updated")
|
||||||
call.respond(article)
|
call.respond(article)
|
||||||
raiseEvent(ArticleUpdate.event, ArticleUpdate(newArticle))
|
raiseEvent(ArticleUpdate.event, ArticleUpdate(newArticle))
|
||||||
|
|||||||
@@ -1,18 +1,26 @@
|
|||||||
package fr.dcproject.security.voter
|
package fr.dcproject.security.voter
|
||||||
|
|
||||||
|
import fr.dcproject.citizenOrNull
|
||||||
import fr.dcproject.entity.ArticleAuthI
|
import fr.dcproject.entity.ArticleAuthI
|
||||||
|
import fr.dcproject.entity.ArticleForUpdate
|
||||||
import fr.dcproject.entity.ArticleI
|
import fr.dcproject.entity.ArticleI
|
||||||
|
import fr.dcproject.entity.Citizen as CitizenEntity
|
||||||
|
import fr.dcproject.entity.CitizenI
|
||||||
import fr.dcproject.entity.UserI
|
import fr.dcproject.entity.UserI
|
||||||
|
import fr.dcproject.repository.Article as ArticleRepo
|
||||||
import fr.dcproject.user
|
import fr.dcproject.user
|
||||||
import fr.ktorVoter.ActionI
|
import fr.ktorVoter.ActionI
|
||||||
import fr.ktorVoter.Vote
|
import fr.ktorVoter.Vote
|
||||||
import fr.ktorVoter.Voter
|
import fr.ktorVoter.Voter
|
||||||
import fr.ktorVoter.checkClass
|
import fr.ktorVoter.checkClass
|
||||||
import io.ktor.application.ApplicationCall
|
import io.ktor.application.ApplicationCall
|
||||||
|
import org.koin.core.KoinComponent
|
||||||
|
import org.koin.core.inject
|
||||||
import fr.dcproject.entity.Comment as CommentEntity
|
import fr.dcproject.entity.Comment as CommentEntity
|
||||||
import fr.dcproject.entity.Vote as VoteEntity
|
import fr.dcproject.entity.Vote as VoteEntity
|
||||||
|
|
||||||
class ArticleVoter : Voter {
|
class ArticleVoter : Voter, KoinComponent {
|
||||||
|
private val articleRepo: ArticleRepo by inject()
|
||||||
enum class Action : ActionI {
|
enum class Action : ActionI {
|
||||||
CREATE,
|
CREATE,
|
||||||
UPDATE,
|
UPDATE,
|
||||||
@@ -30,7 +38,7 @@ class ArticleVoter : Voter {
|
|||||||
if (action == Action.CREATE && user is UserI) return Vote.GRANTED
|
if (action == Action.CREATE && user is UserI) return Vote.GRANTED
|
||||||
if (action == Action.VIEW) return view(subject, user)
|
if (action == Action.VIEW) return view(subject, user)
|
||||||
if (action == Action.DELETE) return delete(subject, user)
|
if (action == Action.DELETE) return delete(subject, user)
|
||||||
if (action == Action.UPDATE) return update(subject, user)
|
if (action == Action.UPDATE) return update(subject, call.citizenOrNull)
|
||||||
if (action is CommentVoter.Action) return voteForComment(action, subject)
|
if (action is CommentVoter.Action) return voteForComment(action, subject)
|
||||||
if (action is VoteVoter.Action) return voteForVote(action, subject)
|
if (action is VoteVoter.Action) return voteForVote(action, subject)
|
||||||
if (action is Action) return Vote.DENIED
|
if (action is Action) return Vote.DENIED
|
||||||
@@ -58,12 +66,17 @@ class ArticleVoter : Voter {
|
|||||||
return Vote.DENIED
|
return Vote.DENIED
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun update(subject: Any?, user: UserI?): Vote {
|
private fun update(subject: Any?, citizen: CitizenEntity?): Vote {
|
||||||
checkClass(ArticleAuthI::class, subject)
|
checkClass(ArticleForUpdate::class, subject)
|
||||||
if (subject is ArticleAuthI<*>) {
|
if (subject is ArticleForUpdate) {
|
||||||
if (user is UserI && subject.createdBy.user.id == user.id) {
|
/* The new Article must by created by the same citizen of the connected citizen */
|
||||||
|
if (citizen is CitizenI && subject.createdBy.id == citizen.id) {
|
||||||
|
/* The creator must be the same of the creator of preview version of article */
|
||||||
|
if(articleRepo.findVerionsByVersionsId(1, 1, subject.versionId).result.first().createdBy.id == citizen.id) {
|
||||||
return Vote.GRANTED
|
return Vote.GRANTED
|
||||||
}
|
}
|
||||||
|
return Vote.DENIED
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return Vote.DENIED
|
return Vote.DENIED
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,7 +73,8 @@ class ArticleSteps : En, KoinTest {
|
|||||||
content = "bla bla bla",
|
content = "bla bla bla",
|
||||||
description = "A super article",
|
description = "A super article",
|
||||||
createdBy = createdBy,
|
createdBy = createdBy,
|
||||||
workgroup = workgroup
|
workgroup = workgroup,
|
||||||
|
versionId = UUID.randomUUID()
|
||||||
)
|
)
|
||||||
get<ArticleRepository>().upsert(article)
|
get<ArticleRepository>().upsert(article)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user