rez_core 2.2.201 → 2.2.203

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rez_core",
3
- "version": "2.2.201",
3
+ "version": "2.2.203",
4
4
  "description": "",
5
5
  "author": "",
6
6
  "private": false,
@@ -128,6 +128,7 @@ export class WrapperService {
128
128
 
129
129
  /**
130
130
  * Wrapper for scheduling meeting in Google Calendar
131
+ * or fallback to sending ICS as email attachment
131
132
  */
132
133
  async scheduleMeetingWrapper(payload: any, loggedInUser: any) {
133
134
  try {
@@ -137,61 +138,121 @@ export class WrapperService {
137
138
 
138
139
  const { level_id, level_type } = loggedInUser;
139
140
 
140
- // 1. Check for config at user’s level
141
- const configs = await this.datasource.query(
141
+ // 1. Try user-level config
142
+ const userConfigs = await this.datasource.query(
142
143
  `SELECT *
143
- FROM cr_communication_hub
144
- WHERE level_id = ?
145
- AND level_type = ?
146
- AND communication_config_type = 'EMAIL' AND provider = 'gmail' AND service = 'API'`,
144
+ FROM cr_communication_hub
145
+ WHERE level_id = ?
146
+ AND level_type = ?
147
+ AND communication_config_type = 'EMAIL'
148
+ AND service = 'API'`,
147
149
  [level_id, level_type],
148
150
  );
149
151
 
150
- let configCred;
151
- let result;
152
+ if (userConfigs && userConfigs.length > 0) {
153
+ const provider = userConfigs[0]?.provider;
154
+ const configId = userConfigs[0]?.config_id;
152
155
 
153
- if (configs && configs.length > 0) {
154
- // only if type is gmail
155
- configCred = await this.datasource.query(
156
- `SELECT config_json
157
- FROM cr_communication_config
158
- WHERE id = ?`,
159
- [configs[0].config_id],
156
+ if (provider === 'gmail') {
157
+ // Gmail Use Google Calendar
158
+ const creds = await this.getConfigCred(configId);
159
+ if (creds) {
160
+ const result = await this.googleService.createEvent(creds, payload);
161
+ return { success: true, data: result };
162
+ }
163
+ }
164
+
165
+ // Non-Gmail provider → Use ICS over email
166
+ const result = await this.sendIcsFallback(
167
+ payload,
168
+ level_id,
169
+ level_type,
160
170
  );
171
+ return { success: true, data: result };
172
+ }
173
+
174
+ // 2. Fallback to ORG-level config
175
+ const orgConfigs = await this.datasource.query(
176
+ `SELECT *
177
+ FROM cr_communication_hub
178
+ WHERE level_type = 'ORG'
179
+ AND level_id = 1
180
+ AND communication_config_type = 'EMAIL'
181
+ AND service = 'API'`,
182
+ );
161
183
 
162
- if (!configCred || configCred.length === 0) {
163
- throw new Error('No Google credentials found for user-level config');
184
+ if (orgConfigs && orgConfigs.length > 0) {
185
+ const provider = orgConfigs[0].provider;
186
+ const configId = orgConfigs[0].config_id;
187
+
188
+ if (provider === 'gmail') {
189
+ // ORG Gmail → Google Calendar
190
+ const creds = await this.getConfigCred(configId);
191
+ if (creds) {
192
+ const result = await this.googleService.createEvent(creds, payload);
193
+ return { success: true, data: result };
194
+ }
164
195
  }
165
196
 
166
- configCred = configCred[0].config_json;
167
- // 3. Call google service
168
- result = await this.googleService.createEvent(configCred, payload);
169
- } else {
170
- const base64String = await this.icsService.generateIcs(payload);
171
-
172
- result = await this.communicationService.sendGenericMessage({
173
- ...payload,
174
- attachments: [
175
- {
176
- content: base64String,
177
- type: 'text/calendar',
178
- filename: 'invite.ics',
179
- disposition: 'attachment',
180
- },
181
- ],
182
- });
197
+ // ORG Non-Gmail → ICS via email
198
+ const result = await this.sendIcsFallback(payload, 1, 'ORG');
199
+ return { success: true, data: result };
183
200
  }
184
201
 
185
- return {
186
- success: true,
187
- data: result,
188
- };
202
+ // 3. Absolute fallback → Default ORG with ICS
203
+ const result = await this.sendIcsFallback(payload, 1, 'ORG');
204
+ return { success: true, data: result };
189
205
  } catch (error: any) {
190
206
  this.logger.error('scheduleMeetingWrapper error', error.message);
191
- return {
192
- success: false,
193
- error: error.message,
194
- };
207
+ return { success: false, error: error.message };
195
208
  }
196
209
  }
210
+
211
+ /**
212
+ * Fetch credentials JSON by config ID
213
+ */
214
+ private async getConfigCred(configId: number) {
215
+ const configRes = await this.datasource.query(
216
+ `SELECT config_json
217
+ FROM cr_communication_config
218
+ WHERE id = ?`,
219
+ [configId],
220
+ );
221
+ return configRes?.[0]?.config_json || null;
222
+ }
223
+
224
+ /**
225
+ * Send ICS fallback via email
226
+ */
227
+ private async sendIcsFallback(
228
+ payload: any,
229
+ levelId: number,
230
+ levelType: string,
231
+ ) {
232
+ const base64String = await this.icsService.generateIcs(payload);
233
+
234
+ const payloadSendMail: GenericMessageDto = {
235
+ levelId,
236
+ levelType,
237
+ to: payload.to,
238
+ message: payload.message,
239
+ subject: payload.subject,
240
+ type: 'EMAIL',
241
+ cc: payload.cc,
242
+ bcc: payload.bcc,
243
+ html: payload.html,
244
+ attachments: [
245
+ {
246
+ content: base64String,
247
+ type: 'text/calendar',
248
+ filename: 'invite.ics',
249
+ disposition: 'attachment',
250
+ },
251
+ ],
252
+ templateId: payload.templateId,
253
+ variables: payload.variables,
254
+ };
255
+
256
+ return this.communicationService.sendGenericMessage(payloadSendMail);
257
+ }
197
258
  }
@@ -66,7 +66,7 @@ export class GmailStrategy implements CommunicationStrategy {
66
66
  `Subject: ${subject}`,
67
67
  'Content-Type: text/html; charset=utf-8',
68
68
  '',
69
- config.html || message,
69
+ message || config.html,
70
70
  ].join('\n');
71
71
 
72
72
  const encodedMessage = Buffer.from(emailContent)
@@ -240,91 +240,7 @@ export class MasterService {
240
240
  throw new Error(`No unique fields found for entityType: ${entityType}`);
241
241
  }
242
242
 
243
- // for (const row of sheetData) {
244
-
245
- // if (row.parent_type && row.parent_id) {
246
- // await this.resolveParent(row);
247
- // }
248
-
249
- // for (const attr of attributes) {
250
- // console.log('inside for loop attr');
251
- // if (attr.data_source_type === 'entity' && row[attr.attribute_key]) {
252
- // console.log('inside if condition');
253
-
254
- // const refEntity = await this.entityMasterService.getEntityData(
255
- // attr.datasource_list,
256
- // loggedInUser,
257
- // );
258
- // const refData = await this.entityManager.query(
259
- // `SELECT * FROM ${refEntity.db_table_name} WHERE code = ? LIMIT 1`,
260
- // [row[attr.attribute_key]],
261
- // );
262
-
263
- // //you will check the org id of refData and loggedInUser.organization_id
264
-
265
- // if (!refData.length) {
266
- // throw new Error(
267
- // `Reference entity not found for code: ${row[attr.attribute_key]}`,
268
- // );
269
- // }
270
-
271
- // row[attr.attribute_key] = refData[0].id;
272
- // }
273
- // }
274
- // }
275
-
276
- // const errors: any[] = [];
277
-
278
- // for (let i = 0; i < sheetData.length; i++) {
279
- // const row = sheetData[i];
280
-
281
- // if (row.parent_type && row.parent_id) {
282
- // await this.resolveParent(row);
283
- // }
284
-
285
- // for (const attr of attributes) {
286
- // if (attr.data_source_type === 'entity' && row[attr.attribute_key]) {
287
- // const refEntity = await this.entityMasterService.getEntityData(
288
- // attr.datasource_list,
289
- // loggedInUser,
290
- // );
291
- // const refData = await this.entityManager.query(
292
- // `SELECT * FROM ${refEntity.db_table_name} WHERE code = ? LIMIT 1`,
293
- // [row[attr.attribute_key]],
294
- // );
295
- // if (!refData.length) {
296
- // throw new Error(
297
- // `Reference entity not found for code: ${row[attr.attribute_key]}`,
298
- // );
299
- // }
300
- // row[attr.attribute_key] = refData[0].id;
301
- // }
302
- // }
303
-
304
- // const rowErrors = await this.entityValidationService.validateEntityData(
305
- // row,
306
- // entityMaster,
307
- // loggedInUser,
308
- // );
309
-
310
- // if (rowErrors && rowErrors.length > 0) {
311
- // errors.push({
312
- // row: i + 1,
313
- // errors: rowErrors,
314
- // });
315
- // }
316
- // }
317
-
318
- // await this.upsertViaService(
319
- // entityType,
320
- // sheetData,
321
- // attributes,
322
- // uniqueFields,
323
- // loggedInUser,
324
- // duplicateHandling,
325
- // );
326
-
327
- // return { message: 'Entity data uploaded successfully' };
243
+
328
244
  const errors: any[] = [];
329
245
 
330
246
  // ✅ Iterate row by row
@@ -362,6 +278,29 @@ export class MasterService {
362
278
  }
363
279
  }
364
280
 
281
+
282
+ for (const attr of attributes) {
283
+ if (attr.data_source_type === 'master' && row[attr.attribute_key]) {
284
+ const refData = await this.entityManager.query(
285
+ `SELECT * FROM cr_list_master_items WHERE name = ? and organization_id = ? LIMIT 1`,
286
+ [row[attr.attribute_key], loggedInUser.organization_id],
287
+ );
288
+
289
+ if (!refData.length) {
290
+ errors.push({
291
+ row: i + 1,
292
+ errors: [
293
+ `Reference master data not found for name: ${row[attr.attribute_key]}`,
294
+ ],
295
+ });
296
+ continue; // skip further processing for this row
297
+ }
298
+
299
+ // replace with reference id
300
+ row[attr.attribute_key] = refData[0].id;
301
+ }
302
+ }
303
+
365
304
  // ✅ validate single row
366
305
  const rowErrors = await this.entityValidationService.validateImportData(
367
306
  row,
@@ -68,7 +68,6 @@ export class OtpController {
68
68
  const browser = parser.getBrowser().name || 'Unknown';
69
69
  const os = parser.getOS().name || 'Unknown';
70
70
 
71
- console.log('data', userAgent, parser, browser, os);
72
71
  return await this.otpService.verifyOtp({
73
72
  ...data,
74
73
  ip,
@@ -16,6 +16,7 @@ import { Request, Response } from 'express';
16
16
  import { UserSessionService } from '../service/user-session.service';
17
17
  import { ConfigService } from '@nestjs/config';
18
18
  import { CommunicationService } from '../../communication/service/communication.service';
19
+ import { UAParser } from 'ua-parser-js';
19
20
 
20
21
  @Controller('auth')
21
22
  export class LoginController {
@@ -77,7 +78,6 @@ export class LoginController {
77
78
  async googleAuthRedirect(@Req() req: any, @Res() res: Response) {
78
79
  const {
79
80
  email,
80
- password,
81
81
  name,
82
82
  accessToken: googleAccessToken,
83
83
  refreshToken: googleRefreshToken,
@@ -86,6 +86,15 @@ export class LoginController {
86
86
  } = req.user;
87
87
  const { state } = req.query;
88
88
 
89
+ const ip =
90
+ (req.headers['x-forwarded-for'] as string)?.split(',')[0].trim() ||
91
+ req.socket.remoteAddress;
92
+
93
+ const userAgent = req.headers['user-agent'] || '';
94
+ const parser = new UAParser(userAgent);
95
+ const browser = parser.getBrowser().name || 'Unknown';
96
+ const os = parser.getOS().name || 'Unknown';
97
+
89
98
  // Check if this is a Gmail configuration request
90
99
  if (
91
100
  state &&
@@ -114,10 +123,11 @@ export class LoginController {
114
123
  // Original login flow
115
124
  const data = await this.loginService.loginWithGoogle({
116
125
  email,
117
- password,
118
- name,
119
126
  subdomain,
120
127
  fcm_token,
128
+ ip,
129
+ browser,
130
+ os,
121
131
  });
122
132
 
123
133
  if (!('accessToken' in data) || !data.accessToken)
@@ -41,8 +41,8 @@ export class LoginService {
41
41
  async login(data: {
42
42
  email: string;
43
43
  password?: string;
44
- subdomain: string;
45
- fcm_token: string;
44
+ subdomain?: string;
45
+ fcm_token?: string;
46
46
  is_otp?: boolean;
47
47
  browser?: string;
48
48
  ip?: string;
@@ -282,12 +282,13 @@ export class LoginService {
282
282
 
283
283
  async loginWithGoogle(data: {
284
284
  email: string;
285
- password: string;
286
- name;
287
- subdomain: string;
288
- fcm_token: string;
285
+ subdomain?: string;
286
+ fcm_token?: string;
287
+ ip?: string;
288
+ browser?: string;
289
+ os?: string;
289
290
  }) {
290
- const { email, password, name, subdomain, fcm_token } = data;
291
+ const { email, subdomain, fcm_token, ip, browser, os } = data;
291
292
  const user = await this.userService.findByEmailId(email);
292
293
 
293
294
  if (!user) {
@@ -311,7 +312,14 @@ export class LoginService {
311
312
  }
312
313
 
313
314
  // Create session (Same as JWT login flow)
314
- return await this.login(data);
315
+ return await this.login({
316
+ email,
317
+ subdomain,
318
+ fcm_token,
319
+ ip,
320
+ browser,
321
+ os,
322
+ });
315
323
  }
316
324
 
317
325
  async logout(sessionKey: string) {