203 lines
6.6 KiB
TypeScript
203 lines
6.6 KiB
TypeScript
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
/* eslint-disable prettier/prettier */
|
|
/* eslint-disable @typescript-eslint/no-use-before-define */
|
|
import { DateTime } from 'luxon';
|
|
import _ from 'lodash';
|
|
|
|
import env from '@config/.env.json';
|
|
import packageFile from 'package.json';
|
|
|
|
import { SettingsType } from '@seed/interfaces/components';
|
|
|
|
import { ErrorsConfig, NotificationEnum } from '@config/config';
|
|
import { EngineNotificationEnum } from '@seed/interfaces/components.notifications';
|
|
import { TranslatableComponent } from '@src/__components/components';
|
|
import { promiseAll } from '@seed/helpers/Utils';
|
|
import DB from '@seed/services/database/DBService';
|
|
|
|
import { v4 as uuid } from 'uuid';
|
|
|
|
export interface GetSettingsOutput {
|
|
env: any[];
|
|
errors: any[];
|
|
emails: any[];
|
|
}
|
|
|
|
export interface EngineServerCacheInfo {
|
|
emailsContent: {
|
|
[key in NotificationEnum | EngineNotificationEnum]: any;
|
|
};
|
|
errorsContent: {
|
|
[key: string]: {
|
|
message: string;
|
|
translations?: {
|
|
subject?: TranslatableComponent;
|
|
body?: TranslatableComponent;
|
|
};
|
|
};
|
|
};
|
|
}
|
|
|
|
export const getSettingsFromDB = async (): Promise<GetSettingsOutput> => {
|
|
const settings = (await await (await DB.getInstance()).db.collection('settings').find().toArray()) as (any | any | any)[];
|
|
|
|
// filtering client side because not too much data and no need to index db
|
|
return {
|
|
env: _.filter(settings, { type: SettingsType.env }) as any[],
|
|
errors: _.filter(settings, { type: SettingsType.errors }) as any[],
|
|
emails: _.filter(settings, { type: SettingsType.emails }) as any[],
|
|
};
|
|
};
|
|
|
|
export const syncEnvFromDB = (currentEnvInDB: GetSettingsOutput): void => {
|
|
// update env
|
|
currentEnvInDB.env.map((env) => {
|
|
process.env[env.key] = env.value;
|
|
});
|
|
};
|
|
|
|
export const initEnvironement = async (env: any): Promise<GetSettingsOutput> => {
|
|
const currentEnv = process.env.NODE_ENV && env[process.env.NODE_ENV] ? env[process.env.NODE_ENV] : env.default;
|
|
|
|
for (const k in currentEnv) {
|
|
process.env[k] = currentEnv[k];
|
|
}
|
|
|
|
// Init also Package.json
|
|
process.env.awsRegion = packageFile.devops.awsRegion;
|
|
|
|
const currentSettings = await getSettingsFromDB();
|
|
syncEnvFromDB(currentSettings);
|
|
|
|
// Force the local to be > DB
|
|
if (process.env.NODE_ENV == 'local') {
|
|
for (const k in currentEnv) {
|
|
process.env[k] = currentEnv[k];
|
|
}
|
|
}
|
|
|
|
console.log('[Server - Env] Loaded');
|
|
|
|
return currentSettings;
|
|
};
|
|
|
|
export class SettingsCache {
|
|
private static instance: SettingsCache;
|
|
private lastCacheDate: DateTime;
|
|
public cache: EngineServerCacheInfo;
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
private constructor() {}
|
|
|
|
public static getInstance(): SettingsCache {
|
|
if (!this.instance) {
|
|
this.instance = new SettingsCache();
|
|
}
|
|
|
|
return this.instance;
|
|
}
|
|
|
|
public async refreshCache(): Promise<void> {
|
|
// check if needs to refresh the cache
|
|
if (!this.lastCacheDate || this.lastCacheDate.diff(DateTime.local(), 'minutes').minutes > 5) {
|
|
const settings = await initEnvironement(env);
|
|
|
|
const promises: Promise<any>[] = [];
|
|
|
|
// Map for errors
|
|
const errorsContent = await mapErrorContent(settings, promises);
|
|
|
|
// Map for emails
|
|
const emailsContent: {
|
|
[key in NotificationEnum | EngineNotificationEnum]: any;
|
|
} = await mapEmailSettings(settings, promises);
|
|
|
|
this.cache = {
|
|
errorsContent,
|
|
emailsContent,
|
|
};
|
|
this.lastCacheDate = DateTime.local();
|
|
|
|
if (promises.length > 0) {
|
|
console.log('Creating defaut in DB');
|
|
await promiseAll(promises);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
async function mapErrorContent(settings: GetSettingsOutput, newData: Promise<any>[]) {
|
|
const errorsContent: {
|
|
[key: string]: {
|
|
message: string;
|
|
translations?: {
|
|
subject?: TranslatableComponent;
|
|
body?: TranslatableComponent;
|
|
};
|
|
};
|
|
} = {};
|
|
for (const key in ErrorsConfig) {
|
|
if (Object.prototype.hasOwnProperty.call(ErrorsConfig, key)) {
|
|
const errIndex = _.findIndex(settings.errors, { key: key });
|
|
errorsContent[key] = {
|
|
message: ErrorsConfig[key],
|
|
};
|
|
if (errIndex === -1) {
|
|
console.error('[SETTINGS - ERROR] Creating default', key);
|
|
newData.push(
|
|
(await DB.getInstance()).db.collection('settings').insertOne({
|
|
key,
|
|
type: SettingsType.errors,
|
|
value: ErrorsConfig[key],
|
|
body: new TranslatableComponent(),
|
|
_id: uuid(),
|
|
r: ['admin'],
|
|
w: ['admin'],
|
|
d: ['admin'],
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
}),
|
|
);
|
|
} else {
|
|
errorsContent[key].translations = {
|
|
subject: settings.errors[errIndex].subject,
|
|
body: settings.errors[errIndex].body,
|
|
};
|
|
}
|
|
}
|
|
}
|
|
return errorsContent;
|
|
}
|
|
|
|
async function mapEmailSettings(settings: GetSettingsOutput, newData: Promise<any>[]) {
|
|
const emails = _.groupBy(settings.emails, 'key');
|
|
const emailsContent: {
|
|
[key in NotificationEnum | EngineNotificationEnum]: any;
|
|
} = {} as any;
|
|
|
|
const enumConcat = [...Object.keys(NotificationEnum), ...Object.keys(EngineNotificationEnum)];
|
|
|
|
enumConcat.forEach(async (element) => {
|
|
if (!emails[element]) {
|
|
console.error('[SETTINGS - EMAIL] Creating default', element);
|
|
newData.push(
|
|
(await DB.getInstance()).db.collection('settings').insertOne({
|
|
key: element,
|
|
type: SettingsType.emails,
|
|
body: new TranslatableComponent(),
|
|
custom: false,
|
|
fromEmail: '',
|
|
fromName: '',
|
|
replyToEmail: '',
|
|
r: ['admin'],
|
|
w: ['admin'],
|
|
d: ['admin'],
|
|
_id: uuid(),
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
}),
|
|
);
|
|
} else emailsContent[element] = emails[element];
|
|
});
|
|
return emailsContent;
|
|
}
|