Merge pull request #572 from ylei-tsubame/issues/419api-add-mail-config
Web UI: add API support for mail config functionsmain
commit
1b923be6a2
30 changed files with 1098 additions and 0 deletions
@ -0,0 +1,106 @@ |
|||||||
|
import assert from 'assert'; |
||||||
|
import { SpawnSyncReturns, spawnSync } from 'child_process'; |
||||||
|
|
||||||
|
import { P_UUID, SERVER_PATHS } from './consts'; |
||||||
|
|
||||||
|
import { stdoutVar } from './shell'; |
||||||
|
|
||||||
|
const MAP_TO_FLAG_BUNDLE: { |
||||||
|
'alert-overrides': Record<keyof AlertOverrideRequestBody | 'uuid', string>; |
||||||
|
'mail-servers': Record<keyof MailServerRequestBody | 'uuid', string>; |
||||||
|
recipients: Record<keyof MailRecipientRequestBody | 'uuid', string>; |
||||||
|
} = { |
||||||
|
'alert-overrides': { |
||||||
|
hostUuid: '--alert-override-host-uuid', |
||||||
|
level: '--alert-override-alert-level', |
||||||
|
mailRecipientUuid: '--alert-override-recipient-uuid', |
||||||
|
uuid: '--alert-override-uuid', |
||||||
|
}, |
||||||
|
'mail-servers': { |
||||||
|
address: '--mail-server-address', |
||||||
|
authentication: '--mail-server-authentication', |
||||||
|
heloDomain: '--mail-server-helo-domain', |
||||||
|
password: '--mail-server-password', |
||||||
|
port: '--mail-server-port', |
||||||
|
security: '--mail-server-security', |
||||||
|
username: '--mail-server-username', |
||||||
|
uuid: '--mail-server-uuid', |
||||||
|
}, |
||||||
|
recipients: { |
||||||
|
email: '--recipient-email', |
||||||
|
language: '--recipient-language', |
||||||
|
level: '--recipient-level', |
||||||
|
name: '--recipient-name', |
||||||
|
uuid: '--recipient-uuid', |
||||||
|
}, |
||||||
|
}; |
||||||
|
|
||||||
|
export const execManageAlerts = ( |
||||||
|
entities: 'alert-overrides' | 'mail-servers' | 'recipients', |
||||||
|
operation: 'add' | 'edit' | 'delete', |
||||||
|
{ |
||||||
|
body, |
||||||
|
uuid, |
||||||
|
}: { |
||||||
|
body?: Record<string, unknown>; |
||||||
|
uuid?: string; |
||||||
|
} = {}, |
||||||
|
): { uuid?: string } => { |
||||||
|
const shallow = { ...body }; |
||||||
|
|
||||||
|
if (uuid) { |
||||||
|
shallow.uuid = uuid; |
||||||
|
} |
||||||
|
|
||||||
|
const commandArgs: string[] = Object.entries( |
||||||
|
MAP_TO_FLAG_BUNDLE[entities], |
||||||
|
).reduce( |
||||||
|
(previous, [key, flag]) => { |
||||||
|
const value = shallow[key]; |
||||||
|
|
||||||
|
if (value !== undefined) { |
||||||
|
previous.push(flag, String(value)); |
||||||
|
} |
||||||
|
|
||||||
|
return previous; |
||||||
|
}, |
||||||
|
[`--${entities}`, `--${operation}`, '--yes'], |
||||||
|
); |
||||||
|
|
||||||
|
stdoutVar({ commandArgs }, 'Manage alerts with args: '); |
||||||
|
|
||||||
|
let result: SpawnSyncReturns<string>; |
||||||
|
|
||||||
|
try { |
||||||
|
result = spawnSync( |
||||||
|
SERVER_PATHS.usr.sbin['anvil-manage-alerts'].self, |
||||||
|
commandArgs, |
||||||
|
{ encoding: 'utf-8', timeout: 10000 }, |
||||||
|
); |
||||||
|
|
||||||
|
const { error, signal, status, stderr, stdout } = result; |
||||||
|
|
||||||
|
stdoutVar( |
||||||
|
{ error, signal, status, stderr, stdout }, |
||||||
|
'Manage alerts returned: ', |
||||||
|
); |
||||||
|
|
||||||
|
assert.strictEqual( |
||||||
|
status, |
||||||
|
0, |
||||||
|
`Expected status to be 0, but got [${status}]`, |
||||||
|
); |
||||||
|
|
||||||
|
assert.strictEqual( |
||||||
|
error, |
||||||
|
undefined, |
||||||
|
`Expected no error, but got [${error}]`, |
||||||
|
); |
||||||
|
} catch (error) { |
||||||
|
throw new Error(`Failed to complete manage alerts; CAUSE: ${error}`); |
||||||
|
} |
||||||
|
|
||||||
|
return { |
||||||
|
uuid: result.stdout.match(new RegExp(P_UUID))?.[0], |
||||||
|
}; |
||||||
|
}; |
@ -0,0 +1,35 @@ |
|||||||
|
import { RequestHandler } from 'express'; |
||||||
|
|
||||||
|
import { execManageAlerts } from '../../execManageAlerts'; |
||||||
|
import { getAlertOverrideRequestBody } from './getAlertOverrideRequestBody'; |
||||||
|
import { stderr, stdout } from '../../shell'; |
||||||
|
|
||||||
|
export const createAlertOverride: RequestHandler< |
||||||
|
undefined, |
||||||
|
undefined, |
||||||
|
AlertOverrideRequestBody |
||||||
|
> = (request, response) => { |
||||||
|
const { body: rBody = {} } = request; |
||||||
|
|
||||||
|
stdout(`Begin creating alert override.`); |
||||||
|
|
||||||
|
let body: AlertOverrideRequestBody; |
||||||
|
|
||||||
|
try { |
||||||
|
body = getAlertOverrideRequestBody(rBody); |
||||||
|
} catch (error) { |
||||||
|
stderr(`Failed to process alert override input; CAUSE: ${error}`); |
||||||
|
|
||||||
|
return response.status(400).send(); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
execManageAlerts('alert-overrides', 'add', { body }); |
||||||
|
} catch (error) { |
||||||
|
stderr(`Failed to create alert override; CAUSE: ${error}`); |
||||||
|
|
||||||
|
return response.status(500).send(); |
||||||
|
} |
||||||
|
|
||||||
|
return response.status(201).send(); |
||||||
|
}; |
@ -0,0 +1,23 @@ |
|||||||
|
import { RequestHandler } from 'express'; |
||||||
|
|
||||||
|
import { execManageAlerts } from '../../execManageAlerts'; |
||||||
|
import { stderr } from '../../shell'; |
||||||
|
|
||||||
|
export const deleteAlertOverride: RequestHandler<AlertOverrideReqParams> = ( |
||||||
|
request, |
||||||
|
response, |
||||||
|
) => { |
||||||
|
const { |
||||||
|
params: { uuid }, |
||||||
|
} = request; |
||||||
|
|
||||||
|
try { |
||||||
|
execManageAlerts('alert-overrides', 'delete', { uuid }); |
||||||
|
} catch (error) { |
||||||
|
stderr(`Failed to delete alert override: CAUSE: ${error}`); |
||||||
|
|
||||||
|
return response.status(500).send(); |
||||||
|
} |
||||||
|
|
||||||
|
return response.status(204).send(); |
||||||
|
}; |
@ -0,0 +1,91 @@ |
|||||||
|
import { RequestHandler } from 'express'; |
||||||
|
|
||||||
|
import { DELETED } from '../../consts'; |
||||||
|
|
||||||
|
import { buildUnknownIDCondition } from '../../buildCondition'; |
||||||
|
import buildGetRequestHandler from '../buildGetRequestHandler'; |
||||||
|
import { buildQueryResultReducer } from '../../buildQueryResultModifier'; |
||||||
|
import { getShortHostName } from '../../disassembleHostName'; |
||||||
|
|
||||||
|
export const getAlertOverride: RequestHandler< |
||||||
|
AlertOverrideReqParams, |
||||||
|
undefined, |
||||||
|
undefined, |
||||||
|
AlertOverrideReqQuery |
||||||
|
> = buildGetRequestHandler((request, options) => { |
||||||
|
const { |
||||||
|
query: { 'mail-recipient': mailRecipient }, |
||||||
|
} = request; |
||||||
|
|
||||||
|
const { after: mailRecipientCond } = buildUnknownIDCondition( |
||||||
|
mailRecipient, |
||||||
|
'b.recipient_uuid', |
||||||
|
{ onFallback: () => 'TRUE' }, |
||||||
|
); |
||||||
|
|
||||||
|
const query = ` |
||||||
|
SELECT |
||||||
|
a.alert_override_uuid, |
||||||
|
a.alert_override_alert_level, |
||||||
|
b.recipient_uuid, |
||||||
|
b.recipient_name, |
||||||
|
c.host_uuid, |
||||||
|
c.host_name, |
||||||
|
d.anvil_uuid, |
||||||
|
d.anvil_name |
||||||
|
FROM alert_overrides AS a |
||||||
|
JOIN recipients AS b |
||||||
|
ON a.alert_override_recipient_uuid = b.recipient_uuid |
||||||
|
JOIN hosts AS c |
||||||
|
ON a.alert_override_host_uuid = c.host_uuid |
||||||
|
JOIN anvils AS d |
||||||
|
ON c.host_uuid IN (d.anvil_node1_host_uuid, d.anvil_node2_host_uuid) |
||||||
|
WHERE a.alert_override_alert_level != -1 |
||||||
|
AND b.recipient_name != '${DELETED}' |
||||||
|
AND ${mailRecipientCond} |
||||||
|
ORDER BY b.recipient_name ASC;`;
|
||||||
|
|
||||||
|
const afterQueryReturn: QueryResultModifierFunction = |
||||||
|
buildQueryResultReducer<AlertOverrideOverviewList>( |
||||||
|
( |
||||||
|
previous, |
||||||
|
[ |
||||||
|
uuid, |
||||||
|
level, |
||||||
|
mailRecipientUuid, |
||||||
|
mailRecipientName, |
||||||
|
hostUuid, |
||||||
|
hostName, |
||||||
|
anvilUuid, |
||||||
|
anvilName, |
||||||
|
], |
||||||
|
) => { |
||||||
|
previous[uuid] = { |
||||||
|
level: Number(level), |
||||||
|
mailRecipient: { |
||||||
|
name: mailRecipientName, |
||||||
|
uuid: mailRecipientUuid, |
||||||
|
}, |
||||||
|
node: { |
||||||
|
name: anvilName, |
||||||
|
uuid: anvilUuid, |
||||||
|
}, |
||||||
|
subnode: { |
||||||
|
name: hostName, |
||||||
|
short: getShortHostName(hostName), |
||||||
|
uuid: hostUuid, |
||||||
|
}, |
||||||
|
uuid, |
||||||
|
}; |
||||||
|
|
||||||
|
return previous; |
||||||
|
}, |
||||||
|
{}, |
||||||
|
); |
||||||
|
|
||||||
|
if (options) { |
||||||
|
options.afterQueryReturn = afterQueryReturn; |
||||||
|
} |
||||||
|
|
||||||
|
return query; |
||||||
|
}); |
@ -0,0 +1,83 @@ |
|||||||
|
import { RequestHandler } from 'express'; |
||||||
|
|
||||||
|
import { DELETED } from '../../consts'; |
||||||
|
|
||||||
|
import buildGetRequestHandler from '../buildGetRequestHandler'; |
||||||
|
import { buildQueryResultModifier } from '../../buildQueryResultModifier'; |
||||||
|
import { getShortHostName } from '../../disassembleHostName'; |
||||||
|
import { sanitize } from '../../sanitize'; |
||||||
|
|
||||||
|
export const getAlertOverrideDetail: RequestHandler<AlertOverrideReqParams> = |
||||||
|
buildGetRequestHandler((request, options) => { |
||||||
|
const { |
||||||
|
params: { uuid: rUuid }, |
||||||
|
} = request; |
||||||
|
|
||||||
|
const uuid = sanitize(rUuid, 'string', { modifierType: 'sql' }); |
||||||
|
|
||||||
|
const query = ` |
||||||
|
SELECT |
||||||
|
a.alert_override_uuid, |
||||||
|
a.alert_override_alert_level, |
||||||
|
b.recipient_uuid, |
||||||
|
b.recipient_name, |
||||||
|
c.host_uuid, |
||||||
|
c.host_name, |
||||||
|
d.anvil_uuid, |
||||||
|
d.anvil_name |
||||||
|
FROM alert_overrides AS a |
||||||
|
JOIN recipients AS b |
||||||
|
ON a.alert_override_recipient_uuid = b.recipient_uuid |
||||||
|
JOIN hosts AS c |
||||||
|
ON a.alert_override_host_uuid = c.host_uuid |
||||||
|
JOIN anvils AS d |
||||||
|
ON c.host_uuid IN (d.anvil_node1_host_uuid, d.anvil_node2_host_uuid) |
||||||
|
WHERE a.alert_override_alert_level != -1 |
||||||
|
AND b.recipient_name != '${DELETED}' |
||||||
|
AND a.alert_override_uuid = '${uuid}' |
||||||
|
ORDER BY b.recipient_name ASC;`;
|
||||||
|
|
||||||
|
const afterQueryReturn: QueryResultModifierFunction = |
||||||
|
buildQueryResultModifier<AlertOverrideDetail | undefined>((rows) => { |
||||||
|
if (!rows.length) { |
||||||
|
return undefined; |
||||||
|
} |
||||||
|
|
||||||
|
const { |
||||||
|
0: [ |
||||||
|
uuid, |
||||||
|
level, |
||||||
|
mailRecipientUuid, |
||||||
|
mailRecipientName, |
||||||
|
hostUuid, |
||||||
|
hostName, |
||||||
|
anvilUuid, |
||||||
|
anvilName, |
||||||
|
], |
||||||
|
} = rows; |
||||||
|
|
||||||
|
return { |
||||||
|
level: Number(level), |
||||||
|
mailRecipient: { |
||||||
|
name: mailRecipientName, |
||||||
|
uuid: mailRecipientUuid, |
||||||
|
}, |
||||||
|
node: { |
||||||
|
name: anvilName, |
||||||
|
uuid: anvilUuid, |
||||||
|
}, |
||||||
|
subnode: { |
||||||
|
name: hostName, |
||||||
|
short: getShortHostName(hostName), |
||||||
|
uuid: hostUuid, |
||||||
|
}, |
||||||
|
uuid, |
||||||
|
}; |
||||||
|
}); |
||||||
|
|
||||||
|
if (options) { |
||||||
|
options.afterQueryReturn = afterQueryReturn; |
||||||
|
} |
||||||
|
|
||||||
|
return query; |
||||||
|
}); |
@ -0,0 +1,45 @@ |
|||||||
|
import assert from 'assert'; |
||||||
|
|
||||||
|
import { REP_UUID } from '../../consts'; |
||||||
|
|
||||||
|
import { sanitize } from '../../sanitize'; |
||||||
|
|
||||||
|
export const getAlertOverrideRequestBody = ( |
||||||
|
body: Partial<AlertOverrideRequestBody>, |
||||||
|
uuid?: string, |
||||||
|
): AlertOverrideRequestBody => { |
||||||
|
const { |
||||||
|
hostUuid: rHostUuid, |
||||||
|
level: rLevel, |
||||||
|
mailRecipientUuid: rMailRecipientUuid, |
||||||
|
} = body; |
||||||
|
|
||||||
|
const hostUuid = sanitize(rHostUuid, 'string'); |
||||||
|
const level = sanitize(rLevel, 'number'); |
||||||
|
const mailRecipientUuid = sanitize(rMailRecipientUuid, 'string'); |
||||||
|
|
||||||
|
if (uuid) { |
||||||
|
assert(REP_UUID.test(uuid), `Expected valid UUIDv4; got [${uuid}]`); |
||||||
|
} |
||||||
|
|
||||||
|
assert( |
||||||
|
REP_UUID.test(hostUuid), |
||||||
|
`Expected valid host UUIDv4; got [${hostUuid}]`, |
||||||
|
); |
||||||
|
|
||||||
|
assert( |
||||||
|
Number.isSafeInteger(level), |
||||||
|
`Expected level to be an integer; got [${level}]`, |
||||||
|
); |
||||||
|
|
||||||
|
assert( |
||||||
|
REP_UUID.test(mailRecipientUuid), |
||||||
|
`Expected valid mail recipient UUIDv4; got [${mailRecipientUuid}]`, |
||||||
|
); |
||||||
|
|
||||||
|
return { |
||||||
|
hostUuid, |
||||||
|
level, |
||||||
|
mailRecipientUuid, |
||||||
|
}; |
||||||
|
}; |
@ -0,0 +1,5 @@ |
|||||||
|
export * from './createAlertOverride'; |
||||||
|
export * from './deleteAlertOverride'; |
||||||
|
export * from './getAlertOverride'; |
||||||
|
export * from './getAlertOverrideDetail'; |
||||||
|
export * from './updateAlertOverride'; |
@ -0,0 +1,38 @@ |
|||||||
|
import { RequestHandler } from 'express'; |
||||||
|
|
||||||
|
import { execManageAlerts } from '../../execManageAlerts'; |
||||||
|
import { getAlertOverrideRequestBody } from './getAlertOverrideRequestBody'; |
||||||
|
import { stderr, stdout } from '../../shell'; |
||||||
|
|
||||||
|
export const updateAlertOverride: RequestHandler< |
||||||
|
AlertOverrideReqParams, |
||||||
|
undefined, |
||||||
|
AlertOverrideRequestBody |
||||||
|
> = (request, response) => { |
||||||
|
const { |
||||||
|
body: rBody = {}, |
||||||
|
params: { uuid }, |
||||||
|
} = request; |
||||||
|
|
||||||
|
stdout('Begin updating alert override.'); |
||||||
|
|
||||||
|
let body: AlertOverrideRequestBody; |
||||||
|
|
||||||
|
try { |
||||||
|
body = getAlertOverrideRequestBody(rBody, uuid); |
||||||
|
} catch (error) { |
||||||
|
stderr(`Failed to process alert override input; CAUSE: ${error}`); |
||||||
|
|
||||||
|
return response.status(400).send(); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
execManageAlerts('alert-overrides', 'edit', { body, uuid }); |
||||||
|
} catch (error) { |
||||||
|
stderr(`Failed to update alert override; CAUSE: ${error}`); |
||||||
|
|
||||||
|
return response.status(500).send(); |
||||||
|
} |
||||||
|
|
||||||
|
return response.status(200).send(); |
||||||
|
}; |
@ -0,0 +1,41 @@ |
|||||||
|
import { RequestHandler } from 'express'; |
||||||
|
|
||||||
|
import { execManageAlerts } from '../../execManageAlerts'; |
||||||
|
import { getMailRecipientRequestBody } from './getMailRecipientRequestBody'; |
||||||
|
import { stderr, stdout } from '../../shell'; |
||||||
|
|
||||||
|
export const createMailRecipient: RequestHandler< |
||||||
|
undefined, |
||||||
|
MailRecipientResponseBody | undefined, |
||||||
|
MailRecipientRequestBody |
||||||
|
> = (request, response) => { |
||||||
|
const { body: rBody = {} } = request; |
||||||
|
|
||||||
|
stdout('Begin creating mail recipient.'); |
||||||
|
|
||||||
|
let reqBody: MailRecipientRequestBody; |
||||||
|
|
||||||
|
try { |
||||||
|
reqBody = getMailRecipientRequestBody(rBody); |
||||||
|
} catch (error) { |
||||||
|
stderr(`Failed to process mail recipient input; CAUSE: ${error}`); |
||||||
|
|
||||||
|
return response.status(400).send(); |
||||||
|
} |
||||||
|
|
||||||
|
let resBody: MailRecipientResponseBody | undefined; |
||||||
|
|
||||||
|
try { |
||||||
|
const { uuid = '' } = execManageAlerts('recipients', 'add', { |
||||||
|
body: reqBody, |
||||||
|
}); |
||||||
|
|
||||||
|
resBody = { uuid }; |
||||||
|
} catch (error) { |
||||||
|
stderr(`Failed to create mail recipient; CAUSE: ${error}`); |
||||||
|
|
||||||
|
return response.status(500).send(); |
||||||
|
} |
||||||
|
|
||||||
|
return response.status(201).send(resBody); |
||||||
|
}; |
@ -0,0 +1,43 @@ |
|||||||
|
import { RequestHandler } from 'express'; |
||||||
|
|
||||||
|
import { query } from '../../accessModule'; |
||||||
|
import { execManageAlerts } from '../../execManageAlerts'; |
||||||
|
import { sanitize } from '../../sanitize'; |
||||||
|
import { stderr } from '../../shell'; |
||||||
|
|
||||||
|
export const deleteMailRecipient: RequestHandler< |
||||||
|
MailRecipientParamsDictionary |
||||||
|
> = async (request, response) => { |
||||||
|
const { |
||||||
|
params: { uuid: rUuid }, |
||||||
|
} = request; |
||||||
|
|
||||||
|
const uuid = sanitize(rUuid, 'string', { modifierType: 'sql' }); |
||||||
|
|
||||||
|
try { |
||||||
|
const rows = await query<[string][]>( |
||||||
|
`SELECT alert_override_uuid
|
||||||
|
FROM alert_overrides |
||||||
|
WHERE alert_override_alert_level != -1 |
||||||
|
AND alert_override_recipient_uuid = '${uuid}';`,
|
||||||
|
); |
||||||
|
|
||||||
|
rows.forEach(([u]) => |
||||||
|
execManageAlerts('alert-overrides', 'delete', { uuid: u }), |
||||||
|
); |
||||||
|
} catch (error) { |
||||||
|
stderr(`Failed to delete related alert override records; CAUSE ${error}`); |
||||||
|
|
||||||
|
return response.status(500).send(); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
execManageAlerts('recipients', 'delete', { uuid }); |
||||||
|
} catch (error) { |
||||||
|
stderr(`Failed to delete alert recipient; CAUSE: ${error}`); |
||||||
|
|
||||||
|
return response.status(500).send(); |
||||||
|
} |
||||||
|
|
||||||
|
return response.status(204).send(); |
||||||
|
}; |
@ -0,0 +1,34 @@ |
|||||||
|
import { RequestHandler } from 'express'; |
||||||
|
|
||||||
|
import { DELETED } from '../../consts'; |
||||||
|
|
||||||
|
import buildGetRequestHandler from '../buildGetRequestHandler'; |
||||||
|
import { buildQueryResultReducer } from '../../buildQueryResultModifier'; |
||||||
|
|
||||||
|
export const getMailRecipient: RequestHandler = buildGetRequestHandler( |
||||||
|
(request, options) => { |
||||||
|
const query = ` |
||||||
|
SELECT |
||||||
|
a.recipient_uuid, |
||||||
|
a.recipient_name |
||||||
|
FROM recipients AS a |
||||||
|
WHERE a.recipient_name != '${DELETED}' |
||||||
|
ORDER BY a.recipient_name ASC;`;
|
||||||
|
|
||||||
|
const afterQueryReturn: QueryResultModifierFunction = |
||||||
|
buildQueryResultReducer<MailRecipientOverviewList>( |
||||||
|
(previous, [uuid, name]) => { |
||||||
|
previous[uuid] = { name, uuid }; |
||||||
|
|
||||||
|
return previous; |
||||||
|
}, |
||||||
|
{}, |
||||||
|
); |
||||||
|
|
||||||
|
if (options) { |
||||||
|
options.afterQueryReturn = afterQueryReturn; |
||||||
|
} |
||||||
|
|
||||||
|
return query; |
||||||
|
}, |
||||||
|
); |
@ -0,0 +1,53 @@ |
|||||||
|
import { RequestHandler } from 'express'; |
||||||
|
|
||||||
|
import { DELETED } from '../../consts'; |
||||||
|
|
||||||
|
import buildGetRequestHandler from '../buildGetRequestHandler'; |
||||||
|
import { buildQueryResultModifier } from '../../buildQueryResultModifier'; |
||||||
|
import { sanitize } from '../../sanitize'; |
||||||
|
|
||||||
|
export const getMailRecipientDetail: RequestHandler<MailRecipientParamsDictionary> = |
||||||
|
buildGetRequestHandler((request, options) => { |
||||||
|
const { |
||||||
|
params: { uuid: rUuid }, |
||||||
|
} = request; |
||||||
|
|
||||||
|
const uuid = sanitize(rUuid, 'string', { modifierType: 'sql' }); |
||||||
|
|
||||||
|
const query = ` |
||||||
|
SELECT |
||||||
|
a.recipient_uuid, |
||||||
|
a.recipient_name, |
||||||
|
a.recipient_email, |
||||||
|
a.recipient_language, |
||||||
|
a.recipient_level |
||||||
|
FROM recipients AS a |
||||||
|
WHERE a.recipient_name != '${DELETED}' |
||||||
|
AND a.recipient_uuid = '${uuid}' |
||||||
|
ORDER BY a.recipient_name ASC;`;
|
||||||
|
|
||||||
|
const afterQueryReturn: QueryResultModifierFunction = |
||||||
|
buildQueryResultModifier<MailRecipientDetail | undefined>((rows) => { |
||||||
|
if (!rows.length) { |
||||||
|
return undefined; |
||||||
|
} |
||||||
|
|
||||||
|
const { |
||||||
|
0: [uuid, name, email, language, level], |
||||||
|
} = rows; |
||||||
|
|
||||||
|
return { |
||||||
|
email, |
||||||
|
language, |
||||||
|
level: Number(level), |
||||||
|
name, |
||||||
|
uuid, |
||||||
|
}; |
||||||
|
}); |
||||||
|
|
||||||
|
if (options) { |
||||||
|
options.afterQueryReturn = afterQueryReturn; |
||||||
|
} |
||||||
|
|
||||||
|
return query; |
||||||
|
}); |
@ -0,0 +1,49 @@ |
|||||||
|
import assert from 'assert'; |
||||||
|
|
||||||
|
import { REP_UUID } from '../../consts'; |
||||||
|
|
||||||
|
import { sanitize } from '../../sanitize'; |
||||||
|
|
||||||
|
export const getMailRecipientRequestBody = ( |
||||||
|
body: Partial<MailRecipientRequestBody>, |
||||||
|
uuid?: string, |
||||||
|
): MailRecipientRequestBody => { |
||||||
|
const { |
||||||
|
email: rEmail, |
||||||
|
language: rLanguage, |
||||||
|
level: rLevel, |
||||||
|
name: rName, |
||||||
|
} = body; |
||||||
|
|
||||||
|
const email = sanitize(rEmail, 'string'); |
||||||
|
const language = sanitize(rLanguage, 'string', { fallback: 'en_CA' }); |
||||||
|
const level = sanitize(rLevel, 'number'); |
||||||
|
const name = sanitize(rName, 'string'); |
||||||
|
|
||||||
|
if (uuid) { |
||||||
|
assert(REP_UUID.test(uuid), `Expected valid UUIDv4; got [${uuid}]`); |
||||||
|
} |
||||||
|
|
||||||
|
assert.ok(email.length, `Expected email; got [${email}]`); |
||||||
|
|
||||||
|
if (language) { |
||||||
|
assert.ok( |
||||||
|
language.length, |
||||||
|
`Expected valid language code; got [${language}]`, |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
assert( |
||||||
|
Number.isSafeInteger(level), |
||||||
|
`Expected level to be an integer; got [${level}]`, |
||||||
|
); |
||||||
|
|
||||||
|
assert.ok(name.length, `Expected name; got [${name}]`); |
||||||
|
|
||||||
|
return { |
||||||
|
email, |
||||||
|
language, |
||||||
|
level, |
||||||
|
name, |
||||||
|
}; |
||||||
|
}; |
@ -0,0 +1,5 @@ |
|||||||
|
export * from './createMailRecipient'; |
||||||
|
export * from './deleteMailRecipient'; |
||||||
|
export * from './getMailRecipient'; |
||||||
|
export * from './getMailRecipientDetail'; |
||||||
|
export * from './updateMailRecipient'; |
@ -0,0 +1,38 @@ |
|||||||
|
import { RequestHandler } from 'express'; |
||||||
|
|
||||||
|
import { execManageAlerts } from '../../execManageAlerts'; |
||||||
|
import { getMailRecipientRequestBody } from './getMailRecipientRequestBody'; |
||||||
|
import { stderr, stdout } from '../../shell'; |
||||||
|
|
||||||
|
export const updateMailRecipient: RequestHandler< |
||||||
|
MailRecipientParamsDictionary, |
||||||
|
undefined, |
||||||
|
MailRecipientRequestBody |
||||||
|
> = (request, response) => { |
||||||
|
const { |
||||||
|
body: rBody = {}, |
||||||
|
params: { uuid }, |
||||||
|
} = request; |
||||||
|
|
||||||
|
stdout('Begin updating mail recipient.'); |
||||||
|
|
||||||
|
let body: MailRecipientRequestBody; |
||||||
|
|
||||||
|
try { |
||||||
|
body = getMailRecipientRequestBody(rBody, uuid); |
||||||
|
} catch (error) { |
||||||
|
stderr(`Failed to process mail recipient input; CAUSE: ${error}`); |
||||||
|
|
||||||
|
return response.status(400).send(); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
execManageAlerts('recipients', 'edit', { body, uuid }); |
||||||
|
} catch (error) { |
||||||
|
stderr(`Failed to update mail recipient; CAUSE: ${error}`); |
||||||
|
|
||||||
|
return response.status(500).send(); |
||||||
|
} |
||||||
|
|
||||||
|
return response.status(200).send(); |
||||||
|
}; |
@ -0,0 +1,35 @@ |
|||||||
|
import { RequestHandler } from 'express'; |
||||||
|
|
||||||
|
import { execManageAlerts } from '../../execManageAlerts'; |
||||||
|
import { getMailServerRequestBody } from './getMailServerRequestBody'; |
||||||
|
import { stderr, stdout } from '../../shell'; |
||||||
|
|
||||||
|
export const createMailServer: RequestHandler< |
||||||
|
undefined, |
||||||
|
undefined, |
||||||
|
MailServerRequestBody |
||||||
|
> = (request, response) => { |
||||||
|
const { body: rBody = {} } = request; |
||||||
|
|
||||||
|
stdout('Begin creating mail server.'); |
||||||
|
|
||||||
|
let body: MailServerRequestBody; |
||||||
|
|
||||||
|
try { |
||||||
|
body = getMailServerRequestBody(rBody); |
||||||
|
} catch (error) { |
||||||
|
stderr(`Failed to process mail server input; CAUSE: ${error}`); |
||||||
|
|
||||||
|
return response.status(400).send(); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
execManageAlerts('mail-servers', 'add', { body }); |
||||||
|
} catch (error) { |
||||||
|
stderr(`Failed to create mail server; CAUSE: ${error}`); |
||||||
|
|
||||||
|
return response.status(500).send(); |
||||||
|
} |
||||||
|
|
||||||
|
return response.status(201).send(); |
||||||
|
}; |
@ -0,0 +1,23 @@ |
|||||||
|
import { RequestHandler } from 'express'; |
||||||
|
|
||||||
|
import { execManageAlerts } from '../../execManageAlerts'; |
||||||
|
import { stderr } from '../../shell'; |
||||||
|
|
||||||
|
export const deleteMailServer: RequestHandler<MailServerParamsDictionary> = ( |
||||||
|
request, |
||||||
|
response, |
||||||
|
) => { |
||||||
|
const { |
||||||
|
params: { uuid }, |
||||||
|
} = request; |
||||||
|
|
||||||
|
try { |
||||||
|
execManageAlerts('mail-servers', 'delete', { uuid }); |
||||||
|
} catch (error) { |
||||||
|
stderr(`Failed to delete mail server; CAUSE: ${error}`); |
||||||
|
|
||||||
|
return response.status(500).send(); |
||||||
|
} |
||||||
|
|
||||||
|
return response.status(204).send(); |
||||||
|
}; |
@ -0,0 +1,39 @@ |
|||||||
|
import { RequestHandler } from 'express'; |
||||||
|
|
||||||
|
import { DELETED } from '../../consts'; |
||||||
|
|
||||||
|
import buildGetRequestHandler from '../buildGetRequestHandler'; |
||||||
|
import { buildQueryResultReducer } from '../../buildQueryResultModifier'; |
||||||
|
|
||||||
|
export const getMailServer: RequestHandler = buildGetRequestHandler( |
||||||
|
(request, options) => { |
||||||
|
const query = ` |
||||||
|
SELECT |
||||||
|
a.mail_server_uuid, |
||||||
|
a.mail_server_address, |
||||||
|
a.mail_server_port |
||||||
|
FROM mail_servers AS a |
||||||
|
WHERE a.mail_server_helo_domain != '${DELETED}' |
||||||
|
ORDER BY a.mail_server_address;`;
|
||||||
|
|
||||||
|
const afterQueryReturn: QueryResultModifierFunction = |
||||||
|
buildQueryResultReducer<MailServerOverviewList>( |
||||||
|
(previous, [uuid, address, port]) => { |
||||||
|
previous[uuid] = { |
||||||
|
address, |
||||||
|
port: Number(port), |
||||||
|
uuid, |
||||||
|
}; |
||||||
|
|
||||||
|
return previous; |
||||||
|
}, |
||||||
|
{}, |
||||||
|
); |
||||||
|
|
||||||
|
if (options) { |
||||||
|
options.afterQueryReturn = afterQueryReturn; |
||||||
|
} |
||||||
|
|
||||||
|
return query; |
||||||
|
}, |
||||||
|
); |
@ -0,0 +1,68 @@ |
|||||||
|
import { RequestHandler } from 'express'; |
||||||
|
|
||||||
|
import { DELETED } from '../../consts'; |
||||||
|
|
||||||
|
import buildGetRequestHandler from '../buildGetRequestHandler'; |
||||||
|
import { buildQueryResultModifier } from '../../buildQueryResultModifier'; |
||||||
|
import { sanitize } from '../../sanitize'; |
||||||
|
|
||||||
|
export const getMailServerDetail: RequestHandler<MailServerParamsDictionary> = |
||||||
|
buildGetRequestHandler((request, options) => { |
||||||
|
const { |
||||||
|
params: { uuid: rUuid }, |
||||||
|
} = request; |
||||||
|
|
||||||
|
const uuid = sanitize(rUuid, 'string', { modifierType: 'sql' }); |
||||||
|
|
||||||
|
const query = ` |
||||||
|
SELECT |
||||||
|
a.mail_server_uuid, |
||||||
|
a.mail_server_address, |
||||||
|
a.mail_server_port, |
||||||
|
a.mail_server_username, |
||||||
|
a.mail_server_password, |
||||||
|
a.mail_server_security, |
||||||
|
a.mail_server_authentication, |
||||||
|
a.mail_server_helo_domain |
||||||
|
FROM mail_servers AS a |
||||||
|
WHERE a.mail_server_helo_domain != '${DELETED}' |
||||||
|
AND a.mail_server_uuid = '${uuid}' |
||||||
|
ORDER BY a.mail_server_address ASC;`;
|
||||||
|
|
||||||
|
const afterQueryReturn: QueryResultModifierFunction = |
||||||
|
buildQueryResultModifier<MailServerDetail | undefined>((rows) => { |
||||||
|
if (!rows.length) { |
||||||
|
return undefined; |
||||||
|
} |
||||||
|
|
||||||
|
const { |
||||||
|
0: [ |
||||||
|
uuid, |
||||||
|
address, |
||||||
|
port, |
||||||
|
username, |
||||||
|
password, |
||||||
|
security, |
||||||
|
authentication, |
||||||
|
heloDomain, |
||||||
|
], |
||||||
|
} = rows; |
||||||
|
|
||||||
|
return { |
||||||
|
address, |
||||||
|
authentication, |
||||||
|
heloDomain, |
||||||
|
password, |
||||||
|
port: Number(port), |
||||||
|
security, |
||||||
|
username, |
||||||
|
uuid, |
||||||
|
}; |
||||||
|
}); |
||||||
|
|
||||||
|
if (options) { |
||||||
|
options.afterQueryReturn = afterQueryReturn; |
||||||
|
} |
||||||
|
|
||||||
|
return query; |
||||||
|
}); |
@ -0,0 +1,63 @@ |
|||||||
|
import assert from 'assert'; |
||||||
|
|
||||||
|
import { REP_UUID } from '../../consts'; |
||||||
|
|
||||||
|
import { sanitize } from '../../sanitize'; |
||||||
|
|
||||||
|
export const getMailServerRequestBody = ( |
||||||
|
body: Partial<MailServerRequestBody>, |
||||||
|
uuid?: string, |
||||||
|
): MailServerRequestBody => { |
||||||
|
const { |
||||||
|
address: rAddress, |
||||||
|
authentication: rAuthentication, |
||||||
|
heloDomain: rHeloDomain, |
||||||
|
password: rPassword, |
||||||
|
port: rPort, |
||||||
|
security: rSecurity, |
||||||
|
username: rUsername, |
||||||
|
} = body; |
||||||
|
|
||||||
|
const address = sanitize(rAddress, 'string'); |
||||||
|
const authentication = sanitize(rAuthentication, 'string', { |
||||||
|
fallback: 'none', |
||||||
|
}); |
||||||
|
const heloDomain = sanitize(rHeloDomain, 'string'); |
||||||
|
const password = sanitize(rPassword, 'string'); |
||||||
|
const port = sanitize(rPort, 'number', { fallback: 587 }); |
||||||
|
const security = sanitize(rSecurity, 'string', { fallback: 'none' }); |
||||||
|
const username = sanitize(rUsername, 'string'); |
||||||
|
|
||||||
|
if (uuid) { |
||||||
|
assert(REP_UUID.test(uuid), `Expected valid UUIDv4; got [${uuid}]`); |
||||||
|
} |
||||||
|
|
||||||
|
assert.ok(address.length, `Expected address; got [${address}]`); |
||||||
|
|
||||||
|
assert( |
||||||
|
['none', 'plain-text', 'encrypted'].includes(authentication), |
||||||
|
`Expected authentication to be 'none', 'plain-text', or 'encrypted'; got [${authentication}]`, |
||||||
|
); |
||||||
|
|
||||||
|
assert.ok(heloDomain.length, `Expected HELO domain; got [${heloDomain}]`); |
||||||
|
|
||||||
|
assert( |
||||||
|
Number.isSafeInteger(port), |
||||||
|
`Expected port to be an integer; got [${port}]`, |
||||||
|
); |
||||||
|
|
||||||
|
assert( |
||||||
|
['none', 'starttls', 'tls-ssl'].includes(security), |
||||||
|
`Expected security to be 'none', 'starttls', or 'tls-ssl'; got [${security}]`, |
||||||
|
); |
||||||
|
|
||||||
|
return { |
||||||
|
address, |
||||||
|
authentication, |
||||||
|
heloDomain, |
||||||
|
password, |
||||||
|
port, |
||||||
|
security, |
||||||
|
username, |
||||||
|
}; |
||||||
|
}; |
@ -0,0 +1,5 @@ |
|||||||
|
export * from './createMailServer'; |
||||||
|
export * from './deleteMailServer'; |
||||||
|
export * from './getMailServer'; |
||||||
|
export * from './getMailServerDetail'; |
||||||
|
export * from './updateMailServer'; |
@ -0,0 +1,38 @@ |
|||||||
|
import { RequestHandler } from 'express'; |
||||||
|
|
||||||
|
import { execManageAlerts } from '../../execManageAlerts'; |
||||||
|
import { getMailServerRequestBody } from './getMailServerRequestBody'; |
||||||
|
import { stderr, stdout } from '../../shell'; |
||||||
|
|
||||||
|
export const updateMailServer: RequestHandler< |
||||||
|
MailServerParamsDictionary, |
||||||
|
undefined, |
||||||
|
MailServerRequestBody |
||||||
|
> = (request, response) => { |
||||||
|
const { |
||||||
|
body: rBody = {}, |
||||||
|
params: { uuid }, |
||||||
|
} = request; |
||||||
|
|
||||||
|
stdout('Begin updating mail server.'); |
||||||
|
|
||||||
|
let body: MailServerRequestBody; |
||||||
|
|
||||||
|
try { |
||||||
|
body = getMailServerRequestBody(rBody, uuid); |
||||||
|
} catch (error) { |
||||||
|
stderr(`Failed to process mail server input; CAUSE: ${error}`); |
||||||
|
|
||||||
|
return response.status(400).send(); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
execManageAlerts('mail-servers', 'edit', { body, uuid }); |
||||||
|
} catch (error) { |
||||||
|
stderr(`Failed to update mail server; CAUSE: ${error}`); |
||||||
|
|
||||||
|
return response.status(500).send(); |
||||||
|
} |
||||||
|
|
||||||
|
return response.status(200).send(); |
||||||
|
}; |
@ -0,0 +1,20 @@ |
|||||||
|
import express from 'express'; |
||||||
|
|
||||||
|
import { |
||||||
|
createAlertOverride, |
||||||
|
deleteAlertOverride, |
||||||
|
getAlertOverride, |
||||||
|
getAlertOverrideDetail, |
||||||
|
updateAlertOverride, |
||||||
|
} from '../lib/request_handlers/alert-override'; |
||||||
|
|
||||||
|
const router = express.Router(); |
||||||
|
|
||||||
|
router |
||||||
|
.delete('/:uuid', deleteAlertOverride) |
||||||
|
.get('/', getAlertOverride) |
||||||
|
.get('/:uuid', getAlertOverrideDetail) |
||||||
|
.post('/', createAlertOverride) |
||||||
|
.put('/:uuid', updateAlertOverride); |
||||||
|
|
||||||
|
export default router; |
@ -0,0 +1,20 @@ |
|||||||
|
import express from 'express'; |
||||||
|
|
||||||
|
import { |
||||||
|
createMailRecipient, |
||||||
|
deleteMailRecipient, |
||||||
|
getMailRecipient, |
||||||
|
getMailRecipientDetail, |
||||||
|
updateMailRecipient, |
||||||
|
} from '../lib/request_handlers/mail-recipient'; |
||||||
|
|
||||||
|
const router = express.Router(); |
||||||
|
|
||||||
|
router |
||||||
|
.delete('/:uuid', deleteMailRecipient) |
||||||
|
.get('/', getMailRecipient) |
||||||
|
.get('/:uuid', getMailRecipientDetail) |
||||||
|
.post('/', createMailRecipient) |
||||||
|
.put('/:uuid', updateMailRecipient); |
||||||
|
|
||||||
|
export default router; |
@ -0,0 +1,20 @@ |
|||||||
|
import express from 'express'; |
||||||
|
|
||||||
|
import { |
||||||
|
createMailServer, |
||||||
|
deleteMailServer, |
||||||
|
getMailServer, |
||||||
|
getMailServerDetail, |
||||||
|
updateMailServer, |
||||||
|
} from '../lib/request_handlers/mail-server'; |
||||||
|
|
||||||
|
const router = express.Router(); |
||||||
|
|
||||||
|
router |
||||||
|
.delete('/:uuid', deleteMailServer) |
||||||
|
.get('/', getMailServer) |
||||||
|
.get('/:uuid', getMailServerDetail) |
||||||
|
.post('/', createMailServer) |
||||||
|
.put('/:uuid', updateMailServer); |
||||||
|
|
||||||
|
export default router; |
@ -0,0 +1,26 @@ |
|||||||
|
type AlertOverrideOverview = { |
||||||
|
level: number; |
||||||
|
mailRecipient: MailRecipientOverview; |
||||||
|
node: { name: string; uuid: string }; |
||||||
|
subnode: { name: string; short: string; uuid: string }; |
||||||
|
uuid: string; |
||||||
|
}; |
||||||
|
|
||||||
|
type AlertOverrideDetail = AlertOverrideOverview; |
||||||
|
|
||||||
|
type AlertOverrideOverviewList = { |
||||||
|
[uuid: string]: AlertOverrideOverview; |
||||||
|
}; |
||||||
|
|
||||||
|
type AlertOverrideReqQuery = { |
||||||
|
'mail-recipient': string | string[]; |
||||||
|
}; |
||||||
|
|
||||||
|
type AlertOverrideReqParams = { |
||||||
|
uuid: string; |
||||||
|
}; |
||||||
|
|
||||||
|
type AlertOverrideRequestBody = Pick<AlertOverrideDetail, 'level'> & { |
||||||
|
hostUuid: string; |
||||||
|
mailRecipientUuid: string; |
||||||
|
}; |
@ -0,0 +1,22 @@ |
|||||||
|
type MailRecipientOverview = { |
||||||
|
name: string; |
||||||
|
uuid: string; |
||||||
|
}; |
||||||
|
|
||||||
|
type MailRecipientDetail = MailRecipientOverview & { |
||||||
|
email: string; |
||||||
|
language: string; |
||||||
|
level: number; |
||||||
|
}; |
||||||
|
|
||||||
|
type MailRecipientOverviewList = { |
||||||
|
[uuid: string]: MailRecipientOverview; |
||||||
|
}; |
||||||
|
|
||||||
|
type MailRecipientParamsDictionary = { |
||||||
|
uuid: string; |
||||||
|
}; |
||||||
|
|
||||||
|
type MailRecipientRequestBody = Omit<MailRecipientDetail, 'uuid'>; |
||||||
|
|
||||||
|
type MailRecipientResponseBody = Pick<MailRecipientDetail, 'uuid'>; |
@ -0,0 +1,23 @@ |
|||||||
|
type MailServerOverview = { |
||||||
|
address: string; |
||||||
|
port: number; |
||||||
|
uuid: string; |
||||||
|
}; |
||||||
|
|
||||||
|
type MailServerDetail = MailServerOverview & { |
||||||
|
authentication: string; |
||||||
|
heloDomain: string; |
||||||
|
password?: string; |
||||||
|
security: string; |
||||||
|
username?: string; |
||||||
|
}; |
||||||
|
|
||||||
|
type MailServerOverviewList = { |
||||||
|
[uuid: string]: MailServerOverview; |
||||||
|
}; |
||||||
|
|
||||||
|
type MailServerParamsDictionary = { |
||||||
|
uuid: string; |
||||||
|
}; |
||||||
|
|
||||||
|
type MailServerRequestBody = Omit<MailServerDetail, 'uuid'>; |
Loading…
Reference in new issue