#68 Clean Entities

This commit is contained in:
2021-02-25 18:32:17 +01:00
parent c1af949204
commit c25cf64f4b
39 changed files with 265 additions and 264 deletions

View File

@@ -15,7 +15,6 @@
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" /> <option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" /> <option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
<option name="IMPORT_NESTED_CLASSES" value="true" /> <option name="IMPORT_NESTED_CLASSES" value="true" />
<option name="ALLOW_TRAILING_COMMA" value="true" />
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings> </JetCodeStyleSettings>
<PostgresCodeStyleSettings version="5"> <PostgresCodeStyleSettings version="5">

View File

@@ -1,42 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Lint+Test+Sonar &amp; Run" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="env">
<map>
<entry key="SEND_GRID_KEY" value="$SEND_GRID_KEY$" />
</map>
</option>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="run" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<extension name="net.ashald.envfile">
<option name="IS_ENABLED" value="false" />
<option name="IS_SUBST" value="false" />
<option name="IS_PATH_MACRO_SUPPORTED" value="false" />
<option name="IS_IGNORE_MISSING_FILES" value="false" />
<option name="IS_ENABLE_EXPERIMENTAL_INTEGRATIONS" value="false" />
<ENTRIES>
<ENTRY IS_ENABLED="true" PARSER="runconfig" />
</ENTRIES>
</extension>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2">
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Lint Format" run_configuration_type="GradleRunConfiguration" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All Tests" run_configuration_type="JUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Sonarqube" run_configuration_type="GradleRunConfiguration" />
</method>
</configuration>
</component>

View File

@@ -18,8 +18,6 @@
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess> <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess> <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled> <DebugAllEnabled>false</DebugAllEnabled>
<method v="2"> <method v="2" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Test" run_configuration_type="GradleRunConfiguration" />
</method>
</configuration> </configuration>
</component> </component>

View File

@@ -4,7 +4,7 @@
<option name="executionName" /> <option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" /> <option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" /> <option name="scriptParameters" value="-x test -x ktlintKotlinScriptCheck -x ktlintTestSourceSetCheck -x ktlintMainSourceSetCheck" />
<option name="taskDescriptions"> <option name="taskDescriptions">
<list /> <list />
</option> </option>

View File

