diff --git a/config.example.yaml b/config.example.yaml index dc1e11a..6aa1ab0 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -9,7 +9,12 @@ log_level: info # Logging level: fatal, error, warn, info, debug, trace, silent # Login flow configuration login: mode: username_password # username_password (default) or username_only or scanner_only or username_or_scanner + # If the login help image must be localised this the second configuration must be chosen. + # If the image is languistically neutral the first cofiguration is enough # login_help_image: '/branding/login-help.png' # optional; supports /absolute/path or https:// URL + # login_help_image: # optional + # en: '/branding/login-help-en.png' # supports /absolute/path or https:// URL + # de: '/branding/login-help-de.png' # supports /absolute/path or https:// URL # validation: # implementation: campus_id # empty/missing means scanner values are used directly for login # campus_id: diff --git a/src/lib/components/LoginModal.svelte b/src/lib/components/LoginModal.svelte index 2c12ff4..4c7b7d0 100644 --- a/src/lib/components/LoginModal.svelte +++ b/src/lib/components/LoginModal.svelte @@ -6,6 +6,7 @@ import { CircleX } from '@lucide/svelte'; import { clientLogger } from '$lib/client/logger'; import { m } from '$lib/paraglide/messages'; + import { getLocale, type Locale } from "$lib/paraglide/runtime"; type LoginMode = 'username_password' | 'username_only' | 'scanner_only' | 'username_or_scanner'; @@ -13,11 +14,20 @@ onSuccess: () => void; onCancel?: () => void; loginMode?: LoginMode; - loginHelpImage?: string; + loginHelpImage?: Record | string; } let { onSuccess, onCancel, loginMode = 'username_password', loginHelpImage }: Props = $props(); + const locale = getLocale().toUpperCase(); + const helpImage = $derived.by(() => { + if (!loginHelpImage) return undefined; + if (typeof loginHelpImage === "string") { + return loginHelpImage; + } + return loginHelpImage[getLocale()]; + }); + const requiresPassword = $derived(loginMode === 'username_password'); const hasCameraToggle = $derived(loginMode === 'username_or_scanner'); const scannerOnlyMode = $derived(loginMode === 'scanner_only'); @@ -211,10 +221,10 @@ class="modal-box max-w-4xl rounded-3xl bg-base-100/95 text-base-content shadow-2xl ring-1 ring-base-300/70" >
- {#if loginHelpImage} + {#if helpImage}
{m.login_required()} diff --git a/src/lib/server/config.ts b/src/lib/server/config.ts index adec21b..92e8e68 100644 --- a/src/lib/server/config.ts +++ b/src/lib/server/config.ts @@ -2,6 +2,7 @@ import fs from 'fs'; import path from 'path'; import YAML from 'yaml'; import { type LogLevel, parseLogLevel } from '$lib/logger/levels'; +import { type Locale } from "$lib/paraglide/runtime"; export type LoginMode = 'username_password' | 'username_only' | 'scanner_only' | 'username_or_scanner'; @@ -35,7 +36,7 @@ export interface MiddlewareInstanceConfig { export interface LoginConfig { mode?: LoginMode; - login_help_image?: string; + login_help_image?: Record | string; validation?: LoginValidationConfig; } @@ -284,6 +285,14 @@ function validateConfigData(data: LMSConfig, requireTaggingFormats: boolean): vo if (!data.middleware_instances || !Array.isArray(data.middleware_instances)) { throw new Error('Invalid configuration: middleware_instances must be an array'); } + + // if (data.login?.login_help_image) { + // for (const [locale, source] of Object.entries(data.login.login_help_image)) { + // if (validateSource(source) === undefined) { + // throw new Error('Invalid configuration: login_help_image must be a path'); + // } + // } + // } } function normalizeConfigData(data: LMSConfig, requireTaggingFormats: boolean): LMSConfig { @@ -294,7 +303,8 @@ function normalizeConfigData(data: LMSConfig, requireTaggingFormats: boolean): L data.log_level = parseLogLevel(data.log_level, 'info'); data.login = { mode: parsedLoginMode, - login_help_image: validateSource(data.login?.login_help_image), + // login_help_image: data.login?.login_help_image, + login_help_image: data.login?.login_help_image, validation: parseLoginValidationConfig(data.login) }; data.gate = parseGateConfig(data); @@ -388,6 +398,9 @@ log_level: info # Logging level: fatal, error, warn, info, debug, trace, silent login: mode: username_password # username_password (default) or username_only or scanner_only or username_or_scanner # login_help_image: '/branding/login-help.png' # optional; supports /absolute/path or https:// URL + # login_help_image: # optional + # de: '/branding/login-help-de.png supports /absolute/path or https:// URL + # en: '/branding/login-help-en.png supports /absolute/path or https:// URL # validation: # implementation: campus_id # empty/missing means scanner values are used directly for login # campus_id: diff --git a/src/routes/checkout/account/+page.server.ts b/src/routes/checkout/account/+page.server.ts index 9634eba..d9fb5dc 100644 --- a/src/routes/checkout/account/+page.server.ts +++ b/src/routes/checkout/account/+page.server.ts @@ -3,17 +3,18 @@ import { getLms } from '$lib/server/lms/resolve'; import { clearAuthCookie, getAuthUserFromCookies } from '$lib/server/auth-cookies'; import { getConfig, type LoginMode } from '$lib/server/config'; import { logger } from '$lib/server/logger'; +import { type Locale } from "$lib/paraglide/runtime"; export const load = (async ({ cookies }) => { const lms = getLms(); const userId = getAuthUserFromCookies(cookies); let loginMode: LoginMode = 'username_password'; - let loginHelpImage: string | undefined; + let loginHelpImage: Record | string | undefined; try { const config = getConfig(); loginMode = config.login?.mode ?? 'username_password'; - loginHelpImage = config.login?.login_help_image; + loginHelpImage = config.login?.login_help_image; } catch (error) { logger.error({ err: error }, 'Failed to load login config; defaulting to username/password'); } diff --git a/src/routes/checkout/borrow/+page.server.ts b/src/routes/checkout/borrow/+page.server.ts index 65f8af2..57c2060 100644 --- a/src/routes/checkout/borrow/+page.server.ts +++ b/src/routes/checkout/borrow/+page.server.ts @@ -3,17 +3,18 @@ import { getLms } from '$lib/server/lms/resolve'; import { clearAuthCookie, getAuthUserFromCookies } from '$lib/server/auth-cookies'; import { getConfig, type LoginMode } from '$lib/server/config'; import { logger } from '$lib/server/logger'; +import { type Locale } from "$lib/paraglide/runtime"; export const load = (async ({ cookies }) => { const lms = getLms(); const userId = getAuthUserFromCookies(cookies); let loginMode: LoginMode = 'username_password'; - let loginHelpImage: string | undefined; + let loginHelpImage: Record | string | undefined; try { const config = getConfig(); loginMode = config.login?.mode ?? 'username_password'; - loginHelpImage = config.login?.login_help_image; + loginHelpImage = config.login?.login_help_image; } catch (error) { logger.error({ err: error }, 'Failed to load login config; defaulting to username/password'); }