Réglages de la console Cloud π Native
+
upsertSystemSetting(setting.key, event)"
+ :model-value="systemSettings.maintenance === 'on'"
+ :label="`${systemSettings.maintenance === 'on' ? 'Désactiver' : 'Activer'} le mode maintenance`"
+ data-testid="toggle-maintenance"
+ @update:model-value="(event: boolean) => upsertSystemSetting('maintenance', event)"
+ />
+
+
+
+
+
+
+
+
diff --git a/apps/server/package.json b/apps/server/package.json
index f14ea08d12..27d3d2227f 100644
--- a/apps/server/package.json
+++ b/apps/server/package.json
@@ -67,7 +67,8 @@
"node-vault-client": "^1.0.1",
"prisma": "^5.19.1",
"undici": "^6.19.2",
- "vitest-mock-extended": "^1.3.1"
+ "vitest-mock-extended": "^1.3.1",
+ "zod": "^3.23.8"
},
"devDependencies": {
"@cpn-console/eslint-config": "workspace:^",
diff --git a/apps/server/src/resources/system/settings/business.ts b/apps/server/src/resources/system/settings/business.ts
index 5e562353b0..2efc8d6d63 100644
--- a/apps/server/src/resources/system/settings/business.ts
+++ b/apps/server/src/resources/system/settings/business.ts
@@ -1,9 +1,14 @@
-import type { UpsertSystemSettingBody } from '@cpn-console/shared'
-import {
- getSystemSettings as getSystemSettingsQuery,
- upsertSystemSetting as upsertSystemSettingQuery,
-} from './queries.js'
+import type { UpsertSystemSettingsBody } from '@cpn-console/shared'
+import { upsertSystemSetting as upsertSystemSettingQuery } from './queries.js'
-export const getSystemSettings = (key?: string) => getSystemSettingsQuery({ key })
+import { config } from '@/utils/config.js'
-export const upsertSystemSetting = (newSystemSetting: UpsertSystemSettingBody) => upsertSystemSettingQuery(newSystemSetting)
+export function getSystemSettings(key?: keyof typeof config) {
+ if (key) {
+ return { [key]: config[key] }
+ } else {
+ return config
+ }
+}
+
+export const upsertSystemSettings = (newSystemSetting: UpsertSystemSettingsBody) => upsertSystemSettingQuery(newSystemSetting)
diff --git a/apps/server/src/resources/system/settings/router.ts b/apps/server/src/resources/system/settings/router.ts
index baa0765b6c..7b5bf3c565 100644
--- a/apps/server/src/resources/system/settings/router.ts
+++ b/apps/server/src/resources/system/settings/router.ts
@@ -1,5 +1,5 @@
import { AdminAuthorized, systemSettingsContract } from '@cpn-console/shared'
-import { getSystemSettings, upsertSystemSetting } from './business.js'
+import { getSystemSettings, upsertSystemSettings } from './business.js'
import { serverInstance } from '@/app.js'
import { authUser } from '@/utils/controller.js'
import { Forbidden403 } from '@/utils/errors.js'
@@ -9,6 +9,12 @@ export function systemSettingsRouter() {
listSystemSettings: async ({ query }) => {
const systemSettings = await getSystemSettings(query.key)
+ if (!systemSettings) {
+ return {
+ status: 500,
+ body: { error: 'System settings not found' },
+ }
+ }
return {
status: 200,
body: systemSettings,
@@ -19,7 +25,7 @@ export function systemSettingsRouter() {
const perms = await authUser(req)
if (!AdminAuthorized.isAdmin(perms.adminPermissions)) return new Forbidden403()
- const systemSetting = await upsertSystemSetting(data)
+ const systemSetting = await upsertSystemSettings(data)
return {
status: 201,
diff --git a/apps/server/src/utils/config.ts b/apps/server/src/utils/config.ts
new file mode 100644
index 0000000000..484e082621
--- /dev/null
+++ b/apps/server/src/utils/config.ts
@@ -0,0 +1,133 @@
+import path from 'node:path'
+import { SystemSettingSchema as ConfigSchema } from '@cpn-console/shared'
+
+const getNodeEnv: () => 'development' | 'test' | 'production' = () => {
+ if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') {
+ return process.env.NODE_ENV
+ }
+ return 'production'
+}
+
+function snakeCaseToCamelCase(input: string) {
+ return input
+ .split('_')
+ .reduce((acc, cur, i) => {
+ if (!i) {
+ return cur.toLowerCase()
+ }
+ return acc + cur.charAt(0).toUpperCase() + cur.substring(1).toLowerCase()
+ }, '')
+}
+
+function deepMerge(target: any, source: any) {
+ const result = { ...target, ...source }
+ for (const key of Object.keys(result)) {
+ if (Array.isArray(target[key]) && Array.isArray(source[key])) {
+ result[key] = result[key].map((value: unknown, idx: number) => {
+ return typeof value === 'object'
+ ? deepMerge(target[key][idx], source[key][idx])
+ : structuredClone(result[key][idx])
+ })
+ } else if (typeof target[key] === 'object' && typeof source[key] === 'object') {
+ result[key] = deepMerge(target[key], source[key])
+ } else {
+ result[key] = structuredClone(result[key])
+ }
+ }
+ return result
+}
+
+const configPaths = {
+ development: path.resolve(__dirname, '../../config-example.json'),
+ production: '/app/config.json',
+ test: path.resolve(__dirname, './configs/config.valid.spec.json'),
+}
+
+const CONFIG_PATH = configPaths[getNodeEnv()]
+const ENV_PREFIX = ['API__', 'DOC__']
+
+// export const ConfigSchema = z.object({
+// maintenance: z.string().default('off'),
+// appName: z.string().default('Console Cloud Pi Native TEST DE FOU'),
+// contactMail: z.string().default('cloudpinative-relations@interieur.gouv.fr'),
+// appSubTitle: z.array(z.string()).default(['Ministère 2', 'de l’intérieur 3', 'et des outre-mer 4']),
+// // appLogoUrl: z.string().default(''), // pas sur de la faisabilité
+// }).strict()
+
+export type Config = Zod.infer