import { and, eq, inArray } from "drizzle-orm"; import { db } from "./db"; import { appConfig, mediaAsset, mediaUsage } from "./db/schema"; export const MAINTENANCE_MODE_KEY = "maintenance_mode"; export { SITE_NAME_KEY, SITE_SETTINGS_DEFAULT_OG_IMAGE_FIELD_KEY, SITE_SETTINGS_ENTITY_ID, SITE_SETTINGS_ENTITY_TYPE, SITE_SETTINGS_FAVICON_FIELD_KEY, SITE_SETTINGS_LOGO_DARK_FIELD_KEY, SITE_SETTINGS_LOGO_LIGHT_FIELD_KEY, SITE_SETTINGS_KEY, DEFAULT_SITE_NAME, buildDefaultSiteSettings, getDefaultSiteSettingsMediaBindings, parseSiteSettingsValue, type SiteSettings, type SiteSettingsMediaBindings, } from "./site-settings"; export { MAIL_SETTINGS_KEY, buildDefaultMailSettings, parseMailSettingsValue, toMailSettingsFormValues, type MailSettings, type MailSettingsFormValues, } from "./mail-settings"; export { MARQUEE_SETTINGS_KEY, buildDefaultMarqueeSettings, parseMarqueeSettingsValue, splitMarqueeRowItems, syncMarqueeSettingsToGermanSource, type MarqueeLocaleSettings, type MarqueeSettings, } from "./marquee-settings"; import { DEFAULT_SITE_NAME, SITE_NAME_KEY, SITE_SETTINGS_DEFAULT_OG_IMAGE_FIELD_KEY, SITE_SETTINGS_ENTITY_ID, SITE_SETTINGS_ENTITY_TYPE, SITE_SETTINGS_FAVICON_FIELD_KEY, SITE_SETTINGS_LOGO_DARK_FIELD_KEY, SITE_SETTINGS_LOGO_LIGHT_FIELD_KEY, SITE_SETTINGS_KEY, buildDefaultSiteSettings, getDefaultSiteSettingsMediaBindings, parseSiteSettingsValue, type SiteSettings, type SiteSettingsMediaBindings, } from "./site-settings"; import { MAIL_SETTINGS_KEY, buildDefaultMailSettings, parseMailSettingsValue, toMailSettingsFormValues, type MailSettings, type MailSettingsFormValues, } from "./mail-settings"; import { MARQUEE_SETTINGS_KEY, buildDefaultMarqueeSettings, parseMarqueeSettingsValue, syncMarqueeSettingsToGermanSource, type MarqueeSettings, } from "./marquee-settings"; // Small helpers over the app_config key/value table (Drizzle). async function readConfigValue(key: string): Promise { const [row] = await db .select({ value: appConfig.value }) .from(appConfig) .where(eq(appConfig.key, key)) .limit(1); return row?.value; } async function upsertConfig(key: string, value: string): Promise { await db .insert(appConfig) .values({ key, value }) .onConflictDoUpdate({ target: appConfig.key, set: { value } }); } export async function getMaintenanceMode(): Promise { try { return (await readConfigValue(MAINTENANCE_MODE_KEY)) === "true"; } catch { return false; } } export async function setMaintenanceMode(enabled: boolean): Promise { await upsertConfig(MAINTENANCE_MODE_KEY, enabled ? "true" : "false"); } export async function getSiteSettings(): Promise { try { const configs = await db .select({ key: appConfig.key, value: appConfig.value }) .from(appConfig) .where(inArray(appConfig.key, [SITE_SETTINGS_KEY, SITE_NAME_KEY])); const configMap = new Map(configs.map((config) => [config.key, config.value])); const fallbackName = configMap.get(SITE_NAME_KEY) ?? DEFAULT_SITE_NAME; return parseSiteSettingsValue(configMap.get(SITE_SETTINGS_KEY), fallbackName); } catch { return buildDefaultSiteSettings(); } } export async function updateSiteSettings(settings: SiteSettings): Promise { await upsertConfig(SITE_SETTINGS_KEY, JSON.stringify(settings)); } export async function getMailSettings(): Promise { try { return parseMailSettingsValue(await readConfigValue(MAIL_SETTINGS_KEY)); } catch { return buildDefaultMailSettings(); } } export async function getMailSettingsFormValues(): Promise { const settings = await getMailSettings(); return toMailSettingsFormValues(settings); } export async function updateMailSettings(settings: MailSettings): Promise { await upsertConfig(MAIL_SETTINGS_KEY, JSON.stringify(settings)); } export async function getMarqueeSettings(): Promise { try { return parseMarqueeSettingsValue(await readConfigValue(MARQUEE_SETTINGS_KEY)); } catch { return buildDefaultMarqueeSettings(); } } export async function updateMarqueeSettings(settings: MarqueeSettings): Promise { const normalizedSettings = syncMarqueeSettingsToGermanSource(settings); await upsertConfig(MARQUEE_SETTINGS_KEY, JSON.stringify(normalizedSettings)); } export async function getSiteSettingsMediaBindings(): Promise { try { const usages = await db .select({ fieldKey: mediaUsage.fieldKey, updatedAt: mediaUsage.updatedAt, assetId: mediaAsset.id, assetUrl: mediaAsset.url, }) .from(mediaUsage) .innerJoin(mediaAsset, eq(mediaAsset.id, mediaUsage.assetId)) .where( and( eq(mediaUsage.entityType, SITE_SETTINGS_ENTITY_TYPE), eq(mediaUsage.entityId, SITE_SETTINGS_ENTITY_ID), ), ); return usages.reduce((result, usage) => { const binding = { assetId: usage.assetId, url: usage.assetUrl, version: usage.updatedAt.toISOString(), }; if (usage.fieldKey === SITE_SETTINGS_LOGO_LIGHT_FIELD_KEY) { result.siteLogoLight = binding; } if (usage.fieldKey === SITE_SETTINGS_LOGO_DARK_FIELD_KEY) { result.siteLogoDark = binding; } if (usage.fieldKey === SITE_SETTINGS_FAVICON_FIELD_KEY) { result.favicon = binding; } if (usage.fieldKey === SITE_SETTINGS_DEFAULT_OG_IMAGE_FIELD_KEY) { result.defaultOgImage = binding; } return result; }, getDefaultSiteSettingsMediaBindings()); } catch { return getDefaultSiteSettingsMediaBindings(); } }