rez_core 2.3.1 → 2.3.2
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/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/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 +4 -0
- package/dist/module/integration/integration.module.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/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/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/module/enterprise/repository/school.repository.ts +0 -1
- package/src/module/filter/repository/saved-filter.repository.ts +0 -1
- package/src/module/integration/factories/whatsapp.factory.ts +10 -0
- package/src/module/integration/integration.module.ts +4 -0
- 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/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/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
|
@@ -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
|
});
|
|
@@ -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,8 @@ 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';
|
|
20
22
|
|
|
21
23
|
// New unified strategies
|
|
22
24
|
import { OutlookStrategy } from './strategies/email/outlook.strategy';
|
|
@@ -61,6 +63,8 @@ import { UserIntegration } from './entity/user-integration.entity';
|
|
|
61
63
|
WhatsAppCloudStrategy,
|
|
62
64
|
OzonetelVoiceStrategy,
|
|
63
65
|
TubelightVoiceStrategy,
|
|
66
|
+
GupshupWhatsAppStrategy,
|
|
67
|
+
TubelightWhatsAppStrategy,
|
|
64
68
|
|
|
65
69
|
// New unified strategies
|
|
66
70
|
OutlookStrategy,
|
|
@@ -0,0 +1,360 @@
|
|
|
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 GupshupConfig {
|
|
9
|
+
apiKey: string;
|
|
10
|
+
appName: string;
|
|
11
|
+
sourceNumber: string;
|
|
12
|
+
baseUrl?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface GupshupMessage {
|
|
16
|
+
channel: string;
|
|
17
|
+
source: string;
|
|
18
|
+
destination: string;
|
|
19
|
+
'src.name': string;
|
|
20
|
+
message: {
|
|
21
|
+
type: string;
|
|
22
|
+
text?: string;
|
|
23
|
+
url?: string;
|
|
24
|
+
caption?: string;
|
|
25
|
+
filename?: string;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface GupshupApiResponse {
|
|
30
|
+
status: string;
|
|
31
|
+
messageId?: string;
|
|
32
|
+
response?: {
|
|
33
|
+
id: string;
|
|
34
|
+
phone: string;
|
|
35
|
+
details: string;
|
|
36
|
+
};
|
|
37
|
+
error?: {
|
|
38
|
+
code: number;
|
|
39
|
+
message: string;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@Injectable()
|
|
44
|
+
export class GupshupWhatsAppStrategy implements IntegrationStrategy {
|
|
45
|
+
private readonly logger = new Logger(GupshupWhatsAppStrategy.name);
|
|
46
|
+
private readonly defaultBaseUrl = 'https://api.gupshup.io/sm/api/v1';
|
|
47
|
+
|
|
48
|
+
async sendMessage(
|
|
49
|
+
to: string,
|
|
50
|
+
message: string,
|
|
51
|
+
config: any,
|
|
52
|
+
): Promise<IntegrationResult> {
|
|
53
|
+
try {
|
|
54
|
+
if (!this.validateConfig(config)) {
|
|
55
|
+
throw new Error('Invalid Gupshup WhatsApp configuration');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const gupshupConfig = config as GupshupConfig;
|
|
59
|
+
const baseUrl = gupshupConfig.baseUrl || this.defaultBaseUrl;
|
|
60
|
+
const url = `${baseUrl}/msg`;
|
|
61
|
+
|
|
62
|
+
const payload = this.prepareMessagePayload(to, message, config);
|
|
63
|
+
|
|
64
|
+
const response: AxiosResponse<GupshupApiResponse> = await axios.post(
|
|
65
|
+
url,
|
|
66
|
+
payload,
|
|
67
|
+
{
|
|
68
|
+
headers: {
|
|
69
|
+
apikey: gupshupConfig.apiKey,
|
|
70
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
71
|
+
},
|
|
72
|
+
timeout: 30000,
|
|
73
|
+
},
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
if (response.data?.status === 'submitted' && response.data?.messageId) {
|
|
77
|
+
this.logger.log(
|
|
78
|
+
`Gupshup WhatsApp message sent successfully to ${to}, messageId: ${response.data.messageId}`,
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
success: true,
|
|
83
|
+
messageId: response.data.messageId,
|
|
84
|
+
provider: 'gupshup',
|
|
85
|
+
service: 'API',
|
|
86
|
+
timestamp: new Date(),
|
|
87
|
+
};
|
|
88
|
+
} else if (response.data?.response?.id) {
|
|
89
|
+
this.logger.log(
|
|
90
|
+
`Gupshup WhatsApp message sent successfully to ${to}, messageId: ${response.data.response.id}`,
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
success: true,
|
|
95
|
+
messageId: response.data.response.id,
|
|
96
|
+
provider: 'gupshup',
|
|
97
|
+
service: 'API',
|
|
98
|
+
timestamp: new Date(),
|
|
99
|
+
};
|
|
100
|
+
} else {
|
|
101
|
+
throw new Error(
|
|
102
|
+
response.data?.error?.message || 'Invalid response from Gupshup API',
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
} catch (error) {
|
|
106
|
+
this.logger.error(
|
|
107
|
+
`Failed to send Gupshup WhatsApp message to ${to}`,
|
|
108
|
+
error.response?.data || error.message,
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
success: false,
|
|
113
|
+
provider: 'gupshup',
|
|
114
|
+
service: 'API',
|
|
115
|
+
error: this.extractErrorMessage(error),
|
|
116
|
+
timestamp: new Date(),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private prepareMessagePayload(
|
|
122
|
+
to: string,
|
|
123
|
+
message: string,
|
|
124
|
+
config: any,
|
|
125
|
+
): URLSearchParams {
|
|
126
|
+
const gupshupConfig = config as GupshupConfig;
|
|
127
|
+
const params = new URLSearchParams();
|
|
128
|
+
|
|
129
|
+
params.append('channel', 'whatsapp');
|
|
130
|
+
params.append('source', gupshupConfig.sourceNumber);
|
|
131
|
+
params.append('destination', this.formatPhoneNumber(to));
|
|
132
|
+
params.append('src.name', gupshupConfig.appName);
|
|
133
|
+
|
|
134
|
+
// Handle different message types based on config
|
|
135
|
+
if (config.messageType) {
|
|
136
|
+
switch (config.messageType) {
|
|
137
|
+
case 'template':
|
|
138
|
+
params.append('message', JSON.stringify({
|
|
139
|
+
type: 'template',
|
|
140
|
+
template: {
|
|
141
|
+
id: config.templateId,
|
|
142
|
+
params: config.templateParams || [],
|
|
143
|
+
},
|
|
144
|
+
}));
|
|
145
|
+
break;
|
|
146
|
+
|
|
147
|
+
case 'image':
|
|
148
|
+
params.append('message', JSON.stringify({
|
|
149
|
+
type: 'image',
|
|
150
|
+
originalUrl: config.mediaUrl,
|
|
151
|
+
previewUrl: config.previewUrl || config.mediaUrl,
|
|
152
|
+
caption: message || config.caption || '',
|
|
153
|
+
}));
|
|
154
|
+
break;
|
|
155
|
+
|
|
156
|
+
case 'document':
|
|
157
|
+
params.append('message', JSON.stringify({
|
|
158
|
+
type: 'file',
|
|
159
|
+
url: config.mediaUrl,
|
|
160
|
+
filename: config.filename || 'document',
|
|
161
|
+
caption: message || config.caption || '',
|
|
162
|
+
}));
|
|
163
|
+
break;
|
|
164
|
+
|
|
165
|
+
case 'audio':
|
|
166
|
+
params.append('message', JSON.stringify({
|
|
167
|
+
type: 'audio',
|
|
168
|
+
url: config.mediaUrl,
|
|
169
|
+
}));
|
|
170
|
+
break;
|
|
171
|
+
|
|
172
|
+
case 'video':
|
|
173
|
+
params.append('message', JSON.stringify({
|
|
174
|
+
type: 'video',
|
|
175
|
+
url: config.mediaUrl,
|
|
176
|
+
caption: message || config.caption || '',
|
|
177
|
+
}));
|
|
178
|
+
break;
|
|
179
|
+
|
|
180
|
+
case 'location':
|
|
181
|
+
params.append('message', JSON.stringify({
|
|
182
|
+
type: 'location',
|
|
183
|
+
longitude: config.longitude,
|
|
184
|
+
latitude: config.latitude,
|
|
185
|
+
name: config.locationName || '',
|
|
186
|
+
address: config.locationAddress || '',
|
|
187
|
+
}));
|
|
188
|
+
break;
|
|
189
|
+
|
|
190
|
+
case 'list':
|
|
191
|
+
params.append('message', JSON.stringify({
|
|
192
|
+
type: 'list',
|
|
193
|
+
title: config.listTitle || 'Select an option',
|
|
194
|
+
body: message,
|
|
195
|
+
globalButtons: config.globalButtons || [],
|
|
196
|
+
items: config.listItems || [],
|
|
197
|
+
}));
|
|
198
|
+
break;
|
|
199
|
+
|
|
200
|
+
case 'quick_reply':
|
|
201
|
+
params.append('message', JSON.stringify({
|
|
202
|
+
type: 'quick_reply',
|
|
203
|
+
content: {
|
|
204
|
+
type: 'text',
|
|
205
|
+
text: message,
|
|
206
|
+
},
|
|
207
|
+
options: config.quickReplyOptions || [],
|
|
208
|
+
}));
|
|
209
|
+
break;
|
|
210
|
+
|
|
211
|
+
default:
|
|
212
|
+
// Fall back to text message
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Default text message if no specific type or fallback
|
|
218
|
+
if (!config.messageType || !['template', 'image', 'document', 'audio', 'video', 'location', 'list', 'quick_reply'].includes(config.messageType)) {
|
|
219
|
+
params.append('message', JSON.stringify({
|
|
220
|
+
type: 'text',
|
|
221
|
+
text: message,
|
|
222
|
+
}));
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return params;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
private formatPhoneNumber(phoneNumber: string): string {
|
|
229
|
+
// Remove any non-digit characters except +
|
|
230
|
+
let formatted = phoneNumber.replace(/[^\d+]/g, '');
|
|
231
|
+
|
|
232
|
+
// If it doesn't start with +, assume it needs country code
|
|
233
|
+
if (!formatted.startsWith('+')) {
|
|
234
|
+
// Add + if missing
|
|
235
|
+
formatted = `+${formatted}`;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return formatted;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
private extractErrorMessage(error: any): string {
|
|
242
|
+
if (error.response?.data?.error?.message) {
|
|
243
|
+
return error.response.data.error.message;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (error.response?.data?.message) {
|
|
247
|
+
return error.response.data.message;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (error.response?.data?.response?.details) {
|
|
251
|
+
return error.response.data.response.details;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (error.message) {
|
|
255
|
+
return error.message;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return 'Unknown Gupshup API error';
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
validateConfig(config: any): boolean {
|
|
262
|
+
if (!config || typeof config !== 'object') {
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Required fields
|
|
267
|
+
if (!config.apiKey || !config.appName || !config.sourceNumber) {
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Validate message type specific requirements
|
|
272
|
+
if (config.messageType) {
|
|
273
|
+
switch (config.messageType) {
|
|
274
|
+
case 'template':
|
|
275
|
+
if (!config.templateId) {
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
break;
|
|
279
|
+
|
|
280
|
+
case 'image':
|
|
281
|
+
case 'document':
|
|
282
|
+
case 'audio':
|
|
283
|
+
case 'video':
|
|
284
|
+
if (!config.mediaUrl) {
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
break;
|
|
288
|
+
|
|
289
|
+
case 'location':
|
|
290
|
+
if (
|
|
291
|
+
typeof config.latitude !== 'number' ||
|
|
292
|
+
typeof config.longitude !== 'number'
|
|
293
|
+
) {
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
break;
|
|
297
|
+
|
|
298
|
+
case 'list':
|
|
299
|
+
if (!config.listItems || !Array.isArray(config.listItems)) {
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
break;
|
|
303
|
+
|
|
304
|
+
case 'quick_reply':
|
|
305
|
+
if (!config.quickReplyOptions || !Array.isArray(config.quickReplyOptions)) {
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return true;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
async getAppInfo(config: GupshupConfig): Promise<any> {
|
|
316
|
+
try {
|
|
317
|
+
const baseUrl = config.baseUrl || this.defaultBaseUrl;
|
|
318
|
+
const url = `${baseUrl}/app`;
|
|
319
|
+
|
|
320
|
+
const response = await axios.get(url, {
|
|
321
|
+
headers: {
|
|
322
|
+
apikey: config.apiKey,
|
|
323
|
+
},
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
return response.data;
|
|
327
|
+
} catch (error) {
|
|
328
|
+
this.logger.error(
|
|
329
|
+
'Failed to get Gupshup app info',
|
|
330
|
+
error.response?.data || error.message,
|
|
331
|
+
);
|
|
332
|
+
throw new Error(
|
|
333
|
+
`Failed to get app info: ${this.extractErrorMessage(error)}`,
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
async getTemplates(config: GupshupConfig): Promise<any> {
|
|
339
|
+
try {
|
|
340
|
+
const baseUrl = config.baseUrl || this.defaultBaseUrl;
|
|
341
|
+
const url = `${baseUrl}/template/list/${config.appName}`;
|
|
342
|
+
|
|
343
|
+
const response = await axios.get(url, {
|
|
344
|
+
headers: {
|
|
345
|
+
apikey: config.apiKey,
|
|
346
|
+
},
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
return response.data;
|
|
350
|
+
} catch (error) {
|
|
351
|
+
this.logger.error(
|
|
352
|
+
'Failed to get Gupshup templates',
|
|
353
|
+
error.response?.data || error.message,
|
|
354
|
+
);
|
|
355
|
+
throw new Error(
|
|
356
|
+
`Failed to get templates: ${this.extractErrorMessage(error)}`,
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|