diff --git a/komga/src/flyway/resources/db/migration/sqlite/V20250108115503__user_roles.sql b/komga/src/flyway/resources/db/migration/sqlite/V20250108115503__user_roles.sql new file mode 100644 index 000000000..88e7d15bf --- /dev/null +++ b/komga/src/flyway/resources/db/migration/sqlite/V20250108115503__user_roles.sql @@ -0,0 +1,68 @@ +CREATE TABLE USER_ROLE +( + USER_ID varchar NOT NULL, + ROLE varchar NOT NULL, + PRIMARY KEY (USER_ID, ROLE), + FOREIGN KEY (USER_ID) REFERENCES USER (ID) +); + +insert into USER_ROLE +select id, "ADMIN" +from user +where ROLE_ADMIN = 1; + +insert into USER_ROLE +select id, "KOREADER_SYNC" +from user +where ROLE_ADMIN = 1; + +insert into USER_ROLE +select id, "FILE_DOWNLOAD" +from user +where ROLE_FILE_DOWNLOAD = 1; + +insert into USER_ROLE +select id, "PAGE_STREAMING" +from user +where ROLE_PAGE_STREAMING = 1; + +insert into USER_ROLE +select id, "KOBO_SYNC" +from user +where ROLE_KOBO_SYNC = 1; + +-- Remove columns ROLE_ADMIN, ROLE_FILE_DOWNLOAD, ROLE_PAGE_STREAMING, ROLE_KOBO_SYNC from USER +PRAGMA foreign_keys= OFF; + +create table USER_dg_tmp +( + ID varchar not null + primary key, + CREATED_DATE datetime default CURRENT_TIMESTAMP not null, + LAST_MODIFIED_DATE datetime default CURRENT_TIMESTAMP not null, + EMAIL varchar not null + unique, + PASSWORD varchar not null, + SHARED_ALL_LIBRARIES boolean default 1 not null, + AGE_RESTRICTION integer, + AGE_RESTRICTION_ALLOW_ONLY boolean +); + +insert into USER_dg_tmp(ID, CREATED_DATE, LAST_MODIFIED_DATE, EMAIL, PASSWORD, SHARED_ALL_LIBRARIES, AGE_RESTRICTION, + AGE_RESTRICTION_ALLOW_ONLY) +select ID, + CREATED_DATE, + LAST_MODIFIED_DATE, + EMAIL, + PASSWORD, + SHARED_ALL_LIBRARIES, + AGE_RESTRICTION, + AGE_RESTRICTION_ALLOW_ONLY +from USER; + +drop table USER; + +alter table USER_dg_tmp + rename to USER; + +PRAGMA foreign_keys= ON; diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/model/KomgaUser.kt b/komga/src/main/kotlin/org/gotson/komga/domain/model/KomgaUser.kt index 0bd780d78..6d5ef5293 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/model/KomgaUser.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/model/KomgaUser.kt @@ -6,22 +6,13 @@ import jakarta.validation.constraints.NotBlank import org.gotson.komga.language.lowerNotBlank import java.time.LocalDateTime -const val ROLE_USER = "USER" -const val ROLE_ADMIN = "ADMIN" -const val ROLE_FILE_DOWNLOAD = "FILE_DOWNLOAD" -const val ROLE_PAGE_STREAMING = "PAGE_STREAMING" -const val ROLE_KOBO_SYNC = "KOBO_SYNC" - data class KomgaUser( @Email(regexp = ".+@.+\\..+") @NotBlank val email: String, @NotBlank val password: String, - val roleAdmin: Boolean, - val roleFileDownload: Boolean = true, - val rolePageStreaming: Boolean = true, - val roleKoboSync: Boolean = false, + val roles: Set = setOf(UserRoles.FILE_DOWNLOAD, UserRoles.PAGE_STREAMING), val sharedLibrariesIds: Set = emptySet(), val sharedAllLibraries: Boolean = true, val restrictions: ContentRestrictions = ContentRestrictions(), @@ -30,14 +21,8 @@ data class KomgaUser( override val lastModifiedDate: LocalDateTime = createdDate, ) : Auditable { @delegate:Transient - val roles: Set by lazy { - buildSet { - add(ROLE_USER) - if (roleAdmin) add(ROLE_ADMIN) - if (roleFileDownload) add(ROLE_FILE_DOWNLOAD) - if (rolePageStreaming) add(ROLE_PAGE_STREAMING) - if (roleKoboSync) add(ROLE_KOBO_SYNC) - } + val isAdmin: Boolean by lazy { + roles.contains(UserRoles.ADMIN) } /** @@ -60,7 +45,7 @@ data class KomgaUser( else -> null } - fun canAccessAllLibraries(): Boolean = sharedAllLibraries || roleAdmin + fun canAccessAllLibraries(): Boolean = sharedAllLibraries || isAdmin fun canAccessLibrary(libraryId: String): Boolean = canAccessAllLibraries() || sharedLibrariesIds.any { it == libraryId } @@ -107,5 +92,5 @@ data class KomgaUser( return !ageDenied && !labelDenied } - override fun toString(): String = "KomgaUser(email='$email', roleAdmin=$roleAdmin, roleFileDownload=$roleFileDownload, rolePageStreaming=$rolePageStreaming, roleKoboSync=$roleKoboSync, sharedLibrariesIds=$sharedLibrariesIds, sharedAllLibraries=$sharedAllLibraries, restrictions=$restrictions, id='$id', createdDate=$createdDate, lastModifiedDate=$lastModifiedDate)" + override fun toString(): String = "KomgaUser(createdDate=$createdDate, email='$email', roles=$roles, sharedLibrariesIds=$sharedLibrariesIds, sharedAllLibraries=$sharedAllLibraries, restrictions=$restrictions, id='$id', lastModifiedDate=$lastModifiedDate)" } diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/model/UserRoles.kt b/komga/src/main/kotlin/org/gotson/komga/domain/model/UserRoles.kt new file mode 100644 index 000000000..f6f4b060f --- /dev/null +++ b/komga/src/main/kotlin/org/gotson/komga/domain/model/UserRoles.kt @@ -0,0 +1,26 @@ +package org.gotson.komga.domain.model + +enum class UserRoles { + ADMIN, + FILE_DOWNLOAD, + PAGE_STREAMING, + KOBO_SYNC, + ; + + companion object { + /** + * Returns a Set composed of the enum constant of this type with the specified name. + * The string must match exactly an identifier used to declare an enum constant in this type. + * (Extraneous whitespace characters are not permitted.) + */ + fun valuesOf(roles: Iterable): Set = + roles + .mapNotNull { + try { + valueOf(it) + } catch (_: Exception) { + null + } + }.toSet() + } +} diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/KomgaUserDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/KomgaUserDao.kt index 8a33936bb..da207114f 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/KomgaUserDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/KomgaUserDao.kt @@ -5,6 +5,7 @@ import org.gotson.komga.domain.model.AllowExclude import org.gotson.komga.domain.model.ApiKey import org.gotson.komga.domain.model.ContentRestrictions import org.gotson.komga.domain.model.KomgaUser +import org.gotson.komga.domain.model.UserRoles import org.gotson.komga.domain.persistence.KomgaUserRepository import org.gotson.komga.jooq.main.Tables import org.gotson.komga.jooq.main.tables.records.AnnouncementsReadRecord @@ -23,6 +24,7 @@ class KomgaUserDao( private val dsl: DSLContext, ) : KomgaUserRepository { private val u = Tables.USER + private val ur = Tables.USER_ROLE private val ul = Tables.USER_LIBRARY_SHARING private val us = Tables.USER_SHARING private val ar = Tables.ANNOUNCEMENTS_READ @@ -60,34 +62,37 @@ class KomgaUserDao( private fun ResultQuery.fetchAndMap() = this .fetchGroups({ it.into(u) }, { it.into(ul) }) - .map { (ur, ulr) -> + .map { (userRecord, ulr) -> val usr = dsl .selectFrom(us) - .where(us.USER_ID.eq(ur.id)) + .where(us.USER_ID.eq(userRecord.id)) .toList() + val roles = + dsl + .select(ur.ROLE) + .from(ur) + .where(ur.USER_ID.eq(userRecord.id)) + .fetch(ur.ROLE) KomgaUser( - email = ur.email, - password = ur.password, - roleAdmin = ur.roleAdmin, - roleFileDownload = ur.roleFileDownload, - rolePageStreaming = ur.rolePageStreaming, - roleKoboSync = ur.roleKoboSync, + email = userRecord.email, + password = userRecord.password, + roles = UserRoles.valuesOf(roles), sharedLibrariesIds = ulr.mapNotNull { it.libraryId }.toSet(), - sharedAllLibraries = ur.sharedAllLibraries, + sharedAllLibraries = userRecord.sharedAllLibraries, restrictions = ContentRestrictions( ageRestriction = - if (ur.ageRestriction != null && ur.ageRestrictionAllowOnly != null) - AgeRestriction(ur.ageRestriction, if (ur.ageRestrictionAllowOnly) AllowExclude.ALLOW_ONLY else AllowExclude.EXCLUDE) + if (userRecord.ageRestriction != null && userRecord.ageRestrictionAllowOnly != null) + AgeRestriction(userRecord.ageRestriction, if (userRecord.ageRestrictionAllowOnly) AllowExclude.ALLOW_ONLY else AllowExclude.EXCLUDE) else null, labelsAllow = usr.filter { it.allow }.map { it.label }.toSet(), labelsExclude = usr.filterNot { it.allow }.map { it.label }.toSet(), ), - id = ur.id, - createdDate = ur.createdDate.toCurrentTimeZone(), - lastModifiedDate = ur.lastModifiedDate.toCurrentTimeZone(), + id = userRecord.id, + createdDate = userRecord.createdDate.toCurrentTimeZone(), + lastModifiedDate = userRecord.lastModifiedDate.toCurrentTimeZone(), ) } @@ -98,10 +103,6 @@ class KomgaUserDao( .set(u.ID, user.id) .set(u.EMAIL, user.email) .set(u.PASSWORD, user.password) - .set(u.ROLE_ADMIN, user.roleAdmin) - .set(u.ROLE_FILE_DOWNLOAD, user.roleFileDownload) - .set(u.ROLE_PAGE_STREAMING, user.rolePageStreaming) - .set(u.ROLE_KOBO_SYNC, user.roleKoboSync) .set(u.SHARED_ALL_LIBRARIES, user.sharedAllLibraries) .set(u.AGE_RESTRICTION, user.restrictions.ageRestriction?.age) .set( @@ -113,6 +114,7 @@ class KomgaUserDao( }, ).execute() + insertRoles(user) insertSharedLibraries(user) insertSharingRestrictions(user) } @@ -133,10 +135,6 @@ class KomgaUserDao( .update(u) .set(u.EMAIL, user.email) .set(u.PASSWORD, user.password) - .set(u.ROLE_ADMIN, user.roleAdmin) - .set(u.ROLE_FILE_DOWNLOAD, user.roleFileDownload) - .set(u.ROLE_PAGE_STREAMING, user.rolePageStreaming) - .set(u.ROLE_KOBO_SYNC, user.roleKoboSync) .set(u.SHARED_ALL_LIBRARIES, user.sharedAllLibraries) .set(u.AGE_RESTRICTION, user.restrictions.ageRestriction?.age) .set( @@ -150,6 +148,11 @@ class KomgaUserDao( .where(u.ID.eq(user.id)) .execute() + dsl + .deleteFrom(ur) + .where(ur.USER_ID.eq(user.id)) + .execute() + dsl .deleteFrom(ul) .where(ul.USER_ID.eq(user.id)) @@ -160,6 +163,7 @@ class KomgaUserDao( .where(us.USER_ID.eq(user.id)) .execute() + insertRoles(user) insertSharedLibraries(user) insertSharingRestrictions(user) } @@ -171,6 +175,16 @@ class KomgaUserDao( dsl.batchStore(announcementIds.map { AnnouncementsReadRecord(user.id, it) }).execute() } + private fun insertRoles(user: KomgaUser) { + user.roles.forEach { + dsl + .insertInto(ur) + .columns(ur.USER_ID, ur.ROLE) + .values(user.id, it.name) + .execute() + } + } + private fun insertSharedLibraries(user: KomgaUser) { user.sharedLibrariesIds.forEach { dsl @@ -205,6 +219,7 @@ class KomgaUserDao( dsl.deleteFrom(ar).where(ar.USER_ID.equal(userId)).execute() dsl.deleteFrom(us).where(us.USER_ID.equal(userId)).execute() dsl.deleteFrom(ul).where(ul.USER_ID.equal(userId)).execute() + dsl.deleteFrom(ur).where(ur.USER_ID.equal(userId)).execute() dsl.deleteFrom(u).where(u.ID.equal(userId)).execute() } @@ -214,6 +229,7 @@ class KomgaUserDao( dsl.deleteFrom(ar).execute() dsl.deleteFrom(us).execute() dsl.deleteFrom(ul).execute() + dsl.deleteFrom(ur).execute() dsl.deleteFrom(u).execute() } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/SecurityConfiguration.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/SecurityConfiguration.kt index 105fe8f76..bfbc811f4 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/SecurityConfiguration.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/SecurityConfiguration.kt @@ -2,12 +2,11 @@ package org.gotson.komga.infrastructure.security import io.github.oshai.kotlinlogging.KotlinLogging import jakarta.servlet.Filter -import org.gotson.komga.domain.model.ROLE_ADMIN -import org.gotson.komga.domain.model.ROLE_KOBO_SYNC -import org.gotson.komga.domain.model.ROLE_USER +import org.gotson.komga.domain.model.UserRoles import org.gotson.komga.infrastructure.configuration.KomgaSettingsProvider import org.gotson.komga.infrastructure.security.apikey.ApiKeyAuthenticationFilter import org.gotson.komga.infrastructure.security.apikey.ApiKeyAuthenticationProvider +import org.gotson.komga.infrastructure.security.apikey.HeaderApiKeyAuthenticationConverter import org.gotson.komga.infrastructure.security.apikey.UriRegexApiKeyAuthenticationConverter import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest import org.springframework.boot.actuate.health.HealthEndpoint @@ -81,7 +80,7 @@ class SecurityConfiguration( // this will only show limited details as `management.endpoint.health.show-details` is set to `when-authorized` it.requestMatchers(EndpointRequest.to(HealthEndpoint::class.java)).permitAll() // restrict all other actuator endpoints to ADMIN only - it.requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole(ROLE_ADMIN) + it.requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole(UserRoles.ADMIN.name) it .requestMatchers( @@ -101,7 +100,7 @@ class SecurityConfiguration( "/api/**", "/opds/**", "/sse/**", - ).hasRole(ROLE_USER) + ).authenticated() }.headers { headersConfigurer -> headersConfigurer.cacheControl { it.disable() } // headers are set in WebMvcConfiguration headersConfigurer.frameOptions { it.sameOrigin() } // for epubreader iframes @@ -174,7 +173,7 @@ class SecurityConfiguration( securityMatcher("/kobo/**") authorizeHttpRequests { - authorize(anyRequest, hasRole(ROLE_KOBO_SYNC)) + authorize(anyRequest, hasRole(UserRoles.KOBO_SYNC.name)) } headers { diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/oauth2/KomgaOAuth2UserServiceConfiguration.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/oauth2/KomgaOAuth2UserServiceConfiguration.kt index c07a69a69..ca3b20394 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/oauth2/KomgaOAuth2UserServiceConfiguration.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/oauth2/KomgaOAuth2UserServiceConfiguration.kt @@ -73,7 +73,7 @@ class KomgaOAuth2UserServiceConfiguration( private fun tryCreateNewUser(email: String) = if (komgaProperties.oauth2AccountCreation) { logger.info { "Creating new user from OAuth2 login: $email" } - userLifecycle.createUser(KomgaUser(email, RandomStringUtils.secure().nextAlphanumeric(12), roleAdmin = false)) + userLifecycle.createUser(KomgaUser(email, RandomStringUtils.secure().nextAlphanumeric(12))) } else { throw OAuth2AuthenticationException("ERR_1025") } diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/CommonBookController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/CommonBookController.kt index 185ba0262..13b6e609b 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/CommonBookController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/CommonBookController.kt @@ -14,8 +14,6 @@ import org.gotson.komga.domain.model.MediaNotReadyException import org.gotson.komga.domain.model.MediaProfile import org.gotson.komga.domain.model.MediaUnsupportedException import org.gotson.komga.domain.model.R2Progression -import org.gotson.komga.domain.model.ROLE_FILE_DOWNLOAD -import org.gotson.komga.domain.model.ROLE_PAGE_STREAMING import org.gotson.komga.domain.model.toR2Progression import org.gotson.komga.domain.persistence.BookRepository import org.gotson.komga.domain.persistence.MediaRepository @@ -199,7 +197,7 @@ class CommonBookController( ], produces = [MediaType.ALL_VALUE], ) - @PreAuthorize("hasRole('$ROLE_PAGE_STREAMING')") + @PreAuthorize("hasRole('PAGE_STREAMING')") fun getBookPageRaw( @AuthenticationPrincipal principal: KomgaPrincipal, request: ServletWebRequest, @@ -319,7 +317,7 @@ class CommonBookController( ], produces = [MediaType.APPLICATION_OCTET_STREAM_VALUE], ) - @PreAuthorize("hasRole('$ROLE_FILE_DOWNLOAD')") + @PreAuthorize("hasRole('FILE_DOWNLOAD')") fun getBookFile( @AuthenticationPrincipal principal: KomgaPrincipal, @PathVariable bookId: String, diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/KoboController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/KoboController.kt index 943a0f74b..c382e0769 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/KoboController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/KoboController.kt @@ -16,7 +16,6 @@ import org.gotson.komga.domain.model.MediaType.EPUB import org.gotson.komga.domain.model.R2Device import org.gotson.komga.domain.model.R2Locator import org.gotson.komga.domain.model.R2Progression -import org.gotson.komga.domain.model.ROLE_FILE_DOWNLOAD import org.gotson.komga.domain.model.SyncPoint import org.gotson.komga.domain.persistence.BookRepository import org.gotson.komga.domain.persistence.MediaRepository @@ -633,7 +632,7 @@ class KoboController( value = ["v1/books/{bookId}/file/epub"], produces = [MediaType.APPLICATION_OCTET_STREAM_VALUE], ) - @PreAuthorize("hasRole('$ROLE_FILE_DOWNLOAD')") + @PreAuthorize("hasRole('FILE_DOWNLOAD')") fun getBookFile( @AuthenticationPrincipal principal: KomgaPrincipal, @PathVariable bookId: String, diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/opds/v1/OpdsController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/opds/v1/OpdsController.kt index 26772e905..b27a024a2 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/opds/v1/OpdsController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/opds/v1/OpdsController.kt @@ -10,7 +10,6 @@ import org.gotson.komga.domain.model.BookSearch import org.gotson.komga.domain.model.Library import org.gotson.komga.domain.model.Media import org.gotson.komga.domain.model.MediaProfile -import org.gotson.komga.domain.model.ROLE_PAGE_STREAMING import org.gotson.komga.domain.model.ReadList import org.gotson.komga.domain.model.ReadStatus import org.gotson.komga.domain.model.SearchCondition @@ -729,7 +728,7 @@ class OpdsController( @ApiResponse(content = [Content(mediaType = "image/*", schema = Schema(type = "string", format = "binary"))]) @GetMapping("books/{bookId}/pages/{pageNumber}", produces = ["image/png", "image/gif", "image/jpeg"]) - @PreAuthorize("hasRole('$ROLE_PAGE_STREAMING')") + @PreAuthorize("hasRole('PAGE_STREAMING')") fun getBookPageOpds( @AuthenticationPrincipal principal: KomgaPrincipal, request: ServletWebRequest, diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/opds/v2/Opds2Controller.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/opds/v2/Opds2Controller.kt index 5770133f1..144c728b5 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/opds/v2/Opds2Controller.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/opds/v2/Opds2Controller.kt @@ -8,7 +8,6 @@ import org.gotson.komga.domain.model.BookSearch import org.gotson.komga.domain.model.KomgaUser import org.gotson.komga.domain.model.Library import org.gotson.komga.domain.model.Media -import org.gotson.komga.domain.model.ROLE_PAGE_STREAMING import org.gotson.komga.domain.model.ReadList import org.gotson.komga.domain.model.ReadStatus import org.gotson.komga.domain.model.SearchCondition @@ -865,7 +864,7 @@ class Opds2Controller( value = ["books/{bookId}/pages/{pageNumber}"], produces = [MediaType.ALL_VALUE], ) - @PreAuthorize("hasRole('$ROLE_PAGE_STREAMING')") + @PreAuthorize("hasRole('PAGE_STREAMING')") fun getBookPage( @AuthenticationPrincipal principal: KomgaPrincipal, request: ServletWebRequest, diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/AnnouncementController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/AnnouncementController.kt index 122eff468..6cb2df549 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/AnnouncementController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/AnnouncementController.kt @@ -1,7 +1,6 @@ package org.gotson.komga.interfaces.api.rest import com.github.benmanes.caffeine.cache.Caffeine -import org.gotson.komga.domain.model.ROLE_ADMIN import org.gotson.komga.domain.persistence.KomgaUserRepository import org.gotson.komga.infrastructure.security.KomgaPrincipal import org.gotson.komga.interfaces.api.rest.dto.JsonFeedDto @@ -36,7 +35,7 @@ class AnnouncementController( .build() @GetMapping - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") fun getAnnouncements( @AuthenticationPrincipal principal: KomgaPrincipal, ): JsonFeedDto = @@ -48,7 +47,7 @@ class AnnouncementController( } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @PutMapping @ResponseStatus(HttpStatus.NO_CONTENT) fun markAnnouncementsRead( diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/BookController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/BookController.kt index 691f3b666..a182b1ae4 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/BookController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/BookController.kt @@ -21,8 +21,6 @@ import org.gotson.komga.domain.model.Media import org.gotson.komga.domain.model.MediaExtensionEpub import org.gotson.komga.domain.model.MediaNotReadyException import org.gotson.komga.domain.model.MediaProfile -import org.gotson.komga.domain.model.ROLE_ADMIN -import org.gotson.komga.domain.model.ROLE_PAGE_STREAMING import org.gotson.komga.domain.model.ReadStatus import org.gotson.komga.domain.model.SearchCondition import org.gotson.komga.domain.model.SearchContext @@ -32,7 +30,6 @@ import org.gotson.komga.domain.persistence.BookMetadataRepository import org.gotson.komga.domain.persistence.BookRepository import org.gotson.komga.domain.persistence.MediaRepository import org.gotson.komga.domain.persistence.ReadListRepository -import org.gotson.komga.domain.persistence.ReadProgressRepository import org.gotson.komga.domain.persistence.ThumbnailBookRepository import org.gotson.komga.domain.service.BookAnalyzer import org.gotson.komga.domain.service.BookLifecycle @@ -106,7 +103,6 @@ class BookController( private val bookAnalyzer: BookAnalyzer, private val bookLifecycle: BookLifecycle, private val bookRepository: BookRepository, - private val readProgressRepository: ReadProgressRepository, private val bookMetadataRepository: BookMetadataRepository, private val mediaRepository: MediaRepository, private val bookDtoRepository: BookDtoRepository, @@ -167,7 +163,7 @@ class BookController( return bookDtoRepository .findAll(bookSearch, SearchContext(principal.user), pageRequest) - .map { it.restrictUrl(!principal.user.roleAdmin) } + .map { it.restrictUrl(!principal.user.isAdmin) } } @Operation(description = "Return newly added or updated books.") @@ -194,7 +190,7 @@ class BookController( .findAll( SearchContext(principal.user), pageRequest, - ).map { it.restrictUrl(!principal.user.roleAdmin) } + ).map { it.restrictUrl(!principal.user.isAdmin) } } @Operation(description = "Return first unread book of series with at least one book read and no books in progress.") @@ -211,11 +207,11 @@ class BookController( principal.user.getAuthorizedLibraryIds(libraryIds), page, principal.user.restrictions, - ).map { it.restrictUrl(!principal.user.roleAdmin) } + ).map { it.restrictUrl(!principal.user.isAdmin) } @PageableAsQueryParam @GetMapping("api/v1/books/duplicates") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") fun getDuplicateBooks( @AuthenticationPrincipal principal: KomgaPrincipal, @RequestParam(name = "unpaged", required = false) unpaged: Boolean = false, @@ -248,7 +244,7 @@ class BookController( bookDtoRepository.findByIdOrNull(bookId, principal.user.id)?.let { contentRestrictionChecker.checkContentRestriction(principal.user, it) - it.restrictUrl(!principal.user.roleAdmin) + it.restrictUrl(!principal.user.isAdmin) } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) @GetMapping("api/v1/books/{bookId}/previous") @@ -260,7 +256,7 @@ class BookController( return bookDtoRepository .findPreviousInSeriesOrNull(bookId, principal.user.id) - ?.restrictUrl(!principal.user.roleAdmin) + ?.restrictUrl(!principal.user.isAdmin) ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) } @@ -273,7 +269,7 @@ class BookController( return bookDtoRepository .findNextInSeriesOrNull(bookId, principal.user.id) - ?.restrictUrl(!principal.user.roleAdmin) + ?.restrictUrl(!principal.user.isAdmin) ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) } @@ -329,7 +325,7 @@ class BookController( } @PostMapping(value = ["api/v1/books/{bookId}/thumbnails"], consumes = [MediaType.MULTIPART_FORM_DATA_VALUE]) - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") fun addUserUploadedBookThumbnail( @AuthenticationPrincipal principal: KomgaPrincipal, @PathVariable(name = "bookId") bookId: String, @@ -358,7 +354,7 @@ class BookController( } @PutMapping("api/v1/books/{bookId}/thumbnails/{thumbnailId}/selected") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.ACCEPTED) fun markSelectedBookThumbnail( @AuthenticationPrincipal principal: KomgaPrincipal, @@ -372,7 +368,7 @@ class BookController( } @DeleteMapping("api/v1/books/{bookId}/thumbnails/{thumbnailId}") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.ACCEPTED) fun deleteUserUploadedBookThumbnail( @AuthenticationPrincipal principal: KomgaPrincipal, @@ -427,7 +423,7 @@ class BookController( value = ["api/v1/books/{bookId}/pages/{pageNumber}"], produces = [MediaType.ALL_VALUE], ) - @PreAuthorize("hasRole('$ROLE_PAGE_STREAMING')") + @PreAuthorize("hasRole('PAGE_STREAMING')") fun getBookPage( @AuthenticationPrincipal principal: KomgaPrincipal, request: ServletWebRequest, @@ -566,7 +562,7 @@ class BookController( ): WPPublicationDto = commonBookController.getWebPubManifestDivinaInternal(principal, bookId, webPubGenerator) @PostMapping("api/v1/books/{bookId}/analyze") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.ACCEPTED) fun analyze( @PathVariable bookId: String, @@ -577,7 +573,7 @@ class BookController( } @PostMapping("api/v1/books/{bookId}/metadata/refresh") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.ACCEPTED) fun refreshMetadata( @PathVariable bookId: String, @@ -589,7 +585,7 @@ class BookController( } @PatchMapping("api/v1/books/{bookId}/metadata") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.NO_CONTENT) fun updateMetadata( @PathVariable bookId: String, @@ -608,7 +604,7 @@ class BookController( } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) @PatchMapping("api/v1/books/metadata") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.NO_CONTENT) fun updateBatchMetadata( @Parameter(description = "A map of book IDs which values are the metadata fields to update. Set a field to null to unset the metadata. You can omit fields you don't want to update.") @@ -670,7 +666,7 @@ class BookController( } @PostMapping("api/v1/books/import") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.ACCEPTED) fun importBooks( @RequestBody bookImportBatch: BookImportBatchDto, @@ -692,7 +688,7 @@ class BookController( } @DeleteMapping("api/v1/books/{bookId}/file") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.ACCEPTED) fun deleteBook( @PathVariable bookId: String, @@ -704,7 +700,7 @@ class BookController( } @PutMapping("api/v1/books/thumbnails") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.ACCEPTED) fun regenerateThumbnails( @RequestParam(name = "for_bigger_result_only", required = false) forBiggerResultOnly: Boolean = false, diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ClaimController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ClaimController.kt index 1f7ce0ad7..c6c391622 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ClaimController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ClaimController.kt @@ -3,6 +3,7 @@ package org.gotson.komga.interfaces.api.rest import jakarta.validation.constraints.Email import jakarta.validation.constraints.NotBlank import org.gotson.komga.domain.model.KomgaUser +import org.gotson.komga.domain.model.UserRoles import org.gotson.komga.domain.service.KomgaUserLifecycle import org.gotson.komga.interfaces.api.rest.dto.UserDto import org.gotson.komga.interfaces.api.rest.dto.toDto @@ -42,10 +43,7 @@ class ClaimController( KomgaUser( email = email, password = password, - roleAdmin = true, - roleFileDownload = true, - rolePageStreaming = true, - roleKoboSync = true, + roles = UserRoles.entries.toSet(), ), ).toDto() } diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/LibraryController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/LibraryController.kt index a81869af3..c7451d354 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/LibraryController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/LibraryController.kt @@ -9,7 +9,6 @@ import org.gotson.komga.domain.model.DirectoryNotFoundException import org.gotson.komga.domain.model.DuplicateNameException import org.gotson.komga.domain.model.Library import org.gotson.komga.domain.model.PathContainedInPath -import org.gotson.komga.domain.model.ROLE_ADMIN import org.gotson.komga.domain.model.SearchCondition import org.gotson.komga.domain.model.SearchContext import org.gotson.komga.domain.model.SearchOperator @@ -60,7 +59,7 @@ class LibraryController( libraryRepository.findAll() } else { libraryRepository.findAllByIds(principal.user.sharedLibrariesIds) - }.sortedBy { it.name.lowercase() }.map { it.toDto(includeRoot = principal.user.roleAdmin) } + }.sortedBy { it.name.lowercase() }.map { it.toDto(includeRoot = principal.user.isAdmin) } @GetMapping("{libraryId}") fun getOne( @@ -69,11 +68,11 @@ class LibraryController( ): LibraryDto = libraryRepository.findByIdOrNull(libraryId)?.let { if (!principal.user.canAccessLibrary(it)) throw ResponseStatusException(HttpStatus.FORBIDDEN) - it.toDto(includeRoot = principal.user.roleAdmin) + it.toDto(includeRoot = principal.user.isAdmin) } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) @PostMapping - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") fun addOne( @AuthenticationPrincipal principal: KomgaPrincipal, @Valid @RequestBody @@ -111,7 +110,7 @@ class LibraryController( analyzeDimensions = library.analyzeDimensions, oneshotsDirectory = library.oneshotsDirectory?.ifBlank { null }, ), - ).toDto(includeRoot = principal.user.roleAdmin) + ).toDto(includeRoot = principal.user.isAdmin) } catch (e: Exception) { when (e) { is FileNotFoundException, @@ -126,7 +125,7 @@ class LibraryController( } @PutMapping("/{libraryId}") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.NO_CONTENT) @Deprecated("Use PATCH /v1/library instead", ReplaceWith("patchOne")) fun updateOne( @@ -138,7 +137,7 @@ class LibraryController( } @PatchMapping("/{libraryId}") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.NO_CONTENT) fun patchOne( @PathVariable libraryId: String, @@ -199,7 +198,7 @@ class LibraryController( } @DeleteMapping("/{libraryId}") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.NO_CONTENT) fun deleteOne( @PathVariable libraryId: String, @@ -210,7 +209,7 @@ class LibraryController( } @PostMapping("{libraryId}/scan") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.ACCEPTED) fun scan( @PathVariable libraryId: String, @@ -222,7 +221,7 @@ class LibraryController( } @PostMapping("{libraryId}/analyze") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.ACCEPTED) fun analyze( @PathVariable libraryId: String, @@ -238,7 +237,7 @@ class LibraryController( } @PostMapping("{libraryId}/metadata/refresh") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.ACCEPTED) fun refreshMetadata( @PathVariable libraryId: String, @@ -256,7 +255,7 @@ class LibraryController( } @PostMapping("{libraryId}/empty-trash") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.ACCEPTED) fun emptyTrash( @PathVariable libraryId: String, diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/PageHashController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/PageHashController.kt index 2a65c52ea..2d7f8aff1 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/PageHashController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/PageHashController.kt @@ -8,7 +8,6 @@ import jakarta.validation.Valid import org.gotson.komga.application.tasks.TaskEmitter import org.gotson.komga.domain.model.BookPageNumbered import org.gotson.komga.domain.model.PageHashKnown -import org.gotson.komga.domain.model.ROLE_ADMIN import org.gotson.komga.domain.persistence.PageHashRepository import org.gotson.komga.domain.service.PageHashLifecycle import org.gotson.komga.infrastructure.swagger.PageableAsQueryParam @@ -37,7 +36,7 @@ import org.springframework.web.server.ResponseStatusException @RestController @RequestMapping("api/v1/page-hashes", produces = [MediaType.APPLICATION_JSON_VALUE]) -@PreAuthorize("hasRole('$ROLE_ADMIN')") +@PreAuthorize("hasRole('ADMIN')") class PageHashController( private val pageHashRepository: PageHashRepository, private val pageHashLifecycle: PageHashLifecycle, diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ReadListController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ReadListController.kt index 34f2f1163..2e6ce65ef 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ReadListController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ReadListController.kt @@ -18,8 +18,6 @@ import org.gotson.komga.domain.model.DomainEvent import org.gotson.komga.domain.model.DuplicateNameException import org.gotson.komga.domain.model.Media import org.gotson.komga.domain.model.MediaType.ZIP -import org.gotson.komga.domain.model.ROLE_ADMIN -import org.gotson.komga.domain.model.ROLE_FILE_DOWNLOAD import org.gotson.komga.domain.model.ReadList import org.gotson.komga.domain.model.ReadStatus import org.gotson.komga.domain.model.SearchCondition @@ -179,7 +177,7 @@ class ReadListController( } @PostMapping(value = ["{id}/thumbnails"], consumes = [MediaType.MULTIPART_FORM_DATA_VALUE]) - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") fun addUserUploadedReadListThumbnail( @AuthenticationPrincipal principal: KomgaPrincipal, @PathVariable(name = "id") id: String, @@ -208,7 +206,7 @@ class ReadListController( } @PutMapping("{id}/thumbnails/{thumbnailId}/selected") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.ACCEPTED) fun markSelectedReadListThumbnail( @AuthenticationPrincipal principal: KomgaPrincipal, @@ -224,7 +222,7 @@ class ReadListController( } @DeleteMapping("{id}/thumbnails/{thumbnailId}") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.ACCEPTED) fun deleteUserUploadedReadListThumbnail( @AuthenticationPrincipal principal: KomgaPrincipal, @@ -239,7 +237,7 @@ class ReadListController( } @PostMapping - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") fun addOne( @Valid @RequestBody readList: ReadListCreationDto, @@ -259,7 +257,7 @@ class ReadListController( } @PostMapping("match/comicrack") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") fun matchFromComicRackList( @RequestParam("file") file: MultipartFile, ): ReadListRequestMatchDto = @@ -270,7 +268,7 @@ class ReadListController( } @PatchMapping("{id}") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.NO_CONTENT) fun updateOne( @PathVariable id: String, @@ -294,7 +292,7 @@ class ReadListController( } @DeleteMapping("{id}") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.NO_CONTENT) fun deleteOne( @PathVariable id: String, @@ -352,7 +350,7 @@ class ReadListController( ) bookDtoRepository .findAll(bookSearch, SearchContext(principal.user), pageRequest) - .map { it.restrictUrl(!principal.user.roleAdmin) } + .map { it.restrictUrl(!principal.user.isAdmin) } } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) @GetMapping("{id}/books/{bookId}/previous") @@ -369,7 +367,7 @@ class ReadListController( principal.user.id, principal.user.getAuthorizedLibraryIds(null), principal.user.restrictions, - )?.restrictUrl(!principal.user.roleAdmin) + )?.restrictUrl(!principal.user.isAdmin) } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) @GetMapping("{id}/books/{bookId}/next") @@ -386,7 +384,7 @@ class ReadListController( principal.user.id, principal.user.getAuthorizedLibraryIds(null), principal.user.restrictions, - )?.restrictUrl(!principal.user.roleAdmin) + )?.restrictUrl(!principal.user.isAdmin) } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) @GetMapping("{id}/read-progress/tachiyomi") @@ -418,7 +416,7 @@ class ReadListController( } @GetMapping("{id}/file", produces = [MediaType.APPLICATION_OCTET_STREAM_VALUE]) - @PreAuthorize("hasRole('$ROLE_FILE_DOWNLOAD')") + @PreAuthorize("hasRole('FILE_DOWNLOAD')") fun getReadListFile( @AuthenticationPrincipal principal: KomgaPrincipal, @PathVariable id: String, diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ReleaseController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ReleaseController.kt index dfa606bf8..38570b7d0 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ReleaseController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/ReleaseController.kt @@ -1,7 +1,6 @@ package org.gotson.komga.interfaces.api.rest import com.github.benmanes.caffeine.cache.Caffeine -import org.gotson.komga.domain.model.ROLE_ADMIN import org.gotson.komga.infrastructure.security.KomgaPrincipal import org.gotson.komga.interfaces.api.rest.dto.GithubReleaseDto import org.gotson.komga.interfaces.api.rest.dto.ReleaseDto @@ -20,7 +19,7 @@ import java.util.concurrent.TimeUnit private const val GITHUB_API = "https://api.github.com/repos/gotson/komga/releases" @RestController -@PreAuthorize("hasRole('$ROLE_ADMIN')") +@PreAuthorize("hasRole('ADMIN')") @RequestMapping("api/v1/releases", produces = [MediaType.APPLICATION_JSON_VALUE]) class ReleaseController( webClientBuilder: WebClient.Builder, @@ -34,7 +33,7 @@ class ReleaseController( .build>() @GetMapping - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") fun getAnnouncements( @AuthenticationPrincipal principal: KomgaPrincipal, ): List = diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/SeriesCollectionController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/SeriesCollectionController.kt index 51327bd64..a9491717f 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/SeriesCollectionController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/SeriesCollectionController.kt @@ -10,7 +10,6 @@ import org.gotson.komga.domain.model.Author import org.gotson.komga.domain.model.Dimension import org.gotson.komga.domain.model.DomainEvent import org.gotson.komga.domain.model.DuplicateNameException -import org.gotson.komga.domain.model.ROLE_ADMIN import org.gotson.komga.domain.model.ReadStatus import org.gotson.komga.domain.model.SearchCondition import org.gotson.komga.domain.model.SearchContext @@ -156,7 +155,7 @@ class SeriesCollectionController( } @PostMapping(value = ["{id}/thumbnails"], consumes = [MediaType.MULTIPART_FORM_DATA_VALUE]) - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") fun addUserUploadedCollectionThumbnail( @AuthenticationPrincipal principal: KomgaPrincipal, @PathVariable(name = "id") id: String, @@ -185,7 +184,7 @@ class SeriesCollectionController( } @PutMapping("{id}/thumbnails/{thumbnailId}/selected") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.ACCEPTED) fun markSelectedCollectionThumbnail( @AuthenticationPrincipal principal: KomgaPrincipal, @@ -201,7 +200,7 @@ class SeriesCollectionController( } @DeleteMapping("{id}/thumbnails/{thumbnailId}") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.ACCEPTED) fun deleteUserUploadedCollectionThumbnail( @AuthenticationPrincipal principal: KomgaPrincipal, @@ -216,7 +215,7 @@ class SeriesCollectionController( } @PostMapping - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") fun addOne( @Valid @RequestBody collection: CollectionCreationDto, @@ -235,7 +234,7 @@ class SeriesCollectionController( } @PatchMapping("{id}") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.NO_CONTENT) fun updateOne( @PathVariable id: String, @@ -258,7 +257,7 @@ class SeriesCollectionController( } @DeleteMapping("{id}") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.NO_CONTENT) fun deleteOne( @PathVariable id: String, @@ -339,6 +338,6 @@ class SeriesCollectionController( seriesDtoRepository .findAll(search, SearchContext(principal.user), pageRequest) - .map { it.restrictUrl(!principal.user.roleAdmin) } + .map { it.restrictUrl(!principal.user.isAdmin) } } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) } diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/SeriesController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/SeriesController.kt index 976a431ca..64f4a64a6 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/SeriesController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/SeriesController.kt @@ -25,8 +25,6 @@ import org.gotson.komga.domain.model.KomgaUser import org.gotson.komga.domain.model.MarkSelectedPreference import org.gotson.komga.domain.model.Media import org.gotson.komga.domain.model.MediaType.ZIP -import org.gotson.komga.domain.model.ROLE_ADMIN -import org.gotson.komga.domain.model.ROLE_FILE_DOWNLOAD import org.gotson.komga.domain.model.ReadStatus import org.gotson.komga.domain.model.SearchCondition import org.gotson.komga.domain.model.SearchContext @@ -220,7 +218,7 @@ class SeriesController( return seriesDtoRepository .findAll(seriesSearch, SearchContext(principal.user), pageRequest) - .map { it.restrictUrl(!principal.user.roleAdmin) } + .map { it.restrictUrl(!principal.user.isAdmin) } } @PageableAsQueryParam @@ -250,7 +248,7 @@ class SeriesController( return seriesDtoRepository .findAll(search, SearchContext(principal.user), pageRequest) - .map { it.restrictUrl(!principal.user.roleAdmin) } + .map { it.restrictUrl(!principal.user.isAdmin) } } @Deprecated("use /v1/series/list/alphabetical-groups instead") @@ -376,7 +374,7 @@ class SeriesController( ), SearchContext(principal.user), pageRequest, - ).map { it.restrictUrl(!principal.user.roleAdmin) } + ).map { it.restrictUrl(!principal.user.isAdmin) } } @Operation(description = "Return newly added series.") @@ -415,7 +413,7 @@ class SeriesController( ), SearchContext(principal.user), pageRequest, - ).map { it.restrictUrl(!principal.user.roleAdmin) } + ).map { it.restrictUrl(!principal.user.isAdmin) } } @Operation(description = "Return recently updated series, but not newly added ones.") @@ -454,7 +452,7 @@ class SeriesController( ), SearchContext(principal.user), pageRequest, - ).map { it.restrictUrl(!principal.user.roleAdmin) } + ).map { it.restrictUrl(!principal.user.isAdmin) } } @GetMapping("v1/series/{seriesId}") @@ -464,7 +462,7 @@ class SeriesController( ): SeriesDto = seriesDtoRepository.findByIdOrNull(id, principal.user.id)?.let { contentRestrictionChecker.checkContentRestriction(principal.user, it) - it.restrictUrl(!principal.user.roleAdmin) + it.restrictUrl(!principal.user.isAdmin) } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) @ApiResponse(content = [Content(schema = Schema(type = "string", format = "binary"))]) @@ -505,7 +503,7 @@ class SeriesController( } @PostMapping(value = ["v1/series/{seriesId}/thumbnails"], consumes = [MediaType.MULTIPART_FORM_DATA_VALUE]) - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") fun postUserUploadedSeriesThumbnail( @PathVariable(name = "seriesId") seriesId: String, @RequestParam("file") file: MultipartFile, @@ -533,7 +531,7 @@ class SeriesController( } @PutMapping("v1/series/{seriesId}/thumbnails/{thumbnailId}/selected") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.ACCEPTED) fun postMarkSelectedSeriesThumbnail( @PathVariable(name = "seriesId") seriesId: String, @@ -547,7 +545,7 @@ class SeriesController( } @DeleteMapping("v1/series/{seriesId}/thumbnails/{thumbnailId}") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.ACCEPTED) fun deleteUserUploadedSeriesThumbnail( @PathVariable(name = "seriesId") seriesId: String, @@ -613,7 +611,7 @@ class SeriesController( search, SearchContext(principal.user), pageRequest, - ).map { it.restrictUrl(!principal.user.roleAdmin) } + ).map { it.restrictUrl(!principal.user.isAdmin) } } @GetMapping("v1/series/{seriesId}/collections") @@ -629,7 +627,7 @@ class SeriesController( } @PostMapping("v1/series/{seriesId}/analyze") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.ACCEPTED) fun analyze( @PathVariable seriesId: String, @@ -638,7 +636,7 @@ class SeriesController( } @PostMapping("v1/series/{seriesId}/metadata/refresh") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.ACCEPTED) fun refreshMetadata( @PathVariable seriesId: String, @@ -650,7 +648,7 @@ class SeriesController( } @PatchMapping("v1/series/{seriesId}/metadata") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.NO_CONTENT) fun updateMetadata( @PathVariable seriesId: String, @@ -780,7 +778,7 @@ class SeriesController( } @GetMapping("v1/series/{seriesId}/file", produces = [MediaType.APPLICATION_OCTET_STREAM_VALUE]) - @PreAuthorize("hasRole('$ROLE_FILE_DOWNLOAD')") + @PreAuthorize("hasRole('FILE_DOWNLOAD')") fun getSeriesFile( @AuthenticationPrincipal principal: KomgaPrincipal, @PathVariable seriesId: String, @@ -827,7 +825,7 @@ class SeriesController( } @DeleteMapping("v1/series/{seriesId}/file") - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") @ResponseStatus(HttpStatus.ACCEPTED) fun deleteSeries( @PathVariable seriesId: String, diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/SettingsController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/SettingsController.kt index bad35518c..4ae30d729 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/SettingsController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/SettingsController.kt @@ -1,7 +1,6 @@ package org.gotson.komga.interfaces.api.rest import jakarta.validation.Valid -import org.gotson.komga.domain.model.ROLE_ADMIN import org.gotson.komga.infrastructure.configuration.KomgaSettingsProvider import org.gotson.komga.infrastructure.kobo.KepubConverter import org.gotson.komga.infrastructure.web.WebServerEffectiveSettings @@ -24,7 +23,7 @@ import kotlin.time.Duration.Companion.days @RestController @RequestMapping(value = ["api/v1/settings"], produces = [MediaType.APPLICATION_JSON_VALUE]) -@PreAuthorize("hasRole('$ROLE_ADMIN')") +@PreAuthorize("hasRole('ADMIN')") class SettingsController( private val komgaSettingsProvider: KomgaSettingsProvider, @Value("\${server.port:#{null}}") private val configServerPort: Int?, diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/TaskController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/TaskController.kt index 4415cfe98..c1dc4562b 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/TaskController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/TaskController.kt @@ -1,7 +1,6 @@ package org.gotson.komga.interfaces.api.rest import org.gotson.komga.application.tasks.TasksRepository -import org.gotson.komga.domain.model.ROLE_ADMIN import org.springframework.http.HttpStatus import org.springframework.http.MediaType import org.springframework.security.access.prepost.PreAuthorize @@ -17,6 +16,6 @@ class TaskController( ) { @DeleteMapping("api/v1/tasks") @ResponseStatus(HttpStatus.OK) - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") fun emptyTaskQueue(): Int = tasksRepository.deleteAllWithoutOwner() } diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/TransientBooksController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/TransientBooksController.kt index 2f2cfc93d..43116ef74 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/TransientBooksController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/TransientBooksController.kt @@ -5,7 +5,6 @@ import io.github.oshai.kotlinlogging.KotlinLogging import org.gotson.komga.domain.model.CodedException import org.gotson.komga.domain.model.MediaNotReadyException import org.gotson.komga.domain.model.MediaProfile -import org.gotson.komga.domain.model.ROLE_ADMIN import org.gotson.komga.domain.model.TransientBook import org.gotson.komga.domain.persistence.TransientBookRepository import org.gotson.komga.domain.service.BookAnalyzer @@ -31,7 +30,7 @@ private val logger = KotlinLogging.logger {} @RestController @RequestMapping("api/v1/transient-books", produces = [MediaType.APPLICATION_JSON_VALUE]) -@PreAuthorize("hasRole('$ROLE_ADMIN')") +@PreAuthorize("hasRole('ADMIN')") class TransientBooksController( private val transientBookLifecycle: TransientBookLifecycle, private val transientBookRepository: TransientBookRepository, diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/UserController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/UserController.kt index ef38f30db..929ea84fc 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/UserController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/UserController.kt @@ -6,11 +6,8 @@ import jakarta.validation.Valid import org.gotson.komga.domain.model.AgeRestriction import org.gotson.komga.domain.model.ContentRestrictions import org.gotson.komga.domain.model.DuplicateNameException -import org.gotson.komga.domain.model.ROLE_ADMIN -import org.gotson.komga.domain.model.ROLE_FILE_DOWNLOAD -import org.gotson.komga.domain.model.ROLE_KOBO_SYNC -import org.gotson.komga.domain.model.ROLE_PAGE_STREAMING import org.gotson.komga.domain.model.UserEmailAlreadyExistsException +import org.gotson.komga.domain.model.UserRoles import org.gotson.komga.domain.persistence.AuthenticationActivityRepository import org.gotson.komga.domain.persistence.KomgaUserRepository import org.gotson.komga.domain.persistence.LibraryRepository @@ -80,12 +77,12 @@ class UserController( } @GetMapping - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") fun getAll(): List = userRepository.findAll().map { it.toDto() } @PostMapping @ResponseStatus(HttpStatus.CREATED) - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") fun addOne( @Valid @RequestBody newUser: UserCreationDto, @@ -98,7 +95,7 @@ class UserController( @DeleteMapping("{id}") @ResponseStatus(HttpStatus.NO_CONTENT) - @PreAuthorize("hasRole('$ROLE_ADMIN') and #principal.user.id != #id") + @PreAuthorize("hasRole('ADMIN') and #principal.user.id != #id") fun delete( @PathVariable id: String, @AuthenticationPrincipal principal: KomgaPrincipal, @@ -110,7 +107,7 @@ class UserController( @PatchMapping("{id}") @ResponseStatus(HttpStatus.NO_CONTENT) - @PreAuthorize("hasRole('$ROLE_ADMIN') and #principal.user.id != #id") + @PreAuthorize("hasRole('ADMIN') and #principal.user.id != #id") fun updateUser( @PathVariable id: String, @Valid @RequestBody @@ -121,10 +118,7 @@ class UserController( val updatedUser = with(patch) { existing.copy( - roleAdmin = if (isSet("roles")) roles!!.contains(ROLE_ADMIN) else existing.roleAdmin, - roleFileDownload = if (isSet("roles")) roles!!.contains(ROLE_FILE_DOWNLOAD) else existing.roleFileDownload, - rolePageStreaming = if (isSet("roles")) roles!!.contains(ROLE_PAGE_STREAMING) else existing.rolePageStreaming, - roleKoboSync = if (isSet("roles")) roles!!.contains(ROLE_KOBO_SYNC) else existing.roleKoboSync, + roles = if (isSet("roles")) UserRoles.valuesOf(roles!!) else existing.roles, sharedAllLibraries = if (isSet("sharedLibraries")) sharedLibraries!!.all else existing.sharedAllLibraries, sharedLibrariesIds = if (isSet("sharedLibraries")) { @@ -167,7 +161,7 @@ class UserController( @PatchMapping("{id}/password") @ResponseStatus(HttpStatus.NO_CONTENT) - @PreAuthorize("hasRole('$ROLE_ADMIN') or #principal.user.id == #id") + @PreAuthorize("hasRole('ADMIN') or #principal.user.id == #id") fun updatePassword( @PathVariable id: String, @AuthenticationPrincipal principal: KomgaPrincipal, @@ -187,7 +181,7 @@ class UserController( @RequestParam(name = "unpaged", required = false) unpaged: Boolean = false, @Parameter(hidden = true) page: Pageable, ): Page { - if (demo && !principal.user.roleAdmin) throw ResponseStatusException(HttpStatus.FORBIDDEN) + if (demo && !principal.user.isAdmin) throw ResponseStatusException(HttpStatus.FORBIDDEN) val sort = if (page.sort.isSorted) page.sort @@ -209,7 +203,7 @@ class UserController( @GetMapping("authentication-activity") @PageableAsQueryParam - @PreAuthorize("hasRole('$ROLE_ADMIN')") + @PreAuthorize("hasRole('ADMIN')") fun getAuthenticationActivity( @RequestParam(name = "unpaged", required = false) unpaged: Boolean = false, @Parameter(hidden = true) page: Pageable, @@ -234,7 +228,7 @@ class UserController( } @GetMapping("{id}/authentication-activity/latest") - @PreAuthorize("hasRole('$ROLE_ADMIN') or #principal.user.id == #id") + @PreAuthorize("hasRole('ADMIN') or #principal.user.id == #id") fun getLatestAuthenticationActivityForUser( @PathVariable id: String, @AuthenticationPrincipal principal: KomgaPrincipal, @@ -249,7 +243,7 @@ class UserController( fun getApiKeys( @AuthenticationPrincipal principal: KomgaPrincipal, ): Collection { - if (demo) throw ResponseStatusException(HttpStatus.FORBIDDEN) + if (demo && !principal.user.isAdmin) throw ResponseStatusException(HttpStatus.FORBIDDEN) return userRepository.findApiKeyByUserId(principal.user.id).map { it.toDto().redacted() } } @@ -258,7 +252,7 @@ class UserController( @AuthenticationPrincipal principal: KomgaPrincipal, @Valid @RequestBody apiKeyRequest: ApiKeyRequestDto, ): ApiKeyDto { - if (demo) throw ResponseStatusException(HttpStatus.FORBIDDEN) + if (demo && !principal.user.isAdmin) throw ResponseStatusException(HttpStatus.FORBIDDEN) return try { userLifecycle.createApiKey(principal.user, apiKeyRequest.comment)?.toDto() } catch (e: DuplicateNameException) { diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/dto/UserDto.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/dto/UserDto.kt index 67c409724..daf9b1da6 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/dto/UserDto.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/dto/UserDto.kt @@ -5,10 +5,7 @@ import jakarta.validation.constraints.NotBlank import org.gotson.komga.domain.model.AgeRestriction import org.gotson.komga.domain.model.AllowExclude import org.gotson.komga.domain.model.KomgaUser -import org.gotson.komga.domain.model.ROLE_ADMIN -import org.gotson.komga.domain.model.ROLE_FILE_DOWNLOAD -import org.gotson.komga.domain.model.ROLE_KOBO_SYNC -import org.gotson.komga.domain.model.ROLE_PAGE_STREAMING +import org.gotson.komga.domain.model.UserRoles import org.gotson.komga.infrastructure.security.KomgaPrincipal data class UserDto( @@ -33,7 +30,7 @@ fun KomgaUser.toDto() = UserDto( id = id, email = email, - roles = roles, + roles = roles.map { it.name }.toSet() + "USER", sharedAllLibraries = sharedAllLibraries, sharedLibrariesIds = sharedLibrariesIds, labelsAllow = restrictions.labelsAllow, @@ -52,10 +49,7 @@ data class UserCreationDto( KomgaUser( email, password, - roleAdmin = roles.contains(ROLE_ADMIN), - roleFileDownload = roles.contains(ROLE_FILE_DOWNLOAD), - rolePageStreaming = roles.contains(ROLE_PAGE_STREAMING), - roleKoboSync = roles.contains(ROLE_KOBO_SYNC), + roles = UserRoles.valuesOf(roles), ) } diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/scheduler/InitialUserController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/scheduler/InitialUserController.kt index 2757ceef4..73b88f1d6 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/scheduler/InitialUserController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/scheduler/InitialUserController.kt @@ -3,6 +3,7 @@ package org.gotson.komga.interfaces.scheduler import io.github.oshai.kotlinlogging.KotlinLogging import org.apache.commons.lang3.RandomStringUtils import org.gotson.komga.domain.model.KomgaUser +import org.gotson.komga.domain.model.UserRoles import org.gotson.komga.domain.service.KomgaUserLifecycle import org.springframework.boot.context.event.ApplicationReadyEvent import org.springframework.context.annotation.Bean @@ -39,8 +40,8 @@ class InitialUsersDevConfiguration { @Bean fun initialUsers(): List = listOf( - KomgaUser("admin@example.org", "admin", roleAdmin = true, roleKoboSync = true), - KomgaUser("user@example.org", "user", roleAdmin = false), + KomgaUser("admin@example.org", "admin", roles = UserRoles.entries.toSet()), + KomgaUser("user@example.org", "user"), ) } @@ -50,6 +51,6 @@ class InitialUsersProdConfiguration { @Bean fun initialUsers(): List = listOf( - KomgaUser("admin@example.org", RandomStringUtils.secure().nextAlphanumeric(12), roleAdmin = true), + KomgaUser("admin@example.org", RandomStringUtils.secure().nextAlphanumeric(12), roles = UserRoles.entries.toSet()), ) } diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/sse/SseController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/sse/SseController.kt index c00e42de7..24742c475 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/sse/SseController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/sse/SseController.kt @@ -117,7 +117,7 @@ class SseController( synchronized(emitters) { emitters - .filter { if (adminOnly) it.value.roleAdmin else true } + .filter { if (adminOnly) it.value.isAdmin else true } .filter { if (userIdOnly != null) it.value.id == userIdOnly else true } .forEach { (emitter, _) -> try { diff --git a/komga/src/test/kotlin/org/gotson/komga/domain/model/KomgaUserTest.kt b/komga/src/test/kotlin/org/gotson/komga/domain/model/KomgaUserTest.kt index 8ead0b6a0..4cda00027 100644 --- a/komga/src/test/kotlin/org/gotson/komga/domain/model/KomgaUserTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/domain/model/KomgaUserTest.kt @@ -5,7 +5,7 @@ import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test class KomgaUserTest { - val defaultUser = KomgaUser("user@example.org", "aPassword", false) + val defaultUser = KomgaUser("user@example.org", "aPassword") @Nested inner class ContentRestriction { diff --git a/komga/src/test/kotlin/org/gotson/komga/domain/service/BookImporterTest.kt b/komga/src/test/kotlin/org/gotson/komga/domain/service/BookImporterTest.kt index f2ff8ac7a..c144ddac4 100644 --- a/komga/src/test/kotlin/org/gotson/komga/domain/service/BookImporterTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/domain/service/BookImporterTest.kt @@ -62,8 +62,8 @@ class BookImporterTest( @Autowired private val readListLifecycle: ReadListLifecycle, ) { private val library = makeLibrary("lib", "file:/library") - private val user1 = KomgaUser("user1@example.org", "", false) - private val user2 = KomgaUser("user2@example.org", "", false) + private val user1 = KomgaUser("user1@example.org", "") + private val user2 = KomgaUser("user2@example.org", "") @MockkBean private lateinit var mockTackReceiver: TaskEmitter diff --git a/komga/src/test/kotlin/org/gotson/komga/domain/service/BookLifecycleTest.kt b/komga/src/test/kotlin/org/gotson/komga/domain/service/BookLifecycleTest.kt index 706429c7b..4e9ad65eb 100644 --- a/komga/src/test/kotlin/org/gotson/komga/domain/service/BookLifecycleTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/domain/service/BookLifecycleTest.kt @@ -62,8 +62,8 @@ class BookLifecycleTest( private lateinit var mockAnalyzer: BookAnalyzer private val library = makeLibrary() - private val user1 = KomgaUser("user1@example.org", "", false) - private val user2 = KomgaUser("user2@example.org", "", false) + private val user1 = KomgaUser("user1@example.org", "") + private val user2 = KomgaUser("user2@example.org", "") @BeforeAll fun `setup library`() { diff --git a/komga/src/test/kotlin/org/gotson/komga/domain/service/KomgaUserLifecycleTest.kt b/komga/src/test/kotlin/org/gotson/komga/domain/service/KomgaUserLifecycleTest.kt index 5f4e4d90c..17a07d7b2 100644 --- a/komga/src/test/kotlin/org/gotson/komga/domain/service/KomgaUserLifecycleTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/domain/service/KomgaUserLifecycleTest.kt @@ -25,8 +25,8 @@ class KomgaUserLifecycleTest( @SpykBean private lateinit var apiKeyGenerator: ApiKeyGenerator - private val user1 = KomgaUser("user1@example.org", "", false) - private val user2 = KomgaUser("user2@example.org", "", false) + private val user1 = KomgaUser("user1@example.org", "") + private val user2 = KomgaUser("user2@example.org", "") @BeforeAll fun setup() { diff --git a/komga/src/test/kotlin/org/gotson/komga/domain/service/LibraryContentLifecycleTest.kt b/komga/src/test/kotlin/org/gotson/komga/domain/service/LibraryContentLifecycleTest.kt index c90733c0d..8d53d06b1 100644 --- a/komga/src/test/kotlin/org/gotson/komga/domain/service/LibraryContentLifecycleTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/domain/service/LibraryContentLifecycleTest.kt @@ -88,7 +88,7 @@ class LibraryContentLifecycleTest( @MockkBean private lateinit var mockTaskEmitter: TaskEmitter - private val user = KomgaUser("user@example.org", "", false, id = "1") + private val user = KomgaUser("user@example.org", "", id = "1") @BeforeAll fun setup() { diff --git a/komga/src/test/kotlin/org/gotson/komga/domain/service/SyncPointLifecycleTest.kt b/komga/src/test/kotlin/org/gotson/komga/domain/service/SyncPointLifecycleTest.kt index a3cb77f9b..3797f41b3 100644 --- a/komga/src/test/kotlin/org/gotson/komga/domain/service/SyncPointLifecycleTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/domain/service/SyncPointLifecycleTest.kt @@ -54,7 +54,6 @@ class SyncPointLifecycleTest( KomgaUser( "user1@example.org", "", - false, sharedLibrariesIds = setOf(library1.id, library2.id), restrictions = ContentRestrictions( diff --git a/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDtoDaoTest.kt b/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDtoDaoTest.kt index 1a288f8a7..d117e78c4 100644 --- a/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDtoDaoTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDtoDaoTest.kt @@ -63,7 +63,7 @@ class BookDtoDaoTest( ) { private val library = makeLibrary() private var series = makeSeries("Series") - private val user = KomgaUser("user@example.org", "", false) + private val user = KomgaUser("user@example.org", "") @MockkBean private lateinit var mockEventPublisher: ApplicationEventPublisher diff --git a/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/BookSearchTest.kt b/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/BookSearchTest.kt index 0b4d9bd46..f4d824d61 100644 --- a/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/BookSearchTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/BookSearchTest.kt @@ -69,8 +69,8 @@ class BookSearchTest( private val library2 = makeLibrary() private val series1 = makeSeries("Series 1").copy(libraryId = library1.id) private val series2 = makeSeries("Series 2").copy(libraryId = library2.id) - private val user1 = KomgaUser("user1@example.org", "p", false) - private val user2 = KomgaUser("user2@example.org", "p", false) + private val user1 = KomgaUser("user1@example.org", "p") + private val user2 = KomgaUser("user2@example.org", "p") @MockkBean private lateinit var mockEventPublisher: ApplicationEventPublisher diff --git a/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/KomgaUserDaoTest.kt b/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/KomgaUserDaoTest.kt index 1187f1068..ffddea44c 100644 --- a/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/KomgaUserDaoTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/KomgaUserDaoTest.kt @@ -5,6 +5,7 @@ import org.gotson.komga.domain.model.AgeRestriction import org.gotson.komga.domain.model.AllowExclude import org.gotson.komga.domain.model.ContentRestrictions import org.gotson.komga.domain.model.KomgaUser +import org.gotson.komga.domain.model.UserRoles import org.gotson.komga.domain.model.makeLibrary import org.gotson.komga.domain.persistence.LibraryRepository import org.gotson.komga.infrastructure.jooq.offset @@ -46,10 +47,6 @@ class KomgaUserDaoTest( KomgaUser( email = "user@example.org", password = "password", - roleAdmin = false, - rolePageStreaming = false, - roleFileDownload = false, - roleKoboSync = false, sharedLibrariesIds = setOf(library.id), sharedAllLibraries = false, ) @@ -63,10 +60,7 @@ class KomgaUserDaoTest( assertThat(lastModifiedDate).isCloseTo(now, offset) assertThat(email).isEqualTo("user@example.org") assertThat(password).isEqualTo("password") - assertThat(roleAdmin).isFalse - assertThat(rolePageStreaming).isFalse - assertThat(roleFileDownload).isFalse - assertThat(roleKoboSync).isFalse + assertThat(roles).containsExactlyInAnyOrder(UserRoles.FILE_DOWNLOAD, UserRoles.PAGE_STREAMING) assertThat(sharedLibrariesIds).containsExactly(library.id) assertThat(sharedAllLibraries).isFalse assertThat(restrictions.ageRestriction).isNull() @@ -81,10 +75,6 @@ class KomgaUserDaoTest( KomgaUser( email = "user@example.org", password = "password", - roleAdmin = false, - rolePageStreaming = false, - roleFileDownload = false, - roleKoboSync = false, sharedLibrariesIds = setOf(library.id), sharedAllLibraries = false, restrictions = @@ -109,10 +99,7 @@ class KomgaUserDaoTest( created.copy( email = "user2@example.org", password = "password2", - roleAdmin = true, - rolePageStreaming = true, - roleFileDownload = true, - roleKoboSync = true, + roles = setOf(UserRoles.ADMIN, UserRoles.FILE_DOWNLOAD, UserRoles.PAGE_STREAMING, UserRoles.KOBO_SYNC), sharedLibrariesIds = emptySet(), sharedAllLibraries = true, restrictions = @@ -134,10 +121,7 @@ class KomgaUserDaoTest( .isNotEqualTo(modified.createdDate) assertThat(email).isEqualTo("user2@example.org") assertThat(password).isEqualTo("password2") - assertThat(roleAdmin).isTrue - assertThat(rolePageStreaming).isTrue - assertThat(roleFileDownload).isTrue - assertThat(roleKoboSync).isTrue + assertThat(roles).containsExactlyInAnyOrder(UserRoles.ADMIN, UserRoles.FILE_DOWNLOAD, UserRoles.PAGE_STREAMING, UserRoles.KOBO_SYNC) assertThat(sharedLibrariesIds).isEmpty() assertThat(sharedAllLibraries).isTrue assertThat(restrictions.ageRestriction).isNotNull @@ -157,8 +141,8 @@ class KomgaUserDaoTest( @Test fun `given multiple users when saving then they are persisted`() { - komgaUserDao.insert(KomgaUser("user1@example.org", "p", false)) - komgaUserDao.insert(KomgaUser("user2@example.org", "p", true)) + komgaUserDao.insert(KomgaUser("user1@example.org", "p")) + komgaUserDao.insert(KomgaUser("user2@example.org", "p")) val users = komgaUserDao.findAll() @@ -171,8 +155,8 @@ class KomgaUserDaoTest( @Test fun `given some users when counting then proper count is returned`() { - komgaUserDao.insert(KomgaUser("user1@example.org", "p", false)) - komgaUserDao.insert(KomgaUser("user2@example.org", "p", true)) + komgaUserDao.insert(KomgaUser("user1@example.org", "p")) + komgaUserDao.insert(KomgaUser("user2@example.org", "p")) val count = komgaUserDao.count() @@ -181,7 +165,7 @@ class KomgaUserDaoTest( @Test fun `given existing user when finding by id then user is returned`() { - val existing = KomgaUser("user1@example.org", "p", false) + val existing = KomgaUser("user1@example.org", "p") komgaUserDao.insert(existing) val user = komgaUserDao.findByIdOrNull(existing.id) @@ -198,7 +182,7 @@ class KomgaUserDaoTest( @Test fun `given existing user when deleting then user is deleted`() { - val existing = KomgaUser("user1@example.org", "p", false) + val existing = KomgaUser("user1@example.org", "p") komgaUserDao.insert(existing) komgaUserDao.delete(existing.id) @@ -209,7 +193,7 @@ class KomgaUserDaoTest( @Test fun `given users when checking if exists by email then return true or false`() { komgaUserDao.insert( - KomgaUser("user1@example.org", "p", false), + KomgaUser("user1@example.org", "p"), ) val exists = komgaUserDao.existsByEmailIgnoreCase("USER1@EXAMPLE.ORG") @@ -222,7 +206,7 @@ class KomgaUserDaoTest( @Test fun `given users when finding by email then return user`() { komgaUserDao.insert( - KomgaUser("user1@example.org", "p", false), + KomgaUser("user1@example.org", "p"), ) val found = komgaUserDao.findByEmailIgnoreCaseOrNull("USER1@EXAMPLE.ORG") diff --git a/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadProgressDaoTest.kt b/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadProgressDaoTest.kt index a6d64ec45..3028dc72c 100644 --- a/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadProgressDaoTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadProgressDaoTest.kt @@ -30,8 +30,8 @@ class ReadProgressDaoTest( private val library = makeLibrary() private val series = makeSeries("Series") - private val user1 = KomgaUser("user1@example.org", "", false) - private val user2 = KomgaUser("user2@example.org", "", false) + private val user1 = KomgaUser("user1@example.org", "") + private val user2 = KomgaUser("user2@example.org", "") private val book1 = makeBook("Book1") private val book2 = makeBook("Book2") diff --git a/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesDtoDaoTest.kt b/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesDtoDaoTest.kt index 215af7a55..15d9bf35b 100644 --- a/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesDtoDaoTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesDtoDaoTest.kt @@ -61,7 +61,7 @@ class SeriesDtoDaoTest( @Autowired private val searchIndexLifecycle: SearchIndexLifecycle, ) { private val library = makeLibrary() - private val user = KomgaUser("user@example.org", "", false) + private val user = KomgaUser("user@example.org", "") @MockkBean private lateinit var mockEventPublisher: ApplicationEventPublisher diff --git a/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesSearchTest.kt b/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesSearchTest.kt index 7c2de0093..239f2a6b4 100644 --- a/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesSearchTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesSearchTest.kt @@ -65,8 +65,8 @@ class SeriesSearchTest( private lateinit var seriesMetadataRepository: SeriesMetadataRepository private val library1 = makeLibrary() private val library2 = makeLibrary() - private val user1 = KomgaUser("user1@example.org", "p", false) - private val user2 = KomgaUser("user2@example.org", "p", false) + private val user1 = KomgaUser("user1@example.org", "p") + private val user2 = KomgaUser("user2@example.org", "p") @MockkBean private lateinit var mockEventPublisher: ApplicationEventPublisher diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/SessionTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/SessionTest.kt index 3856990b5..c4ca42333 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/SessionTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/SessionTest.kt @@ -29,7 +29,7 @@ class SessionTest( @BeforeAll fun setup() { - user = KomgaUser("user@example.org", "user", false) + user = KomgaUser("user@example.org", "user") userLifecycle.createUser(user) } diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/kobo/KoboControllerTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/kobo/KoboControllerTest.kt index d4fd85594..e7b83b85f 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/kobo/KoboControllerTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/kobo/KoboControllerTest.kt @@ -4,6 +4,7 @@ import org.assertj.core.api.Assertions.assertThat import org.gotson.komga.domain.model.KomgaUser import org.gotson.komga.domain.model.Media import org.gotson.komga.domain.model.MediaType +import org.gotson.komga.domain.model.UserRoles import org.gotson.komga.domain.model.makeBook import org.gotson.komga.domain.model.makeLibrary import org.gotson.komga.domain.model.makeSeries @@ -53,8 +54,7 @@ class KoboControllerTest( KomgaUser( "user@example.org", "", - false, - roleKoboSync = true, + roles = setOf(UserRoles.KOBO_SYNC), ) private lateinit var apiKey: String diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/opds/OpdsControllerTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/opds/OpdsControllerTest.kt index a47cee671..086dd6538 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/opds/OpdsControllerTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/opds/OpdsControllerTest.kt @@ -44,8 +44,8 @@ class OpdsControllerTest( @Autowired private val mockMvc: MockMvc, ) { private val library = makeLibrary(id = "1") - private val user = KomgaUser("user@example.org", "", false, id = "1") - private val user2 = KomgaUser("user2@example.org", "", false, id = "2") + private val user = KomgaUser("user@example.org", "", id = "1") + private val user2 = KomgaUser("user2@example.org", "", id = "2") @BeforeAll fun `setup library`() { diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/ActuatorTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/ActuatorTest.kt index 55f780e87..17298e3e1 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/ActuatorTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/ActuatorTest.kt @@ -1,7 +1,5 @@ package org.gotson.komga.interfaces.api.rest -import org.gotson.komga.domain.model.ROLE_ADMIN -import org.gotson.komga.domain.model.ROLE_USER import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc @@ -45,7 +43,7 @@ class ActuatorTest( } @Test - @WithMockUser(roles = [ROLE_USER]) + @WithMockUser fun `given regular user when getting actuator endpoints then returns forbidden`() { mockMvc .get("/actuator") @@ -61,7 +59,7 @@ class ActuatorTest( } @Test - @WithMockUser(roles = [ROLE_ADMIN]) + @WithMockUser(roles = ["ADMIN"]) fun `given admin user when getting actuator endpoints then returns ok`() { mockMvc .get("/actuator") diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/AnnouncementControllerTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/AnnouncementControllerTest.kt index 15ce1ee90..f3139ee05 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/AnnouncementControllerTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/AnnouncementControllerTest.kt @@ -3,7 +3,6 @@ package org.gotson.komga.interfaces.api.rest import com.ninjasquad.springmockk.SpykBean import io.mockk.every import io.mockk.verify -import org.gotson.komga.domain.model.ROLE_ADMIN import org.gotson.komga.interfaces.api.rest.dto.JsonFeedDto import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired @@ -56,7 +55,7 @@ class AnnouncementControllerTest( ) @Test - @WithMockCustomUser(roles = [ROLE_ADMIN]) + @WithMockCustomUser(roles = ["ADMIN"]) fun `when getting announcements multiple times then the server announcements are only fetched once`() { every { announcementController.fetchWebsiteAnnouncements() } returns mockFeed diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/BookControllerTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/BookControllerTest.kt index 827c9b5e2..f8b801ee0 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/BookControllerTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/BookControllerTest.kt @@ -8,7 +8,6 @@ import org.gotson.komga.domain.model.Dimension import org.gotson.komga.domain.model.KomgaUser import org.gotson.komga.domain.model.MarkSelectedPreference import org.gotson.komga.domain.model.Media -import org.gotson.komga.domain.model.ROLE_ADMIN import org.gotson.komga.domain.model.ThumbnailBook import org.gotson.komga.domain.model.makeBook import org.gotson.komga.domain.model.makeLibrary @@ -71,8 +70,8 @@ class BookControllerTest( @Autowired private val mockMvc: MockMvc, ) { private val library = makeLibrary(id = "1") - private val user = KomgaUser("user@example.org", "", false, id = "1") - private val user2 = KomgaUser("user2@example.org", "", false, id = "2") + private val user = KomgaUser("user@example.org", "", id = "1") + private val user2 = KomgaUser("user2@example.org", "", id = "2") @BeforeAll fun `setup library`() { @@ -771,7 +770,7 @@ class BookControllerTest( } @Test - @WithMockCustomUser(roles = [ROLE_ADMIN]) + @WithMockCustomUser(roles = ["ADMIN"]) fun `given admin user when getting books then full url is available`() { val createdSeries = makeSeries(name = "series", libraryId = library.id).let { series -> @@ -958,7 +957,7 @@ class BookControllerTest( """{"isbn":"978-123-456-789-6"}""", // invalid check digit ], ) - @WithMockCustomUser(roles = [ROLE_ADMIN]) + @WithMockCustomUser(roles = ["ADMIN"]) fun `given invalid json when updating metadata then raise validation error`(jsonString: String) { mockMvc .patch("/api/v1/books/1/metadata") { @@ -970,7 +969,7 @@ class BookControllerTest( } @Test - @WithMockCustomUser(roles = [ROLE_ADMIN]) + @WithMockCustomUser(roles = ["ADMIN"]) fun `given valid json when updating metadata then fields are updated`() { makeSeries(name = "series", libraryId = library.id).let { series -> seriesLifecycle.createSeries(series).also { created -> @@ -1050,7 +1049,7 @@ class BookControllerTest( } @Test - @WithMockCustomUser(roles = [ROLE_ADMIN]) + @WithMockCustomUser(roles = ["ADMIN"]) fun `given json with blank fields when updating metadata then fields with blanks are unset`() { makeSeries(name = "series", libraryId = library.id).let { series -> seriesLifecycle.createSeries(series).also { created -> @@ -1095,7 +1094,7 @@ class BookControllerTest( } @Test - @WithMockCustomUser(roles = [ROLE_ADMIN]) + @WithMockCustomUser(roles = ["ADMIN"]) fun `given json with null fields when updating metadata then fields with null are unset`() { val testDate = LocalDate.of(2020, 1, 1) @@ -1157,7 +1156,7 @@ class BookControllerTest( } @Test - @WithMockCustomUser(roles = [ROLE_ADMIN]) + @WithMockCustomUser(roles = ["ADMIN"]) fun `given json without fields when updating metadata then existing fields are untouched`() { val testDate = LocalDate.of(2020, 1, 1) diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/FileSystemControllerTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/FileSystemControllerTest.kt index 29b76a915..6aa82fce6 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/FileSystemControllerTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/FileSystemControllerTest.kt @@ -1,7 +1,5 @@ package org.gotson.komga.interfaces.api.rest -import org.gotson.komga.domain.model.ROLE_ADMIN -import org.gotson.komga.domain.model.ROLE_USER import org.junit.jupiter.api.Test import org.junit.jupiter.api.io.TempDir import org.springframework.beans.factory.annotation.Autowired @@ -39,7 +37,7 @@ class FileSystemControllerTest( } @Test - @WithMockUser(roles = [ROLE_USER, ROLE_ADMIN]) + @WithMockUser(roles = ["ADMIN"]) fun `given relative path param when getDirectoryListing then return bad request`() { mockMvc .post(route) { @@ -49,7 +47,7 @@ class FileSystemControllerTest( } @Test - @WithMockUser(roles = [ROLE_USER, ROLE_ADMIN]) + @WithMockUser(roles = ["ADMIN"]) fun `given non-existent path param when getDirectoryListing then return bad request`( @TempDir parent: Path, ) { diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/LibraryControllerTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/LibraryControllerTest.kt index 1f2bf53fa..decbe055e 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/LibraryControllerTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/LibraryControllerTest.kt @@ -1,7 +1,5 @@ package org.gotson.komga.interfaces.api.rest -import org.gotson.komga.domain.model.ROLE_ADMIN -import org.gotson.komga.domain.model.ROLE_USER import org.gotson.komga.domain.model.makeLibrary import org.gotson.komga.domain.persistence.LibraryRepository import org.hamcrest.Matchers @@ -68,7 +66,7 @@ class LibraryControllerTest( } @Nested - inner class UserRole { + inner class UserRoles { @Test @WithMockCustomUser fun `given user with access to all libraries when getAll then return ok`() { @@ -78,7 +76,7 @@ class LibraryControllerTest( } @Test - @WithMockUser(roles = [ROLE_USER]) + @WithMockUser fun `given user with USER role when addOne then return forbidden`() { // language=JSON val jsonString = """{"name":"test", "root": "C:\\Temp"}""" @@ -127,7 +125,7 @@ class LibraryControllerTest( } @Test - @WithMockCustomUser(roles = [ROLE_ADMIN]) + @WithMockCustomUser(roles = ["ADMIN"]) fun `given admin user when getting books then root is available`() { mockMvc .get(route) @@ -170,7 +168,7 @@ class LibraryControllerTest( } @Test - @WithMockCustomUser(roles = [ROLE_ADMIN]) + @WithMockCustomUser(roles = ["ADMIN"]) fun `given library with exclusions when updating library then exclusions are updated`( @TempDir tmp: Path, ) { diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/MockSpringSecurity.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/MockSpringSecurity.kt index f1c8b9244..240adba80 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/MockSpringSecurity.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/MockSpringSecurity.kt @@ -4,10 +4,7 @@ import org.gotson.komga.domain.model.AgeRestriction import org.gotson.komga.domain.model.AllowExclude import org.gotson.komga.domain.model.ContentRestrictions import org.gotson.komga.domain.model.KomgaUser -import org.gotson.komga.domain.model.ROLE_ADMIN -import org.gotson.komga.domain.model.ROLE_FILE_DOWNLOAD -import org.gotson.komga.domain.model.ROLE_KOBO_SYNC -import org.gotson.komga.domain.model.ROLE_PAGE_STREAMING +import org.gotson.komga.domain.model.UserRoles import org.gotson.komga.infrastructure.security.KomgaPrincipal import org.gotson.komga.infrastructure.security.apikey.ApiKeyAuthenticationToken import org.springframework.security.authentication.UsernamePasswordAuthenticationToken @@ -21,7 +18,7 @@ import org.springframework.security.test.context.support.WithSecurityContextFact @WithSecurityContext(factory = WithMockCustomUserSecurityContextFactory::class, setupBefore = TestExecutionEvent.TEST_EXECUTION) annotation class WithMockCustomUser( val email: String = "user@example.org", - val roles: Array = [ROLE_FILE_DOWNLOAD, ROLE_PAGE_STREAMING, ROLE_KOBO_SYNC], + val roles: Array = ["PAGE_STREAMING", "FILE_DOWNLOAD", "KOBO_SYNC"], val sharedAllLibraries: Boolean = true, val sharedLibraries: Array = [], val id: String = "0", @@ -41,12 +38,9 @@ class WithMockCustomUserSecurityContextFactory : WithSecurityContextFactory @@ -784,7 +783,7 @@ class SeriesControllerTest( """{"language":"japanese"}""", ], ) - @WithMockCustomUser(roles = [ROLE_ADMIN]) + @WithMockCustomUser(roles = ["ADMIN"]) fun `given invalid json when updating metadata then raise validation error`(jsonString: String) { mockMvc .patch("/api/v1/series/1/metadata") { @@ -796,7 +795,7 @@ class SeriesControllerTest( } @Test - @WithMockCustomUser(roles = [ROLE_ADMIN]) + @WithMockCustomUser(roles = ["ADMIN"]) fun `given valid json when updating metadata then fields are updated`() { val createdSeries = makeSeries(name = "series", libraryId = library.id).let { series -> @@ -872,7 +871,7 @@ class SeriesControllerTest( } @Test - @WithMockCustomUser(roles = [ROLE_ADMIN]) + @WithMockCustomUser(roles = ["ADMIN"]) fun `given json with null fields when updating metadata then fields with null are unset`() { val createdSeries = makeSeries(name = "series", libraryId = library.id).let { series -> diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/SettingsControllerTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/SettingsControllerTest.kt index a89281551..3dec331ff 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/SettingsControllerTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/SettingsControllerTest.kt @@ -1,8 +1,6 @@ package org.gotson.komga.interfaces.api.rest import org.assertj.core.api.Assertions.assertThat -import org.gotson.komga.domain.model.ROLE_ADMIN -import org.gotson.komga.domain.model.ROLE_USER import org.gotson.komga.domain.model.ThumbnailSize import org.gotson.komga.infrastructure.configuration.KomgaSettingsProvider import org.junit.jupiter.api.Nested @@ -38,7 +36,7 @@ class SettingsControllerTest( } @Test - @WithMockCustomUser(roles = [ROLE_USER]) + @WithMockCustomUser fun `given restricted user when retrieving settings then returns forbidden`() { mockMvc .get("/api/v1/settings") @@ -49,7 +47,7 @@ class SettingsControllerTest( } @Test - @WithMockCustomUser(roles = [ROLE_ADMIN]) + @WithMockCustomUser(roles = ["ADMIN"]) fun `given admin user when retrieving settings then settings are returned`() { komgaSettingsProvider.deleteEmptyCollections = true komgaSettingsProvider.deleteEmptyReadLists = false @@ -78,7 +76,7 @@ class SettingsControllerTest( } @Test - @WithMockCustomUser(roles = [ROLE_ADMIN]) + @WithMockCustomUser(roles = ["ADMIN"]) fun `given admin user when updating settings then settings are updated`() { komgaSettingsProvider.deleteEmptyCollections = true komgaSettingsProvider.deleteEmptyReadLists = true @@ -123,7 +121,7 @@ class SettingsControllerTest( } @Test - @WithMockCustomUser(roles = [ROLE_ADMIN]) + @WithMockCustomUser(roles = ["ADMIN"]) fun `given admin user when deleting settings then deletable settings are deleted`() { komgaSettingsProvider.deleteEmptyCollections = true komgaSettingsProvider.deleteEmptyReadLists = true @@ -168,7 +166,7 @@ class SettingsControllerTest( } @ParameterizedTest - @WithMockCustomUser(roles = [ROLE_ADMIN]) + @WithMockCustomUser(roles = ["ADMIN"]) @ValueSource( strings = [ //language=JSON diff --git a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/UserControllerTest.kt b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/UserControllerTest.kt index f08fe56d8..91237f739 100644 --- a/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/UserControllerTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/interfaces/api/rest/UserControllerTest.kt @@ -5,10 +5,7 @@ import org.gotson.komga.domain.model.AgeRestriction import org.gotson.komga.domain.model.AllowExclude import org.gotson.komga.domain.model.ContentRestrictions import org.gotson.komga.domain.model.KomgaUser -import org.gotson.komga.domain.model.ROLE_ADMIN -import org.gotson.komga.domain.model.ROLE_FILE_DOWNLOAD -import org.gotson.komga.domain.model.ROLE_KOBO_SYNC -import org.gotson.komga.domain.model.ROLE_PAGE_STREAMING +import org.gotson.komga.domain.model.UserRoles import org.gotson.komga.domain.model.makeLibrary import org.gotson.komga.domain.persistence.KomgaUserRepository import org.gotson.komga.domain.persistence.LibraryRepository @@ -45,7 +42,7 @@ class UserControllerTest( @Autowired private lateinit var userLifecycle: KomgaUserLifecycle - private val admin = KomgaUser("admin@example.org", "", true, id = "admin") + private val admin = KomgaUser("admin@example.org", "", id = "admin") @BeforeAll fun setup() { @@ -74,7 +71,7 @@ class UserControllerTest( @ParameterizedTest @ValueSource(strings = ["user", "user@domain"]) - @WithMockCustomUser(roles = [ROLE_ADMIN]) + @WithMockCustomUser(roles = ["ADMIN"]) fun `when creating a user with invalid email then returns bad request`(email: String) { // language=JSON val jsonString = """{"email":"$email","password":"password"}""" @@ -91,16 +88,16 @@ class UserControllerTest( @Nested inner class Update { @Test - @WithMockCustomUser(id = "admin", roles = [ROLE_ADMIN]) + @WithMockCustomUser(id = "admin", roles = ["ADMIN"]) fun `given user without roles when updating roles then roles are updated`() { - val user = KomgaUser("user@example.org", "", false, id = "user", roleFileDownload = false, rolePageStreaming = false) + val user = KomgaUser("user@example.org", "", id = "user") userLifecycle.createUser(user) // language=JSON val jsonString = """ { - "roles": ["$ROLE_FILE_DOWNLOAD","$ROLE_PAGE_STREAMING","$ROLE_KOBO_SYNC"] + "roles": ["${UserRoles.FILE_DOWNLOAD.name}","${UserRoles.PAGE_STREAMING.name}","${UserRoles.KOBO_SYNC.name}"] } """.trimIndent() @@ -114,17 +111,14 @@ class UserControllerTest( with(userRepository.findByIdOrNull(user.id)) { assertThat(this).isNotNull - assertThat(this!!.roleFileDownload).isTrue - assertThat(this.rolePageStreaming).isTrue - assertThat(this.roleKoboSync).isTrue - assertThat(this.roleAdmin).isFalse + assertThat(this!!.roles).containsExactlyInAnyOrder(UserRoles.KOBO_SYNC, UserRoles.PAGE_STREAMING, UserRoles.FILE_DOWNLOAD) } } @Test - @WithMockCustomUser(id = "admin", roles = [ROLE_ADMIN]) + @WithMockCustomUser(id = "admin", roles = ["ADMIN"]) fun `given user with roles when updating roles then roles are updated`() { - val user = KomgaUser("user@example.org", "", true, id = "user", roleFileDownload = true, rolePageStreaming = true) + val user = KomgaUser("user@example.org", "", id = "user") userLifecycle.createUser(user) // language=JSON @@ -145,16 +139,14 @@ class UserControllerTest( with(userRepository.findByIdOrNull(user.id)) { assertThat(this).isNotNull - assertThat(this!!.roleFileDownload).isFalse - assertThat(this.rolePageStreaming).isFalse - assertThat(this.roleAdmin).isFalse + assertThat(this!!.roles).isEmpty() } } @Test - @WithMockCustomUser(id = "admin", roles = [ROLE_ADMIN]) + @WithMockCustomUser(id = "admin", roles = ["ADMIN"]) fun `given user with library restrictions when updating available libraries then they are updated`() { - val user = KomgaUser("user@example.org", "", false, id = "user", sharedAllLibraries = false, sharedLibrariesIds = setOf("1")) + val user = KomgaUser("user@example.org", "", sharedLibrariesIds = setOf("1"), sharedAllLibraries = false, id = "user") userLifecycle.createUser(user) // language=JSON @@ -184,9 +176,9 @@ class UserControllerTest( } @Test - @WithMockCustomUser(id = "admin", roles = [ROLE_ADMIN]) + @WithMockCustomUser(id = "admin", roles = ["ADMIN"]) fun `given user without library restrictions when restricting libraries then they restrictions are updated`() { - val user = KomgaUser("user@example.org", "", false, id = "user", sharedAllLibraries = true) + val user = KomgaUser("user@example.org", "", sharedAllLibraries = true, id = "user") userLifecycle.createUser(user) // language=JSON @@ -216,9 +208,9 @@ class UserControllerTest( } @Test - @WithMockCustomUser(id = "admin", roles = [ROLE_ADMIN]) + @WithMockCustomUser(id = "admin", roles = ["ADMIN"]) fun `given user with library restrictions when removing restrictions then the restrictions are updated`() { - val user = KomgaUser("user@example.org", "", false, id = "user", sharedAllLibraries = false, sharedLibrariesIds = setOf("2")) + val user = KomgaUser("user@example.org", "", sharedLibrariesIds = setOf("2"), sharedAllLibraries = false, id = "user") userLifecycle.createUser(user) // language=JSON @@ -248,9 +240,9 @@ class UserControllerTest( } @Test - @WithMockCustomUser(id = "admin", roles = [ROLE_ADMIN]) + @WithMockCustomUser(id = "admin", roles = ["ADMIN"]) fun `given user without labels restrictions when adding restrictions then restrictions are updated`() { - val user = KomgaUser("user@example.org", "", false, id = "user") + val user = KomgaUser("user@example.org", "", id = "user") userLifecycle.createUser(user) // language=JSON @@ -278,19 +270,18 @@ class UserControllerTest( } @Test - @WithMockCustomUser(id = "admin", roles = [ROLE_ADMIN]) + @WithMockCustomUser(id = "admin", roles = ["ADMIN"]) fun `given user with labels restrictions when removing restrictions then restrictions are updated`() { val user = KomgaUser( "user@example.org", "", - false, - id = "user", restrictions = ContentRestrictions( labelsAllow = setOf("kids", "cute"), labelsExclude = setOf("adult"), ), + id = "user", ) userLifecycle.createUser(user) @@ -319,9 +310,9 @@ class UserControllerTest( } @Test - @WithMockCustomUser(id = "admin", roles = [ROLE_ADMIN]) + @WithMockCustomUser(id = "admin", roles = ["ADMIN"]) fun `given user without age restriction when adding restrictions then restrictions are updated`() { - val user = KomgaUser("user@example.org", "", false, id = "user") + val user = KomgaUser("user@example.org", "", id = "user") userLifecycle.createUser(user) // language=JSON @@ -352,9 +343,9 @@ class UserControllerTest( } @Test - @WithMockCustomUser(id = "admin", roles = [ROLE_ADMIN]) + @WithMockCustomUser(id = "admin", roles = ["ADMIN"]) fun `given user without age restriction when adding incorrect restrictions then bad request`() { - val user = KomgaUser("user@example.org", "", false, id = "user") + val user = KomgaUser("user@example.org", "", id = "user") userLifecycle.createUser(user) // language=JSON @@ -378,18 +369,17 @@ class UserControllerTest( } @Test - @WithMockCustomUser(id = "admin", roles = [ROLE_ADMIN]) + @WithMockCustomUser(id = "admin", roles = ["ADMIN"]) fun `given user with age restriction when removing restriction then restrictions are updated`() { val user = KomgaUser( "user@example.org", "", - false, - id = "user", restrictions = ContentRestrictions( ageRestriction = AgeRestriction(12, AllowExclude.ALLOW_ONLY), ), + id = "user", ) userLifecycle.createUser(user) @@ -416,18 +406,17 @@ class UserControllerTest( } @Test - @WithMockCustomUser(id = "admin", roles = [ROLE_ADMIN]) + @WithMockCustomUser(id = "admin", roles = ["ADMIN"]) fun `given user with age restriction when changing restriction then restrictions are updated`() { val user = KomgaUser( "user@example.org", "", - false, - id = "user", restrictions = ContentRestrictions( ageRestriction = AgeRestriction(12, AllowExclude.ALLOW_ONLY), ), + id = "user", ) userLifecycle.createUser(user)