rez_core 2.2.183 → 2.2.185

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 (38) hide show
  1. package/dist/module/communication/communication.module.js +3 -6
  2. package/dist/module/communication/communication.module.js.map +1 -1
  3. package/dist/module/communication/factories/email.factory.d.ts +3 -1
  4. package/dist/module/communication/factories/email.factory.js +8 -2
  5. package/dist/module/communication/factories/email.factory.js.map +1 -1
  6. package/dist/module/communication/service/communication-queue.service.js +9 -9
  7. package/dist/module/communication/service/communication-queue.service.js.map +1 -1
  8. package/dist/module/communication/strategies/email/gmail-api.strategy.js.map +1 -1
  9. package/dist/module/communication/strategies/email/sendgrid-api.strategy.d.ts +5 -0
  10. package/dist/module/communication/strategies/email/sendgrid-api.strategy.js +103 -0
  11. package/dist/module/communication/strategies/email/sendgrid-api.strategy.js.map +1 -0
  12. package/dist/module/communication/strategies/gmail.strategy.js +1 -1
  13. package/dist/module/communication/strategies/gmail.strategy.js.map +1 -1
  14. package/dist/module/workflow/controller/comm-template.controller.d.ts +2 -1
  15. package/dist/module/workflow/controller/comm-template.controller.js +4 -3
  16. package/dist/module/workflow/controller/comm-template.controller.js.map +1 -1
  17. package/dist/module/workflow/entity/comm-template.entity.d.ts +1 -0
  18. package/dist/module/workflow/entity/comm-template.entity.js +4 -0
  19. package/dist/module/workflow/entity/comm-template.entity.js.map +1 -1
  20. package/dist/module/workflow/repository/comm-template.repository.d.ts +4 -3
  21. package/dist/module/workflow/repository/comm-template.repository.js +20 -5
  22. package/dist/module/workflow/repository/comm-template.repository.js.map +1 -1
  23. package/dist/module/workflow/service/comm-template.service.d.ts +2 -1
  24. package/dist/module/workflow/service/comm-template.service.js +3 -2
  25. package/dist/module/workflow/service/comm-template.service.js.map +1 -1
  26. package/dist/tsconfig.build.tsbuildinfo +1 -1
  27. package/package.json +2 -1
  28. package/src/module/communication/communication.module.ts +3 -6
  29. package/src/module/communication/factories/email.factory.ts +5 -0
  30. package/src/module/communication/service/communication-queue.service.ts +41 -26
  31. package/src/module/communication/strategies/email/gmail-api.strategy.ts +3 -1
  32. package/src/module/communication/strategies/email/sendgrid-api.strategy.ts +117 -0
  33. package/src/module/communication/strategies/gmail.strategy.ts +21 -11
  34. package/src/module/workflow/controller/comm-template.controller.ts +2 -0
  35. package/src/module/workflow/entity/comm-template.entity.ts +3 -0
  36. package/src/module/workflow/repository/comm-template.repository.ts +33 -4
  37. package/src/module/workflow/service/comm-template.service.ts +7 -1
  38. package/.vscode/extensions.json +0 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rez_core",
3
- "version": "2.2.183",
3
+ "version": "2.2.185",
4
4
  "description": "",
5
5
  "author": "",
6
6
  "private": false,
@@ -34,6 +34,7 @@
34
34
  "@nestjs/schedule": "^6.0.0",
35
35
  "@nestjs/swagger": "^11.0.3",
36
36
  "@nestjs/typeorm": "^11.0.0",
37
+ "@sendgrid/mail": "^8.1.5",
37
38
  "250218_nodejs_core": "file:",
38
39
  "aws-sdk": "^2.1692.0",
39
40
  "axios": "^1.9.0",
@@ -16,6 +16,7 @@ import { CommunicationController } from './controller/communication.controller';
16
16
  import { GmailApiStrategy } from './strategies/email/gmail-api.strategy';
17
17
  import { GmailSmtpStrategy } from './strategies/email/gmail-smtp.strategy';
