rez_core 4.0.5 → 4.0.8

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 (28) hide show
  1. package/.vscode/extensions.json +5 -0
  2. package/dist/module/integration/service/integration.service.d.ts +6 -1
  3. package/dist/module/integration/service/integration.service.js +13 -7
  4. package/dist/module/integration/service/integration.service.js.map +1 -1
  5. package/dist/module/meta/controller/media.controller.d.ts +8 -1
  6. package/dist/module/meta/controller/media.controller.js +5 -8
  7. package/dist/module/meta/controller/media.controller.js.map +1 -1
  8. package/dist/module/meta/service/media-data.service.d.ts +6 -4
  9. package/dist/module/meta/service/media-data.service.js +144 -17
  10. package/dist/module/meta/service/media-data.service.js.map +1 -1
  11. package/dist/module/meta/service/view-master.service.js +1 -1
  12. package/dist/module/meta/service/view-master.service.js.map +1 -1
  13. package/dist/module/notification/controller/otp.controller.d.ts +9 -0
  14. package/dist/module/notification/service/otp.service.d.ts +9 -0
  15. package/dist/module/user/service/login.service.d.ts +18 -0
  16. package/dist/module/user/service/login.service.js +4 -1
  17. package/dist/module/user/service/login.service.js.map +1 -1
  18. package/dist/module/workflow/service/workflow-meta.service.d.ts +3 -1
  19. package/dist/module/workflow/service/workflow-meta.service.js +14 -4
  20. package/dist/module/workflow/service/workflow-meta.service.js.map +1 -1
  21. package/dist/tsconfig.build.tsbuildinfo +1 -1
  22. package/package.json +1 -1
  23. package/src/module/integration/service/integration.service.ts +55 -37
  24. package/src/module/meta/controller/media.controller.ts +21 -6
  25. package/src/module/meta/service/media-data.service.ts +292 -27
  26. package/src/module/meta/service/view-master.service.ts +1 -1
  27. package/src/module/user/service/login.service.ts +4 -4
  28. package/src/module/workflow/service/workflow-meta.service.ts +27 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rez_core",
3
- "version": "4.0.5",
3
+ "version": "4.0.8",
4
4
  "description": "",
5
5
  "author": "",
6
6
  "private": false,
@@ -18,7 +18,10 @@ import {
18
18
  UpdateUserIntegrationDto,
19
19
  } from '../dto/create-config.dto';
20
20
  import { FieldMapperService } from '../../mapper/service/field-mapper.service';
21
- import { COMM_TEMPLATE, ENTITYTYPE_MEDIA } from '../../../constant/global.constant';
21
+ import {
22
+ COMM_TEMPLATE,
23
+ ENTITYTYPE_MEDIA,
24
+ } from '../../../constant/global.constant';
22
25
  import { EntityServiceImpl } from '../../meta/service/entity-service-impl.service';
23
26
  import { MediaDataService } from '../../meta/service/media-data.service';
24
27
  import axios from 'axios';
@@ -90,12 +93,12 @@ export class IntegrationService {
90
93
  private readonly sendGridApiStrategy: SendGridApiStrategy,
91
94
  private readonly configService: ConfigService,
92
95
  private readonly mediaService: MediaDataService,
93
- @Inject('FieldMapperService') private readonly fieldMapperService: FieldMapperService,
96
+ @Inject('FieldMapperService')
97
+ private readonly fieldMapperService: FieldMapperService,
94
98
  private readonly entityService: EntityServiceImpl,
95
99
  @Inject(forwardRef(() => IntegrationQueueService))
96
100
  private readonly queueService?: IntegrationQueueService,
97
- ) {
98
- }
101
+ ) {}
99
102
 
