feat: persist user content restriction

This commit is contained in:
Gauthier Roebroeck 2022-03-02 10:44:12 +08:00
parent c7c5592c50
commit f1ab136b5e
4 changed files with 127 additions and 11 deletions

View file

@ -0,0 +1,13 @@
CREATE TABLE USER_SHARING
(
LABEL varchar NOT NULL,
ALLOW boolean NOT NULL,
USER_ID varchar NOT NULL,
PRIMARY KEY (LABEL, ALLOW, USER_ID),
FOREIGN KEY (USER_ID) REFERENCES USER (ID)
);
ALTER TABLE USER
add column AGE_RESTRICTION integer NULL;
ALTER TABLE USER
add column AGE_RESTRICTION_ALLOW_ONLY boolean NULL;

View file

@ -17,7 +17,7 @@ sealed class ContentRestriction {
class ExcludeOver(age: Int) : AgeRestriction(age) class ExcludeOver(age: Int) : AgeRestriction(age)
} }
sealed class LabelsRestriction(val labels: Collection<String>) : ContentRestriction() { sealed class LabelsRestriction(val labels: Set<String>) : ContentRestriction() {
/** /**
* Allow only content that has at least one of the provided sharing [labels] * Allow only content that has at least one of the provided sharing [labels]
* *

View file

@ -1,5 +1,7 @@
package org.gotson.komga.infrastructure.jooq package org.gotson.komga.infrastructure.jooq
import org.gotson.komga.domain.model.ContentRestriction
import org.gotson.komga.domain.model.ContentRestrictions
import org.gotson.komga.domain.model.KomgaUser import org.gotson.komga.domain.model.KomgaUser
import org.gotson.komga.domain.persistence.KomgaUserRepository import org.gotson.komga.domain.persistence.KomgaUserRepository
import org.gotson.komga.jooq.Tables import org.gotson.komga.jooq.Tables
@ -18,6 +20,7 @@ class KomgaUserDao(
private val u = Tables.USER private val u = Tables.USER
private val ul = Tables.USER_LIBRARY_SHARING private val ul = Tables.USER_LIBRARY_SHARING
private val us = Tables.USER_SHARING
override fun count(): Long = dsl.fetchCount(u).toLong() override fun count(): Long = dsl.fetchCount(u).toLong()
@ -41,6 +44,9 @@ class KomgaUserDao(
private fun ResultQuery<Record>.fetchAndMap() = private fun ResultQuery<Record>.fetchAndMap() =
this.fetchGroups({ it.into(u) }, { it.into(ul) }) this.fetchGroups({ it.into(u) }, { it.into(ul) })
.map { (ur, ulr) -> .map { (ur, ulr) ->
val usr = dsl.selectFrom(us)
.where(us.USER_ID.eq(ur.id))
.toList()
KomgaUser( KomgaUser(
email = ur.email, email = ur.email,
password = ur.password, password = ur.password,
@ -49,6 +55,14 @@ class KomgaUserDao(
rolePageStreaming = ur.rolePageStreaming, rolePageStreaming = ur.rolePageStreaming,
sharedLibrariesIds = ulr.mapNotNull { it.libraryId }.toSet(), sharedLibrariesIds = ulr.mapNotNull { it.libraryId }.toSet(),
sharedAllLibraries = ur.sharedAllLibraries, sharedAllLibraries = ur.sharedAllLibraries,
restrictions = ContentRestrictions(
ageRestriction = if (ur.ageRestriction != null && ur.ageRestrictionAllowOnly != null)
if (ur.ageRestrictionAllowOnly) ContentRestriction.AgeRestriction.AllowOnlyUnder(ur.ageRestriction)
else ContentRestriction.AgeRestriction.ExcludeOver(ur.ageRestriction)
else null,
labelsAllow = usr.filter { it.allow }.map { it.label }.toSet(),
labelsExclude = usr.filterNot { it.allow }.map { it.label }.toSet(),
),
id = ur.id, id = ur.id,
createdDate = ur.createdDate.toCurrentTimeZone(), createdDate = ur.createdDate.toCurrentTimeZone(),
lastModifiedDate = ur.lastModifiedDate.toCurrentTimeZone(), lastModifiedDate = ur.lastModifiedDate.toCurrentTimeZone(),
@ -65,14 +79,19 @@ class KomgaUserDao(
.set(u.ROLE_FILE_DOWNLOAD, user.roleFileDownload) .set(u.ROLE_FILE_DOWNLOAD, user.roleFileDownload)
.set(u.ROLE_PAGE_STREAMING, user.rolePageStreaming) .set(u.ROLE_PAGE_STREAMING, user.rolePageStreaming)
.set(u.SHARED_ALL_LIBRARIES, user.sharedAllLibraries) .set(u.SHARED_ALL_LIBRARIES, user.sharedAllLibraries)
.set(u.AGE_RESTRICTION, user.restrictions.ageRestriction?.age)
.set(
u.AGE_RESTRICTION_ALLOW_ONLY,
when (user.restrictions.ageRestriction) {
is ContentRestriction.AgeRestriction.AllowOnlyUnder -> true
is ContentRestriction.AgeRestriction.ExcludeOver -> false
null -> null
},
)
.execute() .execute()
user.sharedLibrariesIds.forEach { insertSharedLibraries(user)
dsl.insertInto(ul) insertSharingRestrictions(user)
.columns(ul.USER_ID, ul.LIBRARY_ID)
.values(user.id, it)
.execute()
}
} }
@Transactional @Transactional
@ -84,6 +103,15 @@ class KomgaUserDao(
.set(u.ROLE_FILE_DOWNLOAD, user.roleFileDownload) .set(u.ROLE_FILE_DOWNLOAD, user.roleFileDownload)
.set(u.ROLE_PAGE_STREAMING, user.rolePageStreaming) .set(u.ROLE_PAGE_STREAMING, user.rolePageStreaming)
.set(u.SHARED_ALL_LIBRARIES, user.sharedAllLibraries) .set(u.SHARED_ALL_LIBRARIES, user.sharedAllLibraries)
.set(u.AGE_RESTRICTION, user.restrictions.ageRestriction?.age)
.set(
u.AGE_RESTRICTION_ALLOW_ONLY,
when (user.restrictions.ageRestriction) {
is ContentRestriction.AgeRestriction.AllowOnlyUnder -> true
is ContentRestriction.AgeRestriction.ExcludeOver -> false
null -> null
},
)
.set(u.LAST_MODIFIED_DATE, LocalDateTime.now(ZoneId.of("Z"))) .set(u.LAST_MODIFIED_DATE, LocalDateTime.now(ZoneId.of("Z")))
.where(u.ID.eq(user.id)) .where(u.ID.eq(user.id))
.execute() .execute()
@ -92,6 +120,15 @@ class KomgaUserDao(
.where(ul.USER_ID.eq(user.id)) .where(ul.USER_ID.eq(user.id))
.execute() .execute()
dsl.deleteFrom(us)
.where(us.USER_ID.eq(user.id))
.execute()
insertSharedLibraries(user)
insertSharingRestrictions(user)
}
private fun insertSharedLibraries(user: KomgaUser) {
user.sharedLibrariesIds.forEach { user.sharedLibrariesIds.forEach {
dsl.insertInto(ul) dsl.insertInto(ul)
.columns(ul.USER_ID, ul.LIBRARY_ID) .columns(ul.USER_ID, ul.LIBRARY_ID)
@ -100,14 +137,32 @@ class KomgaUserDao(
} }
} }
private fun insertSharingRestrictions(user: KomgaUser) {
user.restrictions.labelsAllowRestriction?.labels?.forEach { label ->
dsl.insertInto(us)
.columns(us.USER_ID, us.ALLOW, us.LABEL)
.values(user.id, true, label)
.execute()
}
user.restrictions.labelsExcludeRestriction?.labels?.forEach { label ->
dsl.insertInto(us)
.columns(us.USER_ID, us.ALLOW, us.LABEL)
.values(user.id, false, label)
.execute()
}
}
@Transactional @Transactional
override fun delete(userId: String) { override fun delete(userId: String) {
dsl.deleteFrom(us).where(us.USER_ID.equal(userId)).execute()
dsl.deleteFrom(ul).where(ul.USER_ID.equal(userId)).execute() dsl.deleteFrom(ul).where(ul.USER_ID.equal(userId)).execute()
dsl.deleteFrom(u).where(u.ID.equal(userId)).execute() dsl.deleteFrom(u).where(u.ID.equal(userId)).execute()
} }
@Transactional @Transactional
override fun deleteAll() { override fun deleteAll() {
dsl.deleteFrom(us).execute()
dsl.deleteFrom(ul).execute() dsl.deleteFrom(ul).execute()
dsl.deleteFrom(u).execute() dsl.deleteFrom(u).execute()
} }

View file

@ -1,6 +1,8 @@
package org.gotson.komga.infrastructure.jooq package org.gotson.komga.infrastructure.jooq
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.gotson.komga.domain.model.ContentRestriction
import org.gotson.komga.domain.model.ContentRestrictions
import org.gotson.komga.domain.model.KomgaUser import org.gotson.komga.domain.model.KomgaUser
import org.gotson.komga.domain.model.makeLibrary import org.gotson.komga.domain.model.makeLibrary
import org.gotson.komga.domain.persistence.LibraryRepository import org.gotson.komga.domain.persistence.LibraryRepository
@ -59,9 +61,12 @@ class KomgaUserDaoTest(
assertThat(lastModifiedDate).isCloseTo(now, offset) assertThat(lastModifiedDate).isCloseTo(now, offset)
assertThat(email).isEqualTo("user@example.org") assertThat(email).isEqualTo("user@example.org")
assertThat(password).isEqualTo("password") assertThat(password).isEqualTo("password")
assertThat(roleAdmin).isFalse() assertThat(roleAdmin).isFalse
assertThat(sharedLibrariesIds).containsExactly(library.id) assertThat(sharedLibrariesIds).containsExactly(library.id)
assertThat(sharedAllLibraries).isFalse() assertThat(sharedAllLibraries).isFalse
assertThat(restrictions.ageRestriction).isNull()
assertThat(restrictions.labelsAllowRestriction).isNull()
assertThat(restrictions.labelsExcludeRestriction).isNull()
} }
} }
@ -73,10 +78,29 @@ class KomgaUserDaoTest(
roleAdmin = false, roleAdmin = false,
sharedLibrariesIds = setOf(library.id), sharedLibrariesIds = setOf(library.id),
sharedAllLibraries = false, sharedAllLibraries = false,
restrictions = ContentRestrictions(
ageRestriction = ContentRestriction.AgeRestriction.AllowOnlyUnder(10),
labelsAllow = setOf("allow"),
labelsExclude = setOf("exclude"),
)
) )
komgaUserDao.insert(user) komgaUserDao.insert(user)
val created = komgaUserDao.findByIdOrNull(user.id)!! val created = komgaUserDao.findByIdOrNull(user.id)!!
with(created) {
assertThat(restrictions.ageRestriction)
.isNotNull
.isExactlyInstanceOf(ContentRestriction.AgeRestriction.AllowOnlyUnder::class.java)
assertThat(restrictions.ageRestriction!!.age).isEqualTo(10)
assertThat(restrictions.labelsAllowRestriction)
.isNotNull
.isExactlyInstanceOf(ContentRestriction.LabelsRestriction.AllowOnly::class.java)
assertThat(restrictions.labelsAllowRestriction!!.labels).containsExactly("allow")
assertThat(restrictions.labelsExcludeRestriction)
.isNotNull
.isExactlyInstanceOf(ContentRestriction.LabelsRestriction.Exclude::class.java)
assertThat(restrictions.labelsExcludeRestriction!!.labels).containsExactly("exclude")
}
val modified = created.copy( val modified = created.copy(
email = "user2@example.org", email = "user2@example.org",
@ -84,6 +108,11 @@ class KomgaUserDaoTest(
roleAdmin = true, roleAdmin = true,
sharedLibrariesIds = emptySet(), sharedLibrariesIds = emptySet(),
sharedAllLibraries = true, sharedAllLibraries = true,
restrictions = ContentRestrictions(
ageRestriction = ContentRestriction.AgeRestriction.ExcludeOver(16),
labelsAllow = setOf("allow2"),
labelsExclude = setOf("exclude2"),
),
) )
val modifiedDate = LocalDateTime.now() val modifiedDate = LocalDateTime.now()
komgaUserDao.update(modified) komgaUserDao.update(modified)
@ -97,9 +126,28 @@ class KomgaUserDaoTest(
.isNotEqualTo(modified.createdDate) .isNotEqualTo(modified.createdDate)
assertThat(email).isEqualTo("user2@example.org") assertThat(email).isEqualTo("user2@example.org")
assertThat(password).isEqualTo("password2") assertThat(password).isEqualTo("password2")
assertThat(roleAdmin).isTrue() assertThat(roleAdmin).isTrue
assertThat(sharedLibrariesIds).isEmpty() assertThat(sharedLibrariesIds).isEmpty()
assertThat(sharedAllLibraries).isTrue() assertThat(sharedAllLibraries).isTrue
assertThat(restrictions.ageRestriction)
.isNotNull
.isExactlyInstanceOf(ContentRestriction.AgeRestriction.ExcludeOver::class.java)
assertThat(restrictions.ageRestriction!!.age).isEqualTo(16)
assertThat(restrictions.labelsAllowRestriction)
.isNotNull
.isExactlyInstanceOf(ContentRestriction.LabelsRestriction.AllowOnly::class.java)
assertThat(restrictions.labelsAllowRestriction!!.labels).containsExactly("allow2")
assertThat(restrictions.labelsExcludeRestriction)
.isNotNull
.isExactlyInstanceOf(ContentRestriction.LabelsRestriction.Exclude::class.java)
assertThat(restrictions.labelsExcludeRestriction!!.labels).containsExactly("exclude2")
}
komgaUserDao.update(modifiedSaved.copy(restrictions = ContentRestrictions()))
with(komgaUserDao.findByIdOrNull(modified.id)!!) {
assertThat(restrictions.ageRestriction).isNull()
assertThat(restrictions.labelsAllowRestriction).isNull()
assertThat(restrictions.labelsExcludeRestriction).isNull()
} }
} }