Multiple minors fix and improve

use data class for entity
Add sealed on entity interfaces
Replace listOf() by setOf() instead of deduplicate
use interface instead of EntityRef
replace .toLowerCase() to .lowercase()
fix test.sh
This commit is contained in:
2022-03-03 19:42:18 +01:00
parent 1c013e3e15
commit f380231e1e
32 changed files with 180 additions and 179 deletions

View File

@@ -48,7 +48,7 @@ data class ArticleForView(
val lastVersion: Boolean = false val lastVersion: Boolean = false
} }
interface ArticleForUpdateI<C : CitizenRef> : ArticleI, ArticleWithTitleI, VersionableId, TargetI, CreatedBy<C> { sealed 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
@@ -56,13 +56,13 @@ interface ArticleForUpdateI<C : CitizenRef> : ArticleI, ArticleWithTitleI, Versi
val workgroup: WorkgroupRef? val workgroup: WorkgroupRef?
} }
class ArticleForUpdate( data class ArticleForUpdate(
override val id: UUID = UUID.randomUUID(), override val id: UUID = UUID.randomUUID(),
override val title: String, override val title: String,
override val anonymous: Boolean = true, override val anonymous: Boolean = true,
override val content: String, override val content: String,
override val description: String, override val description: String,
tags: List<String> = emptyList(), val tags: Set<String> = emptySet(),
override val draft: Boolean = false, override val draft: Boolean = false,
override val createdBy: CitizenRef, override val createdBy: CitizenRef,
override val workgroup: WorkgroupRef? = null, override val workgroup: WorkgroupRef? = null,
@@ -71,12 +71,10 @@ class ArticleForUpdate(
) : ArticleRef(id), ) : ArticleRef(id),
ArticleForUpdateI<CitizenRef>, ArticleForUpdateI<CitizenRef>,
ArticleAuthI<CitizenRef>, ArticleAuthI<CitizenRef>,
VersionableId { VersionableId
val tags: List<String> = tags.distinct()
}
class ArticleForListing( data class ArticleForListing(
id: UUID? = null, override val id: UUID = UUID.randomUUID(),
override val title: String, override val title: String,
override val createdBy: CitizenCreator, override val createdBy: CitizenCreator,
override val workgroup: WorkgroupCart? = null, override val workgroup: WorkgroupCart? = null,
@@ -90,7 +88,7 @@ class ArticleForListing(
CreatedAt by CreatedAt.Imp(), CreatedAt by CreatedAt.Imp(),
CreatedBy<CitizenCartI> CreatedBy<CitizenCartI>
interface ArticleForListingI : ArticleWithTitleI, CreatedBy<CitizenCartI> { sealed interface ArticleForListingI : ArticleWithTitleI, CreatedBy<CitizenCartI> {
val workgroup: WorkgroupCartI? val workgroup: WorkgroupCartI?
} }
@@ -98,13 +96,13 @@ open class ArticleRef(
id: UUID? = null id: UUID? = null
) : ArticleI, TargetRef(id) ) : ArticleI, TargetRef(id)
interface ArticleI : EntityI, TargetI sealed interface ArticleI : EntityI, TargetI
interface ArticleWithTitleI : ArticleI { sealed interface ArticleWithTitleI : ArticleI {
val title: String val title: String
} }
interface ArticleAuthI<U : CitizenI> : sealed interface ArticleAuthI<U : CitizenI> :
ArticleI, ArticleI,
CreatedBy<U>, CreatedBy<U>,
DeletedAt { DeletedAt {

View File

@@ -37,7 +37,7 @@ object UpsertArticle {
val anonymous: Boolean = true, val anonymous: Boolean = true,
val content: String, val content: String,
val description: String, val description: String,
val tags: List<String> = emptyList(), val tags: Set<String> = emptySet(),
val draft: Boolean = false, val draft: Boolean = false,
val versionId: UUID, val versionId: UUID,
val workgroup: WorkgroupRef? = null, val workgroup: WorkgroupRef? = null,

View File

@@ -9,35 +9,45 @@ import io.ktor.auth.Principal
import org.joda.time.DateTime import org.joda.time.DateTime
import java.util.UUID import java.util.UUID
class UserForCreate( data class UserForCreate(
id: UUID = UUID.randomUUID(), override val id: UUID = UUID.randomUUID(),
username: String, override val username: String,
override val password: String, override val password: String,
blockedAt: DateTime? = null, override val blockedAt: DateTime? = null,
roles: List<Roles> = emptyList() override val roles: Set<Roles> = emptySet()
) : User(id, username, blockedAt, roles), ) : UserForViewI,
UserWithPasswordI UserWithPasswordI,
CreatedAt by CreatedAt.Imp(),
UpdatedAt by UpdatedAt.Imp()
open class User( data class User(
id: UUID = UUID.randomUUID(), override val id: UUID = UUID.randomUUID(),
override var username: String, override val username: String,
var blockedAt: DateTime? = null, override val blockedAt: DateTime? = null,
var roles: List<Roles> = emptyList() override val roles: Set<Roles> = emptySet()
) : UserRef(id), ) : UserRef(id),
UserForViewI,
UserWithUsername, UserWithUsername,
CreatedAt by CreatedAt.Imp(), CreatedAt by CreatedAt.Imp(),
UpdatedAt by UpdatedAt.Imp() UpdatedAt by UpdatedAt.Imp()
sealed interface UserForViewI :
UserI,
UserWithUsername,
UserForAuthI,
CreatedAt,
UpdatedAt
class UserCreator( class UserCreator(
id: UUID = UUID.randomUUID(), id: UUID = UUID.randomUUID(),
override val username: String, override val username: String,
) : UserRef(id), UserWithUsername ) : UserRef(id), UserWithUsername
interface UserWithUsername : UserI { sealed interface UserWithUsername : UserI {
val username: String val username: String
} }
interface UserWithPasswordI : UserI { sealed interface UserWithPasswordI : UserI {
val password: String val password: String
} }
@@ -51,11 +61,11 @@ open class UserRef(
id: UUID = UUID.randomUUID() id: UUID = UUID.randomUUID()
) : UserI, Entity(id) ) : UserI, Entity(id)
interface UserI : EntityI, Principal { sealed interface UserI : EntityI, Principal {
enum class Roles { ROLE_USER, ROLE_ADMIN } enum class Roles { ROLE_USER, ROLE_ADMIN }
} }
interface UserForAuthI : UserI { sealed interface UserForAuthI : UserI {
var roles: List<Roles> val roles: Set<Roles>
var blockedAt: DateTime? val blockedAt: DateTime?
} }

View File

@@ -91,7 +91,7 @@ object Register {
user = UserForCreate( user = UserForCreate(
username = user.username, username = user.username,
password = user.password, password = user.password,
roles = listOf(UserI.Roles.ROLE_USER) roles = setOf(UserI.Roles.ROLE_USER)
) )
) )

View File

@@ -17,19 +17,19 @@ import fr.postgresjson.entity.Serializable
import org.joda.time.DateTime import org.joda.time.DateTime
import java.util.UUID import java.util.UUID
class CitizenForCreate( data class CitizenForCreate(
val name: Name, val name: Name,
val email: String, val email: String,
val birthday: DateTime, val birthday: DateTime,
val voteAnonymous: Boolean = true, val voteAnonymous: Boolean = true,
val followAnonymous: Boolean = true, val followAnonymous: Boolean = true,
override val user: UserForCreate, override val user: UserForCreate,
id: UUID = UUID.randomUUID(), override val id: UUID = UUID.randomUUID(),
) : CitizenI, ) : CitizenI,
CitizenRefWithUser(id, user), CitizenWithUserI by CitizenRefWithUser(id, user),
CreatedAt by CreatedAt.Imp() CreatedAt by CreatedAt.Imp()
class Citizen( data class Citizen(
override val id: UUID = UUID.randomUUID(), override val id: UUID = UUID.randomUUID(),
override val name: Name, override val name: Name,
override val email: String, override val email: String,
@@ -37,7 +37,7 @@ class Citizen(
override val voteAnonymous: Boolean = true, override val voteAnonymous: Boolean = true,
override val followAnonymous: Boolean = true, override val followAnonymous: Boolean = true,
override val user: User, override val user: User,
deletedAt: DateTime? = null override val deletedAt: DateTime? = null
) : CitizenWithEmail, ) : CitizenWithEmail,
CitizenCreatorI, CitizenCreatorI,
CitizenWithUserI, CitizenWithUserI,
@@ -62,10 +62,11 @@ data class CitizenCreator(
override val user: UserCreator, override val user: UserCreator,
override val deletedAt: DateTime? = null override val deletedAt: DateTime? = null
) : CitizenCreatorI, ) : CitizenCreatorI,
CitizenRefWithUser(id, user), CitizenI,
CitizenWithUserI by CitizenRefWithUser(id, user),
DeletedAt by DeletedAt.Imp(deletedAt) DeletedAt by DeletedAt.Imp(deletedAt)
interface CitizenCreatorI : CitizenWithUserI, CitizenWithEmail, CitizenCartI, DeletedAt { sealed interface CitizenCreatorI : CitizenWithUserI, CitizenWithEmail, CitizenCartI, DeletedAt {
override val id: UUID override val id: UUID
override val name: Name override val name: Name
override val email: String override val email: String
@@ -75,8 +76,8 @@ interface CitizenCreatorI : CitizenWithUserI, CitizenWithEmail, CitizenCartI, De
override val deletedAt: DateTime? override val deletedAt: DateTime?
} }
class CitizenCart( data class CitizenCart(
id: UUID = UUID.randomUUID(), override val id: UUID = UUID.randomUUID(),
override val name: Name, override val name: Name,
override val user: UserRef, override val user: UserRef,
override val deletedAt: DateTime? = null, override val deletedAt: DateTime? = null,
@@ -84,13 +85,13 @@ class CitizenCart(
CitizenCartI, CitizenCartI,
DeletedAt by DeletedAt.Imp(deletedAt) DeletedAt by DeletedAt.Imp(deletedAt)
interface CitizenCartI : CitizenI, CitizenWithUserI { sealed interface CitizenCartI : CitizenI, CitizenWithUserI {
val name: Name val name: Name
} }
open class CitizenRefWithUser( data class CitizenRefWithUser(
id: UUID = UUID.randomUUID(), override val id: UUID = UUID.randomUUID(),
override val user: UserRef override val user: UserI
) : CitizenWithUserI, ) : CitizenWithUserI,
CitizenRef(id) CitizenRef(id)
@@ -99,7 +100,7 @@ open class CitizenRef(
) : TargetRef(id), ) : TargetRef(id),
CitizenI CitizenI
interface CitizenI : EntityI, TargetI { sealed interface CitizenI : EntityI, TargetI {
data class Name( data class Name(
override val firstName: String, override val firstName: String,
override val lastName: String, override val lastName: String,
@@ -114,10 +115,10 @@ interface CitizenI : EntityI, TargetI {
} }
} }
interface CitizenWithUserI : CitizenI { sealed interface CitizenWithUserI : CitizenI {
val user: UserI val user: UserI
} }
interface CitizenWithEmail : CitizenI { sealed interface CitizenWithEmail : CitizenI {
val email: String val email: String
} }

View File

@@ -16,8 +16,8 @@ import fr.dcproject.component.vote.entity.VotableImp
import org.joda.time.DateTime import org.joda.time.DateTime
import java.util.UUID import java.util.UUID
class CommentForView<T : TargetI, C : CitizenCreatorI>( data class CommentForView<T : TargetI, C : CitizenCreatorI>(
id: UUID = UUID.randomUUID(), override val id: UUID = UUID.randomUUID(),
override val createdBy: C, override val createdBy: C,
override val target: T, override val target: T,
override var content: String, override var content: String,
@@ -30,7 +30,7 @@ class CommentForView<T : TargetI, C : CitizenCreatorI>(
CommentWithTargetI<T>, CommentWithTargetI<T>,
CreatedBy<C> by CreatedBy.Imp(createdBy), CreatedBy<C> by CreatedBy.Imp(createdBy),
UpdatedAt by UpdatedAt.Imp(), UpdatedAt by UpdatedAt.Imp(),
DeletedAt by DeletedAt.Imp(), DeletedAt,
Votable by VotableImp(), Votable by VotableImp(),
TargetI { TargetI {
constructor( constructor(
@@ -50,9 +50,9 @@ open class CommentForUpdate<T : TargetI, C : CitizenI>(
override val createdBy: C, override val createdBy: C,
override val target: T, override val target: T,
open var content: String, open var content: String,
override val parent: CommentParent<T>? = null, override val parent: CommentParentI<T>? = null,
override val deletedAt: DateTime? = null override val deletedAt: DateTime? = null
) : CommentParent<T>(id, deletedAt, target), ) : CommentParentI<T> by CommentParent(id, deletedAt, target),
CommentWithParentI<T>, CommentWithParentI<T>,
ExtraI<T, C>, ExtraI<T, C>,
CommentWithTargetI<T>, CommentWithTargetI<T>,
@@ -62,7 +62,7 @@ open class CommentForUpdate<T : TargetI, C : CitizenI>(
TargetI { TargetI {
constructor( constructor(
createdBy: C, createdBy: C,
parent: CommentParent<T>, parent: CommentParentI<T>,
content: String, content: String,
id: UUID? = null, id: UUID? = null,
) : this( ) : this(
@@ -74,21 +74,21 @@ open class CommentForUpdate<T : TargetI, C : CitizenI>(
) )
} }
open class CommentParent<T : TargetI>( data class CommentParent<T : TargetI>(
override val id: UUID, override val id: UUID,
override val deletedAt: DateTime?, override val deletedAt: DateTime?,
override val target: T override val target: T
) : CommentRef(id), ) : CommentRef(id),
CommentParentI<T> CommentParentI<T>
interface CommentParentI<T : TargetI> : CommentI, DeletedAt, CommentWithTargetI<T> sealed interface CommentParentI<T : TargetI> : CommentI, DeletedAt, CommentWithTargetI<T>
interface CommentWithTargetI<T : TargetI> : CommentI, TargetI, HasTarget<T> interface CommentWithTargetI<T : TargetI> : CommentI, TargetI, HasTarget<T>
interface CommentWithParentI<T : TargetI> { interface CommentWithParentI<T : TargetI> {
val parent: CommentParent<T>? val parent: CommentParentI<T>?
} }
open class CommentRef(id: UUID = UUID.randomUUID()) : CommentI, TargetRef(id) open class CommentRef(id: UUID = UUID.randomUUID()) : CommentI, TargetRef(id)
interface CommentI : EntityI sealed interface CommentI : EntityI

View File

@@ -32,26 +32,21 @@ abstract class CommentRepositoryAbs<T : TargetI>(override var requester: Request
parentId: UUID, parentId: UUID,
page: Int = 1, page: Int = 1,
limit: Int = 50 limit: Int = 50
): Paginated<CommentForView<T, CitizenCreatorI>> { ): Paginated<CommentForView<T, CitizenCreatorI>> = requester
return requester.run { .getFunction("find_comments_by_parent")
getFunction("find_comments_by_parent")
.select<CommentForView<T, CitizenCreator>>( .select<CommentForView<T, CitizenCreator>>(
page, page,
limit, limit,
"parent_id" to parentId "parent_id" to parentId
) )
as Paginated<CommentForView<T, CitizenCreatorI>> as Paginated<CommentForView<T, CitizenCreatorI>>
}
}
open fun findByTarget( open fun findByTarget(
target: EntityI, target: EntityI,
page: Int = 1, page: Int = 1,
limit: Int = 50, limit: Int = 50,
sort: String = "createdAt" sort: String = "createdAt"
): Paginated<CommentForView<T, CitizenCreatorI>> { ): Paginated<CommentForView<T, CitizenCreatorI>> = findByTarget(target.id, page, limit, sort)
return findByTarget(target.id, page, limit, sort)
}
open fun findByTarget( open fun findByTarget(
targetId: UUID, targetId: UUID,
@@ -85,35 +80,29 @@ abstract class CommentRepositoryAbs<T : TargetI>(override var requester: Request
} }
class CommentRepository(requester: Requester) : CommentRepositoryAbs<TargetRef>(requester) { class CommentRepository(requester: Requester) : CommentRepositoryAbs<TargetRef>(requester) {
override fun findById(id: UUID): CommentForView<TargetRef, CitizenCreatorI>? { override fun findById(id: UUID): CommentForView<TargetRef, CitizenCreatorI>? = requester
return requester
.getFunction("find_comment_by_id") .getFunction("find_comment_by_id")
.selectOne<CommentForView<TargetRef, CitizenCreator>>(mapOf("id" to id)) .selectOne<CommentForView<TargetRef, CitizenCreator>>(mapOf("id" to id))
as CommentForView<TargetRef, CitizenCreatorI>? as CommentForView<TargetRef, CitizenCreatorI>?
}
override fun findByCitizen( override fun findByCitizen(
citizen: CitizenI, citizen: CitizenI,
page: Int, page: Int,
limit: Int limit: Int
): Paginated<CommentForView<TargetRef, CitizenCreatorI>> { ): Paginated<CommentForView<TargetRef, CitizenCreatorI>> = requester
return requester.run { .getFunction("find_comments_by_citizen")
getFunction("find_comments_by_citizen")
.select<CommentForView<TargetRef, CitizenCreator>>( .select<CommentForView<TargetRef, CitizenCreator>>(
page, page,
limit, limit,
"created_by_id" to citizen.id "created_by_id" to citizen.id
) as Paginated<CommentForView<TargetRef, CitizenCreatorI>> ) as Paginated<CommentForView<TargetRef, CitizenCreatorI>>
}
}
override fun findByParent( override fun findByParent(
parentId: UUID, parentId: UUID,
page: Int, page: Int,
limit: Int limit: Int
): Paginated<CommentForView<TargetRef, CitizenCreatorI>> { ): Paginated<CommentForView<TargetRef, CitizenCreatorI>> = requester
return requester.run { .getFunction("find_comments_by_parent")
getFunction("find_comments_by_parent")
.select<CommentForView<TargetRef, CitizenCreator>>( .select<CommentForView<TargetRef, CitizenCreator>>(
page, page,
limit, limit,
@@ -121,5 +110,3 @@ class CommentRepository(requester: Requester) : CommentRepositoryAbs<TargetRef>(
) )
as Paginated<CommentForView<TargetRef, CitizenCreatorI>> as Paginated<CommentForView<TargetRef, CitizenCreatorI>>
} }
}
}

View File

@@ -8,19 +8,18 @@ import fr.dcproject.common.entity.HasTarget
import fr.dcproject.common.entity.TargetI import fr.dcproject.common.entity.TargetI
import fr.dcproject.component.citizen.database.CitizenCreator import fr.dcproject.component.citizen.database.CitizenCreator
import fr.dcproject.component.citizen.database.CitizenI import fr.dcproject.component.citizen.database.CitizenI
import fr.dcproject.component.citizen.database.CitizenRef
import java.util.UUID import java.util.UUID
open class FollowForView<T : TargetI>( data class FollowForView<T : TargetI>(
id: UUID = UUID.randomUUID(), override val id: UUID = UUID.randomUUID(),
override val createdBy: CitizenCreator, override val createdBy: CitizenCreator,
override var target: T override var target: T
) : ExtraI<T, CitizenRef>, ) : ExtraI<T, CitizenI>,
FollowRef(id), FollowRef(id),
Created<CitizenRef> by Created.Imp(createdBy) Created<CitizenI> by Created.Imp(createdBy)
class FollowForUpdate<T : TargetI, C : CitizenI>( data class FollowForUpdate<T : TargetI, C : CitizenI>(
id: UUID = UUID.randomUUID(), override val id: UUID = UUID.randomUUID(),
override val target: T, override val target: T,
override val createdBy: C override val createdBy: C
) : FollowRef(id), ) : FollowRef(id),
@@ -31,4 +30,4 @@ open class FollowRef(
override val id: UUID override val id: UUID
) : FollowI ) : FollowI
interface FollowI : EntityI sealed interface FollowI : EntityI

View File

@@ -53,11 +53,11 @@ open class NotificationMessage(
} }
open class EntityNotificationMessage <E : Entity> ( open class EntityNotificationMessage <E : Entity> (
val target: E, open val target: E,
type: String, type: String,
val action: String val action: String
) : NotificationMessage(type) ) : NotificationMessage(type)
class ArticleUpdateNotificationMessage( data class ArticleUpdateNotificationMessage(
target: ArticleForView override val target: ArticleForView
) : EntityNotificationMessage<ArticleForView>(target, "article", "update") ) : EntityNotificationMessage<ArticleForView>(target, "article", "update")

View File

@@ -3,7 +3,7 @@ package fr.dcproject.component.notification.email.content
import fr.dcproject.component.article.database.ArticleWithTitleI import fr.dcproject.component.article.database.ArticleWithTitleI
import fr.dcproject.component.citizen.database.Citizen import fr.dcproject.component.citizen.database.Citizen
class ArticleNotificationEmailContent( data class ArticleNotificationEmailContent(
private val citizen: Citizen, private val citizen: Citizen,
private val target: ArticleWithTitleI, private val target: ArticleWithTitleI,
private val domain: String, private val domain: String,

View File

@@ -2,7 +2,7 @@ package fr.dcproject.component.notification.email.content
import fr.dcproject.component.citizen.database.Citizen import fr.dcproject.component.citizen.database.Citizen
class CitizenNotificationEmailContent( data class CitizenNotificationEmailContent(
private val citizen: Citizen, private val citizen: Citizen,
private val target: Citizen, private val target: Citizen,
private val domain: String, private val domain: String,

View File

@@ -13,8 +13,8 @@ import fr.dcproject.component.citizen.database.CitizenI
import fr.dcproject.component.citizen.database.CitizenRef import fr.dcproject.component.citizen.database.CitizenRef
import java.util.UUID import java.util.UUID
open class Opinion<T : TargetI>( data class Opinion<T : TargetI>(
id: UUID = UUID.randomUUID(), override val id: UUID = UUID.randomUUID(),
override val createdBy: CitizenCreator, override val createdBy: CitizenCreator,
override val target: T, override val target: T,
val choice: OpinionChoice val choice: OpinionChoice
@@ -39,4 +39,4 @@ open class OpinionRef(
override val id: UUID override val id: UUID
) : OpinionI, TargetRef(id) ) : OpinionI, TargetRef(id)
interface OpinionI : EntityI sealed interface OpinionI : EntityI

View File

@@ -7,6 +7,4 @@ interface Opinionable {
val opinions: Opinions val opinions: Opinions
} }
class OpinionableImp : Opinionable { data class OpinionableImp(override var opinions: OpinionsMutable = mutableMapOf()) : Opinionable
override var opinions: OpinionsMutable = mutableMapOf()
}

View File

@@ -2,7 +2,7 @@ package fr.dcproject.component.views.dto
import fr.dcproject.component.views.entity.ViewAggregation import fr.dcproject.component.views.entity.ViewAggregation
class ViewAggregation( data class ViewAggregation(
val total: Int, val total: Int,
val unique: Int val unique: Int
) { ) {

View File

@@ -3,7 +3,7 @@ package fr.dcproject.component.views.entity
import fr.dcproject.common.entity.UpdatedAt import fr.dcproject.common.entity.UpdatedAt
import fr.postgresjson.entity.EntityI import fr.postgresjson.entity.EntityI
class ViewAggregation( data class ViewAggregation(
val total: Int, val total: Int,
val unique: Int val unique: Int
) : EntityI, ) : EntityI,

View File

@@ -12,8 +12,8 @@ import fr.dcproject.component.citizen.database.CitizenCreatorI
import fr.dcproject.component.citizen.database.CitizenI import fr.dcproject.component.citizen.database.CitizenI
import java.util.UUID import java.util.UUID
class VoteForView<T : TargetI>( data class VoteForView<T : TargetI>(
id: UUID = UUID.randomUUID(), override val id: UUID = UUID.randomUUID(),
override val createdBy: CitizenCreator, override val createdBy: CitizenCreator,
override val target: T, override val target: T,
val note: Int, val note: Int,
@@ -30,7 +30,7 @@ class VoteForView<T : TargetI>(
} }
} }
class VoteForUpdate<T : TargetI, C : CitizenI>( data class VoteForUpdate<T : TargetI, C : CitizenI>(
override val id: UUID = UUID.randomUUID(), override val id: UUID = UUID.randomUUID(),
override val note: Int, override val note: Int,
override val target: T, override val target: T,

View File

@@ -2,10 +2,18 @@ package fr.dcproject.component.vote.dto
import fr.dcproject.component.vote.entity.Votable import fr.dcproject.component.vote.entity.Votable
class VoteAggregation(parent: Votable) { data class VoteAggregation(
val up: Int = parent.votes.up val up: Int,
val neutral: Int = parent.votes.neutral val neutral: Int,
val down: Int = parent.votes.down val down: Int,
val total: Int = parent.votes.total val total: Int,
val score: Int = parent.votes.score val score: Int
) {
constructor(parent: Votable) : this(
up = parent.votes.up,
neutral = parent.votes.neutral,
down = parent.votes.down,
total = parent.votes.total,
score = parent.votes.score
)
} }

View File

@@ -4,6 +4,6 @@ interface Votable {
val votes: VoteAggregation val votes: VoteAggregation
} }
class VotableImp : Votable { data class VotableImp(
override val votes: VoteAggregation = VoteAggregation() override val votes: VoteAggregation = VoteAggregation()
} ) : Votable

View File

@@ -43,17 +43,17 @@ data class WorkgroupForUpdate<C : CitizenWithUserI>(
WorkgroupForUpdateI<C>, WorkgroupForUpdateI<C>,
CreatedBy<C> by CreatedBy.Imp(createdBy) CreatedBy<C> by CreatedBy.Imp(createdBy)
interface WorkgroupForUpdateI<C : CitizenWithUserI> : WorkgroupWithAuthI<C>, WorkgroupCartI, CreatedBy<C> { sealed interface WorkgroupForUpdateI<C : CitizenWithUserI> : WorkgroupWithAuthI<C>, WorkgroupCartI, CreatedBy<C> {
val description: String val description: String
val logo: String? val logo: String?
} }
class WorkgroupCart( data class WorkgroupCart(
override val id: UUID, override val id: UUID,
override val name: String override val name: String
) : WorkgroupCartI ) : WorkgroupCartI
interface WorkgroupCartI : EntityI { sealed interface WorkgroupCartI : EntityI {
val name: String val name: String
} }
@@ -61,7 +61,7 @@ open class WorkgroupRef(
id: UUID? = null id: UUID? = null
) : Entity(id ?: UUID.randomUUID()), WorkgroupI ) : Entity(id ?: UUID.randomUUID()), WorkgroupI
interface WorkgroupWithAuthI<Z : CitizenWithUserI> : WorkgroupWithMembersI<Z>, CreatedBy<Z>, DeletedAt { sealed 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)
@@ -70,11 +70,11 @@ interface WorkgroupWithAuthI<Z : CitizenWithUserI> : WorkgroupWithMembersI<Z>, C
fun hasRole(expectedRole: Role, user: UserI): Boolean = members.hasRole(expectedRole, user) fun hasRole(expectedRole: Role, user: UserI): Boolean = members.hasRole(expectedRole, user)
fun hasRole(expectedRole: Role, citizen: CitizenI): Boolean = members.hasRole(expectedRole, citizen) fun hasRole(expectedRole: Role, citizen: CitizenI): Boolean = members.hasRole(expectedRole, citizen)
fun getRoles(user: UserI): List<Role> = members.getRoles(user) fun getRoles(user: UserI): Collection<Role> = members.getRoles(user)
fun getRoles(citizen: CitizenI): List<Role> = members.getRoles(citizen) fun getRoles(citizen: CitizenI): Collection<Role> = members.getRoles(citizen)
} }
interface WorkgroupWithMembersI<Z : CitizenI> : WorkgroupI { sealed interface WorkgroupWithMembersI<Z : CitizenI> : WorkgroupI {
val members: List<Member<Z>> val members: List<Member<Z>>
class Member<C : CitizenI>( class Member<C : CitizenI>(
@@ -90,24 +90,24 @@ interface WorkgroupWithMembersI<Z : CitizenI> : WorkgroupI {
} }
} }
fun List<CitizenI>.hasCitizen(citizen: CitizenI): Boolean = this.map { it.id }.contains(citizen.id) fun Collection<CitizenI>.hasCitizen(citizen: CitizenI): Boolean = this.map { it.id }.contains(citizen.id)
fun <Z : CitizenWithUserI> List<Member<Z>>.isMember(user: UserI): Boolean = fun <Z : CitizenWithUserI> Collection<Member<Z>>.isMember(user: UserI): Boolean =
map { it.citizen.user.id }.contains(user.id) map { it.citizen.user.id }.contains(user.id)
fun <Z : CitizenI> List<Member<Z>>.isMember(citizen: CitizenI): Boolean = fun <Z : CitizenI> Collection<Member<Z>>.isMember(citizen: CitizenI): Boolean =
map { it.citizen.id }.contains(citizen.id) map { it.citizen.id }.contains(citizen.id)
fun <Z : CitizenI> List<Member<Z>>.hasRole(expectedRole: Role, citizen: CitizenI): Boolean = fun <Z : CitizenI> Collection<Member<Z>>.hasRole(expectedRole: Role, citizen: CitizenI): Boolean =
any { member -> member.citizen.id == citizen.id && member.roles.any { it == expectedRole } } any { member -> member.citizen.id == citizen.id && member.roles.any { it == expectedRole } }
fun <Z : CitizenWithUserI> List<Member<Z>>.hasRole(expectedRole: Role, user: UserI): Boolean = fun <Z : CitizenWithUserI> Collection<Member<Z>>.hasRole(expectedRole: Role, user: UserI): Boolean =
any { member -> member.citizen.user.id == user.id && member.roles.any { it == expectedRole } } any { member -> member.citizen.user.id == user.id && member.roles.any { it == expectedRole } }
fun <Z : CitizenWithUserI> List<Member<Z>>.getRoles(user: UserI): List<Role> = fun <Z : CitizenWithUserI> Collection<Member<Z>>.getRoles(user: UserI): Collection<Role> =
firstOrNull { it.citizen.user.id == user.id }?.roles ?: emptyList() firstOrNull { it.citizen.user.id == user.id }?.roles ?: emptyList()
fun <Z : CitizenWithUserI> List<Member<Z>>.getRoles(citizen: CitizenI): List<Role> = fun <Z : CitizenWithUserI> Collection<Member<Z>>.getRoles(citizen: CitizenI): Collection<Role> =
firstOrNull { it.citizen.id == citizen.id }?.roles ?: emptyList() firstOrNull { it.citizen.id == citizen.id }?.roles ?: emptyList()
interface WorkgroupI : EntityI interface WorkgroupI : EntityI

View File

@@ -20,8 +20,8 @@ import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS import org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS
import org.koin.ktor.ext.get import org.koin.ktor.ext.get
import java.util.UUID import java.util.UUID
import kotlin.time.Duration.Companion.seconds
import kotlin.time.ExperimentalTime import kotlin.time.ExperimentalTime
import kotlin.time.seconds
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
@ExperimentalCoroutinesApi @ExperimentalCoroutinesApi
@@ -78,7 +78,7 @@ class ViewTest {
) )
/* Retry because ES is not sync ! */ /* Retry because ES is not sync ! */
retry(10, 0.3.seconds) { retry(10, seconds(0.3)) {
/* Get view */ /* Get view */
val afterView = viewRepository.getViewsCount(article) val afterView = viewRepository.getViewsCount(article)

View File

@@ -35,7 +35,7 @@ class `Check auth on all routes` : BaseTest() {
/* Send request to check security */ /* Send request to check security */
sendRequest( sendRequest(
path.buildUrl(pathName, methodName, api.context), /* Replace route to real URL */ path.buildUrl(pathName, methodName, api.context), /* Replace route to real URL */
HttpMethod.parse(methodName.toUpperCase()) /* Convert http method name to enum */ HttpMethod.parse(methodName.lowercase()) /* Convert http method name to enum */
) )
} }
}.let { requests -> }.let { requests ->

View File

@@ -13,7 +13,7 @@ fun TestApplicationRequest.`authenticated as`(
firstName: String, firstName: String,
lastName: String, lastName: String,
): Citizen { ): Citizen {
val username = "$firstName-$lastName".toLowerCase() val username = "$firstName-$lastName".lowercase()
val repo: CitizenRepository by lazy<CitizenRepository> { GlobalContext.get().get() } val repo: CitizenRepository by lazy<CitizenRepository> { GlobalContext.get().get() }
val citizen = repo.findByUsername(username) ?: error("Citizen not exist with username $username") val citizen = repo.findByUsername(username) ?: error("Citizen not exist with username $username")
val algorithm = GlobalContext.get().get<JwtConfig>().algorithm val algorithm = GlobalContext.get().get<JwtConfig>().algorithm

View File

@@ -14,7 +14,7 @@ import java.util.UUID
fun TestApplicationEngine.`Given I have citizen`( fun TestApplicationEngine.`Given I have citizen`(
firstName: String, firstName: String,
lastName: String, lastName: String,
email: String = ("$firstName-$lastName".toLowerCase()) + "@dc-project.fr", email: String = ("$firstName-$lastName".lowercase()) + "@dc-project.fr",
id: String = UUID.randomUUID().toString(), id: String = UUID.randomUUID().toString(),
callback: Citizen.() -> Unit = {} callback: Citizen.() -> Unit = {}
): Citizen? { ): Citizen? {
@@ -22,7 +22,7 @@ fun TestApplicationEngine.`Given I have citizen`(
val user = UserForCreate( val user = UserForCreate(
id = id.toUUID(), id = id.toUUID(),
username = "$firstName-$lastName".toLowerCase(), username = "$firstName-$lastName".lowercase(),
password = "Azerty123!", password = "Azerty123!",
) )
val citizen = CitizenForCreate( val citizen = CitizenForCreate(

View File

@@ -62,7 +62,7 @@ private fun createWorkgroup(
val creatorName = createdBy ?: CitizenI.Name("Paul", "Langevin") val creatorName = createdBy ?: CitizenI.Name("Paul", "Langevin")
val creator = citizenRepository.findByName(creatorName) ?: run { val creator = citizenRepository.findByName(creatorName) ?: run {
val username = ("username" + UUID.randomUUID().toString()) val username = ("username" + UUID.randomUUID().toString())
.toLowerCase().replace(' ', '-') .lowercase().replace(' ', '-')
val user = UserForCreate( val user = UserForCreate(
username = username, username = username,
password = "Azerty123!", password = "Azerty123!",

View File

@@ -46,7 +46,7 @@ fun TestApplicationResponse.operation(route: String? = null, callback: Operation
.firstOrNull { uri.matches(it.replace("""\{[^{}]+}""".toRegex(), "[^/]+").toRegex()) } .firstOrNull { uri.matches(it.replace("""\{[^{}]+}""".toRegex(), "[^/]+").toRegex()) }
api.getPath(path) api.getPath(path)
?.getOperation(httpMethod.value.toLowerCase()) ?.getOperation(httpMethod.value.lowercase())
?.apply { ?.apply {
this.callback(api, uri) this.callback(api, uri)
} }
@@ -59,7 +59,7 @@ fun TestApplicationResponse.`And the schema response body must be valid`(content
/* Validate Response */ /* Validate Response */
this.apply { this.apply {
val status = call.response.status() val status = call.response.status()
val httpMethod = call.request.httpMethod.value.toUpperCase() val httpMethod = call.request.httpMethod.value.lowercase()
val responseContent: JsonNode = if (content != null) val responseContent: JsonNode = if (content != null)
ObjectMapper().readTree(content) ObjectMapper().readTree(content)
else TextNode("") else TextNode("")
@@ -79,7 +79,7 @@ fun TestApplicationResponse.`And the schema parameters must be valid`() {
operation { api, uri -> operation { api, uri ->
/* Validate Request URL */ /* Validate Request URL */
this.apply { this.apply {
val methodName = call.request.httpMethod.value.toUpperCase() val methodName = call.request.httpMethod.value.lowercase()
Url(call.request.uri).parameters.forEach { parameter: String, values: List<String> -> Url(call.request.uri).parameters.forEach { parameter: String, values: List<String> ->
val schema = getParametersIn(api.context, "query") val schema = getParametersIn(api.context, "query")
?.firstOrNull { it.name == parameter }?.schema ?.firstOrNull { it.name == parameter }?.schema
@@ -103,7 +103,7 @@ fun TestApplicationResponse.`And the schema parameters must be valid`() {
* Validate request body * Validate request body
*/ */
fun TestApplicationResponse.`And the schema request body must be valid`(body: String) { fun TestApplicationResponse.`And the schema request body must be valid`(body: String) {
operation { api, uri -> operation { api, _ ->
requestBody requestBody
.getContentMediaType(call.request.contentType().toString()) .getContentMediaType(call.request.contentType().toString())
.schema .schema

View File

@@ -15,15 +15,15 @@ import io.ktor.server.testing.TestApplicationRequest
import io.ktor.server.testing.setBody import io.ktor.server.testing.setBody
enum class Validate(override val bit: Long) : BitMaskI { enum class Validate(override val bit: Long) : BitMaskI {
NONE(0), NONE(0L),
REQUEST_BODY(1), REQUEST_BODY(1L),
REQUEST_PARAM(2), REQUEST_PARAM(2L),
REQUEST_HEADER(4), REQUEST_HEADER(4L),
REQUEST(1 + 2 + 4), REQUEST(1L + 2L + 4L),
RESPONSE_BODY(8), RESPONSE_BODY(8L),
RESPONSE_HEADER(16), RESPONSE_HEADER(16L),
RESPONSE(8 + 16), RESPONSE(8L + 16L),
ALL((1 + 2 + 4) + (8 + 16)); ALL((1L + 2L + 4L) + (8L + 16L));
operator fun unaryMinus(): BitMaskI = ALL - BitMask(this.bit) operator fun unaryMinus(): BitMaskI = ALL - BitMask(this.bit)
} }

View File

@@ -41,7 +41,7 @@ internal class `Article Access Control` {
private val einstein = CitizenCart( private val einstein = CitizenCart(
user = User( user = User(
username = "albert-einstein", username = "albert-einstein",
roles = listOf(UserI.Roles.ROLE_USER) roles = setOf(UserI.Roles.ROLE_USER)
), ),
name = CitizenI.Name("Albert", "Einstein") name = CitizenI.Name("Albert", "Einstein")
) )

View File

@@ -23,14 +23,14 @@ internal class `Citizen Access Control` {
private val tesla = CitizenCart( private val tesla = CitizenCart(
user = User( user = User(
username = "nicolas-tesla", username = "nicolas-tesla",
roles = listOf(UserI.Roles.ROLE_USER) roles = setOf(UserI.Roles.ROLE_USER)
), ),
name = CitizenI.Name("Nicolas", "Tesla") name = CitizenI.Name("Nicolas", "Tesla")
) )
private val einstein = CitizenCart( private val einstein = CitizenCart(
user = User( user = User(
username = "albert-einstein", username = "albert-einstein",
roles = listOf(UserI.Roles.ROLE_USER) roles = setOf(UserI.Roles.ROLE_USER)
), ),
name = CitizenI.Name("Albert", "Einstein") name = CitizenI.Name("Albert", "Einstein")
) )
@@ -38,7 +38,7 @@ internal class `Citizen Access Control` {
private val curie = CitizenCart( private val curie = CitizenCart(
user = User( user = User(
username = "marie-curie", username = "marie-curie",
roles = listOf(UserI.Roles.ROLE_USER) roles = setOf(UserI.Roles.ROLE_USER)
), ),
name = CitizenI.Name("Marie", "Curie"), name = CitizenI.Name("Marie", "Curie"),
deletedAt = DateTime.now() deletedAt = DateTime.now()

View File

@@ -30,7 +30,7 @@ internal class `Comment Access Control` {
private val tesla = Citizen( private val tesla = Citizen(
user = User( user = User(
username = "nicolas-tesla", username = "nicolas-tesla",
roles = listOf(UserI.Roles.ROLE_USER) roles = setOf(UserI.Roles.ROLE_USER)
), ),
birthday = DateTime.now(), birthday = DateTime.now(),
email = "tesla@best.com", email = "tesla@best.com",
@@ -40,7 +40,7 @@ internal class `Comment Access Control` {
id = UUID.fromString("319f1226-8f47-4df3-babd-2c7671ad0fbc"), id = UUID.fromString("319f1226-8f47-4df3-babd-2c7671ad0fbc"),
user = User( user = User(
username = "albert-einstein", username = "albert-einstein",
roles = listOf(UserI.Roles.ROLE_USER) roles = setOf(UserI.Roles.ROLE_USER)
), ),
birthday = DateTime.now(), birthday = DateTime.now(),
email = "einstein@best.com", email = "einstein@best.com",

View File

@@ -36,7 +36,7 @@ internal class `Follow Access Control` {
private val tesla2 = Citizen( private val tesla2 = Citizen(
user = User( user = User(
username = "nicolas-tesla", username = "nicolas-tesla",
roles = listOf(UserI.Roles.ROLE_USER) roles = setOf(UserI.Roles.ROLE_USER)
), ),
birthday = DateTime.now(), birthday = DateTime.now(),
email = "tesla@best.com", email = "tesla@best.com",
@@ -67,7 +67,7 @@ internal class `Follow Access Control` {
id = UUID.fromString("319f1226-8f47-4df3-babd-2c7671ad0fbc"), id = UUID.fromString("319f1226-8f47-4df3-babd-2c7671ad0fbc"),
user = User( user = User(
username = "albert-einstein", username = "albert-einstein",
roles = listOf(UserI.Roles.ROLE_USER) roles = setOf(UserI.Roles.ROLE_USER)
), ),
birthday = DateTime.now(), birthday = DateTime.now(),
email = "einstein@best.com", email = "einstein@best.com",

View File

@@ -30,7 +30,7 @@ internal class `Vote Access Control` {
id = UUID.fromString("a1e35c99-9d33-4fb4-9201-58d7071243bb"), id = UUID.fromString("a1e35c99-9d33-4fb4-9201-58d7071243bb"),
user = User( user = User(
username = "nicolas-tesla", username = "nicolas-tesla",
roles = listOf(UserI.Roles.ROLE_USER) roles = setOf(UserI.Roles.ROLE_USER)
), ),
birthday = DateTime.now(), birthday = DateTime.now(),
email = "tesla@best.com", email = "tesla@best.com",
@@ -51,7 +51,7 @@ internal class `Vote Access Control` {
id = UUID.fromString("319f1226-8f47-4df3-babd-2c7671ad0fbc"), id = UUID.fromString("319f1226-8f47-4df3-babd-2c7671ad0fbc"),
user = User( user = User(
username = "albert-einstein", username = "albert-einstein",
roles = listOf(UserI.Roles.ROLE_USER) roles = setOf(UserI.Roles.ROLE_USER)
), ),
birthday = DateTime.now(), birthday = DateTime.now(),
email = "einstein@best.com", email = "einstein@best.com",

View File

@@ -15,15 +15,15 @@ fi
case $opt in case $opt in
"RESET DB") "RESET DB")
awk 'FNR==1{print "--------------------"}1' \ awk 'FNR==1{print "--------------------"}1' \
../../main/resources/sql/migrations/*.down.sql \ ../../../main/resources/sql/migrations/*.down.sql \
../../main/resources/sql/migrations/*.up.sql > ./allSQL.sql ../../../main/resources/sql/migrations/*.up.sql > ./allSQL.sql
docker exec -i dc-project_postgresql_test psql test test -q -b -v "ON_ERROR_STOP=1" < ./allSQL.sql docker exec -i dc-project_postgresql_test psql test test -q -b -v "ON_ERROR_STOP=1" < ./allSQL.sql
rm ./allSQL.sql rm ./allSQL.sql
;; ;;
"All") "All")
echo "Start ALL tests" echo "Start ALL tests"
awk 'FNR==1{print "--------------------"}1' \ awk 'FNR==1{print "--------------------"}1' \
../../main/resources/sql/functions/*/*.sql \ ../../../main/resources/sql/functions/*/*.sql \
./fixtures/*.sql \ ./fixtures/*.sql \
./*.sql > ./allSQL.sql ./*.sql > ./allSQL.sql
docker exec -i dc-project_postgresql_test psql test test -q -b -v "ON_ERROR_STOP=1" < ./allSQL.sql docker exec -i dc-project_postgresql_test psql test test -q -b -v "ON_ERROR_STOP=1" < ./allSQL.sql
@@ -34,7 +34,7 @@ case $opt in
*) *)
echo "Start tests $opt" echo "Start tests $opt"
awk 'FNR==1{print "--------------------"}1' \ awk 'FNR==1{print "--------------------"}1' \
../../main/resources/sql/functions/*/*.sql \ ../../../main/resources/sql/functions/*/*.sql \
./fixtures/*.sql \ ./fixtures/*.sql \
./"$opt".sql > ./allSQL.sql ./"$opt".sql > ./allSQL.sql
docker exec -i dc-project_postgresql_test psql test test -q -b -v "ON_ERROR_STOP=1" < ./allSQL.sql docker exec -i dc-project_postgresql_test psql test test -q -b -v "ON_ERROR_STOP=1" < ./allSQL.sql