100
103
  private deriveServiceType(
101
104
  integration_type: string,
@@ -107,15 +110,15 @@ export class IntegrationService {
107
110
  }
108
111
 
109
112
  async sendMessage({
110
- levelId,
111
- levelType,
112
- app_code,
113
- to,
114
- message,
115
- mode,
116
- priority = 1,
117
- user_id,
118
- }: SendMessageDto): Promise<IntegrationResult> {
113
+ levelId,
114
+ levelType,
115
+ app_code,
116
+ to,
117
+ message,
118
+ mode,
119
+ priority = 1,
120
+ user_id,
121
+ }: SendMessageDto): Promise<IntegrationResult> {
119
122
  try {
120
123
  // Get active communication configs for the level
121
124
  const configs = await this.getActiveConfigs(
@@ -195,7 +198,9 @@ export class IntegrationService {
195
198
  .where('config.level_id = :levelId', { levelId })
196
199
  .andWhere('config.level_type = :levelType', { levelType })
197
200
  .andWhere('config.app_code = :app_code', { app_code })
198
- .andWhere('config.integration_type = :integration_type', { integration_type })
201
+ .andWhere('config.integration_type = :integration_type', {
202
+ integration_type,
203
+ })
199
204
  .andWhere('config.status = 1')
200
205
  .orderBy('config.is_default', 'DESC')
201
206
  .addOrderBy('config.priority', 'ASC')
@@ -706,7 +711,7 @@ export class IntegrationService {
706
711
  if (configJson?.[field]) {
707
712
  safeConfig[
708
713
  `has${field.charAt(0).toUpperCase() + field.slice(1)}`
709
- ] = true;
714
+ ] = true;
710
715
  }
711
716
  });
712
717
 
@@ -813,8 +818,9 @@ export class IntegrationService {
813
818
  const did = config.config_json.did;
814
819
 
815
820
  if (did) {
816
-
817
- await this.entityMapperRepository.delete({integration_config_id: config.id})
821
+ await this.entityMapperRepository.delete({
822
+ integration_config_id: config.id,
823
+ });
818
824
 
819
825
  const entityMapper = this.entityMapperRepository.create({
820
826
  integration_config_id: config.id,
@@ -964,7 +970,7 @@ export class IntegrationService {
964
970
  templateId: externalTemplateId,
965
971
  variables,
966
972
  richText,
967
- subject
973
+ subject,
968
974
  };
969
975
 
970
976
  // Handle user integration if user_id provided
@@ -1055,7 +1061,7 @@ export class IntegrationService {
1055
1061
  ...enhancedConfig,
1056
1062
  templateId: externalTemplateId,
1057
1063
  variables,
1058
- richText
1064
+ richText,
1059
1065
  };
1060
1066
 
1061
1067
  // Handle user integration if user_id provided
@@ -1071,11 +1077,7 @@ export class IntegrationService {
1071
1077
  }
1072
1078
  }
1073
1079
 
1074
- const result = await strategy.sendMessage(
1075
- to,
1076
- message,
1077
- finalConfig,
1078
- );
1080
+ const result = await strategy.sendMessage(to, message, finalConfig);
1079
1081
 
1080
1082
  if (result.success) {
1081
1083
  this.logger.log(
@@ -1291,12 +1293,21 @@ export class IntegrationService {
1291
1293
  });
1292
1294
  }
1293
1295
 
1294
- private async processTemplate(
1296
+ public async processTemplate(
1295
1297
  templateId: number,
1296
1298
  entity_type: any,
1297
1299
  entity_id: any,
1298
- ): Promise<{ variables?: Record<string, any>; externalTemplateId?: string; rich_text?: string; subject?: string }> {
1299
- const commTemplate: any = await this.entityService.getEntityData(COMM_TEMPLATE, templateId, {} as any);
1300
+ ): Promise<{
1301
+ variables?: Record<string, any>;
1302
+ externalTemplateId?: string;
1303
+ rich_text?: string;
1304
+ subject?: string;
1305
+ }> {
1306
+ const commTemplate: any = await this.entityService.getEntityData(
1307
+ COMM_TEMPLATE,
1308
+ templateId,
1309
+ {} as any,
1310
+ );
1300
1311
  if (!commTemplate) {
1301
1312
  return {
1302
1313
  variables: {},
@@ -1308,7 +1319,7 @@ export class IntegrationService {
1308
1319
  if (commTemplate.mapper_id) {
1309
1320
  variables = await this.fieldMapperService.resolveData(
1310
1321
  commTemplate.mapper_id,
1311
- "LOOKUP",
1322
+ 'LOOKUP',
1312
1323
  entity_type,
1313
1324
  entity_id,
1314
1325
  {} as any,
@@ -1320,10 +1331,16 @@ export class IntegrationService {
1320
1331
 
1321
1332
  if (!richText) {
1322
1333
  if (commTemplate.markup_id) {
1323
- let url = await this.mediaService.getMediaDownloadUrl(commTemplate.markup_id, {}, 60000);
1334
+ let url = await this.mediaService.getMediaDownloadUrl(
1335
+ commTemplate.markup_id,
1336
+ {},
1337
+ 60000,
1338
+ );
1324
1339
  if (url) {
1325
- let response = await axios.get(url.signedUrl, { responseType: 'text' });
1326
- richText = response.data
1340
+ let response = await axios.get(url.signedUrl, {
1341
+ responseType: 'text',
1342
+ });
1343
+ richText = response.data;
1327
1344
  }
1328
1345
  }
1329
1346
  }
@@ -1335,7 +1352,7 @@ export class IntegrationService {
1335
1352
 
1336
1353
  return {
1337
1354
  rich_text: richText,
1338
- subject: commTemplate.subject
1355
+ subject: commTemplate.subject,
1339
1356
  };
1340
1357
  }
1341
1358
 
@@ -2023,10 +2040,10 @@ export class IntegrationService {
2023
2040
 
2024
2041
  async getIntegrationConfigById(hubId: number): Promise<
2025
2042
  | (IntegrationConfig & {
2026
- config: IntegrationConfig;
2027
- linkedSource?: string;
2028
- configDetails?: any;
2029
- })
2043
+ config: IntegrationConfig;
2044
+ linkedSource?: string;
2045
+ configDetails?: any;
2046
+ })
2030
2047
  | null
2031
2048
  > {
2032
2049
  try {
@@ -2518,7 +2535,8 @@ export class IntegrationService {
2518
2535
  if (!userIntegration) {
2519
2536
  return {
2520
2537
  success: false,
2521
- error: 'User integration mapping not found. Please configure agent details.',
2538
+ error:
2539
+ 'User integration mapping not found. Please configure agent details.',
2522
2540
  };
2523
2541
  }
2524
2542
 
@@ -28,6 +28,8 @@ export class MediaController {
28
28
  attribute_key: string;
29
29
  mapped_entity_type?: string;
30
30
  mapped_entity_id?: number;
31
+ parent_id?: number;
32
+ parent_type?: string;
31
33
  },
32
34
  @Req() req: Request & { user: any },
33
35
  @Res() res: Response,
@@ -40,6 +42,8 @@ export class MediaController {
40
42
  loggedInUser,
41
43
  body.mapped_entity_type,
42
44
  body.mapped_entity_id,
45
+ body.parent_id,
46
+ body.parent_type,
43
47
  );
44
48
  if (result) {
45
49
  res.status(HttpStatus.OK).json({
@@ -81,12 +85,23 @@ export class MediaController {
81
85
  }
82
86
 
83
87
  @Post('generateUploadPath')
84
- async generateUploadPath(@Req() req: Request & { user: any }, @Query('mapped_entity_type') mapped_entity_type: string,
85
- @Query('mapped_entity_id') mapped_entity_id?: number,
86
- @Query('parent_id') parent_id?: number,
87
- @Query('parent_type') parent_type?: string,
88
- ) {
88
+ async generateUploadPath(
89
+ @Req() req: Request & { user: any },
90
+ @Body()
91
+ body: {
92
+ mapped_entity_type: string;
93
+ mapped_entity_id?: number;
94
+ parent_id?: number;
95
+ parent_type?: string;
96
+ },
97
+ ) {
89
98
  const loggedInUser = req.user.userData;
90
- return this.mediaDataService.buildUploadPathGeneric(mapped_entity_type, loggedInUser, mapped_entity_id,parent_id, parent_type)
99
+ return this.mediaDataService.buildUploadPathGeneric(
100
+ body.mapped_entity_type,
101
+ loggedInUser,
102
+ body.mapped_entity_id,
103
+ body.parent_id,
104
+ body.parent_type,
105
+ );
91
106
  }
92
107
  }
@@ -1,17 +1,16 @@
1
1
  import { Injectable } from '@nestjs/common';
2
- import { EntityServiceImpl } from './entity-service-impl.service';
3
- import { MediaDataRepository } from '../repository/media-data.repository';
4
2
  import { ConfigService } from '@nestjs/config';
5
3
  import { S3 } from 'aws-sdk';
6
- import { MediaData } from '../entity/media-data.entity';
4
+ import axios from 'axios';
5
+ import { DataSource } from 'typeorm';
6
+ import { v4 as uuidv4 } from 'uuid';
7
7
  import {
8
8
  ENTITYTYPE_MEDIA,
9
9
  STATUS_PENDING,
10
10
  } from '../../../constant/global.constant';
11
- import { v4 as uuidv4 } from 'uuid';
12
- import { OrganizationService } from '../../enterprise/service/organization.service';
13
- import { EntityMasterService } from './entity-master.service';
14
- import { DataSource } from 'typeorm';
11
+ import { MediaData } from '../entity/media-data.entity';
12
+ import { MediaDataRepository } from '../repository/media-data.repository';
13
+ import { EntityServiceImpl } from './entity-service-impl.service';
15
14
 
16
15
  @Injectable()
17
16
  export class MediaDataService extends EntityServiceImpl {
@@ -41,6 +40,8 @@ export class MediaDataService extends EntityServiceImpl {
41
40
  loggedInUser,
42
41
  mappedEntityType?: string,
43
42
  mappedEntityId?: number,
43
+ parentId?: number,
44
+ parentType?: string,
44
45
  ) {
45
46
  if (!fileName || !mappedAttributeKey) {
46
47
  return null;
@@ -49,8 +50,16 @@ export class MediaDataService extends EntityServiceImpl {
49
50
 
50
51
  const id = uuidv4();
51
52
 
52
- //TODO:
53
- const s3Key = `uploads/${id}.${ext}`;
53
+ const s3Path =
54
+ (await this.buildUploadPathGeneric(
55
+ mappedEntityType || '',
56
+ loggedInUser,
57
+ mappedEntityId,
58
+ parentId,
59
+ parentType,
60
+ )) || `uploads`;
61
+
62
+ const s3Key = `${s3Path}/${id}.${ext}`;
54
63
 
55
64
  const uploadUrl = await this.s3.getSignedUrlPromise('putObject', {
56
65
  Bucket: this.bucketName,
@@ -71,6 +80,7 @@ export class MediaDataService extends EntityServiceImpl {
71
80
  }
72
81
  mediaData.media_url = s3Key;
73
82
 
83
+ //INSERT RECORD IN DOC TABLE
74
84
  const savedEntity = await super.createEntity(mediaData, loggedInUser);
75
85
 
76
86
  if (savedEntity) {
@@ -134,10 +144,12 @@ export class MediaDataService extends EntityServiceImpl {
134
144
  const mediaData = entityData as MediaData;
135
145
  let fileSize: number | undefined;
136
146
  if (this.bucketName) {
137
- const head = await this.s3.headObject({
138
- Bucket: this.bucketName,
139
- Key: mediaData.media_url,
140
- }).promise();
147
+ const head = await this.s3
148
+ .headObject({
149
+ Bucket: this.bucketName,
150
+ Key: mediaData.media_url,
151
+ })
152
+ .promise();
141
153
  fileSize = head.ContentLength;
142
154
  }
143
155
 
@@ -146,14 +158,19 @@ export class MediaDataService extends EntityServiceImpl {
146
158
  Key: mediaData.media_url,
147
159
  Expires: Number(expiresIn) || 60 * 5,
148
160
  });
149
- return { signedUrl, fileName: mediaData.file_name, id: mediaData.id, size: fileSize };
161
+ return {
162
+ signedUrl,
163
+ fileName: mediaData.file_name,
164
+ id: mediaData.id,
165
+ size: fileSize,
166
+ };
150
167
  } catch (error) {
151
168
  console.error('Error generating signed URL for media:', error);
152
169
  throw new Error('Failed to generate signed URL');
153
170
  }
154
171
  }
155
172
 
156
- public async buildUploadPathGeneric(
173
+ public async buildUploadPathGenericdd(
157
174
  mappedEntityType: string,
158
175
  loggedInUser,
159
176
  mappedEntityId?: number,
@@ -161,7 +178,10 @@ export class MediaDataService extends EntityServiceImpl {
161
178
  parentType?: string,
162
179
  ) {
163
180
  // 1️⃣ Fetch entity metadata
164
- const entityMaster = await this.entityMasterService.getEntityData(mappedEntityType, loggedInUser);
181
+ const entityMaster = await this.entityMasterService.getEntityData(
182
+ mappedEntityType,
183
+ loggedInUser,
184
+ );
165
185
  if (!entityMaster) {
166
186
  throw new Error(`Entity master not found for ${mappedEntityType}`);
167
187
  }
@@ -177,17 +197,115 @@ export class MediaDataService extends EntityServiceImpl {
177
197
  const replacements: Record<string, string | null> = {};
178
198
 
179
199
  // --- ORG ---
180
- let organizationData = await this.dataSource.query('SELECT * FROM sso_organization WHERE id = ?', [loggedInUser.organization_id]);
200
+ let organizationData = await this.dataSource.query(
201
+ 'SELECT * FROM sso_organization WHERE id = ?',
202
+ [loggedInUser.organization_id],
203
+ );
181
204
  replacements['org_code'] = organizationData[0].code;
182
205
 
183
206
  // --- LEVEL CODE ---
184
- // Determine which entity to use for level_code
185
- const levelEntityId = entityOverwrite ? mappedEntityId : loggedInUser.level_id;
186
- const levelEntityData = await super.getEntityData(loggedInUser.level_type, levelEntityId, loggedInUser);
207
+ // Priority: If parent is provided, use parent for level_code; otherwise use normal logic
208
+ let levelEntityId: number;
209
+ let levelEntityType: string;
210
+
211
+ if (parentId && parentType) {
212
+ // When parent is provided, parent becomes the level_code
213
+ levelEntityId = parentId;
214
+ levelEntityType = parentType;
215
+ } else {
216
+ // Normal logic: determine which entity to use for level_code
217
+ levelEntityId = entityOverwrite ? mappedEntityId : loggedInUser.level_id;
218
+ levelEntityType = entityOverwrite
219
+ ? mappedEntityType
220
+ : loggedInUser.level_type;
221
+ }
222
+
223
+ // Get entity data for level_code
224
+ const getEntityData = await this.dataSource.query(
225
+ `SELECT * FROM cr_entity_master WHERE mapped_entity_type = ? and organization_id = ?`,
226
+ [levelEntityType, loggedInUser.organization_id],
227
+ );
228
+
229
+ if (getEntityData.length == 0) return null;
230
+ const levelEntityDataResult = await this.dataSource.query(
231
+ `SELECT * FROM ${getEntityData[0]?.db_table_name} WHERE id = ?`,
232
+ [levelEntityId],
233
+ );
234
+
235
+ const levelEntityData = levelEntityDataResult[0] || null;
236
+
187
237
  if (levelEntityData?.code) {
188
238
  replacements['level_code'] = levelEntityData.code; // universal alias
189
239
  }
190
240
 
241
+ // --- MAPPED ENTITY CODE (when parent is provided) ---
242
+ // When parent is provided, the mapped entity becomes an additional level
243
+ if (parentId && parentType && mappedEntityId && mappedEntityType) {
244
+ const mappedEntityKey = `${mappedEntityType.toLowerCase()}_code`;
245
+ const mappedEntityData = await super.getEntityData(
246
+ mappedEntityType,
247
+ mappedEntityId,
248
+ loggedInUser,
249
+ );
250
+ if (mappedEntityData?.code) {
251
+ replacements[mappedEntityKey] = mappedEntityData.code;
252
+
253
+ // Modify path template to include mapped entity
254
+ // Example: ${org_code}/${level_code} becomes ${org_code}/${level_code}/${tem_code}
255
+ const mappedVariable = `\${${mappedEntityKey}}`;
256
+ if (!pathTemplate.includes(mappedVariable)) {
257
+ pathTemplate = pathTemplate + `/${mappedVariable}`;
258
+ }
259
+ }
260
+ }
261
+
262
+ // --- TEMPLATE CODE (if parent is provided) ---
263
+ // Special handling for template_code when parent_id and parent_type are provided
264
+ if (parentId && parentType) {
265
+ // const templateEntityData = await super.getEntityData(
266
+ // parentType,
267
+ // parentId,
268
+ // loggedInUser,
269
+ // );
270
+
271
+ // Get entity data for level_code
272
+ const getEntityData = await this.dataSource.query(
273
+ `SELECT * FROM cr_entity_master WHERE mapped_entity_type = ? and organization_id = ?`,
274
+ [mappedEntityType, loggedInUser.organization_id],
275
+ );
276
+
277
+ if (getEntityData.length == 0) return null;
278
+ const levelEntityDataResult = await this.dataSource.query(
279
+ `SELECT * FROM ${getEntityData[0]?.db_table_name} WHERE id = ?`,
280
+ [mappedEntityId],
281
+ );
282
+
283
+ if (
284
+ levelEntityDataResult?.[0].code &&
285
+ parentType != 'SCH' &&
286
+ loggedInUser.level_type != 'SCH'
287
+ ) {
288
+ replacements['template_code'] = levelEntityDataResult[0].code;
289
+ // If we have parent template, modify the path to include it
290
+ pathTemplate = '${org_code}/template/${template_code}';
291
+ } else {
292
+ const getEntityData = await this.dataSource.query(
293
+ `SELECT * FROM cr_entity_master WHERE mapped_entity_type = ? and organization_id = ?`,
294
+ [mappedEntityType, loggedInUser.organization_id],
295
+ );
296
+
297
+ if (getEntityData.length == 0) return null;
298
+ const levelEntityDataResult = await this.dataSource.query(
299
+ `SELECT * FROM ${getEntityData[0]?.db_table_name} WHERE id = ?`,
300
+ [mappedEntityId],
301
+ );
302
+
303
+ replacements['template_code'] = levelEntityDataResult?.[0].code;
304
+
305
+ pathTemplate = '${org_code}/${level_code}/template/${template_code}';
306
+ }
307
+ }
308
+
191
309
  // --- Dynamic variables inside path ---
192
310
  const matches = pathTemplate.match(/\$\{(\w+)\}/g) || [];
193
311
 
@@ -196,29 +314,48 @@ export class MediaDataService extends EntityServiceImpl {
196
314
  if (replacements[key]) continue; // already resolved
197
315
 
198
316
  if (key === 'org_code') continue; // already set
317
+ if (key === 'level_code') continue; // already set above
318
+ if (key === 'template_code') continue; // handled above if parent is provided
319
+
199
320
  if (key.endsWith('_code')) {
200
321
  // derive entity type dynamically
201
322
  const entityType = key.replace('_code', '').toUpperCase();
202
323
 
203
324
  let entityId: number | undefined;
204
- if (parentType?.toUpperCase() === entityType && parentId) {
205
- entityId = parentId;
325
+
326
+ // Special handling for template_code - use parent if available, otherwise mapped entity
327
+ if (key === 'template_code') {
328
+ if (parentType?.toUpperCase() === 'TEMPLATE' && parentId) {
329
+ entityId = parentId;
330
+ } else if (mappedEntityType === 'TEMPLATE') {
331
+ entityId = mappedEntityId;
332
+ }
206
333
  } else {
207
- entityId = mappedEntityId;
334
+ // For other _code variables, check if parent matches the entity type
335
+ if (parentType?.toUpperCase() === entityType && parentId) {
336
+ entityId = parentId;
337
+ } else if (mappedEntityType === entityType) {
338
+ entityId = mappedEntityId;
339
+ }
208
340
  }
209
341
 
210
342
  // Generic lookup
211
343
  if (entityId) {
212
- const entityData = await super.getEntityData(entityType, entityId, loggedInUser);
344
+ const entityData = await super.getEntityData(
345
+ entityType,
346
+ entityId,
347
+ loggedInUser,
348
+ );
213
349
  replacements[key] = entityData?.code ?? null;
214
350
  }
215
351
  }
216
352
  }
217
353
 
218
354
  // --- ORG special case ---
219
- // If ORG level & overwrite = 0 → remove level_code variable
355
+ // If ORG level & overwrite = 0 → use org_code, otherwise use the mapped entity's code
220
356
  if (loggedInUser.level_type === 'ORG' && entityOverwrite === 0) {
221
- replacements['level_code'] = null;
357
+ // When overwrite is 0 and user is ORG level, but we want to use mapped entity
358
+ // Don't set level_code to null - it should already be set above based on entityOverwrite logic
222
359
  }
223
360
 
224
361
  // 3️⃣ Final substitution and cleanup
@@ -229,12 +366,140 @@ export class MediaDataService extends EntityServiceImpl {
229
366
  return null;
230
367
  }
231
368
 
369
+ public async buildUploadPathGeneric(
370
+ mappedEntityType: string,
371
+ loggedInUser,
372
+ mappedEntityId?: number,
373
+ parentId?: number,
374
+ parentType?: string,
375
+ ) {
376
+ //APPCODE
377
+ let appCode = '';
378
+
379
+ let org_id = loggedInUser.organization_id;
380
+ let level_type = loggedInUser.level_type;
381
+ let level_id =
382
+ loggedInUser.level_type == 'ORG' && mappedEntityType == 'SCH'
383
+ ? mappedEntityId
384
+ : loggedInUser.level_id;
385
+
386
+ let organizationData = {};
387
+ let levelData = {};
388
+ let mappedEntityData = {};
389
+
390
+ if (loggedInUser && loggedInUser.appcode) {
391
+ appCode = loggedInUser.appcode;
392
+ }
393
+
394
+ if (appCode && appCode != 'ADM') {
395
+ const baseUrl = this.configService.get<string>('REDIRECT_BE_URL');
396
+
397
+ // Prepare the query string
398
+ const queryParams = new URLSearchParams({
399
+ loggedInUser: JSON.stringify(loggedInUser),
400
+ }).toString();
401
+
402
+ organizationData = await axios
403
+ .get(`${baseUrl}/organization/public/?${queryParams}`)
404
+ .then((res) => res.data)
405
+ .catch((err) => {
406
+ console.error('Error fetching organization data:', err.message);
407
+ return null;
408
+ });
409
+
410
+ levelData = await axios
411
+ .get(`${baseUrl}/school/public/?${queryParams}`)
412
+ .then((res) => res.data)
413
+ .catch((err) => {
414
+ console.error('Error fetching school data:', err.message);
415
+ return null;
416
+ });
417
+ } else {
418
+ organizationData = await this.dataSource.query(
419
+ 'SELECT * FROM adm_org_profile WHERE id = ?',
420
+ [loggedInUser.organization_id],
421
+ );
422
+ levelData = await this.dataSource.query(
423
+ 'SELECT * FROM adm_school_profile WHERE id = ?',
424
+ [loggedInUser.level_id],
425
+ );
426
+ }
427
+
428
+ console.log(levelData);
429
+
430
+ // 1️⃣ Fetch entity metadata
431
+ // const uploadEntity = await this.entityMasterService.getEntityData(
432
+ // mappedEntityType,
433
+ // loggedInUser,
434
+ // );
435
+ // if (!uploadEntity) {
436
+ // throw new Error(`Entity master not found for ${mappedEntityType}`);
437
+ // }
438
+
439
+ let subfolder =
440
+ mappedEntityType == level_type
441
+ ? 'data'
442
+ : parentType
443
+ ? `${parentType}/${parentId}/${mappedEntityType}`
444
+ : mappedEntityType;
445
+ let path =
446
+ '${org_code}/${level_code}/' +
447
+ (subfolder !== 'data'
448
+ ? `${subfolder}/${mappedEntityId}`
449
+ : `${subfolder}`);
450
+
451
+ // 2️⃣ Prepare replacement map
452
+ const replacements: Record<string, string | null> = {};
453
+ replacements['org_code'] = organizationData[0]?.code;
454
+ replacements['level_code'] = levelData[0]?.code; // universal alias
455
+
456
+ // 3️⃣ Final substitution and cleanup
457
+ if (path) {
458
+ const finalPath = this.resolveUploadPath(path, replacements);
459
+ return finalPath;
460
+ }
461
+ return null;
462
+ }
463
+
232
464
  /**
233
465
  * Replace placeholders with actual values, remove missing variables
234
466
  */
235
- private resolveUploadPath(template: string, replacements: Record<string, string | null>) {
467
+ private resolveUploadPath(
468
+ template: string,
469
+ replacements: Record<string, string | null>,
470
+ ) {
236
471
  let path = template;
237
472
  path = path.replace(/\$\{(\w+)\}/g, (_, key) => replacements[key] || '');
238
473
  return path.replace(/\/+/g, '/').replace(/\/$/, '');
239
474
  }
475
+
476
+ /**
477
+ * Helper method to build upload path for different scenarios
478
+ *
479
+ * @param mappedEntityType - The main entity type (e.g., 'LEAD', 'SCH')
480
+ * @param loggedInUser - Current user context
481
+ * @param mappedEntityId - ID of the main entity
482
+ * @param parentId - Optional parent entity ID (e.g., template ID)
483
+ * @param parentType - Optional parent entity type (e.g., 'TEMPLATE')
484
+ * @returns Promise<string | null> - The resolved upload path
485
+ *
486
+ * Examples:
487
+ * - buildUploadPath('LEAD', user, 123) -> "ORG1/template/SCH1"
488
+ * - buildUploadPath('LEAD', user, 123, 456, 'TEMPLATE') -> "ORG1/template/SCH1/TEMPLATE1"
489
+ */
490
+ async buildUploadPath(
491
+ mappedEntityType: string,
492
+ loggedInUser: any,
493
+ mappedEntityId?: number,
494
+ parentId?: number,
495
+ parentType?: string,
496
+ ): Promise<string | null> {
497
+ return this.buildUploadPathGeneric(
498
+ mappedEntityType,
499
+ loggedInUser,
500
+ mappedEntityId,
501
+ parentId,
502
+ parentType,
503
+ );
504
+ }
240
505
  }
@@ -90,7 +90,7 @@ export class ViewMasterService extends EntityServiceImpl {
90
90
 
91
91
  // Make the GET request with query parameters
92
92
  const response = await axios.get<any>(
93
- `${baseUrl}/school/theme_json/${loggedInUserData?.level_id}`,
93
+ `${baseUrl}/school/public/theme_json/${loggedInUserData?.level_id}`,
94
94
 
95
95
  {
96
96
  headers: {