rez_core 3.1.199 → 3.1.201

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": "3.1.199",
3
+ "version": "3.1.201",
4
4
  "description": "",
5
5
  "author": "",
6
6
  "private": false,
@@ -79,4 +79,14 @@ export class MediaController {
79
79
  });
80
80
  }
81
81
  }
82
+
83
+ @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
+ ) {
89
+ const loggedInUser = req.user.userData;
90
+ return this.mediaDataService.buildUploadPathGeneric(mapped_entity_type, loggedInUser, mapped_entity_id,parent_id, parent_type)
91
+ }
82
92
  }
@@ -75,4 +75,10 @@ export class EntityMaster extends BaseEntity {
75
75
 
76
76
  @Column({ name: 'is_workflow', nullable: true })
77
77
  is_workflow: boolean;
78
+
79
+ @Column({ name: 'doc_upload_path', nullable: true, length:50 })
80
+ doc_upload_path: string;
81
+
82
+ @Column({name: 'overwrite_path', type: 'tinyint', nullable: true})
83
+ overwrite_path: number;
78
84
  }
@@ -9,12 +9,16 @@ import {
9
9
  STATUS_PENDING,
10
10
  } from '../../../constant/global.constant';
11
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';
12
15
 
13
16
  @Injectable()
14
17
  export class MediaDataService extends EntityServiceImpl {
15
18
  constructor(
16
19
  private readonly configService: ConfigService,
17
20
  private readonly mediaRepository: MediaDataRepository,
21
+ private dataSource: DataSource,
18
22
  ) {
19
23
  super();
20
24
  }
@@ -44,6 +48,8 @@ export class MediaDataService extends EntityServiceImpl {
44
48
  const ext = fileName.split('.').pop()?.toLowerCase() ?? '';
45
49
 
46
50
  const id = uuidv4();
51
+
52
+ //TODO:
47
53
  const s3Key = `uploads/${id}.${ext}`;
48
54
 
49
55
  const uploadUrl = await this.s3.getSignedUrlPromise('putObject', {
@@ -140,10 +146,95 @@ export class MediaDataService extends EntityServiceImpl {
140
146
  Key: mediaData.media_url,
141
147
  Expires: Number(expiresIn) || 60 * 5,
142
148
  });
143
- return { signedUrl, fileName: mediaData.file_name, id: mediaData.id, size: fileSize};
149
+ return { signedUrl, fileName: mediaData.file_name, id: mediaData.id, size: fileSize };
144
150
  } catch (error) {
145
151
  console.error('Error generating signed URL for media:', error);
146
152
  throw new Error('Failed to generate signed URL');
147
153
  }
148
154
  }
155
+
156
+ public async buildUploadPathGeneric(
157
+ mappedEntityType: string,
158
+ loggedInUser,
159
+ mappedEntityId?: number,
160
+ parentId?: number,
161
+ parentType?: string,
162
+ ) {
163
+ // 1️⃣ Fetch entity metadata
164
+ const entityMaster = await this.entityMasterService.getEntityData(mappedEntityType, loggedInUser);
165
+ if (!entityMaster) {
166
+ throw new Error(`Entity master not found for ${mappedEntityType}`);
167
+ }
168
+
169
+ let pathTemplate = entityMaster.doc_upload_path ?? '';
170
+ const entityOverwrite = entityMaster.overwrite_path ?? 0;
171
+
172
+ if (!pathTemplate) {
173
+ throw new Error(`doc_upload_path not defined for ${mappedEntityType}`);
174
+ }
175
+
176
+ // 2️⃣ Prepare replacement map
177
+ const replacements: Record<string, string | null> = {};
178
+
179
+ // --- ORG ---
180
+ let organizationData = await this.dataSource.query('SELECT * FROM sso_organization WHERE id = ?', [loggedInUser.organization_id]);
181
+ replacements['org_code'] = organizationData[0].code;
182
+
183
+ // --- 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);
187
+ if (levelEntityData?.code) {
188
+ replacements['level_code'] = levelEntityData.code; // universal alias
189
+ }
190
+
191
+ // --- Dynamic variables inside path ---
192
+ const matches = pathTemplate.match(/\$\{(\w+)\}/g) || [];
193
+
194
+ for (const variable of matches) {
195
+ const key = variable.replace(/\$\{|\}/g, '');
196
+ if (replacements[key]) continue; // already resolved
197
+
198
+ if (key === 'org_code') continue; // already set
199
+ if (key.endsWith('_code')) {
200
+ // derive entity type dynamically
201
+ const entityType = key.replace('_code', '').toUpperCase();
202
+
203
+ let entityId: number | undefined;
204
+ if (parentType?.toUpperCase() === entityType && parentId) {
205
+ entityId = parentId;
206
+ } else {
207
+ entityId = mappedEntityId;
208
+ }
209
+
210
+ // Generic lookup
211
+ if (entityId) {
212
+ const entityData = await super.getEntityData(entityType, entityId, loggedInUser);
213
+ replacements[key] = entityData?.code ?? null;
214
+ }
215
+ }
216
+ }
217
+
218
+ // --- ORG special case ---
219
+ // If ORG level & overwrite = 0 → remove level_code variable
220
+ if (loggedInUser.level_type === 'ORG' && entityOverwrite === 0) {
221
+ replacements['level_code'] = null;
222
+ }
223
+
224
+ // 3️⃣ Final substitution and cleanup
225
+ if (pathTemplate) {
226
+ const finalPath = this.resolveUploadPath(pathTemplate, replacements);
227
+ return finalPath;
228
+ }
229
+ return null;
230
+ }
231
+
232
+ /**
233
+ * Replace placeholders with actual values, remove missing variables
234
+ */
235
+ private resolveUploadPath(template: string, replacements: Record<string, string | null>) {
236
+ let path = template;
237
+ path = path.replace(/\$\{(\w+)\}/g, (_, key) => replacements[key] || '');
238
+ return path.replace(/\/+/g, '/').replace(/\/$/, '');
239
+ }
149
240
  }
