rez_core 2.2.258 → 2.2.259

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. package/dist/app.module.js +2 -2
  2. package/dist/app.module.js.map +1 -1
  3. package/dist/module/integration/controller/calender-event.controller.js.map +1 -0
  4. package/dist/module/integration/controller/integration.controller.d.ts +113 -0
  5. package/dist/module/{communication/controller/communication.controller.js → integration/controller/integration.controller.js} +197 -75
  6. package/dist/module/integration/controller/integration.controller.js.map +1 -0
  7. package/dist/module/{communication → integration}/controller/wrapper.controller.d.ts +1 -1
  8. package/dist/module/integration/controller/wrapper.controller.js.map +1 -0
  9. package/dist/module/{communication → integration}/dto/create-config.dto.d.ts +48 -4
  10. package/dist/module/{communication → integration}/dto/create-config.dto.js +96 -18
  11. package/dist/module/integration/dto/create-config.dto.js.map +1 -0
  12. package/dist/module/{communication/entity/communication-config.entity.d.ts → integration/entity/integration-config.entity.d.ts} +11 -1
  13. package/dist/module/integration/entity/integration-config.entity.js +78 -0
  14. package/dist/module/integration/entity/integration-config.entity.js.map +1 -0
  15. package/dist/module/{communication → integration}/entity/integration-source.entity.d.ts +1 -1
  16. package/dist/module/{communication → integration}/entity/integration-source.entity.js +8 -8
  17. package/dist/module/integration/entity/integration-source.entity.js.map +1 -0
  18. package/dist/module/integration/entity/user-integration.entity.d.ts +23 -0
  19. package/dist/module/integration/entity/user-integration.entity.js +70 -0
  20. package/dist/module/integration/entity/user-integration.entity.js.map +1 -0
  21. package/dist/module/integration/examples/usage.example.d.ts +16 -0
  22. package/dist/module/integration/examples/usage.example.js +217 -0
  23. package/dist/module/integration/examples/usage.example.js.map +1 -0
  24. package/dist/module/{communication → integration}/factories/base.factory.d.ts +2 -2
  25. package/dist/module/integration/factories/base.factory.js.map +1 -0
  26. package/dist/module/{communication → integration}/factories/email.factory.d.ts +3 -7
  27. package/dist/module/{communication → integration}/factories/email.factory.js +1 -13
  28. package/dist/module/integration/factories/email.factory.js.map +1 -0
  29. package/dist/module/{communication/factories/communication.factory.d.ts → integration/factories/integration.factory.d.ts} +4 -4
  30. package/dist/module/{communication/factories/communication.factory.js → integration/factories/integration.factory.js} +26 -26
  31. package/dist/module/integration/factories/integration.factory.js.map +1 -0
  32. package/dist/module/integration/factories/sms.factory.d.ts +9 -0
  33. package/dist/module/integration/factories/sms.factory.js +26 -0
  34. package/dist/module/integration/factories/sms.factory.js.map +1 -0
  35. package/dist/module/{communication → integration}/factories/telephone.factory.d.ts +3 -5
  36. package/dist/module/{communication → integration}/factories/telephone.factory.js +11 -17
  37. package/dist/module/integration/factories/telephone.factory.js.map +1 -0
  38. package/dist/module/{communication → integration}/factories/whatsapp.factory.d.ts +2 -2
  39. package/dist/module/integration/factories/whatsapp.factory.js.map +1 -0
  40. package/dist/module/integration/integration.module.d.ts +2 -0
  41. package/dist/module/{communication/communication.module.js → integration/integration.module.js} +22 -42
  42. package/dist/module/integration/integration.module.js.map +1 -0
  43. package/dist/module/integration/service/calendar-event.service.js.map +1 -0
  44. package/dist/module/{communication/service/communication-queue.service.d.ts → integration/service/integration-queue.service.d.ts} +1 -1
  45. package/dist/module/{communication/service/communication-queue.service.js → integration/service/integration-queue.service.js} +8 -8
  46. package/dist/module/integration/service/integration-queue.service.js.map +1 -0
  47. package/dist/module/integration/service/integration.service.d.ts +155 -0
  48. package/dist/module/{communication/service/communication.service.js → integration/service/integration.service.js} +391 -307
  49. package/dist/module/integration/service/integration.service.js.map +1 -0
  50. package/dist/module/{communication → integration}/service/oauth.service.js +1 -1
  51. package/dist/module/integration/service/oauth.service.js.map +1 -0
  52. package/dist/module/{communication → integration}/service/wrapper.service.d.ts +4 -4
  53. package/dist/module/{communication → integration}/service/wrapper.service.js +25 -26
  54. package/dist/module/integration/service/wrapper.service.js.map +1 -0
  55. package/dist/module/{communication → integration}/strategies/email/gmail-api.strategy.d.ts +3 -3
  56. package/dist/module/{communication → integration}/strategies/email/gmail-api.strategy.js +2 -6
  57. package/dist/module/integration/strategies/email/gmail-api.strategy.js.map +1 -0
  58. package/dist/module/integration/strategies/email/outlook-api.strategy.d.ts +5 -0
  59. package/dist/module/integration/strategies/email/outlook-api.strategy.js.map +1 -0
  60. package/dist/module/integration/strategies/email/outlook.strategy.d.ts +5 -0
  61. package/dist/module/integration/strategies/email/outlook.strategy.js.map +1 -0
  62. package/dist/module/{communication → integration}/strategies/email/sendgrid-api.strategy.d.ts +3 -3
  63. package/dist/module/integration/strategies/email/sendgrid-api.strategy.js.map +1 -0
  64. package/dist/module/{communication/strategies/communication.strategy.d.ts → integration/strategies/integration.strategy.d.ts} +4 -3
  65. package/dist/module/{communication/strategies/communication.strategy.js → integration/strategies/integration.strategy.js} +1 -1
  66. package/dist/module/integration/strategies/integration.strategy.js.map +1 -0
  67. package/dist/module/integration/strategies/telephone/ozonetel-voice.strategy.d.ts +17 -0
  68. package/dist/module/{communication → integration}/strategies/telephone/ozonetel-voice.strategy.js +13 -5
  69. package/dist/module/integration/strategies/telephone/ozonetel-voice.strategy.js.map +1 -0
  70. package/dist/module/{communication → integration}/strategies/telephone/tubelight-voice.strategy.d.ts +6 -4
  71. package/dist/module/{communication → integration}/strategies/telephone/tubelight-voice.strategy.js +3 -7
  72. package/dist/module/integration/strategies/telephone/tubelight-voice.strategy.js.map +1 -0
  73. package/dist/module/{communication → integration}/strategies/whatsapp/whatsapp-cloud.strategy.d.ts +3 -3
  74. package/dist/module/integration/strategies/whatsapp/whatsapp-cloud.strategy.js.map +1 -0
  75. package/dist/module/integration/strategies/whatsapp/whatsapp.strategy.d.ts +5 -0
  76. package/dist/module/integration/strategies/whatsapp/whatsapp.strategy.js.map +1 -0
  77. package/dist/module/meta/entity/entity-master.entity.d.ts +1 -1
  78. package/dist/module/meta/entity/entity-master.entity.js +2 -2
  79. package/dist/module/meta/entity/entity-master.entity.js.map +1 -1
  80. package/dist/module/meta/service/entity-dynamic.service.js +47 -27
  81. package/dist/module/meta/service/entity-dynamic.service.js.map +1 -1
  82. package/dist/module/user/controller/login.controller.d.ts +3 -3
  83. package/dist/module/user/controller/login.controller.js +5 -5
  84. package/dist/module/user/controller/login.controller.js.map +1 -1
  85. package/dist/module/user/user.module.js +2 -2
  86. package/dist/module/user/user.module.js.map +1 -1
  87. package/dist/module/workflow-automation/entity/workflow-automation-action.entity.d.ts +1 -0
  88. package/dist/module/workflow-automation/entity/workflow-automation-action.entity.js +4 -0
  89. package/dist/module/workflow-automation/entity/workflow-automation-action.entity.js.map +1 -1
  90. package/dist/module/workflow-automation/service/workflow-automation.service.d.ts +2 -1
  91. package/dist/module/workflow-automation/service/workflow-automation.service.js +8 -4
  92. package/dist/module/workflow-automation/service/workflow-automation.service.js.map +1 -1
  93. package/dist/tsconfig.build.tsbuildinfo +1 -1
  94. package/docs/modules/event-driven-integration-design.md +92 -0
  95. package/docs/modules/integration.md +197 -0
  96. package/package.json +1 -1
  97. package/src/app.module.ts +2 -2
  98. package/src/module/integration/controller/integration.controller.ts +411 -0
  99. package/src/module/{communication → integration}/dto/create-config.dto.ts +110 -18
  100. package/src/module/{communication/entity/communication-config.entity.ts → integration/entity/integration-config.entity.ts} +33 -6
  101. package/src/module/{communication → integration}/entity/integration-source.entity.ts +1 -1
  102. package/src/module/integration/entity/user-integration.entity.ts +71 -0
  103. package/src/module/integration/examples/usage.example.ts +338 -0
  104. package/src/module/{communication → integration}/factories/base.factory.ts +2 -2
  105. package/src/module/{communication → integration}/factories/email.factory.ts +2 -12
  106. package/src/module/{communication/factories/communication.factory.ts → integration/factories/integration.factory.ts} +18 -18
  107. package/src/module/integration/factories/sms.factory.ts +19 -0
  108. package/src/module/integration/factories/telephone.factory.ts +41 -0
  109. package/src/module/{communication → integration}/factories/whatsapp.factory.ts +2 -2
  110. package/src/module/integration/integration.module.ts +86 -0
  111. package/src/module/{communication/service/communication-queue.service.ts → integration/service/integration-queue.service.ts} +2 -2
  112. package/src/module/{communication/service/communication.service.ts → integration/service/integration.service.ts} +598 -448
  113. package/src/module/{communication → integration}/service/oauth.service.ts +1 -1
  114. package/src/module/{communication → integration}/service/wrapper.service.ts +24 -25
  115. package/src/module/{communication → integration}/strategies/email/gmail-api.strategy.ts +6 -18
  116. package/src/module/{communication → integration}/strategies/email/outlook-api.strategy.ts +5 -5
  117. package/src/module/{communication → integration}/strategies/email/outlook.strategy.ts +5 -5
  118. package/src/module/{communication → integration}/strategies/email/sendgrid-api.strategy.ts +5 -5
  119. package/src/module/{communication/strategies/communication.strategy.ts → integration/strategies/integration.strategy.ts} +7 -3
  120. package/src/module/{communication → integration}/strategies/telephone/ozonetel-voice.strategy.ts +40 -12
  121. package/src/module/{communication → integration}/strategies/telephone/tubelight-voice.strategy.ts +24 -17
  122. package/src/module/{communication → integration}/strategies/whatsapp/whatsapp-cloud.strategy.ts +5 -5
  123. package/src/module/{communication → integration}/strategies/whatsapp/whatsapp.strategy.ts +5 -5
  124. package/src/module/meta/entity/entity-master.entity.ts +2 -2
  125. package/src/module/meta/service/entity-dynamic.service.ts +55 -28
  126. package/src/module/user/controller/login.controller.ts +3 -3
  127. package/src/module/user/user.module.ts +2 -2
  128. package/src/module/workflow-automation/entity/workflow-automation-action.entity.ts +3 -0
  129. package/src/module/workflow-automation/service/workflow-automation.service.ts +8 -4
  130. package/src/resources/dev.properties.yaml +3 -3
  131. package/.vscode/extensions.json +0 -5
  132. package/dist/module/communication/communication.module.d.ts +0 -2
  133. package/dist/module/communication/communication.module.js.map +0 -1
  134. package/dist/module/communication/controller/calender-event.controller.js.map +0 -1
  135. package/dist/module/communication/controller/communication.controller.d.ts +0 -99
  136. package/dist/module/communication/controller/communication.controller.js.map +0 -1
  137. package/dist/module/communication/controller/wrapper.controller.js.map +0 -1
  138. package/dist/module/communication/dto/create-config.dto.js.map +0 -1
  139. package/dist/module/communication/entity/communication-config.entity.js +0 -45
  140. package/dist/module/communication/entity/communication-config.entity.js.map +0 -1
  141. package/dist/module/communication/entity/communication-hub.entity.d.ts +0 -20
  142. package/dist/module/communication/entity/communication-hub.entity.js +0 -115
  143. package/dist/module/communication/entity/communication-hub.entity.js.map +0 -1
  144. package/dist/module/communication/entity/integration-source.entity.js.map +0 -1
  145. package/dist/module/communication/examples/usage.example.d.ts +0 -11
  146. package/dist/module/communication/examples/usage.example.js +0 -89
  147. package/dist/module/communication/examples/usage.example.js.map +0 -1
  148. package/dist/module/communication/factories/base.factory.js.map +0 -1
  149. package/dist/module/communication/factories/communication.factory.js.map +0 -1
  150. package/dist/module/communication/factories/email.factory.js.map +0 -1
  151. package/dist/module/communication/factories/sms.factory.d.ts +0 -15
  152. package/dist/module/communication/factories/sms.factory.js +0 -49
  153. package/dist/module/communication/factories/sms.factory.js.map +0 -1
  154. package/dist/module/communication/factories/telephone.factory.js.map +0 -1
  155. package/dist/module/communication/factories/whatsapp.factory.js.map +0 -1
  156. package/dist/module/communication/service/calendar-event.service.js.map +0 -1
  157. package/dist/module/communication/service/communication-queue.service.js.map +0 -1
  158. package/dist/module/communication/service/communication.service.d.ts +0 -155
  159. package/dist/module/communication/service/communication.service.js.map +0 -1
  160. package/dist/module/communication/service/oauth.service.js.map +0 -1
  161. package/dist/module/communication/service/wrapper.service.js.map +0 -1
  162. package/dist/module/communication/strategies/communication.strategy.js.map +0 -1
  163. package/dist/module/communication/strategies/email/gmail-api.strategy.js.map +0 -1
  164. package/dist/module/communication/strategies/email/gmail-smtp-v2.strategy.d.ts +0 -5
  165. package/dist/module/communication/strategies/email/gmail-smtp-v2.strategy.js +0 -60
  166. package/dist/module/communication/strategies/email/gmail-smtp-v2.strategy.js.map +0 -1
  167. package/dist/module/communication/strategies/email/gmail-smtp.strategy.d.ts +0 -5
  168. package/dist/module/communication/strategies/email/gmail-smtp.strategy.js +0 -49
  169. package/dist/module/communication/strategies/email/gmail-smtp.strategy.js.map +0 -1
  170. package/dist/module/communication/strategies/email/outlook-api.strategy.d.ts +0 -5
  171. package/dist/module/communication/strategies/email/outlook-api.strategy.js.map +0 -1
  172. package/dist/module/communication/strategies/email/outlook-smtp.strategy.d.ts +0 -5
  173. package/dist/module/communication/strategies/email/outlook-smtp.strategy.js +0 -65
  174. package/dist/module/communication/strategies/email/outlook-smtp.strategy.js.map +0 -1
  175. package/dist/module/communication/strategies/email/outlook.strategy.d.ts +0 -5
  176. package/dist/module/communication/strategies/email/outlook.strategy.js.map +0 -1
  177. package/dist/module/communication/strategies/email/sendgrid-api.strategy.js.map +0 -1
  178. package/dist/module/communication/strategies/sms/knowlarity-multi.strategy.d.ts +0 -6
  179. package/dist/module/communication/strategies/sms/knowlarity-multi.strategy.js +0 -121
  180. package/dist/module/communication/strategies/sms/knowlarity-multi.strategy.js.map +0 -1
  181. package/dist/module/communication/strategies/sms/knowlarity.strategy.d.ts +0 -5
  182. package/dist/module/communication/strategies/sms/knowlarity.strategy.js +0 -44
  183. package/dist/module/communication/strategies/sms/knowlarity.strategy.js.map +0 -1
  184. package/dist/module/communication/strategies/sms/twilio-v2.strategy.d.ts +0 -5
  185. package/dist/module/communication/strategies/sms/twilio-v2.strategy.js +0 -48
  186. package/dist/module/communication/strategies/sms/twilio-v2.strategy.js.map +0 -1
  187. package/dist/module/communication/strategies/sms/twilio.strategy.d.ts +0 -5
  188. package/dist/module/communication/strategies/sms/twilio.strategy.js +0 -44
  189. package/dist/module/communication/strategies/sms/twilio.strategy.js.map +0 -1
  190. package/dist/module/communication/strategies/telephone/knowlarity-multi.strategy.d.ts +0 -6
  191. package/dist/module/communication/strategies/telephone/knowlarity-multi.strategy.js +0 -121
  192. package/dist/module/communication/strategies/telephone/knowlarity-multi.strategy.js.map +0 -1
  193. package/dist/module/communication/strategies/telephone/knowlarity-voice.strategy.d.ts +0 -5
  194. package/dist/module/communication/strategies/telephone/knowlarity-voice.strategy.js +0 -44
  195. package/dist/module/communication/strategies/telephone/knowlarity-voice.strategy.js.map +0 -1
  196. package/dist/module/communication/strategies/telephone/ozonetel-voice.strategy.d.ts +0 -15
  197. package/dist/module/communication/strategies/telephone/ozonetel-voice.strategy.js.map +0 -1
  198. package/dist/module/communication/strategies/telephone/tubelight-voice.strategy.js.map +0 -1
  199. package/dist/module/communication/strategies/whatsapp/whatsapp-cloud.strategy.js.map +0 -1
  200. package/dist/module/communication/strategies/whatsapp/whatsapp.strategy.d.ts +0 -5
  201. package/dist/module/communication/strategies/whatsapp/whatsapp.strategy.js.map +0 -1
  202. package/docs/modules/communication.md +0 -177
  203. package/src/module/communication/communication.module.ts +0 -106
  204. package/src/module/communication/controller/communication.controller.ts +0 -293
  205. package/src/module/communication/entity/communication-hub.entity.ts +0 -103
  206. package/src/module/communication/examples/usage.example.ts +0 -170
  207. package/src/module/communication/factories/sms.factory.ts +0 -44
  208. package/src/module/communication/factories/telephone.factory.ts +0 -49
  209. package/src/module/communication/strategies/email/gmail-smtp-v2.strategy.ts +0 -68
  210. package/src/module/communication/strategies/email/gmail-smtp.strategy.ts +0 -51
  211. package/src/module/communication/strategies/email/outlook-smtp.strategy.ts +0 -73
  212. package/src/module/communication/strategies/sms/knowlarity-multi.strategy.ts +0 -158
  213. package/src/module/communication/strategies/sms/knowlarity.strategy.ts +0 -44
  214. package/src/module/communication/strategies/sms/twilio-v2.strategy.ts +0 -47
  215. package/src/module/communication/strategies/sms/twilio.strategy.ts +0 -44
  216. package/src/module/communication/strategies/telephone/knowlarity-multi.strategy.ts +0 -158
  217. package/src/module/communication/strategies/telephone/knowlarity-voice.strategy.ts +0 -44
  218. /package/dist/module/{communication → integration}/controller/calender-event.controller.d.ts +0 -0
  219. /package/dist/module/{communication → integration}/controller/calender-event.controller.js +0 -0
  220. /package/dist/module/{communication → integration}/controller/wrapper.controller.js +0 -0
  221. /package/dist/module/{communication → integration}/factories/base.factory.js +0 -0
  222. /package/dist/module/{communication → integration}/factories/whatsapp.factory.js +0 -0
  223. /package/dist/module/{communication → integration}/service/calendar-event.service.d.ts +0 -0
  224. /package/dist/module/{communication → integration}/service/calendar-event.service.js +0 -0
  225. /package/dist/module/{communication → integration}/service/oauth.service.d.ts +0 -0
  226. /package/dist/module/{communication → integration}/strategies/email/outlook-api.strategy.js +0 -0
  227. /package/dist/module/{communication → integration}/strategies/email/outlook.strategy.js +0 -0
  228. /package/dist/module/{communication → integration}/strategies/email/sendgrid-api.strategy.js +0 -0
  229. /package/dist/module/{communication → integration}/strategies/whatsapp/whatsapp-cloud.strategy.js +0 -0
  230. /package/dist/module/{communication → integration}/strategies/whatsapp/whatsapp.strategy.js +0 -0
  231. /package/src/module/{communication → integration}/controller/calender-event.controller.ts +0 -0
  232. /package/src/module/{communication → integration}/controller/wrapper.controller.ts +0 -0
  233. /package/src/module/{communication → integration}/service/calendar-event.service.ts +0 -0
