rez_core 2.2.190 → 2.2.192

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 (36) hide show
  1. package/dist/module/communication/communication.module.js +4 -1
  2. package/dist/module/communication/communication.module.js.map +1 -1
  3. package/dist/module/communication/controller/calender-event.controller.d.ts +31 -0
  4. package/dist/module/communication/controller/calender-event.controller.js +51 -0
  5. package/dist/module/communication/controller/calender-event.controller.js.map +1 -0
  6. package/dist/module/communication/controller/communication.controller.d.ts +16 -1
  7. package/dist/module/communication/controller/communication.controller.js +62 -0
  8. package/dist/module/communication/controller/communication.controller.js.map +1 -1
  9. package/dist/module/communication/dto/create-config.dto.d.ts +40 -0
  10. package/dist/module/communication/dto/create-config.dto.js +24 -1
  11. package/dist/module/communication/dto/create-config.dto.js.map +1 -1
  12. package/dist/module/communication/factories/whatsapp.factory.d.ts +3 -1
  13. package/dist/module/communication/factories/whatsapp.factory.js +13 -3
  14. package/dist/module/communication/factories/whatsapp.factory.js.map +1 -1
  15. package/dist/module/communication/service/calendar-event.service.d.ts +32 -0
  16. package/dist/module/communication/service/calendar-event.service.js +115 -0
  17. package/dist/module/communication/service/calendar-event.service.js.map +1 -0
  18. package/dist/module/communication/service/communication.service.d.ts +13 -0
  19. package/dist/module/communication/service/communication.service.js +90 -1
  20. package/dist/module/communication/service/communication.service.js.map +1 -1
  21. package/dist/module/communication/strategies/whatsapp/whatsapp-cloud.strategy.d.ts +15 -0
  22. package/dist/module/communication/strategies/whatsapp/whatsapp-cloud.strategy.js +233 -16
  23. package/dist/module/communication/strategies/whatsapp/whatsapp-cloud.strategy.js.map +1 -1
  24. package/dist/module/workflow/service/task.service.js +0 -1
  25. package/dist/module/workflow/service/task.service.js.map +1 -1
  26. package/dist/tsconfig.build.tsbuildinfo +1 -1
  27. package/package.json +1 -1
  28. package/src/module/communication/communication.module.ts +5 -1
  29. package/src/module/communication/controller/calender-event.controller.ts +31 -0
  30. package/src/module/communication/controller/communication.controller.ts +62 -0
  31. package/src/module/communication/dto/create-config.dto.ts +71 -0
  32. package/src/module/communication/factories/whatsapp.factory.ts +13 -2
  33. package/src/module/communication/service/calendar-event.service.ts +123 -0
  34. package/src/module/communication/service/communication.service.ts +153 -2
  35. package/src/module/communication/strategies/whatsapp/whatsapp-cloud.strategy.ts +373 -19
  36. package/src/module/workflow/service/task.service.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rez_core",
3
- "version": "2.2.190",
3
+ "version": "2.2.192",
4
4
  "description": "",
5
5
  "author": "",
6
6
  "private": false,
@@ -38,10 +38,12 @@ import { SmsFactory } from './factories/sms.factory';
38
38
  import { WhatsAppFactory } from './factories/whatsapp.factory';
39
39
  import { TelephoneFactory } from './factories/telephone.factory';
40
40
  import { CommunicationFactory } from './factories/communication.factory';
41
+ import { GoogleController } from './controller/calender-event.controller';
42
+ import { GoogleService } from './service/calendar-event.service';
41
43
 