@@ -127,7 +127,7 @@ export class NotificationsService {
127
127
 
128
128
  // Make the GET request with query parameters
129
129
  const response = await axios.get(
130
- `${baseUrl}/users/profile-image-url/${notification?.user_id}?entity_type=UPR&${queryParams}`,
130
+ `${baseUrl}/users/profile-image-url/${notification?.user_id}?entity_type=USR&${queryParams}`,
131
131
  {
132
132
  headers: {
133
133
  'Content-Type': 'application/json',
@@ -68,7 +68,7 @@ export class ActivityLogRepository {
68
68
 
69
69
  // Make the GET request with query parameters
70
70
  const response = await axios.get(
71
- `${baseUrl}/users/profile-image-url/${param?.created_by}?entity_type=UPR&${queryParams}`,
71
+ `${baseUrl}/users/profile-image-url/${param?.created_by}?entity_type=USR&${queryParams}`,
72
72
  {
73
73
  headers: {
74
74
  'Content-Type': 'application/json',
@@ -222,7 +222,7 @@ export class StageGroupService extends EntityServiceImpl {
222
222
 
223
223
  // Make the GET request with query parameters
224
224
  const response = await axios.get(
225
- `${baseUrl}/users/profile-image-url/${userId}?entity_type=UPR&${queryParams}`,
225
+ `${baseUrl}/users/profile-image-url/${userId}?entity_type=USR&${queryParams}`,
226
226
  {
227
227
  headers: {
228
228
  'Content-Type': 'application/json',
@@ -320,7 +320,7 @@ export class TaskService extends EntityServiceImpl {
320
320
 
321
321
  // Make the GET request with query parameters
322
322
  const response = await axios.get(
323
- `${baseUrl}/users/profile-image-url/${param?.task_owner}?entity_type=UPR&${queryParams}`,
323
+ `${baseUrl}/users/profile-image-url/${param?.task_owner}?entity_type=USR&${queryParams}`,
324
324
  {
325
325
  headers: {
326
326
  'Content-Type': 'application/json',