Fix #106

Open
flecomte wants to merge 2 commits from fix into master
32 changed files with 180 additions and 179 deletions
Showing only changes of commit f380231e1e - Show all commits

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