42
44
  @Module({
43
45
  imports: [TypeOrmModule.forFeature([CommunicationConfig, CommunicationHub])],
44
- controllers: [CommunicationController],
46
+ controllers: [CommunicationController, GoogleController],
45
47
  providers: [
46
48
  // Main Services
47
49
  CommunicationService,
@@ -75,6 +77,8 @@ import { CommunicationFactory } from './factories/communication.factory';
75
77
  WhatsAppFactory,
76
78
  TelephoneFactory,
77
79
  CommunicationFactory,
80
+
81
+ GoogleService,
78
82
  ],
79
83
  exports: [
80
84
  CommunicationService,
@@ -0,0 +1,31 @@
1
+ // src/google/google.controller.ts
2
+ import { Body, Controller, Param, Patch, Post } from '@nestjs/common';
3
+ import { GoogleService } from '../service/calendar-event.service';
4
+
5
+ @Controller('google/calendar')
6
+ export class GoogleController {
7
+ constructor(private readonly googleService: GoogleService) {}
8
+
9
+ /**
10
+ * Create calendar event
11
+ */
12
+ @Post('create')
13
+ async createEvent(
14
+ @Body('googleCred') googleCred: any,
15
+ @Body('payload') payload: any,
16
+ ) {
17
+ return this.googleService.createEvent(googleCred, payload);
18
+ }
19
+
20
+ /**
21
+ * Update calendar event
22
+ */
23
+ @Patch('update/:eventId')
24
+ async updateEvent(
25
+ @Param('eventId') eventId: string,
26
+ @Body('googleCred') googleCred: any,
27
+ @Body('payload') payload: any,
28
+ ) {
29
+ return this.googleService.updateEvent(googleCred, eventId, payload);
30
+ }
31
+ }
@@ -20,6 +20,7 @@ import {
20
20
  GmailOAuthInitDto,
21
21
  OutlookOAuthInitDto,
22
22
  SendGridVerifiedSendersDto,
23
+ UpdateConfigDto,
23
24
  UpdateConfigStatusDto,
24
25
  } from '../dto/create-config.dto';
25
26
 
@@ -150,6 +151,39 @@ export class CommunicationController {
150
151
  });
151
152
  }
152
153
 
154
+ @Get('config/:id')
155
+ async getCommunicationConfigById(@Param('id', ParseIntPipe) hubId: number) {
156
+ try {
157
+ const config =
158
+ await this.communicationService.getCommunicationConfigById(hubId);
159
+
160
+ if (!config) {
161
+ throw new BadRequestException({
162
+ success: false,
163
+ error: 'NOT_FOUND',
164
+ message: 'Communication configuration not found',
165
+ code: 'CONFIGURATION_NOT_FOUND',
166
+ });
167
+ }
168
+
169
+ return {
170
+ success: true,
171
+ data: config,
172
+ };
173
+ } catch (error) {
174
+ if (error instanceof BadRequestException) {
175
+ throw error;
176
+ }
177
+
178
+ throw new BadRequestException({
179
+ success: false,
180
+ error: 'FETCH_ERROR',
181
+ message: error.message || 'Failed to fetch communication configuration',
182
+ code: 'INTERNAL_ERROR',
183
+ });
184
+ }
185
+ }
186
+
153
187
  @Put('config/:id/status')
154
188
  async updateConfigStatus(
155
189
  @Param('id', ParseIntPipe) hubId: number,
@@ -221,4 +255,32 @@ export class CommunicationController {
221
255
  });
222
256
  }
223
257
  }
258
+
259
+ @Post('config/update/:hubId')
260
+ @HttpCode(HttpStatus.OK)
261
+ async updateConfig(
262
+ @Param('hubId', ParseIntPipe) hubId: number,
263
+ @Body() updateDto: UpdateConfigDto,
264
+ ) {
265
+ try {
266
+ const result = await this.communicationService.updateConfiguration(
267
+ hubId,
268
+ updateDto,
269
+ );
270
+
271
+ return {
272
+ success: true,
273
+ message: 'Communication configuration updated successfully',
274
+ data: result,
275
+ };
276
+ } catch (error) {
277
+ throw new BadRequestException({
278
+ success: false,
279
+ error: 'UPDATE_ERROR',
280
+ message:
281
+ error.message || 'Failed to update communication configuration',
282
+ code: 'CONFIGURATION_ERROR',
283
+ });
284
+ }
285
+ }
224
286
  }
@@ -115,6 +115,77 @@ export class UpdateConfigStatusDto {
115
115
  status: number;
116
116
  }
117
117
 
