mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-16 08:15:48 +00:00
Fix #632
This commit is contained in:
@@ -9,7 +9,7 @@ import {
|
|||||||
SharedSelection
|
SharedSelection
|
||||||
} from "@heroui/react";
|
} from "@heroui/react";
|
||||||
import {CaretDown} from "@phosphor-icons/react";
|
import {CaretDown} from "@phosphor-icons/react";
|
||||||
import {UserPreferenceService} from "Frontend/util/user-preference-service";
|
import {useUserPreferenceService} from "Frontend/util/user-preference-service";
|
||||||
|
|
||||||
export interface ComboButtonOption {
|
export interface ComboButtonOption {
|
||||||
label: string;
|
label: string;
|
||||||
@@ -27,11 +27,12 @@ export interface ComboButtonProps {
|
|||||||
export default function ComboButton({options, preferredOptionKey, description}: ComboButtonProps) {
|
export default function ComboButton({options, preferredOptionKey, description}: ComboButtonProps) {
|
||||||
const [selectedOption, setSelectedOption] = useState(new Set([Object.keys(options)[0]]));
|
const [selectedOption, setSelectedOption] = useState(new Set([Object.keys(options)[0]]));
|
||||||
const selectedOptionValue = Array.from(selectedOption)[0];
|
const selectedOptionValue = Array.from(selectedOption)[0];
|
||||||
|
const userPreferenceService = useUserPreferenceService();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!preferredOptionKey) return;
|
if (!preferredOptionKey) return;
|
||||||
|
|
||||||
UserPreferenceService.get(preferredOptionKey).then((key) => {
|
userPreferenceService.get(preferredOptionKey).then((key) => {
|
||||||
if (key && options[key]) {
|
if (key && options[key]) {
|
||||||
setSelectedOption(new Set([key]));
|
setSelectedOption(new Set([key]));
|
||||||
} else {
|
} else {
|
||||||
@@ -44,7 +45,7 @@ export default function ComboButton({options, preferredOptionKey, description}:
|
|||||||
if (!keys.currentKey) return;
|
if (!keys.currentKey) return;
|
||||||
|
|
||||||
if (preferredOptionKey) {
|
if (preferredOptionKey) {
|
||||||
await UserPreferenceService.set(preferredOptionKey, keys.currentKey);
|
await userPreferenceService.set(preferredOptionKey, keys.currentKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
setSelectedOption(new Set([keys.currentKey]));
|
setSelectedOption(new Set([keys.currentKey]));
|
||||||
|
|||||||
@@ -5,13 +5,14 @@ import {themes} from "Frontend/theming/themes";
|
|||||||
import {Theme} from "Frontend/theming/theme";
|
import {Theme} from "Frontend/theming/theme";
|
||||||
import ThemePreview from "Frontend/components/theming/ThemePreview";
|
import ThemePreview from "Frontend/components/theming/ThemePreview";
|
||||||
import {toTitleCase} from "Frontend/util/utils";
|
import {toTitleCase} from "Frontend/util/utils";
|
||||||
import {UserPreferenceService} from "Frontend/util/user-preference-service";
|
import {useUserPreferenceService} from "Frontend/util/user-preference-service";
|
||||||
|
|
||||||
export function ThemeSelector() {
|
export function ThemeSelector() {
|
||||||
|
|
||||||
const {theme, setTheme} = useTheme();
|
const {theme, setTheme} = useTheme();
|
||||||
const [selectedTheme, setSelectedTheme] = useState(theme?.substring(0, theme?.lastIndexOf("-")));
|
const [selectedTheme, setSelectedTheme] = useState(theme?.substring(0, theme?.lastIndexOf("-")));
|
||||||
const [selectedMode, setSelectedMode] = useState<Selection>();
|
const [selectedMode, setSelectedMode] = useState<Selection>();
|
||||||
|
const userPreferenceService = useUserPreferenceService();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!selectedMode)
|
if (!selectedMode)
|
||||||
@@ -24,7 +25,7 @@ export function ThemeSelector() {
|
|||||||
if (selectedMode instanceof Set) {
|
if (selectedMode instanceof Set) {
|
||||||
let theme = `${selectedTheme}-${selectedMode.values().next().value}`;
|
let theme = `${selectedTheme}-${selectedMode.values().next().value}`;
|
||||||
setTheme(theme);
|
setTheme(theme);
|
||||||
UserPreferenceService.set("preferred-theme", theme).catch(console.error);
|
userPreferenceService.set("preferred-theme", theme).catch(console.error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,39 +1,45 @@
|
|||||||
import {UserPreferencesEndpoint} from "Frontend/generated/endpoints";
|
import {UserPreferencesEndpoint} from "Frontend/generated/endpoints";
|
||||||
|
import {useAuth} from "Frontend/util/auth";
|
||||||
|
|
||||||
export class UserPreferenceService {
|
export function useUserPreferenceService() {
|
||||||
static LOCAL_STORAGE_PREFIX = "gameyfin.";
|
const LOCAL_STORAGE_PREFIX = "gameyfin.";
|
||||||
|
const auth = useAuth();
|
||||||
|
|
||||||
|
async function sync(): Promise<void> {
|
||||||
|
if (auth.state.user === undefined) return;
|
||||||
|
|
||||||
static async sync(): Promise<void> {
|
|
||||||
let keys = Object.keys(localStorage);
|
let keys = Object.keys(localStorage);
|
||||||
for (let key of keys) {
|
for (let key of keys) {
|
||||||
if (!key.startsWith(`${this.LOCAL_STORAGE_PREFIX}`)) {
|
if (!key.startsWith(LOCAL_STORAGE_PREFIX)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let value = await UserPreferencesEndpoint.get(key.replace(this.LOCAL_STORAGE_PREFIX, ""));
|
let value = await UserPreferencesEndpoint.get(key.replace(LOCAL_STORAGE_PREFIX, ""));
|
||||||
if (value) {
|
if (value) {
|
||||||
localStorage.setItem(key, value);
|
localStorage.setItem(key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async get(key: string): Promise<string | undefined> {
|
async function get(key: string): Promise<string | undefined> {
|
||||||
let localPreference = localStorage.getItem(`${this.LOCAL_STORAGE_PREFIX}${key}`);
|
let localPreference = localStorage.getItem(`${LOCAL_STORAGE_PREFIX}${key}`);
|
||||||
|
|
||||||
if (localPreference) {
|
if (localPreference) {
|
||||||
return localPreference;
|
return localPreference;
|
||||||
} else {
|
} else {
|
||||||
|
if (auth.state.user === undefined) return undefined;
|
||||||
let syncedPreference = await UserPreferencesEndpoint.get(key);
|
let syncedPreference = await UserPreferencesEndpoint.get(key);
|
||||||
if (syncedPreference) {
|
if (syncedPreference) {
|
||||||
localStorage.setItem(`${this.LOCAL_STORAGE_PREFIX}${key}`, syncedPreference);
|
localStorage.setItem(`${LOCAL_STORAGE_PREFIX}${key}`, syncedPreference);
|
||||||
return syncedPreference;
|
return syncedPreference;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async set(key: string, value: string) {
|
async function set(key: string, value: string): Promise<void> {
|
||||||
|
localStorage.setItem(`${LOCAL_STORAGE_PREFIX}${key}`, value);
|
||||||
|
if (auth.state.user === undefined) return;
|
||||||
await UserPreferencesEndpoint.set(key, value);
|
await UserPreferencesEndpoint.set(key, value);
|
||||||
localStorage.setItem(`${this.LOCAL_STORAGE_PREFIX}${key}`, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {sync, get, set};
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,7 @@ import {useAuth} from "Frontend/util/auth";
|
|||||||
import {ArrowLeft, DiceSix, Heart, House, ListMagnifyingGlass, SignIn} from "@phosphor-icons/react";
|
import {ArrowLeft, DiceSix, Heart, House, ListMagnifyingGlass, SignIn} from "@phosphor-icons/react";
|
||||||
import Confetti, {ConfettiProps} from "react-confetti-boom";
|
import Confetti, {ConfettiProps} from "react-confetti-boom";
|
||||||
import {useTheme} from "next-themes";
|
import {useTheme} from "next-themes";
|
||||||
import {UserPreferenceService} from "Frontend/util/user-preference-service";
|
import {useUserPreferenceService} from "Frontend/util/user-preference-service";
|
||||||
import SearchBar from "Frontend/components/general/SearchBar";
|
import SearchBar from "Frontend/components/general/SearchBar";
|
||||||
import {useSnapshot} from "valtio/react";
|
import {useSnapshot} from "valtio/react";
|
||||||
import {gameState} from "Frontend/state/GameState";
|
import {gameState} from "Frontend/state/GameState";
|
||||||
@@ -20,6 +20,7 @@ export default function MainLayout() {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const auth = useAuth();
|
const auth = useAuth();
|
||||||
|
const userPreferenceService = useUserPreferenceService();
|
||||||
const routeMetadata = useRouteMetadata();
|
const routeMetadata = useRouteMetadata();
|
||||||
const {setTheme} = useTheme();
|
const {setTheme} = useTheme();
|
||||||
const isSearchPage = location.pathname.startsWith("/search");
|
const isSearchPage = location.pathname.startsWith("/search");
|
||||||
@@ -30,11 +31,13 @@ export default function MainLayout() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let newTitle = `Gameyfin - ${routeMetadata?.title}`;
|
let newTitle = `Gameyfin - ${routeMetadata?.title}`;
|
||||||
window.addEventListener('popstate', () => document.title = newTitle);
|
window.addEventListener('popstate', () => document.title = newTitle);
|
||||||
|
}, []);
|
||||||
|
|
||||||
UserPreferenceService.sync()
|
useEffect(() => {
|
||||||
|
userPreferenceService.sync()
|
||||||
.then(() => loadUserTheme().catch(console.error))
|
.then(() => loadUserTheme().catch(console.error))
|
||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
}, []);
|
}, [auth.state.user]);
|
||||||
|
|
||||||
const confettiProps: ConfettiProps = {
|
const confettiProps: ConfettiProps = {
|
||||||
mode: 'boom',
|
mode: 'boom',
|
||||||
@@ -47,7 +50,7 @@ export default function MainLayout() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function loadUserTheme() {
|
async function loadUserTheme() {
|
||||||
let syncedTheme = await UserPreferenceService.get("preferred-theme")
|
let syncedTheme = await userPreferenceService.get("preferred-theme")
|
||||||
if (syncedTheme !== undefined) {
|
if (syncedTheme !== undefined) {
|
||||||
setTheme(syncedTheme);
|
setTheme(syncedTheme);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ class SecurityConfig(
|
|||||||
.requestMatchers("/accept-invitation").permitAll()
|
.requestMatchers("/accept-invitation").permitAll()
|
||||||
.requestMatchers("/public/**").permitAll()
|
.requestMatchers("/public/**").permitAll()
|
||||||
.requestMatchers("/images/**").permitAll()
|
.requestMatchers("/images/**").permitAll()
|
||||||
|
.requestMatchers("/favicon.ico").permitAll()
|
||||||
|
|
||||||
// Dynamic public access for certain endpoints
|
// Dynamic public access for certain endpoints
|
||||||
auth.requestMatchers("/").access(DynamicPublicAccessAuthorizationManager(config))
|
auth.requestMatchers("/").access(DynamicPublicAccessAuthorizationManager(config))
|
||||||
|
|||||||
@@ -26,8 +26,7 @@ class LibraryEndpoint(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getAll() = libraryService.getAll()
|
fun getAll() = libraryService.getAll()
|
||||||
|
|
||||||
|
|
||||||
fun subscribeToScanProgressEvents(): Flux<List<LibraryScanProgress>> {
|
fun subscribeToScanProgressEvents(): Flux<List<LibraryScanProgress>> {
|
||||||
val user = userService.getCurrentUser()
|
val user = userService.getCurrentUser()
|
||||||
return if (user.isAdmin()) LibraryService.subscribeToScanProgressEvents()
|
return if (user.isAdmin()) LibraryService.subscribeToScanProgressEvents()
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.gameyfin.app.users
|
package org.gameyfin.app.users
|
||||||
|
|
||||||
|
import com.vaadin.flow.server.auth.AnonymousAllowed
|
||||||
import com.vaadin.hilla.Endpoint
|
import com.vaadin.hilla.Endpoint
|
||||||
import jakarta.annotation.security.PermitAll
|
import jakarta.annotation.security.PermitAll
|
||||||
import jakarta.annotation.security.RolesAllowed
|
import jakarta.annotation.security.RolesAllowed
|
||||||
@@ -16,8 +17,10 @@ class UserEndpoint(
|
|||||||
private val userService: UserService,
|
private val userService: UserService,
|
||||||
private val roleService: RoleService
|
private val roleService: RoleService
|
||||||
) {
|
) {
|
||||||
@PermitAll
|
@AnonymousAllowed
|
||||||
fun getUserInfo(): UserInfoDto {
|
fun getUserInfo(): UserInfoDto? {
|
||||||
|
val auth = SecurityContextHolder.getContext().authentication
|
||||||
|
if (!auth.isAuthenticated || auth.principal == "anonymousUser") return null
|
||||||
return userService.getUserInfo()
|
return userService.getUserInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user