@@ -3,29 +3,34 @@ import { InjectRepository } from '@nestjs/typeorm';
3
3
  import { Not, Repository } from 'typeorm';
4
4
  import { ConfigService } from '@nestjs/config';
5
5
  import { google } from 'googleapis';
6
- import {
7
- CommunicationConfigType,
8
- CommunicationHub,
9
- } from '../entity/communication-hub.entity';
10
- import { CommunicationConfig } from '../entity/communication-config.entity';
11
- import { CommunicationFactory } from '../factories/communication.factory';
12
- import { CommunicationResult } from '../strategies/communication.strategy';
6
+ import { IntegrationConfig } from '../entity/integration-config.entity';
7
+ import { UserIntegration } from '../entity/user-integration.entity';
8
+ import { IntegrationFactory } from '../factories/integration.factory';
9
+ import { IntegrationResult } from '../strategies/integration.strategy';
13
10
  import { GmailApiStrategy } from '../strategies/email/gmail-api.strategy';
14
11
  import { SendGridApiStrategy } from '../strategies/email/sendgrid-api.strategy';
15
- import { CommunicationQueueService } from './communication-queue.service';
12
+ import { IntegrationQueueService } from './integration-queue.service';
13
+ import {
14
+ BulkMessageDto,
15
+ CreateUserIntegrationDto,
16
+ UpdateUserIntegrationDto,
17
+ } from '../dto/create-config.dto';
16
18
 
17
19
  export interface SendMessageDto {
18
20
  levelId: number;
19
21
  levelType: string;
22
+ app_code: string;
20
23
  to: string;
21
24
  message: string;
22
- mode?: CommunicationConfigType;
25
+ mode?: 'EMAIL' | 'SMS' | 'WA' | 'TELEPHONE';
23
26
  priority?: number;
27
+ user_id?: number;
24
28
  }
