@futdevpro/nts-dynamo 1.7.16 → 1.7.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +171 -0
- package/lib/_constants/mocks/app-extended-server.mock.d.ts.map +1 -1
- package/lib/_constants/mocks/app-extended-server.mock.js.map +1 -1
- package/lib/_constants/mocks/app-server.mock.d.ts.map +1 -1
- package/lib/_constants/mocks/app-server.mock.js.map +1 -1
- package/lib/_constants/mocks/data-model.mock.d.ts.map +1 -1
- package/lib/_constants/mocks/data-model.mock.js.map +1 -1
- package/lib/_constants/mocks/email-service-collection.mock.d.ts.map +1 -1
- package/lib/_constants/mocks/email-service-collection.mock.js.map +1 -1
- package/lib/_constants/mocks/email-service.mock.js +3 -3
- package/lib/_constants/mocks/email-service.mock.js.map +1 -1
- package/lib/_constants/mocks/endpoint.mock.d.ts.map +1 -1
- package/lib/_constants/mocks/endpoint.mock.js.map +1 -1
- package/lib/_constants/mocks/socket-server.mock.d.ts.map +1 -1
- package/lib/_constants/mocks/socket-server.mock.js.map +1 -1
- package/lib/_enums/index.js +1 -1
- package/lib/_enums/index.js.map +1 -1
- package/lib/_models/control-models/api-call-params.control-model.d.ts +2 -2
- package/lib/_models/control-models/api-call-params.control-model.d.ts.map +1 -1
- package/lib/_models/control-models/api-call-params.control-model.js.map +1 -1
- package/lib/_models/control-models/app-system-controls.control-model copy.d.ts.map +1 -1
- package/lib/_models/control-models/app-system-controls.control-model copy.js.map +1 -1
- package/lib/_models/control-models/app-system-controls.control-model.d.ts.map +1 -1
- package/lib/_models/control-models/app-system-controls.control-model.js.map +1 -1
- package/lib/_models/control-models/endpoint-params.control-model.d.ts.map +1 -1
- package/lib/_models/control-models/endpoint-params.control-model.js +15 -9
- package/lib/_models/control-models/endpoint-params.control-model.js.map +1 -1
- package/lib/_models/control-models/http-settings.control-model.d.ts +1 -1
- package/lib/_models/control-models/http-settings.control-model.d.ts.map +1 -1
- package/lib/_models/control-models/http-settings.control-model.js +3 -1
- package/lib/_models/control-models/http-settings.control-model.js.map +1 -1
- package/lib/_models/control-models/socket-client-service-params.control-model.js.map +1 -1
- package/lib/_models/control-models/socket-event.control-model.js.map +1 -1
- package/lib/_models/control-models/socket-presence.control-model.js.map +1 -1
- package/lib/_modules/custom-data/custom-data.controller.d.ts.map +1 -1
- package/lib/_modules/custom-data/custom-data.controller.js +2 -1
- package/lib/_modules/custom-data/custom-data.controller.js.map +1 -1
- package/lib/_modules/custom-data/get-custom-data-routing-module.util.d.ts.map +1 -1
- package/lib/_modules/custom-data/get-custom-data-routing-module.util.js.map +1 -1
- package/lib/_modules/test/get-test-routing-module.util.d.ts.map +1 -1
- package/lib/_modules/test/get-test-routing-module.util.js.map +1 -1
- package/lib/_modules/test/test.controller.d.ts.map +1 -1
- package/lib/_modules/test/test.controller.js.map +1 -1
- package/lib/_modules/usage/get-usage-routing-module.util.d.ts.map +1 -1
- package/lib/_modules/usage/get-usage-routing-module.util.js +1 -1
- package/lib/_modules/usage/get-usage-routing-module.util.js.map +1 -1
- package/lib/_modules/usage/usage.controller.d.ts.map +1 -1
- package/lib/_modules/usage/usage.controller.js +15 -14
- package/lib/_modules/usage/usage.controller.js.map +1 -1
- package/lib/_modules/usage/usage.data-service.d.ts +3 -1
- package/lib/_modules/usage/usage.data-service.d.ts.map +1 -1
- package/lib/_modules/usage/usage.data-service.js +24 -16
- package/lib/_modules/usage/usage.data-service.js.map +1 -1
- package/lib/_services/base/data.service.d.ts.map +1 -1
- package/lib/_services/base/data.service.js +45 -23
- package/lib/_services/base/data.service.js.map +1 -1
- package/lib/_services/base/db.service.d.ts.map +1 -1
- package/lib/_services/base/db.service.js +82 -53
- package/lib/_services/base/db.service.js.map +1 -1
- package/lib/_services/base/singleton.service.d.ts.map +1 -1
- package/lib/_services/base/singleton.service.js.map +1 -1
- package/lib/_services/core/api.service.d.ts +21 -13
- package/lib/_services/core/api.service.d.ts.map +1 -1
- package/lib/_services/core/api.service.js +192 -143
- package/lib/_services/core/api.service.js.map +1 -1
- package/lib/_services/core/auth.service.d.ts.map +1 -1
- package/lib/_services/core/auth.service.js.map +1 -1
- package/lib/_services/core/email.service.d.ts +50 -36
- package/lib/_services/core/email.service.d.ts.map +1 -1
- package/lib/_services/core/email.service.js +329 -94
- package/lib/_services/core/email.service.js.map +1 -1
- package/lib/_services/core/global.service.d.ts.map +1 -1
- package/lib/_services/core/global.service.js +30 -19
- package/lib/_services/core/global.service.js.map +1 -1
- package/lib/_services/route/controller.service.d.ts.map +1 -1
- package/lib/_services/route/controller.service.js.map +1 -1
- package/lib/_services/route/routing-module.service.d.ts.map +1 -1
- package/lib/_services/route/routing-module.service.js +2 -2
- package/lib/_services/route/routing-module.service.js.map +1 -1
- package/lib/_services/server/app-extended.server.d.ts.map +1 -1
- package/lib/_services/server/app-extended.server.js +19 -14
- package/lib/_services/server/app-extended.server.js.map +1 -1
- package/lib/_services/server/app-extended.server.spec.js +1 -0
- package/lib/_services/server/app-extended.server.spec.js.map +1 -1
- package/lib/_services/server/app.server.d.ts +4 -3
- package/lib/_services/server/app.server.d.ts.map +1 -1
- package/lib/_services/server/app.server.js +107 -52
- package/lib/_services/server/app.server.js.map +1 -1
- package/lib/_services/server/app.server.spec.js +1 -0
- package/lib/_services/server/app.server.spec.js.map +1 -1
- package/lib/_services/shared.static-service.js.map +1 -1
- package/lib/_services/socket/socket-client.service.js.map +1 -1
- package/lib/_services/socket/socket-server.service.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/nodemon.json +3 -1
- package/package.json +9 -8
- package/src/_constants/mocks/app-extended-server.mock.ts +6 -2
- package/src/_constants/mocks/app-server.mock.ts +7 -1
- package/src/_constants/mocks/data-model.mock.ts +2 -2
- package/src/_constants/mocks/email-service-collection.mock.ts +2 -1
- package/src/_constants/mocks/email-service.mock.ts +2 -2
- package/src/_constants/mocks/endpoint.mock.ts +28 -26
- package/src/_constants/mocks/socket-server.mock.ts +12 -4
- package/src/_enums/index.ts +1 -1
- package/src/_models/control-models/api-call-params.control-model.ts +3 -2
- package/src/_models/control-models/app-system-controls.control-model copy.ts +1 -1
- package/src/_models/control-models/app-system-controls.control-model.ts +1 -1
- package/src/_models/control-models/endpoint-params.control-model.ts +39 -16
- package/src/_models/control-models/http-settings.control-model.ts +4 -2
- package/src/_modules/custom-data/custom-data.controller.ts +55 -51
- package/src/_modules/custom-data/get-custom-data-routing-module.util.ts +7 -3
- package/src/_modules/test/get-test-routing-module.util.ts +7 -3
- package/src/_modules/test/test.controller.ts +98 -96
- package/src/_modules/usage/get-usage-routing-module.util.ts +8 -4
- package/src/_modules/usage/usage.controller.ts +108 -102
- package/src/_modules/usage/usage.data-service.ts +54 -28
- package/src/_services/base/data.service.ts +133 -34
- package/src/_services/base/db.service.ts +254 -171
- package/src/_services/base/singleton.service.ts +1 -1
- package/src/_services/core/api.service.ts +348 -218
- package/src/_services/core/auth.service.ts +2 -0
- package/src/_services/core/email.service.ts +537 -129
- package/src/_services/core/global.service.ts +56 -26
- package/src/_services/route/controller.service.ts +3 -1
- package/src/_services/route/routing-module.service.ts +33 -16
- package/src/_services/server/app-extended.server.spec.ts +22 -17
- package/src/_services/server/app-extended.server.ts +108 -45
- package/src/_services/server/app.server.spec.ts +17 -12
- package/src/_services/server/app.server.ts +264 -138
|
@@ -2,9 +2,56 @@
|
|
|
2
2
|
import * as FileSystem from 'fs';
|
|
3
3
|
import * as Path from 'path';
|
|
4
4
|
import * as NodeMailer from 'nodemailer';
|
|
5
|
+
|
|
5
6
|
import { Options as MailOptions, Attachment } from 'nodemailer/lib/mailer';
|
|
6
7
|
|
|
7
|
-
import { Dynamo_Error, Dynamo_Log } from '@futdevpro/fsm-dynamo';
|
|
8
|
+
import { Dynamo_Array, Dynamo_Error, Dynamo_Log } from '@futdevpro/fsm-dynamo';
|
|
9
|
+
|
|
10
|
+
export interface DynamoNTS_EmailServiceSettings {
|
|
11
|
+
host: string,
|
|
12
|
+
port: number,
|
|
13
|
+
email: string,
|
|
14
|
+
pass: string,
|
|
15
|
+
senderName: string,
|
|
16
|
+
rootPath: string,
|
|
17
|
+
templateComponents?: DynamoNTS_EmailTemplateComponent[],
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class DynamoNTS_EmailTemplateComponent {
|
|
21
|
+
name: string;
|
|
22
|
+
selector: string;
|
|
23
|
+
|
|
24
|
+
templatePath?: string;
|
|
25
|
+
template?: string;
|
|
26
|
+
|
|
27
|
+
stylePath?: string;
|
|
28
|
+
styles?: string;
|
|
29
|
+
|
|
30
|
+
headerLinks?: string = '';
|
|
31
|
+
|
|
32
|
+
properties?: string[] = [];
|
|
33
|
+
subComponentSelectors?: string[] = [];
|
|
34
|
+
|
|
35
|
+
constructor(
|
|
36
|
+
set?: DynamoNTS_EmailTemplateComponent
|
|
37
|
+
) {
|
|
38
|
+
if (set) {
|
|
39
|
+
Object.assign(this, set);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface DynamoNTS_SendEmailSettings<T = { [propertyKey: string]: string; }> {
|
|
45
|
+
to: string;
|
|
46
|
+
subject: string;
|
|
47
|
+
/** direct email content, if provided, this will be used */
|
|
48
|
+
content?: string;
|
|
49
|
+
|
|
50
|
+
templateComponentName: string;
|
|
51
|
+
templateProperties?: T;
|
|
52
|
+
|
|
53
|
+
attachments?: Attachment[];
|
|
54
|
+
}
|
|
8
55
|
|
|
9
56
|
/**
|
|
10
57
|
*
|
|
@@ -15,142 +62,119 @@ export class DynamoNTS_EmailService {
|
|
|
15
62
|
private nmTransporter: NodeMailer.Transporter;
|
|
16
63
|
private senderName: string;
|
|
17
64
|
private senderNEmail: string;
|
|
18
|
-
|
|
19
|
-
|
|
65
|
+
|
|
66
|
+
private components: DynamoNTS_EmailTemplateComponent[] = [];
|
|
67
|
+
private componentsBySelector: {
|
|
68
|
+
[selector: string]: DynamoNTS_EmailTemplateComponent
|
|
20
69
|
} = {};
|
|
21
|
-
private
|
|
22
|
-
[
|
|
70
|
+
private componentsByName: {
|
|
71
|
+
[componentName: string]: DynamoNTS_EmailTemplateComponent
|
|
23
72
|
} = {};
|
|
24
|
-
|
|
73
|
+
|
|
74
|
+
private readonly styleLimitWarning: number = 16;
|
|
25
75
|
|
|
26
76
|
defaultErrorUserMsg =
|
|
27
77
|
`We encountered an uncought Email Service Error, ` +
|
|
28
78
|
`\nplease contact the responsible development team.`;
|
|
29
79
|
|
|
30
80
|
constructor (
|
|
31
|
-
set:
|
|
32
|
-
host: string,
|
|
33
|
-
port: number,
|
|
34
|
-
email: string,
|
|
35
|
-
pass: string,
|
|
36
|
-
senderName: string,
|
|
37
|
-
rootPath: string,
|
|
38
|
-
templatePaths: {
|
|
39
|
-
[templateName: string]: string
|
|
40
|
-
},
|
|
41
|
-
}
|
|
81
|
+
set: DynamoNTS_EmailServiceSettings
|
|
42
82
|
) {
|
|
83
|
+
this.serviceName = this.constructor?.name;
|
|
84
|
+
this.senderName = set.senderName;
|
|
85
|
+
this.senderNEmail = `${set.senderName} <${set.email}>`;
|
|
86
|
+
this.nmTransporter = NodeMailer.createTransport({
|
|
87
|
+
host: set.host,
|
|
88
|
+
port: set.port,
|
|
89
|
+
auth: {
|
|
90
|
+
user: set.email,
|
|
91
|
+
pass: set.pass,
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
this.components = set.templateComponents ?? [];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async asyncPostConstruct(): Promise<void> {
|
|
43
99
|
try {
|
|
44
|
-
this.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
auth: {
|
|
52
|
-
user: set.email,
|
|
53
|
-
pass: set.pass
|
|
54
|
-
}
|
|
55
|
-
});
|
|
100
|
+
if (this.components) {
|
|
101
|
+
await Dynamo_Array.asyncForEach(
|
|
102
|
+
this.components,
|
|
103
|
+
async (component: DynamoNTS_EmailTemplateComponent): Promise<void> => {
|
|
104
|
+
await this.loadComponent(component);
|
|
105
|
+
}
|
|
106
|
+
);
|
|
56
107
|
|
|
57
|
-
|
|
58
|
-
for (let key in set.templatePaths) {
|
|
59
|
-
this.loadTemplate(key, set.rootPath, set.templatePaths[key]);
|
|
60
|
-
}
|
|
61
|
-
} else {
|
|
62
|
-
this.constructionFinished();
|
|
108
|
+
this.connectComponents();
|
|
63
109
|
}
|
|
110
|
+
|
|
111
|
+
Dynamo_Log.success(`\nEmailService construction (${this.senderName}) Finished!`);
|
|
64
112
|
} catch (error) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
113
|
+
throw new Dynamo_Error({
|
|
114
|
+
...this._getDefaultErrorSettings('asyncPostConstruct', error, 'SYSTEM'),
|
|
68
115
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
116
|
+
errorCode: 'NTS-ES0-APC0',
|
|
117
|
+
message:
|
|
118
|
+
`\nDynamoBEEmailService ERROR, ` +
|
|
119
|
+
`\nThe emailService construction failed for ${this.serviceName}.`,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
74
122
|
}
|
|
75
123
|
|
|
76
124
|
/**
|
|
77
125
|
*
|
|
78
126
|
* @param set
|
|
79
127
|
*/
|
|
80
|
-
public async sendEmail(
|
|
81
|
-
set:
|
|
82
|
-
|
|
83
|
-
subject: string,
|
|
84
|
-
content?: string,
|
|
85
|
-
useTemplate?: string,
|
|
86
|
-
templateProperties?: {
|
|
87
|
-
[propertyKey: string]: string
|
|
88
|
-
},
|
|
89
|
-
attachments?: Attachment[]
|
|
90
|
-
},
|
|
91
|
-
issuer?: string,
|
|
128
|
+
public async sendEmail<T>(
|
|
129
|
+
set: DynamoNTS_SendEmailSettings<T>,
|
|
130
|
+
issuer: string
|
|
92
131
|
): Promise<void> {
|
|
93
132
|
try {
|
|
94
133
|
let content: string;
|
|
95
134
|
|
|
96
135
|
if (set.content) {
|
|
97
|
-
content = set.content
|
|
136
|
+
content = set.content;
|
|
137
|
+
|
|
98
138
|
} else {
|
|
99
|
-
if (!set.
|
|
139
|
+
if (!set.templateComponentName) {
|
|
100
140
|
throw new Dynamo_Error({
|
|
101
141
|
...this._getDefaultErrorSettings(
|
|
102
142
|
'sendEmail',
|
|
103
|
-
new Error(
|
|
143
|
+
new Error(
|
|
144
|
+
`No email template component is given!`
|
|
145
|
+
),
|
|
104
146
|
issuer
|
|
105
147
|
),
|
|
106
148
|
|
|
107
|
-
errorCode: 'NTS-
|
|
149
|
+
errorCode: 'NTS-ES0-SE1',
|
|
108
150
|
});
|
|
109
151
|
}
|
|
110
152
|
|
|
111
|
-
if (!this.
|
|
153
|
+
if (!this.componentsByName[set.templateComponentName]) {
|
|
112
154
|
throw new Dynamo_Error({
|
|
113
155
|
...this._getDefaultErrorSettings(
|
|
114
156
|
'sendEmail',
|
|
115
|
-
new Error(
|
|
157
|
+
new Error(
|
|
158
|
+
`No email template component found with this name! (${set.templateComponentName})`
|
|
159
|
+
),
|
|
116
160
|
issuer
|
|
117
161
|
),
|
|
118
162
|
|
|
119
|
-
errorCode: 'NTS-
|
|
163
|
+
errorCode: 'NTS-ES0-SE2',
|
|
164
|
+
additionalContent: {
|
|
165
|
+
availableComponenets: Object.keys(this.componentsByName),
|
|
166
|
+
},
|
|
120
167
|
});
|
|
121
168
|
}
|
|
122
169
|
|
|
123
|
-
content = this.
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
this.templatePropertyKeys[set.useTemplate].forEach((key: string, index: number) => {
|
|
129
|
-
props += `${key}${index != this.templatePropertyKeys[set.useTemplate].length - 1 ? ', ' : ''}`;
|
|
130
|
-
});
|
|
131
|
-
Dynamo_Log.error('\nDynamoBEEmailService ERROR: INVALID sendEmail settings', set);
|
|
132
|
-
|
|
133
|
-
throw new Dynamo_Error({
|
|
134
|
-
...this._getDefaultErrorSettings(
|
|
135
|
-
'sendEmail',
|
|
136
|
-
new Error(`TemplateProperties missing! properties needed: ${props}`),
|
|
137
|
-
issuer
|
|
138
|
-
),
|
|
139
|
-
|
|
140
|
-
errorCode: 'NTS-ES4-103',
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
this.templatePropertyKeys[set.useTemplate].forEach((propertyKey: string) => {
|
|
144
|
-
if (!set.templateProperties[propertyKey]) {
|
|
145
|
-
Dynamo_Log.error(`TemplateProperty missing! (${propertyKey})`);
|
|
146
|
-
}
|
|
147
|
-
const reg = new RegExp(`{{${propertyKey}}}`, 'g')
|
|
148
|
-
content = content.replace(reg, set.templateProperties[propertyKey]);
|
|
149
|
-
});
|
|
150
|
-
}
|
|
170
|
+
content = this.compileTemplateComponent(
|
|
171
|
+
set.templateComponentName,
|
|
172
|
+
set.templateProperties,
|
|
173
|
+
issuer
|
|
174
|
+
);
|
|
151
175
|
}
|
|
152
176
|
|
|
153
|
-
|
|
177
|
+
const mailOptions: MailOptions = {
|
|
154
178
|
from: this.senderNEmail,
|
|
155
179
|
to: set.to,
|
|
156
180
|
subject: set.subject,
|
|
@@ -158,8 +182,8 @@ export class DynamoNTS_EmailService {
|
|
|
158
182
|
attachments: set.attachments,
|
|
159
183
|
};
|
|
160
184
|
|
|
161
|
-
await new Promise<void>((resolve, reject) => {
|
|
162
|
-
this.nmTransporter.sendMail(mailOptions, (error
|
|
185
|
+
await new Promise<void>((resolve, reject): void => {
|
|
186
|
+
this.nmTransporter.sendMail(mailOptions, (error): void => {
|
|
163
187
|
if (error) {
|
|
164
188
|
reject(error);
|
|
165
189
|
} else {
|
|
@@ -168,55 +192,419 @@ export class DynamoNTS_EmailService {
|
|
|
168
192
|
});
|
|
169
193
|
});
|
|
170
194
|
} catch (error) {
|
|
171
|
-
if (error?.includes?.('all recipients were rejected')) {
|
|
195
|
+
if ((error as Error).message?.includes?.('all recipients were rejected')) {
|
|
172
196
|
throw new Dynamo_Error({
|
|
173
197
|
...this._getDefaultErrorSettings('sendEmail', error, issuer),
|
|
174
198
|
|
|
175
|
-
errorCode: 'NTS-
|
|
176
|
-
userMessage: `Can't send mail to ${set.to}
|
|
177
|
-
|
|
199
|
+
errorCode: 'NTS-ES0-SE4',
|
|
200
|
+
userMessage: `Can't send mail to ${set.to}!`,
|
|
201
|
+
message: `sendEmail failed to ${set.to}`,
|
|
202
|
+
});
|
|
203
|
+
|
|
178
204
|
} else {
|
|
179
205
|
throw new Dynamo_Error({
|
|
180
206
|
...this._getDefaultErrorSettings('sendEmail', error, issuer),
|
|
181
207
|
|
|
182
|
-
errorCode: 'NTS-
|
|
183
|
-
message: `
|
|
208
|
+
errorCode: 'NTS-ES0-SE0',
|
|
209
|
+
message: `sendEmail failed to ${set.to}`,
|
|
184
210
|
});
|
|
185
211
|
}
|
|
186
212
|
}
|
|
187
213
|
}
|
|
188
214
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
* @returns
|
|
195
|
-
*/
|
|
196
|
-
private async loadTemplate(templateName: string, rootPath: string, templatePath: string): Promise<void> {
|
|
215
|
+
private compileTemplateComponent<T>(
|
|
216
|
+
componentName: string,
|
|
217
|
+
componentProperties:T,
|
|
218
|
+
issuer: string
|
|
219
|
+
): string {
|
|
197
220
|
try {
|
|
198
|
-
this.
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
221
|
+
if (!this.componentsByName[componentName]) {
|
|
222
|
+
throw new Dynamo_Error({
|
|
223
|
+
...this._getDefaultErrorSettings(
|
|
224
|
+
'setupComponent',
|
|
225
|
+
new Error(`No email component found with this name! (${componentName})`),
|
|
226
|
+
issuer
|
|
227
|
+
),
|
|
228
|
+
|
|
229
|
+
errorCode: 'NTS-ES0-SC1',
|
|
230
|
+
additionalContent: {
|
|
231
|
+
availableComponenets: Object.keys(this.componentsByName),
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const component: DynamoNTS_EmailTemplateComponent = this.componentsByName[componentName];
|
|
237
|
+
let template: string = this.compileHTMLMainFrame(component);
|
|
238
|
+
|
|
239
|
+
template = template.replace('<nts-content>', '');
|
|
240
|
+
template = this.compileComponentProperties<T>(
|
|
241
|
+
component,
|
|
242
|
+
componentProperties,
|
|
243
|
+
template,
|
|
244
|
+
issuer
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
component.subComponentSelectors.forEach((subComponentSelector: string): void => {
|
|
248
|
+
while (template.includes(`<nts-${subComponentSelector}`)) {
|
|
249
|
+
template = this.compileSubComponent<T>(
|
|
250
|
+
subComponentSelector, componentProperties, template, issuer
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
template = this.templateTrim(template);
|
|
256
|
+
|
|
257
|
+
return template;
|
|
258
|
+
} catch (error) {
|
|
259
|
+
throw new Dynamo_Error({
|
|
260
|
+
...this._getDefaultErrorSettings('setupComponent', error, issuer),
|
|
261
|
+
|
|
262
|
+
errorCode: 'NTS-ES0-SC0',
|
|
263
|
+
message: `setupComponent failed! (${componentName})`,
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
private compileHTMLMainFrame(component: DynamoNTS_EmailTemplateComponent): string {
|
|
269
|
+
const allLinks: string[] = [];
|
|
270
|
+
const allStyles: string[] = [];
|
|
271
|
+
|
|
272
|
+
if (component.headerLinks) {
|
|
273
|
+
allLinks.push(component.headerLinks);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (component.styles) {
|
|
277
|
+
allStyles.push(component.styles);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
component.subComponentSelectors.forEach((subComponentSelector: string): void => {
|
|
281
|
+
const subComponent: DynamoNTS_EmailTemplateComponent =
|
|
282
|
+
this.componentsBySelector[subComponentSelector];
|
|
283
|
+
|
|
284
|
+
if (subComponent.headerLinks) {
|
|
285
|
+
allLinks.push(subComponent.headerLinks.trim());
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (subComponent.styles) {
|
|
289
|
+
allStyles.push(subComponent.styles.trim());
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
const styles = this.styleTrim(allStyles.join(''));
|
|
294
|
+
const styleSize = this.getStringKBSize(styles);
|
|
295
|
+
|
|
296
|
+
if (this.styleLimitWarning < styleSize) {
|
|
297
|
+
Dynamo_Log.warn(
|
|
298
|
+
`\nDynamoNTS EmailService WARNING (${this.serviceName}), ` +
|
|
299
|
+
`\nEmail template styles are too big! (${styleSize}KB)` +
|
|
300
|
+
`\ncomponent: ${component.name} (${component.selector})` +
|
|
301
|
+
`\nSome email clients may not support this!` +
|
|
302
|
+
`\nThe limit is ${this.styleLimitWarning}KB!`
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return `\n<!DOCTYPE html>` +
|
|
307
|
+
`\n<html>` +
|
|
308
|
+
`\n <head>` +
|
|
309
|
+
`\n ${allLinks.join('')}` +
|
|
310
|
+
`\n` +
|
|
311
|
+
`\n <style>` +
|
|
312
|
+
`\n ${styles}` +
|
|
313
|
+
`\n </style>` +
|
|
314
|
+
`\n </head>` +
|
|
315
|
+
`\n <body>` +
|
|
316
|
+
`\n ${component.template}` +
|
|
317
|
+
`\n </body>` +
|
|
318
|
+
`\n</html> `;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/** trims all rows and remove everything between /*...*\/ */
|
|
322
|
+
private styleTrim(style: string): string {
|
|
323
|
+
let result: string = style.split('\n').map((row: string): string => row.trim()).join('');
|
|
324
|
+
|
|
325
|
+
while (result.includes('/*')) {
|
|
326
|
+
const start = result.indexOf('/*');
|
|
327
|
+
const end = result.indexOf('*/', start) + 2;
|
|
328
|
+
|
|
329
|
+
result = result.substring(0, start) + result.substring(end);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return result;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/** removes HTML comments */
|
|
336
|
+
private templateTrim(template: string): string {
|
|
337
|
+
let result: string = template;
|
|
338
|
+
|
|
339
|
+
while (result.includes('<!--')) {
|
|
340
|
+
const start = result.indexOf('<!--');
|
|
341
|
+
const end = result.indexOf('-->', start) + 3;
|
|
342
|
+
|
|
343
|
+
result = result.substring(0, start) + result.substring(end);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return result;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
private getStringKBSize(str: string): number {
|
|
351
|
+
const b: number = str.length * 2;
|
|
352
|
+
|
|
353
|
+
return b / 1024;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
private compileComponentProperties<T>(
|
|
357
|
+
component: DynamoNTS_EmailTemplateComponent,
|
|
358
|
+
componentProperties: T,
|
|
359
|
+
template: string,
|
|
360
|
+
issuer: string
|
|
361
|
+
): string {
|
|
362
|
+
component.properties.forEach((propertyKey: string): void => {
|
|
363
|
+
if (!componentProperties[propertyKey]) {
|
|
364
|
+
throw new Dynamo_Error({
|
|
365
|
+
...this._getDefaultErrorSettings(
|
|
366
|
+
'setupComponent',
|
|
367
|
+
new Error(
|
|
368
|
+
`ComponentProperty missing from input! ${propertyKey} for ${component.name}`
|
|
369
|
+
),
|
|
370
|
+
issuer
|
|
371
|
+
),
|
|
372
|
+
|
|
373
|
+
errorCode: 'NTS-ES0-SC4',
|
|
374
|
+
additionalContent: {
|
|
375
|
+
componentProperties: Object.keys(componentProperties),
|
|
376
|
+
},
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const propReg = new RegExp(`{{${propertyKey}}}`, 'g');
|
|
381
|
+
|
|
382
|
+
template = template.replace(propReg, componentProperties[propertyKey]);
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
return template;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
private compileSubComponent<T>(
|
|
389
|
+
subComponentSelector: string,
|
|
390
|
+
componentProperties: T,
|
|
391
|
+
template: string,
|
|
392
|
+
issuer: string
|
|
393
|
+
): string {
|
|
394
|
+
const subComponent: DynamoNTS_EmailTemplateComponent =
|
|
395
|
+
this.componentsBySelector[subComponentSelector];
|
|
396
|
+
|
|
397
|
+
if (!subComponent) {
|
|
398
|
+
throw new Dynamo_Error({
|
|
399
|
+
...this._getDefaultErrorSettings(
|
|
400
|
+
'setupComponent',
|
|
401
|
+
new Error(`SubComponent missing from components! (${subComponentSelector})`),
|
|
402
|
+
issuer
|
|
403
|
+
),
|
|
404
|
+
|
|
405
|
+
errorCode: 'NTS-ES0-SC2',
|
|
406
|
+
additionalContent: this.componentsBySelector,
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
let subComponentTemplate: string = subComponent.template;
|
|
411
|
+
const startTag = `<nts-${subComponent.selector}`;
|
|
412
|
+
const endTag = `</nts-${subComponent.selector}>`;
|
|
413
|
+
const tagHTMLProperties: string =
|
|
414
|
+
template.split(startTag)[1].split('>')[0];
|
|
415
|
+
let componentContent: string;
|
|
416
|
+
|
|
417
|
+
if (!tagHTMLProperties) {
|
|
418
|
+
componentContent = template.split(`${startTag}>`)[1].split(endTag)[0];
|
|
419
|
+
} else {
|
|
420
|
+
componentContent = template.split(startTag)[1].split('>')[1].split(endTag)[0];
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
const contentReg = new RegExp(`<nts-content>`, 'g');
|
|
424
|
+
|
|
425
|
+
subComponentTemplate = subComponentTemplate.replace(contentReg, componentContent);
|
|
426
|
+
subComponentTemplate = this.compileComponentProperties<T>(
|
|
427
|
+
subComponent,
|
|
428
|
+
componentProperties,
|
|
429
|
+
subComponentTemplate,
|
|
430
|
+
issuer
|
|
431
|
+
);
|
|
432
|
+
|
|
433
|
+
const startTagReg = new RegExp(startTag, 'g');
|
|
434
|
+
const endTagReg = new RegExp(endTag, 'g');
|
|
435
|
+
|
|
436
|
+
template = template.replace(startTagReg, '<div');
|
|
437
|
+
template = template.replace(componentContent, subComponentTemplate);
|
|
438
|
+
template = template.replace(endTagReg, '</div>');
|
|
439
|
+
|
|
440
|
+
/* while (template.includes(`<nts-${subComponent.selector}`)) {
|
|
441
|
+
const replaceStartIndex = template.indexOf(`<nts-${subComponent.selector}`);
|
|
442
|
+
const replaceEndIndex = template.indexOf(endTag, replaceStartIndex) + endTag.length;
|
|
443
|
+
|
|
444
|
+
template =
|
|
445
|
+
template.substring(0, replaceStartIndex) +
|
|
446
|
+
subComponentCompiled +
|
|
447
|
+
template.substring(replaceEndIndex);
|
|
448
|
+
} */
|
|
449
|
+
|
|
450
|
+
return template;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
private async loadComponent(component: DynamoNTS_EmailTemplateComponent): Promise<void> {
|
|
454
|
+
try {
|
|
455
|
+
if (this.componentsBySelector[component.selector]) {
|
|
456
|
+
throw new Dynamo_Error({
|
|
457
|
+
...this._getDefaultErrorSettings('loadComponent', new Error(), 'SYSTEM'),
|
|
209
458
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
459
|
+
errorCode: 'NTS-ES0-LC1',
|
|
460
|
+
message: `Template already loaded! (${component.name})`,
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (!component.templatePath && !component.template) {
|
|
465
|
+
throw new Dynamo_Error({
|
|
466
|
+
...this._getDefaultErrorSettings('loadComponent', new Error(), 'SYSTEM'),
|
|
467
|
+
|
|
468
|
+
errorCode: 'NTS-ES0-LC2',
|
|
469
|
+
message: `Component missing template and templatePath! (${component.name})`,
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
if (!component.template) {
|
|
474
|
+
await new Promise<void>((resolve, reject): void => {
|
|
475
|
+
FileSystem.readFile(component.templatePath, 'utf8' , (err, template): void => {
|
|
476
|
+
if (err || !template) {
|
|
477
|
+
if (!err) {
|
|
478
|
+
err = new Error(
|
|
479
|
+
`Couldn't load email component's template; ${component.name} ` +
|
|
480
|
+
`from ${component.templatePath}`
|
|
481
|
+
);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
reject(
|
|
485
|
+
new Dynamo_Error({
|
|
486
|
+
...this._getDefaultErrorSettings('loadTemplate', err, 'SYSTEM'),
|
|
487
|
+
|
|
488
|
+
errorCode: 'NTS-ES0-LC3',
|
|
489
|
+
})
|
|
490
|
+
);
|
|
491
|
+
|
|
492
|
+
return;
|
|
213
493
|
}
|
|
494
|
+
|
|
495
|
+
component.template = template;
|
|
496
|
+
|
|
214
497
|
resolve();
|
|
215
|
-
}
|
|
498
|
+
});
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
if (component.stylePath) {
|
|
503
|
+
await new Promise<void>((resolve, reject): void => {
|
|
504
|
+
FileSystem.readFile(component.stylePath, 'utf8' , (err, styles): void => {
|
|
505
|
+
if (err || !styles) {
|
|
506
|
+
if (!err) {
|
|
507
|
+
err = new Error(
|
|
508
|
+
`Couldn't load email component's styles; ${component.name} ` +
|
|
509
|
+
`from ${component.stylePath}`
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
reject(
|
|
514
|
+
new Dynamo_Error({
|
|
515
|
+
...this._getDefaultErrorSettings('loadTemplate', err, 'SYSTEM'),
|
|
516
|
+
|
|
517
|
+
errorCode: 'NTS-ES0-LC4',
|
|
518
|
+
})
|
|
519
|
+
);
|
|
520
|
+
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
component.styles = styles;
|
|
525
|
+
|
|
526
|
+
resolve();
|
|
527
|
+
});
|
|
216
528
|
});
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
component.properties = this.getTemplatePropertyKeys(component.template);
|
|
532
|
+
this.componentsBySelector[component.selector] = component;
|
|
533
|
+
this.componentsByName[component.name] = component;
|
|
534
|
+
|
|
535
|
+
component.properties.forEach((propertyKey: string): void => {
|
|
536
|
+
if (!component.template.includes(`{{${propertyKey}}}`)) {
|
|
537
|
+
throw new Dynamo_Error({
|
|
538
|
+
...this._getDefaultErrorSettings(
|
|
539
|
+
'loadComponent',
|
|
540
|
+
new Error(
|
|
541
|
+
`TemplateProperty missing from template! (${propertyKey} for ${component.name})`
|
|
542
|
+
),
|
|
543
|
+
'SYSTEM'
|
|
544
|
+
),
|
|
545
|
+
|
|
546
|
+
errorCode: 'NTS-ES0-LC5',
|
|
547
|
+
additionalContent: component.template,
|
|
548
|
+
});
|
|
549
|
+
}
|
|
217
550
|
});
|
|
218
551
|
} catch (error) {
|
|
219
|
-
|
|
552
|
+
throw new Dynamo_Error({
|
|
553
|
+
...this._getDefaultErrorSettings('loadComponent', error, 'SYSTEM'),
|
|
554
|
+
|
|
555
|
+
errorCode: 'NTS-ES0-LC0',
|
|
556
|
+
message: `loadComponent failed! (${component.name})`,
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
private connectComponents(): void {
|
|
562
|
+
try {
|
|
563
|
+
for (const componentSelector in this.componentsBySelector) {
|
|
564
|
+
this.componentsBySelector[componentSelector].subComponentSelectors = [];
|
|
565
|
+
|
|
566
|
+
const innerTags: string[] =
|
|
567
|
+
this.componentsBySelector[componentSelector].template.split('<nts-');
|
|
568
|
+
|
|
569
|
+
innerTags.shift();
|
|
570
|
+
innerTags.forEach(
|
|
571
|
+
(subComponents: string): void => {
|
|
572
|
+
const subComponentSelector = subComponents.split('>')[0].split(' ')[0];
|
|
573
|
+
|
|
574
|
+
if (subComponentSelector !== 'content') {
|
|
575
|
+
const fullSelector = 'nts-' + subComponentSelector;
|
|
576
|
+
|
|
577
|
+
if (fullSelector) {
|
|
578
|
+
if (!this.componentsBySelector[subComponentSelector]) {
|
|
579
|
+
throw new Dynamo_Error({
|
|
580
|
+
...this._getDefaultErrorSettings(
|
|
581
|
+
'connectComponents',
|
|
582
|
+
new Error(`SubComponent missing from components! (${fullSelector})`),
|
|
583
|
+
'SYSTEM'
|
|
584
|
+
),
|
|
585
|
+
|
|
586
|
+
errorCode: 'NTS-ES0-CC1',
|
|
587
|
+
additionalContent: {
|
|
588
|
+
availableComponenets: Object.keys(this.componentsBySelector),
|
|
589
|
+
},
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
this.componentsBySelector[componentSelector].subComponentSelectors.push(
|
|
594
|
+
subComponentSelector
|
|
595
|
+
);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
);
|
|
600
|
+
}
|
|
601
|
+
} catch (error) {
|
|
602
|
+
throw new Dynamo_Error({
|
|
603
|
+
...this._getDefaultErrorSettings('connectComponents', error, 'SYSTEM'),
|
|
604
|
+
|
|
605
|
+
errorCode: 'NTS-ES0-CC0',
|
|
606
|
+
message: `connectComponents failed!`,
|
|
607
|
+
});
|
|
220
608
|
}
|
|
221
609
|
}
|
|
222
610
|
|
|
@@ -233,31 +621,51 @@ export class DynamoNTS_EmailService {
|
|
|
233
621
|
|
|
234
622
|
while (propertyOpenTagIndex >= 0) {
|
|
235
623
|
if (propertyCloseTagIndex === -1) {
|
|
236
|
-
Dynamo_Log.error(
|
|
624
|
+
Dynamo_Log.error(
|
|
625
|
+
`\nDynamoBEEmailService ERROR, missing closing tag from email template! ` +
|
|
626
|
+
`(${propertyOpenTagIndex} -)`,
|
|
627
|
+
propertyKeys
|
|
628
|
+
);
|
|
629
|
+
|
|
237
630
|
throw new Dynamo_Error({
|
|
238
|
-
errorCode: 'NTS-
|
|
631
|
+
errorCode: 'NTS-ES0-200',
|
|
239
632
|
addECToUserMsg: true,
|
|
240
633
|
message: `ERROR, missing closing tag from email template! (${propertyOpenTagIndex} -)`,
|
|
241
|
-
userMessage: this.defaultErrorUserMsg
|
|
634
|
+
userMessage: this.defaultErrorUserMsg,
|
|
242
635
|
});
|
|
243
636
|
}
|
|
244
637
|
|
|
245
638
|
const newKey: string = template.substring(propertyOpenTagIndex + 2, propertyCloseTagIndex);
|
|
639
|
+
|
|
246
640
|
if (!propertyKeys.includes(newKey)) {
|
|
247
641
|
propertyKeys.push(newKey);
|
|
248
642
|
}
|
|
249
643
|
|
|
644
|
+
// KELLEZIDE?
|
|
250
645
|
propertyOpenTagIndex = template.indexOf('{{', propertyOpenTagIndex + 2);
|
|
251
646
|
propertyCloseTagIndex = template.indexOf('}}', propertyOpenTagIndex + 2);
|
|
252
647
|
}
|
|
253
648
|
// console.log('\n\n\nTEST propertyKeys: ', propertyKeys);
|
|
649
|
+
|
|
254
650
|
return propertyKeys;
|
|
255
651
|
} catch (error) {
|
|
256
|
-
|
|
652
|
+
throw new Dynamo_Error({
|
|
653
|
+
...this._getDefaultErrorSettings('getTemplatePropertyKeys', error, 'SYSTEM'),
|
|
654
|
+
|
|
655
|
+
errorCode: 'NTS-ES0-GTPK0',
|
|
656
|
+
message: `getTemplatePropertyKeys failed!`,
|
|
657
|
+
additionalContent: template,
|
|
658
|
+
});
|
|
257
659
|
}
|
|
258
660
|
}
|
|
259
661
|
|
|
260
|
-
|
|
662
|
+
|
|
663
|
+
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
664
|
+
private _getDefaultErrorSettings(
|
|
665
|
+
fnName: string,
|
|
666
|
+
error: Error | Dynamo_Error,
|
|
667
|
+
issuer: string
|
|
668
|
+
)/* : Dynamo_ErrorSettings */ {
|
|
261
669
|
return {
|
|
262
670
|
status: (error as Dynamo_Error)?.___status ?? 500,
|
|
263
671
|
message: (error as Error)?.message ?? `${fnName} was UNSUCCESFUL (NTS; ${this.serviceName})`,
|
|
@@ -266,6 +674,6 @@ export class DynamoNTS_EmailService {
|
|
|
266
674
|
issuer: issuer,
|
|
267
675
|
issuerService: this.serviceName,
|
|
268
676
|
error: error,
|
|
269
|
-
}
|
|
677
|
+
};
|
|
270
678
|
}
|
|
271
679
|
}
|