@@ -1,7 +1,7 @@
package fr.dcproject.common.dto package fr.dcproject.common.dto
import fr.postgresjson.entity.EntityCreatedAt
import org.joda.time.DateTime import org.joda.time.DateTime
import fr.dcproject.common.entity.CreatedAt as EntityCreatedAt
interface CreatedAt { interface CreatedAt {
val createdAt: DateTime val createdAt: DateTime

View File

@@ -1,13 +1,13 @@
package fr.dcproject.common.dto package fr.dcproject.common.dto
import fr.postgresjson.entity.EntityVersioning import fr.dcproject.common.entity.Versionable as VersionableEntity
import java.util.UUID import java.util.UUID
interface Versionable { interface Versionable {
val versionId: UUID val versionId: UUID
val versionNumber: Int val versionNumber: Int
class Imp(parent: EntityVersioning<UUID, Int>) : Versionable { class Imp(parent: VersionableEntity) : Versionable {
override val versionNumber: Int = parent.versionNumber override val versionNumber: Int = parent.versionNumber
override val versionId: UUID = parent.versionId override val versionId: UUID = parent.versionId
} }

View File

@@ -0,0 +1,28 @@
package fr.dcproject.common.entity
import fr.dcproject.component.citizen.CitizenI
interface Created<C : CitizenI> : CreatedAt, CreatedBy<C> {
class Imp<C : CitizenI>(createdBy: C) :
Created<C>,
CreatedBy<C> by CreatedBy.Imp(createdBy),
CreatedAt by CreatedAt.Imp()
}
interface Updated<C : CitizenI> : UpdatedAt, UpdatedBy<C> {
class Imp<C : CitizenI>(updatedAt: C) :
Updated<C>,
UpdatedBy<C> by UpdatedBy.Imp(updatedAt),
UpdatedAt by UpdatedAt.Imp()
}
interface Deleted<C : CitizenI> : DeletedAt, DeletedBy<C> {
override fun isDeleted(): Boolean = (this as DeletedAt).isDeleted()
class Imp<C : CitizenI>(deletedAt: C) :
Deleted<C>,
DeletedBy<C> by DeletedBy.Imp(deletedAt),
DeletedAt by DeletedAt.Imp() {
override fun isDeleted(): Boolean = (this as Deleted<C>).isDeleted()
}
}

View File

@@ -0,0 +1,25 @@
package fr.dcproject.common.entity
import fr.dcproject.component.citizen.CitizenI
interface CreatedBy<T : CitizenI> {
val createdBy: T
class Imp<T : CitizenI>(override val createdBy: T) : CreatedBy<T>
}
interface UpdatedBy<T : CitizenI> {
val updatedBy: T
class Imp<T : CitizenI>(override val updatedBy: T) : UpdatedBy<T>
}
interface DeletedBy<T : CitizenI> {
val deletedBy: T?
fun isDeleted(): Boolean {
return deletedBy?.let { true } ?: false
}
class Imp<T : CitizenI>(override val deletedBy: T?) : DeletedBy<T>
}

View File

@@ -1,14 +0,0 @@
package fr.dcproject.common.entity
import fr.dcproject.component.citizen.CitizenI
import fr.postgresjson.entity.EntityCreatedBy
import fr.postgresjson.entity.EntityI
/**
* TODO remove EntityCreatedBy<EntityI>
*/
interface CreatedBy<T : CitizenI> : EntityCreatedBy<EntityI> {
override val createdBy: T
}
class CreatedByImp<T : CitizenI>(override val createdBy: T) : CreatedBy<T>

View File

@@ -0,0 +1,30 @@
package fr.dcproject.common.entity
import org.joda.time.DateTime
/* Interface */
interface CreatedAt {
val createdAt: DateTime
class Imp(
override val createdAt: DateTime = DateTime.now()
) : CreatedAt
}
interface UpdatedAt {
val updatedAt: DateTime
class Imp(
override val updatedAt: DateTime = DateTime.now()
) : UpdatedAt
}
interface DeletedAt {
val deletedAt: DateTime?
fun isDeleted(): Boolean {
return deletedAt?.let {
it < DateTime.now()
} ?: false
}
class Imp(
override val deletedAt: DateTime? = null
) : DeletedAt
}

View File

@@ -1,8 +1,12 @@
package fr.dcproject.common.entity package fr.dcproject.common.entity
import fr.postgresjson.entity.EntityI import fr.postgresjson.entity.UuidEntityI
import java.util.UUID import java.util.UUID
interface EntityI : EntityI { interface EntityI : UuidEntityI {
val id: UUID override val id: UUID
}
open class Entity(id: UUID? = null) : EntityI {
override val id: UUID = id ?: UUID.randomUUID()
} }

View File

@@ -5,25 +5,21 @@ import fr.dcproject.component.citizen.CitizenI
import fr.dcproject.component.comment.generic.CommentRef import fr.dcproject.component.comment.generic.CommentRef
import fr.dcproject.component.constitution.ConstitutionRef import fr.dcproject.component.constitution.ConstitutionRef
import fr.dcproject.component.opinion.entity.OpinionRef import fr.dcproject.component.opinion.entity.OpinionRef
import fr.postgresjson.entity.EntityCreatedAt
import fr.postgresjson.entity.EntityCreatedBy
import fr.postgresjson.entity.UuidEntity
import fr.postgresjson.entity.UuidEntityI
import java.util.UUID import java.util.UUID
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.reflect.full.isSubclassOf import kotlin.reflect.full.isSubclassOf
interface ExtraI<T : TargetI, C : CitizenI> : interface ExtraI<T : TargetI, C : CitizenI> :
UuidEntityI, EntityI,
HasTarget<T>, HasTarget<T>,
EntityCreatedAt, CreatedAt,
EntityCreatedBy<C> CreatedBy<C>
interface HasTarget<T : TargetI> { interface HasTarget<T : TargetI> {
val target: T val target: T
} }
open class TargetRef(id: UUID? = null, reference: String = "") : TargetI, UuidEntity(id) { open class TargetRef(id: UUID? = null, reference: String = "") : TargetI, Entity(id) {
final override val reference: String final override val reference: String
get() = if (field != "") field else TargetI.getReference(this) get() = if (field != "") field else TargetI.getReference(this)
@@ -33,7 +29,7 @@ open class TargetRef(id: UUID? = null, reference: String = "") : TargetI, UuidEn
} }
} }
interface TargetI : UuidEntityI { interface TargetI : EntityI {
enum class TargetName(val targetReference: String) { enum class TargetName(val targetReference: String) {
Article("article"), Article("article"),
Constitution("constitution"), Constitution("constitution"),

View File

@@ -1,17 +1,25 @@
package fr.dcproject.common.entity package fr.dcproject.common.entity
import fr.postgresjson.entity.EntityVersioning
import java.util.UUID import java.util.UUID
interface VersionableRef { interface VersionableId {
val versionId: UUID val versionId: UUID
class Imp(
versionId: UUID? = null,
) : VersionableId {
override val versionId: UUID = versionId ?: UUID.randomUUID()
}
} }
class VersionableRefImp( interface Versionable : VersionableId {
override val versionId: UUID override val versionId: UUID
) : VersionableRef val versionNumber: Int
interface Versionable : VersionableRef, EntityVersioning<UUID, Int> { class Imp(
override val versionId: UUID override val versionNumber: Int,
override val versionNumber: Int versionId: UUID? = null,
) : Versionable {
override val versionId: UUID = versionId ?: UUID.randomUUID()
}
} }

View File

@@ -1,9 +1,13 @@
package fr.dcproject.component.article package fr.dcproject.component.article
import fr.dcproject.common.entity.CreatedAt
import fr.dcproject.common.entity.CreatedBy import fr.dcproject.common.entity.CreatedBy
import fr.dcproject.common.entity.DeletedAt
import fr.dcproject.common.entity.EntityI
import fr.dcproject.common.entity.TargetI import fr.dcproject.common.entity.TargetI
import fr.dcproject.common.entity.TargetRef import fr.dcproject.common.entity.TargetRef
import fr.dcproject.common.entity.VersionableRef import fr.dcproject.common.entity.Versionable
import fr.dcproject.common.entity.VersionableId
import fr.dcproject.component.citizen.CitizenCart import fr.dcproject.component.citizen.CitizenCart
import fr.dcproject.component.citizen.CitizenCartI import fr.dcproject.component.citizen.CitizenCartI
import fr.dcproject.component.citizen.CitizenI import fr.dcproject.component.citizen.CitizenI
@@ -16,12 +20,6 @@ import fr.dcproject.component.workgroup.WorkgroupCart
import fr.dcproject.component.workgroup.WorkgroupCartI import fr.dcproject.component.workgroup.WorkgroupCartI
import fr.dcproject.component.workgroup.WorkgroupRef import fr.dcproject.component.workgroup.WorkgroupRef
import fr.dcproject.component.workgroup.WorkgroupSimple import fr.dcproject.component.workgroup.WorkgroupSimple
import fr.postgresjson.entity.EntityCreatedAt
import fr.postgresjson.entity.EntityCreatedAtImp
import fr.postgresjson.entity.EntityDeletedAt
import fr.postgresjson.entity.EntityDeletedAtImp
import fr.postgresjson.entity.EntityVersioning
import fr.postgresjson.entity.UuidEntityI
import org.joda.time.DateTime import org.joda.time.DateTime
import java.util.UUID import java.util.UUID
@@ -42,16 +40,16 @@ data class ArticleForView(
) : ArticleRef(id), ) : ArticleRef(id),
ArticleAuthI<CitizenRef>, ArticleAuthI<CitizenRef>,
ArticleWithTitleI, ArticleWithTitleI,
EntityVersioning<UUID, Int>, Versionable,
EntityCreatedAt by EntityCreatedAtImp(), CreatedAt by CreatedAt.Imp(),
EntityDeletedAt by EntityDeletedAtImp(deletedAt), DeletedAt by DeletedAt.Imp(deletedAt),
VersionableRef, VersionableId,
Opinionable, Opinionable,
Votable by VotableImp() { Votable by VotableImp() {
val lastVersion: Boolean = false val lastVersion: Boolean = false
} }
interface ArticleForUpdateI<C : CitizenRef> : ArticleI, ArticleWithTitleI, VersionableRef, TargetI, CreatedBy<C> { interface ArticleForUpdateI<C : CitizenRef> : ArticleI, ArticleWithTitleI, VersionableId, TargetI, CreatedBy<C> {
val anonymous: Boolean val anonymous: Boolean
val content: String val content: String
val description: String val description: String
@@ -74,7 +72,7 @@ class ArticleForUpdate(
) : ArticleRef(id), ) : ArticleRef(id),
ArticleForUpdateI<CitizenRef>, ArticleForUpdateI<CitizenRef>,
ArticleAuthI<CitizenRef>, ArticleAuthI<CitizenRef>,
VersionableRef { VersionableId {
val tags: List<String> = tags.distinct() val tags: List<String> = tags.distinct()
} }
@@ -99,7 +97,7 @@ open class ArticleRef(
id: UUID? = null id: UUID? = null
) : ArticleI, TargetRef(id) ) : ArticleI, TargetRef(id)
interface ArticleI : UuidEntityI, TargetI interface ArticleI : EntityI, TargetI
interface ArticleWithTitleI : ArticleI { interface ArticleWithTitleI : ArticleI {
val title: String val title: String
@@ -108,6 +106,6 @@ interface ArticleWithTitleI : ArticleI {
interface ArticleAuthI<U : CitizenI> : interface ArticleAuthI<U : CitizenI> :
ArticleI, ArticleI,
CreatedBy<U>, CreatedBy<U>,
EntityDeletedAt { DeletedAt {
val draft: Boolean val draft: Boolean
} }

View File

@@ -1,7 +1,7 @@
package fr.dcproject.component.article package fr.dcproject.component.article
import fr.dcproject.common.entity.CreatedBy import fr.dcproject.common.entity.CreatedBy
import fr.dcproject.common.entity.VersionableRef import fr.dcproject.common.entity.VersionableId
import fr.dcproject.common.security.AccessControl import fr.dcproject.common.security.AccessControl
import fr.dcproject.common.security.AccessResponse import fr.dcproject.common.security.AccessResponse
import fr.dcproject.component.citizen.CitizenI import fr.dcproject.component.citizen.CitizenI
@@ -28,7 +28,7 @@ class ArticleAccessControl(private val articleRepo: ArticleRepository) : AccessC
fun <S> canUpsert(subject: S, citizen: CitizenI?): AccessResponse fun <S> canUpsert(subject: S, citizen: CitizenI?): AccessResponse
where S : ArticleI, where S : ArticleI,
S : CreatedBy<*>, S : CreatedBy<*>,
S : VersionableRef { S : VersionableId {
if (citizen == null) return denied("You must be connected to create article", "article.create.notConnected") if (citizen == null) return denied("You must be connected to create article", "article.create.notConnected")
/* The new Article must by created by the same citizen of the connected citizen */ /* The new Article must by created by the same citizen of the connected citizen */
if (subject.createdBy.id == citizen.id) { if (subject.createdBy.id == citizen.id) {

View File

@@ -1,6 +1,6 @@
package fr.dcproject.component.article package fr.dcproject.component.article
import fr.dcproject.common.entity.VersionableRef import fr.dcproject.common.entity.VersionableId
import fr.dcproject.common.utils.contentToString import fr.dcproject.common.utils.contentToString
import fr.dcproject.common.utils.getJsonField import fr.dcproject.common.utils.getJsonField
import fr.dcproject.common.utils.toIso import fr.dcproject.common.utils.toIso
@@ -16,7 +16,7 @@ import java.util.UUID
/** /**
* Wrapper for manage views with elasticsearch * Wrapper for manage views with elasticsearch
*/ */
class ArticleViewManager <A> (private val restClient: RestClient) : ViewManager<A> where A : VersionableRef, A : ArticleI { class ArticleViewManager <A> (private val restClient: RestClient) : ViewManager<A> where A : VersionableId, A : ArticleI {
/** /**
* Add view on article to elasticsearch * Add view on article to elasticsearch
*/ */

View File

@@ -1,12 +1,10 @@
package fr.dcproject.component.auth package fr.dcproject.component.auth
import fr.dcproject.common.entity.CreatedAt
import fr.dcproject.common.entity.Entity
import fr.dcproject.common.entity.EntityI
import fr.dcproject.common.entity.UpdatedAt
import fr.dcproject.component.auth.UserI.Roles import fr.dcproject.component.auth.UserI.Roles
import fr.postgresjson.entity.EntityCreatedAt
import fr.postgresjson.entity.EntityCreatedAtImp
import fr.postgresjson.entity.EntityUpdatedAt
import fr.postgresjson.entity.EntityUpdatedAtImp
import fr.postgresjson.entity.UuidEntity
import fr.postgresjson.entity.UuidEntityI
import io.ktor.auth.Principal import io.ktor.auth.Principal
import org.joda.time.DateTime import org.joda.time.DateTime
import java.util.UUID import java.util.UUID
@@ -26,8 +24,8 @@ open class User(
var blockedAt: DateTime? = null, var blockedAt: DateTime? = null,
var roles: List<Roles> = emptyList() var roles: List<Roles> = emptyList()
) : UserRef(id), ) : UserRef(id),
EntityCreatedAt by EntityCreatedAtImp(), CreatedAt by CreatedAt.Imp(),
EntityUpdatedAt by EntityUpdatedAtImp() UpdatedAt by UpdatedAt.Imp()
interface UserWithPasswordI { interface UserWithPasswordI {
val id: UUID val id: UUID
@@ -42,9 +40,9 @@ class UserWithPassword(
open class UserRef( open class UserRef(
id: UUID = UUID.randomUUID() id: UUID = UUID.randomUUID()
) : UserI, UuidEntity(id) ) : UserI, Entity(id)
interface UserI : UuidEntityI, Principal { interface UserI : EntityI, Principal {
enum class Roles { ROLE_USER, ROLE_ADMIN } enum class Roles { ROLE_USER, ROLE_ADMIN }
} }

View File

@@ -1,18 +1,16 @@
package fr.dcproject.component.citizen package fr.dcproject.component.citizen
import fr.dcproject.common.entity.CreatedAt
import fr.dcproject.common.entity.DeletedAt
import fr.dcproject.common.entity.Entity
import fr.dcproject.common.entity.EntityI
import fr.dcproject.component.auth.User import fr.dcproject.component.auth.User
import fr.dcproject.component.auth.UserForCreate import fr.dcproject.component.auth.UserForCreate
import fr.dcproject.component.auth.UserI import fr.dcproject.component.auth.UserI
import fr.dcproject.component.auth.UserRef import fr.dcproject.component.auth.UserRef
import fr.dcproject.component.citizen.CitizenI.Name import fr.dcproject.component.citizen.CitizenI.Name
import fr.dcproject.component.workgroup.WorkgroupSimple import fr.dcproject.component.workgroup.WorkgroupSimple
import fr.postgresjson.entity.EntityCreatedAt
import fr.postgresjson.entity.EntityCreatedAtImp
import fr.postgresjson.entity.EntityDeletedAt
import fr.postgresjson.entity.EntityDeletedAtImp
import fr.postgresjson.entity.Serializable import fr.postgresjson.entity.Serializable
import fr.postgresjson.entity.UuidEntity
import fr.postgresjson.entity.UuidEntityI
import org.joda.time.DateTime import org.joda.time.DateTime
import java.util.UUID import java.util.UUID
@@ -26,7 +24,7 @@ class CitizenForCreate(
id: UUID = UUID.randomUUID(), id: UUID = UUID.randomUUID(),
) : CitizenI, ) : CitizenI,
CitizenRefWithUser(id, user), CitizenRefWithUser(id, user),
EntityCreatedAt by EntityCreatedAtImp() CreatedAt by CreatedAt.Imp()
class Citizen( class Citizen(
override val id: UUID = UUID.randomUUID(), override val id: UUID = UUID.randomUUID(),
@@ -42,8 +40,8 @@ class Citizen(
CitizenWithUserI, CitizenWithUserI,
CitizenRef(id), CitizenRef(id),
CitizenCartI, CitizenCartI,
EntityCreatedAt by EntityCreatedAtImp(), CreatedAt by CreatedAt.Imp(),
EntityDeletedAt by EntityDeletedAtImp(deletedAt) { DeletedAt by DeletedAt.Imp(deletedAt) {
var workgroups: List<WorkgroupAndRoles> = emptyList() var workgroups: List<WorkgroupAndRoles> = emptyList()
class WorkgroupAndRoles( class WorkgroupAndRoles(
@@ -64,7 +62,7 @@ data class CitizenBasic(
override val deletedAt: DateTime? = null override val deletedAt: DateTime? = null
) : CitizenBasicI, ) : CitizenBasicI,
CitizenRefWithUser(id, user), CitizenRefWithUser(id, user),
EntityDeletedAt by EntityDeletedAtImp(deletedAt) DeletedAt by DeletedAt.Imp(deletedAt)
@Deprecated("") @Deprecated("")
open class CitizenSimple( open class CitizenSimple(
@@ -92,10 +90,10 @@ open class CitizenRefWithUser(
open class CitizenRef( open class CitizenRef(
id: UUID = UUID.randomUUID() id: UUID = UUID.randomUUID()
) : UuidEntity(id), ) : Entity(id),
CitizenI CitizenI
interface CitizenI : UuidEntityI { interface CitizenI : EntityI {
data class Name( data class Name(
override val firstName: String, override val firstName: String,
override val lastName: String, override val lastName: String,
@@ -111,7 +109,7 @@ interface CitizenI : UuidEntityI {
} }
@Deprecated("") @Deprecated("")
interface CitizenBasicI : CitizenWithUserI, CitizenWithEmail, EntityDeletedAt { interface CitizenBasicI : CitizenWithUserI, CitizenWithEmail, DeletedAt {
val name: Name val name: Name
val birthday: DateTime val birthday: DateTime
val voteAnonymous: Boolean val voteAnonymous: Boolean

View File

@@ -1,14 +1,14 @@
package fr.dcproject.component.citizen package fr.dcproject.component.citizen
import fr.dcproject.common.entity.DeletedAt
import fr.dcproject.common.security.AccessControl import fr.dcproject.common.security.AccessControl
import fr.dcproject.common.security.AccessResponse import fr.dcproject.common.security.AccessResponse
import fr.postgresjson.entity.EntityDeletedAt
class CitizenAccessControl : AccessControl() { class CitizenAccessControl : AccessControl() {
fun <S> canView(subjects: List<S>, connectedCitizen: CitizenI?): AccessResponse where S : CitizenI, S : EntityDeletedAt = fun <S> canView(subjects: List<S>, connectedCitizen: CitizenI?): AccessResponse where S : CitizenI, S : DeletedAt =
canAll(subjects) { canView(it, connectedCitizen) } canAll(subjects) { canView(it, connectedCitizen) }
fun <S> canView(subject: S, connectedCitizen: CitizenI?): AccessResponse where S : CitizenI, S : EntityDeletedAt { fun <S> canView(subject: S, connectedCitizen: CitizenI?): AccessResponse where S : CitizenI, S : DeletedAt {
if (connectedCitizen == null) return denied("You must be connected to view citizen", "citizen.view.connected") if (connectedCitizen == null) return denied("You must be connected to view citizen", "citizen.view.connected")
return if (subject.isDeleted()) denied("You cannot view a deleted citizen", "citizen.view.deleted") return if (subject.isDeleted()) denied("You cannot view a deleted citizen", "citizen.view.deleted")
else granted() else granted()

View File

@@ -1,5 +1,6 @@
package fr.dcproject.component.comment.article package fr.dcproject.component.comment.article
import fr.dcproject.common.entity.EntityI
import fr.dcproject.common.entity.TargetI import fr.dcproject.common.entity.TargetI
import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.article.ArticleForView
import fr.dcproject.component.article.ArticleRef import fr.dcproject.component.article.ArticleRef
@@ -9,7 +10,6 @@ import fr.dcproject.component.comment.generic.CommentForView
import fr.dcproject.component.comment.generic.CommentRepositoryAbs import fr.dcproject.component.comment.generic.CommentRepositoryAbs
import fr.postgresjson.connexion.Paginated import fr.postgresjson.connexion.Paginated
import fr.postgresjson.connexion.Requester import fr.postgresjson.connexion.Requester
import fr.postgresjson.entity.UuidEntityI
import java.util.UUID import java.util.UUID
class CommentArticleRepository(requester: Requester) : CommentRepositoryAbs<ArticleForView>(requester) { class CommentArticleRepository(requester: Requester) : CommentRepositoryAbs<ArticleForView>(requester) {
@@ -36,7 +36,7 @@ class CommentArticleRepository(requester: Requester) : CommentRepositoryAbs<Arti
} }
override fun findByTarget( override fun findByTarget(
target: UuidEntityI, target: EntityI,
page: Int, page: Int,
limit: Int, limit: Int,
sort: Sort sort: Sort

View File

@@ -1,5 +1,6 @@
package fr.dcproject.component.comment.constitution package fr.dcproject.component.comment.constitution
import fr.dcproject.common.entity.EntityI
import fr.dcproject.common.entity.TargetI import fr.dcproject.common.entity.TargetI
import fr.dcproject.component.citizen.CitizenI import fr.dcproject.component.citizen.CitizenI
import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.component.citizen.CitizenRef
@@ -9,7 +10,6 @@ import fr.dcproject.component.comment.generic.CommentRepositoryAbs
import fr.dcproject.component.constitution.ConstitutionRef import fr.dcproject.component.constitution.ConstitutionRef
import fr.postgresjson.connexion.Paginated import fr.postgresjson.connexion.Paginated
import fr.postgresjson.connexion.Requester import fr.postgresjson.connexion.Requester
import fr.postgresjson.entity.UuidEntityI
import java.util.UUID import java.util.UUID
class CommentConstitutionRepository(requester: Requester) : CommentRepositoryAbs<ConstitutionRef>(requester) { class CommentConstitutionRepository(requester: Requester) : CommentRepositoryAbs<ConstitutionRef>(requester) {
@@ -36,7 +36,7 @@ class CommentConstitutionRepository(requester: Requester) : CommentRepositoryAbs
} }
override fun findByTarget( override fun findByTarget(
target: UuidEntityI, target: EntityI,
page: Int, page: Int,
limit: Int, limit: Int,
sort: CommentArticleRepository.Sort sort: CommentArticleRepository.Sort

View File

@@ -1,21 +1,17 @@
package fr.dcproject.component.comment.generic package fr.dcproject.component.comment.generic
import fr.dcproject.common.entity.CreatedAt
import fr.dcproject.common.entity.CreatedBy
import fr.dcproject.common.entity.DeletedAt
import fr.dcproject.common.entity.EntityI import fr.dcproject.common.entity.EntityI
import fr.dcproject.common.entity.ExtraI import fr.dcproject.common.entity.ExtraI
import fr.dcproject.common.entity.HasTarget import fr.dcproject.common.entity.HasTarget
import fr.dcproject.common.entity.TargetI import fr.dcproject.common.entity.TargetI
import fr.dcproject.common.entity.TargetRef import fr.dcproject.common.entity.TargetRef
import fr.dcproject.common.entity.UpdatedAt
import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.component.citizen.CitizenRef
import fr.dcproject.component.vote.entity.Votable import fr.dcproject.component.vote.entity.Votable
import fr.dcproject.component.vote.entity.VotableImp import fr.dcproject.component.vote.entity.VotableImp
import fr.postgresjson.entity.EntityCreatedAt
import fr.postgresjson.entity.EntityCreatedAtImp
import fr.postgresjson.entity.EntityCreatedBy
import fr.postgresjson.entity.EntityCreatedByImp
import fr.postgresjson.entity.EntityDeletedAt
import fr.postgresjson.entity.EntityDeletedAtImp
import fr.postgresjson.entity.EntityUpdatedAt
import fr.postgresjson.entity.EntityUpdatedAtImp
import org.joda.time.DateTime import org.joda.time.DateTime
import java.util.UUID import java.util.UUID
@@ -31,9 +27,9 @@ class CommentForView<T : TargetI, C : CitizenRef>(
CommentWithParentI<T>, CommentWithParentI<T>,
CommentForUpdate<T, C>(id, createdBy, target, content, parent, deletedAt), CommentForUpdate<T, C>(id, createdBy, target, content, parent, deletedAt),
CommentWithTargetI<T>, CommentWithTargetI<T>,
EntityCreatedBy<C> by EntityCreatedByImp(createdBy), CreatedBy<C> by CreatedBy.Imp(createdBy),
EntityUpdatedAt by EntityUpdatedAtImp(), UpdatedAt by UpdatedAt.Imp(),
EntityDeletedAt by EntityDeletedAtImp(), DeletedAt by DeletedAt.Imp(),
Votable by VotableImp(), Votable by VotableImp(),
TargetI { TargetI {
constructor( constructor(
@@ -59,9 +55,9 @@ open class CommentForUpdate<T : TargetI, C : CitizenRef>(
CommentWithParentI<T>, CommentWithParentI<T>,
ExtraI<T, C>, ExtraI<T, C>,
CommentWithTargetI<T>, CommentWithTargetI<T>,
EntityCreatedAt by EntityCreatedAtImp(), CreatedAt by CreatedAt.Imp(),
EntityCreatedBy<C>, CreatedBy<C>,
EntityDeletedAt, DeletedAt,
TargetI { TargetI {
constructor( constructor(
createdBy: C, createdBy: C,
@@ -82,7 +78,7 @@ open class CommentParent<T : TargetI>(
) : CommentRef(id), ) : CommentRef(id),
CommentParentI<T> CommentParentI<T>
interface CommentParentI<T : TargetI> : CommentI, EntityDeletedAt, CommentWithTargetI<T> interface CommentParentI<T : TargetI> : CommentI, DeletedAt, CommentWithTargetI<T>
interface CommentWithTargetI<T : TargetI> : CommentI, TargetI, HasTarget<T> interface CommentWithTargetI<T : TargetI> : CommentI, TargetI, HasTarget<T>

View File

@@ -1,39 +1,39 @@
package fr.dcproject.component.comment.generic package fr.dcproject.component.comment.generic
import fr.dcproject.common.entity.CreatedBy
import fr.dcproject.common.entity.DeletedAt
import fr.dcproject.common.entity.HasTarget import fr.dcproject.common.entity.HasTarget
import fr.dcproject.common.security.AccessControl import fr.dcproject.common.security.AccessControl
import fr.dcproject.common.security.AccessResponse import fr.dcproject.common.security.AccessResponse
import fr.dcproject.component.citizen.CitizenI import fr.dcproject.component.citizen.CitizenI
import fr.postgresjson.entity.EntityCreatedBy
import fr.postgresjson.entity.EntityDeletedAt
class CommentAccessControl : AccessControl() { class CommentAccessControl : AccessControl() {
fun <S> canView(subjects: List<S>, citizen: CitizenI?): AccessResponse fun <S> canView(subjects: List<S>, citizen: CitizenI?): AccessResponse
where S : CommentI, where S : CommentI,
S : EntityDeletedAt = canAll(subjects) { canView(it, citizen) } S : DeletedAt = canAll(subjects) { canView(it, citizen) }
fun <S> canView(subject: S, citizen: CitizenI?): AccessResponse fun <S> canView(subject: S, citizen: CitizenI?): AccessResponse
where S : CommentI, where S : CommentI,
S : EntityDeletedAt = when { S : DeletedAt = when {
subject.isDeleted() -> denied("Your cannot view a deleted comment", "comment.view.deleted") subject.isDeleted() -> denied("Your cannot view a deleted comment", "comment.view.deleted")
else -> granted() else -> granted()
} }
fun <S, CR : CitizenI> canCreate(subject: S, citizen: CitizenI?): AccessResponse fun <S, CR : CitizenI> canCreate(subject: S, citizen: CitizenI?): AccessResponse
where S : CommentI, where S : CommentI,
S : EntityCreatedBy<CR>, S : CreatedBy<CR>,
S : CommentWithParentI<*>, S : CommentWithParentI<*>,
S : HasTarget<*> = when { S : HasTarget<*> = when {
citizen == null -> denied("You must be connected to create user", "comment.create.notConnected") citizen == null -> denied("You must be connected to create user", "comment.create.notConnected")
subject.createdBy.id != citizen.id -> denied("You cannot create a comment with other user than yours", "comment.create.wrongUser") subject.createdBy.id != citizen.id -> denied("You cannot create a comment with other user than yours", "comment.create.wrongUser")
subject.parent?.isDeleted() ?: false -> denied("You cannot create a comment on deleted parent", "comment.create.deletedParent") subject.parent?.isDeleted() ?: false -> denied("You cannot create a comment on deleted parent", "comment.create.deletedParent")
subject.target.let { it is EntityDeletedAt && it.isDeleted() } -> denied("You cannot create a comment on deleted target", "comment.create.deletedTarget") subject.target.let { it is DeletedAt && it.isDeleted() } -> denied("You cannot create a comment on deleted target", "comment.create.deletedTarget")
else -> granted() else -> granted()
} }
fun <S, CR : CitizenI> canUpdate(subject: S, citizen: CitizenI?): AccessResponse fun <S, CR : CitizenI> canUpdate(subject: S, citizen: CitizenI?): AccessResponse
where S : CommentI, where S : CommentI,
S : EntityCreatedBy<CR> = when { S : CreatedBy<CR> = when {
citizen == null -> denied("You must be connected to update comment", "comment.update.notConnected") citizen == null -> denied("You must be connected to update comment", "comment.update.notConnected")
citizen.id != subject.createdBy.id -> denied("You cannot update another user of yours", "comment.update.notYours") citizen.id != subject.createdBy.id -> denied("You cannot update another user of yours", "comment.update.notYours")
else -> granted() else -> granted()

View File

@@ -1,5 +1,6 @@
package fr.dcproject.component.comment.generic package fr.dcproject.component.comment.generic
import fr.dcproject.common.entity.EntityI
import fr.dcproject.common.entity.TargetI import fr.dcproject.common.entity.TargetI
import fr.dcproject.common.entity.TargetRef import fr.dcproject.common.entity.TargetRef
import fr.dcproject.component.citizen.CitizenI import fr.dcproject.component.citizen.CitizenI
@@ -7,7 +8,6 @@ import fr.dcproject.component.citizen.CitizenRef
import fr.dcproject.component.comment.article.CommentArticleRepository import fr.dcproject.component.comment.article.CommentArticleRepository
import fr.postgresjson.connexion.Paginated import fr.postgresjson.connexion.Paginated
import fr.postgresjson.connexion.Requester import fr.postgresjson.connexion.Requester
import fr.postgresjson.entity.UuidEntityI
import fr.postgresjson.repository.RepositoryI import fr.postgresjson.repository.RepositoryI
import java.util.UUID import java.util.UUID
@@ -44,7 +44,7 @@ abstract class CommentRepositoryAbs<T : TargetI>(override var requester: Request
} }
open fun findByTarget( open fun findByTarget(
target: UuidEntityI, target: EntityI,
page: Int = 1, page: Int = 1,
limit: Int = 50, limit: Int = 50,
sort: CommentArticleRepository.Sort = CommentArticleRepository.Sort.CREATED_AT sort: CommentArticleRepository.Sort = CommentArticleRepository.Sort.CREATED_AT

View File

@@ -1,21 +1,17 @@
package fr.dcproject.component.constitution package fr.dcproject.component.constitution
import fr.dcproject.common.entity.CreatedAt
import fr.dcproject.common.entity.CreatedBy
import fr.dcproject.common.entity.DeletedAt
import fr.dcproject.common.entity.Entity
import fr.dcproject.common.entity.TargetI import fr.dcproject.common.entity.TargetI
import fr.dcproject.common.entity.TargetRef import fr.dcproject.common.entity.TargetRef
import fr.dcproject.common.entity.VersionableId
import fr.dcproject.component.article.ArticleForListing import fr.dcproject.component.article.ArticleForListing
import fr.dcproject.component.article.ArticleI import fr.dcproject.component.article.ArticleI
import fr.dcproject.component.citizen.CitizenSimple import fr.dcproject.component.citizen.CitizenSimple
import fr.dcproject.component.citizen.CitizenWithUserI import fr.dcproject.component.citizen.CitizenWithUserI
import fr.dcproject.component.constitution.ConstitutionSimple.TitleSimple import fr.dcproject.component.constitution.ConstitutionSimple.TitleSimple
import fr.postgresjson.entity.EntityCreatedAt
import fr.postgresjson.entity.EntityCreatedAtImp
import fr.postgresjson.entity.EntityCreatedBy
import fr.postgresjson.entity.EntityCreatedByImp
import fr.postgresjson.entity.EntityDeletedAt
import fr.postgresjson.entity.EntityDeletedAtImp
import fr.postgresjson.entity.EntityVersioning
import fr.postgresjson.entity.UuidEntity
import fr.postgresjson.entity.UuidEntityVersioning
import java.util.UUID import java.util.UUID
class Constitution( class Constitution(
@@ -54,10 +50,10 @@ open class ConstitutionSimple<Cr : CitizenWithUserI, T : TitleSimple<*>>(
override val createdBy: Cr, override val createdBy: Cr,
versionId: UUID = UUID.randomUUID() versionId: UUID = UUID.randomUUID()
) : ConstitutionRef(id), ) : ConstitutionRef(id),
EntityVersioning<UUID, Int> by UuidEntityVersioning(versionId = versionId, versionNumber = 0), VersionableId by VersionableId.Imp(versionId),
EntityCreatedAt by EntityCreatedAtImp(), CreatedAt by CreatedAt.Imp(),
EntityCreatedBy<Cr> by EntityCreatedByImp(createdBy), CreatedBy<Cr> by CreatedBy.Imp(createdBy),
EntityDeletedAt by EntityDeletedAtImp() { DeletedAt by DeletedAt.Imp() {
init { init {
titles.forEachIndexed { index, title -> titles.forEachIndexed { index, title ->
@@ -76,7 +72,7 @@ open class ConstitutionSimple<Cr : CitizenWithUserI, T : TitleSimple<*>>(
open class ConstitutionRef(id: UUID? = null) : ConstitutionS(id ?: UUID.randomUUID()) { open class ConstitutionRef(id: UUID? = null) : ConstitutionS(id ?: UUID.randomUUID()) {
open class TitleRef( open class TitleRef(
id: UUID = UUID.randomUUID() id: UUID = UUID.randomUUID()
) : UuidEntity(id) ) : Entity(id)
} }
sealed class ConstitutionS(id: UUID = UUID.randomUUID()) : TargetRef(id), TargetI sealed class ConstitutionS(id: UUID = UUID.randomUUID()) : TargetRef(id), TargetI

View File

@@ -1,10 +1,10 @@
package fr.dcproject.component.constitution package fr.dcproject.component.constitution
import fr.dcproject.common.entity.CreatedBy
import fr.dcproject.common.entity.DeletedAt
import fr.dcproject.common.security.AccessControl import fr.dcproject.common.security.AccessControl
import fr.dcproject.common.security.AccessResponse import fr.dcproject.common.security.AccessResponse
import fr.dcproject.component.citizen.CitizenI import fr.dcproject.component.citizen.CitizenI
import fr.postgresjson.entity.EntityCreatedBy
import fr.postgresjson.entity.EntityDeletedAt
class ConstitutionAccessControl : AccessControl() { class ConstitutionAccessControl : AccessControl() {
fun canCreate(subject: ConstitutionS, citizen: CitizenI?): AccessResponse = when { fun canCreate(subject: ConstitutionS, citizen: CitizenI?): AccessResponse = when {
@@ -15,18 +15,18 @@ class ConstitutionAccessControl : AccessControl() {
fun <S : ConstitutionSimple<*, *>> canView(subjects: List<S>, citizen: CitizenI?): AccessResponse = fun <S : ConstitutionSimple<*, *>> canView(subjects: List<S>, citizen: CitizenI?): AccessResponse =
canAll(subjects) { canView(it, citizen) } canAll(subjects) { canView(it, citizen) }
fun <S> canView(subject: S, citizen: CitizenI?): AccessResponse where S : EntityDeletedAt, S : ConstitutionS = when { fun <S> canView(subject: S, citizen: CitizenI?): AccessResponse where S : DeletedAt, S : ConstitutionS = when {
subject.isDeleted() -> denied("You cannot view a deleted constitution", "constitution.view.deleted") subject.isDeleted() -> denied("You cannot view a deleted constitution", "constitution.view.deleted")
else -> granted() else -> granted()
} }
fun <S> canDelete(subject: S, citizen: CitizenI?): AccessResponse where S : EntityCreatedBy<CitizenI>, S : ConstitutionRef = when { fun <S> canDelete(subject: S, citizen: CitizenI?): AccessResponse where S : CreatedBy<CitizenI>, S : ConstitutionRef = when {
citizen == null -> denied("You must be connected to delete constitution", "constitution.delete.notConnected") citizen == null -> denied("You must be connected to delete constitution", "constitution.delete.notConnected")
subject.createdBy.id != citizen.id -> denied("You cannot delete the constitution of other citizen", "constitution.delete.otherCitizen") subject.createdBy.id != citizen.id -> denied("You cannot delete the constitution of other citizen", "constitution.delete.otherCitizen")
else -> granted() else -> granted()
} }
fun <S> canUpdate(subject: S, citizen: CitizenI?): AccessResponse where S : EntityCreatedBy<CitizenI>, S : ConstitutionRef = when { fun <S> canUpdate(subject: S, citizen: CitizenI?): AccessResponse where S : CreatedBy<CitizenI>, S : ConstitutionRef = when {
citizen == null -> denied("You must be connected to update constitution", "constitution.update.notConnected") citizen == null -> denied("You must be connected to update constitution", "constitution.update.notConnected")
subject.createdBy.id != citizen.id -> denied("You cannot update the constitution of other citizen", "constitution.update.otherCitizen") subject.createdBy.id != citizen.id -> denied("You cannot update the constitution of other citizen", "constitution.update.otherCitizen")
else -> granted() else -> granted()

View File

@@ -1,5 +1,6 @@
package fr.dcproject.component.constitution.routes package fr.dcproject.component.constitution.routes
import fr.dcproject.common.entity.Entity
import fr.dcproject.common.security.assert import fr.dcproject.common.security.assert
import fr.dcproject.common.utils.receiveOrBadRequest import fr.dcproject.common.utils.receiveOrBadRequest
import fr.dcproject.component.article.ArticleRef import fr.dcproject.component.article.ArticleRef
@@ -13,7 +14,6 @@ import fr.dcproject.component.constitution.ConstitutionSimple
import fr.dcproject.component.constitution.ConstitutionSimple.TitleSimple import fr.dcproject.component.constitution.ConstitutionSimple.TitleSimple
import fr.dcproject.component.constitution.routes.CreateConstitution.PostConstitutionRequest.Input import fr.dcproject.component.constitution.routes.CreateConstitution.PostConstitutionRequest.Input
import fr.dcproject.component.constitution.routes.CreateConstitution.PostConstitutionRequest.Input.Title import fr.dcproject.component.constitution.routes.CreateConstitution.PostConstitutionRequest.Input.Title
import fr.postgresjson.entity.UuidEntity
import io.ktor.application.call import io.ktor.application.call
import io.ktor.locations.KtorExperimentalLocationsAPI import io.ktor.locations.KtorExperimentalLocationsAPI
import io.ktor.locations.Location import io.ktor.locations.Location
@@ -45,7 +45,7 @@ object CreateConstitution {
var name: String, var name: String,
var rank: Int? = null, var rank: Int? = null,
var articles: MutableList<ArticleRef> = mutableListOf() var articles: MutableList<ArticleRef> = mutableListOf()
) : UuidEntity(id) ) : Entity(id)
} }
} }

View File

@@ -1,16 +1,14 @@
package fr.dcproject.component.follow package fr.dcproject.component.follow
import fr.dcproject.common.entity.Created
import fr.dcproject.common.entity.CreatedBy
import fr.dcproject.common.entity.EntityI
import fr.dcproject.common.entity.ExtraI import fr.dcproject.common.entity.ExtraI
import fr.dcproject.common.entity.HasTarget import fr.dcproject.common.entity.HasTarget
import fr.dcproject.common.entity.TargetI import fr.dcproject.common.entity.TargetI
import fr.dcproject.component.citizen.CitizenBasic import fr.dcproject.component.citizen.CitizenBasic
import fr.dcproject.component.citizen.CitizenBasicI import fr.dcproject.component.citizen.CitizenBasicI
import fr.dcproject.component.citizen.CitizenI import fr.dcproject.component.citizen.CitizenI
import fr.postgresjson.entity.EntityCreatedAt
import fr.postgresjson.entity.EntityCreatedAtImp
import fr.postgresjson.entity.EntityCreatedBy
import fr.postgresjson.entity.EntityCreatedByImp
import fr.postgresjson.entity.UuidEntityI
import java.util.UUID import java.util.UUID
@Deprecated("") @Deprecated("")
@@ -28,8 +26,7 @@ open class FollowSimple<T : TargetI, C : CitizenI>(
override var target: T override var target: T
) : ExtraI<T, C>, ) : ExtraI<T, C>,
FollowRef(id), FollowRef(id),
EntityCreatedAt by EntityCreatedAtImp(), Created<C> by Created.Imp(createdBy)
EntityCreatedBy<C> by EntityCreatedByImp(createdBy)
class FollowForUpdate<T : TargetI, C : CitizenI>( class FollowForUpdate<T : TargetI, C : CitizenI>(
id: UUID = UUID.randomUUID(), id: UUID = UUID.randomUUID(),
@@ -37,10 +34,10 @@ class FollowForUpdate<T : TargetI, C : CitizenI>(
override val createdBy: C override val createdBy: C
) : FollowRef(id), ) : FollowRef(id),
HasTarget<T>, HasTarget<T>,
EntityCreatedBy<C> by EntityCreatedByImp<C>(createdBy) CreatedBy<C> by CreatedBy.Imp<C>(createdBy)
open class FollowRef( open class FollowRef(
override val id: UUID override val id: UUID
) : FollowI ) : FollowI
interface FollowI : UuidEntityI interface FollowI : EntityI

View File

@@ -1,5 +1,6 @@
package fr.dcproject.component.follow package fr.dcproject.component.follow
import fr.dcproject.common.entity.Entity
import fr.dcproject.common.entity.TargetRef import fr.dcproject.common.entity.TargetRef
import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.article.ArticleForView
import fr.dcproject.component.article.ArticleRef import fr.dcproject.component.article.ArticleRef
@@ -8,7 +9,6 @@ import fr.dcproject.component.citizen.CitizenRef
import fr.dcproject.component.constitution.ConstitutionRef import fr.dcproject.component.constitution.ConstitutionRef
import fr.postgresjson.connexion.Paginated import fr.postgresjson.connexion.Paginated
import fr.postgresjson.connexion.Requester import fr.postgresjson.connexion.Requester
import fr.postgresjson.entity.UuidEntity
import fr.postgresjson.repository.RepositoryI import fr.postgresjson.repository.RepositoryI
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flow
@@ -71,7 +71,7 @@ sealed class FollowRepository<IN : TargetRef, OUT : TargetRef>(override var requ
) )
fun findFollowsByTarget( fun findFollowsByTarget(
target: UuidEntity, target: Entity,
bulkSize: Int = 300 bulkSize: Int = 300
): Flow<FollowSimple<IN, CitizenRef>> = flow { ): Flow<FollowSimple<IN, CitizenRef>> = flow {
var nextPage = 1 var nextPage = 1
@@ -85,7 +85,7 @@ sealed class FollowRepository<IN : TargetRef, OUT : TargetRef>(override var requ
} }
abstract fun findFollowsByTarget( abstract fun findFollowsByTarget(
target: UuidEntity, target: Entity,
page: Int = 1, page: Int = 1,
limit: Int = 300 limit: Int = 300
): Paginated<FollowSimple<IN, CitizenRef>> ): Paginated<FollowSimple<IN, CitizenRef>>
@@ -108,7 +108,7 @@ class FollowArticleRepository(requester: Requester) : FollowRepository<ArticleRe
} }
override fun findFollowsByTarget( override fun findFollowsByTarget(
target: UuidEntity, target: Entity,
page: Int, page: Int,
limit: Int limit: Int
): Paginated<FollowSimple<ArticleRef, CitizenRef>> { ): Paginated<FollowSimple<ArticleRef, CitizenRef>> {
@@ -139,7 +139,7 @@ class FollowConstitutionRepository(requester: Requester) : FollowRepository<Cons
} }
override fun findFollowsByTarget( override fun findFollowsByTarget(
target: UuidEntity, target: Entity,
page: Int, page: Int,
limit: Int limit: Int
): Paginated<FollowSimple<ConstitutionRef, CitizenRef>> { ): Paginated<FollowSimple<ConstitutionRef, CitizenRef>> {

View File

@@ -7,8 +7,8 @@ import com.fasterxml.jackson.databind.module.SimpleModule
import com.fasterxml.jackson.datatype.joda.JodaModule import com.fasterxml.jackson.datatype.joda.JodaModule
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue import com.fasterxml.jackson.module.kotlin.readValue
import fr.dcproject.common.entity.Entity
import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.article.ArticleForView
import fr.postgresjson.entity.UuidEntity
import org.joda.time.DateTime import org.joda.time.DateTime
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
@@ -47,7 +47,7 @@ open class Notification(
} }
open class EntityNotification( open class EntityNotification(
val target: UuidEntity, val target: Entity,
type: String, type: String,
val action: String val action: String
) : Notification(type) ) : Notification(type)

View File

@@ -4,6 +4,7 @@ import com.sendgrid.helpers.mail.Mail
import com.sendgrid.helpers.mail.objects.Content import com.sendgrid.helpers.mail.objects.Content
import com.sendgrid.helpers.mail.objects.Email import com.sendgrid.helpers.mail.objects.Email
import fr.dcproject.common.email.Mailer import fr.dcproject.common.email.Mailer
import fr.dcproject.common.entity.EntityI
import fr.dcproject.common.entity.TargetRef import fr.dcproject.common.entity.TargetRef
import fr.dcproject.component.article.ArticleRepository import fr.dcproject.component.article.ArticleRepository
import fr.dcproject.component.article.ArticleWithTitleI import fr.dcproject.component.article.ArticleWithTitleI
@@ -11,7 +12,6 @@ import fr.dcproject.component.citizen.CitizenBasicI
import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.component.citizen.CitizenRef
import fr.dcproject.component.citizen.CitizenRepository import fr.dcproject.component.citizen.CitizenRepository
import fr.dcproject.component.follow.FollowSimple import fr.dcproject.component.follow.FollowSimple
import fr.postgresjson.entity.UuidEntityI
import java.util.UUID import java.util.UUID
class NotificationEmailSender( class NotificationEmailSender(
@@ -43,7 +43,7 @@ class NotificationEmailSender(
} }
} }
private fun generateHtmlContent(citizen: CitizenBasicI, target: UuidEntityI): String? { private fun generateHtmlContent(citizen: CitizenBasicI, target: EntityI): String? {
return when (target) { return when (target) {
is ArticleWithTitleI -> """ is ArticleWithTitleI -> """
Hello ${citizen.name.getFullName()},<br/> Hello ${citizen.name.getFullName()},<br/>
@@ -53,7 +53,7 @@ class NotificationEmailSender(
} }
} }
private fun generateContent(citizen: CitizenBasicI, target: UuidEntityI): String { private fun generateContent(citizen: CitizenBasicI, target: EntityI): String {
return when (target) { return when (target) {
is ArticleWithTitleI -> """ is ArticleWithTitleI -> """
Hello ${citizen.name.getFullName()}, Hello ${citizen.name.getFullName()},

View File

@@ -1,12 +1,12 @@
package fr.dcproject.component.opinion package fr.dcproject.component.opinion
import fr.dcproject.common.entity.CreatedBy
import fr.dcproject.common.entity.DeletedAt
import fr.dcproject.common.entity.HasTarget import fr.dcproject.common.entity.HasTarget
import fr.dcproject.common.security.AccessControl import fr.dcproject.common.security.AccessControl
import fr.dcproject.common.security.AccessResponse import fr.dcproject.common.security.AccessResponse
import fr.dcproject.component.citizen.CitizenI import fr.dcproject.component.citizen.CitizenI
import fr.dcproject.component.opinion.entity.OpinionI import fr.dcproject.component.opinion.entity.OpinionI
import fr.postgresjson.entity.EntityCreatedBy
import fr.postgresjson.entity.EntityDeletedAt
class OpinionAccessControl : AccessControl() { class OpinionAccessControl : AccessControl() {
@@ -17,21 +17,21 @@ class OpinionAccessControl : AccessControl() {
val target = subject.target val target = subject.target
return when { return when {
citizen == null -> denied("You must be connected to make an opinion", "opinion.create.notConnected") citizen == null -> denied("You must be connected to make an opinion", "opinion.create.notConnected")
target is EntityDeletedAt && target.isDeleted() -> denied("You cannot make opinion on deleted target", "opinion.create.deletedTarget") target is DeletedAt && target.isDeleted() -> denied("You cannot make opinion on deleted target", "opinion.create.deletedTarget")
else -> granted() else -> granted()
} }
} }
fun <S, SS : List<S>, C : CitizenI> canView(subjects: SS, citizen: CitizenI?): AccessResponse where S : OpinionI, S : EntityCreatedBy<C> = fun <S, SS : List<S>, C : CitizenI> canView(subjects: SS, citizen: CitizenI?): AccessResponse where S : OpinionI, S : CreatedBy<C> =
canAll(subjects) { canView(it, citizen) } canAll(subjects) { canView(it, citizen) }
fun <S, C : CitizenI> canView(subject: S, citizen: CitizenI?): AccessResponse where S : OpinionI, S : EntityCreatedBy<C> = when { fun <S, C : CitizenI> canView(subject: S, citizen: CitizenI?): AccessResponse where S : OpinionI, S : CreatedBy<C> = when {
citizen == null -> denied("You must be connected to delete opinion", "opinion.delete.notConnected") citizen == null -> denied("You must be connected to delete opinion", "opinion.delete.notConnected")
subject.createdBy.id != citizen.id -> denied("You cannot view opinions of other citizen", "opinion.view.otherCitizen") subject.createdBy.id != citizen.id -> denied("You cannot view opinions of other citizen", "opinion.view.otherCitizen")
else -> granted() else -> granted()
} }
fun <S, C : CitizenI> canDelete(subject: S, citizen: CitizenI?): AccessResponse where S : EntityCreatedBy<C>, S : OpinionI = when { fun <S, C : CitizenI> canDelete(subject: S, citizen: CitizenI?): AccessResponse where S : CreatedBy<C>, S : OpinionI = when {
citizen == null -> denied("You must be connected to delete opinion", "opinion.delete.notConnected") citizen == null -> denied("You must be connected to delete opinion", "opinion.delete.notConnected")
subject.createdBy.id != citizen.id -> denied("You can only delete your opinions", "opinion.delete.notYours") subject.createdBy.id != citizen.id -> denied("You can only delete your opinions", "opinion.delete.notYours")
else -> granted() else -> granted()

View File

@@ -1,5 +1,8 @@
package fr.dcproject.component.opinion.entity package fr.dcproject.component.opinion.entity
import fr.dcproject.common.entity.CreatedAt
import fr.dcproject.common.entity.CreatedBy
import fr.dcproject.common.entity.EntityI
import fr.dcproject.common.entity.ExtraI import fr.dcproject.common.entity.ExtraI
import fr.dcproject.common.entity.HasTarget import fr.dcproject.common.entity.HasTarget
import fr.dcproject.common.entity.TargetI import fr.dcproject.common.entity.TargetI
@@ -9,11 +12,6 @@ import fr.dcproject.component.citizen.CitizenBasic
import fr.dcproject.component.citizen.CitizenBasicI import fr.dcproject.component.citizen.CitizenBasicI
import fr.dcproject.component.citizen.CitizenI import fr.dcproject.component.citizen.CitizenI
import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.component.citizen.CitizenRef
import fr.postgresjson.entity.EntityCreatedAt
import fr.postgresjson.entity.EntityCreatedAtImp
import fr.postgresjson.entity.EntityCreatedBy
import fr.postgresjson.entity.EntityCreatedByImp
import fr.postgresjson.entity.UuidEntityI
import java.util.UUID import java.util.UUID
@Deprecated("") @Deprecated("")
@@ -24,8 +22,8 @@ open class Opinion<T : TargetI>(
val choice: OpinionChoice val choice: OpinionChoice
) : OpinionRef(id), ) : OpinionRef(id),
ExtraI<T, CitizenBasicI>, ExtraI<T, CitizenBasicI>,
EntityCreatedAt by EntityCreatedAtImp(), CreatedAt by CreatedAt.Imp(),
EntityCreatedBy<CitizenBasicI> by EntityCreatedByImp(createdBy) { CreatedBy<CitizenBasicI> by CreatedBy.Imp(createdBy) {
fun getName(): String = choice.name fun getName(): String = choice.name
} }
@@ -45,10 +43,10 @@ data class OpinionForUpdate<T : TargetI>(
override val createdBy: CitizenRef override val createdBy: CitizenRef
) : OpinionRef(id), ) : OpinionRef(id),
HasTarget<T>, HasTarget<T>,
EntityCreatedBy<CitizenI> by EntityCreatedByImp(createdBy) CreatedBy<CitizenI> by CreatedBy.Imp(createdBy)
open class OpinionRef( open class OpinionRef(
override val id: UUID override val id: UUID
) : OpinionI, TargetRef(id) ) : OpinionI, TargetRef(id)
interface OpinionI : UuidEntityI interface OpinionI : EntityI

View File

@@ -1,11 +1,9 @@
package fr.dcproject.component.opinion.entity package fr.dcproject.component.opinion.entity
import fr.postgresjson.entity.EntityCreatedAt import fr.dcproject.common.entity.CreatedAt
import fr.postgresjson.entity.EntityCreatedAtImp import fr.dcproject.common.entity.DeletedAt
import fr.postgresjson.entity.EntityDeletedAt import fr.dcproject.common.entity.Entity
import fr.postgresjson.entity.EntityDeletedAtImp import fr.dcproject.common.entity.EntityI
import fr.postgresjson.entity.UuidEntity
import fr.postgresjson.entity.UuidEntityI
import java.util.UUID import java.util.UUID
class OpinionChoice( class OpinionChoice(
@@ -13,12 +11,12 @@ class OpinionChoice(
val name: String, val name: String,
val target: List<String>? val target: List<String>?
) : OpinionChoiceRef(id), ) : OpinionChoiceRef(id),
EntityCreatedAt by EntityCreatedAtImp(), CreatedAt by CreatedAt.Imp(),
EntityDeletedAt by EntityDeletedAtImp() DeletedAt by DeletedAt.Imp()
open class OpinionChoiceRef( open class OpinionChoiceRef(
id: UUID? id: UUID?
) : OpinionChoiceI, ) : OpinionChoiceI,
UuidEntity(id ?: UUID.randomUUID()) Entity(id ?: UUID.randomUUID())
interface OpinionChoiceI : UuidEntityI interface OpinionChoiceI : EntityI

View File

@@ -1,13 +1,12 @@
package fr.dcproject.component.views.entity package fr.dcproject.component.views.entity
import fr.dcproject.common.entity.UpdatedAt
import fr.postgresjson.entity.EntityI import fr.postgresjson.entity.EntityI
import fr.postgresjson.entity.EntityUpdatedAt
import fr.postgresjson.entity.EntityUpdatedAtImp
class ViewAggregation( class ViewAggregation(
val total: Int, val total: Int,
val unique: Int val unique: Int
) : EntityI, ) : EntityI,
EntityUpdatedAt by EntityUpdatedAtImp() { UpdatedAt by UpdatedAt.Imp() {
constructor() : this(0, 0) constructor() : this(0, 0)
} }

View File

@@ -1,15 +1,15 @@
package fr.dcproject.component.vote package fr.dcproject.component.vote
import fr.dcproject.common.entity.DeletedAt
import fr.dcproject.common.entity.TargetI import fr.dcproject.common.entity.TargetI
import fr.dcproject.common.security.AccessControl import fr.dcproject.common.security.AccessControl
import fr.dcproject.common.security.AccessResponse import fr.dcproject.common.security.AccessResponse
import fr.dcproject.component.citizen.CitizenI import fr.dcproject.component.citizen.CitizenI
import fr.dcproject.component.vote.entity.VoteForUpdateI import fr.dcproject.component.vote.entity.VoteForUpdateI
import fr.postgresjson.entity.EntityDeletedAt
import fr.dcproject.component.vote.entity.Vote as VoteEntity import fr.dcproject.component.vote.entity.Vote as VoteEntity
class VoteAccessControl : AccessControl() { class VoteAccessControl : AccessControl() {
fun <S> canCreate(subject: VoteForUpdateI<S, *>, citizen: CitizenI?): AccessResponse where S : EntityDeletedAt, S : TargetI = when { fun <S> canCreate(subject: VoteForUpdateI<S, *>, citizen: CitizenI?): AccessResponse where S : DeletedAt, S : TargetI = when {
citizen == null -> denied("You must be connected for vote", "vote.create.connected") citizen == null -> denied("You must be connected for vote", "vote.create.connected")
subject.target.isDeleted() -> denied("You cannot vote on deleted target", "vote.create.isDeleted") subject.target.isDeleted() -> denied("You cannot vote on deleted target", "vote.create.isDeleted")
else -> granted() else -> granted()

View File

@@ -1,18 +1,15 @@
package fr.dcproject.component.vote.entity package fr.dcproject.component.vote.entity
import fr.dcproject.common.entity.CreatedAt
import fr.dcproject.common.entity.CreatedBy
import fr.dcproject.common.entity.EntityI
import fr.dcproject.common.entity.ExtraI import fr.dcproject.common.entity.ExtraI
import fr.dcproject.common.entity.HasTarget import fr.dcproject.common.entity.HasTarget
import fr.dcproject.common.entity.TargetI import fr.dcproject.common.entity.TargetI
import fr.dcproject.common.entity.UpdatedAt
import fr.dcproject.component.citizen.CitizenBasic import fr.dcproject.component.citizen.CitizenBasic
import fr.dcproject.component.citizen.CitizenBasicI import fr.dcproject.component.citizen.CitizenBasicI
import fr.dcproject.component.citizen.CitizenI import fr.dcproject.component.citizen.CitizenI
import fr.postgresjson.entity.EntityCreatedAt
import fr.postgresjson.entity.EntityCreatedAtImp
import fr.postgresjson.entity.EntityCreatedBy
import fr.postgresjson.entity.EntityCreatedByImp
import fr.postgresjson.entity.EntityUpdatedAt
import fr.postgresjson.entity.EntityUpdatedAtImp
import fr.postgresjson.entity.UuidEntityI
import java.util.UUID import java.util.UUID
@Deprecated("") @Deprecated("")
@@ -24,9 +21,9 @@ class Vote<T : TargetI>(
var anonymous: Boolean = true var anonymous: Boolean = true
) : ExtraI<T, CitizenBasicI>, ) : ExtraI<T, CitizenBasicI>,
VoteRef(id), VoteRef(id),
EntityCreatedAt by EntityCreatedAtImp(), CreatedAt by CreatedAt.Imp(),
EntityCreatedBy<CitizenBasicI> by EntityCreatedByImp(createdBy), CreatedBy<CitizenBasicI> by CreatedBy.Imp(createdBy),
EntityUpdatedAt by EntityUpdatedAtImp() { UpdatedAt by UpdatedAt.Imp() {
init { init {
if (note > 1 && note < -1) { if (note > 1 && note < -1) {
error("note must be 1, 0 or -1") error("note must be 1, 0 or -1")
@@ -41,9 +38,9 @@ class VoteForUpdate<T : TargetI, C : CitizenI>(
override val createdBy: C override val createdBy: C
) : VoteRef(id), ) : VoteRef(id),
VoteForUpdateI<T, C>, VoteForUpdateI<T, C>,
EntityCreatedBy<C> by EntityCreatedByImp<C>(createdBy) CreatedBy<C> by CreatedBy.Imp<C>(createdBy)
interface VoteForUpdateI<T : TargetI, C : CitizenI> : VoteI, HasTarget<T>, EntityCreatedBy<C> { interface VoteForUpdateI<T : TargetI, C : CitizenI> : VoteI, HasTarget<T>, CreatedBy<C> {
override val id: UUID override val id: UUID
val note: Int val note: Int
override val target: T override val target: T
@@ -54,4 +51,4 @@ open class VoteRef(
override val id: UUID override val id: UUID
) : VoteI ) : VoteI
interface VoteI : UuidEntityI interface VoteI : EntityI

View File

@@ -1,8 +1,6 @@
package fr.dcproject.component.vote.entity package fr.dcproject.component.vote.entity
import fr.postgresjson.entity.EntityI import fr.dcproject.common.entity.UpdatedAt
import fr.postgresjson.entity.EntityUpdatedAt
import fr.postgresjson.entity.EntityUpdatedAtImp
class VoteAggregation( class VoteAggregation(
val up: Int, val up: Int,
@@ -10,7 +8,7 @@ class VoteAggregation(
val down: Int, val down: Int,
val total: Int, val total: Int,
val score: Int val score: Int
) : EntityI, ) : fr.postgresjson.entity.EntityI,
EntityUpdatedAt by EntityUpdatedAtImp() { UpdatedAt by UpdatedAt.Imp() {
constructor() : this(0, 0, 0, 0, 0) constructor() : this(0, 0, 0, 0, 0)
} }

View File

@@ -1,22 +1,18 @@
package fr.dcproject.component.workgroup package fr.dcproject.component.workgroup
import fr.dcproject.common.entity.CreatedAt
import fr.dcproject.common.entity.CreatedBy
import fr.dcproject.common.entity.DeletedAt
import fr.dcproject.common.entity.Entity
import fr.dcproject.common.entity.EntityI
import fr.dcproject.common.entity.UpdatedAt
import fr.dcproject.component.auth.UserI import fr.dcproject.component.auth.UserI
import fr.dcproject.component.citizen.CitizenBasicI import fr.dcproject.component.citizen.CitizenBasicI
import fr.dcproject.component.citizen.CitizenI import fr.dcproject.component.citizen.CitizenI
import fr.dcproject.component.citizen.CitizenWithUserI import fr.dcproject.component.citizen.CitizenWithUserI
import fr.dcproject.component.workgroup.WorkgroupWithMembersI.Member import fr.dcproject.component.workgroup.WorkgroupWithMembersI.Member
import fr.dcproject.component.workgroup.WorkgroupWithMembersI.Member.Role import fr.dcproject.component.workgroup.WorkgroupWithMembersI.Member.Role
import fr.postgresjson.entity.EntityCreatedAt import fr.postgresjson.entity.Serializable
import fr.postgresjson.entity.EntityCreatedAtImp
import fr.postgresjson.entity.EntityCreatedBy
import fr.postgresjson.entity.EntityCreatedByImp
import fr.postgresjson.entity.EntityDeletedAt
import fr.postgresjson.entity.EntityDeletedAtImp
import fr.postgresjson.entity.EntityI
import fr.postgresjson.entity.EntityUpdatedAt
import fr.postgresjson.entity.EntityUpdatedAtImp
import fr.postgresjson.entity.UuidEntity
import fr.postgresjson.entity.UuidEntityI
import java.util.UUID import java.util.UUID
@Deprecated("") @Deprecated("")
@@ -37,8 +33,8 @@ data class Workgroup <C : CitizenBasicI>(
anonymous, anonymous,
createdBy createdBy
), ),
EntityCreatedAt by EntityCreatedAtImp(), CreatedAt by CreatedAt.Imp(),
EntityUpdatedAt by EntityUpdatedAtImp() UpdatedAt by UpdatedAt.Imp()
@Deprecated("") @Deprecated("")
open class WorkgroupSimple<Z : CitizenI>( open class WorkgroupSimple<Z : CitizenI>(
@@ -49,22 +45,22 @@ open class WorkgroupSimple<Z : CitizenI>(
open var anonymous: Boolean = true, open var anonymous: Boolean = true,
createdBy: Z createdBy: Z
) : WorkgroupRef(id), ) : WorkgroupRef(id),
EntityCreatedBy<Z> by EntityCreatedByImp(createdBy), CreatedBy<Z> by CreatedBy.Imp(createdBy),
EntityDeletedAt by EntityDeletedAtImp() DeletedAt by DeletedAt.Imp()
class WorkgroupCart( class WorkgroupCart(
override val id: UUID, override val id: UUID,
override val name: String override val name: String
) : WorkgroupCartI ) : WorkgroupCartI
interface WorkgroupCartI : UuidEntityI { interface WorkgroupCartI : EntityI {
val name: String val name: String
} }
open class WorkgroupRef( open class WorkgroupRef(
id: UUID? = null id: UUID? = null
) : UuidEntity(id ?: UUID.randomUUID()), WorkgroupI ) : Entity(id ?: UUID.randomUUID()), WorkgroupI
interface WorkgroupWithAuthI<Z : CitizenWithUserI> : WorkgroupWithMembersI<Z>, EntityCreatedBy<Z>, EntityDeletedAt { interface WorkgroupWithAuthI<Z : CitizenWithUserI> : WorkgroupWithMembersI<Z>, CreatedBy<Z>, DeletedAt {
val anonymous: Boolean val anonymous: Boolean
fun isMember(user: UserI): Boolean = members.isMember(user) fun isMember(user: UserI): Boolean = members.isMember(user)
@@ -83,7 +79,7 @@ interface WorkgroupWithMembersI<Z : CitizenI> : WorkgroupI {
class Member<C : CitizenI> ( class Member<C : CitizenI> (
val citizen: C, val citizen: C,
val roles: List<Role> = emptyList() val roles: List<Role> = emptyList()
) : EntityI { ) : fr.postgresjson.entity.EntityI {
enum class Role { enum class Role {
MASTER, MASTER,
MANAGER, MANAGER,
@@ -113,4 +109,4 @@ fun <Z : CitizenWithUserI> List<Member<Z>>.getRoles(user: UserI): List<Role> =
fun <Z : CitizenWithUserI> List<Member<Z>>.getRoles(citizen: CitizenI): List<Role> = fun <Z : CitizenWithUserI> List<Member<Z>>.getRoles(citizen: CitizenI): List<Role> =
firstOrNull { it.citizen.id == citizen.id }?.roles ?: emptyList() firstOrNull { it.citizen.id == citizen.id }?.roles ?: emptyList()
interface WorkgroupI : UuidEntityI interface WorkgroupI : EntityI