18
18
  import { OutlookApiStrategy } from './strategies/email/outlook-api.strategy';
19
+ import { SendGridApiStrategy } from './strategies/email/sendgrid-api.strategy';
19
20
  import { TwilioStrategy } from './strategies/sms/twilio.strategy';
20
21
  import { KnowlarityStrategy as KnowlaritySMSStrategy } from './strategies/sms/knowlarity.strategy';
21
22
  import { WhatsAppCloudStrategy } from './strategies/whatsapp/whatsapp-cloud.strategy';
@@ -39,12 +40,7 @@ import { TelephoneFactory } from './factories/telephone.factory';
39
40
  import { CommunicationFactory } from './factories/communication.factory';
40
41
 
41
42
  @Module({
42
- imports: [
43
- TypeOrmModule.forFeature([
44
- CommunicationConfig,
45
- CommunicationHub,
46
- ]),
47
- ],
43
+ imports: [TypeOrmModule.forFeature([CommunicationConfig, CommunicationHub])],
48
44
  controllers: [CommunicationController],
49
45
  providers: [
50
46
  // Main Services
@@ -56,6 +52,7 @@ import { CommunicationFactory } from './factories/communication.factory';
56
52
  GmailApiStrategy,
57
53
  GmailSmtpStrategy,
58
54
  OutlookApiStrategy,
55
+ SendGridApiStrategy,
59
56
 
60
57
  // Existing SMS/WhatsApp/Telephone Strategies
61
58
  TwilioStrategy,
@@ -5,6 +5,7 @@ import { GmailStrategy } from '../strategies/gmail.strategy';
5
5
  import { OutlookStrategy } from '../strategies/outlook.strategy';
6
6
  import { GmailSMTPStrategy } from '../strategies/gmail-smtp.strategy';
7
7
  import { OutlookSMTPStrategy } from '../strategies/outlook-smtp.strategy';
8
+ import { SendGridApiStrategy } from '../strategies/email/sendgrid-api.strategy';
8
9
 
9
10
  @Injectable()
10
11
  export class EmailFactory implements BaseFactory {
@@ -13,6 +14,7 @@ export class EmailFactory implements BaseFactory {
13
14
  private outlookStrategy: OutlookStrategy,
14
15
  private gmailSMTPStrategy: GmailSMTPStrategy,
15
16
  private outlookSMTPStrategy: OutlookSMTPStrategy,
17
+ private sendGridApiStrategy: SendGridApiStrategy,
16
18
  ) {}
17
19
 
18
20
  createProvider(service: string, provider: string): CommunicationStrategy {
@@ -23,6 +25,8 @@ export class EmailFactory implements BaseFactory {
23
25
  return this.gmailStrategy;
24
26
  case 'api_outlook':
25
27
  return this.outlookStrategy;
28
+ case 'api_sendgrid':
29
+ return this.sendGridApiStrategy;
26
30
  case 'smtp_gmail':
27
31
  return this.gmailSMTPStrategy;
28
32
  case 'smtp_outlook':
@@ -39,6 +43,7 @@ export class EmailFactory implements BaseFactory {
39
43
  return [
40
44
  { service: 'API', provider: 'gmail' },
41
45
  { service: 'API', provider: 'outlook' },
46
+ { service: 'API', provider: 'sendgrid' },
42
47
  { service: 'SMTP', provider: 'gmail' },
43
48
  { service: 'SMTP', provider: 'outlook' },
44
49
  ];
@@ -37,7 +37,7 @@ export class CommunicationQueueService {
37
37
  metadata?: any,
38
38
  ): Promise<string> {
39
39
  const messageId = this.generateMessageId();
40
-
40
+
41
41
  const queuedMessage: QueuedMessage = {
42
42
  id: messageId,
43
43
  levelId,
@@ -56,7 +56,9 @@ export class CommunicationQueueService {
56
56
  this.queue.push(queuedMessage);
57
57
  this.sortQueue();
58
58
 
59
- this.logger.log(`Message queued: ${messageId} for ${recipient} with priority ${priority}`);
59
+ this.logger.log(
60
+ `Message queued: ${messageId} for ${recipient} with priority ${priority}`,
61
+ );
60
62
  return messageId;
61
63
  }
62
64
 
@@ -90,13 +92,17 @@ export class CommunicationQueueService {
90
92
 
91
93
  getQueueStats() {
92
94
  const total = this.queue.length;
93
- const pending = this.queue.filter(m => !m.scheduledFor || m.scheduledFor <= new Date()).length;
94
- const scheduled = this.queue.filter(m => m.scheduledFor && m.scheduledFor > new Date()).length;
95
-
95
+ const pending = this.queue.filter(
96
+ (m) => !m.scheduledFor || m.scheduledFor <= new Date(),
97
+ ).length;
98
+ const scheduled = this.queue.filter(
99
+ (m) => m.scheduledFor && m.scheduledFor > new Date(),
100
+ ).length;
101
+
96
102
  const byPriority = {
97
- high: this.queue.filter(m => m.priority === 'high').length,
98
- medium: this.queue.filter(m => m.priority === 'medium').length,
99
- low: this.queue.filter(m => m.priority === 'low').length,
103
+ high: this.queue.filter((m) => m.priority === 'high').length,
104
+ medium: this.queue.filter((m) => m.priority === 'medium').length,
105
+ low: this.queue.filter((m) => m.priority === 'low').length,
100
106
  };
101
107
 
102
108
  return {
@@ -117,10 +123,10 @@ export class CommunicationQueueService {
117
123
 
118
124
  try {
119
125
  const now = new Date();
120
-
126
+
121
127
  // Get messages ready to send (not scheduled or scheduled time has passed)
122
128
  const readyMessages = this.queue.filter(
123
- message => !message.scheduledFor || message.scheduledFor <= now
129
+ (message) => !message.scheduledFor || message.scheduledFor <= now,
124
130
  );
125
131
 
126
132
  if (readyMessages.length === 0) {
@@ -139,28 +145,37 @@ export class CommunicationQueueService {
139
145
  for (const message of messagesToProcess) {
140
146
  try {
141
147
  // Remove message from queue
142
- this.queue = this.queue.filter(m => m.id !== message.id);
143
-
144
- this.logger.log(`Processing queued message ${message.id} for ${message.recipient}`);
145
-
148
+ this.queue = this.queue.filter((m) => m.id !== message.id);
149
+
150
+ this.logger.log(
151
+ `Processing queued message ${message.id} for ${message.recipient}`,
152
+ );
153
+
146
154
  // Note: In a real implementation, you would call the communication service here
147
155
  // For now, we just simulate successful processing
148
-
149
156
  } catch (error) {
150
- this.logger.error(`Failed to process message ${message.id}:`, error.message);
151
-
157
+ this.logger.error(
158
+ `Failed to process message ${message.id}:`,
159
+ error.message,
160
+ );
161
+
152
162
  // Retry logic
153
163
  if (message.retryCount < message.maxRetries) {
154
164
  message.retryCount++;
155
- message.scheduledFor = new Date(Date.now() + (message.retryCount * 60000)); // Retry after 1, 2, 3 minutes
165
+ message.scheduledFor = new Date(
166
+ Date.now() + message.retryCount * 60000,
167
+ ); // Retry after 1, 2, 3 minutes
156
168
  this.queue.push(message);
157
- this.logger.warn(`Message ${message.id} will be retried (attempt ${message.retryCount}/${message.maxRetries})`);
169
+ this.logger.warn(
170
+ `Message ${message.id} will be retried (attempt ${message.retryCount}/${message.maxRetries})`,
171
+ );
158
172
  } else {
159
- this.logger.error(`Message ${message.id} failed permanently after ${message.maxRetries} attempts`);
173
+ this.logger.error(
174
+ `Message ${message.id} failed permanently after ${message.maxRetries} attempts`,
175
+ );
160
176
  }
161
177
  }
162
178
  }
163
-
164
179
  } catch (error) {
165
180
  this.logger.error('Error processing queue:', error.message);
166
181
  } finally {
@@ -175,7 +190,7 @@ export class CommunicationQueueService {
175
190
  if (priorityOrder[a.priority] !== priorityOrder[b.priority]) {
176
191
  return priorityOrder[b.priority] - priorityOrder[a.priority];
177
192
  }
178
-
193
+
179
194
  // Then by creation time (oldest first)
180
195
  return a.createdAt.getTime() - b.createdAt.getTime();
181
196
  });
@@ -202,13 +217,13 @@ export class CommunicationQueueService {
202
217
  // Cancel a specific message
203
218
  cancelMessage(messageId: string): boolean {
204
219
  const initialLength = this.queue.length;
205
- this.queue = this.queue.filter(m => m.id !== messageId);
220
+ this.queue = this.queue.filter((m) => m.id !== messageId);
206
221
  const canceled = this.queue.length < initialLength;
207
-
222
+
208
223
  if (canceled) {
209
224
  this.logger.log(`Message ${messageId} canceled`);
210
225
  }
211
-
226
+
212
227
  return canceled;
213
228
  }
214
- }
229
+ }
@@ -16,7 +16,9 @@ export class GmailApiStrategy implements CommunicationStrategy {
16
16
  ): Promise<CommunicationResult> {
17
17
  try {
18
18
  if (!config || !config.refreshToken) {
19
- throw new Error('Invalid Gmail API configuration - missing refresh token');
19
+ throw new Error(
20
+ 'Invalid Gmail API configuration - missing refresh token',
21
+ );
20
22
  }
21
23
 
22
24
  const { subject, html, cc, bcc } = config;
@@ -0,0 +1,117 @@
1
+ import { Injectable } from '@nestjs/common';
2
+ import * as sgMail from '@sendgrid/mail';
3
+ import {
4
+ CommunicationStrategy,
5
+ CommunicationResult,
6
+ } from '../communication.strategy';
7
+
8
+ @Injectable()
9
+ export class SendGridApiStrategy implements CommunicationStrategy {
10
+ async sendMessage(
11
+ to: string,
12
+ message: string,
13
+ config: any,
14
+ ): Promise<CommunicationResult> {
15
+ try {
16
+ const {
17
+ apiKey,
18
+ fromEmail,
19
+ templateId,
20
+ dynamicTemplateData,
21
+ subject,
22
+ html,
23
+ } = config;
24
+
25
+ if (!apiKey || !fromEmail) {
26
+ throw new Error(
27
+ 'Missing required SendGrid credentials: apiKey and fromEmail are required',
28
+ );
29
+ }
30
+
31
+ sgMail.setApiKey(apiKey);
32
+
33
+ const toArray = Array.isArray(to) ? to : [to];
34
+ const mailData: any = {
35
+ to: toArray,
36
+ from: fromEmail,
37
+ subject: subject || 'Notification',
38
+ };
39
+
40
+ // Handle template emails
41
+ if (templateId) {
42
+ mailData.templateId = templateId;
43
+ if (dynamicTemplateData) {
44
+ mailData.dynamicTemplateData = dynamicTemplateData;
45
+ }
46
+ } else {
47
+ // Regular email content
48
+ if (html && message) {
49
+ mailData.html = html;
50
+ mailData.text = message;
51
+ } else if (html) {
52
+ mailData.html = html;
53
+ } else {
54
+ mailData.text = message || 'Hello from SendGrid!';
55
+ }
56
+ }
57
+
58
+ // Add CC/BCC if provided
59
+ if (config.cc) {
60
+ mailData.cc = Array.isArray(config.cc) ? config.cc : [config.cc];
61
+ }
62
+ if (config.bcc) {
63
+ mailData.bcc = Array.isArray(config.bcc) ? config.bcc : [config.bcc];
64
+ }
65
+
66
+ // Add additional SendGrid features
67
+ if (config.attachments) {
68
+ mailData.attachments = config.attachments;
69
+ }
70
+ if (config.categories) {
71
+ mailData.categories = Array.isArray(config.categories)
72
+ ? config.categories
73
+ : [config.categories];
74
+ }
75
+ if (config.customArgs) {
76
+ mailData.customArgs = config.customArgs;
77
+ }
78
+ if (config.sendAt) {
79
+ mailData.sendAt = config.sendAt;
80
+ }
81
+
82
+ const result = await sgMail.send(mailData);
83
+
84
+ return {
85
+ success: true,
86
+ provider: 'sendgrid',
87
+ service: 'API',
88
+ messageId: result[0].headers['x-message-id'] || undefined,
89
+ timestamp: new Date(),
90
+ };
91
+ } catch (error) {
92
+ let errorMessage = 'Unknown error';
93
+
94
+ if (error.response?.body?.errors) {
95
+ errorMessage = error.response.body.errors
96
+ .map((err: any) => err.message)
97
+ .join(', ');
98
+ } else if (error.response?.body?.message) {
99
+ errorMessage = error.response.body.message;
100
+ } else if (error.message) {
101
+ errorMessage = error.message;
102
+ }
103
+
104
+ return {
105
+ success: false,
106
+ provider: 'sendgrid',
107
+ service: 'API',
108
+ error: errorMessage,
109
+ timestamp: new Date(),
110
+ };
111
+ }
112
+ }
113
+
114
+ validateConfig(config: any): boolean {
115
+ return !!(config.apiKey && config.fromEmail);
116
+ }
117
+ }
@@ -20,20 +20,26 @@ export class GmailStrategy implements CommunicationStrategy {
20
20
 
21
21
  // For backward compatibility, only validate essential fields for sending
22
22
  if (!refreshToken || !email) {
23
- throw new Error('Missing required Gmail credentials: refreshToken and email are required');
23
+ throw new Error(
24
+ 'Missing required Gmail credentials: refreshToken and email are required',
25
+ );
24
26
  }
25
27
 
26
28
  // Get system OAuth credentials
27
29
  const systemClientId = this.configService.get<string>('CLIENT_ID');
28
- const systemClientSecret = this.configService.get<string>('CLIENT_SECRET');
30
+ const systemClientSecret =
31
+ this.configService.get<string>('CLIENT_SECRET');
29
32
 
30
33
  if (!systemClientId || !systemClientSecret) {
31
34
  throw new Error('Gmail OAuth system credentials not configured');
32
35
  }
33
36
 
34
37
  // Create OAuth2 client with system credentials
35
- const oauth2Client = new google.auth.OAuth2(systemClientId, systemClientSecret);
36
-
38
+ const oauth2Client = new google.auth.OAuth2(
39
+ systemClientId,
40
+ systemClientSecret,
41
+ );
42
+
37
43
  oauth2Client.setCredentials({
38
44
  refresh_token: refreshToken,
39
45
  access_token: accessToken,
@@ -82,16 +88,20 @@ export class GmailStrategy implements CommunicationStrategy {
82
88
  service: 'API',
83
89
  messageId: result.data.id || undefined,
84
90
  timestamp: new Date(),
85
- refreshedToken: config.accessToken !== accessToken ? config.accessToken : undefined,
91
+ refreshedToken:
92
+ config.accessToken !== accessToken ? config.accessToken : undefined,
86
93
  };
87
94
  } catch (error) {
88
95
  console.log('Gmail strategy error:', error);
89
- console.log('Config validation:', JSON.stringify({
90
- hasRefreshToken: !!config.refreshToken,
91
- hasAccessToken: !!config.accessToken,
92
- hasEmail: !!config.email
93
- }));
94
-
96
+ console.log(
97
+ 'Config validation:',
98
+ JSON.stringify({
99
+ hasRefreshToken: !!config.refreshToken,
100
+ hasAccessToken: !!config.accessToken,
101
+ hasEmail: !!config.email,
102
+ }),
103
+ );
104
+
95
105
  return {
96
106
  success: false,
97
107
  provider: 'gmail',
@@ -21,10 +21,12 @@ export class CommTemplateController {
21
21
  async getTemplate(
22
22
  @Req() req: Request & { user: any },
23
23
  @Body('entity_type') entity_type: string,
24
+ @Body('action_id') action_id: number,
24
25
  ) {
25
26
  const loggedInUser = req.user.userData;
26
27
  const result = this.commTemplateService.getAllCommTemplate(
27
28
  entity_type || '',
29
+ action_id,
28
30
  loggedInUser,
29
31
  );
30
32
  return result;
@@ -28,4 +28,7 @@ export class CommTemplate extends BaseEntity {
28
28
  // if format_type is 'markup', this field will be used
29
29
  @Column({ nullable: true })
30
30
  markup_id: number;
31
+
32
+ @Column({ nullable: true })
33
+ is_template: boolean;
31
34
  }
@@ -1,7 +1,7 @@
1
1
  import { Injectable, NotFoundException } from '@nestjs/common';
2
2
  import { InjectRepository } from '@nestjs/typeorm';
3
3
  import { Workflow } from '../entity/workflow.entity';
4
- import { Repository } from 'typeorm';
4
+ import { DataSource, Repository } from 'typeorm';
5
5
  import { CommTemplate } from '../entity/comm-template.entity';
6
6
  import { TemplateAttach } from '../entity/template-attach-mapper.entity';
7
7
  import { MediaDataService } from 'src/module/meta/service/media-data.service';
@@ -14,15 +14,44 @@ export class CommTemplateRepository {
14
14
  @InjectRepository(TemplateAttach)
15
15
  private readonly templateAttachEntity: Repository<TemplateAttach>,
16
16
  private readonly mediaDataService: MediaDataService,
17
+ private readonly dataSource: DataSource,
17
18
  ) {}
18
19
 
19
- async getAllCommTemplate(entity_type: string, loggedInUser) {
20
+ async getAllCommTemplate(
21
+ entity_type: string,
22
+ action_id: number,
23
+ loggedInUser,
24
+ ) {
20
25
  const { organization_id } = loggedInUser;
26
+
27
+ const [actionResult] = await this.dataSource.query(
28
+ `SELECT is_template
29
+ FROM cr_wf_action
30
+ WHERE id = ? AND organization_id = ?
31
+ LIMIT 1`,
32
+ [action_id, organization_id],
33
+ );
34
+
35
+ if (!actionResult) {
36
+ throw new Error('Invalid action_id');
37
+ }
38
+
39
+ const { is_template } = actionResult;
40
+
41
+ await this.dataSource.query(
42
+ `UPDATE cr_wf_comm_template
43
+ SET is_template = ?
44
+ WHERE mapped_entity_type = ?
45
+ AND organization_id = ?`,
46
+ [is_template, entity_type, organization_id],
47
+ );
48
+
21
49
  return this.commTemplateRepository.find({
22
- select: ['name', 'code', 'mode'],
50
+ select: ['name', 'code', 'mode', 'is_template'],
23
51
  where: {
24
52
  mapped_entity_type: entity_type,
25
- organization_id: organization_id,
53
+ organization_id,
54
+ is_template,
26
55
  },
27
56
  });
28
57
  }
@@ -78,10 +78,15 @@ export class CommTemplateService extends EntityServiceImpl {
78
78
  return getTemplate;
79
79
  }
80
80
 
81
- async getAllCommTemplate(entity_type: string, loggedInUser) {
81
+ async getAllCommTemplate(
82
+ entity_type: string,
83
+ action_id: number,
84
+ loggedInUser,
85
+ ) {
82
86
  const commTemplateData =
83
87
  await this.commTemplateRepository.getAllCommTemplate(
84
88
  entity_type,
89
+ action_id,
85
90
  loggedInUser,
86
91
  );
87
92
 
@@ -89,6 +94,7 @@ export class CommTemplateService extends EntityServiceImpl {
89
94
  value: item.code,
90
95
  label: item.name,
91
96
  mode: item.mode,
97
+ template: item.is_template,
92
98
  }));
93
99
 
94
100
  return response;
@@ -1,5 +0,0 @@
1
- {
2
- "recommendations": [
3
- "dbaeumer.vscode-eslint"
4
- ]
5
- }