@flusys/nestjs-storage 0.1.0-beta.2 → 1.0.0-beta
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/README.md +3 -7
- package/cjs/config/storage-config.service.js +31 -0
- package/cjs/controllers/file-manager.controller.js +8 -6
- package/cjs/controllers/folder.controller.js +3 -4
- package/cjs/controllers/storage-config.controller.js +3 -4
- package/cjs/controllers/upload.controller.js +22 -169
- package/cjs/dtos/file-manager.dto.js +36 -2
- package/cjs/dtos/upload.dto.js +16 -0
- package/cjs/middlewares/file-serve.middleware.js +204 -0
- package/cjs/middlewares/index.js +18 -0
- package/cjs/modules/storage.module.js +58 -14
- package/cjs/providers/azure-provider.optional.js +1 -2
- package/cjs/providers/local-provider.js +43 -11
- package/cjs/providers/storage-factory.service.js +49 -5
- package/cjs/services/file-manager.service.js +134 -9
- package/cjs/services/folder.service.js +17 -48
- package/cjs/services/storage-datasource.provider.js +10 -16
- package/cjs/services/storage-provider-config.service.js +26 -32
- package/cjs/services/upload.service.js +135 -24
- package/cjs/utils/image-compressor.util.js +43 -5
- package/config/storage-config.service.d.ts +2 -0
- package/controllers/file-manager.controller.d.ts +1 -1
- package/controllers/upload.controller.d.ts +5 -4
- package/dtos/file-manager.dto.d.ts +4 -0
- package/dtos/upload.dto.d.ts +2 -0
- package/fesm/config/storage-config.service.js +31 -0
- package/fesm/controllers/file-manager.controller.js +8 -6
- package/fesm/controllers/folder.controller.js +5 -6
- package/fesm/controllers/storage-config.controller.js +5 -6
- package/fesm/controllers/upload.controller.js +25 -131
- package/fesm/dtos/file-manager.dto.js +36 -2
- package/fesm/dtos/upload.dto.js +16 -0
- package/fesm/middlewares/file-serve.middleware.js +153 -0
- package/fesm/middlewares/index.js +1 -0
- package/fesm/modules/storage.module.js +60 -16
- package/fesm/providers/azure-provider.optional.js +1 -2
- package/fesm/providers/local-provider.js +43 -11
- package/fesm/providers/storage-factory.service.js +50 -6
- package/fesm/services/file-manager.service.js +134 -9
- package/fesm/services/folder.service.js +18 -49
- package/fesm/services/storage-datasource.provider.js +10 -16
- package/fesm/services/storage-provider-config.service.js +26 -32
- package/fesm/services/upload.service.js +135 -24
- package/fesm/utils/image-compressor.util.js +3 -1
- package/interfaces/file-manager.interface.d.ts +2 -0
- package/interfaces/storage-module-options.interface.d.ts +2 -0
- package/interfaces/storage-provider.interface.d.ts +2 -0
- package/middlewares/file-serve.middleware.d.ts +9 -0
- package/middlewares/index.d.ts +1 -0
- package/modules/storage.module.d.ts +3 -2
- package/package.json +26 -11
- package/providers/local-provider.d.ts +2 -1
- package/providers/storage-factory.service.d.ts +4 -0
- package/services/file-manager.service.d.ts +7 -1
- package/services/folder.service.d.ts +1 -2
- package/services/storage-provider-config.service.d.ts +2 -2
- package/services/upload.service.d.ts +6 -2
|
@@ -90,6 +90,13 @@ const USER_ACTION_PERMISSION_CACHE_KEY = 'user_action_permission';
|
|
|
90
90
|
const SHOW_PRIVATE_FILE_ACTION = 'storage.file.viewPrivate';
|
|
91
91
|
let FileManagerService = class FileManagerService extends _classes.RequestScopedApiService {
|
|
92
92
|
/**
|
|
93
|
+
* Get base URL for file serving
|
|
94
|
+
* Priority: appUrl config > request headers
|
|
95
|
+
*/ getFileBaseUrl(protocol, host) {
|
|
96
|
+
const appUrl = this.storageConfig.getAppUrl();
|
|
97
|
+
return appUrl?.replace(/\/$/, '') ?? `${protocol}://${host}`;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
93
100
|
* Resolve entity class for this service
|
|
94
101
|
* @returns FileManager or FileManagerWithCompany based on configuration
|
|
95
102
|
*/ resolveEntity() {
|
|
@@ -188,6 +195,7 @@ let FileManagerService = class FileManagerService extends _classes.RequestScoped
|
|
|
188
195
|
'key',
|
|
189
196
|
'url',
|
|
190
197
|
'location',
|
|
198
|
+
'storageConfigId',
|
|
191
199
|
'isPrivate',
|
|
192
200
|
'createdAt',
|
|
193
201
|
'deletedAt'
|
|
@@ -198,6 +206,7 @@ let FileManagerService = class FileManagerService extends _classes.RequestScoped
|
|
|
198
206
|
if (this.storageConfig.isCompanyFeatureEnabled()) {
|
|
199
207
|
selectFields.push('file_manager.companyId');
|
|
200
208
|
}
|
|
209
|
+
// Join folder
|
|
201
210
|
selectFields.push('folder.id');
|
|
202
211
|
selectFields.push('folder.name');
|
|
203
212
|
query.leftJoinAndSelect('file_manager.folder', 'folder');
|
|
@@ -207,6 +216,57 @@ let FileManagerService = class FileManagerService extends _classes.RequestScoped
|
|
|
207
216
|
isRaw: false
|
|
208
217
|
};
|
|
209
218
|
}
|
|
219
|
+
/**
|
|
220
|
+
* Enrich file list with provider names from storage_config table
|
|
221
|
+
* Call this method to add providerName to the list results
|
|
222
|
+
*/ async enrichWithProviderNames(items) {
|
|
223
|
+
// Get unique storage config IDs
|
|
224
|
+
const configIds = [
|
|
225
|
+
...new Set(items.map((item)=>item.storageConfigId).filter(Boolean))
|
|
226
|
+
];
|
|
227
|
+
this.logger.debug(`enrichWithProviderNames: items count=${items.length}, configIds=${JSON.stringify(configIds)}`);
|
|
228
|
+
if (configIds.length === 0) {
|
|
229
|
+
this.logger.debug('enrichWithProviderNames: No storage config IDs found in items');
|
|
230
|
+
return items.map((item)=>({
|
|
231
|
+
...item,
|
|
232
|
+
providerName: undefined
|
|
233
|
+
}));
|
|
234
|
+
}
|
|
235
|
+
// Fetch storage config names
|
|
236
|
+
try {
|
|
237
|
+
const enableCompanyFeature = this.storageConfig.isCompanyFeatureEnabled();
|
|
238
|
+
const storageConfigEntity = enableCompanyFeature ? (await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../entities")))).StorageConfigWithCompany : (await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../entities")))).StorageConfig;
|
|
239
|
+
const storageConfigRepository = await this.dataSourceProvider.getRepository(storageConfigEntity);
|
|
240
|
+
const configs = await storageConfigRepository.find({
|
|
241
|
+
where: {
|
|
242
|
+
id: (0, _typeorm.In)(configIds)
|
|
243
|
+
},
|
|
244
|
+
select: [
|
|
245
|
+
'id',
|
|
246
|
+
'name'
|
|
247
|
+
]
|
|
248
|
+
});
|
|
249
|
+
this.logger.debug(`enrichWithProviderNames: Found ${configs.length} configs: ${JSON.stringify(configs)}`);
|
|
250
|
+
// Create a map for quick lookup
|
|
251
|
+
const configNameMap = new Map(configs.map((c)=>[
|
|
252
|
+
c.id,
|
|
253
|
+
c.name
|
|
254
|
+
]));
|
|
255
|
+
// Enrich items with provider names
|
|
256
|
+
const enrichedItems = items.map((item)=>({
|
|
257
|
+
...item,
|
|
258
|
+
providerName: item.storageConfigId ? configNameMap.get(item.storageConfigId) : undefined
|
|
259
|
+
}));
|
|
260
|
+
this.logger.debug(`enrichWithProviderNames: First enriched item: ${JSON.stringify(enrichedItems[0])}`);
|
|
261
|
+
return enrichedItems;
|
|
262
|
+
} catch (error) {
|
|
263
|
+
this.logger.warn(`Failed to fetch provider names: ${error}`);
|
|
264
|
+
return items.map((item)=>({
|
|
265
|
+
...item,
|
|
266
|
+
providerName: undefined
|
|
267
|
+
}));
|
|
268
|
+
}
|
|
269
|
+
}
|
|
210
270
|
async getFilterQuery(query, filter, _user) {
|
|
211
271
|
Object.entries(filter).forEach(([key, value])=>{
|
|
212
272
|
if (key === 'contentType') {
|
|
@@ -269,7 +329,7 @@ let FileManagerService = class FileManagerService extends _classes.RequestScoped
|
|
|
269
329
|
}
|
|
270
330
|
return result;
|
|
271
331
|
}
|
|
272
|
-
async beforeDeleteOperation(dto,
|
|
332
|
+
async beforeDeleteOperation(dto, user, _queryRunner) {
|
|
273
333
|
if (dto.type === 'permanent') {
|
|
274
334
|
const ids = Array.isArray(dto.id) ? dto.id : [
|
|
275
335
|
dto.id
|
|
@@ -282,13 +342,46 @@ let FileManagerService = class FileManagerService extends _classes.RequestScoped
|
|
|
282
342
|
fileManager.forEach((file)=>{
|
|
283
343
|
const configId = file.storageConfigId || 'default';
|
|
284
344
|
if (!filesByConfig.has(configId)) {
|
|
285
|
-
filesByConfig.set(configId,
|
|
345
|
+
filesByConfig.set(configId, {
|
|
346
|
+
keys: [],
|
|
347
|
+
location: file.location
|
|
348
|
+
});
|
|
286
349
|
}
|
|
287
|
-
filesByConfig.get(configId).push(file.key);
|
|
350
|
+
filesByConfig.get(configId).keys.push(file.key);
|
|
288
351
|
});
|
|
289
352
|
// Delete files from each storage config
|
|
290
|
-
for (const [configId, keys] of filesByConfig){
|
|
291
|
-
|
|
353
|
+
for (const [configId, { keys, location }] of filesByConfig){
|
|
354
|
+
// For local files with old key format (no '/'), we need to prefix with basePath
|
|
355
|
+
let deleteKeys = keys;
|
|
356
|
+
if (location === _filelocationenum.FileLocationEnum.LOCAL && configId !== 'default') {
|
|
357
|
+
try {
|
|
358
|
+
const enableCompanyFeature = this.storageConfig.isCompanyFeatureEnabled();
|
|
359
|
+
const storageConfigEntity = enableCompanyFeature ? (await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../entities")))).StorageConfigWithCompany : (await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../entities")))).StorageConfig;
|
|
360
|
+
const storageConfigRepository = await this.dataSourceProvider.getRepository(storageConfigEntity);
|
|
361
|
+
const config = await storageConfigRepository.findOne({
|
|
362
|
+
where: {
|
|
363
|
+
id: configId
|
|
364
|
+
},
|
|
365
|
+
select: [
|
|
366
|
+
'id',
|
|
367
|
+
'config'
|
|
368
|
+
]
|
|
369
|
+
});
|
|
370
|
+
if (config && config.config?.basePath) {
|
|
371
|
+
const basePath = config.config.basePath.replace(/^\.\//, '');
|
|
372
|
+
// Convert old keys to new format
|
|
373
|
+
deleteKeys = keys.map((key)=>{
|
|
374
|
+
if (!key.includes('/')) {
|
|
375
|
+
return `${basePath}/${key}`;
|
|
376
|
+
}
|
|
377
|
+
return key;
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
} catch (error) {
|
|
381
|
+
this.logger.warn(`Failed to get basePath for delete: ${error}`);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
await this.uploadService.deleteMultipleFile(deleteKeys, configId === 'default' ? undefined : configId, user ?? undefined, location);
|
|
292
385
|
}
|
|
293
386
|
}
|
|
294
387
|
}
|
|
@@ -320,13 +413,43 @@ let FileManagerService = class FileManagerService extends _classes.RequestScoped
|
|
|
320
413
|
shouldUpdate = true;
|
|
321
414
|
} catch (error) {
|
|
322
415
|
this.logger.error(`Failed to generate URL for file ${file.id}: ${error?.message || 'Unknown error'}`);
|
|
323
|
-
// Use fallback URL
|
|
324
|
-
|
|
416
|
+
// Use fallback URL with appUrl from config
|
|
417
|
+
const baseUrl = this.getFileBaseUrl(protocol, host);
|
|
418
|
+
file.url = `${baseUrl}/storage/upload/file/${file.key}`;
|
|
325
419
|
}
|
|
326
420
|
}
|
|
327
421
|
// SFTP/Local files - always construct full URL (no expiry, but need full path)
|
|
328
422
|
if (file.location === _filelocationenum.FileLocationEnum.SFTP || file.location === _filelocationenum.FileLocationEnum.LOCAL) {
|
|
329
|
-
|
|
423
|
+
// For backward compatibility: if key doesn't include basePath, look it up from config
|
|
424
|
+
let fileKey = file.key;
|
|
425
|
+
// Check if key looks like it's missing the basePath (old format)
|
|
426
|
+
// Old format: "uuid-filename.png"
|
|
427
|
+
// New format: "uploads/uuid-filename.png" or "uploads/company1/uuid-filename.png"
|
|
428
|
+
if (!fileKey.includes('/') && file.storageConfigId) {
|
|
429
|
+
try {
|
|
430
|
+
const enableCompanyFeature = this.storageConfig.isCompanyFeatureEnabled();
|
|
431
|
+
const storageConfigEntity = enableCompanyFeature ? (await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../entities")))).StorageConfigWithCompany : (await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../entities")))).StorageConfig;
|
|
432
|
+
const storageConfigRepository = await this.dataSourceProvider.getRepository(storageConfigEntity);
|
|
433
|
+
const config = await storageConfigRepository.findOne({
|
|
434
|
+
where: {
|
|
435
|
+
id: file.storageConfigId
|
|
436
|
+
},
|
|
437
|
+
select: [
|
|
438
|
+
'id',
|
|
439
|
+
'config'
|
|
440
|
+
]
|
|
441
|
+
});
|
|
442
|
+
if (config && config.config?.basePath) {
|
|
443
|
+
const basePath = config.config.basePath.replace(/^\.\//, ''); // Remove leading ./
|
|
444
|
+
fileKey = `${basePath}/${file.key}`;
|
|
445
|
+
this.logger.debug(`Prefixed old key with basePath: ${fileKey}`);
|
|
446
|
+
}
|
|
447
|
+
} catch (error) {
|
|
448
|
+
this.logger.warn(`Failed to get basePath for file ${file.id}: ${error}`);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
const baseUrl = this.getFileBaseUrl(protocol, host);
|
|
452
|
+
const expectedUrl = `${baseUrl}/storage/upload/file/${fileKey}`;
|
|
330
453
|
if (file.url !== expectedUrl) {
|
|
331
454
|
file.url = expectedUrl;
|
|
332
455
|
shouldUpdate = true;
|
|
@@ -337,7 +460,9 @@ let FileManagerService = class FileManagerService extends _classes.RequestScoped
|
|
|
337
460
|
id: file.id,
|
|
338
461
|
name: file.name,
|
|
339
462
|
contentType: file.contentType,
|
|
340
|
-
url: file.url || ''
|
|
463
|
+
url: file.url || '',
|
|
464
|
+
location: file.location,
|
|
465
|
+
storageConfigId: file.storageConfigId || undefined
|
|
341
466
|
};
|
|
342
467
|
}));
|
|
343
468
|
// Save only changed records
|
|
@@ -42,46 +42,24 @@ function _ts_param(paramIndex, decorator) {
|
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
44
|
let FolderService = class FolderService extends _classes.RequestScopedApiService {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
* @returns Folder or FolderWithCompany based on configuration
|
|
48
|
-
*/ resolveEntity() {
|
|
49
|
-
const enableCompanyFeature = this.storageConfig.isCompanyFeatureEnabled();
|
|
50
|
-
return enableCompanyFeature ? _entities.FolderWithCompany : _entities.Folder;
|
|
45
|
+
resolveEntity() {
|
|
46
|
+
return this.storageConfig.isCompanyFeatureEnabled() ? _entities.FolderWithCompany : _entities.Folder;
|
|
51
47
|
}
|
|
52
|
-
|
|
53
|
-
* Get DataSource provider for this service
|
|
54
|
-
* @returns StorageDataSourceProvider instance
|
|
55
|
-
*/ getDataSourceProvider() {
|
|
48
|
+
getDataSourceProvider() {
|
|
56
49
|
return this.dataSourceProvider;
|
|
57
50
|
}
|
|
51
|
+
// Entity Conversion
|
|
58
52
|
async convertSingleDtoToEntity(dto, user) {
|
|
59
|
-
|
|
60
|
-
//
|
|
61
|
-
if (
|
|
62
|
-
|
|
63
|
-
where: {
|
|
64
|
-
id: dto.id
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
if (!dbData) {
|
|
68
|
-
throw new _common.NotFoundException('No such entity data found for update! Please, Try Again.');
|
|
69
|
-
}
|
|
70
|
-
folder = dbData;
|
|
71
|
-
}
|
|
72
|
-
// Set company/branch IDs if company feature is enabled
|
|
73
|
-
folder = {
|
|
74
|
-
...folder,
|
|
75
|
-
...dto
|
|
76
|
-
};
|
|
77
|
-
// Only set company fields if they exist on the entity (when company feature is enabled)
|
|
78
|
-
if ('companyId' in folder) {
|
|
79
|
-
folder.companyId = user?.companyId ?? null;
|
|
53
|
+
const entity = await super.convertSingleDtoToEntity(dto, user);
|
|
54
|
+
// Set companyId from user context if company feature enabled
|
|
55
|
+
if (this.storageConfig.isCompanyFeatureEnabled()) {
|
|
56
|
+
entity.companyId = user?.companyId ?? null;
|
|
80
57
|
}
|
|
81
|
-
return
|
|
58
|
+
return entity;
|
|
82
59
|
}
|
|
60
|
+
// Query Customization
|
|
83
61
|
async getSelectQuery(query, _user, select) {
|
|
84
|
-
if (!select
|
|
62
|
+
if (!select?.length) {
|
|
85
63
|
select = [
|
|
86
64
|
'id',
|
|
87
65
|
'name',
|
|
@@ -89,35 +67,26 @@ let FolderService = class FolderService extends _classes.RequestScopedApiService
|
|
|
89
67
|
'createdAt',
|
|
90
68
|
'deletedAt'
|
|
91
69
|
];
|
|
70
|
+
if (this.storageConfig.isCompanyFeatureEnabled()) {
|
|
71
|
+
select.push('companyId');
|
|
72
|
+
}
|
|
92
73
|
}
|
|
93
|
-
|
|
94
|
-
// Add company context fields if company feature is enabled
|
|
95
|
-
// The entity will have these fields only if company feature is enabled
|
|
96
|
-
if (this.storageConfig.isCompanyFeatureEnabled()) {
|
|
97
|
-
selectFields.push('folder.companyId');
|
|
98
|
-
}
|
|
99
|
-
query.select(selectFields);
|
|
74
|
+
query.select(select.map((f)=>`${this.entityName}.${f}`));
|
|
100
75
|
return {
|
|
101
76
|
query,
|
|
102
77
|
isRaw: false
|
|
103
78
|
};
|
|
104
79
|
}
|
|
105
|
-
|
|
106
|
-
* Override: Extra query manipulation - Auto-filter by user's company
|
|
107
|
-
*/ async getExtraManipulateQuery(query, filterDto, user) {
|
|
80
|
+
async getExtraManipulateQuery(query, filterDto, user) {
|
|
108
81
|
const result = await super.getExtraManipulateQuery(query, filterDto, user);
|
|
109
|
-
|
|
110
|
-
const enableCompanyFeature = this.storageConfig.isCompanyFeatureEnabled();
|
|
111
|
-
if (enableCompanyFeature && user?.companyId) {
|
|
82
|
+
if (this.storageConfig.isCompanyFeatureEnabled() && user?.companyId) {
|
|
112
83
|
query.andWhere('folder.companyId = :companyId', {
|
|
113
84
|
companyId: user.companyId
|
|
114
85
|
});
|
|
115
86
|
}
|
|
116
87
|
return result;
|
|
117
88
|
}
|
|
118
|
-
// NOTE: @Inject() required for bundled code - type metadata may be lost during esbuild
|
|
119
89
|
constructor(cacheManager, utilsService, storageConfig, dataSourceProvider){
|
|
120
|
-
// Repository will be set asynchronously by RequestScopedApiService
|
|
121
90
|
super('folder', null, cacheManager, utilsService, FolderService.name, true), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "storageConfig", void 0), _define_property(this, "dataSourceProvider", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.storageConfig = storageConfig, this.dataSourceProvider = dataSourceProvider;
|
|
122
91
|
}
|
|
123
92
|
};
|
|
@@ -83,10 +83,8 @@ function _ts_param(paramIndex, decorator) {
|
|
|
83
83
|
};
|
|
84
84
|
}
|
|
85
85
|
let StorageDataSourceProvider = class StorageDataSourceProvider extends _modules.MultiTenantDataSourceService {
|
|
86
|
-
//
|
|
87
|
-
/**
|
|
88
|
-
* Build parent options from StorageModuleOptions
|
|
89
|
-
*/ static buildParentOptions(options) {
|
|
86
|
+
// Factory Methods
|
|
87
|
+
/** Build parent options from StorageModuleOptions */ static buildParentOptions(options) {
|
|
90
88
|
return {
|
|
91
89
|
bootstrapAppConfig: options.bootstrapAppConfig,
|
|
92
90
|
defaultDatabaseConfig: options.config?.defaultDatabaseConfig,
|
|
@@ -94,10 +92,8 @@ let StorageDataSourceProvider = class StorageDataSourceProvider extends _modules
|
|
|
94
92
|
tenants: options.config?.tenants
|
|
95
93
|
};
|
|
96
94
|
}
|
|
97
|
-
//
|
|
98
|
-
/**
|
|
99
|
-
* Get global enable company feature flag
|
|
100
|
-
*/ getEnableCompanyFeature() {
|
|
95
|
+
// Feature Flags
|
|
96
|
+
/** Get global enable company feature flag */ getEnableCompanyFeature() {
|
|
101
97
|
return this.storageOptions.bootstrapAppConfig?.enableCompanyFeature ?? false;
|
|
102
98
|
}
|
|
103
99
|
/**
|
|
@@ -111,11 +107,11 @@ let StorageDataSourceProvider = class StorageDataSourceProvider extends _modules
|
|
|
111
107
|
*/ getEnableCompanyFeatureForCurrentTenant() {
|
|
112
108
|
return this.getEnableCompanyFeatureForTenant(this.getCurrentTenant() ?? undefined);
|
|
113
109
|
}
|
|
114
|
-
//
|
|
110
|
+
// Entity Management
|
|
115
111
|
/**
|
|
116
|
-
* Get storage entities for migrations based on company feature flag
|
|
117
|
-
*
|
|
118
|
-
*
|
|
112
|
+
* Get storage entities for migrations based on company feature flag.
|
|
113
|
+
* For TypeORM repositories, we always use the base entities (FileManager, etc.)
|
|
114
|
+
* but for migrations, we need the correct entity based on the feature flag.
|
|
119
115
|
*/ async getStorageEntities(enableCompanyFeature) {
|
|
120
116
|
const enable = enableCompanyFeature ?? this.getEnableCompanyFeature();
|
|
121
117
|
const { FileManager, Folder, StorageConfig } = await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../entities")));
|
|
@@ -135,10 +131,8 @@ let StorageDataSourceProvider = class StorageDataSourceProvider extends _modules
|
|
|
135
131
|
StorageConfig
|
|
136
132
|
];
|
|
137
133
|
}
|
|
138
|
-
//
|
|
139
|
-
/**
|
|
140
|
-
* Override to dynamically set entities based on tenant config
|
|
141
|
-
*/ async createDataSourceFromConfig(config) {
|
|
134
|
+
// Overrides
|
|
135
|
+
/** Override to dynamically set entities based on tenant config */ async createDataSourceFromConfig(config) {
|
|
142
136
|
const currentTenant = this.getCurrentTenant();
|
|
143
137
|
const enableCompanyFeature = this.getEnableCompanyFeatureForTenant(currentTenant ?? undefined);
|
|
144
138
|
const entities = await this.getStorageEntities(enableCompanyFeature);
|
|
@@ -42,34 +42,24 @@ function _ts_param(paramIndex, decorator) {
|
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
44
|
let StorageProviderConfigService = class StorageProviderConfigService extends _classes.RequestScopedApiService {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
* @returns StorageConfig or StorageConfigWithCompany based on configuration
|
|
48
|
-
*/ resolveEntity() {
|
|
49
|
-
const enableCompanyFeature = this.storageConfig.isCompanyFeatureEnabled();
|
|
50
|
-
return enableCompanyFeature ? _entities.StorageConfigWithCompany : _entities.StorageConfig;
|
|
45
|
+
resolveEntity() {
|
|
46
|
+
return this.storageConfig.isCompanyFeatureEnabled() ? _entities.StorageConfigWithCompany : _entities.StorageConfig;
|
|
51
47
|
}
|
|
52
|
-
|
|
53
|
-
* Get DataSource provider for this service
|
|
54
|
-
* @returns StorageDataSourceProvider instance
|
|
55
|
-
*/ getDataSourceProvider() {
|
|
48
|
+
getDataSourceProvider() {
|
|
56
49
|
return this.dataSourceProvider;
|
|
57
50
|
}
|
|
51
|
+
// Entity Conversion
|
|
58
52
|
async convertSingleDtoToEntity(dto, user) {
|
|
59
|
-
|
|
60
|
-
// Set
|
|
61
|
-
storageConfig
|
|
62
|
-
|
|
63
|
-
...dto
|
|
64
|
-
};
|
|
65
|
-
// Only set company fields if they exist on the entity (when company feature is enabled)
|
|
66
|
-
if ('companyId' in storageConfig) {
|
|
67
|
-
storageConfig.companyId = user?.companyId ?? null;
|
|
53
|
+
const entity = await super.convertSingleDtoToEntity(dto, user);
|
|
54
|
+
// Set companyId from user context if company feature enabled
|
|
55
|
+
if (this.storageConfig.isCompanyFeatureEnabled()) {
|
|
56
|
+
entity.companyId = user?.companyId ?? null;
|
|
68
57
|
}
|
|
69
|
-
return
|
|
58
|
+
return entity;
|
|
70
59
|
}
|
|
60
|
+
// Query Customization
|
|
71
61
|
async getSelectQuery(query, _user, select) {
|
|
72
|
-
if (!select
|
|
62
|
+
if (!select?.length) {
|
|
73
63
|
select = [
|
|
74
64
|
'id',
|
|
75
65
|
'name',
|
|
@@ -78,25 +68,19 @@ let StorageProviderConfigService = class StorageProviderConfigService extends _c
|
|
|
78
68
|
'createdAt',
|
|
79
69
|
'updatedAt'
|
|
80
70
|
];
|
|
81
|
-
// Add company fields if company feature is enabled
|
|
82
71
|
if (this.storageConfig.isCompanyFeatureEnabled()) {
|
|
83
72
|
select.push('companyId');
|
|
84
73
|
}
|
|
85
74
|
}
|
|
86
|
-
|
|
87
|
-
query.select(selectFields);
|
|
75
|
+
query.select(select.map((f)=>`${this.entityName}.${f}`));
|
|
88
76
|
return {
|
|
89
77
|
query,
|
|
90
78
|
isRaw: false
|
|
91
79
|
};
|
|
92
80
|
}
|
|
93
|
-
|
|
94
|
-
* Override: Extra query manipulation - Auto-filter by user's company
|
|
95
|
-
*/ async getExtraManipulateQuery(query, filterDto, user) {
|
|
81
|
+
async getExtraManipulateQuery(query, filterDto, user) {
|
|
96
82
|
const result = await super.getExtraManipulateQuery(query, filterDto, user);
|
|
97
|
-
|
|
98
|
-
const enableCompanyFeature = this.storageConfig.isCompanyFeatureEnabled();
|
|
99
|
-
if (enableCompanyFeature && user?.companyId) {
|
|
83
|
+
if (this.storageConfig.isCompanyFeatureEnabled() && user?.companyId) {
|
|
100
84
|
query.andWhere('storageConfig.companyId = :companyId', {
|
|
101
85
|
companyId: user.companyId
|
|
102
86
|
});
|
|
@@ -105,6 +89,18 @@ let StorageProviderConfigService = class StorageProviderConfigService extends _c
|
|
|
105
89
|
return result;
|
|
106
90
|
}
|
|
107
91
|
/**
|
|
92
|
+
* Find storage config by ID without throwing (returns null if not found)
|
|
93
|
+
* Uses direct repository query - bypasses company filtering
|
|
94
|
+
* Use for internal operations like file deletion where config ID is already known
|
|
95
|
+
*/ async findByIdDirect(id) {
|
|
96
|
+
await this.ensureRepositoryInitialized();
|
|
97
|
+
return await this.repository.findOne({
|
|
98
|
+
where: {
|
|
99
|
+
id
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
108
104
|
* Get default storage configuration (scoped to user's company if enabled)
|
|
109
105
|
* Falls back to any available config if 'default' not found
|
|
110
106
|
*/ async getDefaultConfig(user) {
|
|
@@ -150,9 +146,7 @@ let StorageProviderConfigService = class StorageProviderConfigService extends _c
|
|
|
150
146
|
where
|
|
151
147
|
});
|
|
152
148
|
}
|
|
153
|
-
// NOTE: @Inject() required for bundled code - type metadata may be lost during esbuild
|
|
154
149
|
constructor(cacheManager, utilsService, storageConfig, dataSourceProvider){
|
|
155
|
-
// Repository will be set asynchronously by RequestScopedApiService
|
|
156
150
|
super('storageConfig', null, cacheManager, utilsService, StorageProviderConfigService.name, true), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "storageConfig", void 0), _define_property(this, "dataSourceProvider", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.storageConfig = storageConfig, this.dataSourceProvider = dataSourceProvider;
|
|
157
151
|
}
|
|
158
152
|
};
|