rez_core 5.0.207 → 5.0.209
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module/enterprise/repository/school.repository.js +8 -8
- package/dist/module/enterprise/repository/school.repository.js.map +1 -1
- package/dist/module/meta/service/resolver.service.js +28 -32
- package/dist/module/meta/service/resolver.service.js.map +1 -1
- package/dist/module/notification/notification.module.js +2 -0
- package/dist/module/notification/notification.module.js.map +1 -1
- package/dist/module/notification/repository/notification.repository.d.ts +7 -0
- package/dist/module/notification/repository/notification.repository.js +43 -0
- package/dist/module/notification/repository/notification.repository.js.map +1 -0
- package/dist/module/notification/service/notification.service.d.ts +3 -1
- package/dist/module/notification/service/notification.service.js +25 -38
- package/dist/module/notification/service/notification.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/module/enterprise/repository/school.repository.ts +33 -16
- package/src/module/meta/service/resolver.service.ts +50 -38
- package/src/module/notification/notification.module.ts +2 -0
- package/src/module/notification/repository/notification.repository.ts +33 -0
- package/src/module/notification/service/notification.service.ts +42 -60
package/package.json
CHANGED
|
@@ -4,8 +4,7 @@ import { ReflectionHelper } from '../../../utils/service/reflection-helper.servi
|
|
|
4
4
|
|
|
5
5
|
@Injectable()
|
|
6
6
|
export class SchoolRepository {
|
|
7
|
-
constructor(private readonly reflectionHelper: ReflectionHelper) {
|
|
8
|
-
}
|
|
7
|
+
constructor(private readonly reflectionHelper: ReflectionHelper) {}
|
|
9
8
|
|
|
10
9
|
async findAllByOrgId(orgId: number): Promise<any[]> {
|
|
11
10
|
const schoolRepo = this.reflectionHelper.getRepoService('SSOSchool');
|
|
@@ -26,11 +25,12 @@ export class SchoolRepository {
|
|
|
26
25
|
}
|
|
27
26
|
|
|
28
27
|
async getUserContextDropdown(userId: number, appCode: string, org_id) {
|
|
29
|
-
const userRoleRepo =
|
|
28
|
+
const userRoleRepo =
|
|
29
|
+
this.reflectionHelper.getRepoService('UserRoleMapping');
|
|
30
30
|
|
|
31
31
|
const hasOrgAccess = await userRoleRepo
|
|
32
32
|
.createQueryBuilder('urm')
|
|
33
|
-
.where('urm.user_id = :userId', { userId })
|
|
33
|
+
.where('urm.user_id::text = :userId', { userId: String(userId) })
|
|
34
34
|
.andWhere('urm.appcode = :appCode', { appCode })
|
|
35
35
|
.andWhere('urm.level_type = :levelType', { levelType: 'ORG' })
|
|
36
36
|
.getRawMany();
|
|
@@ -40,7 +40,8 @@ export class SchoolRepository {
|
|
|
40
40
|
currentORGLevel_id = org_id;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
const listMasterItemsRepo =
|
|
43
|
+
const listMasterItemsRepo =
|
|
44
|
+
this.reflectionHelper.getRepoService('ListMasterItems');
|
|
44
45
|
const resolvedInactiveStatus = await listMasterItemsRepo.findOne({
|
|
45
46
|
where: {
|
|
46
47
|
code: STATUS_INACTIVE,
|
|
@@ -49,7 +50,8 @@ export class SchoolRepository {
|
|
|
49
50
|
});
|
|
50
51
|
|
|
51
52
|
if (hasOrgAccess.length > 0) {
|
|
52
|
-
const organizationRepo =
|
|
53
|
+
const organizationRepo =
|
|
54
|
+
this.reflectionHelper.getRepoService('OrganizationData');
|
|
53
55
|
|
|
54
56
|
const schools = await organizationRepo
|
|
55
57
|
.createQueryBuilder('org')
|
|
@@ -72,7 +74,7 @@ export class SchoolRepository {
|
|
|
72
74
|
.innerJoin(
|
|
73
75
|
'sso_organization',
|
|
74
76
|
'brn',
|
|
75
|
-
|
|
77
|
+
"brn.type = 'BRN' AND brn.parent_id::varchar = org.id::varchar",
|
|
76
78
|
)
|
|
77
79
|
// JOIN school table
|
|
78
80
|
.innerJoin(
|
|
@@ -161,7 +163,6 @@ export class SchoolRepository {
|
|
|
161
163
|
brands: Object.values(org.brands),
|
|
162
164
|
}));
|
|
163
165
|
} else {
|
|
164
|
-
|
|
165
166
|
const orgResult = await organizationRepo.findOne({
|
|
166
167
|
where: {
|
|
167
168
|
id: currentORGLevel_id,
|
|
@@ -180,8 +181,8 @@ export class SchoolRepository {
|
|
|
180
181
|
];
|
|
181
182
|
}
|
|
182
183
|
} else {
|
|
183
|
-
|
|
184
|
-
|
|
184
|
+
const userRoleMappingRepo =
|
|
185
|
+
this.reflectionHelper.getRepoService('UserRoleMapping');
|
|
185
186
|
|
|
186
187
|
const brnMappings = await userRoleMappingRepo
|
|
187
188
|
.createQueryBuilder('urm')
|
|
@@ -195,9 +196,17 @@ export class SchoolRepository {
|
|
|
195
196
|
'school.location AS school_location',
|
|
196
197
|
'school.status AS school_status',
|
|
197
198
|
])
|
|
198
|
-
.innerJoin(
|
|
199
|
-
|
|
200
|
-
|
|
199
|
+
.innerJoin(
|
|
200
|
+
'sso_organization',
|
|
201
|
+
'brand',
|
|
202
|
+
'brand.id::text = urm.level_id::text',
|
|
203
|
+
)
|
|
204
|
+
.innerJoin(
|
|
205
|
+
'sso_school',
|
|
206
|
+
'school',
|
|
207
|
+
'school.brand_id::text = brand.id::text',
|
|
208
|
+
)
|
|
209
|
+
.where('urm.user_id::text = :userId', { userId: String(userId) })
|
|
201
210
|
.andWhere('urm.appcode = :appCode', { appCode })
|
|
202
211
|
.andWhere('urm.level_type = :levelType', { levelType: 'BRN' })
|
|
203
212
|
.distinct(true)
|
|
@@ -215,9 +224,17 @@ export class SchoolRepository {
|
|
|
215
224
|
'school.location AS school_location',
|
|
216
225
|
'school.status AS school_status',
|
|
217
226
|
])
|
|
218
|
-
.innerJoin(
|
|
219
|
-
|
|
220
|
-
|
|
227
|
+
.innerJoin(
|
|
228
|
+
'sso_school',
|
|
229
|
+
'school',
|
|
230
|
+
'school.id::text = urm.level_id::text',
|
|
231
|
+
)
|
|
232
|
+
.innerJoin(
|
|
233
|
+
'sso_organization',
|
|
234
|
+
'brand',
|
|
235
|
+
'brand.id::text = school.brand_id::text',
|
|
236
|
+
)
|
|
237
|
+
.where('urm.user_id::text = :userId', { userId: String(userId) })
|
|
221
238
|
.andWhere('urm.appcode = :appCode', { appCode })
|
|
222
239
|
.andWhere('urm.level_type = :levelType', { levelType: 'SCH' })
|
|
223
240
|
.distinct(true)
|
|
@@ -111,9 +111,9 @@ export class ResolverService {
|
|
|
111
111
|
attr.element_type === 'date' ||
|
|
112
112
|
attr.element_type === 'datetime'
|
|
113
113
|
) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
const dateFormat =
|
|
115
|
+
attr.element_type === 'date' ? 'DD-MM-YYYY' : 'DD-MM-YYYY HH:mm:ss';
|
|
116
|
+
const dateValue = moment(codeValue, dateFormat).utcOffset('+05:30'); // IST
|
|
117
117
|
if (dateValue.isValid()) {
|
|
118
118
|
resolvedEntityData[field] =
|
|
119
119
|
attr.element_type === 'date'
|
|
@@ -159,70 +159,82 @@ export class ResolverService {
|
|
|
159
159
|
attrKey,
|
|
160
160
|
loggedInUser.enterprise_id,
|
|
161
161
|
);
|
|
162
|
-
if (!attr) return rawValue;
|
|
163
162
|
|
|
164
|
-
|
|
163
|
+
if (!attr) return rawValue;
|
|
164
|
+
// ----------- ENTITY TYPE RESOLUTION -------------------
|
|
165
165
|
if (attr.data_source_type === 'entity') {
|
|
166
166
|
const entityDef = await this.entityMasterRepo.getEntityByMappedEntityType(
|
|
167
167
|
attr.datasource_list,
|
|
168
168
|
loggedInUser.enterprise_id,
|
|
169
169
|
);
|
|
170
|
-
|
|
171
170
|
if (!entityDef) return rawValue;
|
|
172
171
|
|
|
173
172
|
const tableName = entityDef.db_table_name;
|
|
174
173
|
|
|
174
|
+
// --- If array (multi-select) ---
|
|
175
175
|
if (Array.isArray(rawValue)) {
|
|
176
176
|
const resolvedValues: string[] = [];
|
|
177
|
+
|
|
177
178
|
for (const value of rawValue) {
|
|
178
179
|
const query =
|
|
179
180
|
tableName === 'sso_organization'
|
|
180
|
-
? `SELECT *
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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);
|
|
181
|
+
? `SELECT * FROM ${tableName} WHERE code = $1`
|
|
182
|
+
: `SELECT * FROM ${tableName} WHERE id = $1`;
|
|
183
|
+
|
|
184
|
+
const [item] = await this.entityManger.query(query, [value]);
|
|
189
185
|
resolvedValues.push(item?.[attr.data_source_attribute] ?? value);
|
|
190
186
|
}
|
|
191
|
-
return resolvedValues;
|
|
192
|
-
} else {
|
|
193
|
-
const query = `SELECT *
|
|
194
|
-
FROM ${tableName}
|
|
195
|
-
WHERE id = $1`;
|
|
196
|
-
const params = [rawValue];
|
|
197
187
|
|
|
198
|
-
|
|
199
|
-
return item?.[attr.data_source_attribute] ?? rawValue;
|
|
188
|
+
return resolvedValues;
|
|
200
189
|
}
|
|
190
|
+
|
|
191
|
+
// --- Single value ---
|
|
192
|
+
const query = `SELECT * FROM ${tableName} WHERE id = $1`;
|
|
193
|
+
const [item] = await this.entityManger.query(query, [rawValue]);
|
|
194
|
+
|
|
195
|
+
return item?.[attr.data_source_attribute] ?? rawValue;
|
|
201
196
|
}
|
|
202
197
|
|
|
203
|
-
//
|
|
204
|
-
|
|
198
|
+
// ----------- MASTER TYPE RESOLUTION -------------------
|
|
199
|
+
if (attr.data_source_type === 'master') {
|
|
205
200
|
const repo = this.reflectionHelper.getRepoService('ListMasterItems');
|
|
206
|
-
|
|
201
|
+
|
|
202
|
+
let value = rawValue;
|
|
203
|
+
|
|
204
|
+
// 🟦 If rawValue is a JSON string representing array → parse it
|
|
205
|
+
if (typeof rawValue === 'string') {
|
|
206
|
+
try {
|
|
207
|
+
const parsed = JSON.parse(rawValue);
|
|
208
|
+
if (Array.isArray(parsed)) value = parsed;
|
|
209
|
+
} catch (e) {
|
|
210
|
+
// keep as string
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// 🟩 If value is array → resolve each
|
|
215
|
+
if (Array.isArray(value)) {
|
|
207
216
|
const resolvedValues: string[] = [];
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
},
|
|
217
|
+
|
|
218
|
+
for (const id of value) {
|
|
219
|
+
const item = await repo.findOne({
|
|
220
|
+
where: { id: Number(id) },
|
|
213
221
|
});
|
|
214
|
-
resolvedValues.push(item?.[attr.data_source_attribute] ??
|
|
222
|
+
resolvedValues.push(item?.[attr.data_source_attribute] ?? id);
|
|
215
223
|
}
|
|
224
|
+
|
|
216
225
|
return resolvedValues;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
},
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// 🟨 Single value (must be number)
|
|
229
|
+
if (!isNaN(rawValue)) {
|
|
230
|
+
const item = await repo.findOne({
|
|
231
|
+
where: { id: Number(rawValue) },
|
|
223
232
|
});
|
|
233
|
+
|
|
224
234
|
return item?.[attr.data_source_attribute] ?? rawValue;
|
|
225
235
|
}
|
|
236
|
+
|
|
237
|
+
return rawValue;
|
|
226
238
|
}
|
|
227
239
|
|
|
228
240
|
return rawValue;
|
|
@@ -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
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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
|
-
//
|
|
86
|
+
// Avoid duplicate API calls for each user_id
|
|
111
87
|
//
|
|
112
|
-
const
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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;
|