rez_core 2.2.158 → 2.2.161
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/auth/strategies/google.strategy.js +6 -1
- package/dist/module/auth/strategies/google.strategy.js.map +1 -1
- package/dist/module/auth/strategies/jwt.strategy.js +1 -1
- package/dist/module/auth/strategies/jwt.strategy.js.map +1 -1
- package/dist/module/communication/communication.module.js +13 -2
- package/dist/module/communication/communication.module.js.map +1 -1
- package/dist/module/communication/controller/communication.controller.js.map +1 -1
- package/dist/module/communication/dto/create-config.dto.js +11 -1
- package/dist/module/communication/dto/create-config.dto.js.map +1 -1
- package/dist/module/communication/entity/communication-config.entity.js.map +1 -1
- package/dist/module/communication/entity/communication-hub.entity.js +11 -1
- package/dist/module/communication/entity/communication-hub.entity.js.map +1 -1
- package/dist/module/communication/examples/usage.example.js +9 -9
- package/dist/module/communication/examples/usage.example.js.map +1 -1
- package/dist/module/communication/factories/communication.factory.js +4 -4
- package/dist/module/communication/factories/communication.factory.js.map +1 -1
- package/dist/module/communication/factories/email.factory.js +1 -1
- package/dist/module/communication/factories/email.factory.js.map +1 -1
- package/dist/module/communication/factories/sms.factory.js +1 -1
- package/dist/module/communication/factories/sms.factory.js.map +1 -1
- package/dist/module/communication/factories/telephone.factory.js +2 -4
- package/dist/module/communication/factories/telephone.factory.js.map +1 -1
- package/dist/module/communication/factories/whatsapp.factory.js +2 -4
- package/dist/module/communication/factories/whatsapp.factory.js.map +1 -1
- package/dist/module/communication/service/communication-queue.service.d.ts +40 -0
- package/dist/module/communication/service/communication-queue.service.js +147 -0
- package/dist/module/communication/service/communication-queue.service.js.map +1 -0
- package/dist/module/communication/service/communication.service.d.ts +34 -2
- package/dist/module/communication/service/communication.service.js +149 -36
- package/dist/module/communication/service/communication.service.js.map +1 -1
- package/dist/module/communication/service/oauth.service.js +25 -20
- package/dist/module/communication/service/oauth.service.js.map +1 -1
- package/dist/module/communication/strategies/communication.strategy.d.ts +1 -0
- package/dist/module/communication/strategies/email/gmail-api.strategy.js +16 -7
- package/dist/module/communication/strategies/email/gmail-api.strategy.js.map +1 -1
- package/dist/module/communication/strategies/gmail-smtp.strategy.js +2 -3
- package/dist/module/communication/strategies/gmail-smtp.strategy.js.map +1 -1
- package/dist/module/communication/strategies/gmail.strategy.js +20 -1
- package/dist/module/communication/strategies/gmail.strategy.js.map +1 -1
- package/dist/module/communication/strategies/knowlarity.strategy.js +20 -14
- package/dist/module/communication/strategies/knowlarity.strategy.js.map +1 -1
- package/dist/module/communication/strategies/outlook-smtp.strategy.js +2 -3
- package/dist/module/communication/strategies/outlook-smtp.strategy.js.map +1 -1
- package/dist/module/communication/strategies/outlook.strategy.js +1 -1
- package/dist/module/communication/strategies/outlook.strategy.js.map +1 -1
- package/dist/module/communication/strategies/sms.strategy.js +1 -3
- package/dist/module/communication/strategies/sms.strategy.js.map +1 -1
- package/dist/module/communication/strategies/whatsapp.strategy.js +1 -2
- package/dist/module/communication/strategies/whatsapp.strategy.js.map +1 -1
- package/dist/module/dashboard/dashboard.module.js +1 -1
- package/dist/module/dashboard/repository/dashboard.repository.js.map +1 -1
- package/dist/module/dashboard/service/dashboard.service.js +3 -3
- package/dist/module/dashboard/service/dashboard.service.js.map +1 -1
- package/dist/module/enterprise/repository/organization.repository.js.map +1 -1
- package/dist/module/filter/entity/saved-filter-master.entity.d.ts +1 -1
- package/dist/module/filter/service/filter.service.js +3 -3
- package/dist/module/filter/service/filter.service.js.map +1 -1
- package/dist/module/filter/service/saved-filter.service.js.map +1 -1
- package/dist/module/layout/controller/layout.controller.js +1 -1
- package/dist/module/layout/controller/layout.controller.js.map +1 -1
- package/dist/module/layout/repository/header-section.repository.js.map +1 -1
- package/dist/module/layout/service/header-section.service.js +2 -2
- package/dist/module/layout/service/header-section.service.js.map +1 -1
- package/dist/module/layout_preference/repository/layout_preference.repository.js +1 -1
- package/dist/module/layout_preference/service/layout_preference.service.js +1 -1
- package/dist/module/layout_preference/service/layout_preference.service.js.map +1 -1
- package/dist/module/listmaster/controller/list-master.controller.js +1 -1
- package/dist/module/listmaster/controller/list-master.controller.js.map +1 -1
- package/dist/module/listmaster/repository/list-master.repository.js.map +1 -1
- package/dist/module/listmaster/service/list-master.service.js +2 -2
- package/dist/module/listmaster/service/list-master.service.js.map +1 -1
- package/dist/module/master/controller/master.controller.js +2 -2
- package/dist/module/master/controller/master.controller.js.map +1 -1
- package/dist/module/master/service/master.service.js +1 -1
- package/dist/module/master/service/master.service.js.map +1 -1
- package/dist/module/meta/controller/attribute-master.controller.js +3 -3
- package/dist/module/meta/controller/attribute-master.controller.js.map +1 -1
- package/dist/module/meta/controller/entity-dynamic.controller.js +1 -1
- package/dist/module/meta/controller/entity-dynamic.controller.js.map +1 -1
- package/dist/module/meta/controller/entity.controller.js +2 -2
- package/dist/module/meta/controller/entity.controller.js.map +1 -1
- package/dist/module/meta/controller/media.controller.js +1 -1
- package/dist/module/meta/controller/media.controller.js.map +1 -1
- package/dist/module/meta/controller/meta.controller.js +1 -1
- package/dist/module/meta/controller/meta.controller.js.map +1 -1
- package/dist/module/meta/dto/entity-table.dto.js.map +1 -1
- package/dist/module/meta/entity/entity-master.entity.d.ts +1 -0
- package/dist/module/meta/entity/entity-master.entity.js +4 -0
- package/dist/module/meta/entity/entity-master.entity.js.map +1 -1
- package/dist/module/meta/entity/entity-table.entity.js.map +1 -1
- package/dist/module/meta/service/entity-dynamic.service.js +1 -1
- package/dist/module/meta/service/entity-dynamic.service.js.map +1 -1
- package/dist/module/meta/service/entity-list.service.js +11 -11
- package/dist/module/meta/service/entity-list.service.js.map +1 -1
- package/dist/module/meta/service/entity-service-impl.service.js +2 -2
- package/dist/module/meta/service/entity-service-impl.service.js.map +1 -1
- package/dist/module/meta/service/entity-table-column.service.js +3 -3
- package/dist/module/meta/service/entity-table-column.service.js.map +1 -1
- package/dist/module/meta/service/entity-table.service.js +2 -2
- package/dist/module/meta/service/entity-table.service.js.map +1 -1
- package/dist/module/meta/service/media-data.service.js +3 -3
- package/dist/module/meta/service/media-data.service.js.map +1 -1
- package/dist/module/meta/service/update-form-json.service.d.ts +3 -3
- package/dist/module/meta/service/update-form-json.service.js +1 -1
- package/dist/module/meta/service/update-form-json.service.js.map +1 -1
- package/dist/module/module/controller/menu.controller.js.map +1 -1
- package/dist/module/module/controller/module-access.controller.js +1 -1
- package/dist/module/module/controller/module-access.controller.js.map +1 -1
- package/dist/module/module/entity/module-access.entity.js.map +1 -1
- package/dist/module/module/entity/module.entity.js.map +1 -1
- package/dist/module/module/service/module-access.service.d.ts +1 -1
- package/dist/module/module/service/module-access.service.js +1 -1
- package/dist/module/module/service/module-access.service.js.map +1 -1
- package/dist/module/notification/controller/otp.controller.js +3 -3
- package/dist/module/notification/controller/otp.controller.js.map +1 -1
- package/dist/module/notification/service/email.service.js +2 -2
- package/dist/module/notification/service/email.service.js.map +1 -1
- package/dist/module/notification/service/otp.service.js +1 -1
- package/dist/module/notification/service/otp.service.js.map +1 -1
- package/dist/module/user/controller/login.controller.js +4 -2
- package/dist/module/user/controller/login.controller.js.map +1 -1
- package/dist/module/user/service/login.service.js +3 -3
- package/dist/module/user/service/login.service.js.map +1 -1
- package/dist/module/user/service/role.service.js +1 -1
- package/dist/module/user/service/role.service.js.map +1 -1
- package/dist/module/user/service/user.service.js +5 -5
- package/dist/module/user/service/user.service.js.map +1 -1
- package/dist/module/workflow/controller/workflow-meta.controller.d.ts +1 -1
- package/dist/module/workflow/controller/workflow-meta.controller.js +7 -5
- package/dist/module/workflow/controller/workflow-meta.controller.js.map +1 -1
- package/dist/module/workflow/service/action.service.js +3 -3
- package/dist/module/workflow/service/action.service.js.map +1 -1
- package/dist/module/workflow/service/stage-group.service.js +1 -1
- package/dist/module/workflow/service/stage-group.service.js.map +1 -1
- package/dist/module/workflow/service/task.service.js +1 -0
- package/dist/module/workflow/service/task.service.js.map +1 -1
- package/dist/module/workflow/service/workflow-meta.service.d.ts +1 -1
- package/dist/module/workflow/service/workflow-meta.service.js +14 -14
- package/dist/module/workflow/service/workflow-meta.service.js.map +1 -1
- package/dist/resources/properties.module.js +2 -2
- package/dist/resources/properties.module.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utils/service/base64util.service.js.map +1 -1
- package/dist/utils/service/clockIDGenUtil.service.js.map +1 -1
- package/dist/utils/service/dateUtil.service.js +1 -1
- package/dist/utils/service/dateUtil.service.js.map +1 -1
- package/dist/utils/service/encryptUtil.service.js +4 -4
- package/dist/utils/service/encryptUtil.service.js.map +1 -1
- package/dist/utils/service/excel-helper.service.js +4 -1
- package/dist/utils/service/excel-helper.service.js.map +1 -1
- package/dist/utils/service/json-util.service.js.map +1 -1
- package/dist/utils/service/loggingUtil.service.js +3 -3
- package/dist/utils/service/loggingUtil.service.js.map +1 -1
- package/package.json +1 -1
- package/src/decorators/roles.decorator.ts +1 -1
- package/src/module/auth/strategies/google.strategy.ts +6 -1
- package/src/module/auth/strategies/jwt.strategy.ts +1 -1
- package/src/module/communication/communication.module.ts +13 -2
- package/src/module/communication/controller/communication.controller.ts +21 -18
- package/src/module/communication/dto/create-config.dto.ts +32 -13
- package/src/module/communication/entity/communication-config.entity.ts +15 -9
- package/src/module/communication/entity/communication-hub.entity.ts +29 -3
- package/src/module/communication/examples/usage.example.ts +18 -17
- package/src/module/communication/factories/communication.factory.ts +36 -18
- package/src/module/communication/factories/email.factory.ts +8 -5
- package/src/module/communication/factories/sms.factory.ts +8 -5
- package/src/module/communication/factories/telephone.factory.ts +9 -8
- package/src/module/communication/factories/whatsapp.factory.ts +9 -8
- package/src/module/communication/service/communication-queue.service.ts +214 -0
- package/src/module/communication/service/communication.service.ts +381 -112
- package/src/module/communication/service/oauth.service.ts +67 -46
- package/src/module/communication/strategies/communication.strategy.ts +1 -0
- package/src/module/communication/strategies/email/gmail-api.strategy.ts +44 -24
- package/src/module/communication/strategies/gmail-smtp.strategy.ts +15 -11
- package/src/module/communication/strategies/gmail.strategy.ts +42 -7
- package/src/module/communication/strategies/knowlarity.strategy.ts +67 -33
- package/src/module/communication/strategies/outlook-smtp.strategy.ts +15 -11
- package/src/module/communication/strategies/outlook.strategy.ts +12 -5
- package/src/module/communication/strategies/sms.strategy.ts +13 -10
- package/src/module/communication/strategies/whatsapp.strategy.ts +13 -9
- package/src/module/dashboard/dashboard.module.ts +1 -1
- package/src/module/dashboard/repository/dashboard.repository.ts +4 -2
- package/src/module/dashboard/service/dashboard.service.ts +16 -12
- package/src/module/enterprise/repository/organization.repository.ts +3 -1
- package/src/module/enterprise/service/enterprise.service.ts +2 -2
- package/src/module/filter/entity/saved-filter-master.entity.ts +3 -3
- package/src/module/filter/service/filter.service.ts +3 -3
- package/src/module/filter/service/saved-filter.service.ts +1 -1
- package/src/module/layout/controller/layout.controller.ts +1 -1
- package/src/module/layout/repository/header-section.repository.ts +2 -2
- package/src/module/layout/service/header-section.service.ts +2 -3
- package/src/module/layout_preference/repository/layout_preference.repository.ts +2 -2
- package/src/module/layout_preference/service/layout_preference.service.ts +1 -1
- package/src/module/listmaster/controller/list-master.controller.ts +1 -1
- package/src/module/listmaster/repository/list-master.repository.ts +2 -2
- package/src/module/listmaster/service/list-master.service.ts +2 -2
- package/src/module/master/controller/master.controller.ts +2 -2
- package/src/module/master/service/master.service.ts +1 -1
- package/src/module/meta/controller/attribute-master.controller.ts +3 -3
- package/src/module/meta/controller/entity-dynamic.controller.ts +1 -1
- package/src/module/meta/controller/entity.controller.ts +2 -2
- package/src/module/meta/controller/media.controller.ts +1 -1
- package/src/module/meta/controller/meta.controller.ts +1 -1
- package/src/module/meta/dto/entity-tab.dto.ts +4 -4
- package/src/module/meta/dto/entity-table.dto.ts +5 -6
- package/src/module/meta/entity/entity-master.entity.ts +3 -0
- package/src/module/meta/entity/entity-table.entity.ts +1 -2
- package/src/module/meta/service/entity-dynamic.service.ts +1 -1
- package/src/module/meta/service/entity-list.service.ts +18 -14
- package/src/module/meta/service/entity-service-impl.service.ts +2 -2
- package/src/module/meta/service/entity-table-column.service.ts +3 -3
- package/src/module/meta/service/entity-table.service.ts +2 -2
- package/src/module/meta/service/entity.service.ts +1 -1
- package/src/module/meta/service/media-data.service.ts +3 -3
- package/src/module/meta/service/update-form-json.service.ts +17 -26
- package/src/module/module/controller/menu.controller.ts +0 -1
- package/src/module/module/controller/module-access.controller.ts +2 -3
- package/src/module/module/entity/menu.entity.ts +1 -1
- package/src/module/module/entity/module-access.entity.ts +6 -6
- package/src/module/module/entity/module-action.entity.ts +2 -2
- package/src/module/module/entity/module.entity.ts +0 -1
- package/src/module/module/service/module-access.service.ts +7 -8
- package/src/module/notification/controller/otp.controller.ts +10 -4
- package/src/module/notification/repository/otp.repository.ts +1 -1
- package/src/module/notification/service/email.service.ts +2 -2
- package/src/module/notification/service/otp.service.ts +8 -3
- package/src/module/third-party-module/third-party.module.ts +1 -1
- package/src/module/user/controller/login.controller.ts +27 -12
- package/src/module/user/service/login.service.ts +27 -27
- package/src/module/user/service/role.service.ts +1 -1
- package/src/module/user/service/user.service.ts +5 -5
- package/src/module/workflow/controller/workflow-meta.controller.ts +5 -1
- package/src/module/workflow/service/action.service.ts +3 -3
- package/src/module/workflow/service/stage-group.service.ts +1 -1
- package/src/module/workflow/service/task.service.ts +1 -0
- package/src/module/workflow/service/workflow-meta.service.ts +19 -18
- package/src/resources/properties.module.ts +10 -10
- package/src/utils/dto/excel-data.dto.ts +2 -2
- package/src/utils/dto/excelsheet-data.dto.ts +3 -3
- package/src/utils/service/base64util.service.ts +16 -17
- package/src/utils/service/clockIDGenUtil.service.ts +15 -13
- package/src/utils/service/dateUtil.service.ts +6 -6
- package/src/utils/service/encryptUtil.service.ts +4 -4
- package/src/utils/service/excel-helper.service.ts +4 -1
- package/src/utils/service/file-util.service.ts +2 -2
- package/src/utils/service/json-util.service.ts +19 -19
- package/src/utils/service/loggingUtil.service.ts +4 -4
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { Injectable, Logger } from '@nestjs/common';
|
|
1
|
+
import { Injectable, Logger, Inject, forwardRef } from '@nestjs/common';
|
|
2
2
|
import { InjectRepository } from '@nestjs/typeorm';
|
|
3
3
|
import { Repository } from 'typeorm';
|
|
4
4
|
import { ConfigService } from '@nestjs/config';
|
|
5
5
|
import { google } from 'googleapis';
|
|
6
6
|
import {
|
|
7
|
-
CommunicationHub,
|
|
8
7
|
CommunicationConfigType,
|
|
8
|
+
CommunicationHub,
|
|
9
9
|
} from '../entity/communication-hub.entity';
|
|
10
10
|
import { CommunicationConfig } from '../entity/communication-config.entity';
|
|
11
11
|
import { CommunicationFactory } from '../factories/communication.factory';
|
|
12
12
|
import { CommunicationResult } from '../strategies/communication.strategy';
|
|
13
13
|
import { GmailApiStrategy } from '../strategies/email/gmail-api.strategy';
|
|
14
|
+
import { CommunicationQueueService } from './communication-queue.service';
|
|
14
15
|
|
|
15
16
|
export interface SendMessageDto {
|
|
16
17
|
levelId: number;
|
|
@@ -83,6 +84,8 @@ export class CommunicationService {
|
|
|
83
84
|
private readonly communicationFactory: CommunicationFactory,
|
|
84
85
|
private readonly gmailApiStrategy: GmailApiStrategy,
|
|
85
86
|
private readonly configService: ConfigService,
|
|
87
|
+
@Inject(forwardRef(() => CommunicationQueueService))
|
|
88
|
+
private readonly queueService?: CommunicationQueueService,
|
|
86
89
|
) {}
|
|
87
90
|
|
|
88
91
|
async sendMessage({
|
|
@@ -145,20 +148,22 @@ export class CommunicationService {
|
|
|
145
148
|
.createQueryBuilder('hub')
|
|
146
149
|
.leftJoin('communication_config', 'config', 'config.id = hub.config_id')
|
|
147
150
|
.select([
|
|
148
|
-
'hub.id',
|
|
149
|
-
'hub.
|
|
150
|
-
'hub.
|
|
151
|
-
'hub.
|
|
152
|
-
'hub.
|
|
153
|
-
'hub.
|
|
154
|
-
'hub.
|
|
155
|
-
'hub.
|
|
156
|
-
'hub.
|
|
157
|
-
'hub.
|
|
151
|
+
'hub.id as hub_id',
|
|
152
|
+
'hub.level_id as hub_level_id',
|
|
153
|
+
'hub.level_type as hub_level_type',
|
|
154
|
+
'hub.status as hub_status',
|
|
155
|
+
'hub.config_id as hub_config_id',
|
|
156
|
+
'hub.communication_config_type as hub_communication_config_type',
|
|
157
|
+
'hub.service as hub_service',
|
|
158
|
+
'hub.provider as hub_provider',
|
|
159
|
+
'hub.priority as hub_priority',
|
|
160
|
+
'hub.is_default as hub_is_default',
|
|
161
|
+
'hub.created_at as hub_created_at',
|
|
162
|
+
'hub.updated_at as hub_updated_at',
|
|
158
163
|
'config.id as config_id',
|
|
159
164
|
'config.config_json as config_json',
|
|
160
165
|
'config.created_at as config_created_at',
|
|
161
|
-
'config.updated_at as config_updated_at'
|
|
166
|
+
'config.updated_at as config_updated_at',
|
|
162
167
|
])
|
|
163
168
|
.where('hub.level_id = :levelId', { levelId })
|
|
164
169
|
.andWhere('hub.level_type = :levelType', { levelType })
|
|
@@ -171,7 +176,7 @@ export class CommunicationService {
|
|
|
171
176
|
const results = await query.getRawMany();
|
|
172
177
|
|
|
173
178
|
// Transform the raw results into the expected format
|
|
174
|
-
const hubsWithConfig: CommunicationHubWithConfig[] = results.map(row => ({
|
|
179
|
+
const hubsWithConfig: CommunicationHubWithConfig[] = results.map((row) => ({
|
|
175
180
|
id: row.hub_id,
|
|
176
181
|
level_id: row.hub_level_id,
|
|
177
182
|
level_type: row.hub_level_type,
|
|
@@ -214,7 +219,32 @@ export class CommunicationService {
|
|
|
214
219
|
hub.provider,
|
|
215
220
|
);
|
|
216
221
|
|
|
217
|
-
|
|
222
|
+
const result = await strategy.sendMessage(to, message, hub.config.config_json);
|
|
223
|
+
|
|
224
|
+
// If token was refreshed, update it in the database
|
|
225
|
+
if (result.refreshedToken && result.success) {
|
|
226
|
+
try {
|
|
227
|
+
const currentConfig = hub.config.config_json as any;
|
|
228
|
+
const updatedConfig = {
|
|
229
|
+
...currentConfig,
|
|
230
|
+
accessToken: result.refreshedToken,
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
await this.configRepository.update(hub.config.id, {
|
|
234
|
+
config_json: updatedConfig,
|
|
235
|
+
} as any);
|
|
236
|
+
|
|
237
|
+
this.logger.log(
|
|
238
|
+
`Updated access token for ${hub.provider}/${hub.service} configuration`,
|
|
239
|
+
);
|
|
240
|
+
} catch (error) {
|
|
241
|
+
this.logger.warn(
|
|
242
|
+
`Failed to update refreshed token in database: ${error.message}`,
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return result;
|
|
218
248
|
}
|
|
219
249
|
|
|
220
250
|
async createCommunicationConfig(
|
|
@@ -226,29 +256,57 @@ export class CommunicationService {
|
|
|
226
256
|
config: any,
|
|
227
257
|
priority?: number,
|
|
228
258
|
is_default?: boolean,
|
|
229
|
-
): Promise<
|
|
259
|
+
): Promise<
|
|
260
|
+
CommunicationHub | { authUrl: string; state: string; message: string }
|
|
261
|
+
> {
|
|
230
262
|
// Validate service/provider combination using supported combinations
|
|
231
263
|
const supportedCombinations = await this.getSupportedCombinations();
|
|
232
264
|
const isValidCombination = supportedCombinations.some(
|
|
233
|
-
combo =>
|
|
234
|
-
|
|
235
|
-
|
|
265
|
+
(combo) =>
|
|
266
|
+
combo.mode === configType &&
|
|
267
|
+
combo.service.toLowerCase() === service.toLowerCase() &&
|
|
268
|
+
combo.provider.toLowerCase() === provider.toLowerCase(),
|
|
236
269
|
);
|
|
237
|
-
|
|
270
|
+
|
|
238
271
|
if (!isValidCombination) {
|
|
239
|
-
throw new Error(
|
|
272
|
+
throw new Error(
|
|
273
|
+
`Unsupported combination: ${configType}/${service}/${provider}`,
|
|
274
|
+
);
|
|
240
275
|
}
|
|
241
276
|
|
|
242
277
|
// Check if this requires OAuth flow
|
|
243
|
-
const requiresOAuth = this.requiresOAuthFlow(
|
|
244
|
-
|
|
278
|
+
const requiresOAuth = this.requiresOAuthFlow(
|
|
279
|
+
configType,
|
|
280
|
+
service,
|
|
281
|
+
provider,
|
|
282
|
+
config,
|
|
283
|
+
);
|
|
284
|
+
|
|
245
285
|
if (requiresOAuth) {
|
|
246
286
|
// Generate OAuth URL and return it instead of creating config immediately
|
|
247
|
-
return await this.generateOAuthUrl(
|
|
287
|
+
return await this.generateOAuthUrl(
|
|
288
|
+
levelId,
|
|
289
|
+
levelType,
|
|
290
|
+
configType,
|
|
291
|
+
service,
|
|
292
|
+
provider,
|
|
293
|
+
config,
|
|
294
|
+
priority,
|
|
295
|
+
is_default,
|
|
296
|
+
);
|
|
248
297
|
}
|
|
249
298
|
|
|
250
299
|
// Direct config creation (non-OAuth flow)
|
|
251
|
-
return await this.createDirectConfig(
|
|
300
|
+
return await this.createDirectConfig(
|
|
301
|
+
levelId,
|
|
302
|
+
levelType,
|
|
303
|
+
configType,
|
|
304
|
+
service,
|
|
305
|
+
provider,
|
|
306
|
+
config,
|
|
307
|
+
priority,
|
|
308
|
+
is_default,
|
|
309
|
+
);
|
|
252
310
|
}
|
|
253
311
|
|
|
254
312
|
async getSupportedCombinations(): Promise<
|
|
@@ -275,7 +333,9 @@ export class CommunicationService {
|
|
|
275
333
|
await this.hubRepository.update(hubId, { status });
|
|
276
334
|
}
|
|
277
335
|
|
|
278
|
-
async sendGenericMessage(
|
|
336
|
+
async sendGenericMessage(
|
|
337
|
+
messageDto: GenericMessageDto,
|
|
338
|
+
): Promise<CommunicationResult> {
|
|
279
339
|
try {
|
|
280
340
|
const {
|
|
281
341
|
levelId,
|
|
@@ -291,17 +351,26 @@ export class CommunicationService {
|
|
|
291
351
|
attachments,
|
|
292
352
|
mediaUrl,
|
|
293
353
|
templateId,
|
|
294
|
-
variables
|
|
354
|
+
variables,
|
|
295
355
|
} = messageDto;
|
|
296
356
|
|
|
297
357
|
// Auto-detect communication type if not specified
|
|
298
358
|
const communicationType = this.detectCommunicationType(to, type);
|
|
299
|
-
|
|
359
|
+
|
|
300
360
|
// Get active hubs for the detected type
|
|
301
|
-
const hubs = await this.getActiveHubs(
|
|
302
|
-
|
|
361
|
+
const hubs = await this.getActiveHubs(
|
|
362
|
+
levelId,
|
|
363
|
+
levelType,
|
|
364
|
+
communicationType,
|
|
365
|
+
);
|
|
366
|
+
|
|
303
367
|
if (!hubs.length) {
|
|
304
|
-
|
|
368
|
+
this.logger.warn(
|
|
369
|
+
`No communication hubs found for ${levelType} ${levelId}. Please configure communication providers using the createCommunicationConfig method.`
|
|
370
|
+
);
|
|
371
|
+
throw new Error(
|
|
372
|
+
`No active ${communicationType} configuration found for ${levelType} ${levelId}. Please configure a communication provider first.`,
|
|
373
|
+
);
|
|
305
374
|
}
|
|
306
375
|
|
|
307
376
|
// Sort hubs by priority and default preference
|
|
@@ -338,10 +407,17 @@ export class CommunicationService {
|
|
|
338
407
|
}
|
|
339
408
|
|
|
340
409
|
// Merge config with enhanced parameters
|
|
341
|
-
const finalConfig = {
|
|
410
|
+
const finalConfig = {
|
|
411
|
+
...hub.config.config_json,
|
|
412
|
+
...enhancedConfig,
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
const result = await strategy.sendMessage(
|
|
416
|
+
recipient,
|
|
417
|
+
processedMessage,
|
|
418
|
+
finalConfig,
|
|
419
|
+
);
|
|
342
420
|
|
|
343
|
-
const result = await strategy.sendMessage(recipient, processedMessage, finalConfig);
|
|
344
|
-
|
|
345
421
|
if (result.success) {
|
|
346
422
|
this.logger.log(
|
|
347
423
|
`Generic message sent successfully via ${hub.provider}/${hub.service} to ${recipient}`,
|
|
@@ -367,7 +443,7 @@ export class CommunicationService {
|
|
|
367
443
|
if (hasSuccess) {
|
|
368
444
|
return {
|
|
369
445
|
success: true,
|
|
370
|
-
messageId: results.map(r => r.messageId).join(','),
|
|
446
|
+
messageId: results.map((r) => r.messageId).join(','),
|
|
371
447
|
provider: 'multiple',
|
|
372
448
|
service: 'multiple',
|
|
373
449
|
timestamp: new Date(),
|
|
@@ -390,10 +466,17 @@ export class CommunicationService {
|
|
|
390
466
|
}
|
|
391
467
|
|
|
392
468
|
// Merge config with enhanced parameters
|
|
393
|
-
const finalConfig = {
|
|
469
|
+
const finalConfig = {
|
|
470
|
+
...hub.config.config_json,
|
|
471
|
+
...enhancedConfig,
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
const result = await strategy.sendMessage(
|
|
475
|
+
to,
|
|
476
|
+
processedMessage,
|
|
477
|
+
finalConfig,
|
|
478
|
+
);
|
|
394
479
|
|
|
395
|
-
const result = await strategy.sendMessage(to, processedMessage, finalConfig);
|
|
396
|
-
|
|
397
480
|
if (result.success) {
|
|
398
481
|
this.logger.log(
|
|
399
482
|
`Generic message sent successfully via ${hub.provider}/${hub.service} to ${to}`,
|
|
@@ -421,7 +504,9 @@ export class CommunicationService {
|
|
|
421
504
|
}
|
|
422
505
|
}
|
|
423
506
|
|
|
424
|
-
async sendBulkMessage(
|
|
507
|
+
async sendBulkMessage(
|
|
508
|
+
bulkDto: BulkMessageDto,
|
|
509
|
+
): Promise<{ results: CommunicationResult[]; summary: any }> {
|
|
425
510
|
try {
|
|
426
511
|
const {
|
|
427
512
|
levelId,
|
|
@@ -434,7 +519,7 @@ export class CommunicationService {
|
|
|
434
519
|
html,
|
|
435
520
|
templateId,
|
|
436
521
|
variables,
|
|
437
|
-
batchSize = 10
|
|
522
|
+
batchSize = 10,
|
|
438
523
|
} = bulkDto;
|
|
439
524
|
|
|
440
525
|
const results: CommunicationResult[] = [];
|
|
@@ -442,7 +527,9 @@ export class CommunicationService {
|
|
|
442
527
|
|
|
443
528
|
for (let i = 0; i < batches.length; i++) {
|
|
444
529
|
const batch = batches[i];
|
|
445
|
-
this.logger.log(
|
|
530
|
+
this.logger.log(
|
|
531
|
+
`Processing batch ${i + 1}/${batches.length} with ${batch.length} recipients`,
|
|
532
|
+
);
|
|
446
533
|
|
|
447
534
|
const batchPromises = batch.map(async (recipient) => {
|
|
448
535
|
try {
|
|
@@ -490,18 +577,24 @@ export class CommunicationService {
|
|
|
490
577
|
|
|
491
578
|
// Rate limiting delay between batches
|
|
492
579
|
if (i < batches.length - 1) {
|
|
493
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
580
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
494
581
|
}
|
|
495
582
|
}
|
|
496
583
|
|
|
497
584
|
const summary = {
|
|
498
585
|
total: results.length,
|
|
499
|
-
successful: results.filter(r => r.success).length,
|
|
500
|
-
failed: results.filter(r => !r.success).length,
|
|
501
|
-
successRate:
|
|
586
|
+
successful: results.filter((r) => r.success).length,
|
|
587
|
+
failed: results.filter((r) => !r.success).length,
|
|
588
|
+
successRate:
|
|
589
|
+
(
|
|
590
|
+
(results.filter((r) => r.success).length / results.length) *
|
|
591
|
+
100
|
|
592
|
+
).toFixed(2) + '%',
|
|
502
593
|
};
|
|
503
594
|
|
|
504
|
-
this.logger.log(
|
|
595
|
+
this.logger.log(
|
|
596
|
+
`Bulk message completed: ${summary.successful}/${summary.total} successful`,
|
|
597
|
+
);
|
|
505
598
|
|
|
506
599
|
return { results, summary };
|
|
507
600
|
} catch (error) {
|
|
@@ -510,10 +603,12 @@ export class CommunicationService {
|
|
|
510
603
|
}
|
|
511
604
|
}
|
|
512
605
|
|
|
513
|
-
async scheduleMessage(
|
|
606
|
+
async scheduleMessage(
|
|
607
|
+
scheduledDto: any,
|
|
608
|
+
): Promise<{ scheduled: boolean; scheduleId?: string }> {
|
|
514
609
|
// For now, return a placeholder. In production, integrate with a job queue like Bull or Agenda
|
|
515
610
|
this.logger.log(`Message scheduled for ${scheduledDto.scheduleFor}`);
|
|
516
|
-
|
|
611
|
+
|
|
517
612
|
return {
|
|
518
613
|
scheduled: true,
|
|
519
614
|
scheduleId: `sched_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`,
|
|
@@ -523,9 +618,14 @@ export class CommunicationService {
|
|
|
523
618
|
async sendTemplateMessage(templateDto: any): Promise<CommunicationResult> {
|
|
524
619
|
// Get template content (integrate with your template system)
|
|
525
620
|
const template = await this.getTemplate(templateDto.templateId);
|
|
526
|
-
|
|
527
|
-
const processedMessage = this.processTemplate(
|
|
528
|
-
|
|
621
|
+
|
|
622
|
+
const processedMessage = this.processTemplate(
|
|
623
|
+
template.content,
|
|
624
|
+
templateDto.variables,
|
|
625
|
+
);
|
|
626
|
+
const processedSubject = template.subject
|
|
627
|
+
? this.processTemplate(template.subject, templateDto.variables)
|
|
628
|
+
: undefined;
|
|
529
629
|
|
|
530
630
|
const messageDto: GenericMessageDto = {
|
|
531
631
|
levelId: templateDto.levelId,
|
|
@@ -541,7 +641,10 @@ export class CommunicationService {
|
|
|
541
641
|
return this.sendGenericMessage(messageDto);
|
|
542
642
|
}
|
|
543
643
|
|
|
544
|
-
private detectCommunicationType(
|
|
644
|
+
private detectCommunicationType(
|
|
645
|
+
to: string | string[],
|
|
646
|
+
type?: string,
|
|
647
|
+
): CommunicationConfigType {
|
|
545
648
|
if (type) {
|
|
546
649
|
return type as CommunicationConfigType;
|
|
547
650
|
}
|
|
@@ -572,18 +675,23 @@ export class CommunicationService {
|
|
|
572
675
|
if (a.is_default !== b.is_default) {
|
|
573
676
|
return b.is_default ? 1 : -1;
|
|
574
677
|
}
|
|
575
|
-
|
|
678
|
+
|
|
576
679
|
// Then sort by priority (lower number = higher priority)
|
|
577
680
|
if (a.priority !== b.priority) {
|
|
578
681
|
return a.priority - b.priority;
|
|
579
682
|
}
|
|
580
|
-
|
|
683
|
+
|
|
581
684
|
// Finally sort by created_at descending (newest first)
|
|
582
|
-
return
|
|
685
|
+
return (
|
|
686
|
+
new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
|
|
687
|
+
);
|
|
583
688
|
});
|
|
584
689
|
}
|
|
585
690
|
|
|
586
|
-
private processTemplate(
|
|
691
|
+
private processTemplate(
|
|
692
|
+
template: string,
|
|
693
|
+
variables: Record<string, any>,
|
|
694
|
+
): string {
|
|
587
695
|
return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
|
|
588
696
|
const value = variables[key];
|
|
589
697
|
return value !== undefined ? String(value) : match;
|
|
@@ -617,15 +725,17 @@ export class CommunicationService {
|
|
|
617
725
|
// Get system OAuth credentials from config
|
|
618
726
|
const clientId = this.configService.get<string>('CLIENT_ID');
|
|
619
727
|
const clientSecret = this.configService.get<string>('CLIENT_SECRET');
|
|
620
|
-
|
|
728
|
+
|
|
621
729
|
if (!clientId || !clientSecret) {
|
|
622
730
|
throw new Error('Gmail OAuth credentials not configured');
|
|
623
731
|
}
|
|
624
732
|
|
|
625
733
|
const state = this.generateSecureState();
|
|
626
734
|
// Use the existing registered callback URL
|
|
627
|
-
const callbackUrl =
|
|
628
|
-
|
|
735
|
+
const callbackUrl =
|
|
736
|
+
this.configService.get<string>('CALLBACK_URL') ||
|
|
737
|
+
'http://localhost:5001/auth/google/callback';
|
|
738
|
+
|
|
629
739
|
this.gmailOAuthStates.set(state, {
|
|
630
740
|
levelId,
|
|
631
741
|
levelType,
|
|
@@ -634,9 +744,12 @@ export class CommunicationService {
|
|
|
634
744
|
});
|
|
635
745
|
|
|
636
746
|
// Auto-cleanup after 10 minutes
|
|
637
|
-
setTimeout(
|
|
638
|
-
|
|
639
|
-
|
|
747
|
+
setTimeout(
|
|
748
|
+
() => {
|
|
749
|
+
this.gmailOAuthStates.delete(state);
|
|
750
|
+
},
|
|
751
|
+
10 * 60 * 1000,
|
|
752
|
+
);
|
|
640
753
|
|
|
641
754
|
const oauth2Client = new google.auth.OAuth2(
|
|
642
755
|
clientId,
|
|
@@ -684,7 +797,9 @@ export class CommunicationService {
|
|
|
684
797
|
// Get system OAuth credentials
|
|
685
798
|
const clientId = this.configService.get<string>('CLIENT_ID');
|
|
686
799
|
const clientSecret = this.configService.get<string>('CLIENT_SECRET');
|
|
687
|
-
const callbackUrl =
|
|
800
|
+
const callbackUrl =
|
|
801
|
+
this.configService.get<string>('CALLBACK_URL') ||
|
|
802
|
+
'http://localhost:5001/auth/google/callback';
|
|
688
803
|
|
|
689
804
|
const oauth2Client = new google.auth.OAuth2(
|
|
690
805
|
clientId,
|
|
@@ -693,7 +808,7 @@ export class CommunicationService {
|
|
|
693
808
|
);
|
|
694
809
|
|
|
695
810
|
const { tokens } = await oauth2Client.getToken(code);
|
|
696
|
-
|
|
811
|
+
|
|
697
812
|
if (!tokens.access_token) {
|
|
698
813
|
throw new Error('Failed to obtain access token');
|
|
699
814
|
}
|
|
@@ -821,11 +936,15 @@ export class CommunicationService {
|
|
|
821
936
|
};
|
|
822
937
|
} catch (error) {
|
|
823
938
|
this.logger.error('Error handling Gmail tokens callback:', error.message);
|
|
824
|
-
throw new Error(
|
|
939
|
+
throw new Error(
|
|
940
|
+
`Failed to complete Gmail tokens callback: ${error.message}`,
|
|
941
|
+
);
|
|
825
942
|
}
|
|
826
943
|
}
|
|
827
944
|
|
|
828
|
-
async testGmailConfig(
|
|
945
|
+
async testGmailConfig(
|
|
946
|
+
hubId: number,
|
|
947
|
+
): Promise<{ success: boolean; error?: string }> {
|
|
829
948
|
try {
|
|
830
949
|
const hub = await this.hubRepository.findOne({
|
|
831
950
|
where: { id: hubId },
|
|
@@ -843,10 +962,15 @@ export class CommunicationService {
|
|
|
843
962
|
throw new Error('Configuration not found');
|
|
844
963
|
}
|
|
845
964
|
|
|
846
|
-
const isValid = await this.gmailApiStrategy.validateConnection(
|
|
847
|
-
|
|
965
|
+
const isValid = await this.gmailApiStrategy.validateConnection(
|
|
966
|
+
config.config_json,
|
|
967
|
+
);
|
|
968
|
+
|
|
848
969
|
if (!isValid) {
|
|
849
|
-
return {
|
|
970
|
+
return {
|
|
971
|
+
success: false,
|
|
972
|
+
error: 'Gmail configuration is invalid or expired',
|
|
973
|
+
};
|
|
850
974
|
}
|
|
851
975
|
|
|
852
976
|
return { success: true };
|
|
@@ -864,20 +988,20 @@ export class CommunicationService {
|
|
|
864
988
|
configType: CommunicationConfigType,
|
|
865
989
|
service: string,
|
|
866
990
|
provider: string,
|
|
867
|
-
config: any
|
|
991
|
+
config: any,
|
|
868
992
|
): boolean {
|
|
869
993
|
// Check if config indicates OAuth is needed (missing tokens or explicit OAuth request)
|
|
870
994
|
const key = `${configType.toLowerCase()}_${service.toLowerCase()}_${provider.toLowerCase()}`;
|
|
871
|
-
|
|
995
|
+
|
|
872
996
|
switch (key) {
|
|
873
997
|
case 'email_api_gmail':
|
|
874
998
|
// Requires OAuth if no access token provided or OAuth explicitly requested
|
|
875
999
|
return !config.accessToken || config.useOAuth === true;
|
|
876
|
-
|
|
1000
|
+
|
|
877
1001
|
case 'email_api_outlook':
|
|
878
1002
|
// Requires OAuth if no access token provided or OAuth explicitly requested
|
|
879
1003
|
return !config.accessToken || config.useOAuth === true;
|
|
880
|
-
|
|
1004
|
+
|
|
881
1005
|
default:
|
|
882
1006
|
// Most other providers don't require OAuth
|
|
883
1007
|
return false;
|
|
@@ -892,29 +1016,41 @@ export class CommunicationService {
|
|
|
892
1016
|
provider: string,
|
|
893
1017
|
config: any,
|
|
894
1018
|
priority?: number,
|
|
895
|
-
is_default?: boolean
|
|
1019
|
+
is_default?: boolean,
|
|
896
1020
|
): Promise<{ authUrl: string; state: string; message: string }> {
|
|
897
1021
|
const key = `${configType.toLowerCase()}_${service.toLowerCase()}_${provider.toLowerCase()}`;
|
|
898
|
-
|
|
1022
|
+
|
|
899
1023
|
switch (key) {
|
|
900
1024
|
case 'email_api_gmail':
|
|
901
|
-
const gmailResult = await this.initGmailOAuth(
|
|
1025
|
+
const gmailResult = await this.initGmailOAuth(
|
|
1026
|
+
levelId,
|
|
1027
|
+
levelType,
|
|
1028
|
+
config.email,
|
|
1029
|
+
);
|
|
902
1030
|
return {
|
|
903
1031
|
authUrl: gmailResult.authUrl,
|
|
904
1032
|
state: gmailResult.state,
|
|
905
|
-
message:
|
|
1033
|
+
message:
|
|
1034
|
+
'Please complete Gmail OAuth authorization. Configuration will be created automatically after authorization.',
|
|
906
1035
|
};
|
|
907
|
-
|
|
1036
|
+
|
|
908
1037
|
case 'email_api_outlook':
|
|
909
|
-
const outlookResult = await this.initOutlookOAuth(
|
|
1038
|
+
const outlookResult = await this.initOutlookOAuth(
|
|
1039
|
+
levelId,
|
|
1040
|
+
levelType,
|
|
1041
|
+
config.email,
|
|
1042
|
+
);
|
|
910
1043
|
return {
|
|
911
1044
|
authUrl: outlookResult.authUrl,
|
|
912
1045
|
state: outlookResult.state,
|
|
913
|
-
message:
|
|
1046
|
+
message:
|
|
1047
|
+
'Please complete Outlook OAuth authorization. Configuration will be created automatically after authorization.',
|
|
914
1048
|
};
|
|
915
|
-
|
|
1049
|
+
|
|
916
1050
|
default:
|
|
917
|
-
throw new Error(
|
|
1051
|
+
throw new Error(
|
|
1052
|
+
`OAuth not supported for ${configType}/${service}/${provider}`,
|
|
1053
|
+
);
|
|
918
1054
|
}
|
|
919
1055
|
}
|
|
920
1056
|
|
|
@@ -926,23 +1062,23 @@ export class CommunicationService {
|
|
|
926
1062
|
provider: string,
|
|
927
1063
|
config: any,
|
|
928
1064
|
priority?: number,
|
|
929
|
-
is_default?: boolean
|
|
1065
|
+
is_default?: boolean,
|
|
930
1066
|
): Promise<CommunicationHub> {
|
|
931
1067
|
// If setting as default, remove default from other configurations of same type
|
|
932
1068
|
if (is_default) {
|
|
933
1069
|
await this.hubRepository.update(
|
|
934
|
-
{
|
|
1070
|
+
{
|
|
935
1071
|
level_id: levelId,
|
|
936
1072
|
level_type: levelType,
|
|
937
1073
|
communication_config_type: configType,
|
|
938
1074
|
},
|
|
939
|
-
{ is_default: false }
|
|
1075
|
+
{ is_default: false },
|
|
940
1076
|
);
|
|
941
1077
|
}
|
|
942
1078
|
|
|
943
1079
|
// First, create the config
|
|
944
1080
|
const communicationConfig = this.configRepository.create({
|
|
945
|
-
config_json: config
|
|
1081
|
+
config_json: config,
|
|
946
1082
|
});
|
|
947
1083
|
const savedConfig = await this.configRepository.save(communicationConfig);
|
|
948
1084
|
|
|
@@ -960,8 +1096,10 @@ export class CommunicationService {
|
|
|
960
1096
|
});
|
|
961
1097
|
|
|
962
1098
|
const savedHub = await this.hubRepository.save(hub);
|
|
963
|
-
this.logger.log(
|
|
964
|
-
|
|
1099
|
+
this.logger.log(
|
|
1100
|
+
`Communication config created: ${configType}/${service}/${provider} for ${levelType} ${levelId}`,
|
|
1101
|
+
);
|
|
1102
|
+
|
|
965
1103
|
return Array.isArray(savedHub) ? savedHub[0] : savedHub;
|
|
966
1104
|
}
|
|
967
1105
|
|
|
@@ -974,14 +1112,16 @@ export class CommunicationService {
|
|
|
974
1112
|
// Get system OAuth credentials from config
|
|
975
1113
|
const clientId = this.configService.get<string>('OUTLOOK_CLIENT_ID');
|
|
976
1114
|
const tenantId = this.configService.get<string>('OUTLOOK_TENANT_ID');
|
|
977
|
-
|
|
1115
|
+
|
|
978
1116
|
if (!clientId || !tenantId) {
|
|
979
1117
|
throw new Error('Outlook OAuth credentials not configured');
|
|
980
1118
|
}
|
|
981
1119
|
|
|
982
1120
|
const state = this.generateSecureState();
|
|
983
|
-
const callbackUrl =
|
|
984
|
-
|
|
1121
|
+
const callbackUrl =
|
|
1122
|
+
this.configService.get<string>('OUTLOOK_CALLBACK_URL') ||
|
|
1123
|
+
'http://localhost:5001/auth/outlook/callback';
|
|
1124
|
+
|
|
985
1125
|
this.gmailOAuthStates.set(state, {
|
|
986
1126
|
levelId,
|
|
987
1127
|
levelType,
|
|
@@ -990,16 +1130,20 @@ export class CommunicationService {
|
|
|
990
1130
|
});
|
|
991
1131
|
|
|
992
1132
|
// Auto-cleanup after 10 minutes
|
|
993
|
-
setTimeout(
|
|
994
|
-
|
|
995
|
-
|
|
1133
|
+
setTimeout(
|
|
1134
|
+
() => {
|
|
1135
|
+
this.gmailOAuthStates.delete(state);
|
|
1136
|
+
},
|
|
1137
|
+
10 * 60 * 1000,
|
|
1138
|
+
);
|
|
996
1139
|
|
|
997
1140
|
const scopes = [
|
|
998
1141
|
'https://graph.microsoft.com/Mail.Send',
|
|
999
1142
|
'https://graph.microsoft.com/User.Read',
|
|
1000
1143
|
];
|
|
1001
1144
|
|
|
1002
|
-
const authUrl =
|
|
1145
|
+
const authUrl =
|
|
1146
|
+
`https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/authorize?` +
|
|
1003
1147
|
`client_id=${clientId}&` +
|
|
1004
1148
|
`response_type=code&` +
|
|
1005
1149
|
`redirect_uri=${encodeURIComponent(callbackUrl)}&` +
|
|
@@ -1033,27 +1177,34 @@ export class CommunicationService {
|
|
|
1033
1177
|
}
|
|
1034
1178
|
|
|
1035
1179
|
const clientId = this.configService.get<string>('OUTLOOK_CLIENT_ID');
|
|
1036
|
-
const clientSecret = this.configService.get<string>(
|
|
1180
|
+
const clientSecret = this.configService.get<string>(
|
|
1181
|
+
'OUTLOOK_CLIENT_SECRET',
|
|
1182
|
+
);
|
|
1037
1183
|
const tenantId = this.configService.get<string>('OUTLOOK_TENANT_ID');
|
|
1038
|
-
const callbackUrl =
|
|
1184
|
+
const callbackUrl =
|
|
1185
|
+
this.configService.get<string>('OUTLOOK_CALLBACK_URL') ||
|
|
1186
|
+
'http://localhost:5001/auth/outlook/callback';
|
|
1039
1187
|
|
|
1040
1188
|
// Exchange code for tokens
|
|
1041
|
-
const tokenResponse = await fetch(
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1189
|
+
const tokenResponse = await fetch(
|
|
1190
|
+
`https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`,
|
|
1191
|
+
{
|
|
1192
|
+
method: 'POST',
|
|
1193
|
+
headers: {
|
|
1194
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
1195
|
+
},
|
|
1196
|
+
body: new URLSearchParams({
|
|
1197
|
+
client_id: clientId!,
|
|
1198
|
+
client_secret: clientSecret!,
|
|
1199
|
+
code: code,
|
|
1200
|
+
redirect_uri: callbackUrl,
|
|
1201
|
+
grant_type: 'authorization_code',
|
|
1202
|
+
}),
|
|
1045
1203
|
},
|
|
1046
|
-
|
|
1047
|
-
client_id: clientId!,
|
|
1048
|
-
client_secret: clientSecret!,
|
|
1049
|
-
code: code,
|
|
1050
|
-
redirect_uri: callbackUrl,
|
|
1051
|
-
grant_type: 'authorization_code',
|
|
1052
|
-
}),
|
|
1053
|
-
});
|
|
1204
|
+
);
|
|
1054
1205
|
|
|
1055
1206
|
const tokens = await tokenResponse.json();
|
|
1056
|
-
|
|
1207
|
+
|
|
1057
1208
|
if (!tokens.access_token) {
|
|
1058
1209
|
throw new Error('Failed to obtain access token');
|
|
1059
1210
|
}
|
|
@@ -1061,7 +1212,7 @@ export class CommunicationService {
|
|
|
1061
1212
|
// Get user info from Microsoft Graph
|
|
1062
1213
|
const userResponse = await fetch('https://graph.microsoft.com/v1.0/me', {
|
|
1063
1214
|
headers: {
|
|
1064
|
-
|
|
1215
|
+
Authorization: `Bearer ${tokens.access_token}`,
|
|
1065
1216
|
},
|
|
1066
1217
|
});
|
|
1067
1218
|
|
|
@@ -1111,8 +1262,126 @@ export class CommunicationService {
|
|
|
1111
1262
|
configId: savedConfig.id,
|
|
1112
1263
|
};
|
|
1113
1264
|
} catch (error) {
|
|
1114
|
-
this.logger.error(
|
|
1265
|
+
this.logger.error(
|
|
1266
|
+
'Error handling Outlook OAuth callback:',
|
|
1267
|
+
error.message,
|
|
1268
|
+
);
|
|
1115
1269
|
throw new Error(`Failed to complete Outlook OAuth: ${error.message}`);
|
|
1116
1270
|
}
|
|
1117
1271
|
}
|
|
1272
|
+
|
|
1273
|
+
// Simple Queue Integration Methods
|
|
1274
|
+
|
|
1275
|
+
async queueMessage(
|
|
1276
|
+
messageDto: GenericMessageDto & { useQueue?: boolean; scheduledFor?: Date },
|
|
1277
|
+
): Promise<{ queued: boolean; messageId?: string; result?: CommunicationResult }> {
|
|
1278
|
+
if (!this.queueService || !messageDto.useQueue) {
|
|
1279
|
+
// Fallback to immediate sending if queue is not available or not requested
|
|
1280
|
+
const result = await this.sendGenericMessage(messageDto);
|
|
1281
|
+
return { queued: false, result };
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
try {
|
|
1285
|
+
const priority = this.mapPriorityToSimpleQueue(messageDto.priority);
|
|
1286
|
+
|
|
1287
|
+
const messageId = await this.queueService.queueMessage(
|
|
1288
|
+
messageDto.levelId,
|
|
1289
|
+
messageDto.levelType,
|
|
1290
|
+
Array.isArray(messageDto.to) ? messageDto.to[0] : messageDto.to,
|
|
1291
|
+
messageDto.message,
|
|
1292
|
+
messageDto.type,
|
|
1293
|
+
priority,
|
|
1294
|
+
messageDto.scheduledFor,
|
|
1295
|
+
{
|
|
1296
|
+
subject: messageDto.subject,
|
|
1297
|
+
html: messageDto.html,
|
|
1298
|
+
cc: messageDto.cc,
|
|
1299
|
+
bcc: messageDto.bcc,
|
|
1300
|
+
attachments: messageDto.attachments,
|
|
1301
|
+
mediaUrl: messageDto.mediaUrl,
|
|
1302
|
+
templateId: messageDto.templateId,
|
|
1303
|
+
variables: messageDto.variables,
|
|
1304
|
+
},
|
|
1305
|
+
);
|
|
1306
|
+
|
|
1307
|
+
return { queued: true, messageId };
|
|
1308
|
+
} catch (error) {
|
|
1309
|
+
this.logger.error('Error queuing message, falling back to immediate send:', error.message);
|
|
1310
|
+
// Fallback to immediate sending
|
|
1311
|
+
const result = await this.sendGenericMessage(messageDto);
|
|
1312
|
+
return { queued: false, result };
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
async queueBulkMessage(
|
|
1317
|
+
bulkDto: BulkMessageDto & { useQueue?: boolean; scheduledFor?: Date },
|
|
1318
|
+
): Promise<{ queued: boolean; messageIds?: string[]; result?: any }> {
|
|
1319
|
+
if (!this.queueService || !bulkDto.useQueue) {
|
|
1320
|
+
// Fallback to immediate sending if queue is not available or not requested
|
|
1321
|
+
const result = await this.sendBulkMessage(bulkDto);
|
|
1322
|
+
return { queued: false, result };
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
try {
|
|
1326
|
+
const priority = this.mapPriorityToSimpleQueue(bulkDto.priority) || 'low';
|
|
1327
|
+
|
|
1328
|
+
const messageIds = await this.queueService.queueBulkMessages(
|
|
1329
|
+
bulkDto.levelId,
|
|
1330
|
+
bulkDto.levelType,
|
|
1331
|
+
bulkDto.recipients,
|
|
1332
|
+
bulkDto.message,
|
|
1333
|
+
bulkDto.type,
|
|
1334
|
+
priority,
|
|
1335
|
+
{
|
|
1336
|
+
subject: bulkDto.subject,
|
|
1337
|
+
html: bulkDto.html,
|
|
1338
|
+
templateId: bulkDto.templateId,
|
|
1339
|
+
variables: bulkDto.variables,
|
|
1340
|
+
},
|
|
1341
|
+
);
|
|
1342
|
+
|
|
1343
|
+
return { queued: true, messageIds };
|
|
1344
|
+
} catch (error) {
|
|
1345
|
+
this.logger.error('Error queuing bulk message, falling back to immediate send:', error.message);
|
|
1346
|
+
// Fallback to immediate sending
|
|
1347
|
+
const result = await this.sendBulkMessage(bulkDto);
|
|
1348
|
+
return { queued: false, result };
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
// Helper method to check if queue service is available
|
|
1353
|
+
isQueueAvailable(): boolean {
|
|
1354
|
+
return !!this.queueService;
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
// Helper method to get queue stats if available
|
|
1358
|
+
getQueueStats() {
|
|
1359
|
+
if (!this.queueService) {
|
|
1360
|
+
return null;
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
return this.queueService.getQueueStats();
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
// Helper method to cancel queued messages
|
|
1367
|
+
cancelQueuedMessage(messageId: string): boolean {
|
|
1368
|
+
if (!this.queueService) {
|
|
1369
|
+
return false;
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
return this.queueService.cancelMessage(messageId);
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
private mapPriorityToSimpleQueue(priority?: string): 'high' | 'medium' | 'low' {
|
|
1376
|
+
switch (priority?.toLowerCase()) {
|
|
1377
|
+
case 'high':
|
|
1378
|
+
case 'urgent':
|
|
1379
|
+
return 'high';
|
|
1380
|
+
case 'low':
|
|
1381
|
+
return 'low';
|
|
1382
|
+
case 'medium':
|
|
1383
|
+
default:
|
|
1384
|
+
return 'medium';
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1118
1387
|
}
|