From 03727cf1263b60346f24564b7ff80d64db137215 Mon Sep 17 00:00:00 2001 From: freddieptf Date: Tue, 26 Nov 2024 03:50:29 +0300 Subject: [PATCH] address feedback --- src/config/config-factory.ts | 44 ++++++++++++++++++++++++++++++++---- src/config/index.ts | 7 ++++-- src/routes/add-place.ts | 5 ++-- src/routes/move.ts | 3 ++- 4 files changed, 49 insertions(+), 10 deletions(-) diff --git a/src/config/config-factory.ts b/src/config/config-factory.ts index dc6a7169..40bb12a1 100644 --- a/src/config/config-factory.ts +++ b/src/config/config-factory.ts @@ -4,11 +4,43 @@ import kenyaConfig from './chis-ke'; import togoConfig from './chis-tg'; import civConfig from './chis-civ'; +export enum Feature { + Create = 'create', + ReplaceContact = 'replace-contact', + Move = 'move', +} + +const parseConfig = (c: any): PartnerConfig => { + return { + config: { + ...c.config, + contact_types: c.config.contact_types.map((t: any) => { + return { + ...t, + feature_flags: t.feature_flags?.map((v: string) => { + if ((Object.values(Feature) as string[]).indexOf(v) === -1) { + throw new Error( + 'invalid feature flag: ' + + v + + '. Acceptable values are [' + + Object.values(Feature).join(' | ') + + ']' + ); + } + return v as Feature; + }), + }; + }), + }, + mutate: c.mutate, + }; +}; + const CONFIG_MAP: { [key: string]: PartnerConfig } = { - 'CHIS-KE': kenyaConfig, - 'CHIS-UG': ugandaConfig, - 'CHIS-TG': togoConfig, - 'CHIS-CIV': civConfig + 'CHIS-KE': parseConfig(kenyaConfig), + 'CHIS-UG': parseConfig(ugandaConfig), + 'CHIS-TG': parseConfig(togoConfig), + 'CHIS-CIV': parseConfig(civConfig), }; export default function getConfigByKey(key: string = 'CHIS-KE'): PartnerConfig { @@ -17,7 +49,9 @@ export default function getConfigByKey(key: string = 'CHIS-KE'): PartnerConfig { const result = CONFIG_MAP[usingKey]; if (!result) { const available = JSON.stringify(Object.keys(CONFIG_MAP)); - throw Error(`Failed to start: Cannot find configuration "${usingKey}". Configurations available are ${available}`); + throw Error( + `Failed to start: Cannot find configuration '${usingKey}'. Configurations available are ${available}` + ); } return result; diff --git a/src/config/index.ts b/src/config/index.ts index e7ed8667..0a1bc85d 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -1,6 +1,6 @@ import _ from 'lodash'; import { ChtApi, PlacePayload } from '../lib/cht-api'; -import getConfigByKey from './config-factory'; +import getConfigByKey, { Feature } from './config-factory'; export type ConfigSystem = { domains: AuthenticationInfo[]; @@ -26,7 +26,7 @@ export type ContactType = { contact_properties: ContactProperty[]; deactivate_users_on_replace?: boolean; hint?: string; - feature_flags?: string[]; + feature_flags?: Feature[]; }; export type HierarchyConstraint = { @@ -123,6 +123,9 @@ export class Config { } public static hasMultipleRoles(contactType: ContactType): boolean { + if (contactType.feature_flags?.length === 1 && contactType.feature_flags.includes(Feature.Move)) { + return false; + } if (!contactType.user_role.length || contactType.user_role.some(role => !role.trim())) { throw Error(`unvalidatable config: 'user_role' property is empty or contains empty strings`); } diff --git a/src/routes/add-place.ts b/src/routes/add-place.ts index de54fae0..2f7e19f3 100644 --- a/src/routes/add-place.ts +++ b/src/routes/add-place.ts @@ -7,6 +7,7 @@ import SessionCache from '../services/session-cache'; import RemotePlaceResolver from '../lib/remote-place-resolver'; import { UploadManager } from '../services/upload-manager'; import RemotePlaceCache from '../lib/remote-place-cache'; +import { Feature } from '../config/config-factory'; export default async function addPlace(fastify: FastifyInstance) { fastify.get('/add-place', async (req, resp) => { @@ -18,8 +19,8 @@ export default async function addPlace(fastify: FastifyInstance) { : contactTypes[contactTypes.length - 1]; const op = queryParams.op || 'new'; if (contactType.feature_flags) { - if ((op === 'new' && !contactType.feature_flags.includes('create')) || - (op === 'replace' && !contactType.feature_flags.includes('replace-contact'))) { + if ((op === 'new' && !contactType.feature_flags.includes(Feature.Create)) || + (op === 'replace' && !contactType.feature_flags.includes(Feature.ReplaceContact))) { resp.code(404).type('text/html').send('Not Found'); return; } diff --git a/src/routes/move.ts b/src/routes/move.ts index e7c93ac7..f0e77d75 100644 --- a/src/routes/move.ts +++ b/src/routes/move.ts @@ -5,6 +5,7 @@ import { ChtApi } from '../lib/cht-api'; import { FastifyInstance } from 'fastify'; import MoveLib from '../lib/move'; import SessionCache from '../services/session-cache'; +import { Feature } from '../config/config-factory'; export default async function sessionCache(fastify: FastifyInstance) { fastify.get('/move/:placeType', async (req, resp) => { @@ -13,7 +14,7 @@ export default async function sessionCache(fastify: FastifyInstance) { const contactTypes = Config.contactTypes(); const contactType = Config.getContactType(placeType); - if (contactType.feature_flags && !contactType.feature_flags.includes('move')) { + if (contactType.feature_flags && !contactType.feature_flags.includes(Feature.Move)) { resp.code(404).type('text/html').send('Not Found'); return; }