-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #52 from bcgov/feature/template-email
Implement templated roadmap functionality
- Loading branch information
Showing
43 changed files
with
1,465 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
export { default as documentController } from './document'; | ||
export { default as noteController } from './note'; | ||
export { default as permitController } from './permit'; | ||
export { default as roadmapController } from './roadmap'; | ||
export { default as submissionController } from './submission'; | ||
export { default as userController } from './user'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { NIL } from 'uuid'; | ||
|
||
import { getCurrentIdentity } from '../components/utils'; | ||
import { comsService, emailService, noteService, userService } from '../services'; | ||
|
||
import type { NextFunction, Request, Response } from '../interfaces/IExpress'; | ||
import type { Email, EmailAttachment } from '../types'; | ||
|
||
const controller = { | ||
/** | ||
* @function send | ||
* Send an email with the roadmap data | ||
*/ | ||
send: async ( | ||
req: Request<never, never, { activityId: string; selectedFileIds: Array<string>; emailData: Email }>, | ||
res: Response, | ||
next: NextFunction | ||
) => { | ||
try { | ||
if (req.body.selectedFileIds) { | ||
const attachments: Array<EmailAttachment> = []; | ||
|
||
const comsObjects = await comsService.getObjects(req.headers, req.body.selectedFileIds); | ||
|
||
// Attempt to get the requested documents from COMS | ||
// If succesful it is converted to base64 encoding and added to the attachment list | ||
const objectPromises = req.body.selectedFileIds.map(async (id) => { | ||
const { status, headers, data } = await comsService.getObject(req.headers, id); | ||
|
||
if (status === 200) { | ||
const filename = comsObjects.find((x: { id: string }) => x.id === id)?.name; | ||
if (filename) { | ||
attachments.push({ | ||
content: Buffer.from(data).toString('base64'), | ||
contentType: headers['content-type'], | ||
encoding: 'base64', | ||
filename: filename | ||
}); | ||
} else { | ||
throw new Error(`Unable to obtain filename for file ${id}`); | ||
} | ||
} | ||
}); | ||
|
||
await Promise.all(objectPromises); | ||
|
||
// All succesful so attachment list is added to payload | ||
req.body.emailData.attachments = attachments; | ||
} | ||
|
||
// Send the email | ||
const { data, status } = await emailService.email(req.body.emailData); | ||
|
||
// Add a new note on success | ||
if (status === 201) { | ||
const userId = await userService.getCurrentUserId(getCurrentIdentity(req.currentUser, NIL), NIL); | ||
|
||
let noteBody = req.body.emailData.body; | ||
if (req.body.emailData.attachments) { | ||
noteBody += '\n\nAttachments:\n'; | ||
req.body.emailData.attachments.forEach((x) => { | ||
noteBody += `${x.filename}\n`; | ||
}); | ||
} | ||
|
||
await noteService.createNote({ | ||
activityId: req.body.activityId, | ||
note: noteBody, | ||
noteType: 'Roadmap', | ||
title: 'Sent roadmap', | ||
createdAt: new Date().toISOString(), | ||
createdBy: userId | ||
}); | ||
} | ||
|
||
res.status(status).json(data); | ||
} catch (e: unknown) { | ||
next(e); | ||
} | ||
} | ||
}; | ||
|
||
export default controller; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import express from 'express'; | ||
import { roadmapController } from '../../controllers'; | ||
import { requireSomeAuth } from '../../middleware/requireSomeAuth'; | ||
import { roadmapValidator } from '../../validators'; | ||
|
||
import type { NextFunction, Request, Response } from '../../interfaces/IExpress'; | ||
|
||
const router = express.Router(); | ||
router.use(requireSomeAuth); | ||
|
||
// Send an email with the roadmap data | ||
router.put('/', roadmapValidator.send, (req: Request, res: Response, next: NextFunction): void => { | ||
roadmapController.send(req, res, next); | ||
}); | ||
|
||
export default router; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import axios from 'axios'; | ||
import config from 'config'; | ||
|
||
import type { AxiosInstance, AxiosRequestConfig } from 'axios'; | ||
import type { IncomingHttpHeaders } from 'http'; | ||
|
||
/** | ||
* @function comsAxios | ||
* Returns an Axios instance for the COMS API | ||
* @param {AxiosRequestConfig} options Axios request config options | ||
* @returns {AxiosInstance} An axios instance | ||
*/ | ||
function comsAxios(options: AxiosRequestConfig = {}): AxiosInstance { | ||
// Create axios instance | ||
const instance = axios.create({ | ||
baseURL: config.get('frontend.coms.apiPath'), | ||
timeout: 10000, | ||
...options | ||
}); | ||
|
||
return instance; | ||
} | ||
|
||
const service = { | ||
/** | ||
* @function getObject | ||
* Get an object | ||
* @param {IncomingHttpHeaders} incomingHeaders The request headers | ||
* @param {string} objectId The id for the object to get | ||
*/ | ||
async getObject(incomingHeaders: IncomingHttpHeaders, objectId: string) { | ||
const { status, headers, data } = await comsAxios({ responseType: 'arraybuffer', headers: incomingHeaders }).get( | ||
`/object/${objectId}` | ||
); | ||
return { status, headers, data }; | ||
}, | ||
|
||
/** | ||
* @function getObjects | ||
* Gets a list of objects | ||
* @param {IncomingHttpHeaders} incomingHeaders The request headers | ||
* @param {string[]} objectIds Array of object ids to get | ||
*/ | ||
async getObjects(incomingHeaders: IncomingHttpHeaders, objectIds: Array<string>) { | ||
const { data } = await comsAxios({ headers: incomingHeaders }).get('/object', { | ||
params: { objectId: objectIds } | ||
}); | ||
|
||
return data; | ||
} | ||
}; | ||
|
||
export default service; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import axios from 'axios'; | ||
import config from 'config'; | ||
|
||
import type { AxiosInstance } from 'axios'; | ||
import type { Email } from '../types'; | ||
|
||
/** | ||
* @function getToken | ||
* Gets Auth token using CHES client credentials | ||
* @returns | ||
*/ | ||
async function getToken() { | ||
const response = await axios({ | ||
method: 'POST', | ||
url: config.get('server.ches.tokenUrl'), | ||
data: { | ||
grant_type: 'client_credentials', | ||
client_id: config.get('server.ches.clientId'), | ||
client_secret: config.get('server.ches.clientSecret') | ||
}, | ||
headers: { | ||
'Content-type': 'application/x-www-form-urlencoded' | ||
}, | ||
withCredentials: true | ||
}); | ||
return response.data.access_token; | ||
} | ||
/** | ||
* @function chesAxios | ||
* Returns an Axios instance with Authorization header | ||
* @param {AxiosRequestConfig} options Axios request config options | ||
* @returns {AxiosInstance} An axios instance | ||
*/ | ||
function chesAxios(): AxiosInstance { | ||
// Create axios instance | ||
const chesAxios = axios.create({ | ||
baseURL: config.get('server.ches.apiPath'), | ||
timeout: 10000 | ||
}); | ||
// Add bearer token | ||
chesAxios.interceptors.request.use(async (config) => { | ||
const token = await getToken(); | ||
const auth = token ? `Bearer ${token}` : ''; | ||
config.headers['Authorization'] = auth; | ||
return config; | ||
}); | ||
return chesAxios; | ||
} | ||
|
||
const service = { | ||
/** | ||
* @function email | ||
* Sends an email with CHES service | ||
* @param emailData | ||
* @returns Axios response status and data | ||
*/ | ||
email: async (emailData: Email) => { | ||
try { | ||
const { data, status } = await chesAxios().post('/email', emailData, { | ||
headers: { | ||
'Content-Type': 'application/json' | ||
}, | ||
maxContentLength: Infinity, | ||
maxBodyLength: Infinity | ||
}); | ||
return { data, status }; | ||
} catch (e: unknown) { | ||
if (axios.isAxiosError(e)) { | ||
return { | ||
data: e.response?.data.errors[0].message, | ||
status: e.response ? e.response.status : 500 | ||
}; | ||
} else { | ||
return { | ||
data: 'Email error', | ||
status: 500 | ||
}; | ||
} | ||
} | ||
}, | ||
|
||
/** | ||
* @function health | ||
* Checks CHES service health | ||
* @returns Axios response status and data | ||
*/ | ||
health: async () => { | ||
const { data, status } = await chesAxios().get('/health'); | ||
return { data, status }; | ||
} | ||
}; | ||
|
||
export default service; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
export { default as submissionService } from './submission'; | ||
export { default as comsService } from './coms'; | ||
export { default as documentService } from './document'; | ||
export { default as emailService } from './email'; | ||
export { default as noteService } from './note'; | ||
export { default as permitService } from './permit'; | ||
export { default as submissionService } from './submission'; | ||
export { default as userService } from './user'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { EmailAttachment } from './EmailAttachment'; | ||
|
||
export type Email = { | ||
bcc?: Array<string>; | ||
bodyType: string; | ||
body: string; | ||
cc?: Array<string>; | ||
delayTS?: number; | ||
encoding?: string; | ||
from: string; | ||
priority?: string; | ||
subject: string; | ||
to: Array<string>; | ||
tag?: string; | ||
attachments?: Array<EmailAttachment>; | ||
}; |
Oops, something went wrong.