@futdevpro/nts-dynamo 1.7.17 → 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.
Files changed (129) hide show
  1. package/.eslintrc.json +171 -0
  2. package/lib/_constants/mocks/app-extended-server.mock.d.ts.map +1 -1
  3. package/lib/_constants/mocks/app-extended-server.mock.js.map +1 -1
  4. package/lib/_constants/mocks/app-server.mock.d.ts.map +1 -1
  5. package/lib/_constants/mocks/app-server.mock.js.map +1 -1
  6. package/lib/_constants/mocks/data-model.mock.d.ts.map +1 -1
  7. package/lib/_constants/mocks/data-model.mock.js.map +1 -1
  8. package/lib/_constants/mocks/email-service-collection.mock.d.ts.map +1 -1
  9. package/lib/_constants/mocks/email-service-collection.mock.js.map +1 -1
  10. package/lib/_constants/mocks/email-service.mock.js +3 -3
  11. package/lib/_constants/mocks/email-service.mock.js.map +1 -1
  12. package/lib/_constants/mocks/endpoint.mock.d.ts.map +1 -1
  13. package/lib/_constants/mocks/endpoint.mock.js.map +1 -1
  14. package/lib/_constants/mocks/socket-server.mock.d.ts.map +1 -1
  15. package/lib/_constants/mocks/socket-server.mock.js.map +1 -1
  16. package/lib/_enums/index.js +1 -1
  17. package/lib/_enums/index.js.map +1 -1
  18. package/lib/_models/control-models/api-call-params.control-model.d.ts +2 -2
  19. package/lib/_models/control-models/api-call-params.control-model.d.ts.map +1 -1
  20. package/lib/_models/control-models/api-call-params.control-model.js.map +1 -1
  21. package/lib/_models/control-models/app-system-controls.control-model copy.d.ts.map +1 -1
  22. package/lib/_models/control-models/app-system-controls.control-model copy.js.map +1 -1
  23. package/lib/_models/control-models/app-system-controls.control-model.d.ts.map +1 -1
  24. package/lib/_models/control-models/app-system-controls.control-model.js.map +1 -1
  25. package/lib/_models/control-models/endpoint-params.control-model.d.ts.map +1 -1
  26. package/lib/_models/control-models/endpoint-params.control-model.js +15 -9
  27. package/lib/_models/control-models/endpoint-params.control-model.js.map +1 -1
  28. package/lib/_models/control-models/http-settings.control-model.d.ts +1 -1
  29. package/lib/_models/control-models/http-settings.control-model.d.ts.map +1 -1
  30. package/lib/_models/control-models/http-settings.control-model.js +3 -1
  31. package/lib/_models/control-models/http-settings.control-model.js.map +1 -1
  32. package/lib/_models/control-models/socket-client-service-params.control-model.js.map +1 -1
  33. package/lib/_models/control-models/socket-event.control-model.js.map +1 -1
  34. package/lib/_models/control-models/socket-presence.control-model.js.map +1 -1
  35. package/lib/_modules/custom-data/custom-data.controller.d.ts.map +1 -1
  36. package/lib/_modules/custom-data/custom-data.controller.js +2 -1
  37. package/lib/_modules/custom-data/custom-data.controller.js.map +1 -1
  38. package/lib/_modules/custom-data/get-custom-data-routing-module.util.d.ts.map +1 -1
  39. package/lib/_modules/custom-data/get-custom-data-routing-module.util.js.map +1 -1
  40. package/lib/_modules/test/get-test-routing-module.util.d.ts.map +1 -1
  41. package/lib/_modules/test/get-test-routing-module.util.js.map +1 -1
  42. package/lib/_modules/test/test.controller.d.ts.map +1 -1
  43. package/lib/_modules/test/test.controller.js.map +1 -1
  44. package/lib/_modules/usage/get-usage-routing-module.util.d.ts.map +1 -1
  45. package/lib/_modules/usage/get-usage-routing-module.util.js +1 -1
  46. package/lib/_modules/usage/get-usage-routing-module.util.js.map +1 -1
  47. package/lib/_modules/usage/usage.controller.d.ts.map +1 -1
  48. package/lib/_modules/usage/usage.controller.js +15 -14
  49. package/lib/_modules/usage/usage.controller.js.map +1 -1
  50. package/lib/_modules/usage/usage.data-service.d.ts +3 -1
  51. package/lib/_modules/usage/usage.data-service.d.ts.map +1 -1
  52. package/lib/_modules/usage/usage.data-service.js +24 -16
  53. package/lib/_modules/usage/usage.data-service.js.map +1 -1
  54. package/lib/_services/base/data.service.d.ts.map +1 -1
  55. package/lib/_services/base/data.service.js +45 -23
  56. package/lib/_services/base/data.service.js.map +1 -1
  57. package/lib/_services/base/db.service.d.ts.map +1 -1
  58. package/lib/_services/base/db.service.js +82 -53
  59. package/lib/_services/base/db.service.js.map +1 -1
  60. package/lib/_services/base/singleton.service.d.ts.map +1 -1
  61. package/lib/_services/base/singleton.service.js.map +1 -1
  62. package/lib/_services/core/api.service.d.ts +21 -13
  63. package/lib/_services/core/api.service.d.ts.map +1 -1
  64. package/lib/_services/core/api.service.js +192 -143
  65. package/lib/_services/core/api.service.js.map +1 -1
  66. package/lib/_services/core/auth.service.d.ts.map +1 -1
  67. package/lib/_services/core/auth.service.js.map +1 -1
  68. package/lib/_services/core/email.service.d.ts +50 -36
  69. package/lib/_services/core/email.service.d.ts.map +1 -1
  70. package/lib/_services/core/email.service.js +329 -94
  71. package/lib/_services/core/email.service.js.map +1 -1
  72. package/lib/_services/core/global.service.d.ts.map +1 -1
  73. package/lib/_services/core/global.service.js +30 -19
  74. package/lib/_services/core/global.service.js.map +1 -1
  75. package/lib/_services/route/controller.service.d.ts.map +1 -1
  76. package/lib/_services/route/controller.service.js.map +1 -1
  77. package/lib/_services/route/routing-module.service.d.ts.map +1 -1
  78. package/lib/_services/route/routing-module.service.js +2 -2
  79. package/lib/_services/route/routing-module.service.js.map +1 -1
  80. package/lib/_services/server/app-extended.server.d.ts.map +1 -1
  81. package/lib/_services/server/app-extended.server.js +19 -14
  82. package/lib/_services/server/app-extended.server.js.map +1 -1
  83. package/lib/_services/server/app-extended.server.spec.js +1 -0
  84. package/lib/_services/server/app-extended.server.spec.js.map +1 -1
  85. package/lib/_services/server/app.server.d.ts +4 -3
  86. package/lib/_services/server/app.server.d.ts.map +1 -1
  87. package/lib/_services/server/app.server.js +106 -51
  88. package/lib/_services/server/app.server.js.map +1 -1
  89. package/lib/_services/server/app.server.spec.js +1 -0
  90. package/lib/_services/server/app.server.spec.js.map +1 -1
  91. package/lib/_services/shared.static-service.js.map +1 -1
  92. package/lib/_services/socket/socket-client.service.js.map +1 -1
  93. package/lib/_services/socket/socket-server.service.js.map +1 -1
  94. package/lib/tsconfig.tsbuildinfo +1 -1
  95. package/nodemon.json +3 -1
  96. package/package.json +9 -8
  97. package/src/_constants/mocks/app-extended-server.mock.ts +6 -2
  98. package/src/_constants/mocks/app-server.mock.ts +7 -1
  99. package/src/_constants/mocks/data-model.mock.ts +2 -2
  100. package/src/_constants/mocks/email-service-collection.mock.ts +2 -1
  101. package/src/_constants/mocks/email-service.mock.ts +2 -2
  102. package/src/_constants/mocks/endpoint.mock.ts +28 -26
  103. package/src/_constants/mocks/socket-server.mock.ts +12 -4
  104. package/src/_enums/index.ts +1 -1
  105. package/src/_models/control-models/api-call-params.control-model.ts +3 -2
  106. package/src/_models/control-models/app-system-controls.control-model copy.ts +1 -1
  107. package/src/_models/control-models/app-system-controls.control-model.ts +1 -1
  108. package/src/_models/control-models/endpoint-params.control-model.ts +39 -16
  109. package/src/_models/control-models/http-settings.control-model.ts +4 -2
  110. package/src/_modules/custom-data/custom-data.controller.ts +55 -51
  111. package/src/_modules/custom-data/get-custom-data-routing-module.util.ts +7 -3
  112. package/src/_modules/test/get-test-routing-module.util.ts +7 -3
  113. package/src/_modules/test/test.controller.ts +98 -96
  114. package/src/_modules/usage/get-usage-routing-module.util.ts +8 -4
  115. package/src/_modules/usage/usage.controller.ts +108 -102
  116. package/src/_modules/usage/usage.data-service.ts +54 -28
  117. package/src/_services/base/data.service.ts +133 -34
  118. package/src/_services/base/db.service.ts +254 -171
  119. package/src/_services/base/singleton.service.ts +1 -1
  120. package/src/_services/core/api.service.ts +348 -218
  121. package/src/_services/core/auth.service.ts +2 -0
  122. package/src/_services/core/email.service.ts +537 -129
  123. package/src/_services/core/global.service.ts +56 -26
  124. package/src/_services/route/controller.service.ts +3 -1
  125. package/src/_services/route/routing-module.service.ts +33 -16
  126. package/src/_services/server/app-extended.server.spec.ts +22 -17
  127. package/src/_services/server/app-extended.server.ts +108 -45
  128. package/src/_services/server/app.server.spec.ts +17 -12
  129. 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
