rez_core 5.0.207 → 5.0.208

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": "5.0.207",
3
+ "version": "5.0.208",
4
4
  "description": "",
5
5
  "author": "",
6
6
  "private": false,
@@ -111,9 +111,8 @@ export class ResolverService {
111
111
  attr.element_type === 'date' ||
112
112
  attr.element_type === 'datetime'
113
113
  ) {
114
- // 👇 Explicitly define input format to avoid deprecation warning
115
- const dateValue = moment(codeValue, "DD-MM-YYYY", true).utcOffset('+05:30');
116
-
114
+ const dateFormat = attr.element_type === 'date' ? "DD-MM-YYYY" : "DD-MM-YYYY HH:mm:ss";
115
+ const dateValue = moment(codeValue,dateFormat).utcOffset('+05:30'); // IST
117
116
  if (dateValue.isValid()) {
118
117
  resolvedEntityData[field] =
119
118
  attr.element_type === 'date'
@@ -159,75 +158,88 @@ export class ResolverService {
159
158
  attrKey,
160
159
  loggedInUser.enterprise_id,
161
160
  );
162
- if (!attr) return rawValue;
163
161
 
164
- // -------- ENTITY data_source_type --------
162
+ if (!attr) return rawValue;
163
+ // ----------- ENTITY TYPE RESOLUTION -------------------
165
164
  if (attr.data_source_type === 'entity') {
166
165
  const entityDef = await this.entityMasterRepo.getEntityByMappedEntityType(
167
166
  attr.datasource_list,
168
167
  loggedInUser.enterprise_id,
169
168
  );
170
-
171
169
  if (!entityDef) return rawValue;
172
170
 
173
171
  const tableName = entityDef.db_table_name;
174
172
 
173
+ // --- If array (multi-select) ---
175
174
  if (Array.isArray(rawValue)) {
176
175
  const resolvedValues: string[] = [];
176
+
177
177
  for (const value of rawValue) {
178
178
  const query =
179
179
  tableName === 'sso_organization'
180
- ? `SELECT *
181
- FROM ${tableName}
182
- WHERE code = $1`
183
- : `SELECT *
184
- FROM ${tableName}
185
- WHERE id = $1`;
186
- const params = tableName === 'sso_organization' ? [value] : [value];
187
-
188
- const [item] = await this.entityManger.query(query, params);
180
+ ? `SELECT * FROM ${tableName} WHERE code = $1`
181
+ : `SELECT * FROM ${tableName} WHERE id = $1`;
182
+
183
+ const [item] = await this.entityManger.query(query, [value]);
189
184
  resolvedValues.push(item?.[attr.data_source_attribute] ?? value);
190
185
  }
191
- return resolvedValues;
192
- } else {
193
- const query = `SELECT *
194
- FROM ${tableName}
195
- WHERE id = $1`;
196
- const params = [rawValue];
197
186
 
198
- const [item] = await this.entityManger.query(query, params);
199
- return item?.[attr.data_source_attribute] ?? rawValue;
187
+ return resolvedValues;
200
188
  }
189
+
190
+ // --- Single value ---
191
+ const query = `SELECT * FROM ${tableName} WHERE id = $1`;
192
+ const [item] = await this.entityManger.query(query, [rawValue]);
193
+
194
+ return item?.[attr.data_source_attribute] ?? rawValue;
201
195
  }
202
196
 
203
- // -------- MASTER data_source_type --------
204
- else if (attr.data_source_type === 'master') {
197
+ // ----------- MASTER TYPE RESOLUTION -------------------
198
+ if (attr.data_source_type === 'master') {
205
199
  const repo = this.reflectionHelper.getRepoService('ListMasterItems');
206
- if (Array.isArray(rawValue)) {
200
+
201
+ let value = rawValue;
202
+
203
+ // 🟦 If rawValue is a JSON string representing array → parse it
204
+ if (typeof rawValue === 'string') {
205
+ try {
206
+ const parsed = JSON.parse(rawValue);
207
+ if (Array.isArray(parsed)) value = parsed;
208
+ } catch (e) {
209
+ // keep as string
210
+ }
211
+ }
212
+
213
+ // 🟩 If value is array → resolve each
214
+ if (Array.isArray(value)) {
207
215
  const resolvedValues: string[] = [];
208
- for (const code of rawValue) {
209
- let item = repo.findOne({
210
- where: {
211
- id: code,
212
- },
216
+
217
+ for (const id of value) {
218
+ const item = await repo.findOne({
219
+ where: { id: Number(id) },
213
220
  });
214
- resolvedValues.push(item?.[attr.data_source_attribute] ?? code);
221
+ resolvedValues.push(item?.[attr.data_source_attribute] ?? id);
215
222
  }
223
+
216
224
  return resolvedValues;
217
- } else {
218
- if (typeof rawValue !== 'number') return rawValue;
219
- let item = await repo.findOne({
220
- where: {
221
- id: Number(rawValue),
222
- },
225
+ }
226
+
227
+ // 🟨 Single value (must be number)
228
+ if (!isNaN(rawValue)) {
229
+ const item = await repo.findOne({
230
+ where: { id: Number(rawValue) },
223
231
  });
232
+
224
233
  return item?.[attr.data_source_attribute] ?? rawValue;
225
234
  }
235
+
236
+ return rawValue;
226
237
  }
227
238
 
228
239
  return rawValue;
229
240
  }
230
241
 
242
+
231
243
  async getResolvedId(
232
244
  loggedInUser: UserData,
233
245
  attrKey: string,
@@ -17,6 +17,7 @@ import { NotificationsController } from './controller/notification.controller';
17
17
  import { NotificationsService } from './service/notification.service';
18
18
  import { EntityModule } from '../meta/entity.module';
19
19
  import { FirebaseAdminProvider } from './firebase-admin.config';
20
+ import { NotificationRepository } from './repository/notification.repository';
20
21
 
21
22
  @Module({
22
23
  imports: [
@@ -57,6 +58,7 @@ import { FirebaseAdminProvider } from './firebase-admin.config';
57
58
  EmailService,
58
59
  NotificationsService,
59
60
  FirebaseAdminProvider,
61
+ NotificationRepository,
60
62
  ],
61
63
  exports: [
62
64
  OtpService,
@@ -0,0 +1,33 @@
1
+ import { Injectable } from '@nestjs/common';
2
+ import { InjectRepository } from '@nestjs/typeorm';
3
+ import { Repository, EntityManager } from 'typeorm';
4
+ import { NotificationData } from '../entity/notification.entity';
5
+
6
+ @Injectable()
7
+ export class NotificationRepository {
8
+ constructor(
9
+ @InjectRepository(NotificationData)
10
+ private readonly notificationRepo: Repository<NotificationData>,
11
+ ) {}
12
+
13
+ async getAllNotifications(
14
+ userId: number,
15
+ levelId: number,
16
+ levelType: string,
17
+ isReadFilter?,
18
+ ) {
19
+ const qb = this.notificationRepo
20
+ .createQueryBuilder('n')
21
+ .where('n.user_id = :userId', { userId })
22
+ .andWhere('n.level_id = :levelId', { levelId })
23
+ .andWhere('n.level_type = :levelType', { levelType });
24
+
25
+ if (isReadFilter !== undefined) {
26
+ qb.andWhere('n.is_read = :isRead', { isRead: isReadFilter });
27
+ }
28
+
29
+ qb.orderBy('n.created_date', 'DESC');
30
+
31
+ return await qb.getMany();
32
+ }
33
+ }
@@ -5,6 +5,7 @@ import * as admin from 'firebase-admin';
5
5
  import axios from 'axios';
6
6
  import { ConfigService } from '@nestjs/config';
7
7
  import { ReflectionHelper } from 'src/utils/service/reflection-helper.service';
8
+ import { NotificationRepository } from '../repository/notification.repository';
8
9
 
9
10
  @Injectable()
10
11
  export class NotificationsService {
@@ -14,6 +15,7 @@ export class NotificationsService {
14
15
  private readonly configService: ConfigService,
15
16
  private readonly reflectionHelper: ReflectionHelper,
16
17
  @Inject('FIREBASE_ADMIN') private readonly firebaseAdmin: typeof admin,
18
+ private readonly notificationRepository: NotificationRepository,
17
19
  ) {}
18
20
 
19
21
  private tokens: Map<string, string> = new Map(); // store in memory for now
@@ -69,73 +71,53 @@ export class NotificationsService {
69
71
  loggedInUser: any,
70
72
  filterQuery?: { is_read?: string },
71
73
  ) {
72
- const { id, level_id, level_type } = loggedInUser;
73
-
74
- //
75
- // Convert "true"/"false" → "1"/"0" as strings
76
- //
77
- let isReadFilter: string | undefined = undefined;
78
- if (filterQuery && filterQuery.is_read !== undefined) {
79
- const isRead = String(filterQuery.is_read).toLowerCase() === 'true';
80
- isReadFilter = isRead ? '1' : '0'; // <-- always string
81
- }
82
-
83
- //
84
- // Build base SQL
85
- //
86
- let paramIndex = 1;
87
- let sql = `
88
- SELECT n.*
89
- FROM frm_notification n
90
- WHERE n.user_id = $${paramIndex}
91
- AND n.level_id = $${paramIndex + 1}
92
- AND n.level_type = $${paramIndex + 2}
93
- `;
94
-
95
- const params: string[] = [String(id), String(level_id), String(level_type)];
96
- paramIndex += 3;
97
-
98
- //
99
- // Apply optional filter
100
- //
101
- if (isReadFilter !== undefined) {
102
- sql += ` AND n.is_read = $${paramIndex}`;
103
- params.push(String(isReadFilter));
104
- paramIndex++;
105
- }
106
-
107
- sql += ` ORDER BY n.created_date DESC`;
74
+ const { id: userId, level_id, level_type } = loggedInUser;
75
+
76
+ // Fetch notifications from repository
77
+ const notifications: any =
78
+ await this.notificationRepository.getAllNotifications(
79
+ userId,
80
+ level_id,
81
+ level_type,
82
+ filterQuery?.is_read,
83
+ );
108
84
 
109
85
  //
110
- // Execute query
86
+ // Avoid duplicate API calls for each user_id
111
87
  //
112
- const notifications = await this.entityManager.query(sql, params);
88
+ const mediaCache = new Map<
89
+ number,
90
+ { name: string; profile_image: string }
91
+ >();
113
92
 
114
- //
115
- // Enrich profile image + user name
116
- //
117
- const mediaCache = new Map();
93
+ const baseUrl = this.configService.get<string>('REDIRECT_BE_URL');
118
94
 
119
95
  for (const notification of notifications) {
120
- notification.is_read =
121
- notification.is_read === 1 || notification.is_read === '1';
122
-
123
- try {
124
- const baseUrl = this.configService.get<string>('REDIRECT_BE_URL');
125
- const queryParams = new URLSearchParams({
126
- loggedInUser: JSON.stringify(loggedInUser),
127
- }).toString();
128
-
129
- const response = await axios.get(
130
- `${baseUrl}/users/profile-image-url/${notification.user_id}?entity_type=USR&${queryParams}`,
131
- { headers: { 'Content-Type': 'application/json' } },
132
- );
133
-
134
- notification.user_name = response.data.name;
135
- notification.user_profile = response.data.profile_image;
136
- } catch (error) {
137
- console.error('⚠️ Internal Entity API call failed:', error.message);
96
+ const uid = notification?.user_id;
97
+
98
+ if (uid && !mediaCache.has(uid)) {
99
+ try {
100
+ const queryParams = new URLSearchParams({
101
+ loggedInUser: JSON.stringify(loggedInUser),
102
+ }).toString();
103
+
104
+ const response = await axios.get(
105
+ `${baseUrl}/users/profile-image-url/${uid}?entity_type=USR&${queryParams}`,
106
+ { headers: { 'Content-Type': 'application/json' } },
107
+ );
108
+
109
+ mediaCache.set(uid, {
110
+ name: response.data.name,
111
+ profile_image: response.data.profile_image,
112
+ });
113
+ } catch (err) {
114
+ console.error('⚠️ Internal Entity API call failed:', err.message);
115
+ }
138
116
  }
117
+
118
+ const cachedData = mediaCache.get(uid);
119
+ notification.user_name = cachedData?.name;
120
+ notification.user_profile = cachedData?.profile_image;
139
121
  }
140
122
 
141
123
  return notifications;