rez_core 2.2.154 → 2.2.156
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.module.js +2 -0
- package/dist/app.module.js.map +1 -1
- package/dist/constant/global.constant.d.ts +1 -1
- package/dist/constant/global.constant.js +1 -1
- package/dist/constant/global.constant.js.map +1 -1
- package/dist/module/auth/strategies/google.strategy.js +1 -1
- package/dist/module/auth/strategies/google.strategy.js.map +1 -1
- package/dist/module/communication/communication.module.d.ts +2 -0
- package/dist/module/communication/communication.module.js +69 -0
- package/dist/module/communication/communication.module.js.map +1 -0
- package/dist/module/communication/controller/communication.controller.d.ts +54 -0
- package/dist/module/communication/controller/communication.controller.js +148 -0
- package/dist/module/communication/controller/communication.controller.js.map +1 -0
- package/dist/module/communication/dto/create-config.dto.d.ts +91 -0
- package/dist/module/communication/dto/create-config.dto.js +243 -0
- package/dist/module/communication/dto/create-config.dto.js.map +1 -0
- package/dist/module/communication/entity/communication-config.entity.d.ts +44 -0
- package/dist/module/communication/entity/communication-config.entity.js +45 -0
- package/dist/module/communication/entity/communication-config.entity.js.map +1 -0
- package/dist/module/communication/entity/communication-hub.entity.d.ts +20 -0
- package/dist/module/communication/entity/communication-hub.entity.js +105 -0
- package/dist/module/communication/entity/communication-hub.entity.js.map +1 -0
- package/dist/module/communication/examples/usage.example.d.ts +11 -0
- package/dist/module/communication/examples/usage.example.js +89 -0
- package/dist/module/communication/examples/usage.example.js.map +1 -0
- package/dist/module/communication/factories/base.factory.d.ts +9 -0
- package/dist/module/communication/factories/base.factory.js +3 -0
- package/dist/module/communication/factories/base.factory.js.map +1 -0
- package/dist/module/communication/factories/communication.factory.d.ts +33 -0
- package/dist/module/communication/factories/communication.factory.js +104 -0
- package/dist/module/communication/factories/communication.factory.js.map +1 -0
- package/dist/module/communication/factories/email.factory.d.ts +19 -0
- package/dist/module/communication/factories/email.factory.js +61 -0
- package/dist/module/communication/factories/email.factory.js.map +1 -0
- package/dist/module/communication/factories/sms.factory.d.ts +15 -0
- package/dist/module/communication/factories/sms.factory.js +49 -0
- package/dist/module/communication/factories/sms.factory.js.map +1 -0
- package/dist/module/communication/factories/telephone.factory.d.ts +13 -0
- package/dist/module/communication/factories/telephone.factory.js +43 -0
- package/dist/module/communication/factories/telephone.factory.js.map +1 -0
- package/dist/module/communication/factories/whatsapp.factory.d.ts +13 -0
- package/dist/module/communication/factories/whatsapp.factory.js +43 -0
- package/dist/module/communication/factories/whatsapp.factory.js.map +1 -0
- package/dist/module/communication/service/communication.service.d.ts +111 -0
- package/dist/module/communication/service/communication.service.js +726 -0
- package/dist/module/communication/service/communication.service.js.map +1 -0
- package/dist/module/communication/service/oauth.service.d.ts +18 -0
- package/dist/module/communication/service/oauth.service.js +185 -0
- package/dist/module/communication/service/oauth.service.js.map +1 -0
- package/dist/module/communication/strategies/communication.strategy.d.ts +17 -0
- package/dist/module/communication/strategies/communication.strategy.js +3 -0
- package/dist/module/communication/strategies/communication.strategy.js.map +1 -0
- package/dist/module/communication/strategies/email/gmail-api.strategy.d.ts +7 -0
- package/dist/module/communication/strategies/email/gmail-api.strategy.js +135 -0
- package/dist/module/communication/strategies/email/gmail-api.strategy.js.map +1 -0
- package/dist/module/communication/strategies/email/gmail-smtp.strategy.d.ts +5 -0
- package/dist/module/communication/strategies/email/gmail-smtp.strategy.js +49 -0
- package/dist/module/communication/strategies/email/gmail-smtp.strategy.js.map +1 -0
- package/dist/module/communication/strategies/email/outlook-api.strategy.d.ts +5 -0
- package/dist/module/communication/strategies/email/outlook-api.strategy.js +44 -0
- package/dist/module/communication/strategies/email/outlook-api.strategy.js.map +1 -0
- package/dist/module/communication/strategies/gmail-smtp.strategy.d.ts +5 -0
- package/dist/module/communication/strategies/gmail-smtp.strategy.js +61 -0
- package/dist/module/communication/strategies/gmail-smtp.strategy.js.map +1 -0
- package/dist/module/communication/strategies/gmail.strategy.d.ts +5 -0
- package/dist/module/communication/strategies/gmail.strategy.js +71 -0
- package/dist/module/communication/strategies/gmail.strategy.js.map +1 -0
- package/dist/module/communication/strategies/knowlarity.strategy.d.ts +6 -0
- package/dist/module/communication/strategies/knowlarity.strategy.js +115 -0
- package/dist/module/communication/strategies/knowlarity.strategy.js.map +1 -0
- package/dist/module/communication/strategies/outlook-smtp.strategy.d.ts +5 -0
- package/dist/module/communication/strategies/outlook-smtp.strategy.js +66 -0
- package/dist/module/communication/strategies/outlook-smtp.strategy.js.map +1 -0
- package/dist/module/communication/strategies/outlook.strategy.d.ts +5 -0
- package/dist/module/communication/strategies/outlook.strategy.js +64 -0
- package/dist/module/communication/strategies/outlook.strategy.js.map +1 -0
- package/dist/module/communication/strategies/sms/knowlarity.strategy.d.ts +5 -0
- package/dist/module/communication/strategies/sms/knowlarity.strategy.js +44 -0
- package/dist/module/communication/strategies/sms/knowlarity.strategy.js.map +1 -0
- package/dist/module/communication/strategies/sms/twilio.strategy.d.ts +5 -0
- package/dist/module/communication/strategies/sms/twilio.strategy.js +44 -0
- package/dist/module/communication/strategies/sms/twilio.strategy.js.map +1 -0
- package/dist/module/communication/strategies/sms.strategy.d.ts +5 -0
- package/dist/module/communication/strategies/sms.strategy.js +50 -0
- package/dist/module/communication/strategies/sms.strategy.js.map +1 -0
- package/dist/module/communication/strategies/telephone/knowlarity-voice.strategy.d.ts +5 -0
- package/dist/module/communication/strategies/telephone/knowlarity-voice.strategy.js +44 -0
- package/dist/module/communication/strategies/telephone/knowlarity-voice.strategy.js.map +1 -0
- package/dist/module/communication/strategies/whatsapp/whatsapp-cloud.strategy.d.ts +5 -0
- package/dist/module/communication/strategies/whatsapp/whatsapp-cloud.strategy.js +47 -0
- package/dist/module/communication/strategies/whatsapp/whatsapp-cloud.strategy.js.map +1 -0
- package/dist/module/communication/strategies/whatsapp.strategy.d.ts +5 -0
- package/dist/module/communication/strategies/whatsapp.strategy.js +58 -0
- package/dist/module/communication/strategies/whatsapp.strategy.js.map +1 -0
- package/dist/module/meta/entity.module.js +2 -1
- package/dist/module/meta/entity.module.js.map +1 -1
- package/dist/module/user/controller/login.controller.d.ts +4 -2
- package/dist/module/user/controller/login.controller.js +26 -4
- package/dist/module/user/controller/login.controller.js.map +1 -1
- package/dist/module/workflow/service/populate-workflow.service.js +2 -2
- package/dist/module/workflow/service/populate-workflow.service.js.map +1 -1
- package/dist/module/workflow/service/stage.service.js +1 -1
- package/dist/module/workflow/service/stage.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +4 -1
- package/src/app.module.ts +2 -0
- package/src/constant/global.constant.ts +1 -1
- package/src/module/auth/strategies/google.strategy.ts +1 -1
- package/src/module/communication/communication.module.ts +77 -0
- package/src/module/communication/controller/communication.controller.ts +122 -0
- package/src/module/communication/dto/create-config.dto.ts +234 -0
- package/src/module/communication/entity/communication-config.entity.ts +80 -0
- package/src/module/communication/entity/communication-hub.entity.ts +77 -0
- package/src/module/communication/examples/usage.example.ts +169 -0
- package/src/module/communication/factories/base.factory.ts +7 -0
- package/src/module/communication/factories/communication.factory.ts +103 -0
- package/src/module/communication/factories/email.factory.ts +51 -0
- package/src/module/communication/factories/sms.factory.ts +41 -0
- package/src/module/communication/factories/telephone.factory.ts +34 -0
- package/src/module/communication/factories/whatsapp.factory.ts +34 -0
- package/src/module/communication/service/communication.service.ts +1118 -0
- package/src/module/communication/service/oauth.service.ts +203 -0
- package/src/module/communication/strategies/communication.strategy.ts +23 -0
- package/src/module/communication/strategies/email/gmail-api.strategy.ts +161 -0
- package/src/module/communication/strategies/email/gmail-smtp.strategy.ts +51 -0
- package/src/module/communication/strategies/email/outlook-api.strategy.ts +44 -0
- package/src/module/communication/strategies/gmail-smtp.strategy.ts +64 -0
- package/src/module/communication/strategies/gmail.strategy.ts +68 -0
- package/src/module/communication/strategies/knowlarity.strategy.ts +124 -0
- package/src/module/communication/strategies/outlook-smtp.strategy.ts +69 -0
- package/src/module/communication/strategies/outlook.strategy.ts +57 -0
- package/src/module/communication/strategies/sms/knowlarity.strategy.ts +44 -0
- package/src/module/communication/strategies/sms/twilio.strategy.ts +44 -0
- package/src/module/communication/strategies/sms.strategy.ts +44 -0
- package/src/module/communication/strategies/telephone/knowlarity-voice.strategy.ts +44 -0
- package/src/module/communication/strategies/whatsapp/whatsapp-cloud.strategy.ts +49 -0
- package/src/module/communication/strategies/whatsapp.strategy.ts +53 -0
- package/src/module/meta/entity.module.ts +2 -1
- package/src/module/user/controller/login.controller.ts +34 -3
- package/src/module/workflow/service/populate-workflow.service.ts +3 -3
- package/src/module/workflow/service/stage.service.ts +1 -1
- package/src/resources/dev.properties.yaml +1 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { Injectable, BadRequestException } from '@nestjs/common';
|
|
2
|
+
import { google } from 'googleapis';
|
|
3
|
+
import { Client } from '@microsoft/microsoft-graph-client';
|
|
4
|
+
|
|
5
|
+
@Injectable()
|
|
6
|
+
export class OAuthService {
|
|
7
|
+
private readonly gmailOAuth2Client = new google.auth.OAuth2(
|
|
8
|
+
process.env.GMAIL_CLIENT_ID,
|
|
9
|
+
process.env.GMAIL_CLIENT_SECRET,
|
|
10
|
+
process.env.GMAIL_REDIRECT_URI || 'http://localhost:3000/api/communication/oauth/callback/gmail'
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
private readonly outlookScopes = [
|
|
14
|
+
'https://graph.microsoft.com/mail.send',
|
|
15
|
+
'https://graph.microsoft.com/user.read'
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
private readonly gmailScopes = [
|
|
19
|
+
'https://www.googleapis.com/auth/gmail.send',
|
|
20
|
+
'https://www.googleapis.com/auth/gmail.readonly'
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
generateGmailAuthUrl(state: string): string {
|
|
24
|
+
return this.gmailOAuth2Client.generateAuthUrl({
|
|
25
|
+
access_type: 'offline',
|
|
26
|
+
scope: this.gmailScopes,
|
|
27
|
+
state: state,
|
|
28
|
+
prompt: 'consent'
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
generateOutlookAuthUrl(state: string): string {
|
|
33
|
+
const clientId = process.env.OUTLOOK_CLIENT_ID;
|
|
34
|
+
const redirectUri = encodeURIComponent(process.env.OUTLOOK_REDIRECT_URI || 'http://localhost:3000/api/communication/oauth/callback/outlook');
|
|
35
|
+
const scope = encodeURIComponent(this.outlookScopes.join(' '));
|
|
36
|
+
|
|
37
|
+
return `https://login.microsoftonline.com/common/oauth2/v2.0/authorize?` +
|
|
38
|
+
`client_id=${clientId}&` +
|
|
39
|
+
`response_type=code&` +
|
|
40
|
+
`redirect_uri=${redirectUri}&` +
|
|
41
|
+
`scope=${scope}&` +
|
|
42
|
+
`response_mode=query&` +
|
|
43
|
+
`state=${state}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async exchangeGmailCode(code: string): Promise<any> {
|
|
47
|
+
try {
|
|
48
|
+
const { tokens } = await this.gmailOAuth2Client.getToken(code);
|
|
49
|
+
|
|
50
|
+
this.gmailOAuth2Client.setCredentials(tokens);
|
|
51
|
+
|
|
52
|
+
// Get user info
|
|
53
|
+
const oauth2 = google.oauth2({
|
|
54
|
+
auth: this.gmailOAuth2Client,
|
|
55
|
+
version: 'v2'
|
|
56
|
+
});
|
|
57
|
+
const userInfo = await oauth2.userinfo.get();
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
accessToken: tokens.access_token,
|
|
61
|
+
refreshToken: tokens.refresh_token,
|
|
62
|
+
expiresIn: tokens.expiry_date,
|
|
63
|
+
email: userInfo.data.email,
|
|
64
|
+
tokenType: tokens.token_type,
|
|
65
|
+
scope: tokens.scope
|
|
66
|
+
};
|
|
67
|
+
} catch (error) {
|
|
68
|
+
throw new BadRequestException('Failed to exchange Gmail authorization code');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async exchangeOutlookCode(code: string): Promise<any> {
|
|
73
|
+
try {
|
|
74
|
+
const clientId = process.env.OUTLOOK_CLIENT_ID;
|
|
75
|
+
const clientSecret = process.env.OUTLOOK_CLIENT_SECRET;
|
|
76
|
+
const redirectUri = process.env.OUTLOOK_REDIRECT_URI || 'http://localhost:3000/api/communication/oauth/callback/outlook';
|
|
77
|
+
|
|
78
|
+
const tokenUrl = 'https://login.microsoftonline.com/common/oauth2/v2.0/token';
|
|
79
|
+
|
|
80
|
+
const response = await fetch(tokenUrl, {
|
|
81
|
+
method: 'POST',
|
|
82
|
+
headers: {
|
|
83
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
84
|
+
},
|
|
85
|
+
body: new URLSearchParams({
|
|
86
|
+
client_id: clientId!,
|
|
87
|
+
client_secret: clientSecret!,
|
|
88
|
+
code: code,
|
|
89
|
+
redirect_uri: redirectUri,
|
|
90
|
+
grant_type: 'authorization_code',
|
|
91
|
+
scope: this.outlookScopes.join(' ')
|
|
92
|
+
})
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const tokenData = await response.json();
|
|
96
|
+
|
|
97
|
+
if (!response.ok) {
|
|
98
|
+
throw new Error(tokenData.error_description || 'Token exchange failed');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Get user info using the access token
|
|
102
|
+
const graphClient = Client.init({
|
|
103
|
+
authProvider: {
|
|
104
|
+
getAccessToken: async () => tokenData.access_token,
|
|
105
|
+
} as any,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const userInfo = await graphClient.api('/me').get();
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
accessToken: tokenData.access_token,
|
|
112
|
+
refreshToken: tokenData.refresh_token,
|
|
113
|
+
expiresIn: tokenData.expires_in,
|
|
114
|
+
email: userInfo.mail || userInfo.userPrincipalName,
|
|
115
|
+
tokenType: tokenData.token_type,
|
|
116
|
+
scope: tokenData.scope
|
|
117
|
+
};
|
|
118
|
+
} catch (error) {
|
|
119
|
+
throw new BadRequestException('Failed to exchange Outlook authorization code');
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async refreshGmailToken(refreshToken: string): Promise<any> {
|
|
124
|
+
try {
|
|
125
|
+
this.gmailOAuth2Client.setCredentials({
|
|
126
|
+
refresh_token: refreshToken
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
const { credentials } = await this.gmailOAuth2Client.refreshAccessToken();
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
accessToken: credentials.access_token,
|
|
133
|
+
refreshToken: credentials.refresh_token || refreshToken,
|
|
134
|
+
expiresIn: credentials.expiry_date,
|
|
135
|
+
tokenType: credentials.token_type
|
|
136
|
+
};
|
|
137
|
+
} catch (error) {
|
|
138
|
+
throw new BadRequestException('Failed to refresh Gmail token');
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async refreshOutlookToken(refreshToken: string): Promise<any> {
|
|
143
|
+
try {
|
|
144
|
+
const clientId = process.env.OUTLOOK_CLIENT_ID;
|
|
145
|
+
const clientSecret = process.env.OUTLOOK_CLIENT_SECRET;
|
|
146
|
+
|
|
147
|
+
const tokenUrl = 'https://login.microsoftonline.com/common/oauth2/v2.0/token';
|
|
148
|
+
|
|
149
|
+
const response = await fetch(tokenUrl, {
|
|
150
|
+
method: 'POST',
|
|
151
|
+
headers: {
|
|
152
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
153
|
+
},
|
|
154
|
+
body: new URLSearchParams({
|
|
155
|
+
client_id: clientId!,
|
|
156
|
+
client_secret: clientSecret!,
|
|
157
|
+
refresh_token: refreshToken,
|
|
158
|
+
grant_type: 'refresh_token',
|
|
159
|
+
scope: this.outlookScopes.join(' ')
|
|
160
|
+
})
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const tokenData = await response.json();
|
|
164
|
+
|
|
165
|
+
if (!response.ok) {
|
|
166
|
+
throw new Error(tokenData.error_description || 'Token refresh failed');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
accessToken: tokenData.access_token,
|
|
171
|
+
refreshToken: tokenData.refresh_token || refreshToken,
|
|
172
|
+
expiresIn: tokenData.expires_in,
|
|
173
|
+
tokenType: tokenData.token_type
|
|
174
|
+
};
|
|
175
|
+
} catch (error) {
|
|
176
|
+
throw new BadRequestException('Failed to refresh Outlook token');
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
generateState(prefix: string, additionalData?: any): string {
|
|
181
|
+
const timestamp = Date.now();
|
|
182
|
+
const random = Math.random().toString(36).substring(7);
|
|
183
|
+
const data = additionalData ? JSON.stringify(additionalData) : '';
|
|
184
|
+
return `${prefix}:${timestamp}:${random}:${Buffer.from(data).toString('base64')}`;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
parseState(state: string): { prefix: string; timestamp: number; random: string; data: any } {
|
|
188
|
+
const parts = state.split(':');
|
|
189
|
+
if (parts.length !== 4) {
|
|
190
|
+
throw new BadRequestException('Invalid state parameter');
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const [prefix, timestamp, random, encodedData] = parts;
|
|
194
|
+
const data = encodedData ? JSON.parse(Buffer.from(encodedData, 'base64').toString()) : null;
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
prefix,
|
|
198
|
+
timestamp: parseInt(timestamp),
|
|
199
|
+
random,
|
|
200
|
+
data
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface CommunicationStrategy {
|
|
2
|
+
sendMessage(
|
|
3
|
+
to: string,
|
|
4
|
+
message: string,
|
|
5
|
+
config: any,
|
|
6
|
+
): Promise<CommunicationResult>;
|
|
7
|
+
validateConfig(config: any): boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface CommunicationResult {
|
|
11
|
+
success: boolean;
|
|
12
|
+
messageId?: string;
|
|
13
|
+
provider: string;
|
|
14
|
+
service: string;
|
|
15
|
+
error?: string;
|
|
16
|
+
timestamp: Date;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface MessageTemplate {
|
|
20
|
+
subject?: string;
|
|
21
|
+
body: string;
|
|
22
|
+
attachments?: any[];
|
|
23
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
import {
|
|
4
|
+
CommunicationStrategy,
|
|
5
|
+
CommunicationResult,
|
|
6
|
+
} from '../communication.strategy';
|
|
7
|
+
|
|
8
|
+
@Injectable()
|
|
9
|
+
export class GmailApiStrategy implements CommunicationStrategy {
|
|
10
|
+
async sendMessage(
|
|
11
|
+
to: string | string[],
|
|
12
|
+
message: string,
|
|
13
|
+
config: any,
|
|
14
|
+
): Promise<CommunicationResult> {
|
|
15
|
+
try {
|
|
16
|
+
if (!this.validateConfig(config)) {
|
|
17
|
+
throw new Error('Invalid Gmail API configuration');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const { accessToken, subject, html, cc, bcc } = config;
|
|
21
|
+
|
|
22
|
+
console.log('---- Using HTTP Gmail API ----');
|
|
23
|
+
console.log('accessToken:', accessToken ? 'Present' : 'Missing');
|
|
24
|
+
|
|
25
|
+
const toRecipients = Array.isArray(to) ? to.join(', ') : to;
|
|
26
|
+
const ccRecipients = cc ? (Array.isArray(cc) ? cc.join(', ') : cc) : undefined;
|
|
27
|
+
const bccRecipients = bcc ? (Array.isArray(bcc) ? bcc.join(', ') : bcc) : undefined;
|
|
28
|
+
|
|
29
|
+
const emailLines = [
|
|
30
|
+
`To: ${toRecipients}`,
|
|
31
|
+
`Subject: ${subject || 'Notification'}`,
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
if (ccRecipients) {
|
|
35
|
+
emailLines.push(`Cc: ${ccRecipients}`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (bccRecipients) {
|
|
39
|
+
emailLines.push(`Bcc: ${bccRecipients}`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
emailLines.push('Content-Type: text/html; charset=utf-8');
|
|
43
|
+
emailLines.push('');
|
|
44
|
+
|
|
45
|
+
if (html) {
|
|
46
|
+
emailLines.push(html);
|
|
47
|
+
} else {
|
|
48
|
+
emailLines.push(message);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const emailContent = emailLines.join('\n');
|
|
52
|
+
const encodedMessage = Buffer.from(emailContent)
|
|
53
|
+
.toString('base64')
|
|
54
|
+
.replace(/\+/g, '-')
|
|
55
|
+
.replace(/\//g, '_')
|
|
56
|
+
.replace(/=+$/, '');
|
|
57
|
+
|
|
58
|
+
// Direct HTTP call to Gmail API
|
|
59
|
+
const response = await axios.post(
|
|
60
|
+
'https://gmail.googleapis.com/gmail/v1/users/me/messages/send',
|
|
61
|
+
{
|
|
62
|
+
raw: encodedMessage,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
headers: {
|
|
66
|
+
'Authorization': `Bearer ${accessToken}`,
|
|
67
|
+
'Content-Type': 'application/json',
|
|
68
|
+
},
|
|
69
|
+
timeout: 30000, // 30 second timeout
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
console.log('---- Gmail HTTP API Success ----');
|
|
74
|
+
console.log('Response status:', response.status);
|
|
75
|
+
console.log('Message ID:', response.data?.id);
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
success: true,
|
|
79
|
+
messageId: response.data?.id || undefined,
|
|
80
|
+
provider: 'gmail',
|
|
81
|
+
service: 'API',
|
|
82
|
+
timestamp: new Date(),
|
|
83
|
+
};
|
|
84
|
+
} catch (error) {
|
|
85
|
+
console.error('---- Gmail HTTP API Error ----');
|
|
86
|
+
console.error('Error message:', error.message);
|
|
87
|
+
console.error('Status:', error.response?.status);
|
|
88
|
+
console.error('Response data:', error.response?.data);
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
success: false,
|
|
92
|
+
provider: 'gmail',
|
|
93
|
+
service: 'API',
|
|
94
|
+
error: error.response?.data?.error?.message || error.message || 'Gmail API error',
|
|
95
|
+
timestamp: new Date(),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
validateConfig(config: any): boolean {
|
|
101
|
+
if (!config) return false;
|
|
102
|
+
|
|
103
|
+
// For HTTP API, we just need accessToken
|
|
104
|
+
return (
|
|
105
|
+
config.accessToken &&
|
|
106
|
+
typeof config.accessToken === 'string'
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async refreshAccessToken(config: any): Promise<string> {
|
|
111
|
+
try {
|
|
112
|
+
const { clientId, clientSecret, refreshToken } = config;
|
|
113
|
+
|
|
114
|
+
if (!clientId || !clientSecret || !refreshToken) {
|
|
115
|
+
throw new Error('Missing OAuth credentials for token refresh');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const response = await axios.post('https://oauth2.googleapis.com/token', {
|
|
119
|
+
client_id: clientId,
|
|
120
|
+
client_secret: clientSecret,
|
|
121
|
+
refresh_token: refreshToken,
|
|
122
|
+
grant_type: 'refresh_token',
|
|
123
|
+
}, {
|
|
124
|
+
headers: {
|
|
125
|
+
'Content-Type': 'application/json',
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
return response.data.access_token || '';
|
|
130
|
+
} catch (error) {
|
|
131
|
+
console.error('Failed to refresh access token:', error.response?.data || error.message);
|
|
132
|
+
throw new Error(`Failed to refresh Gmail access token: ${error.response?.data?.error_description || error.message}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async validateConnection(config: any): Promise<boolean> {
|
|
137
|
+
try {
|
|
138
|
+
if (!this.validateConfig(config)) {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const { accessToken } = config;
|
|
143
|
+
|
|
144
|
+
// Test the connection by getting user profile
|
|
145
|
+
const response = await axios.get(
|
|
146
|
+
'https://gmail.googleapis.com/gmail/v1/users/me/profile',
|
|
147
|
+
{
|
|
148
|
+
headers: {
|
|
149
|
+
'Authorization': `Bearer ${accessToken}`,
|
|
150
|
+
},
|
|
151
|
+
timeout: 10000, // 10 second timeout for validation
|
|
152
|
+
}
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
return response.status === 200 && response.data.emailAddress;
|
|
156
|
+
} catch (error) {
|
|
157
|
+
console.error('Gmail connection validation failed:', error.response?.data || error.message);
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import {
|
|
3
|
+
CommunicationStrategy,
|
|
4
|
+
CommunicationResult,
|
|
5
|
+
} from '../communication.strategy';
|
|
6
|
+
|
|
7
|
+
@Injectable()
|
|
8
|
+
export class GmailSmtpStrategy implements CommunicationStrategy {
|
|
9
|
+
async sendMessage(
|
|
10
|
+
to: string,
|
|
11
|
+
message: string,
|
|
12
|
+
config: any,
|
|
13
|
+
): Promise<CommunicationResult> {
|
|
14
|
+
try {
|
|
15
|
+
if (!this.validateConfig(config)) {
|
|
16
|
+
throw new Error('Invalid Gmail SMTP configuration');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// SMTP implementation would go here using nodemailer
|
|
20
|
+
// This is a placeholder for actual SMTP integration
|
|
21
|
+
console.log('Sending email via Gmail SMTP to:', to);
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
success: true,
|
|
25
|
+
messageId: `gmail-smtp-${Date.now()}`,
|
|
26
|
+
provider: 'gmail',
|
|
27
|
+
service: 'SMTP',
|
|
28
|
+
timestamp: new Date(),
|
|
29
|
+
};
|
|
30
|
+
} catch (error) {
|
|
31
|
+
return {
|
|
32
|
+
success: false,
|
|
33
|
+
provider: 'gmail',
|
|
34
|
+
service: 'SMTP',
|
|
35
|
+
error: error.message,
|
|
36
|
+
timestamp: new Date(),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
validateConfig(config: any): boolean {
|
|
42
|
+
return (
|
|
43
|
+
config &&
|
|
44
|
+
config.host &&
|
|
45
|
+
config.port &&
|
|
46
|
+
config.auth &&
|
|
47
|
+
config.auth.user &&
|
|
48
|
+
config.auth.pass
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import {
|
|
3
|
+
CommunicationStrategy,
|
|
4
|
+
CommunicationResult,
|
|
5
|
+
} from '../communication.strategy';
|
|
6
|
+
|
|
7
|
+
@Injectable()
|
|
8
|
+
export class OutlookApiStrategy implements CommunicationStrategy {
|
|
9
|
+
async sendMessage(
|
|
10
|
+
to: string,
|
|
11
|
+
message: string,
|
|
12
|
+
config: any,
|
|
13
|
+
): Promise<CommunicationResult> {
|
|
14
|
+
try {
|
|
15
|
+
if (!this.validateConfig(config)) {
|
|
16
|
+
throw new Error('Invalid Outlook API configuration');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Microsoft Graph API implementation would go here
|
|
20
|
+
// This is a placeholder for actual Outlook API integration
|
|
21
|
+
console.log('Sending email via Outlook API to:', to);
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
success: true,
|
|
25
|
+
messageId: `outlook-${Date.now()}`,
|
|
26
|
+
provider: 'outlook',
|
|
27
|
+
service: 'API',
|
|
28
|
+
timestamp: new Date(),
|
|
29
|
+
};
|
|
30
|
+
} catch (error) {
|
|
31
|
+
return {
|
|
32
|
+
success: false,
|
|
33
|
+
provider: 'outlook',
|
|
34
|
+
service: 'API',
|
|
35
|
+
error: error.message,
|
|
36
|
+
timestamp: new Date(),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
validateConfig(config: any): boolean {
|
|
42
|
+
return config && config.clientId && config.clientSecret && config.tenantId;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import * as nodemailer from 'nodemailer';
|
|
3
|
+
import { CommunicationStrategy, CommunicationResult } from './communication.strategy';
|
|
4
|
+
|
|
5
|
+
@Injectable()
|
|
6
|
+
export class GmailSMTPStrategy implements CommunicationStrategy {
|
|
7
|
+
async sendMessage(to: string, message: string, config: any): Promise<CommunicationResult> {
|
|
8
|
+
try {
|
|
9
|
+
const {
|
|
10
|
+
email,
|
|
11
|
+
password,
|
|
12
|
+
subject = 'Notification',
|
|
13
|
+
html,
|
|
14
|
+
attachments,
|
|
15
|
+
cc,
|
|
16
|
+
bcc
|
|
17
|
+
} = config;
|
|
18
|
+
|
|
19
|
+
const transporter = nodemailer.createTransport({
|
|
20
|
+
service: 'gmail',
|
|
21
|
+
auth: {
|
|
22
|
+
user: email,
|
|
23
|
+
pass: password,
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const mailOptions = {
|
|
28
|
+
from: email,
|
|
29
|
+
to: Array.isArray(to) ? to.join(',') : to,
|
|
30
|
+
cc: cc ? (Array.isArray(cc) ? cc.join(',') : cc) : undefined,
|
|
31
|
+
bcc: bcc ? (Array.isArray(bcc) ? bcc.join(',') : bcc) : undefined,
|
|
32
|
+
subject,
|
|
33
|
+
text: message,
|
|
34
|
+
html: html || message,
|
|
35
|
+
attachments: attachments || [],
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const result = await transporter.sendMail(mailOptions);
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
success: true,
|
|
42
|
+
provider: 'gmail',
|
|
43
|
+
service: 'SMTP',
|
|
44
|
+
messageId: result.messageId,
|
|
45
|
+
timestamp: new Date(),
|
|
46
|
+
};
|
|
47
|
+
} catch (error) {
|
|
48
|
+
return {
|
|
49
|
+
success: false,
|
|
50
|
+
provider: 'gmail',
|
|
51
|
+
service: 'SMTP',
|
|
52
|
+
error: error.message,
|
|
53
|
+
timestamp: new Date(),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
validateConfig(config: any): boolean {
|
|
59
|
+
return !!(
|
|
60
|
+
config.email &&
|
|
61
|
+
config.password
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import { google } from 'googleapis';
|
|
3
|
+
import { CommunicationStrategy, CommunicationResult } from './communication.strategy';
|
|
4
|
+
|
|
5
|
+
@Injectable()
|
|
6
|
+
export class GmailStrategy implements CommunicationStrategy {
|
|
7
|
+
async sendMessage(to: string, message: string, config: any): Promise<CommunicationResult> {
|
|
8
|
+
try {
|
|
9
|
+
const { clientId, clientSecret, refreshToken, accessToken, email } = config;
|
|
10
|
+
|
|
11
|
+
const oauth2Client = new google.auth.OAuth2(clientId, clientSecret);
|
|
12
|
+
oauth2Client.setCredentials({
|
|
13
|
+
refresh_token: refreshToken,
|
|
14
|
+
access_token: accessToken,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const gmail = google.gmail({ version: 'v1', auth: oauth2Client });
|
|
18
|
+
|
|
19
|
+
const subject = config.subject || 'Notification';
|
|
20
|
+
const emailContent = [
|
|
21
|
+
`From: ${email}`,
|
|
22
|
+
`To: ${to}`,
|
|
23
|
+
`Subject: ${subject}`,
|
|
24
|
+
'Content-Type: text/html; charset=utf-8',
|
|
25
|
+
'',
|
|
26
|
+
config.html || message,
|
|
27
|
+
].join('\n');
|
|
28
|
+
|
|
29
|
+
const encodedMessage = Buffer.from(emailContent)
|
|
30
|
+
.toString('base64')
|
|
31
|
+
.replace(/\+/g, '-')
|
|
32
|
+
.replace(/\//g, '_')
|
|
33
|
+
.replace(/=+$/, '');
|
|
34
|
+
|
|
35
|
+
const result = await gmail.users.messages.send({
|
|
36
|
+
userId: 'me',
|
|
37
|
+
requestBody: {
|
|
38
|
+
raw: encodedMessage,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
success: true,
|
|
44
|
+
provider: 'gmail',
|
|
45
|
+
service: 'API',
|
|
46
|
+
messageId: result.data.id || undefined,
|
|
47
|
+
timestamp: new Date(),
|
|
48
|
+
};
|
|
49
|
+
} catch (error) {
|
|
50
|
+
return {
|
|
51
|
+
success: false,
|
|
52
|
+
provider: 'gmail',
|
|
53
|
+
service: 'API',
|
|
54
|
+
error: error.message,
|
|
55
|
+
timestamp: new Date(),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
validateConfig(config: any): boolean {
|
|
61
|
+
return !!(
|
|
62
|
+
config.clientId &&
|
|
63
|
+
config.clientSecret &&
|
|
64
|
+
config.refreshToken &&
|
|
65
|
+
config.email
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
}
|