diff --git a/app/src/main/frontend/components/general/modals/EditGameMetadataModal.tsx b/app/src/main/frontend/components/general/modals/EditGameMetadataModal.tsx
index b9eddd8..9cd774d 100644
--- a/app/src/main/frontend/components/general/modals/EditGameMetadataModal.tsx
+++ b/app/src/main/frontend/components/general/modals/EditGameMetadataModal.tsx
@@ -87,6 +87,8 @@ export default function EditGameMetadataModal({game, isOpen, onOpenChange}: Edit
+
diff --git a/app/src/main/frontend/routes.tsx b/app/src/main/frontend/routes.tsx
index bc0cc12..a57c23c 100644
--- a/app/src/main/frontend/routes.tsx
+++ b/app/src/main/frontend/routes.tsx
@@ -23,6 +23,7 @@ import SearchView from "Frontend/views/SearchView";
import RecentlyAddedView from "Frontend/views/RecentlyAddedView";
import LibraryView from "Frontend/views/LibraryView";
import {RouterConfigurationBuilder} from "@vaadin/hilla-file-router/runtime.js";
+import {ConfigEndpoint} from "Frontend/generated/endpoints";
export const {router, routes} = new RouterConfigurationBuilder()
.withReactRoutes([
@@ -32,7 +33,7 @@ export const {router, routes} = new RouterConfigurationBuilder()
children: [
{
element:
,
- handle: {requiresLogin: true},
+ handle: {requiresLogin: !ConfigEndpoint.isPublicAccessEnabled()},
children: [
{
index: true, element:
@@ -64,6 +65,7 @@ export const {router, routes} = new RouterConfigurationBuilder()
{
path: 'administration',
element:
,
+ handle: {requiresLogin: true},
children: [
{
path: 'libraries',
diff --git a/app/src/main/frontend/views/MainLayout.tsx b/app/src/main/frontend/views/MainLayout.tsx
index 5c9e8cd..516f28d 100644
--- a/app/src/main/frontend/views/MainLayout.tsx
+++ b/app/src/main/frontend/views/MainLayout.tsx
@@ -6,7 +6,7 @@ import GameyfinLogo from "Frontend/components/theming/GameyfinLogo";
import * as PackageJson from "../../../../package.json";
import {Outlet, useLocation, useNavigate} from "react-router";
import {useAuth} from "Frontend/util/auth";
-import {ArrowLeft, DiceSix, Heart, House, ListMagnifyingGlass} from "@phosphor-icons/react";
+import {ArrowLeft, DiceSix, Heart, House, ListMagnifyingGlass, SignIn} from "@phosphor-icons/react";
import Confetti, {ConfettiProps} from "react-confetti-boom";
import {useTheme} from "next-themes";
import {UserPreferenceService} from "Frontend/util/user-preference-service";
@@ -103,9 +103,24 @@ export default function MainLayout() {
}
-
-
-
+ {auth.state.user &&
+
+
+
+ }
+ {!auth.state.user &&
+
+
+
+
+
+ }
diff --git a/app/src/main/frontend/views/SearchView.tsx b/app/src/main/frontend/views/SearchView.tsx
index 261141b..a7c7074 100644
--- a/app/src/main/frontend/views/SearchView.tsx
+++ b/app/src/main/frontend/views/SearchView.tsx
@@ -18,6 +18,7 @@ export default function SearchView() {
const knownThemes = useSnapshot(gameState).knownThemes;
const knownFeatures = useSnapshot(gameState).knownFeatures;
const knownPerspectives = useSnapshot(gameState).knownPerspectives;
+ const knownKeywords = useSnapshot(gameState).knownKeywords;
const libraries = useSnapshot(libraryState).libraries as LibraryDto[];
const [searchParams, setSearchParams] = useSearchParams();
@@ -31,6 +32,7 @@ export default function SearchView() {
const [selectedThemes, setSelectedThemes] = useState
>(new Set());
const [selectedFeatures, setSelectedFeatures] = useState>(new Set());
const [selectedPerspectives, setSelectedPerspectives] = useState>(new Set());
+ const [selectedKeywords, setSelectedKeywords] = useState>(new Set());
// Load initial filter values from URL parameters on component mount
useEffect(() => {
@@ -42,6 +44,7 @@ export default function SearchView() {
const themes = searchParams.getAll("theme");
const features = searchParams.getAll("feature");
const perspectives = searchParams.getAll("perspective");
+ const keywords = searchParams.getAll("keyword");
setSearchTerm(term);
setSelectedLibraries(new Set(libs));
@@ -50,6 +53,7 @@ export default function SearchView() {
setSelectedThemes(new Set(themes));
setSelectedFeatures(new Set(features));
setSelectedPerspectives(new Set(perspectives));
+ setSelectedKeywords(new Set(keywords));
setInitialLoadComplete(true);
}, []);
@@ -102,15 +106,21 @@ export default function SearchView() {
});
}
+ if (selectedKeywords.size > 0) {
+ selectedKeywords.forEach(keyword => {
+ newParams.append("keyword", keyword);
+ });
+ }
+
setSearchParams(newParams, {replace: true});
}, [searchTerm, selectedLibraries, selectedDevelopers, selectedGenres,
- selectedThemes, selectedFeatures, selectedPerspectives]);
+ selectedThemes, selectedFeatures, selectedPerspectives, selectedKeywords]);
const filteredGames = useMemo(() => filterGames(), [
games, searchTerm,
selectedLibraries, selectedDevelopers,
selectedGenres, selectedThemes,
- selectedFeatures, selectedPerspectives
+ selectedFeatures, selectedPerspectives, selectedKeywords
]);
function filterGames(): GameDto[] {
@@ -164,6 +174,13 @@ export default function SearchView() {
);
}
+ // Apply keyword filter
+ if (selectedKeywords.size > 0) {
+ filtered = filtered.filter(game =>
+ game.keywords?.some(keyword => selectedKeywords.has(keyword))
+ );
+ }
+
return filtered;
}
@@ -183,10 +200,17 @@ export default function SearchView() {
onChange={(event) => setSearchTerm(event.target.value)}
onClear={() => setSearchTerm("")}
/>
-
+
diff --git a/app/src/main/kotlin/org/gameyfin/app/config/ConfigEndpoint.kt b/app/src/main/kotlin/org/gameyfin/app/config/ConfigEndpoint.kt
index 16d70c1..77281ba 100644
--- a/app/src/main/kotlin/org/gameyfin/app/config/ConfigEndpoint.kt
+++ b/app/src/main/kotlin/org/gameyfin/app/config/ConfigEndpoint.kt
@@ -1,5 +1,6 @@
package org.gameyfin.app.config
+import com.vaadin.flow.server.auth.AnonymousAllowed
import com.vaadin.hilla.Endpoint
import io.github.oshai.kotlinlogging.KotlinLogging
import jakarta.annotation.security.PermitAll
@@ -7,6 +8,7 @@ import jakarta.annotation.security.RolesAllowed
import org.gameyfin.app.config.dto.ConfigEntryDto
import org.gameyfin.app.config.dto.ConfigUpdateDto
import org.gameyfin.app.core.Role
+import org.gameyfin.app.core.annotations.DynamicPublicAccess
import org.gameyfin.app.users.UserService
import org.gameyfin.app.users.util.isAdmin
import reactor.core.publisher.Flux
@@ -36,9 +38,16 @@ class ConfigEndpoint(
/** Specific read-only endpoint for all users **/
- @PermitAll
- fun isSsoEnabled(): Boolean? = configService.get(ConfigProperties.SSO.OIDC.Enabled)
+ @DynamicPublicAccess
+ @AnonymousAllowed
+ fun isSsoEnabled(): Boolean = configService.get(ConfigProperties.SSO.OIDC.Enabled) == true
+
+ @DynamicPublicAccess
+ @AnonymousAllowed
+ fun getSsoLogoutUrl(): String? = configService.get(ConfigProperties.SSO.OIDC.LogoutUrl)
+
+ @DynamicPublicAccess
+ @AnonymousAllowed
+ fun isPublicAccessEnabled(): Boolean = configService.get(ConfigProperties.Libraries.AllowPublicAccess) == true
- @PermitAll
- fun getLogoutUrl(): String? = configService.get(ConfigProperties.SSO.OIDC.LogoutUrl)
}
diff --git a/app/src/main/kotlin/org/gameyfin/app/config/ConfigProperties.kt b/app/src/main/kotlin/org/gameyfin/app/config/ConfigProperties.kt
index b58bba4..3f90350 100644
--- a/app/src/main/kotlin/org/gameyfin/app/config/ConfigProperties.kt
+++ b/app/src/main/kotlin/org/gameyfin/app/config/ConfigProperties.kt
@@ -17,7 +17,7 @@ sealed class ConfigProperties(
data object AllowPublicAccess : ConfigProperties(
Boolean::class,
"library.allow-public-access",
- "Allow access to game libraries without login (coming soon™)",
+ "Allow access to Gameyfin without login",
false
)
diff --git a/app/src/main/kotlin/org/gameyfin/app/core/annotations/DynamicAccessInterceptor.kt b/app/src/main/kotlin/org/gameyfin/app/core/annotations/DynamicAccessInterceptor.kt
index 8595a18..8dc4e05 100644
--- a/app/src/main/kotlin/org/gameyfin/app/core/annotations/DynamicAccessInterceptor.kt
+++ b/app/src/main/kotlin/org/gameyfin/app/core/annotations/DynamicAccessInterceptor.kt
@@ -1,16 +1,16 @@
package org.gameyfin.app.core.annotations
-import org.gameyfin.app.config.ConfigService
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import org.gameyfin.app.config.ConfigProperties
+import org.gameyfin.app.config.ConfigService
import org.springframework.stereotype.Component
import org.springframework.web.method.HandlerMethod
import org.springframework.web.servlet.HandlerInterceptor
@Component
class DynamicAccessInterceptor(
- private val configService: ConfigService
+ private val config: ConfigService
) : HandlerInterceptor {
override fun preHandle(
@@ -20,15 +20,16 @@ class DynamicAccessInterceptor(
): Boolean {
val handlerMethod = (handler as? HandlerMethod) ?: return true
val method = handlerMethod.method
+ val clazz = handlerMethod.beanType
- // Check if method is annotated with @DynamicPublicAccess
- if (method.isAnnotationPresent(DynamicPublicAccess::class.java)) {
- // Check if user is authenticated or public access is enabled
- if (request.userPrincipal != null || configService.get(ConfigProperties.Libraries.AllowPublicAccess) == true) {
+ val hasDynamicPublicAccess =
+ method.isAnnotationPresent(DynamicPublicAccess::class.java) ||
+ clazz.isAnnotationPresent(DynamicPublicAccess::class.java)
+
+ if (hasDynamicPublicAccess) {
+ if (request.userPrincipal != null || config.get(ConfigProperties.Libraries.AllowPublicAccess) == true) {
return true
}
-
- // Deny access if user is not logged in and public access is disabled
response.status = HttpServletResponse.SC_UNAUTHORIZED
return false
}
diff --git a/app/src/main/kotlin/org/gameyfin/app/core/download/DownloadEndpoint.kt b/app/src/main/kotlin/org/gameyfin/app/core/download/DownloadEndpoint.kt
index b5f604d..9c788a4 100644
--- a/app/src/main/kotlin/org/gameyfin/app/core/download/DownloadEndpoint.kt
+++ b/app/src/main/kotlin/org/gameyfin/app/core/download/DownloadEndpoint.kt
@@ -1,5 +1,6 @@
package org.gameyfin.app.core.download
+import com.vaadin.flow.server.auth.AnonymousAllowed
import org.gameyfin.app.core.annotations.DynamicPublicAccess
import org.gameyfin.app.games.GameService
import org.gameyfin.pluginapi.download.FileDownload
@@ -11,6 +12,7 @@ import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBo
@RestController
@RequestMapping("/download")
@DynamicPublicAccess
+@AnonymousAllowed
class DownloadEndpoint(
private val downloadService: DownloadService,
private val gameService: GameService
diff --git a/app/src/main/kotlin/org/gameyfin/app/core/download/DownloadProviderEndpoint.kt b/app/src/main/kotlin/org/gameyfin/app/core/download/DownloadProviderEndpoint.kt
index 933b1f8..e9d3684 100644
--- a/app/src/main/kotlin/org/gameyfin/app/core/download/DownloadProviderEndpoint.kt
+++ b/app/src/main/kotlin/org/gameyfin/app/core/download/DownloadProviderEndpoint.kt
@@ -1,10 +1,12 @@
package org.gameyfin.app.core.download
+import com.vaadin.flow.server.auth.AnonymousAllowed
import com.vaadin.hilla.Endpoint
-import jakarta.annotation.security.PermitAll
+import org.gameyfin.app.core.annotations.DynamicPublicAccess
@Endpoint
-@PermitAll
+@DynamicPublicAccess
+@AnonymousAllowed
class DownloadProviderEndpoint(
private val downloadService: DownloadService
) {
diff --git a/app/src/main/kotlin/org/gameyfin/app/core/plugins/PluginService.kt b/app/src/main/kotlin/org/gameyfin/app/core/plugins/PluginService.kt
index bd15f64..c85b446 100644
--- a/app/src/main/kotlin/org/gameyfin/app/core/plugins/PluginService.kt
+++ b/app/src/main/kotlin/org/gameyfin/app/core/plugins/PluginService.kt
@@ -109,8 +109,8 @@ class PluginService(
label = meta.label,
description = meta.description,
default = meta.default,
- isSecret = meta.isSecret,
- isRequired = meta.isRequired,
+ secret = meta.isSecret,
+ required = meta.isRequired,
allowedValues = meta.allowedValues?.map { it.toString() }
)
}
diff --git a/app/src/main/kotlin/org/gameyfin/app/core/plugins/dto/PluginConfigMetadataDto.kt b/app/src/main/kotlin/org/gameyfin/app/core/plugins/dto/PluginConfigMetadataDto.kt
index 5e7b1c6..d26d917 100644
--- a/app/src/main/kotlin/org/gameyfin/app/core/plugins/dto/PluginConfigMetadataDto.kt
+++ b/app/src/main/kotlin/org/gameyfin/app/core/plugins/dto/PluginConfigMetadataDto.kt
@@ -10,7 +10,7 @@ class PluginConfigMetadataDto(
val label: String,
val description: String,
val default: Serializable?,
- val isSecret: Boolean,
- val isRequired: Boolean,
+ val secret: Boolean,
+ val required: Boolean,
val allowedValues: List?
)
\ No newline at end of file
diff --git a/app/src/main/kotlin/org/gameyfin/app/core/security/DynamicPublicAccessAuthorizationManager.kt b/app/src/main/kotlin/org/gameyfin/app/core/security/DynamicPublicAccessAuthorizationManager.kt
new file mode 100644
index 0000000..689f87d
--- /dev/null
+++ b/app/src/main/kotlin/org/gameyfin/app/core/security/DynamicPublicAccessAuthorizationManager.kt
@@ -0,0 +1,23 @@
+package org.gameyfin.app.core.security
+
+import org.gameyfin.app.config.ConfigProperties
+import org.gameyfin.app.config.ConfigService
+import org.springframework.security.authorization.AuthorizationDecision
+import org.springframework.security.authorization.AuthorizationManager
+import org.springframework.security.core.Authentication
+import org.springframework.security.web.access.intercept.RequestAuthorizationContext
+import java.util.function.Supplier
+
+class DynamicPublicAccessAuthorizationManager(
+ private val config: ConfigService
+) : AuthorizationManager {
+
+ @Deprecated("Deprecated in superclass")
+ override fun check(
+ authentication: Supplier?,
+ `object`: RequestAuthorizationContext?
+ ): AuthorizationDecision? {
+ val allow = config.get(ConfigProperties.Libraries.AllowPublicAccess) == true
+ return AuthorizationDecision(allow)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/org/gameyfin/app/core/security/SecurityConfig.kt b/app/src/main/kotlin/org/gameyfin/app/core/security/SecurityConfig.kt
index 63885de..99f59bd 100644
--- a/app/src/main/kotlin/org/gameyfin/app/core/security/SecurityConfig.kt
+++ b/app/src/main/kotlin/org/gameyfin/app/core/security/SecurityConfig.kt
@@ -39,11 +39,18 @@ class SecurityConfig(
// Configure your static resources with public access before calling super.configure(HttpSecurity) as it adds final anyRequest matcher
http.authorizeHttpRequests { auth: AuthorizeHttpRequestsConfigurer.AuthorizationManagerRequestMatcherRegistry ->
- auth.requestMatchers("/setup").permitAll()
+ auth.requestMatchers("/login").permitAll()
+ .requestMatchers("/setup").permitAll()
.requestMatchers("/reset-password").permitAll()
.requestMatchers("/accept-invitation").permitAll()
.requestMatchers("/public/**").permitAll()
.requestMatchers("/images/**").permitAll()
+
+ // Dynamic public access for certain endpoints
+ auth.requestMatchers("/game/**").access(DynamicPublicAccessAuthorizationManager(config))
+ .requestMatchers("/library/**").access(DynamicPublicAccessAuthorizationManager(config))
+ .requestMatchers("/search/**").access(DynamicPublicAccessAuthorizationManager(config))
+ .requestMatchers("/download/**").access(DynamicPublicAccessAuthorizationManager(config))
}
http.sessionManagement { sessionManagement ->
diff --git a/app/src/main/kotlin/org/gameyfin/app/games/GameEndpoint.kt b/app/src/main/kotlin/org/gameyfin/app/games/GameEndpoint.kt
index 8901878..ec3ce56 100644
--- a/app/src/main/kotlin/org/gameyfin/app/games/GameEndpoint.kt
+++ b/app/src/main/kotlin/org/gameyfin/app/games/GameEndpoint.kt
@@ -1,20 +1,18 @@
package org.gameyfin.app.games
+import com.vaadin.flow.server.auth.AnonymousAllowed
import com.vaadin.hilla.Endpoint
-import jakarta.annotation.security.PermitAll
import jakarta.annotation.security.RolesAllowed
import org.gameyfin.app.core.Role
-import org.gameyfin.app.games.dto.GameDto
-import org.gameyfin.app.games.dto.GameEvent
-import org.gameyfin.app.games.dto.GameSearchResultDto
-import org.gameyfin.app.games.dto.GameUpdateDto
-import org.gameyfin.app.games.dto.OriginalIdDto
+import org.gameyfin.app.core.annotations.DynamicPublicAccess
+import org.gameyfin.app.games.dto.*
import org.gameyfin.app.libraries.LibraryService
import reactor.core.publisher.Flux
import java.nio.file.Path
@Endpoint
-@PermitAll
+@DynamicPublicAccess
+@AnonymousAllowed
class GameEndpoint(
private val gameService: GameService,
private val libraryService: LibraryService
diff --git a/app/src/main/kotlin/org/gameyfin/app/libraries/LibraryEndpoint.kt b/app/src/main/kotlin/org/gameyfin/app/libraries/LibraryEndpoint.kt
index 677906c..0e3476b 100644
--- a/app/src/main/kotlin/org/gameyfin/app/libraries/LibraryEndpoint.kt
+++ b/app/src/main/kotlin/org/gameyfin/app/libraries/LibraryEndpoint.kt
@@ -1,9 +1,10 @@
package org.gameyfin.app.libraries
+import com.vaadin.flow.server.auth.AnonymousAllowed
import com.vaadin.hilla.Endpoint
-import jakarta.annotation.security.PermitAll
import jakarta.annotation.security.RolesAllowed
import org.gameyfin.app.core.Role
+import org.gameyfin.app.core.annotations.DynamicPublicAccess
import org.gameyfin.app.libraries.dto.LibraryDto
import org.gameyfin.app.libraries.dto.LibraryEvent
import org.gameyfin.app.libraries.dto.LibraryScanProgress
@@ -14,7 +15,8 @@ import org.gameyfin.app.users.util.isAdmin
import reactor.core.publisher.Flux
@Endpoint
-@PermitAll
+@DynamicPublicAccess
+@AnonymousAllowed
class LibraryEndpoint(
private val libraryService: LibraryService,
private val userService: UserService,
diff --git a/app/src/main/kotlin/org/gameyfin/app/media/ImageEndpoint.kt b/app/src/main/kotlin/org/gameyfin/app/media/ImageEndpoint.kt
index 020cbb8..0d8b74b 100644
--- a/app/src/main/kotlin/org/gameyfin/app/media/ImageEndpoint.kt
+++ b/app/src/main/kotlin/org/gameyfin/app/media/ImageEndpoint.kt
@@ -1,13 +1,15 @@
package org.gameyfin.app.media
-import org.gameyfin.app.core.plugins.PluginService
-import org.gameyfin.app.games.entities.Image
-import org.gameyfin.app.games.entities.ImageType
-import org.gameyfin.app.users.UserService
+import com.vaadin.flow.server.auth.AnonymousAllowed
+import jakarta.annotation.security.PermitAll
import jakarta.annotation.security.RolesAllowed
import org.gameyfin.app.core.Role
import org.gameyfin.app.core.Utils
import org.gameyfin.app.core.annotations.DynamicPublicAccess
+import org.gameyfin.app.core.plugins.PluginService
+import org.gameyfin.app.games.entities.Image
+import org.gameyfin.app.games.entities.ImageType
+import org.gameyfin.app.users.UserService
import org.springframework.core.io.ByteArrayResource
import org.springframework.core.io.InputStreamResource
import org.springframework.http.HttpHeaders
@@ -18,9 +20,10 @@ import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.web.bind.annotation.*
import org.springframework.web.multipart.MultipartFile
-@DynamicPublicAccess
@RestController
@RequestMapping("/images")
+@DynamicPublicAccess
+@AnonymousAllowed
class ImageEndpoint(
private val imageService: ImageService,
private val userService: UserService,
@@ -36,6 +39,7 @@ class ImageEndpoint(
fun getCover(@PathVariable("id") id: Long): ResponseEntity? {
return getImageContent(id)
}
+
@GetMapping("/header/{id}")
fun getHeader(@PathVariable("id") id: Long): ResponseEntity? {
return getImageContent(id)
@@ -54,6 +58,7 @@ class ImageEndpoint(
return getImageContent(avatar.id!!)
}
+ @PermitAll
@PostMapping("/avatar/upload")
fun uploadAvatar(@RequestParam("file") file: MultipartFile) {
val auth: Authentication = SecurityContextHolder.getContext().authentication
@@ -68,6 +73,7 @@ class ImageEndpoint(
userService.updateAvatar(auth.name, image)
}
+ @PermitAll
@PostMapping("/avatar/delete")
fun deleteAvatar() {
val auth: Authentication = SecurityContextHolder.getContext().authentication
diff --git a/app/src/main/kotlin/org/gameyfin/app/system/SystemEndpoint.kt b/app/src/main/kotlin/org/gameyfin/app/system/SystemEndpoint.kt
index 2e3e565..b2da29a 100644
--- a/app/src/main/kotlin/org/gameyfin/app/system/SystemEndpoint.kt
+++ b/app/src/main/kotlin/org/gameyfin/app/system/SystemEndpoint.kt
@@ -5,11 +5,10 @@ import jakarta.annotation.security.RolesAllowed
import org.gameyfin.app.core.Role
@Endpoint
+@RolesAllowed(Role.Names.ADMIN)
class SystemEndpoint(
private val systemService: SystemService
) {
-
- @RolesAllowed(Role.Names.ADMIN)
fun restart() {
systemService.restart()
}
diff --git a/app/src/main/kotlin/org/gameyfin/app/users/RoleService.kt b/app/src/main/kotlin/org/gameyfin/app/users/RoleService.kt
index 90dedc6..d5feeef 100644
--- a/app/src/main/kotlin/org/gameyfin/app/users/RoleService.kt
+++ b/app/src/main/kotlin/org/gameyfin/app/users/RoleService.kt
@@ -1,8 +1,8 @@
package org.gameyfin.app.users
-import org.gameyfin.app.users.persistence.UserRepository
import org.gameyfin.app.core.Role
import org.gameyfin.app.users.entities.User
+import org.gameyfin.app.users.persistence.UserRepository
import org.springframework.security.core.Authentication
import org.springframework.security.core.GrantedAuthority
import org.springframework.security.core.authority.SimpleGrantedAuthority
@@ -66,7 +66,7 @@ class RoleService(
.filterIsInstance()
.flatMap { oidcUserAuthority ->
val userInfo = oidcUserAuthority.userInfo
- val roles = userInfo.getClaim>("roles")
+ val roles = userInfo.getClaim>("roles") ?: return@flatMap emptySequence()
roles.asSequence().mapNotNull {
if (it.startsWith(SSO_ROLE_PREFIX)) SimpleGrantedAuthority(
it.replace(SSO_ROLE_PREFIX, INTERNAL_ROLE_PREFIX)
diff --git a/app/src/main/kotlin/org/gameyfin/app/users/UserEndpoint.kt b/app/src/main/kotlin/org/gameyfin/app/users/UserEndpoint.kt
index 7b0411e..f208966 100644
--- a/app/src/main/kotlin/org/gameyfin/app/users/UserEndpoint.kt
+++ b/app/src/main/kotlin/org/gameyfin/app/users/UserEndpoint.kt
@@ -16,11 +16,6 @@ class UserEndpoint(
private val userService: UserService,
private val roleService: RoleService
) {
- @PermitAll
- fun existsByMail(email: String): Boolean {
- return userService.existsByEmail(email)
- }
-
@PermitAll
fun getUserInfo(): UserInfoDto {
return userService.getUserInfo()
@@ -32,6 +27,11 @@ class UserEndpoint(
userService.updateUser(auth.name, updates)
}
+ @RolesAllowed(Role.Names.ADMIN)
+ fun existsByMail(email: String): Boolean {
+ return userService.existsByEmail(email)
+ }
+
@RolesAllowed(Role.Names.ADMIN)
fun getAllUsers(): List {
return userService.getAllUsers()
diff --git a/build.gradle.kts b/build.gradle.kts
index b8f0334..54a8f85 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -6,7 +6,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
import java.nio.file.Files
group = "org.gameyfin"
-version = "2.0.0.beta4"
+version = "2.0.0.beta5"
allprojects {
repositories {
diff --git a/gradle.properties b/gradle.properties
index 0b0d9d6..a6935cc 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,5 +1,7 @@
-# Increase Gradle metaspace size
+# Gradle properties
org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m
+org.gradle.parallel=true
+org.gradle.caching=true
# Plugin versions
kotlinVersion=2.2.0
kspVersion=2.2.0-2.0.2