Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | 1x 1x 1x 1x 1x 1x | import axios from 'axios';
import {bind, inject, BindingScope} from '@loopback/core';
import {SecurityBindings} from '@loopback/security';
import {UserProfile} from '@logchain/components/aws';
import {EmailConfig} from '@logchain/models/scan/email-config.model';
import {Pmo} from '@logchain/models/scan/pmo.model';
import { buildAttachmentViewUrl } from '@logchain/utils/attachment-link.util';
export interface BrevoEmailParams {
templateId: number;
to: string[];
params: Record<string, unknown>;
}
@bind({scope: BindingScope.TRANSIENT})
export class BrevoService {
private readonly apiKey = process.env.BREVO_API_KEY ?? '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';
private readonly baseUrl = process.env.BREVO_BASE_URL ?? 'https://api.brevo.com/v3';
@inject(SecurityBindings.USER, {optional: true})
public current_user: UserProfile;
getCurrentUserEmail(): string | null {
return this.current_user?.email|| null;
}
getCurrentUserName(): string | null {
return this.current_user?.name || null;
}
formatProcessedAt(date: Date): string {
const sgDate = new Date(date.toLocaleString('en-US', {timeZone: 'Asia/Singapore'}));
/* const day = sgDate.toLocaleDateString('en-SG', {
weekday: 'short',
timeZone: 'Asia/Singapore',
}); */
const day = String(sgDate.getDate()).padStart(2, '0');
const month = String(sgDate.getMonth() + 1).padStart(2, '0');
const year = sgDate.getFullYear();
const hours = String(sgDate.getHours()).padStart(2, '0');
const minutes = String(sgDate.getMinutes()).padStart(2, '0');
return `${day}-${month}-${year} ${hours}:${minutes}`;
}
async sendNotificationEmail(config: EmailConfig, type: string = 'update', params?: Record<string, unknown>): Promise<void> {
//p: Pmo, remark: string = '', attachments?: any[]
if (config && config.template_id) {
/*
//Coming soon: support additional email list in config
const toList = config.additonal_email_list
? config.additonal_email_list.split(',').map(e => e.trim()).filter(Boolean)
: []; */
let pmoList = '';
let attachmentLinks = '';
switch(type){
case 'update':
if(params?.pmo_list && Array.isArray(params.pmo_list)){
pmoList = '<ul>';
let temp = '';
for(const pmoItem of params.pmo_list){
pmoList += `<li><strong>PMO Code:</strong> ${pmoItem.pmo.code}`;
const attachments = pmoItem.attachments || [];
temp = attachments.map((att: any) => {
const filename = att.file_url.split('/').pop() || 'Attachment';
const viewUrl = buildAttachmentViewUrl(att.id);
return `<a style="display: inline-block; width: 100px; height: 100px; margin: 5px; border: 1px solid #ccc; overflow: hidden;" href="${viewUrl}" target="_blank"><img style="display: block; width: 100%; height: auto; object-fit: cover;" src="${viewUrl}" alt="${filename}" /></a>`;
}).join('');
attachmentLinks += temp;
pmoList += '</li>';
}
if(attachmentLinks){
attachmentLinks = `<div style="margin-top: 10px;">${attachmentLinks}</div>`;
}
pmoList += '</ul><br/>';
}
break;
case 'reject':
if(params?.pmos && params.pmos instanceof Array){
pmoList = '<ul>';
for(const pmoItem of params.pmos){
pmoList += `<li><strong>PMO Code:</strong> ${pmoItem.code}</li>`;
}
pmoList += '</ul><br/>';
}
break;
}
await this.sendTransactionalEmail({
'templateId': config.template_id,
'to': [this.getCurrentUserEmail()!],
'params': {
'processed_by': this.getCurrentUserName(),
'processed_at': this.formatProcessedAt(new Date()),
'pmo_list': pmoList,
'attachments': attachmentLinks,
'remarks': params?.remarks ? 'Remarks: ' + params.remarks : '',
},
});
}
}
async sendTransactionalEmail(options: BrevoEmailParams): Promise<void> {
const {templateId, to, params} = options;
const recipients = to.map(email => ({email: email.trim()}));
await axios.post(
`${this.baseUrl}/smtp/email`,
{
templateId,
sender: {name: process.env.BREVO_SENDER_NAME ?? 'Logchain', email: process.env.BREVO_SENDER_EMAIL ?? ''},
to: recipients,
params,
},
{
headers: {
'api-key': this.apiKey,
'Content-Type': 'application/json',
'accept': 'application/json',
},
},
);
}
}
|