-
Notifications
You must be signed in to change notification settings - Fork 3
Makes configuration uploadable thru API #240
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
src/config/index.ts
Outdated
| const parentMatch = contactType.hierarchy.find(c => c.level === 1); | ||
| if (!parentMatch) { | ||
| throw new Error(`hierarchy at level 1 is required: "${contactType.name}"`); | ||
| throw new Error(`hierarchy at level 1 is required: "${contactType?.name}"`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clean up
src/config/index.ts
Outdated
| const contactMatch = config.contact_types.find(c => c.name === name); | ||
| public static async getContactType(name: string) : Promise<ContactType> { | ||
| const {config} = await init(); | ||
| const contactMatch = config.contact_types.find(c => c?.name === name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clean up
src/config/config-factory.ts
Outdated
| }; | ||
|
|
||
| export default function getConfigByKey(key: string = 'CHIS-KE'): PartnerConfig { | ||
| export default async function getConfigByKey(key: string = 'CHIS-KE'): Promise<PartnerConfig> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In what scenario would the config be invalid after upload? Isn't validity checked at upload time?
src/config/index.ts
Outdated
|
|
||
| const partnerConfig = getConfigByKey(CONFIG_NAME); | ||
| const { config } = partnerConfig; | ||
| async function init(): Promise<PartnerConfig> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use getConfigByKey directly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this change necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, isAdmin is more of a chtSession property than an action on chtSession
|
|
||
| try { | ||
| const chtSession = Auth.createCookieSession(cookieToken); | ||
| if (req.routeOptions.url === '/api/config' && !chtSession?.isAdmin) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you should add this check to the route's request handler itself
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think authorization should be handled in the auth hook/middleware
but i have no strong opinion about this though i can move it
LMK
src/config/config-factory.ts
Outdated
|
|
||
| export async function readConfig(): Promise<PartnerConfig> { | ||
| try { | ||
| const fileContent = await fs.promises.readFile(uploadedConfigFilePath, 'utf-8'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see alot of calls had to be converted to async so i have to ask, Is there a synchronous equivalent to this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah sure there is but its asynchronous mainly for performance.
since this is an api/server you'd want to support concurrency with multiple requests without blocking
also config is read almost every time you make a request to the server for a page
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If It's for performance, wouldn't caching the config be more performant than reading from disk for every request?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe maybe not
Its just a single small file we just read from
but generally i wouldn't advice reading file synchronously in a server cos of its blocking nature
It more like reading db data synchronously, not advisable
src/config/chis-ke/gross.ts
Outdated
| }; | ||
|
|
||
| const contactType = Config.getContactType(payload.contact_type); | ||
| const contactType = await Config.getContactType(payload.contact_type); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't look like this is still an async function
|
|
||
| const authHeader = req.headers.authorization as string; | ||
| if (authHeader && authHeader.startsWith('Basic ')) { | ||
| if (!req.routeOptions.url?.startsWith('/api')) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When i POST the config without credentials it will try to redirect me to the /login endpoint which i think is awkward for an API. Is there any way this can be improved?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved
src/config/index.ts
Outdated
|
|
||
| //if config has default config i.e a new install | ||
| //return passed domain for api config upload authentication | ||
| if (availableDomains.some(c => c.domain === 'localhost')) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand the comment here, why are you explicitly checking for localhost?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
src/config/index.ts
Outdated
| } | ||
|
|
||
| public static getLogoBase64() : string { | ||
| public static async getLogoBase64(): Promise<string> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't need to be async
| fastify.post('/place/dob', async (req, resp) => { | ||
| const { place_type, prefix, prop_type } = req.query as any; | ||
| const contactType = Config.getContactType(place_type).contact_properties.find(prop => prop.type === prop_type); | ||
| const config = await Config.getContactType(place_type); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be reverted, doesn't look relevant to the changes in the PR
|
|
||
| }); | ||
|
|
||
| fastify.post('/api/config', async (req: FastifyRequest, reply: FastifyReply) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was able to post a config without any domains, which crashed the app after a logout. I was unable to post a new config after the crash happened
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
gj finding this case but there will be others. i'd bet on it.
this points to a deeper problem - how do you recover in production if an invalid config crashes the app? just another reason this pattern is concerning
src/config/config-factory.ts
Outdated
| if (!key) { | ||
| console.log('no configuration found. Setting to default'); | ||
| const defaultConfig = kenyaConfig; | ||
| defaultConfig.config.domains = [{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't this override the domains in this config? Would it be better to just crash the app if the key isn't set in the environment variables since that would be a deployment config issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The crash scenario is just below this code block which i think is a better way of handling this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i have added default config in case env variable is not provided this can then be overridden via api
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
environment variables should always be provided and checked at start up. We also shouldn't be changing the config values in code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thats not what im doing
i simply making the env variable optional
if not provided the app falls back to a default config which allows overwriting via api with any auth domain
other configs ie env and uploaded, will validate authenticate domain before overwriting
chck it out
src/config/config-factory.ts
Outdated
| try { | ||
| const jsonString: string = JSON.stringify(jsonConfigData, null, 2); | ||
| fs.writeFileSync(this.filePath, jsonString); | ||
| this.refreshConfig(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since refreshConfig is only used here, maybe you can just directly set the config here after writing it. Saves you a trip to the filesystem.
nitpick: the parameter name jsonConfigData is kinda confusing, maybe just config is fine?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets leave it there keeps it organized the writeconfig will be doing more than it describes
besides its a great action to have on the class
src/routes/app.ts
Outdated
| export default async function sessionCache(fastify: FastifyInstance) { | ||
| fastify.get('/', async (req, resp) => { | ||
| const contactTypes = Config.contactTypes(); | ||
| const contactTypes = await Config.contactTypes(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No longer async
freddieptf
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good progress, there are some changes around having a "default config" that i feel should not be a part of this PR and require further discourse. Please create another issue for this and lets have this PR only address adding the API
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am against having a default config simply because you'd be making some assumptions of one's setup. The dev should have their environment set up correctly and provide a valid config for their setup before starting the service and if none is provided the app shouldn't start
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
its not meant to be used it wouldnt work its just a place holder to allow uploading config on setting up the tool without breaking the tool
its there to allow some upload config
not having it leaves a gap on how config upload workflow would go
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if you leave ke(or other) config as default i cant update config in my set up if i dont have admin access to ke instance
also remember config is not set only in env variable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not having it leaves a gap on how config upload workflow would go
Isn't the workflow simply overwriting the app's current config?
if you leave ke(or other) config as default i cant update config in my set up if i dont have admin access to ke instance
also remember config is not set only in env variable
The config to load is already set via the CONFIG_NAME env variable. If no part of this api touches the env variables then how would that value change? For your case wouldn't It always be chis-ug?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
built in config file is never overwritten
a new file is created for the uploaded config
NOTE as of last week chis-ug is no longer a built in config it was removed by some PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How would the UG app be deployed with these changes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no env variable
deploy app
upload config from project repo
| // TODO: Joi? Chai? | ||
| public static assertValid({ config }: PartnerConfig = partnerConfig) { | ||
| for (const contactType of config.contact_types) { | ||
| public static assertValid(config?: PartnerConfig) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the config is undefined isn't it invalid by default?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure i understand this fully
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You made the parameter config optional. It shouldn't be
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was optional before
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It had a default value, that doesn't mean it was optional. I don't think you should be able to pass an undefined value to this function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thats exaclty what it means :)
check this out
cht-user-management/src/index.ts
Line 10 in 6547f53
| Config.assertValid(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It had a default value. The default value was set outside the function, you are setting the default value inside the function and changing the function signature to allow for a null value. That's my issue here. The function is meant to validate a config that's passed to it via the parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that function was being called with a undefined parameter im not changing the signiture
have you looked at the link?
it literally accepts undefined param
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also the default param value was being set in the function not outside
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let me know if you want to hope on a call tomorrow so we can finalize this
src/routes/api.ts
Outdated
| fastify.post('/api/config', async (req: FastifyRequest, reply: FastifyReply) => { | ||
| try { | ||
| const config = await req.body as ConfigSystem; | ||
| await Config.assertValid({ config }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assertValid is not async
| public static assertValid({ config }: PartnerConfig = partnerConfig) { | ||
| for (const contactType of config.contact_types) { | ||
| public static assertValid(config?: PartnerConfig) { | ||
| const { config: assertionConfig } = config || ConfigFactory.getConfigFactory().loadConfig(CONFIG_NAME); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be validating the passed config, not trying to load it in the function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i did this cause the way it was built initially
in some cases assertValid is called without any config passed
so to minimized changes i had to cater for these scenarios
it not doing anything different from what was there only how its implemented
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some in some cases assertValid is called with any config passed
and that's exactly how it's supposed to work, to validate the config passed to the function. Please revert.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i dont understand before this PR this function is called without passing config into it
its what im trying to maintain here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It had a default value that was the config loaded at startup. The equivalent behavior now would be calling loadConfig and passing that value to this function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
similar to what is being discussed here #240 (comment)
| reply.send({ message: 'configuration updated' }); | ||
| return; | ||
| } catch (error) { | ||
| console.error('Route api/config: ', error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Validation errors should return status code 400
| const newConfigHasExistingDomain = _.some(availableDomains, | ||
| existingDomain => _.some(assertionConfig.domains, newDomain => _.isMatch(existingDomain, newDomain))); | ||
| if (!this.isDefaultConfig() && !newConfigHasExistingDomain) { | ||
| throw Error(`Invalid configuration: 'domains' property doesn't contains any existing domain`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason for not allowing the domain list to be fully updated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if you have domains a,b, and c in the tool
when updated you dont want to overwrite them with x,y and z without atleast having any of a,b and c in the new config
avoid locking yourself out accidentally/intentionally
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if you only had credentials for domain d and it gets overwritten leaving domains a, b, x, y, z? Wouldn't you still be locked out?
That doesn't make the config invalid and i don't think it's something we should be checking for. Admins have access to the deployments (cht and this tool) and should be able to handle such cases so i don't see how that would be a problem
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dont you think a person with credentials to a domain not part of the UMT domains shouldnt be able to overwrite domains
scenario: if i had admin access to ug instance should i be able to use the same admin access to upload config in a ke instance
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't prevent that though. If that's what you're trying to prevent then shouldn't you be checking that the domain passed in the api call exists in the config's domain list?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let me explain better
if i had admin access to ug i can overwrite all domains and change them to all ke domains
this check tries to avoid this such that at least one of the new domains exited in the previous config
Overwriting all is NOT impossible this just makes it harder so its not done by accident
Overwriting all would be at least a 2 step operation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hence avoid admin locking them selves out by uploading all ke domains in a ug app and locking themselves out because they dont have ke credentials
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if i had admin access to ug i can overwrite all domains and change them to all ke domains
That's up-to the user and it's out of our hands. The user is an admin, they have ways to fix that.
scenario: if i had admin access to ug instance should i be able to use the same admin access to upload config in a ke instance
This is the scenario you should be fixing as it's a valid bug here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
honestly i dont see any problem with that check its just a precaution
that scenario is handled
| throw Error(`invalid configuration: 'contact_types' property is empty`); | ||
| } | ||
|
|
||
| for (const contactType of assertionConfig.contact_types) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to update this and make validation very thorough making sure all required fields on the ContactType object have values. Use the object definition as a guide on what is strictly required. For eg. I can upload a ContactType without the name field even though it's required
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mainly focused on things that would crash the app
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any required fields missing from ContactType will crash the app at some point. The app functionality i.e all generated forms, heavily depends on ContactType.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i have tested this the app will only misbehave but wont crush unless there is a particular scenario im missing
if the app is misbehaving config can be update ideally it should be tested before deploying
at least for now
lets handle these other cases in a new pr trying to get this in asap its blocking work
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The app won't work correctly if a ContactType doesn't have a valid name. The data clean-up you'd set yourself up for just from this one field missing is worth having the checks in place now. This is just one example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i dont think cht would accept uploading data if the name is invalid/wrong
and for this is unlikely to happen given config has to go thru testing by the dev before deployment
again this wont break the app lets handle all these scenarios in another pr
| checkRedisConnection(); | ||
|
|
||
| fastify.addHook('preValidation', async (req: FastifyRequest, reply: FastifyReply) => { | ||
| if (req.routeOptions.url?.startsWith('/api') && req.method === 'POST') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be for all request methods?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is checking for credentials not all requests have credentials/authheader
only api call come with authheader
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't the check you implemented apply for all api calls? Why limit it to POST calls only?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so you can call this endpoint in a browser to view config
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if this is specific to a single endpoing, why isn't it in the route file. why does it have to awkwardly be in this hook?
| 'CHIS-TG': togoConfig, | ||
| 'CHIS-CIV': civConfig, | ||
| 'CHIS-ML': maliConfig, | ||
| DEFAULT: defaultConfig |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you just add the config for uganda back into the repo? it should can a flag like can upload to true to ensure configs on other instances are not replaceable
| this.filePath = path.join(this.getConfigUploadDirectory(), 'config.json'); | ||
| } | ||
|
|
||
| static getConfigFactory(): ConfigFactory { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if this is a singleton, why not just have ConfigFactory be a static class?
| }; | ||
|
|
||
| constructor() { | ||
| this.filePath = path.join(this.getConfigUploadDirectory(), 'config.json'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
filePath should be explicit about what file it is pointing at. maybe uploadedConfigPath
|
|
||
| const usingKey = key.toUpperCase(); | ||
| console.log(`Using configuration: ${key}`); | ||
| const result = this.DEFAULT_CONFIG_MAP[usingKey]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| const result = this.DEFAULT_CONFIG_MAP[usingKey]; | |
| this.config = this.DEFAULT_CONFIG_MAP[usingKey]; |
This would be cleaner without the intermittent variable result imo
|
|
||
| private getConfigUploadDirectory(): string { | ||
| const configDir = path.join(__dirname, '..', 'config_uploads'); | ||
| if (!fs.existsSync(configDir)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
better to have this existsSync check in writeConfig?
| } | ||
|
|
||
| private getConfigUploadDirectory(): string { | ||
| const configDir = path.join(__dirname, '..', 'config_uploads'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what sort of scenarios have you tested to ensure proper persistence of this file in docker?
| try { | ||
| const config = await req.body as ConfigSystem; | ||
| Config.assertValid({ config }); | ||
| ConfigFactory.getConfigFactory().writeConfig(config); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems writeConfig should call assertValid? that feels like the right flow to ensure invalid configs cannot be written
| checkRedisConnection(); | ||
|
|
||
| fastify.addHook('preValidation', async (req: FastifyRequest, reply: FastifyReply) => { | ||
| if (req.routeOptions.url?.startsWith('/api') && req.method === 'POST') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if this is specific to a single endpoing, why isn't it in the route file. why does it have to awkwardly be in this hook?
| return; | ||
| } | ||
|
|
||
| const { domain } = req.query as { [key: string]: string }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is basic auth really what we want to use? why not just have an authenticated API? imo we should require users of the API to use /login (one way to authenticate to UMT), get issued a cookie, and then include it in requests to /api. that seems straightforward and not terribly burdensome to users of the API (atm just jonathan)
| import { Config, PartnerConfig } from '../src/config'; | ||
| import { CONFIG_MAP } from '../src/config/config-factory'; | ||
| import DEFAULT_CONFIG_MAP from '../src/config/config-factory'; | ||
| import { mockSimpleContactType } from './mocks'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add tests for config-factory?
Description
Current app requires rebuilding and re-deploying a app in order to change config
This approach introduces uploadable config making it easier to change configuration
The app defaults to the prebuilt config, once a new configuration is uploaded it overrides any pre-built config
Configuration can only be updated by CHT admins
Fixes #194
changes
/api/configused with basic auth to upload config