118
+ export class UpdateConfigDto {
119
+ @IsOptional()
120
+ @IsObject()
121
+ config?: {
122
+ // OAuth Control
123
+ useOAuth?: boolean;
124
+
125
+ // Gmail API Config
126
+ clientId?: string;
127
+ clientSecret?: string;
128
+ refreshToken?: string;
129
+ accessToken?: string;
130
+
131
+ // Outlook API Config
132
+ tenantId?: string;
133
+
134
+ // WhatsApp Config
135
+ phoneNumberId?: string;
136
+ apiVersion?: string;
137
+
138
+ // Twilio Config
139
+ accountSid?: string;
140
+ authToken?: string;
141
+ fromNumber?: string;
142
+
143
+ // AWS SES Config
144
+ accessKeyId?: string;
145
+ secretAccessKey?: string;
146
+ region?: string;
147
+ fromEmail?: string;
148
+
149
+ // SMTP Config (Gmail, Outlook, Generic)
150
+ email?: string;
151
+ password?: string;
152
+ host?: string;
153
+ port?: number;
154
+ secure?: boolean;
155
+ user?: string;
156
+ from?: string;
157
+ tls?: any;
158
+
159
+ // SendGrid SMTP Config
160
+ apiKey?: string;
161
+ templateId?: string;
162
+ dynamicTemplateData?: any;
163
+
164
+ // Knowlarity Config
165
+ callerNumber?: string;
166
+ apiSecret?: string;
167
+ baseUrl?: string;
168
+ callType?: 'voice' | 'sms';
169
+ voiceMessage?: string;
170
+ language?: string;
171
+
172
+ // Common optional fields
173
+ [key: string]: any;
174
+ };
175
+
176
+ @IsOptional()
177
+ @IsNumber()
178
+ priority?: number;
179
+
180
+ @IsOptional()
181
+ @IsBoolean()
182
+ is_default?: boolean;
183
+
184
+ @IsOptional()
185
+ @IsNumber()
186
+ status?: number;
187
+ }
188
+
118
189
  export class GenericSendMessageDto {
119
190
  @IsNotEmpty()
120
191
  @IsNumber()
@@ -2,10 +2,14 @@ import { Injectable } from '@nestjs/common';
2
2
  import { BaseFactory } from './base.factory';
3
3
  import { CommunicationStrategy } from '../strategies/communication.strategy';
4
4
  import { WhatsAppStrategy } from '../strategies/whatsapp.strategy';
5
+ import { WhatsAppCloudStrategy } from '../strategies/whatsapp/whatsapp-cloud.strategy';
5
6
 
6
7
  @Injectable()
7
8
  export class WhatsAppFactory implements BaseFactory {
8
- constructor(private whatsappStrategy: WhatsAppStrategy) {}
9
+ constructor(
10
+ private whatsappStrategy: WhatsAppStrategy,
11
+ private whatsappCloudStrategy: WhatsAppCloudStrategy,
12
+ ) {}
9
13
 
10
14
  createProvider(service: string, provider: string): CommunicationStrategy {
11
15
  const key = `${service.toLowerCase()}_${provider.toLowerCase()}`;
@@ -13,6 +17,9 @@ export class WhatsAppFactory implements BaseFactory {
13
17
  switch (key) {
14
18
  case 'api_whatsapp':
15
19
  return this.whatsappStrategy;
20
+ case 'api_whatsapp-cloud':
21
+ case 'api_meta':
22
+ return this.whatsappCloudStrategy;
16
23
 
17
24
  default:
18
25
  throw new Error(
@@ -22,7 +29,11 @@ export class WhatsAppFactory implements BaseFactory {
22
29
  }
23
30
 
24
31
  getSupportedCombinations(): Array<{ service: string; provider: string }> {
25
- return [{ service: 'API', provider: 'whatsapp' }];
32
+ return [
33
+ { service: 'API', provider: 'whatsapp' },
34
+ { service: 'API', provider: 'whatsapp-cloud' },
35
+ { service: 'API', provider: 'meta' },
36
+ ];
26
37
  }
27
38
 
28
39
  validateCombination(service: string, provider: string): boolean {
@@ -0,0 +1,123 @@
1
+ // src/google/google.service.ts
2
+ import { Injectable, Logger } from '@nestjs/common';
3
+ import axios from 'axios';
4
+ import { GmailApiStrategy } from '../strategies/email/gmail-api.strategy';
5
+
6
+ @Injectable()
7
+ export class GoogleService {
8
+ private readonly logger = new Logger(GoogleService.name);
9
+
10
+ constructor(private readonly gmailApiStrategy: GmailApiStrategy) {}
11
+
12
+ /**
13
+ * Create a Google Calendar event
14
+ */
15
+ async createEvent(googleCred: any, payload: any) {
16
+ if (!googleCred?.refreshToken) {
17
+ throw new Error('Missing refresh token');
18
+ }
19
+
20
+ try {
21
+ const accessToken =
22
+ await this.gmailApiStrategy.refreshAccessToken(googleCred);
23
+
24
+ const event = {
25
+ summary: payload.title,
26
+ description: payload.description,
27
+ location: payload.location,
28
+ start: {
29
+ dateTime: payload.startTime,
30
+ timeZone: payload.timeZone || 'Asia/Kolkata',
31
+ },
32
+ end: {
33
+ dateTime: payload.endTime,
34
+ timeZone: payload.timeZone || 'Asia/Kolkata',
35
+ },
36
+ attendees: payload.attendees?.map((email) => ({ email })) || [],
37
+ };
38
+
39
+ const response = await axios.post(
40
+ 'https://www.googleapis.com/calendar/v3/calendars/primary/events?sendUpdates=all',
41
+ event,
42
+ {
43
+ headers: {
44
+ Authorization: `Bearer ${accessToken}`,
45
+ 'Content-Type': 'application/json',
46
+ },
47
+ },
48
+ );
49
+
50
+ this.logger.log(`Event created: ${response.data.id}`);
51
+ return {
52
+ success: true,
53
+ eventId: response.data.id,
54
+ htmlLink: response.data.htmlLink,
55
+ accessToken,
56
+ };
57
+ } catch (error: any) {
58
+ this.logger.error('CreateEvent error', error.message);
59
+ return {
60
+ success: false,
61
+ error: error.response?.data?.error?.message || error.message,
62
+ };
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Update a Google Calendar event
68
+ */
69
+ async updateEvent(googleCred: any, eventId: string, payload: any) {
70
+ if (!googleCred?.refreshToken) {
71
+ throw new Error('Missing refresh token');
72
+ }
73
+
74
+ try {
75
+ const accessToken =
76
+ await this.gmailApiStrategy.refreshAccessToken(googleCred);
77
+
78
+ const event = {
79
+ summary: payload.title,
80
+ description: payload.description,
81
+ location: payload.location,
82
+ start: {
83
+ dateTime: payload.startTime,
84
+ timeZone: payload.timeZone || 'Asia/Kolkata',
85
+ },
86
+ end: {
87
+ dateTime: payload.endTime,
88
+ timeZone: payload.timeZone || 'Asia/Kolkata',
89
+ },
90
+ attendees: payload.attendees?.map((email) => ({ email })) || [],
91
+ };
92
+
93
+ if (payload.meetingType === 'online' && payload.meetingLink) {
94
+ event.description = `${event.description || ''}\nJoin here: ${payload.meetingLink}`;
95
+ }
96
+
97
+ const response = await axios.patch(
98
+ `https://www.googleapis.com/calendar/v3/calendars/primary/events/${eventId}?sendUpdates=all`,
99
+ event,
100
+ {
101
+ headers: {
102
+ Authorization: `Bearer ${accessToken}`,
103
+ 'Content-Type': 'application/json',
104
+ },
105
+ },
106
+ );
107
+
108
+ this.logger.log(`Event updated: ${response.data.id}`);
109
+ return {
110
+ success: true,
111
+ eventId: response.data.id,
112
+ htmlLink: response.data.htmlLink,
113
+ accessToken,
114
+ };
115
+ } catch (error: any) {
116
+ this.logger.error('UpdateEvent error', error.message);
117
+ return {
118
+ success: false,
119
+ error: error.response?.data?.error?.message || error.message,
120
+ };
121
+ }
122
+ }
123
+ }
@@ -1,6 +1,6 @@
1
1
  import { forwardRef, Inject, Injectable, Logger } from '@nestjs/common';
2
2
  import { InjectRepository } from '@nestjs/typeorm';
3
- import { Repository } from 'typeorm';
3
+ import { Repository, Not } from 'typeorm';
4
4
  import { ConfigService } from '@nestjs/config';
5
5
  import { google } from 'googleapis';
6
6
  import {
@@ -339,7 +339,7 @@ export class CommunicationService {
339
339
  ): Promise<
340
340
  Array<CommunicationHub & { linkedSource?: string; configDetails?: any }>
341
341
  > {
342
- const where: any = { level_id: levelId, level_type: levelType, status: 1 };
342
+ const where: any = { level_id: levelId, level_type: levelType };
343
343
 
344
344
  if (filters?.communication_config_type) {
345
345
  where.communication_config_type = filters.communication_config_type;
@@ -669,6 +669,95 @@ export class CommunicationService {
669
669
  );
670
670
  }
671
671
 
672
+ async updateConfiguration(
673
+ hubId: number,
674
+ updateData: {
675
+ config?: any;
676
+ priority?: number;
677
+ is_default?: boolean;
678
+ status?: number;
679
+ },
680
+ ): Promise<CommunicationHub & { config?: any }> {
681
+ // Find the existing hub
682
+ const hub = await this.hubRepository.findOne({
683
+ where: { id: hubId },
684
+ });
685
+
686
+ if (!hub) {
687
+ throw new Error('Communication configuration not found');
688
+ }
689
+
690
+ // Update configuration JSON if provided
691
+ if (updateData.config) {
692
+ const existingConfig = await this.configRepository.findOne({
693
+ where: { id: hub.config_id },
694
+ });
695
+
696
+ if (!existingConfig) {
697
+ throw new Error('Configuration record not found');
698
+ }
699
+
700
+ // Merge the new config with existing config
701
+ const updatedConfigJson = {
702
+ ...existingConfig.config_json,
703
+ ...updateData.config,
704
+ };
705
+
706
+ await this.configRepository.update(hub.config_id, {
707
+ config_json: updatedConfigJson,
708
+ });
709
+ }
710
+
711
+ // Handle default configuration logic
712
+ if (updateData.is_default === true) {
713
+ // Remove default from other configurations of same type and level
714
+ await this.hubRepository.update(
715
+ {
716
+ level_id: hub.level_id,
717
+ level_type: hub.level_type,
718
+ communication_config_type: hub.communication_config_type,
719
+ id: Not(hubId), // Exclude current hub
720
+ },
721
+ { is_default: false },
722
+ );
723
+ }
724
+
725
+ // Update hub metadata
726
+ const hubUpdateData: any = {};
727
+ if (updateData.priority !== undefined) {
728
+ hubUpdateData.priority = updateData.priority;
729
+ }
730
+ if (updateData.is_default !== undefined) {
731
+ hubUpdateData.is_default = updateData.is_default;
732
+ }
733
+ if (updateData.status !== undefined) {
734
+ hubUpdateData.status = updateData.status;
735
+ }
736
+
737
+ // Apply hub updates if any
738
+ if (Object.keys(hubUpdateData).length > 0) {
739
+ await this.hubRepository.update(hubId, hubUpdateData);
740
+ }
741
+
742
+ // Fetch and return updated hub with config
743
+ const updatedHub = await this.hubRepository.findOne({
744
+ where: { id: hubId },
745
+ });
746
+
747
+ const updatedConfig = await this.configRepository.findOne({
748
+ where: { id: hub.config_id },
749
+ });
750
+
751
+ this.logger.log(
752
+ `Communication configuration updated: Hub ${hubId}, Type ${hub.communication_config_type}`,
753
+ );
754
+
755
+ return {
756
+ ...updatedHub!,
757
+ config: updatedConfig?.config_json,
758
+ };
759
+ }
760
+
672
761
  async sendGenericMessage(
673
762
  messageDto: GenericMessageDto,
674
763
  ): Promise<CommunicationResult> {
@@ -1651,4 +1740,66 @@ export class CommunicationService {
1651
1740
  throw new Error(`Failed to complete Outlook OAuth: ${error.message}`);
1652
1741
  }
1653
1742
  }
1743
+
1744
+ async getCommunicationConfigById(
1745
+ hubId: number,
1746
+ ): Promise<(CommunicationHub & { config: CommunicationConfig; linkedSource?: string; configDetails?: any }) | null> {
1747
+ try {
1748
+ // Find the communication hub by ID
1749
+ const hub = await this.hubRepository.findOne({
1750
+ where: { id: hubId },
1751
+ });
1752
+
1753
+ if (!hub) {
1754
+ return null;
1755
+ }
1756
+
1757
+ // Find the associated config
1758
+ const config = await this.configRepository.findOne({
1759
+ where: { id: hub.config_id },
1760
+ });
1761
+
1762
+ if (!config) {
1763
+ this.logger.warn(
1764
+ `Configuration not found for hub ${hubId} with config_id ${hub.config_id}`,
1765
+ );
1766
+ return {
1767
+ ...hub,
1768
+ config: null as any,
1769
+ linkedSource: 'Configuration not found',
1770
+ configDetails: null,
1771
+ };
1772
+ }
1773
+
1774
+ // Extract linked source and config details
1775
+ const linkedSource = this.extractLinkedSource(
1776
+ hub.communication_config_type,
1777
+ hub.service,
1778
+ hub.provider,
1779
+ config.config_json,
1780
+ );
1781
+
1782
+ const configDetails = this.extractConfigDetails(
1783
+ hub.communication_config_type,
1784
+ hub.service,
1785
+ hub.provider,
1786
+ config.config_json,
1787
+ );
1788
+
1789
+ return {
1790
+ ...hub,
1791
+ config,
1792
+ linkedSource,
1793
+ configDetails,
1794
+ };
1795
+ } catch (error) {
1796
+ this.logger.error(
1797
+ `Error fetching communication config by ID ${hubId}:`,
1798
+ error.message,
1799
+ );
1800
+ throw new Error(
1801
+ `Failed to fetch communication configuration: ${error.message}`,
1802
+ );
1803
+ }
1804
+ }
1654
1805
  }