diff --git a/charts/dbildungs-iam-server/config/config.json b/charts/dbildungs-iam-server/config/config.json index 11310e644..1f97ca216 100644 --- a/charts/dbildungs-iam-server/config/config.json +++ b/charts/dbildungs-iam-server/config/config.json @@ -51,7 +51,7 @@ "BACKEND_FOR_FRONTEND_MODULE_LOG_LEVEL": "debug" }, "ITSLEARNING": { - "ENABLED": "false", + "ENABLED": false, "ENDPOINT": "https://itslearning.example.com", "USERNAME": "username", "PASSWORD": "password", @@ -60,7 +60,7 @@ "ROOT_ERSATZ": "ersatz" }, "OX": { - "ENABLED": "false", + "ENABLED": false, "ENDPOINT": "https://ox_ip:ox_port/webservices/OXUserService", "CONTEXT_ID": "1337", "CONTEXT_NAME": "contextname", diff --git a/charts/dbildungs-iam-server/templates/configmap.yaml b/charts/dbildungs-iam-server/templates/configmap.yaml index d786d57cf..26ed48bdc 100644 --- a/charts/dbildungs-iam-server/templates/configmap.yaml +++ b/charts/dbildungs-iam-server/templates/configmap.yaml @@ -21,3 +21,6 @@ data: LDAP_OEFFENTLICHE_SCHULEN_DOMAIN: "{{ .Values.ldap.oeffentlicheSchulenDomain }}" LDAP_ERSATZSCHULEN_DOMAIN: "{{ .Values.ldap.ersatzschulenDomain }}" STATUS_REDIRECT_URL: "{{ .Values.status.url }}" + ITSLEARNING_ROOT: '{{ .Values.itslearning.root }}' + ITSLEARNING_ROOT_OEFFENTLICH: '{{ .Values.itslearning.rootOeffentlich }}' + ITSLEARNING_ROOT_ERSATZ: '{{ .Values.itslearning.rootErsatz }}' diff --git a/charts/dbildungs-iam-server/values.yaml b/charts/dbildungs-iam-server/values.yaml index 9ef83effd..b5763a9fc 100644 --- a/charts/dbildungs-iam-server/values.yaml +++ b/charts/dbildungs-iam-server/values.yaml @@ -32,6 +32,11 @@ ldap: oeffentlicheSchulenDomain: schule-sh.de ersatzschulenDomain: ersatzschule-sh.de +itslearning: + root: sh + rootOeffentlich: oeffentlich + rootErsatz: ersatz + auth: # existingSecret: Refers to a secret already present in the cluster, which is required. existingSecret: '' diff --git a/config/config.json b/config/config.json index 75096e5ed..d51ab0f0f 100644 --- a/config/config.json +++ b/config/config.json @@ -63,7 +63,7 @@ "BACKEND_FOR_FRONTEND_MODULE_LOG_LEVEL": "debug" }, "ITSLEARNING": { - "ENABLED": "false", + "ENABLED": false, "ENDPOINT": "https://itslearning-test.example.com", "USERNAME": "username", "PASSWORD": "password", @@ -72,7 +72,7 @@ "ROOT_ERSATZ": "ersatz" }, "OX": { - "ENABLED": "false", + "ENABLED": false, "ENDPOINT": "http://ox.dev.spsh.dbildungsplattform.de/webservices/", "CONTEXT_ID": "1337", "CONTEXT_NAME": "contextname", diff --git a/src/modules/itslearning/event-handlers/itslearning-organisations.event-handler.ts b/src/modules/itslearning/event-handlers/itslearning-organisations.event-handler.ts index b49ab3dbd..60734b4c5 100644 --- a/src/modules/itslearning/event-handlers/itslearning-organisations.event-handler.ts +++ b/src/modules/itslearning/event-handlers/itslearning-organisations.event-handler.ts @@ -31,7 +31,7 @@ export class ItsLearningOrganisationsEventHandler { ) { const itsLearningConfig: ItsLearningConfig = configService.getOrThrow('ITSLEARNING'); - this.ENABLED = itsLearningConfig.ENABLED === 'true'; + this.ENABLED = itsLearningConfig.ENABLED; this.ROOT_OEFFENTLICH = itsLearningConfig.ROOT_OEFFENTLICH; } diff --git a/src/modules/itslearning/event-handlers/itslearning-persons.event-handler.ts b/src/modules/itslearning/event-handlers/itslearning-persons.event-handler.ts index 728cd4cb9..ea003c264 100644 --- a/src/modules/itslearning/event-handlers/itslearning-persons.event-handler.ts +++ b/src/modules/itslearning/event-handlers/itslearning-persons.event-handler.ts @@ -36,7 +36,7 @@ export class ItsLearningPersonsEventHandler { ) { const itsLearningConfig: ItsLearningConfig = configService.getOrThrow('ITSLEARNING'); - this.ENABLED = itsLearningConfig.ENABLED === 'true'; + this.ENABLED = itsLearningConfig.ENABLED; } @EventHandler(PersonRenamedEvent) diff --git a/src/modules/itslearning/event-handlers/itslearning-sync.event-handler.ts b/src/modules/itslearning/event-handlers/itslearning-sync.event-handler.ts index 23fd50f83..af60a25dc 100644 --- a/src/modules/itslearning/event-handlers/itslearning-sync.event-handler.ts +++ b/src/modules/itslearning/event-handlers/itslearning-sync.event-handler.ts @@ -46,7 +46,7 @@ export class ItsLearningSyncEventHandler { ) { const itsLearningConfig: ItsLearningConfig = configService.getOrThrow('ITSLEARNING'); - this.ENABLED = itsLearningConfig.ENABLED === 'true'; + this.ENABLED = itsLearningConfig.ENABLED; } @EventHandler(PersonExternalSystemsSyncEvent) diff --git a/src/modules/ox/domain/ox-event-handler.ts b/src/modules/ox/domain/ox-event-handler.ts index a47d78138..17018794f 100644 --- a/src/modules/ox/domain/ox-event-handler.ts +++ b/src/modules/ox/domain/ox-event-handler.ts @@ -60,7 +60,7 @@ export class OxEventHandler { ) { const oxConfig: OxConfig = configService.getOrThrow('OX'); - this.ENABLED = oxConfig.ENABLED === 'true'; + this.ENABLED = oxConfig.ENABLED; this.authUser = oxConfig.USERNAME; this.authPassword = oxConfig.PASSWORD; this.contextID = oxConfig.CONTEXT_ID; diff --git a/src/shared/config/config.env.ts b/src/shared/config/config.env.ts index 074f295f4..90408b131 100644 --- a/src/shared/config/config.env.ts +++ b/src/shared/config/config.env.ts @@ -8,6 +8,7 @@ import { PrivacyIdeaConfig } from './privacyidea.config.js'; import { SystemConfig } from './system.config.js'; import { OxConfig } from './ox.config.js'; import { RedisConfig } from './redis.config.js'; +import { envToOptionalBoolean } from './utils.js'; export type Config = { DB: Partial; @@ -56,10 +57,13 @@ export default (): Config => ({ PASSWORD: process.env['REDIS_PASSWORD'], }, ITSLEARNING: { - ENABLED: process.env['ITSLEARNING_ENABLED']?.toLowerCase() as 'true' | 'false', + ENABLED: envToOptionalBoolean('ITSLEARNING_ENABLED'), ENDPOINT: process.env['ITSLEARNING_ENDPOINT'], USERNAME: process.env['ITSLEARNING_USERNAME'], PASSWORD: process.env['ITSLEARNING_PASSWORD'], + ROOT: process.env['ITSLEARNING_ROOT'], + ROOT_OEFFENTLICH: process.env['ITSLEARNING_ROOT_OEFFENTLICH'], + ROOT_ERSATZ: process.env['ITSLEARNING_ROOT_ERSATZ'], }, PRIVACYIDEA: { ENDPOINT: process.env['PI_BASE_URL'], @@ -69,7 +73,7 @@ export default (): Config => ({ REALM: process.env['PI_REALM'], }, OX: { - ENABLED: process.env['OX_ENABLED']?.toLowerCase() as 'true' | 'false', + ENABLED: envToOptionalBoolean('OX_ENABLED'), ENDPOINT: process.env['OX_ENDPOINT'], USERNAME: process.env['OX_USERNAME'], PASSWORD: process.env['OX_PASSWORD'], diff --git a/src/shared/config/config.loader.spec.ts b/src/shared/config/config.loader.spec.ts index 9fa1dcd1a..080fbc3ff 100644 --- a/src/shared/config/config.loader.spec.ts +++ b/src/shared/config/config.loader.spec.ts @@ -55,7 +55,7 @@ describe('configloader', () => { BIND_DN: 'cn=admin,dc=schule-sh,dc=de', }, ITSLEARNING: { - ENABLED: 'true', + ENABLED: true, ENDPOINT: 'http://itslearning', USERNAME: 'username', ROOT: 'sh', @@ -70,7 +70,7 @@ describe('configloader', () => { REALM: 'defrealm', }, OX: { - ENABLED: 'true', + ENABLED: true, ENDPOINT: 'https://ox_ip:ox_port/webservices/OXUserService', CONTEXT_ID: '1337', CONTEXT_NAME: 'context1', @@ -175,7 +175,7 @@ describe('configloader', () => { ADMIN_PASSWORD: 'password', }, ITSLEARNING: { - ENABLED: 'true', + ENABLED: true, ENDPOINT: 'http://itslearning', USERNAME: 'username', PASSWORD: 'password', @@ -191,7 +191,7 @@ describe('configloader', () => { REALM: 'defrealm', }, OX: { - ENABLED: 'true', + ENABLED: true, ENDPOINT: 'https://ox_ip:ox_port/webservices/OXUserService', CONTEXT_ID: '1337', CONTEXT_NAME: 'context1', diff --git a/src/shared/config/itslearning.config.ts b/src/shared/config/itslearning.config.ts index 18c9d4b5c..54b2a976e 100644 --- a/src/shared/config/itslearning.config.ts +++ b/src/shared/config/itslearning.config.ts @@ -1,8 +1,8 @@ -import { IsBooleanString, IsString } from 'class-validator'; +import { IsBoolean, IsString } from 'class-validator'; export class ItsLearningConfig { - @IsBooleanString() - public readonly ENABLED!: 'true' | 'false'; + @IsBoolean() + public readonly ENABLED!: boolean; @IsString() public readonly ENDPOINT!: string; diff --git a/src/shared/config/ox.config.ts b/src/shared/config/ox.config.ts index d8ada0442..4e6cdea3b 100644 --- a/src/shared/config/ox.config.ts +++ b/src/shared/config/ox.config.ts @@ -1,8 +1,8 @@ -import { IsBooleanString, IsNumberString, IsString } from 'class-validator'; +import { IsBoolean, IsNumberString, IsString } from 'class-validator'; export class OxConfig { - @IsBooleanString() - public readonly ENABLED!: 'true' | 'false'; + @IsBoolean() + public readonly ENABLED!: boolean; @IsString() public readonly ENDPOINT!: string; diff --git a/src/shared/config/utils.spec.ts b/src/shared/config/utils.spec.ts new file mode 100644 index 000000000..5e0ea2cfa --- /dev/null +++ b/src/shared/config/utils.spec.ts @@ -0,0 +1,28 @@ +import { envToOptionalBoolean } from './utils.js'; + +const TEST_KEY: string = 'CONFIG_UTIL_TEST_KEY'; + +describe('Config Utils', () => { + describe('envToOptionalBoolean', () => { + it.each([ + ['', undefined], + ['true', true], + ['TRUE', true], + ['false', false], + ['FALSE', false], + ])( + 'when environment variable is "%s", should return %s', + (input: string | undefined, expected: boolean | undefined) => { + process.env[TEST_KEY] = input; + + expect(envToOptionalBoolean(TEST_KEY)).toBe(expected); + }, + ); + + it('should throw error, if the environment variable is set to an invalid string', () => { + process.env[TEST_KEY] = 'INVALID'; + + expect(() => envToOptionalBoolean(TEST_KEY)).toThrow(); + }); + }); +}); diff --git a/src/shared/config/utils.ts b/src/shared/config/utils.ts new file mode 100644 index 000000000..d23571bff --- /dev/null +++ b/src/shared/config/utils.ts @@ -0,0 +1,28 @@ +/** + * Reads the environment variable and returns an optional boolean. + * Depending on the input: + * - undefined or empty string -> undefined + * - "true" (case insensitive) -> true + * - "false" (case insensitive) -> false + * - any other string -> throws error + * + * @param key The name of the environment variable + */ +export function envToOptionalBoolean(key: string): boolean | undefined { + const value: string | undefined = process.env[key]; + + if (!value) { + return undefined; + } + + const lower: string | undefined = value.toLowerCase(); + + switch (lower) { + case 'true': + return true; + case 'false': + return false; + default: + throw new Error(`Expected environment variable "${key}" to be "true" or "false", received "${value}".`); + } +} diff --git a/test/config.test.json b/test/config.test.json index 5c86ca289..dc344ca7e 100644 --- a/test/config.test.json +++ b/test/config.test.json @@ -49,7 +49,7 @@ "DEFAULT_LOG_LEVEL": "info" }, "ITSLEARNING": { - "ENABLED": "false", + "ENABLED": false, "ENDPOINT": "https://itslearning-test.example.com", "USERNAME": "username", "PASSWORD": "password", @@ -65,7 +65,7 @@ "REALM": "defrealm" }, "OX": { - "ENABLED": "false", + "ENABLED": false, "ENDPOINT": "https://ox_ip:ox_port/webservices/", "USERNAME": "username", "PASSWORD": "password"