- private templates: {
19
- [templateName: string]: string
65
+
66
+ private components: DynamoNTS_EmailTemplateComponent[] = [];
67
+ private componentsBySelector: {
68
+ [selector: string]: DynamoNTS_EmailTemplateComponent
20
69
  } = {};
21
- private templatePropertyKeys: {
22
- [templateName: string]: string[]
70
+ private componentsByName: {
71
+ [componentName: string]: DynamoNTS_EmailTemplateComponent
23
72
  } = {};
24
- private templateLoadingInProgressCounter = 0;
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.serviceName = this.constructor?.name;
45
- // console.log('\n\n\n\n\nNEW CONSTRUCT STARTED', set.email);
46
- this.senderName = set.senderName;
47
- this.senderNEmail = `${set.senderName} <${set.email}>`;
48
- this.nmTransporter = NodeMailer.createTransport({
49
- host: set.host,
50
- port: set.port,
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
- if (set.templatePaths) {
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
- Dynamo_Log.error(`\nDynamoBEEmailService ERROR, The emailService construction failed for ${set.email}.`, new Error());
66
- }
67
- }
113
+ throw new Dynamo_Error({
114
+ ...this._getDefaultErrorSettings('asyncPostConstruct', error, 'SYSTEM'),
68
115
 
69
- /**
70
- *
71
- */
72
- private constructionFinished(): void {
73
- Dynamo_Log.success(`\nEmailService construction (${this.senderName}) Finished!`)
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
- to: string,
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.useTemplate) {
139
+ if (!set.templateComponentName) {
100
140
  throw new Dynamo_Error({
101
141
  ...this._getDefaultErrorSettings(
102
142
  'sendEmail',
103
- new Error(`No content setting passsed to emailSending!`),
143
+ new Error(
144
+ `No email template component is given!`
145
+ ),
104
146
  issuer
105
147
  ),
106
148
 
107
- errorCode: 'NTS-ES4-101',
149
+ errorCode: 'NTS-ES0-SE1',
108
150
  });
109
151
  }
110
152
 
111
- if (!this.templates[set.useTemplate]) {
153
+ if (!this.componentsByName[set.templateComponentName]) {
112
154
  throw new Dynamo_Error({
113
155
  ...this._getDefaultErrorSettings(
114
156
  'sendEmail',
115
- new Error(`No email template found with this parameter! (${set.useTemplate})`),
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-ES4-102',
163
+ errorCode: 'NTS-ES0-SE2',
164
+ additionalContent: {
165
+ availableComponenets: Object.keys(this.componentsByName),
166
+ },
120
167
  });
121
168
  }
122
169
 
123
- content = this.templates[set.useTemplate];
124
-
125
- if (0 < this.templatePropertyKeys[set.useTemplate].length) {
126
- if (!set.templateProperties) {
127
- let props = '';
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
- let mailOptions: MailOptions = {
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, info) => {
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-ES4-104',
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-ES4-100',
183
- message: `SendEmail failed!`,
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
- * @param templateName
192
- * @param rootPath
193
- * @param templatePath
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.templateLoadingInProgressCounter++;
199
- return new Promise<void>((resolve, reject) => {
200
- templatePath = Path.join(rootPath, templatePath);
201
- FileSystem.readFile(templatePath, 'utf8' , (err, template) => {
202
- if (err) {
203
- Dynamo_Log.error(`\nDynamoBEEmailService readFile ERROR (0), Couldn't load email template; ${templateName} from ${templatePath}\nerror:\n`, err, '\n');
204
- reject(err);
205
- return;
206
- } else {
207
- this.templates[templateName] = template;
208
- this.templatePropertyKeys[templateName] = this.getTemplatePropertyKeys(template);
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
- this.templateLoadingInProgressCounter--;
211
- if (this.templateLoadingInProgressCounter == 0) {
212
- this.constructionFinished();
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
- Dynamo_Log.error(`\nDynamoBEEmailService ERROR (1), Couldn't load email template; ${templateName} from ${templatePath}`, new Error());
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(`\nDynamoBEEmailService ERROR, missing closing tag from email template! (${propertyOpenTagIndex} -)`, propertyKeys);
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-ES4-200',
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
- Dynamo_Log.error(`\nDynamoBEEmailService ERROR, getTemplatePropertyKeys ERROR`, new Error(), '\ntemplate:\n', template);
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
- private _getDefaultErrorSettings(fnName: string, error: Error | Dynamo_Error, issuer: string) {
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
  }