25
29
 
26
30
  export interface GenericMessageDto {
27
31
  levelId: number;
28
32
  levelType: string;
33
+ app_code: string;
29
34
  to: string | string[];
30
35
  message: string;
31
36
  subject?: string;
@@ -38,29 +43,17 @@ export interface GenericMessageDto {
38
43
  mediaUrl?: string;
39
44
  templateId?: string;
40
45
  variables?: Record<string, any>;
46
+ user_id?: number;
41
47
  }
42
48
 
43
- export interface BulkMessageDto {
44
- levelId: number;
45
- levelType: string;
46
- recipients: string[];
47
- message: string;
48
- subject?: string;
49
- type?: 'EMAIL' | 'SMS' | 'WA' | 'TELEPHONE';
50
- priority?: 'high' | 'medium' | 'low';
51
- html?: string;
52
- templateId?: string;
53
- variables?: Record<string, any>;
54
- batchSize?: number;
55
- }
56
-
57
- export interface CommunicationHubWithConfig extends CommunicationHub {
58
- config: CommunicationConfig;
49
+ export interface IntegrationConfigWithConfig extends IntegrationConfig {
50
+ config?: any;
59
51
  }
60
52
 
61
53
  interface GmailOAuthState {
62
54
  levelId: number;
63
55
  levelType: string;
56
+ app_code: string;
64
57
  email?: string;
65
58
  timestamp: number;
66
59
  }
@@ -71,63 +64,78 @@ export interface GmailSSOResult {
71
64
  }
72
65
 
73
66
  @Injectable()
74
- export class CommunicationService {
75
- private readonly logger = new Logger(CommunicationService.name);
67
+ export class IntegrationService {
68
+ private readonly logger = new Logger(IntegrationService.name);
76
69
  private readonly gmailOAuthStates = new Map<string, GmailOAuthState>();
77
70
 
78
71
  constructor(
79
- @InjectRepository(CommunicationHub)
80
- private readonly hubRepository: Repository<CommunicationHub>,
81
-
82
- @InjectRepository(CommunicationConfig)
83
- private readonly configRepository: Repository<CommunicationConfig>,
72
+ @InjectRepository(IntegrationConfig)
73
+ private readonly configRepository: Repository<IntegrationConfig>,
74
+ @InjectRepository(UserIntegration)
75
+ private readonly userIntegrationRepository: Repository<UserIntegration>,
84
76
 
85
- private readonly communicationFactory: CommunicationFactory,
77
+ private readonly integrationFactory: IntegrationFactory,
86
78
  private readonly gmailApiStrategy: GmailApiStrategy,
87
79
  private readonly sendGridApiStrategy: SendGridApiStrategy,
88
80
  private readonly configService: ConfigService,
89
- @Inject(forwardRef(() => CommunicationQueueService))
90
- private readonly queueService?: CommunicationQueueService,
81
+ @Inject(forwardRef(() => IntegrationQueueService))
82
+ private readonly queueService?: IntegrationQueueService,
91
83
  ) {}
92
84
 
85
+ private deriveServiceType(
86
+ integration_type: string,
87
+ integration_provider: string,
88
+ config_json: any,
89
+ ): string {
90
+ // All integrations use API only (no SMTP support)
91
+ return 'API';
92
+ }
93
+
93
94
  async sendMessage({
94
95
  levelId,
95
96
  levelType,
97
+ app_code,
96
98
  to,
97
99
  message,
98
100
  mode,
99
101
  priority = 1,
100
- }: SendMessageDto): Promise<CommunicationResult> {
102
+ user_id,
103
+ }: SendMessageDto): Promise<IntegrationResult> {
101
104
  try {
102
- // Get active communication hubs for the level
103
- const hubs = await this.getActiveHubs(levelId, levelType, mode);
105
+ // Get active communication configs for the level
106
+ const configs = await this.getActiveConfigs(
107
+ levelId,
108
+ levelType,
109
+ app_code,
110
+ mode,
111
+ );
104
112
 
105
- if (!hubs.length) {
113
+ if (!configs.length) {
106
114
  throw new Error(
107
115
  `No active communication configuration found for ${levelType} ${levelId}`,
108
116
  );
109
117
  }
110
118
 
111
119
  // Sort by priority if provided
112
- const sortedHubs = this.sortHubsByPriority(hubs, priority);
120
+ const sortedConfigs = this.sortConfigsByPriority(configs, priority);
113
121
 
114
- // Try each hub until one succeeds
115
- for (const hub of sortedHubs) {
122
+ // Try each config until one succeeds
123
+ for (const config of sortedConfigs) {
116
124
  try {
117
- const result = await this.sendViaHub(hub, to, message);
125
+ const result = await this.sendViaConfig(config, to, message, user_id);
118
126
  if (result.success) {
119
127
  this.logger.log(
120
- `Message sent successfully via ${hub.provider}/${hub.service}`,
128
+ `Message sent successfully via ${config.integration_provider}`,
121
129
  );
122
130
  return result;
123
131
  }
124
132
 
125
133
  this.logger.warn(
126
- `Failed to send via ${hub.provider}/${hub.service}: ${result.error}`,
134
+ `Failed to send via ${config.integration_provider}: ${result.error}`,
127
135
  );
128
136
  } catch (error) {
129
137
  this.logger.error(
130
- `Error sending via ${hub.provider}/${hub.service}:`,
138
+ `Error sending via ${config.integration_provider}:`,
131
139
  error.message,
132
140
  );
133
141
  continue;
@@ -141,111 +149,85 @@ export class CommunicationService {
141
149
  }
142
150
  }
143
151
 
144
- async getActiveHubs(
152
+ async getActiveConfigs(
145
153
  levelId: number,
146
154
  levelType: string,
147
- mode?: CommunicationConfigType,
148
- ): Promise<CommunicationHubWithConfig[]> {
149
- let query = this.hubRepository
150
- .createQueryBuilder('hub')
151
- .leftJoin(
152
- 'cr_communication_config',
153
- 'config',
154
- 'config.id = hub.config_id',
155
- )
156
- .select([
157
- 'hub.id as hub_id',
158
- 'hub.level_id as hub_level_id',
159
- 'hub.level_type as hub_level_type',
160
- 'hub.status as hub_status',
161
- 'hub.config_id as hub_config_id',
162
- 'hub.communication_config_type as hub_communication_config_type',
163
- 'hub.service as hub_service',
164
- 'hub.provider as hub_provider',
165
- 'hub.priority as hub_priority',
166
- 'hub.is_default as hub_is_default',
167
- 'hub.created_at as hub_created_at',
168
- 'hub.updated_at as hub_updated_at',
169
- 'config.id as config_id',
170
- 'config.config_json as config_json',
171
- 'config.created_at as config_created_at',
172
- 'config.updated_at as config_updated_at',
173
- ])
174
- .where('hub.level_id = :levelId', { levelId })
175
- .andWhere('hub.level_type = :levelType', { levelType })
176
- .andWhere('hub.status = :status', { status: 1 });
155
+ app_code: string,
156
+ mode?: 'EMAIL' | 'SMS' | 'WA' | 'TELEPHONE',
157
+ ): Promise<IntegrationConfig[]> {
158
+ const queryBuilder = this.configRepository
159
+ .createQueryBuilder('config')
160
+ .where('config.level_id = :levelId', { levelId })
161
+ .andWhere('config.level_type = :levelType', { levelType })
162
+ .andWhere('config.app_code = :app_code', { app_code })
163
+ .andWhere('config.status = 1');
177
164
 
178
165
  if (mode) {
179
- query = query.andWhere('hub.communication_config_type = :mode', { mode });
166
+ queryBuilder.andWhere('config.integration_type = :mode', { mode });
180
167
  }
181
168
 
182
- const results = await query.getRawMany();
183
-
184
- // Transform the raw results into the expected format
185
- const hubsWithConfig: CommunicationHubWithConfig[] = results.map((row) => ({
186
- id: row.hub_id,
187
- level_id: row.hub_level_id,
188
- level_type: row.hub_level_type,
189
- status: row.hub_status,
190
- config_id: row.hub_config_id,
191
- communication_config_type: row.hub_communication_config_type,
192
- service: row.hub_service,
193
- provider: row.hub_provider,
194
- priority: row.hub_priority || 1,
195
- is_default: row.hub_is_default || false,
196
- created_at: row.hub_created_at,
197
- updated_at: row.hub_updated_at,
198
- config: {
199
- id: row.config_id,
200
- config_json: row.config_json,
201
- created_at: row.config_created_at,
202
- updated_at: row.config_updated_at,
203
- },
204
- }));
205
-
206
- return hubsWithConfig;
169
+ return await queryBuilder.getMany();
207
170
  }
208
171
 
209
- private sortHubsByPriority(
210
- hubs: CommunicationHubWithConfig[],
172
+ private sortConfigsByPriority(
173
+ configs: IntegrationConfig[],
211
174
  _priority: number,
212
- ): CommunicationHubWithConfig[] {
213
- // For now, just return as-is. In the future, implement priority logic
214
- return hubs;
175
+ ): IntegrationConfig[] {
176
+ return configs.sort((a, b) => {
177
+ // First sort by default (true comes first)
178
+ if (a.is_default !== b.is_default) {
179
+ return a.is_default ? -1 : 1;
180
+ }
181
+ // Then by priority (lower number = higher priority)
182
+ return a.priority - b.priority;
183
+ });
215
184
  }
216
185
 
217
- private async sendViaHub(
218
- hub: CommunicationHubWithConfig,
186
+ private async sendViaConfig(
187
+ config: IntegrationConfig,
219
188
  to: string,
220
189
  message: string,
221
- ): Promise<CommunicationResult> {
222
- const strategy = this.communicationFactory.create(
223
- hub.communication_config_type,
224
- hub.service,
225
- hub.provider,
190
+ user_id?: number,
191
+ ): Promise<IntegrationResult> {
192
+ const strategy = this.integrationFactory.create(
193
+ config.integration_type,
194
+ 'API', // service is deprecated, using default
195
+ config.integration_provider,
226
196
  );
227
197
 
228
- const result = await strategy.sendMessage(
229
- to,
230
- message,
231
- hub.config.config_json,
232
- );
198
+ // Get user integration data if user_id provided
199
+ let finalConfig = config.config_json;
200
+ if (user_id) {
201
+ const userIntegrationData = await this.getUserIntegrationForStrategy(
202
+ user_id,
203
+ config.id,
204
+ );
205
+
206
+ if (userIntegrationData) {
207
+ finalConfig = {
208
+ ...config.config_json,
209
+ external_user_id: userIntegrationData.external_user_id,
210
+ };
211
+ }
212
+ }
213
+
214
+ const result = await strategy.sendMessage(to, message, finalConfig);
233
215
 
234
216
  // If token was refreshed, update it in the database
235
217
  if (result.refreshedToken && result.success) {
236
218
  try {
237
- const currentConfig = hub.config.config_json as any;
219
+ const currentConfig = config.config_json as any;
238
220
  const updatedConfig = {
239
221
  ...currentConfig,
240
222
  accessToken: result.refreshedToken,
241
223
  };
242
224
 
243
- await this.configRepository.update(hub.config.id, {
225
+ await this.configRepository.update(config.id, {
244
226
  config_json: updatedConfig,
245
227
  } as any);
246
228
 
247
229
  this.logger.log(
248
- `Updated access token for ${hub.provider}/${hub.service} configuration`,
230
+ `Updated access token for ${config.integration_provider} configuration`,
249
231
  );
250
232
  } catch (error) {
251
233
  this.logger.warn(
@@ -257,52 +239,66 @@ export class CommunicationService {
257
239
  return result;
258
240
  }
259
241
 
260
- async createCommunicationConfig(
242
+ async createIntegrationConfig(
261
243
  levelId: number,
262
244
  levelType: string,
263
- configType: CommunicationConfigType,
264
- service: string,
245
+ app_code: string,
246
+ configType: 'EMAIL' | 'SMS' | 'WA' | 'TELEPHONE',
265
247
  provider: string,
248
+ integration_source_id: number,
266
249
  config: any,
267
250
  priority?: number,
268
251
  is_default?: boolean,
269
252
  ): Promise<
270
- CommunicationHub | { authUrl: string; state: string; message: string }
253
+ IntegrationConfig | { authUrl: string; state: string; message: string }
271
254
  > {
272
- // Deactivate any existing active configurations of the same type to ensure only one is active
273
- await this.validateUniqueActiveConfig(levelId, levelType, configType);
255
+ // Validate that no duplicate provider configurations exist
256
+ await this.validateUniqueActiveConfig(
257
+ levelId,
258
+ levelType,
259
+ app_code,
260
+ configType,
261
+ provider,
262
+ );
274
263
 
275
- // Validate service/provider combination using supported combinations
264
+ // Deactivate all other configurations of the same integration type
265
+ await this.configRepository.update(
266
+ {
267
+ level_id: levelId,
268
+ level_type: levelType,
269
+ app_code: app_code,
270
+ integration_type: configType,
271
+ status: 1,
272
+ },
273
+ { status: 0 },
274
+ );
275
+
276
+ // Validate provider and get service type from supported combinations
276
277
  const supportedCombinations = await this.getSupportedCombinations();
277
- const isValidCombination = supportedCombinations.some(
278
+ const validCombination = supportedCombinations.find(
278
279
  (combo) =>
279
280
  combo.mode === configType &&
280
- combo.service.toLowerCase() === service.toLowerCase() &&
281
281
  combo.provider.toLowerCase() === provider.toLowerCase(),
282
282
  );
283
283
 
284
- if (!isValidCombination) {
285
- throw new Error(
286
- `Unsupported combination: ${configType}/${service}/${provider}`,
287
- );
284
+ if (!validCombination) {
285
+ throw new Error(`Unsupported combination: ${configType}/${provider}`);
288
286
  }
289
287
 
288
+ const service = validCombination.service;
289
+
290
290
  // Check if this requires OAuth flow
291
- const requiresOAuth = this.requiresOAuthFlow(
292
- configType,
293
- service,
294
- provider,
295
- config,
296
- );
291
+ const requiresOAuth = this.requiresOAuthFlow(configType, provider, config);
297
292
 
298
293
  if (requiresOAuth) {
299
294
  // Generate OAuth URL and return it instead of creating config immediately
300
295
  return await this.generateOAuthUrl(
301
296
  levelId,
302
297
  levelType,
298
+ app_code,
303
299
  configType,
304
- service,
305
300
  provider,
301
+ integration_source_id,
306
302
  config,
307
303
  priority,
308
304
  is_default,
@@ -313,9 +309,10 @@ export class CommunicationService {
313
309
  return await this.createDirectConfig(
314
310
  levelId,
315
311
  levelType,
312
+ app_code,
316
313
  configType,
317
- service,
318
314
  provider,
315
+ integration_source_id,
319
316
  config,
320
317
  priority,
321
318
  is_default,
@@ -327,35 +324,35 @@ export class CommunicationService {
327
324
  service: string;
328
325
  provider: string;
329
326
  }[] {
330
- return this.communicationFactory.getAllSupportedCombinations();
327
+ return this.integrationFactory.getAllSupportedCombinations();
331
328
  }
332
329
 
333
330
  async getLevelConfigs(
334
331
  levelId: number,
335
332
  levelType: string,
336
333
  filters?: {
337
- communication_config_type?: 'WA' | 'SMS' | 'EMAIL' | 'TELEPHONE';
338
- service?: 'API' | 'THIRD_PARTY' | 'SMTP';
339
- provider?: string;
334
+ app_code?: string;
335
+ integration_type?: 'WA' | 'SMS' | 'EMAIL' | 'TELEPHONE';
336
+ integration_provider?: string;
340
337
  },
341
338
  ): Promise<
342
- Array<CommunicationHub & { linkedSource?: string; configDetails?: any }>
339
+ Array<IntegrationConfig & { linkedSource?: string; configDetails?: any }>
343
340
  > {
344
341
  const where: any = { level_id: levelId, level_type: levelType };
345
342
 
346
- if (filters?.communication_config_type) {
347
- where.communication_config_type = filters.communication_config_type;
343
+ if (filters?.app_code) {
344
+ where.app_code = filters.app_code;
348
345
  }
349
346
 
350
- if (filters?.service) {
351
- where.service = filters.service;
347
+ if (filters?.integration_type) {
348
+ where.integration_type = filters.integration_type;
352
349
  }
353
350
 
354
- if (filters?.provider) {
355
- where.provider = filters.provider;
351
+ if (filters?.integration_provider) {
352
+ where.integration_provider = filters.integration_provider;
356
353
  }
357
354
 
358
- const hubs = await this.hubRepository.find({
355
+ const hubs = await this.configRepository.find({
359
356
  where,
360
357
  order: { created_at: 'DESC' },
361
358
  });
@@ -364,11 +361,11 @@ export class CommunicationService {
364
361
  const enhancedHubs = await Promise.all(
365
362
  hubs.map(async (hub) => {
366
363
  try {
367
- const config = await this.configRepository.findOne({
368
- where: { id: hub.config_id },
364
+ const relatedConfig = await this.configRepository.findOne({
365
+ where: { id: hub.id },
369
366
  });
370
367
 
371
- if (!config) {
368
+ if (!relatedConfig) {
372
369
  return {
373
370
  ...hub,
374
371
  linkedSource: 'Configuration not found',
@@ -377,17 +374,15 @@ export class CommunicationService {
377
374
  }
378
375
 
379
376
  const linkedSource = this.extractLinkedSource(
380
- hub.communication_config_type,
381
- hub.service,
382
- hub.provider,
383
- config.config_json,
377
+ hub.integration_type,
378
+ hub.integration_provider,
379
+ relatedConfig.config_json,
384
380
  );
385
381
 
386
382
  const configDetails = this.extractConfigDetails(
387
- hub.communication_config_type,
388
- hub.service,
389
- hub.provider,
390
- config.config_json,
383
+ hub.integration_type,
384
+ hub.integration_provider,
385
+ relatedConfig.config_json,
391
386
  );
392
387
 
393
388
  return {
@@ -414,21 +409,20 @@ export class CommunicationService {
414
409
 
415
410
  private extractLinkedSource(
416
411
  configType: string,
417
- service: string,
418
412
  provider: string,
419
413
  configJson: any,
420
414
  ): string {
421
- const key = `${configType.toLowerCase()}_${service.toLowerCase()}_${provider.toLowerCase()}`;
415
+ const key = `${configType.toLowerCase()}_${provider.toLowerCase()}`;
422
416
 
423
417
  try {
424
418
  switch (key) {
425
419
  // Gmail configurations
426
- case 'email_api_gmail':
420
+ case 'email_gmail':
427
421
  case 'email_smtp_gmail':
428
422
  return configJson?.email || 'Gmail account not configured';
429
423
 
430
424
  // Outlook configurations
431
- case 'email_api_outlook':
425
+ case 'email_outlook':
432
426
  case 'email_smtp_outlook':
433
427
  return configJson?.email || 'Outlook account not configured';
434
428
 
@@ -461,8 +455,8 @@ export class CommunicationService {
461
455
  : 'Ozonetel voice not configured';
462
456
 
463
457
  // AWS SES configurations
464
- case 'email_api_aws-ses':
465
- case 'email_api_ses':
458
+ case 'email_aws-ses':
459
+ case 'email_ses':
466
460
  return configJson?.fromEmail || 'AWS SES not configured';
467
461
 
468
462
  // SendGrid configurations
@@ -492,16 +486,15 @@ export class CommunicationService {
492
486
 
493
487
  private extractConfigDetails(
494
488
  configType: string,
495
- service: string,
496
489
  provider: string,
497
490
  configJson: any,
498
491
  ): any {
499
- const key = `${configType.toLowerCase()}_${service.toLowerCase()}_${provider.toLowerCase()}`;
492
+ const key = `${configType.toLowerCase()}_${provider.toLowerCase()}`;
500
493
 
501
494
  try {
502
495
  switch (key) {
503
496
  // Gmail configurations
504
- case 'email_api_gmail':
497
+ case 'email_gmail':
505
498
  return {
506
499
  email: configJson?.email,
507
500
  authMethod: configJson?.authMethod || 'OAUTH2',
@@ -519,7 +512,7 @@ export class CommunicationService {
519
512
  };
520
513
 
521
514
  // Outlook configurations
522
- case 'email_api_outlook':
515
+ case 'email_outlook':
523
516
  return {
524
517
  email: configJson?.email,
525
518
  authMethod: 'OAUTH2',
@@ -578,8 +571,8 @@ export class CommunicationService {
578
571
  };
579
572
 
580
573
  // AWS SES configurations
581
- case 'email_api_aws-ses':
582
- case 'email_api_ses':
574
+ case 'email_aws-ses':
575
+ case 'email_ses':
583
576
  return {
584
577
  fromEmail: configJson?.fromEmail,
585
578
  region: configJson?.region,
@@ -665,21 +658,22 @@ export class CommunicationService {
665
658
 
666
659
  async updateConfigStatus(hubId: number, status: number): Promise<void> {
667
660
  // Find the hub to get level and type information
668
- const hub = await this.hubRepository.findOne({
661
+ const config = await this.configRepository.findOne({
669
662
  where: { id: hubId },
670
663
  });
671
664
 
672
- if (!hub) {
673
- throw new Error('Communication configuration not found');
665
+ if (!config) {
666
+ throw new Error('Integration configuration not found');
674
667
  }
675
668
 
676
- // If activating, deactivate other configs with same level_id + level_type + communication_config_type
669
+ // If activating, deactivate ALL other configs of the same integration type
677
670
  if (status === 1) {
678
- await this.hubRepository.update(
671
+ await this.configRepository.update(
679
672
  {
680
- level_id: hub.level_id,
681
- level_type: hub.level_type,
682
- communication_config_type: hub.communication_config_type,
673
+ level_id: config.level_id,
674
+ level_type: config.level_type,
675
+ app_code: config.app_code,
676
+ integration_type: config.integration_type,
683
677
  status: 1,
684
678
  id: Not(hubId),
685
679
  },
@@ -688,26 +682,22 @@ export class CommunicationService {
688
682
  }
689
683
 
690
684
  // Update the requested config
691
- await this.hubRepository.update(hubId, { status });
685
+ await this.configRepository.update(hubId, { status });
692
686
  }
693
687
 
694
- async deleteConfiguration(hubId: number): Promise<void> {
695
- // Find the hub to get the config_id
696
- const hub = await this.hubRepository.findOne({
697
- where: { id: hubId },
688
+ async deleteConfiguration(configId: number): Promise<void> {
689
+ // Find the hub to get the id
690
+ const config = await this.configRepository.findOne({
691
+ where: { id: configId },
698
692
  });
699
693
 
700
- if (!hub) {
701
- throw new Error('Communication configuration not found');
694
+ if (!config) {
695
+ throw new Error('Integration configuration not found');
702
696
  }
703
697
 
704
- await this.hubRepository.delete(hubId);
705
-
706
- await this.configRepository.delete(hub.config_id);
698
+ await this.configRepository.delete(configId);
707
699
 
708
- this.logger.log(
709
- `Communication configuration deleted: Hub ${hubId}, Config ${hub.config_id}`,
710
- );
700
+ this.logger.log(`Integration configuration deleted: ${configId}`);
711
701
  }
712
702
 
713
703
  async updateConfiguration(
@@ -718,104 +708,75 @@ export class CommunicationService {
718
708
  is_default?: boolean;
719
709
  status?: number;
720
710
  },
721
- ): Promise<CommunicationHub & { config?: any }> {
711
+ ): Promise<IntegrationConfig & { config?: any }> {
722
712
  // Find the existing hub
723
- const hub = await this.hubRepository.findOne({
713
+ const config = await this.configRepository.findOne({
724
714
  where: { id: hubId },
725
715
  });
726
716
 
727
- if (!hub) {
728
- throw new Error('Communication configuration not found');
717
+ if (!config) {
718
+ throw new Error('Integration configuration not found');
729
719
  }
730
720
 
731
721
  // Update configuration JSON if provided
732
722
  if (updateData.config) {
733
- const existingConfig = await this.configRepository.findOne({
734
- where: { id: hub.config_id },
735
- });
736
-
737
- if (!existingConfig) {
738
- throw new Error('Configuration record not found');
739
- }
740
-
741
723
  // Merge the new config with existing config
742
724
  const updatedConfigJson = {
743
- ...existingConfig.config_json,
725
+ ...config.config_json,
744
726
  ...updateData.config,
745
727
  };
746
728
 
747
- await this.configRepository.update(hub.config_id, {
729
+ await this.configRepository.update(config.id, {
748
730
  config_json: updatedConfigJson,
749
- });
750
- }
751
-
752
- // Deactivate other configurations if this one is being activated
753
- if (updateData.status === 1) {
754
- await this.validateUniqueActiveConfig(
755
- hub.level_id,
756
- hub.level_type,
757
- hub.communication_config_type,
758
- hubId, // Exclude current hub
759
- );
731
+ } as any);
760
732
  }
761
733
 
762
- // Handle default configuration logic
734
+ // Handle default configuration logic (simplified for now)
763
735
  if (updateData.is_default === true) {
764
736
  // Remove default from other configurations of same type and level
765
- await this.hubRepository.update(
737
+ await this.configRepository.update(
766
738
  {
767
- level_id: hub.level_id,
768
- level_type: hub.level_type,
769
- communication_config_type: hub.communication_config_type,
770
- id: Not(hubId), // Exclude current hub
739
+ level_id: config.level_id,
740
+ level_type: config.level_type,
741
+ integration_type: config.integration_type,
742
+ id: Not(hubId),
771
743
  },
772
744
  { is_default: false },
773
745
  );
774
746
  }
775
747
 
776
- // Update hub metadata
777
- const hubUpdateData: any = {};
778
- if (updateData.priority !== undefined) {
779
- hubUpdateData.priority = updateData.priority;
780
- }
781
- if (updateData.is_default !== undefined) {
782
- hubUpdateData.is_default = updateData.is_default;
783
- }
784
- if (updateData.status !== undefined) {
785
- hubUpdateData.status = updateData.status;
748
+ // Apply direct config updates if any
749
+ const directUpdates: any = {};
750
+ if (updateData.priority !== undefined)
751
+ directUpdates.priority = updateData.priority;
752
+ if (updateData.is_default !== undefined)
753
+ directUpdates.is_default = updateData.is_default;
754
+ if (updateData.status !== undefined)
755
+ directUpdates.status = updateData.status;
756
+
757
+ if (Object.keys(directUpdates).length > 0) {
758
+ await this.configRepository.update(config.id, directUpdates);
786
759
  }
787
760
 
788
- // Apply hub updates if any
789
- if (Object.keys(hubUpdateData).length > 0) {
790
- await this.hubRepository.update(hubId, hubUpdateData);
791
- }
792
-
793
- // Fetch and return updated hub with config
794
- const updatedHub = await this.hubRepository.findOne({
795
- where: { id: hubId },
796
- });
797
-
761
+ // Fetch and return updated config
798
762
  const updatedConfig = await this.configRepository.findOne({
799
- where: { id: hub.config_id },
763
+ where: { id: hubId },
800
764
  });
801
765
 
802
- this.logger.log(
803
- `Communication configuration updated: Hub ${hubId}, Type ${hub.communication_config_type}`,
804
- );
805
-
806
766
  return {
807
- ...updatedHub!,
767
+ ...updatedConfig,
808
768
  config: updatedConfig?.config_json,
809
- };
769
+ } as any;
810
770
  }
811
771
 
812
772
  async sendGenericMessage(
813
773
  messageDto: GenericMessageDto,
814
- ): Promise<CommunicationResult> {
774
+ ): Promise<IntegrationResult> {
815
775
  try {
816
776
  const {
817
777
  levelId,
818
778
  levelType,
779
+ app_code,
819
780
  to,
820
781
  message,
821
782
  type,
@@ -828,21 +789,23 @@ export class CommunicationService {
828
789
  mediaUrl,
829
790
  templateId,
830
791
  variables,
792
+ user_id,
831
793
  } = messageDto;
832
794
 
833
795
  // Auto-detect communication type if not specified
834
796
  const communicationType = this.detectCommunicationType(to, type);
835
797
 
836
- // Get active hubs for the detected type
837
- const hubs = await this.getActiveHubs(
798
+ // Get active configs for the detected type
799
+ const configs = await this.getActiveConfigs(
838
800
  levelId,
839
801
  levelType,
802
+ app_code,
840
803
  communicationType,
841
804
  );
842
805
 
843
- if (!hubs.length) {
806
+ if (!configs.length) {
844
807
  this.logger.warn(
845
- `No communication hubs found for ${levelType} ${levelId}. Please configure communication providers using the createCommunicationConfig method.`,
808
+ `No communication hubs found for ${levelType} ${levelId}. Please configure integration providers using the createIntegrationConfig method.`,
846
809
  );
847
810
  throw new Error(
848
811
  `No active ${communicationType} configuration found for ${levelType} ${levelId}. Please configure a communication provider first.`,
@@ -850,7 +813,10 @@ export class CommunicationService {
850
813
  }
851
814
 
852
815
  // Sort hubs by priority and default preference
853
- const sortedHubs = this.sortHubsByPriorityAndDefault(hubs, priority);
816
+ const sortedConfigs = this.sortConfigsByPriorityAndDefault(
817
+ configs,
818
+ priority,
819
+ );
854
820
 
855
821
  // Prepare enhanced config with additional parameters
856
822
  const enhancedConfig = {
@@ -864,16 +830,21 @@ export class CommunicationService {
864
830
 
865
831
  // Handle multiple recipients by sending to each individually
866
832
  if (Array.isArray(to)) {
867
- const results: CommunicationResult[] = [];
833
+ const results: IntegrationResult[] = [];
868
834
  let hasSuccess = false;
869
835
 
870
836
  for (const recipient of to) {
871
- for (const hub of sortedHubs) {
837
+ for (const hub of sortedConfigs) {
872
838
  try {
873
- const strategy = this.communicationFactory.create(
874
- hub.communication_config_type,
875
- hub.service,
876
- hub.provider,
839
+ const serviceType = this.deriveServiceType(
840
+ hub.integration_type,
841
+ hub.integration_provider,
842
+ hub.config_json,
843
+ );
844
+ const strategy = this.integrationFactory.create(
845
+ hub.integration_type,
846
+ serviceType,
847
+ hub.integration_provider,
877
848
  );
878
849
 
879
850
  // Process template if provided
@@ -883,13 +854,26 @@ export class CommunicationService {
883
854
  }
884
855
 
885
856
  // Merge config with enhanced parameters
886
- const finalConfig = {
887
- ...hub.config.config_json,
857
+ let finalConfig = {
858
+ ...hub.config_json,
888
859
  ...enhancedConfig,
889
860
  templateId,
890
861
  variables,
891
862
  };
892
863
 
864
+ // Handle user integration if user_id provided
865
+ if (user_id) {
866
+ const userIntegrationData =
867
+ await this.getUserIntegrationForStrategy(user_id, hub.id);
868
+
869
+ if (userIntegrationData) {
870
+ finalConfig = {
871
+ ...finalConfig,
872
+ external_user_id: userIntegrationData.external_user_id,
873
+ };
874
+ }
875
+ }
876
+
893
877
  const result = await strategy.sendMessage(
894
878
  recipient,
895
879
  processedMessage,
@@ -898,7 +882,7 @@ export class CommunicationService {
898
882
 
899
883
  if (result.success) {
900
884
  this.logger.log(
901
- `Generic message sent successfully via ${hub.provider}/${hub.service} to ${recipient}`,
885
+ `Generic message sent successfully via ${hub.integration_provider} to ${recipient}`,
902
886
  );
903
887
  results.push(result);
904
888
  hasSuccess = true;
@@ -906,11 +890,11 @@ export class CommunicationService {
906
890
  }
907
891
 
908
892
  this.logger.warn(
909
- `Failed to send via ${hub.provider}/${hub.service} to ${recipient}: ${result.error}`,
893
+ `Failed to send via ${hub.integration_provider} to ${recipient}: ${result.error}`,
910
894
  );
911
895
  } catch (error) {
912
896
  this.logger.error(
913
- `Error sending via ${hub.provider}/${hub.service} to ${recipient}:`,
897
+ `Error sending via ${hub.integration_provider} to ${recipient}:`,
914
898
  error.message,
915
899
  );
916
900
  continue;
@@ -929,12 +913,17 @@ export class CommunicationService {
929
913
  }
930
914
  } else {
931
915
  // Handle single recipient
932
- for (const hub of sortedHubs) {
916
+ for (const hub of sortedConfigs) {
933
917
  try {
934
- const strategy = this.communicationFactory.create(
935
- hub.communication_config_type,
936
- hub.service,
937
- hub.provider,
918
+ const serviceType = this.deriveServiceType(
919
+ hub.integration_type,
920
+ hub.integration_provider,
921
+ hub.config_json,
922
+ );
923
+ const strategy = this.integrationFactory.create(
924
+ hub.integration_type,
925
+ serviceType,
926
+ hub.integration_provider,
938
927
  );
939
928
 
940
929
  // Process template if provided
@@ -947,13 +936,26 @@ export class CommunicationService {
947
936
  }
948
937
 
949
938
  // Merge config with enhanced parameters
950
- const finalConfig = {
951
- ...hub.config.config_json,
939
+ let finalConfig = {
940
+ ...hub.config_json,
952
941
  ...enhancedConfig,
953
942
  templateId,
954
943
  variables,
955
944
  };
956
945
 
946
+ // Handle user integration if user_id provided
947
+ if (user_id) {
948
+ const userIntegrationData =
949
+ await this.getUserIntegrationForStrategy(user_id, hub.id);
950
+
951
+ if (userIntegrationData) {
952
+ finalConfig = {
953
+ ...finalConfig,
954
+ external_user_id: userIntegrationData.external_user_id,
955
+ };
956
+ }
957
+ }
958
+
957
959
  const result = await strategy.sendMessage(
958
960
  to,
959
961
  processedMessage,
@@ -962,17 +964,17 @@ export class CommunicationService {
962
964
 
963
965
  if (result.success) {
964
966
  this.logger.log(
965
- `Generic message sent successfully via ${hub.provider}/${hub.service} to ${to}`,
967
+ `Generic message sent successfully via ${hub.integration_provider} to ${to}`,
966
968
  );
967
969
  return result;
968
970
  }
969
971
 
970
972
  this.logger.warn(
971
- `Failed to send via ${hub.provider}/${hub.service}: ${result.error}`,
973
+ `Failed to send via ${hub.integration_provider}: ${result.error}`,
972
974
  );
973
975
  } catch (error) {
974
976
  this.logger.error(
975
- `Error sending via ${hub.provider}/${hub.service}:`,
977
+ `Error sending via ${hub.integration_provider}:`,
976
978
  error.message,
977
979
  );
978
980
  continue;
@@ -989,11 +991,12 @@ export class CommunicationService {
989
991
 
990
992
  async sendBulkMessage(
991
993
  bulkDto: BulkMessageDto,
992
- ): Promise<{ results: CommunicationResult[]; summary: any }> {
994
+ ): Promise<{ results: IntegrationResult[]; summary: any }> {
993
995
  try {
994
996
  const {
995
997
  levelId,
996
998
  levelType,
999
+ app_code,
997
1000
  recipients,
998
1001
  message,
999
1002
  type,
@@ -1005,7 +1008,7 @@ export class CommunicationService {
1005
1008
  batchSize = 10,
1006
1009
  } = bulkDto;
1007
1010
 
1008
- const results: CommunicationResult[] = [];
1011
+ const results: IntegrationResult[] = [];
1009
1012
  const batches = this.chunkArray(recipients, batchSize);
1010
1013
 
1011
1014
  for (let i = 0; i < batches.length; i++) {
@@ -1019,6 +1022,7 @@ export class CommunicationService {
1019
1022
  const messageDto: GenericMessageDto = {
1020
1023
  levelId,
1021
1024
  levelType,
1025
+ app_code,
1022
1026
  to: recipient,
1023
1027
  message,
1024
1028
  type,
@@ -1037,7 +1041,7 @@ export class CommunicationService {
1037
1041
  service: 'unknown',
1038
1042
  error: error.message,
1039
1043
  timestamp: new Date(),
1040
- } as CommunicationResult;
1044
+ } as IntegrationResult;
1041
1045
  }
1042
1046
  });
1043
1047
 
@@ -1052,7 +1056,7 @@ export class CommunicationService {
1052
1056
  service: 'unknown',
1053
1057
  error: result.reason?.message || 'Unknown error',
1054
1058
  timestamp: new Date(),
1055
- } as CommunicationResult;
1059
+ } as IntegrationResult;
1056
1060
  }
1057
1061
  });
1058
1062
 
@@ -1098,7 +1102,7 @@ export class CommunicationService {
1098
1102
  };
1099
1103
  }
1100
1104
 
1101
- async sendTemplateMessage(templateDto: any): Promise<CommunicationResult> {
1105
+ async sendTemplateMessage(templateDto: any): Promise<IntegrationResult> {
1102
1106
  // Get template content (integrate with your template system)
1103
1107
  const template = await this.getTemplate(templateDto.templateId);
1104
1108
 
@@ -1113,6 +1117,7 @@ export class CommunicationService {
1113
1117
  const messageDto: GenericMessageDto = {
1114
1118
  levelId: templateDto.levelId,
1115
1119
  levelType: templateDto.levelType,
1120
+ app_code: templateDto.app_code,
1116
1121
  to: templateDto.to,
1117
1122
  message: processedMessage,
1118
1123
  subject: processedSubject,
@@ -1127,33 +1132,33 @@ export class CommunicationService {
1127
1132
  private detectCommunicationType(
1128
1133
  to: string | string[],
1129
1134
  type?: string,
1130
- ): CommunicationConfigType {
1135
+ ): 'EMAIL' | 'SMS' | 'WA' | 'TELEPHONE' {
1131
1136
  if (type) {
1132
- return type as CommunicationConfigType;
1137
+ return type as 'EMAIL' | 'SMS' | 'WA' | 'TELEPHONE';
1133
1138
  }
1134
1139
 
1135
1140
  const recipient = Array.isArray(to) ? to[0] : to;
1136
1141
 
1137
1142
  // Email detection
1138
1143
  if (recipient.includes('@')) {
1139
- return CommunicationConfigType.EMAIL;
1144
+ return 'EMAIL';
1140
1145
  }
1141
1146
 
1142
1147
  // Phone number detection (basic)
1143
1148
  if (/^\+?[\d\s\-\(\)]+$/.test(recipient)) {
1144
1149
  // Could be SMS or WhatsApp, default to SMS
1145
- return CommunicationConfigType.SMS;
1150
+ return 'SMS';
1146
1151
  }
1147
1152
 
1148
1153
  // Default to EMAIL if unsure
1149
- return CommunicationConfigType.EMAIL;
1154
+ return 'EMAIL';
1150
1155
  }
1151
1156
 
1152
- private sortHubsByPriorityAndDefault(
1153
- hubs: CommunicationHubWithConfig[],
1157
+ private sortConfigsByPriorityAndDefault(
1158
+ configs: IntegrationConfigWithConfig[],
1154
1159
  _priority: string,
1155
- ): CommunicationHubWithConfig[] {
1156
- return hubs.sort((a, b) => {
1160
+ ): IntegrationConfigWithConfig[] {
1161
+ return configs.sort((a, b) => {
1157
1162
  // First sort by default (true comes first)
1158
1163
  if (a.is_default !== b.is_default) {
1159
1164
  return b.is_default ? 1 : -1;
@@ -1202,6 +1207,7 @@ export class CommunicationService {
1202
1207
  async initGmailOAuth(
1203
1208
  levelId: number,
1204
1209
  levelType: string,
1210
+ app_code: string,
1205
1211
  email?: string,
1206
1212
  ): Promise<{ authUrl: string; state: string }> {
1207
1213
  try {
@@ -1222,6 +1228,7 @@ export class CommunicationService {
1222
1228
  this.gmailOAuthStates.set(state, {
1223
1229
  levelId,
1224
1230
  levelType,
1231
+ app_code,
1225
1232
  email,
1226
1233
  timestamp: Date.now(),
1227
1234
  });
@@ -1327,34 +1334,33 @@ export class CommunicationService {
1327
1334
  await this.validateUniqueActiveConfig(
1328
1335
  oauthState.levelId,
1329
1336
  oauthState.levelType,
1330
- CommunicationConfigType.EMAIL,
1337
+ oauthState.app_code,
1338
+ 'EMAIL',
1339
+ 'gmail',
1331
1340
  );
1332
1341
 
1333
- // Create communication config
1334
- const communicationConfig = this.configRepository.create({
1335
- config_json: gmailConfig as any,
1336
- });
1337
- const savedConfig = await this.configRepository.save(communicationConfig);
1338
-
1339
- // Create communication hub
1340
- const hub = this.hubRepository.create({
1342
+ // Create integration config
1343
+ const config = this.configRepository.create({
1344
+ app_code: oauthState.app_code,
1345
+ integration_type: 'EMAIL',
1346
+ integration_provider: 'gmail',
1347
+ integration_source_id: 1, // Gmail source ID
1341
1348
  level_id: oauthState.levelId,
1342
1349
  level_type: oauthState.levelType,
1343
- config_id: savedConfig.id,
1344
- communication_config_type: CommunicationConfigType.EMAIL,
1345
- service: 'API',
1346
- provider: 'gmail',
1347
1350
  status: 1,
1351
+ priority: 1,
1352
+ is_default: false,
1353
+ config_json: gmailConfig as any,
1348
1354
  });
1349
1355
 
1350
- const savedHub = await this.hubRepository.save(hub);
1356
+ const savedConfig = await this.configRepository.save(config);
1351
1357
 
1352
1358
  this.logger.log(
1353
1359
  `Gmail OAuth configuration created successfully for ${oauthState.levelType} ${oauthState.levelId} and email ${email}`,
1354
1360
  );
1355
1361
 
1356
1362
  return {
1357
- hubId: savedHub.id,
1363
+ hubId: savedConfig.id,
1358
1364
  configId: savedConfig.id,
1359
1365
  };
1360
1366
  } catch (error) {
@@ -1390,7 +1396,9 @@ export class CommunicationService {
1390
1396
  await this.validateUniqueActiveConfig(
1391
1397
  oauthState.levelId,
1392
1398
  oauthState.levelType,
1393
- CommunicationConfigType.EMAIL,
1399
+ oauthState.app_code,
1400
+ 'EMAIL',
1401
+ 'gmail',
1394
1402
  );
1395
1403
 
1396
1404
  // Pure SSO configuration - no client credentials stored per user
@@ -1405,31 +1413,28 @@ export class CommunicationService {
1405
1413
  ],
1406
1414
  };
1407
1415
 
1408
- // Create communication config
1409
- const communicationConfig = this.configRepository.create({
1410
- config_json: gmailConfig as any,
1411
- });
1412
- const savedConfig = await this.configRepository.save(communicationConfig);
1413
-
1414
- // Create communication hub
1415
- const hub = this.hubRepository.create({
1416
+ // Create integration config
1417
+ const config = this.configRepository.create({
1418
+ app_code: oauthState.app_code,
1419
+ integration_type: 'EMAIL',
1420
+ integration_provider: 'gmail',
1421
+ integration_source_id: 1, // Gmail source ID
1416
1422
  level_id: oauthState.levelId,
1417
1423
  level_type: oauthState.levelType,
1418
- config_id: savedConfig.id,
1419
- communication_config_type: CommunicationConfigType.EMAIL,
1420
- service: 'API',
1421
- provider: 'gmail',
1422
1424
  status: 1,
1425
+ priority: 1,
1426
+ is_default: false,
1427
+ config_json: gmailConfig as any,
1423
1428
  });
1424
1429
 
1425
- const savedHub = await this.hubRepository.save(hub);
1430
+ const savedConfig = await this.configRepository.save(config);
1426
1431
 
1427
1432
  this.logger.log(
1428
1433
  `Gmail tokens configuration created successfully for ${oauthState.levelType} ${oauthState.levelId} and email ${email}`,
1429
1434
  );
1430
1435
 
1431
1436
  return {
1432
- hubId: savedHub.id,
1437
+ hubId: savedConfig.id,
1433
1438
  configId: savedConfig.id,
1434
1439
  };
1435
1440
  } catch (error) {
@@ -1444,24 +1449,16 @@ export class CommunicationService {
1444
1449
  hubId: number,
1445
1450
  ): Promise<{ success: boolean; error?: string }> {
1446
1451
  try {
1447
- const hub = await this.hubRepository.findOne({
1452
+ const integrationConfig = await this.configRepository.findOne({
1448
1453
  where: { id: hubId },
1449
1454
  });
1450
1455
 
1451
- if (!hub) {
1452
- throw new Error('Communication hub not found');
1453
- }
1454
-
1455
- const config = await this.configRepository.findOne({
1456
- where: { id: hub.config_id },
1457
- });
1458
-
1459
- if (!config) {
1460
- throw new Error('Configuration not found');
1456
+ if (!integrationConfig) {
1457
+ throw new Error('Integration config not found');
1461
1458
  }
1462
1459
 
1463
1460
  const isValid = await this.gmailApiStrategy.validateConnection(
1464
- config.config_json,
1461
+ integrationConfig.config_json,
1465
1462
  );
1466
1463
 
1467
1464
  if (!isValid) {
@@ -1485,15 +1482,19 @@ export class CommunicationService {
1485
1482
  private async validateUniqueActiveConfig(
1486
1483
  levelId: number,
1487
1484
  levelType: string,
1488
- configType: CommunicationConfigType,
1485
+ app_code: string,
1486
+ configType: 'EMAIL' | 'SMS' | 'WA' | 'TELEPHONE',
1487
+ provider: string,
1489
1488
  excludeHubId?: number,
1490
1489
  ): Promise<void> {
1491
- // Find all active configurations of the same type for this level
1492
- const query = this.hubRepository
1490
+ // Find all active configurations of the same provider for this level and app_code
1491
+ const query = this.configRepository
1493
1492
  .createQueryBuilder('hub')
1494
1493
  .where('hub.level_id = :levelId', { levelId })
1495
1494
  .andWhere('hub.level_type = :levelType', { levelType })
1496
- .andWhere('hub.communication_config_type = :configType', { configType })
1495
+ .andWhere('hub.app_code = :app_code', { app_code })
1496
+ .andWhere('hub.integration_type = :configType', { configType })
1497
+ .andWhere('hub.integration_provider = :provider', { provider })
1497
1498
  .andWhere('hub.status = :status', { status: 1 });
1498
1499
 
1499
1500
  // Exclude current hub if updating
@@ -1503,40 +1504,28 @@ export class CommunicationService {
1503
1504
 
1504
1505
  const existingActiveConfigs = await query.getMany();
1505
1506
 
1506
- // If there are existing active configurations, deactivate them
1507
+ // If there are existing active configurations of the same provider, throw error
1507
1508
  if (existingActiveConfigs.length > 0) {
1508
- await this.hubRepository.update(
1509
- {
1510
- level_id: levelId,
1511
- level_type: levelType,
1512
- communication_config_type: configType,
1513
- status: 1,
1514
- ...(excludeHubId && { id: Not(excludeHubId) }),
1515
- },
1516
- { status: 0 }, // Deactivate
1517
- );
1518
-
1519
- this.logger.log(
1520
- `Deactivated ${existingActiveConfigs.length} existing ${configType} configuration(s) for ${levelType} ${levelId} to maintain single active provider rule.`,
1509
+ throw new Error(
1510
+ `A ${provider} configuration already exists for ${configType} in app_code ${app_code}, ${levelType} ${levelId}. Only one configuration per provider is allowed.`,
1521
1511
  );
1522
1512
  }
1523
1513
  }
1524
1514
 
1525
1515
  private requiresOAuthFlow(
1526
- configType: CommunicationConfigType,
1527
- service: string,
1516
+ configType: 'EMAIL' | 'SMS' | 'WA' | 'TELEPHONE',
1528
1517
  provider: string,
1529
1518
  config: any,
1530
1519
  ): boolean {
1531
1520
  // Check if config indicates OAuth is needed (missing tokens or explicit OAuth request)
1532
- const key = `${configType.toLowerCase()}_${service.toLowerCase()}_${provider.toLowerCase()}`;
1521
+ const key = `${configType.toLowerCase()}_${provider.toLowerCase()}`;
1533
1522
 
1534
1523
  switch (key) {
1535
- case 'email_api_gmail':
1524
+ case 'email_gmail':
1536
1525
  // Requires OAuth if no access token provided or OAuth explicitly requested
1537
1526
  return !config.accessToken || config.useOAuth === true;
1538
1527
 
1539
- case 'email_api_outlook':
1528
+ case 'email_outlook':
1540
1529
  // Requires OAuth if no access token provided or OAuth explicitly requested
1541
1530
  return !config.accessToken || config.useOAuth === true;
1542
1531
 
@@ -1549,20 +1538,22 @@ export class CommunicationService {
1549
1538
  private async generateOAuthUrl(
1550
1539
  levelId: number,
1551
1540
  levelType: string,
1552
- configType: CommunicationConfigType,
1553
- service: string,
1541
+ app_code: string,
1542
+ configType: 'EMAIL' | 'SMS' | 'WA' | 'TELEPHONE',
1554
1543
  provider: string,
1544
+ integration_source_id: number,
1555
1545
  config: any,
1556
1546
  priority?: number,
1557
1547
  is_default?: boolean,
1558
1548
  ): Promise<{ authUrl: string; state: string; message: string }> {
1559
- const key = `${configType.toLowerCase()}_${service.toLowerCase()}_${provider.toLowerCase()}`;
1549
+ const key = `${configType.toLowerCase()}_${provider.toLowerCase()}`;
1560
1550
 
1561
1551
  switch (key) {
1562
- case 'email_api_gmail':
1552
+ case 'email_gmail':
1563
1553
  const gmailResult = await this.initGmailOAuth(
1564
1554
  levelId,
1565
1555
  levelType,
1556
+ app_code,
1566
1557
  config.email,
1567
1558
  );
1568
1559
  return {
@@ -1572,10 +1563,11 @@ export class CommunicationService {
1572
1563
  'Please complete Gmail OAuth authorization. Configuration will be created automatically after authorization.',
1573
1564
  };
1574
1565
 
1575
- case 'email_api_outlook':
1566
+ case 'email_outlook':
1576
1567
  const outlookResult = await this.initOutlookOAuth(
1577
1568
  levelId,
1578
1569
  levelType,
1570
+ app_code,
1579
1571
  config.email,
1580
1572
  );
1581
1573
  return {
@@ -1586,67 +1578,81 @@ export class CommunicationService {
1586
1578
  };
1587
1579
 
1588
1580
  default:
1589
- throw new Error(
1590
- `OAuth not supported for ${configType}/${service}/${provider}`,
1591
- );
1581
+ throw new Error(`OAuth not supported for ${configType}/${provider}`);
1592
1582
  }
1593
1583
  }
1594
1584
 
1595
1585
  private async createDirectConfig(
1596
1586
  levelId: number,
1597
1587
  levelType: string,
1598
- configType: CommunicationConfigType,
1599
- service: string,
1588
+ app_code: string,
1589
+ configType: 'EMAIL' | 'SMS' | 'WA' | 'TELEPHONE',
1600
1590
  provider: string,
1591
+ integration_source_id: number,
1601
1592
  config: any,
1602
1593
  priority?: number,
1603
1594
  is_default?: boolean,
1604
- ): Promise<CommunicationHub> {
1605
- // Deactivate any existing active configurations of the same type to ensure only one is active
1606
- await this.validateUniqueActiveConfig(levelId, levelType, configType);
1595
+ ): Promise<IntegrationConfig> {
1596
+ // Validate that no duplicate provider configurations exist
1597
+ await this.validateUniqueActiveConfig(
1598
+ levelId,
1599
+ levelType,
1600
+ app_code,
1601
+ configType,
1602
+ provider,
1603
+ );
1604
+
1605
+ // Deactivate all other configurations of the same integration type
1606
+ await this.configRepository.update(
1607
+ {
1608
+ level_id: levelId,
1609
+ level_type: levelType,
1610
+ app_code: app_code,
1611
+ integration_type: configType,
1612
+ status: 1,
1613
+ },
1614
+ { status: 0 },
1615
+ );
1607
1616
 
1608
- // If setting as default, remove default from other configurations of same type
1617
+ // If setting as default, remove default from other configurations of same type and app_code
1609
1618
  if (is_default) {
1610
- await this.hubRepository.update(
1619
+ await this.configRepository.update(
1611
1620
  {
1612
1621
  level_id: levelId,
1613
1622
  level_type: levelType,
1614
- communication_config_type: configType,
1623
+ app_code: app_code,
1624
+ integration_type: configType,
1615
1625
  },
1616
1626
  { is_default: false },
1617
1627
  );
1618
1628
  }
1619
1629
 
1620
- // First, create the config
1621
- const communicationConfig = this.configRepository.create({
1622
- config_json: config,
1623
- });
1624
- const savedConfig = await this.configRepository.save(communicationConfig);
1625
-
1626
- // Then create the hub
1627
- const hub = this.hubRepository.create({
1630
+ // Create integration config
1631
+ const integrationConfig = this.configRepository.create({
1632
+ app_code: app_code,
1633
+ integration_type: configType,
1634
+ integration_provider: provider,
1635
+ integration_source_id: integration_source_id,
1628
1636
  level_id: levelId,
1629
1637
  level_type: levelType,
1630
- config_id: savedConfig.id,
1631
- communication_config_type: configType,
1632
- service: service as any,
1633
- provider: provider as any,
1638
+ status: 1,
1634
1639
  priority: priority || 1,
1635
1640
  is_default: is_default || false,
1636
- status: 1,
1641
+ config_json: config,
1637
1642
  });
1638
1643
 
1639
- const savedHub = await this.hubRepository.save(hub);
1644
+ const savedConfig = await this.configRepository.save(integrationConfig);
1640
1645
  this.logger.log(
1641
- `Communication config created: ${configType}/${service}/${provider} for ${levelType} ${levelId}`,
1646
+ `Communication config created: ${configType}/${provider} for ${levelType} ${levelId}`,
1642
1647
  );
1643
1648
 
1644
- return Array.isArray(savedHub) ? savedHub[0] : savedHub;
1649
+ return Array.isArray(savedConfig) ? savedConfig[0] : savedConfig;
1645
1650
  }
1646
1651
 
1647
1652
  async initOutlookOAuth(
1648
1653
  levelId: number,
1649
1654
  levelType: string,
1655
+ app_code: string,
1650
1656
  email?: string,
1651
1657
  ): Promise<{ authUrl: string; state: string }> {
1652
1658
  try {
@@ -1666,6 +1672,7 @@ export class CommunicationService {
1666
1672
  this.gmailOAuthStates.set(state, {
1667
1673
  levelId,
1668
1674
  levelType,
1675
+ app_code,
1669
1676
  email,
1670
1677
  timestamp: Date.now(),
1671
1678
  });
@@ -1768,7 +1775,9 @@ export class CommunicationService {
1768
1775
  await this.validateUniqueActiveConfig(
1769
1776
  oauthState.levelId,
1770
1777
  oauthState.levelType,
1771
- CommunicationConfigType.EMAIL,
1778
+ oauthState.app_code,
1779
+ 'EMAIL',
1780
+ 'outlook',
1772
1781
  );
1773
1782
 
1774
1783
  const outlookConfig = {
@@ -1782,31 +1791,28 @@ export class CommunicationService {
1782
1791
  expiresIn: tokens.expires_in,
1783
1792
  };
1784
1793
 
1785
- // Create communication config
1786
- const communicationConfig = this.configRepository.create({
1787
- config_json: outlookConfig as any,
1788
- });
1789
- const savedConfig = await this.configRepository.save(communicationConfig);
1790
-
1791
- // Create communication hub
1792
- const hub = this.hubRepository.create({
1794
+ // Create integration config
1795
+ const config = this.configRepository.create({
1796
+ app_code: oauthState.app_code,
1797
+ integration_type: 'EMAIL',
1798
+ integration_provider: 'outlook',
1799
+ integration_source_id: 1, // Outlook source ID
1793
1800
  level_id: oauthState.levelId,
1794
1801
  level_type: oauthState.levelType,
1795
- config_id: savedConfig.id,
1796
- communication_config_type: CommunicationConfigType.EMAIL,
1797
- service: 'API',
1798
- provider: 'outlook',
1799
1802
  status: 1,
1803
+ priority: 1,
1804
+ is_default: false,
1805
+ config_json: outlookConfig as any,
1800
1806
  });
1801
1807
 
1802
- const savedHub = await this.hubRepository.save(hub);
1808
+ const savedConfig = await this.configRepository.save(config);
1803
1809
 
1804
1810
  this.logger.log(
1805
1811
  `Outlook OAuth configuration created successfully for ${oauthState.levelType} ${oauthState.levelId} and email ${email}`,
1806
1812
  );
1807
1813
 
1808
1814
  return {
1809
- hubId: savedHub.id,
1815
+ hubId: savedConfig.id,
1810
1816
  configId: savedConfig.id,
1811
1817
  };
1812
1818
  } catch (error) {
@@ -1818,59 +1824,40 @@ export class CommunicationService {
1818
1824
  }
1819
1825
  }
1820
1826
 
1821
- async getCommunicationConfigById(hubId: number): Promise<
1822
- | (CommunicationHub & {
1823
- config: CommunicationConfig;
1827
+ async getIntegrationConfigById(hubId: number): Promise<
1828
+ | (IntegrationConfig & {
1829
+ config: IntegrationConfig;
1824
1830
  linkedSource?: string;
1825
1831
  configDetails?: any;
1826
1832
  })
1827
1833
  | null
1828
1834
  > {
1829
1835
  try {
1830
- // Find the communication hub by ID
1831
- const hub = await this.hubRepository.findOne({
1836
+ // Find the integration config by ID
1837
+ const integrationConfig = await this.configRepository.findOne({
1832
1838
  where: { id: hubId },
1833
1839
  });
1834
1840
 
1835
- if (!hub) {
1841
+ if (!integrationConfig) {
1836
1842
  return null;
1837
1843
  }
1838
1844
 
1839
- // Find the associated config
1840
- const config = await this.configRepository.findOne({
1841
- where: { id: hub.config_id },
1842
- });
1843
-
1844
- if (!config) {
1845
- this.logger.warn(
1846
- `Configuration not found for hub ${hubId} with config_id ${hub.config_id}`,
1847
- );
1848
- return {
1849
- ...hub,
1850
- config: null as any,
1851
- linkedSource: 'Configuration not found',
1852
- configDetails: null,
1853
- };
1854
- }
1855
-
1856
1845
  // Extract linked source and config details
1857
1846
  const linkedSource = this.extractLinkedSource(
1858
- hub.communication_config_type,
1859
- hub.service,
1860
- hub.provider,
1861
- config.config_json,
1847
+ integrationConfig.integration_type,
1848
+ integrationConfig.integration_provider,
1849
+ integrationConfig.config_json,
1862
1850
  );
1863
1851
 
1864
1852
  const configDetails = this.extractConfigDetails(
1865
- hub.communication_config_type,
1866
- hub.service,
1867
- hub.provider,
1868
- config.config_json,
1853
+ integrationConfig.integration_type,
1854
+ integrationConfig.integration_provider,
1855
+ integrationConfig.config_json,
1869
1856
  );
1870
1857
 
1871
1858
  return {
1872
- ...hub,
1873
- config,
1859
+ ...integrationConfig,
1860
+ config: integrationConfig,
1874
1861
  linkedSource,
1875
1862
  configDetails,
1876
1863
  };
@@ -1888,6 +1875,7 @@ export class CommunicationService {
1888
1875
  async getSendGridTemplates(
1889
1876
  levelId: number,
1890
1877
  levelType: string,
1878
+ app_code: string,
1891
1879
  ): Promise<{
1892
1880
  success: boolean;
1893
1881
  data?: Array<{
@@ -1898,14 +1886,17 @@ export class CommunicationService {
1898
1886
  }> {
1899
1887
  try {
1900
1888
  // Find active SendGrid configurations for this level
1901
- const hubs = await this.getActiveHubs(
1889
+ const hubs = await this.getActiveConfigs(
1902
1890
  levelId,
1903
1891
  levelType,
1904
- CommunicationConfigType.EMAIL,
1892
+ app_code,
1893
+ 'EMAIL',
1905
1894
  );
1906
1895
 
1907
1896
  // Look for SendGrid provider
1908
- const sendGridHub = hubs.find((hub) => hub.provider === 'sendgrid');
1897
+ const sendGridHub = hubs.find(
1898
+ (hub) => hub.integration_provider === 'sendgrid',
1899
+ );
1909
1900
 
1910
1901
  if (!sendGridHub) {
1911
1902
  return {
@@ -1915,7 +1906,7 @@ export class CommunicationService {
1915
1906
  }
1916
1907
 
1917
1908
  // Extract API key from configuration
1918
- const apiKey = sendGridHub.config?.config_json?.apiKey;
1909
+ const apiKey = sendGridHub.config_json?.apiKey;
1919
1910
 
1920
1911
  if (!apiKey) {
1921
1912
  return {
@@ -1967,4 +1958,163 @@ export class CommunicationService {
1967
1958
  };
1968
1959
  }
1969
1960
  }
1961
+
1962
+ // UserIntegration Management Methods
1963
+
1964
+ async createUserIntegration(
1965
+ createDto: CreateUserIntegrationDto,
1966
+ ): Promise<UserIntegration> {
1967
+ try {
1968
+ // Check if mapping already exists
1969
+ const existing = await this.userIntegrationRepository.findOne({
1970
+ where: {
1971
+ user_id: createDto.user_id,
1972
+ integration_config_id: createDto.integration_config_id,
1973
+ },
1974
+ });
1975
+
1976
+ if (existing) {
1977
+ throw new Error('User integration mapping already exists');
1978
+ }
1979
+
1980
+ // Verify integration config exists
1981
+ const config = await this.configRepository.findOne({
1982
+ where: { id: createDto.integration_config_id },
1983
+ });
1984
+
1985
+ if (!config) {
1986
+ throw new Error('Integration configuration not found');
1987
+ }
1988
+
1989
+ const userIntegration = this.userIntegrationRepository.create(createDto);
1990
+ return await this.userIntegrationRepository.save(userIntegration);
1991
+ } catch (error) {
1992
+ this.logger.error(
1993
+ `Error creating user integration mapping: ${error.message}`,
1994
+ );
1995
+ throw error;
1996
+ }
1997
+ }
1998
+
1999
+ async getUserIntegrations(userId: number): Promise<UserIntegration[]> {
2000
+ try {
2001
+ return await this.userIntegrationRepository.find({
2002
+ where: { user_id: userId, is_active: true },
2003
+ order: { created_at: 'DESC' },
2004
+ });
2005
+ } catch (error) {
2006
+ this.logger.error(
2007
+ `Error fetching user integrations for user ${userId}: ${error.message}`,
2008
+ );
2009
+ throw error;
2010
+ }
2011
+ }
2012
+
2013
+ async getConfigUserIntegrations(
2014
+ configId: number,
2015
+ ): Promise<UserIntegration[]> {
2016
+ try {
2017
+ return await this.userIntegrationRepository.find({
2018
+ where: { integration_config_id: configId, is_active: true },
2019
+ order: { created_at: 'DESC' },
2020
+ });
2021
+ } catch (error) {
2022
+ this.logger.error(
2023
+ `Error fetching user integrations for config ${configId}: ${error.message}`,
2024
+ );
2025
+ throw error;
2026
+ }
2027
+ }
2028
+
2029
+ async getUserIntegrationByUserAndConfig(
2030
+ userId: number,
2031
+ configId: number,
2032
+ ): Promise<UserIntegration | null> {
2033
+ try {
2034
+ return await this.userIntegrationRepository.findOne({
2035
+ where: {
2036
+ user_id: userId,
2037
+ integration_config_id: configId,
2038
+ is_active: true,
2039
+ },
2040
+ });
2041
+ } catch (error) {
2042
+ this.logger.error(
2043
+ `Error fetching user integration for user ${userId} and config ${configId}: ${error.message}`,
2044
+ );
2045
+ throw error;
2046
+ }
2047
+ }
2048
+
2049
+ async updateUserIntegration(
2050
+ id: number,
2051
+ updateDto: UpdateUserIntegrationDto,
2052
+ ): Promise<UserIntegration> {
2053
+ try {
2054
+ const userIntegration = await this.userIntegrationRepository.findOne({
2055
+ where: { id },
2056
+ });
2057
+
2058
+ if (!userIntegration) {
2059
+ throw new Error('User integration mapping not found');
2060
+ }
2061
+
2062
+ Object.assign(userIntegration, updateDto);
2063
+ return await this.userIntegrationRepository.save(userIntegration);
2064
+ } catch (error) {
2065
+ this.logger.error(
2066
+ `Error updating user integration ${id}: ${error.message}`,
2067
+ );
2068
+ throw error;
2069
+ }
2070
+ }
2071
+
2072
+ async deleteUserIntegration(id: number): Promise<void> {
2073
+ try {
2074
+ const userIntegration = await this.userIntegrationRepository.findOne({
2075
+ where: { id },
2076
+ });
2077
+
2078
+ if (!userIntegration) {
2079
+ throw new Error('User integration mapping not found');
2080
+ }
2081
+
2082
+ await this.userIntegrationRepository.remove(userIntegration);
2083
+ } catch (error) {
2084
+ this.logger.error(
2085
+ `Error deleting user integration ${id}: ${error.message}`,
2086
+ );
2087
+ throw error;
2088
+ }
2089
+ }
2090
+
2091
+ /**
2092
+ * Get user integration data for a specific integration strategy
2093
+ * This method is intended to be used by strategies that need user mapping
2094
+ */
2095
+ async getUserIntegrationForStrategy(
2096
+ userId: number,
2097
+ integrationConfigId: number,
2098
+ ): Promise<any | null> {
2099
+ try {
2100
+ const userIntegration = await this.getUserIntegrationByUserAndConfig(
2101
+ userId,
2102
+ integrationConfigId,
2103
+ );
2104
+
2105
+ if (!userIntegration) {
2106
+ return null;
2107
+ }
2108
+
2109
+ return {
2110
+ external_user_id: userIntegration.external_user_id,
2111
+ external_user_data: userIntegration.external_user_data,
2112
+ };
2113
+ } catch (error) {
2114
+ this.logger.error(
2115
+ `Error fetching user integration data for strategy: ${error.message}`,
2116
+ );
2117
+ return null;
2118
+ }
2119
+ }
1970
2120
  }