rez_core 2.3.1 → 2.3.4
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/dist/app.module.js +2 -0
- package/dist/app.module.js.map +1 -1
- package/dist/module/enterprise/repository/school.repository.js +0 -1
- package/dist/module/enterprise/repository/school.repository.js.map +1 -1
- package/dist/module/filter/repository/saved-filter.repository.js +0 -1
- package/dist/module/filter/repository/saved-filter.repository.js.map +1 -1
- package/dist/module/integration/controller/integration.controller.d.ts +8 -1
- package/dist/module/integration/controller/integration.controller.js +22 -0
- package/dist/module/integration/controller/integration.controller.js.map +1 -1
- package/dist/module/integration/dto/create-config.dto.d.ts +7 -0
- package/dist/module/integration/dto/create-config.dto.js +29 -1
- package/dist/module/integration/dto/create-config.dto.js.map +1 -1
- package/dist/module/integration/factories/sms.factory.d.ts +9 -1
- package/dist/module/integration/factories/sms.factory.js +36 -4
- package/dist/module/integration/factories/sms.factory.js.map +1 -1
- package/dist/module/integration/factories/whatsapp.factory.d.ts +5 -1
- package/dist/module/integration/factories/whatsapp.factory.js +14 -2
- package/dist/module/integration/factories/whatsapp.factory.js.map +1 -1
- package/dist/module/integration/integration.module.js +10 -0
- package/dist/module/integration/integration.module.js.map +1 -1
- package/dist/module/integration/service/integration.service.d.ts +7 -0
- package/dist/module/integration/service/integration.service.js +51 -0
- package/dist/module/integration/service/integration.service.js.map +1 -1
- package/dist/module/integration/strategies/sms/gupshup-sms.strategy.d.ts +9 -0
- package/dist/module/integration/strategies/sms/gupshup-sms.strategy.js +104 -0
- package/dist/module/integration/strategies/sms/gupshup-sms.strategy.js.map +1 -0
- package/dist/module/integration/strategies/sms/msg91-sms.strategy.d.ts +9 -0
- package/dist/module/integration/strategies/sms/msg91-sms.strategy.js +113 -0
- package/dist/module/integration/strategies/sms/msg91-sms.strategy.js.map +1 -0
- package/dist/module/integration/strategies/sms/tubelight-sms.strategy.d.ts +9 -0
- package/dist/module/integration/strategies/sms/tubelight-sms.strategy.js +109 -0
- package/dist/module/integration/strategies/sms/tubelight-sms.strategy.js.map +1 -0
- package/dist/module/integration/strategies/telephone/ozonetel-voice.strategy.d.ts +7 -2
- package/dist/module/integration/strategies/telephone/ozonetel-voice.strategy.js +52 -5
- package/dist/module/integration/strategies/telephone/ozonetel-voice.strategy.js.map +1 -1
- package/dist/module/integration/strategies/whatsapp/gupshup-whatsapp.strategy.d.ts +19 -0
- package/dist/module/integration/strategies/whatsapp/gupshup-whatsapp.strategy.js +257 -0
- package/dist/module/integration/strategies/whatsapp/gupshup-whatsapp.strategy.js.map +1 -0
- package/dist/module/integration/strategies/whatsapp/tubelight-whatsapp.strategy.d.ts +22 -0
- package/dist/module/integration/strategies/whatsapp/tubelight-whatsapp.strategy.js +295 -0
- package/dist/module/integration/strategies/whatsapp/tubelight-whatsapp.strategy.js.map +1 -0
- package/dist/module/layout_preference/service/layout_preference.service.js +0 -2
- package/dist/module/layout_preference/service/layout_preference.service.js.map +1 -1
- package/dist/module/listmaster/service/list-master.service.js +0 -1
- package/dist/module/listmaster/service/list-master.service.js.map +1 -1
- package/dist/module/mapper/controller/field-mapper.controller.d.ts +6 -0
- package/dist/module/mapper/controller/field-mapper.controller.js +45 -0
- package/dist/module/mapper/controller/field-mapper.controller.js.map +1 -0
- package/dist/module/mapper/dto/field-mapper.dto.d.ts +11 -0
- package/dist/module/mapper/dto/field-mapper.dto.js +8 -0
- package/dist/module/mapper/dto/field-mapper.dto.js.map +1 -0
- package/dist/module/mapper/entity/field-lovs.entity.d.ts +7 -0
- package/dist/module/mapper/entity/field-lovs.entity.js +38 -0
- package/dist/module/mapper/entity/field-lovs.entity.js.map +1 -0
- package/dist/module/mapper/entity/field-mapper.entity.d.ts +12 -0
- package/dist/module/mapper/entity/field-mapper.entity.js +58 -0
- package/dist/module/mapper/entity/field-mapper.entity.js.map +1 -0
- package/dist/module/mapper/mapper.module.d.ts +2 -0
- package/dist/module/mapper/mapper.module.js +38 -0
- package/dist/module/mapper/mapper.module.js.map +1 -0
- package/dist/module/mapper/repository/field-lovs.repository.d.ts +8 -0
- package/dist/module/mapper/repository/field-lovs.repository.js +41 -0
- package/dist/module/mapper/repository/field-lovs.repository.js.map +1 -0
- package/dist/module/mapper/repository/field-mapper.repository.d.ts +9 -0
- package/dist/module/mapper/repository/field-mapper.repository.js +42 -0
- package/dist/module/mapper/repository/field-mapper.repository.js.map +1 -0
- package/dist/module/mapper/service/field-mapper.service.d.ts +16 -0
- package/dist/module/mapper/service/field-mapper.service.js +92 -0
- package/dist/module/mapper/service/field-mapper.service.js.map +1 -0
- package/dist/module/master/service/master.service.js +0 -2
- package/dist/module/master/service/master.service.js.map +1 -1
- package/dist/module/meta/repository/entity-table.repository.js +0 -1
- package/dist/module/meta/repository/entity-table.repository.js.map +1 -1
- package/dist/module/meta/service/entity-dynamic.service.js +0 -1
- package/dist/module/meta/service/entity-dynamic.service.js.map +1 -1
- package/dist/module/meta/service/entity-service-impl.service.js +0 -2
- package/dist/module/meta/service/entity-service-impl.service.js.map +1 -1
- package/dist/module/meta/service/entity-table.service.js +0 -2
- package/dist/module/meta/service/entity-table.service.js.map +1 -1
- package/dist/module/meta/service/field-group.service.js +0 -1
- package/dist/module/meta/service/field-group.service.js.map +1 -1
- package/dist/module/module/service/module-access.service.js +0 -6
- package/dist/module/module/service/module-access.service.js.map +1 -1
- package/dist/module/notification/service/email.service.js +0 -1
- package/dist/module/notification/service/email.service.js.map +1 -1
- package/dist/module/user/service/login.service.js +0 -1
- package/dist/module/user/service/login.service.js.map +1 -1
- package/dist/module/workflow/entity/action.entity.d.ts +2 -0
- package/dist/module/workflow/entity/action.entity.js +8 -0
- package/dist/module/workflow/entity/action.entity.js.map +1 -1
- package/dist/module/workflow/repository/stage.repository.js +0 -1
- package/dist/module/workflow/repository/stage.repository.js.map +1 -1
- package/dist/module/workflow/service/action.service.js +0 -1
- package/dist/module/workflow/service/action.service.js.map +1 -1
- package/dist/module/workflow/service/comm-template.service.js +0 -1
- package/dist/module/workflow/service/comm-template.service.js.map +1 -1
- package/dist/module/workflow/service/populate-workflow.service.js +0 -5
- package/dist/module/workflow/service/populate-workflow.service.js.map +1 -1
- package/dist/module/workflow/service/task.service.js +0 -1
- package/dist/module/workflow/service/task.service.js.map +1 -1
- package/dist/module/workflow/service/workflow-meta.service.js +0 -2
- package/dist/module/workflow/service/workflow-meta.service.js.map +1 -1
- package/dist/module/workflow-automation/service/workflow-automation-engine.service.js +0 -1
- package/dist/module/workflow-automation/service/workflow-automation-engine.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/docs/modules/integration.md +55 -1
- package/package.json +1 -1
- package/src/app.module.ts +2 -0
- package/src/module/enterprise/repository/school.repository.ts +0 -1
- package/src/module/filter/repository/saved-filter.repository.ts +0 -1
- package/src/module/integration/controller/integration.controller.ts +24 -0
- package/src/module/integration/dto/create-config.dto.ts +22 -0
- package/src/module/integration/factories/sms.factory.ts +39 -6
- package/src/module/integration/factories/whatsapp.factory.ts +10 -0
- package/src/module/integration/integration.module.ts +14 -0
- package/src/module/integration/service/integration.service.ts +107 -0
- package/src/module/integration/strategies/sms/gupshup-sms.strategy.ts +146 -0
- package/src/module/integration/strategies/sms/msg91-sms.strategy.ts +164 -0
- package/src/module/integration/strategies/sms/tubelight-sms.strategy.ts +163 -0
- package/src/module/integration/strategies/telephone/ozonetel-voice.strategy.ts +80 -7
- package/src/module/integration/strategies/whatsapp/gupshup-whatsapp.strategy.ts +360 -0
- package/src/module/integration/strategies/whatsapp/tubelight-whatsapp.strategy.ts +419 -0
- package/src/module/layout_preference/service/layout_preference.service.ts +0 -2
- package/src/module/listmaster/service/list-master.service.ts +1 -10
- package/src/module/mapper/controller/field-mapper.controller.ts +19 -0
- package/src/module/mapper/dto/field-mapper.dto.ts +14 -0
- package/src/module/mapper/entity/field-lovs.entity.ts +21 -0
- package/src/module/mapper/entity/field-mapper.entity.ts +36 -0
- package/src/module/mapper/mapper.module.ts +26 -0
- package/src/module/mapper/repository/field-lovs.repository.ts +22 -0
- package/src/module/mapper/repository/field-mapper.repository.ts +27 -0
- package/src/module/mapper/service/field-mapper.service.ts +91 -0
- package/src/module/master/service/master.service.ts +0 -2
- package/src/module/meta/repository/entity-table.repository.ts +0 -1
- package/src/module/meta/service/entity-dynamic.service.ts +1 -5
- package/src/module/meta/service/entity-service-impl.service.ts +0 -4
- package/src/module/meta/service/entity-table.service.ts +0 -2
- package/src/module/meta/service/field-group.service.ts +0 -1
- package/src/module/module/service/module-access.service.ts +0 -13
- package/src/module/notification/service/email.service.ts +0 -1
- package/src/module/user/service/login.service.ts +0 -1
- package/src/module/workflow/entity/action.entity.ts +6 -0
- package/src/module/workflow/repository/stage.repository.ts +1 -2
- package/src/module/workflow/service/action.service.ts +0 -1
- package/src/module/workflow/service/comm-template.service.ts +0 -1
- package/src/module/workflow/service/populate-workflow.service.ts +2 -12
- package/src/module/workflow/service/task.service.ts +0 -1
- package/src/module/workflow/service/workflow-meta.service.ts +1 -4
- package/src/module/workflow-automation/service/workflow-automation-engine.service.ts +0 -1
- package/src/resources/dev.properties.yaml +1 -1
- package/.vscode/extensions.json +0 -5
|
@@ -139,7 +139,7 @@ export class IntegrationService {
|
|
|
139
139
|
```json
|
|
140
140
|
{
|
|
141
141
|
"app_code": "MYAPP",
|
|
142
|
-
"integration_type": "WA",
|
|
142
|
+
"integration_type": "WA",
|
|
143
143
|
"integration_provider": "whatsapp",
|
|
144
144
|
"integration_source_id": 3,
|
|
145
145
|
"config_json": {
|
|
@@ -150,6 +150,60 @@ export class IntegrationService {
|
|
|
150
150
|
}
|
|
151
151
|
```
|
|
152
152
|
|
|
153
|
+
### Gupshup WhatsApp
|
|
154
|
+
```json
|
|
155
|
+
{
|
|
156
|
+
"app_code": "MYAPP",
|
|
157
|
+
"integration_type": "WA",
|
|
158
|
+
"integration_provider": "gupshup",
|
|
159
|
+
"integration_source_id": 4,
|
|
160
|
+
"config_json": {
|
|
161
|
+
"apiKey": "your-gupshup-api-key",
|
|
162
|
+
"appName": "your-app-name",
|
|
163
|
+
"sourceNumber": "your-source-number",
|
|
164
|
+
"baseUrl": "https://api.gupshup.io/sm/api/v1"
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**Gupshup Message Types:**
|
|
170
|
+
- **Text Message**: Default type, just send message
|
|
171
|
+
- **Template**: Requires `messageType: "template"`, `templateId`, optional `templateParams`
|
|
172
|
+
- **Image**: Requires `messageType: "image"`, `mediaUrl`, optional `previewUrl`, `caption`
|
|
173
|
+
- **Document**: Requires `messageType: "document"`, `mediaUrl`, optional `filename`, `caption`
|
|
174
|
+
- **Audio**: Requires `messageType: "audio"`, `mediaUrl`
|
|
175
|
+
- **Video**: Requires `messageType: "video"`, `mediaUrl`, optional `caption`
|
|
176
|
+
- **Location**: Requires `messageType: "location"`, `latitude`, `longitude`, optional `locationName`, `locationAddress`
|
|
177
|
+
- **List**: Requires `messageType: "list"`, `listItems`, optional `listTitle`, `globalButtons`
|
|
178
|
+
- **Quick Reply**: Requires `messageType: "quick_reply"`, `quickReplyOptions`
|
|
179
|
+
|
|
180
|
+
### Tubelight WhatsApp
|
|
181
|
+
```json
|
|
182
|
+
{
|
|
183
|
+
"app_code": "MYAPP",
|
|
184
|
+
"integration_type": "WA",
|
|
185
|
+
"integration_provider": "tubelight",
|
|
186
|
+
"integration_source_id": 5,
|
|
187
|
+
"config_json": {
|
|
188
|
+
"userName": "your-tubelight-username",
|
|
189
|
+
"password": "your-tubelight-password",
|
|
190
|
+
"tenantId": "your-tenant-id",
|
|
191
|
+
"sourceNumber": "your-source-number",
|
|
192
|
+
"baseUrl": "https://portal.tubelightcommunications.com/whatsapp/api/v1"
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**Tubelight Message Types:**
|
|
198
|
+
- **Text Message**: Default type with `messageType: "TEXT"` or no messageType specified
|
|
199
|
+
- **Template**: Requires `messageType: "template"`, `templateId`, optional `templateParams`, `templateLanguage` (default: "en")
|
|
200
|
+
- **Image**: Requires `messageType: "image"`, `mediaUrl`, optional `caption`
|
|
201
|
+
- **Document**: Requires `messageType: "document"`, `mediaUrl`, optional `filename`, `caption`
|
|
202
|
+
- **Audio**: Requires `messageType: "audio"`, `mediaUrl`
|
|
203
|
+
- **Video**: Requires `messageType: "video"`, `mediaUrl`, optional `caption`
|
|
204
|
+
- **Location**: Requires `messageType: "location"`, `latitude`, `longitude`, optional `locationName`, `locationAddress`
|
|
205
|
+
- **Interactive**: Requires `messageType: "interactive"`, `interactiveType` ("button" or "list"), optional `buttons`, `sections`, `header`, `footer`
|
|
206
|
+
|
|
153
207
|
### Knowlarity Voice
|
|
154
208
|
```json
|
|
155
209
|
{
|
package/package.json
CHANGED
package/src/app.module.ts
CHANGED
|
@@ -19,6 +19,7 @@ import { DashboardModule } from './module/dashboard/dashboard.module';
|
|
|
19
19
|
import { IntegrationModule } from './module/integration/integration.module';
|
|
20
20
|
import { ScheduleModule } from '@nestjs/schedule';
|
|
21
21
|
import { AuthModule } from './module/auth/auth.module';
|
|
22
|
+
import { MapperModule } from './module/mapper/mapper.module';
|
|
22
23
|
|
|
23
24
|
@Module({
|
|
24
25
|
imports: [
|
|
@@ -41,6 +42,7 @@ import { AuthModule } from './module/auth/auth.module';
|
|
|
41
42
|
DashboardModule,
|
|
42
43
|
IntegrationModule,
|
|
43
44
|
AuthModule,
|
|
45
|
+
MapperModule,
|
|
44
46
|
ScheduleModule.forRoot(),
|
|
45
47
|
],
|
|
46
48
|
})
|
|
@@ -37,7 +37,6 @@ export class SchoolRepository {
|
|
|
37
37
|
.andWhere('urm.level_type = :levelType', { levelType: 'ORG' })
|
|
38
38
|
.getRawMany();
|
|
39
39
|
|
|
40
|
-
console.log('hasOrgAccess', hasOrgAccess);
|
|
41
40
|
|
|
42
41
|
let currentORGLevel_id = hasOrgAccess[0]?.urm_level_id;
|
|
43
42
|
if (hasOrgAccess[0]?.urm_level_id == 1) {
|
|
@@ -35,7 +35,6 @@ export class SavedFilterRepositoryService {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
async getDetailsByCode(code: string): Promise<SavedFilterDetail[]> {
|
|
38
|
-
console.log("IN GET DETAILS BY CODE", code);
|
|
39
38
|
return this.savedFilterDetailRepo.find({
|
|
40
39
|
where: { mapped_filter_code: code },
|
|
41
40
|
});
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
import { IntegrationService } from '../service/integration.service';
|
|
16
16
|
import {
|
|
17
17
|
BulkMessageDto,
|
|
18
|
+
CheckAgentStatusDto,
|
|
18
19
|
CreateConfigDto,
|
|
19
20
|
CreateUserIntegrationDto,
|
|
20
21
|
GenericSendMessageDto,
|
|
@@ -69,6 +70,29 @@ export class IntegrationController {
|
|
|
69
70
|
return this.integrationService.sendTemplateMessage(templateMessage);
|
|
70
71
|
}
|
|
71
72
|
|
|
73
|
+
@Post('check-agent-status')
|
|
74
|
+
@HttpCode(HttpStatus.OK)
|
|
75
|
+
async checkAgentStatus(@Body() checkAgentStatusDto: CheckAgentStatusDto) {
|
|
76
|
+
try {
|
|
77
|
+
const result = await this.integrationService.checkAgentStatus(
|
|
78
|
+
checkAgentStatusDto.levelId,
|
|
79
|
+
checkAgentStatusDto.levelType,
|
|
80
|
+
checkAgentStatusDto.app_code,
|
|
81
|
+
checkAgentStatusDto.user_id,
|
|
82
|
+
checkAgentStatusDto.type || 'TELEPHONE',
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
return result;
|
|
86
|
+
} catch (error) {
|
|
87
|
+
throw new BadRequestException({
|
|
88
|
+
success: false,
|
|
89
|
+
error: 'CHECK_AGENT_STATUS_ERROR',
|
|
90
|
+
message: error.message || 'Failed to check agent status',
|
|
91
|
+
code: 'AGENT_STATUS_ERROR',
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
72
96
|
@Post('config')
|
|
73
97
|
@HttpCode(HttpStatus.OK)
|
|
74
98
|
async createConfig(@Body() createConfigDto: CreateConfigDto) {
|
|
@@ -473,3 +473,25 @@ export class UpdateUserIntegrationDto {
|
|
|
473
473
|
@IsBoolean()
|
|
474
474
|
is_active?: boolean;
|
|
475
475
|
}
|
|
476
|
+
|
|
477
|
+
export class CheckAgentStatusDto {
|
|
478
|
+
@IsNotEmpty()
|
|
479
|
+
@IsNumber()
|
|
480
|
+
levelId: number;
|
|
481
|
+
|
|
482
|
+
@IsNotEmpty()
|
|
483
|
+
@IsString()
|
|
484
|
+
levelType: string;
|
|
485
|
+
|
|
486
|
+
@IsNotEmpty()
|
|
487
|
+
@IsString()
|
|
488
|
+
app_code: string;
|
|
489
|
+
|
|
490
|
+
@IsNotEmpty()
|
|
491
|
+
@IsNumber()
|
|
492
|
+
user_id: number;
|
|
493
|
+
|
|
494
|
+
@IsOptional()
|
|
495
|
+
@IsIn(['TELEPHONE'])
|
|
496
|
+
type?: 'TELEPHONE';
|
|
497
|
+
}
|
|
@@ -1,19 +1,52 @@
|
|
|
1
1
|
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import { BaseFactory } from './base.factory';
|
|
2
3
|
import { IntegrationStrategy } from '../strategies/integration.strategy';
|
|
4
|
+
import { GupshupSmsStrategy } from '../strategies/sms/gupshup-sms.strategy';
|
|
5
|
+
import { TubelightSmsStrategy } from '../strategies/sms/tubelight-sms.strategy';
|
|
6
|
+
import { Msg91SmsStrategy } from '../strategies/sms/msg91-sms.strategy';
|
|
3
7
|
|
|
4
8
|
@Injectable()
|
|
5
|
-
export class SmsFactory {
|
|
9
|
+
export class SmsFactory implements BaseFactory {
|
|
10
|
+
constructor(
|
|
11
|
+
private gupshupSmsStrategy: GupshupSmsStrategy,
|
|
12
|
+
private tubelightSmsStrategy: TubelightSmsStrategy,
|
|
13
|
+
private msg91SmsStrategy: Msg91SmsStrategy,
|
|
14
|
+
) {}
|
|
15
|
+
|
|
6
16
|
createProvider(service: string, provider: string): IntegrationStrategy {
|
|
7
|
-
|
|
17
|
+
const key = `${service.toLowerCase()}_${provider.toLowerCase()}`;
|
|
18
|
+
|
|
19
|
+
switch (key) {
|
|
20
|
+
case 'api_gupshup':
|
|
21
|
+
case 'sms_gupshup':
|
|
22
|
+
return this.gupshupSmsStrategy;
|
|
23
|
+
case 'api_tubelight':
|
|
24
|
+
case 'sms_tubelight':
|
|
25
|
+
return this.tubelightSmsStrategy;
|
|
26
|
+
case 'api_msg91':
|
|
27
|
+
case 'sms_msg91':
|
|
28
|
+
return this.msg91SmsStrategy;
|
|
29
|
+
|
|
30
|
+
default:
|
|
31
|
+
throw new Error(
|
|
32
|
+
`Unsupported SMS service/provider: ${service}/${provider}`,
|
|
33
|
+
);
|
|
34
|
+
}
|
|
8
35
|
}
|
|
9
36
|
|
|
10
37
|
getSupportedCombinations(): Array<{ service: string; provider: string }> {
|
|
11
|
-
|
|
12
|
-
|
|
38
|
+
return [
|
|
39
|
+
{ service: 'API', provider: 'gupshup' },
|
|
40
|
+
{ service: 'API', provider: 'tubelight' },
|
|
41
|
+
{ service: 'API', provider: 'msg91' },
|
|
42
|
+
];
|
|
13
43
|
}
|
|
14
44
|
|
|
15
45
|
validateCombination(service: string, provider: string): boolean {
|
|
16
|
-
|
|
17
|
-
|
|
46
|
+
return this.getSupportedCombinations().some(
|
|
47
|
+
(combo) =>
|
|
48
|
+
combo.service.toLowerCase() === service.toLowerCase() &&
|
|
49
|
+
combo.provider.toLowerCase() === provider.toLowerCase(),
|
|
50
|
+
);
|
|
18
51
|
}
|
|
19
52
|
}
|
|
@@ -3,12 +3,16 @@ import { BaseFactory } from './base.factory';
|
|
|
3
3
|
import { IntegrationStrategy } from '../strategies/integration.strategy';
|
|
4
4
|
import { WhatsAppStrategy } from '../strategies/whatsapp/whatsapp.strategy';
|
|
5
5
|
import { WhatsAppCloudStrategy } from '../strategies/whatsapp/whatsapp-cloud.strategy';
|
|
6
|
+
import { GupshupWhatsAppStrategy } from '../strategies/whatsapp/gupshup-whatsapp.strategy';
|
|
7
|
+
import { TubelightWhatsAppStrategy } from '../strategies/whatsapp/tubelight-whatsapp.strategy';
|
|
6
8
|
|
|
7
9
|
@Injectable()
|
|
8
10
|
export class WhatsAppFactory implements BaseFactory {
|
|
9
11
|
constructor(
|
|
10
12
|
private whatsappStrategy: WhatsAppStrategy,
|
|
11
13
|
private whatsappCloudStrategy: WhatsAppCloudStrategy,
|
|
14
|
+
private gupshupWhatsAppStrategy: GupshupWhatsAppStrategy,
|
|
15
|
+
private tubelightWhatsAppStrategy: TubelightWhatsAppStrategy,
|
|
12
16
|
) {}
|
|
13
17
|
|
|
14
18
|
createProvider(service: string, provider: string): IntegrationStrategy {
|
|
@@ -20,6 +24,10 @@ export class WhatsAppFactory implements BaseFactory {
|
|
|
20
24
|
case 'api_whatsapp-cloud':
|
|
21
25
|
case 'api_meta':
|
|
22
26
|
return this.whatsappCloudStrategy;
|
|
27
|
+
case 'api_gupshup':
|
|
28
|
+
return this.gupshupWhatsAppStrategy;
|
|
29
|
+
case 'api_tubelight':
|
|
30
|
+
return this.tubelightWhatsAppStrategy;
|
|
23
31
|
|
|
24
32
|
default:
|
|
25
33
|
throw new Error(
|
|
@@ -33,6 +41,8 @@ export class WhatsAppFactory implements BaseFactory {
|
|
|
33
41
|
{ service: 'API', provider: 'whatsapp' },
|
|
34
42
|
{ service: 'API', provider: 'whatsapp-cloud' },
|
|
35
43
|
{ service: 'API', provider: 'meta' },
|
|
44
|
+
{ service: 'API', provider: 'gupshup' },
|
|
45
|
+
{ service: 'API', provider: 'tubelight' },
|
|
36
46
|
];
|
|
37
47
|
}
|
|
38
48
|
|
|
@@ -17,6 +17,13 @@ import { SendGridApiStrategy } from './strategies/email/sendgrid-api.strategy';
|
|
|
17
17
|
import { WhatsAppCloudStrategy } from './strategies/whatsapp/whatsapp-cloud.strategy';
|
|
18
18
|
import { OzonetelVoiceStrategy } from './strategies/telephone/ozonetel-voice.strategy';
|
|
19
19
|
import { TubelightVoiceStrategy } from './strategies/telephone/tubelight-voice.strategy';
|
|
20
|
+
import { GupshupWhatsAppStrategy } from './strategies/whatsapp/gupshup-whatsapp.strategy';
|
|
21
|
+
import { TubelightWhatsAppStrategy } from './strategies/whatsapp/tubelight-whatsapp.strategy';
|
|
22
|
+
|
|
23
|
+
// SMS Strategies
|
|
24
|
+
import { GupshupSmsStrategy } from './strategies/sms/gupshup-sms.strategy';
|
|
25
|
+
import { TubelightSmsStrategy } from './strategies/sms/tubelight-sms.strategy';
|
|
26
|
+
import { Msg91SmsStrategy } from './strategies/sms/msg91-sms.strategy';
|
|
20
27
|
|
|
21
28
|
// New unified strategies
|
|
22
29
|
import { OutlookStrategy } from './strategies/email/outlook.strategy';
|
|
@@ -61,6 +68,13 @@ import { UserIntegration } from './entity/user-integration.entity';
|
|
|
61
68
|
WhatsAppCloudStrategy,
|
|
62
69
|
OzonetelVoiceStrategy,
|
|
63
70
|
TubelightVoiceStrategy,
|
|
71
|
+
GupshupWhatsAppStrategy,
|
|
72
|
+
TubelightWhatsAppStrategy,
|
|
73
|
+
|
|
74
|
+
// SMS Strategies
|
|
75
|
+
GupshupSmsStrategy,
|
|
76
|
+
TubelightSmsStrategy,
|
|
77
|
+
Msg91SmsStrategy,
|
|
64
78
|
|
|
65
79
|
// New unified strategies
|
|
66
80
|
OutlookStrategy,
|
|
@@ -2164,4 +2164,111 @@ export class IntegrationService {
|
|
|
2164
2164
|
return null;
|
|
2165
2165
|
}
|
|
2166
2166
|
}
|
|
2167
|
+
|
|
2168
|
+
/**
|
|
2169
|
+
* Check agent status for TELEPHONE integration
|
|
2170
|
+
* Currently supports: Ozonetel
|
|
2171
|
+
*/
|
|
2172
|
+
async checkAgentStatus(
|
|
2173
|
+
levelId: number,
|
|
2174
|
+
levelType: string,
|
|
2175
|
+
appCode: string,
|
|
2176
|
+
userId: number,
|
|
2177
|
+
integrationType: 'TELEPHONE' = 'TELEPHONE',
|
|
2178
|
+
): Promise<{
|
|
2179
|
+
success: boolean;
|
|
2180
|
+
isReady?: boolean;
|
|
2181
|
+
state?: string;
|
|
2182
|
+
agentInfo?: any;
|
|
2183
|
+
error?: string;
|
|
2184
|
+
}> {
|
|
2185
|
+
try {
|
|
2186
|
+
// Get the active configuration
|
|
2187
|
+
const config = await this.getSingleActiveConfig(
|
|
2188
|
+
levelId,
|
|
2189
|
+
levelType,
|
|
2190
|
+
appCode,
|
|
2191
|
+
integrationType,
|
|
2192
|
+
);
|
|
2193
|
+
|
|
2194
|
+
if (!config) {
|
|
2195
|
+
return {
|
|
2196
|
+
success: false,
|
|
2197
|
+
error: 'No active TELEPHONE configuration found',
|
|
2198
|
+
};
|
|
2199
|
+
}
|
|
2200
|
+
|
|
2201
|
+
// Get user integration mapping
|
|
2202
|
+
const userIntegration = await this.getUserIntegrationByUserAndConfig(
|
|
2203
|
+
userId,
|
|
2204
|
+
config.id,
|
|
2205
|
+
);
|
|
2206
|
+
|
|
2207
|
+
if (!userIntegration) {
|
|
2208
|
+
return {
|
|
2209
|
+
success: false,
|
|
2210
|
+
error: 'User integration mapping not found. Please configure agent details.',
|
|
2211
|
+
};
|
|
2212
|
+
}
|
|
2213
|
+
|
|
2214
|
+
// Create strategy instance
|
|
2215
|
+
const strategy = this.integrationFactory.create(
|
|
2216
|
+
config.integration_type,
|
|
2217
|
+
'API', // service is deprecated, using default
|
|
2218
|
+
config.integration_provider,
|
|
2219
|
+
);
|
|
2220
|
+
|
|
2221
|
+
// Get the merged config with user data
|
|
2222
|
+
let mergedConfig = config.config_json;
|
|
2223
|
+
|
|
2224
|
+
if (strategy.createUserSpecificConfig) {
|
|
2225
|
+
mergedConfig = strategy.createUserSpecificConfig(
|
|
2226
|
+
config.config_json,
|
|
2227
|
+
userIntegration.external_user_id,
|
|
2228
|
+
);
|
|
2229
|
+
}
|
|
2230
|
+
|
|
2231
|
+
// Check if strategy is Ozonetel (currently only Ozonetel supports status check)
|
|
2232
|
+
if (config.integration_provider.toLowerCase() === 'ozonetel') {
|
|
2233
|
+
const ozonetelStrategy = strategy as any;
|
|
2234
|
+
|
|
2235
|
+
// Generate token
|
|
2236
|
+
const token = await ozonetelStrategy.generateToken(mergedConfig);
|
|
2237
|
+
if (!token) {
|
|
2238
|
+
return {
|
|
2239
|
+
success: false,
|
|
2240
|
+
error: 'Failed to authenticate with telephone provider',
|
|
2241
|
+
};
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2244
|
+
// Check agent status
|
|
2245
|
+
const statusResult = await ozonetelStrategy.checkAgentStatus(
|
|
2246
|
+
mergedConfig,
|
|
2247
|
+
token,
|
|
2248
|
+
);
|
|
2249
|
+
|
|
2250
|
+
return {
|
|
2251
|
+
success: true,
|
|
2252
|
+
isReady: statusResult.isReady,
|
|
2253
|
+
state: statusResult.state,
|
|
2254
|
+
error: statusResult.error,
|
|
2255
|
+
};
|
|
2256
|
+
}
|
|
2257
|
+
|
|
2258
|
+
// For other providers, return not supported
|
|
2259
|
+
return {
|
|
2260
|
+
success: false,
|
|
2261
|
+
error: `Agent status check not supported for provider: ${config.integration_provider}`,
|
|
2262
|
+
};
|
|
2263
|
+
} catch (error) {
|
|
2264
|
+
this.logger.error(
|
|
2265
|
+
`Error checking agent status: ${error.message}`,
|
|
2266
|
+
error.stack,
|
|
2267
|
+
);
|
|
2268
|
+
return {
|
|
2269
|
+
success: false,
|
|
2270
|
+
error: error.message || 'Failed to check agent status',
|
|
2271
|
+
};
|
|
2272
|
+
}
|
|
2273
|
+
}
|
|
2167
2274
|
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { Injectable, Logger } from '@nestjs/common';
|
|
2
|
+
import axios, { AxiosResponse } from 'axios';
|
|
3
|
+
import {
|
|
4
|
+
IntegrationStrategy,
|
|
5
|
+
IntegrationResult,
|
|
6
|
+
} from '../integration.strategy';
|
|
7
|
+
|
|
8
|
+
interface GupshupSmsConfig {
|
|
9
|
+
apiKey: string;
|
|
10
|
+
sourceNumber: string;
|
|
11
|
+
baseUrl?: string;
|
|
12
|
+
method?: string; // 'SendMessage' or 'SendSMS'
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface GupshupSmsApiResponse {
|
|
16
|
+
status: string;
|
|
17
|
+
messageId?: string;
|
|
18
|
+
response?: {
|
|
19
|
+
id: string;
|
|
20
|
+
phone: string;
|
|
21
|
+
details: string;
|
|
22
|
+
};
|
|
23
|
+
error?: {
|
|
24
|
+
code: number;
|
|
25
|
+
message: string;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@Injectable()
|
|
30
|
+
export class GupshupSmsStrategy implements IntegrationStrategy {
|
|
31
|
+
private readonly logger = new Logger(GupshupSmsStrategy.name);
|
|
32
|
+
private readonly defaultBaseUrl = 'https://enterprise.smsgupshup.com/GatewayAPI/rest';
|
|
33
|
+
|
|
34
|
+
async sendMessage(
|
|
35
|
+
to: string,
|
|
36
|
+
message: string,
|
|
37
|
+
config: any,
|
|
38
|
+
): Promise<IntegrationResult> {
|
|
39
|
+
try {
|
|
40
|
+
if (!this.validateConfig(config)) {
|
|
41
|
+
throw new Error('Invalid Gupshup SMS configuration');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const gupshupConfig = config as GupshupSmsConfig;
|
|
45
|
+
const baseUrl = gupshupConfig.baseUrl || this.defaultBaseUrl;
|
|
46
|
+
const method = gupshupConfig.method || 'SendMessage';
|
|
47
|
+
|
|
48
|
+
const params = new URLSearchParams();
|
|
49
|
+
params.append('method', method);
|
|
50
|
+
params.append('send_to', this.formatPhoneNumber(to));
|
|
51
|
+
params.append('msg', message);
|
|
52
|
+
params.append('msg_type', 'TEXT');
|
|
53
|
+
params.append('userid', gupshupConfig.apiKey);
|
|
54
|
+
params.append('auth_scheme', 'plain');
|
|
55
|
+
params.append('v', '1.1');
|
|
56
|
+
params.append('format', 'text');
|
|
57
|
+
|
|
58
|
+
const url = `${baseUrl}?${params.toString()}`;
|
|
59
|
+
|
|
60
|
+
const response: AxiosResponse = await axios.get(url, {
|
|
61
|
+
timeout: 30000,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Gupshup SMS API returns text response like: "success | message-id"
|
|
65
|
+
const responseText = response.data?.toString() || '';
|
|
66
|
+
|
|
67
|
+
if (responseText.toLowerCase().includes('success')) {
|
|
68
|
+
const parts = responseText.split('|');
|
|
69
|
+
const messageId = parts.length > 1 ? parts[1].trim() : new Date().getTime().toString();
|
|
70
|
+
|
|
71
|
+
this.logger.log(
|
|
72
|
+
`Gupshup SMS sent successfully to ${to}, messageId: ${messageId}`,
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
success: true,
|
|
77
|
+
messageId: messageId,
|
|
78
|
+
provider: 'gupshup',
|
|
79
|
+
service: 'SMS',
|
|
80
|
+
timestamp: new Date(),
|
|
81
|
+
};
|
|
82
|
+
} else {
|
|
83
|
+
throw new Error(responseText || 'Failed to send SMS via Gupshup');
|
|
84
|
+
}
|
|
85
|
+
} catch (error) {
|
|
86
|
+
this.logger.error(
|
|
87
|
+
`Failed to send Gupshup SMS to ${to}`,
|
|
88
|
+
error.response?.data || error.message,
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
success: false,
|
|
93
|
+
provider: 'gupshup',
|
|
94
|
+
service: 'SMS',
|
|
95
|
+
error: this.extractErrorMessage(error),
|
|
96
|
+
timestamp: new Date(),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private formatPhoneNumber(phoneNumber: string): string {
|
|
102
|
+
// Remove any non-digit characters except +
|
|
103
|
+
let formatted = phoneNumber.replace(/[^\d+]/g, '');
|
|
104
|
+
|
|
105
|
+
// Remove + if present as Gupshup expects just numbers
|
|
106
|
+
formatted = formatted.replace(/\+/g, '');
|
|
107
|
+
|
|
108
|
+
return formatted;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private extractErrorMessage(error: any): string {
|
|
112
|
+
if (error.response?.data) {
|
|
113
|
+
const data = error.response.data.toString();
|
|
114
|
+
if (data) {
|
|
115
|
+
return data;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (error.response?.data?.error?.message) {
|
|
120
|
+
return error.response.data.error.message;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (error.response?.data?.message) {
|
|
124
|
+
return error.response.data.message;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (error.message) {
|
|
128
|
+
return error.message;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return 'Unknown Gupshup SMS API error';
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
validateConfig(config: any): boolean {
|
|
135
|
+
if (!config || typeof config !== 'object') {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Required fields
|
|
140
|
+
if (!config.apiKey || !config.sourceNumber) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
}
|