@flusys/nestjs-storage 1.0.0-beta → 1.0.0
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 +174 -13
- package/cjs/config/index.js +0 -1
- package/cjs/config/storage.constants.js +0 -17
- package/cjs/controllers/file-manager.controller.js +44 -1
- package/cjs/controllers/folder.controller.js +44 -1
- package/cjs/controllers/storage-config.controller.js +44 -1
- package/cjs/controllers/upload.controller.js +18 -29
- package/cjs/docs/storage-swagger.config.js +24 -136
- package/cjs/dtos/file-manager.dto.js +71 -35
- package/cjs/dtos/folder.dto.js +15 -9
- package/cjs/dtos/storage-config.dto.js +25 -66
- package/cjs/dtos/upload.dto.js +24 -17
- package/cjs/entities/file-manager-with-company.entity.js +3 -4
- package/cjs/entities/file-manager.entity.js +71 -3
- package/cjs/entities/folder-with-company.entity.js +3 -4
- package/cjs/entities/folder.entity.js +19 -3
- package/cjs/entities/index.js +9 -10
- package/cjs/entities/storage-config-with-company.entity.js +3 -4
- package/cjs/entities/storage-config.entity.js +73 -3
- package/cjs/interfaces/index.js +0 -1
- package/cjs/middlewares/file-serve.middleware.js +113 -100
- package/cjs/modules/storage.module.js +82 -136
- package/cjs/providers/azure-provider.optional.js +10 -38
- package/cjs/providers/local-provider.js +38 -31
- package/cjs/providers/s3-provider.optional.js +19 -40
- package/cjs/providers/storage-factory.service.js +54 -99
- package/cjs/providers/storage-provider.registry.js +8 -18
- package/cjs/services/file-manager.service.js +238 -323
- package/cjs/services/folder.service.js +8 -11
- package/cjs/services/index.js +1 -0
- package/cjs/{config → services}/storage-config.service.js +32 -76
- package/cjs/services/storage-datasource.provider.js +16 -26
- package/cjs/services/storage-provider-config.service.js +21 -38
- package/cjs/services/upload.service.js +72 -88
- package/cjs/utils/file-validator.util.js +458 -0
- package/cjs/utils/image-compressor.util.js +3 -8
- package/config/index.d.ts +0 -1
- package/config/storage.constants.d.ts +0 -8
- package/controllers/upload.controller.d.ts +3 -6
- package/dtos/file-manager.dto.d.ts +13 -7
- package/dtos/folder.dto.d.ts +5 -5
- package/dtos/storage-config.dto.d.ts +13 -14
- package/entities/file-manager-with-company.entity.d.ts +2 -2
- package/entities/file-manager.entity.d.ts +11 -2
- package/entities/folder-with-company.entity.d.ts +2 -2
- package/entities/folder.entity.d.ts +4 -2
- package/entities/index.d.ts +3 -4
- package/entities/storage-config-with-company.entity.d.ts +2 -2
- package/entities/storage-config.entity.d.ts +7 -2
- package/fesm/config/index.js +0 -1
- package/fesm/config/storage.constants.js +0 -8
- package/fesm/controllers/file-manager.controller.js +45 -2
- package/fesm/controllers/folder.controller.js +45 -2
- package/fesm/controllers/storage-config.controller.js +45 -2
- package/fesm/controllers/upload.controller.js +19 -30
- package/fesm/docs/storage-swagger.config.js +27 -142
- package/fesm/dtos/file-manager.dto.js +72 -36
- package/fesm/dtos/folder.dto.js +16 -10
- package/fesm/dtos/storage-config.dto.js +29 -76
- package/fesm/dtos/upload.dto.js +25 -19
- package/fesm/entities/file-manager-with-company.entity.js +3 -4
- package/fesm/entities/file-manager.entity.js +72 -4
- package/fesm/entities/folder-with-company.entity.js +3 -4
- package/fesm/entities/folder.entity.js +20 -4
- package/fesm/entities/index.js +5 -13
- package/fesm/entities/storage-config-with-company.entity.js +3 -4
- package/fesm/entities/storage-config.entity.js +74 -4
- package/fesm/interfaces/index.js +0 -1
- package/fesm/interfaces/storage-config.interface.js +1 -3
- package/fesm/middlewares/file-serve.middleware.js +114 -101
- package/fesm/modules/storage.module.js +83 -136
- package/fesm/providers/azure-provider.optional.js +11 -42
- package/fesm/providers/local-provider.js +38 -31
- package/fesm/providers/s3-provider.optional.js +20 -44
- package/fesm/providers/storage-factory.service.js +52 -97
- package/fesm/providers/storage-provider.registry.js +10 -20
- package/fesm/services/file-manager.service.js +237 -322
- package/fesm/services/folder.service.js +6 -9
- package/fesm/services/index.js +1 -0
- package/fesm/{config → services}/storage-config.service.js +32 -76
- package/fesm/services/storage-datasource.provider.js +16 -26
- package/fesm/services/storage-provider-config.service.js +19 -36
- package/fesm/services/upload.service.js +71 -87
- package/fesm/utils/file-validator.util.js +451 -0
- package/fesm/utils/image-compressor.util.js +3 -8
- package/interfaces/file-manager.interface.d.ts +7 -4
- package/interfaces/index.d.ts +0 -1
- package/interfaces/storage-config.interface.d.ts +3 -22
- package/interfaces/storage-module-options.interface.d.ts +0 -5
- package/middlewares/file-serve.middleware.d.ts +9 -1
- package/modules/storage.module.d.ts +1 -2
- package/package.json +6 -6
- package/providers/azure-provider.optional.d.ts +8 -6
- package/providers/local-provider.d.ts +2 -7
- package/providers/s3-provider.optional.d.ts +9 -7
- package/providers/storage-factory.service.d.ts +8 -9
- package/providers/storage-provider.registry.d.ts +4 -4
- package/services/file-manager.service.d.ts +23 -16
- package/services/folder.service.d.ts +4 -4
- package/services/index.d.ts +1 -0
- package/services/storage-config.service.d.ts +24 -0
- package/services/storage-datasource.provider.d.ts +3 -4
- package/services/storage-provider-config.service.d.ts +5 -6
- package/services/upload.service.d.ts +5 -5
- package/utils/file-validator.util.d.ts +19 -0
- package/cjs/entities/file-manager-base.entity.js +0 -115
- package/cjs/entities/folder-base.entity.js +0 -55
- package/cjs/entities/storage-config-base.entity.js +0 -64
- package/cjs/interfaces/file-upload-response.interface.js +0 -4
- package/config/storage-config.service.d.ts +0 -22
- package/entities/file-manager-base.entity.d.ts +0 -13
- package/entities/folder-base.entity.d.ts +0 -5
- package/entities/storage-config-base.entity.d.ts +0 -7
- package/fesm/entities/file-manager-base.entity.js +0 -108
- package/fesm/entities/folder-base.entity.js +0 -48
- package/fesm/entities/storage-config-base.entity.js +0 -57
- package/fesm/interfaces/file-upload-response.interface.js +0 -1
- package/interfaces/file-upload-response.interface.d.ts +0 -6
|
@@ -27,8 +27,9 @@ function _ts_param(paramIndex, decorator) {
|
|
|
27
27
|
}
|
|
28
28
|
import { RequestScopedApiService, HybridCache } from '@flusys/nestjs-shared/classes';
|
|
29
29
|
import { UtilsService } from '@flusys/nestjs-shared/modules';
|
|
30
|
+
import { applyCompanyFilter } from '@flusys/nestjs-shared/utils';
|
|
30
31
|
import { Inject, Injectable, Scope } from '@nestjs/common';
|
|
31
|
-
import { StorageConfigService } from '
|
|
32
|
+
import { StorageConfigService } from './storage-config.service';
|
|
32
33
|
import { Folder, FolderWithCompany } from '../entities';
|
|
33
34
|
import { StorageDataSourceProvider } from './storage-datasource.provider';
|
|
34
35
|
export class FolderService extends RequestScopedApiService {
|
|
@@ -38,16 +39,13 @@ export class FolderService extends RequestScopedApiService {
|
|
|
38
39
|
getDataSourceProvider() {
|
|
39
40
|
return this.dataSourceProvider;
|
|
40
41
|
}
|
|
41
|
-
// Entity Conversion
|
|
42
42
|
async convertSingleDtoToEntity(dto, user) {
|
|
43
43
|
const entity = await super.convertSingleDtoToEntity(dto, user);
|
|
44
|
-
// Set companyId from user context if company feature enabled
|
|
45
44
|
if (this.storageConfig.isCompanyFeatureEnabled()) {
|
|
46
45
|
entity.companyId = user?.companyId ?? null;
|
|
47
46
|
}
|
|
48
47
|
return entity;
|
|
49
48
|
}
|
|
50
|
-
// Query Customization
|
|
51
49
|
async getSelectQuery(query, _user, select) {
|
|
52
50
|
if (!select?.length) {
|
|
53
51
|
select = [
|
|
@@ -69,11 +67,10 @@ export class FolderService extends RequestScopedApiService {
|
|
|
69
67
|
}
|
|
70
68
|
async getExtraManipulateQuery(query, filterDto, user) {
|
|
71
69
|
const result = await super.getExtraManipulateQuery(query, filterDto, user);
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
70
|
+
applyCompanyFilter(query, {
|
|
71
|
+
isCompanyFeatureEnabled: this.storageConfig.isCompanyFeatureEnabled(),
|
|
72
|
+
entityAlias: 'folder'
|
|
73
|
+
}, user);
|
|
77
74
|
return result;
|
|
78
75
|
}
|
|
79
76
|
constructor(cacheManager, utilsService, storageConfig, dataSourceProvider){
|
package/fesm/services/index.js
CHANGED
|
@@ -27,115 +27,71 @@ function _ts_param(paramIndex, decorator) {
|
|
|
27
27
|
}
|
|
28
28
|
import { Inject, Injectable } from '@nestjs/common';
|
|
29
29
|
import { StorageModuleOptions } from '../interfaces';
|
|
30
|
-
import { STORAGE_MODULE_OPTIONS, DEFAULT_MAX_FILE_SIZE, DEFAULT_ALLOWED_FILE_TYPES } from '
|
|
30
|
+
import { STORAGE_MODULE_OPTIONS, DEFAULT_MAX_FILE_SIZE, DEFAULT_ALLOWED_FILE_TYPES } from '../config/storage.constants';
|
|
31
|
+
const BYTES_PER_MB = 1024 * 1024;
|
|
32
|
+
const DEFAULT_LOCAL_PATH = './uploads';
|
|
33
|
+
const DEFAULT_PORT = '3000';
|
|
31
34
|
export class StorageConfigService {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
*/ isCompanyFeatureEnabled() {
|
|
35
|
+
// ─── IModuleConfigService Implementation ────────────────────────────────────
|
|
36
|
+
isCompanyFeatureEnabled() {
|
|
35
37
|
return this.options.bootstrapAppConfig?.enableCompanyFeature ?? false;
|
|
36
38
|
}
|
|
37
|
-
|
|
38
|
-
* Get database mode
|
|
39
|
-
*/ getDatabaseMode() {
|
|
39
|
+
getDatabaseMode() {
|
|
40
40
|
return this.options.bootstrapAppConfig?.databaseMode ?? 'single';
|
|
41
41
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
isMultiTenant() {
|
|
43
|
+
return this.getDatabaseMode() === 'multi-tenant';
|
|
44
|
+
}
|
|
45
|
+
// ─── Config Getters ─────────────────────────────────────────────────────────
|
|
46
|
+
getMaxFileSize() {
|
|
45
47
|
return this.options.config?.maxFileSize ?? DEFAULT_MAX_FILE_SIZE;
|
|
46
48
|
}
|
|
47
|
-
|
|
48
|
-
* Get allowed file types (MIME types or patterns)
|
|
49
|
-
*/ getAllowedFileTypes() {
|
|
49
|
+
getAllowedFileTypes() {
|
|
50
50
|
return this.options.config?.allowedFileTypes ?? DEFAULT_ALLOWED_FILE_TYPES;
|
|
51
51
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
getOptions() {
|
|
53
|
+
return this.options;
|
|
54
|
+
}
|
|
55
|
+
getDefaultLocalStoragePath() {
|
|
56
|
+
return this.options.config?.localStoragePath ?? DEFAULT_LOCAL_PATH;
|
|
57
|
+
}
|
|
58
|
+
getAppUrl() {
|
|
59
|
+
return this.options.config?.appUrl ?? process.env.APP_URL ?? `http://localhost:${process.env.PORT ?? DEFAULT_PORT}`;
|
|
60
|
+
}
|
|
61
|
+
// ─── Validation Methods ─────────────────────────────────────────────────────
|
|
62
|
+
isFileTypeAllowed(mimeType) {
|
|
55
63
|
const allowedTypes = this.getAllowedFileTypes();
|
|
56
|
-
// If wildcard, allow all
|
|
57
64
|
if (allowedTypes.includes('*/*')) {
|
|
58
65
|
return true;
|
|
59
66
|
}
|
|
60
|
-
|
|
61
|
-
return allowedTypes.some((allowedType)=>{
|
|
62
|
-
if (allowedType.endsWith('/*')) {
|
|
63
|
-
const prefix = allowedType.slice(0, -2);
|
|
64
|
-
return mimeType.startsWith(prefix);
|
|
65
|
-
}
|
|
66
|
-
return allowedType === mimeType;
|
|
67
|
-
});
|
|
67
|
+
return allowedTypes.some((type)=>type.endsWith('/*') ? mimeType.startsWith(type.slice(0, -2)) : type === mimeType);
|
|
68
68
|
}
|
|
69
|
-
|
|
70
|
-
* Validate file size
|
|
71
|
-
*/ validateFileSize(fileSize) {
|
|
69
|
+
validateFileSize(fileSize) {
|
|
72
70
|
const maxSize = this.getMaxFileSize();
|
|
73
71
|
if (fileSize > maxSize) {
|
|
74
|
-
const maxSizeMB = (maxSize / (1024 * 1024)).toFixed(2);
|
|
75
|
-
const fileSizeMB = (fileSize / (1024 * 1024)).toFixed(2);
|
|
76
72
|
return {
|
|
77
73
|
valid: false,
|
|
78
|
-
message: `File size (${
|
|
74
|
+
message: `File size (${this.toMB(fileSize)}MB) exceeds maximum ${this.toMB(maxSize)}MB`
|
|
79
75
|
};
|
|
80
76
|
}
|
|
81
77
|
return {
|
|
82
78
|
valid: true
|
|
83
79
|
};
|
|
84
80
|
}
|
|
85
|
-
|
|
86
|
-
* Validate file type
|
|
87
|
-
*/ validateFileType(mimeType) {
|
|
81
|
+
validateFileType(mimeType) {
|
|
88
82
|
if (!this.isFileTypeAllowed(mimeType)) {
|
|
89
|
-
const allowedTypes = this.getAllowedFileTypes();
|
|
90
83
|
return {
|
|
91
84
|
valid: false,
|
|
92
|
-
message: `File type "${mimeType}"
|
|
85
|
+
message: `File type "${mimeType}" not allowed. Allowed: ${this.getAllowedFileTypes().join(', ')}`
|
|
93
86
|
};
|
|
94
87
|
}
|
|
95
88
|
return {
|
|
96
89
|
valid: true
|
|
97
90
|
};
|
|
98
91
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
return this.options.config?.defaultDatabaseConfig;
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Get all options
|
|
106
|
-
*/ getOptions() {
|
|
107
|
-
return this.options;
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Get default local storage base path
|
|
111
|
-
* Used for serving local files without database lookup
|
|
112
|
-
* Falls back to './uploads' if not configured
|
|
113
|
-
*/ getDefaultLocalStoragePath() {
|
|
114
|
-
// Check if localStoragePath is configured in module options
|
|
115
|
-
const configuredPath = this.options.config?.localStoragePath;
|
|
116
|
-
if (configuredPath) {
|
|
117
|
-
return configuredPath;
|
|
118
|
-
}
|
|
119
|
-
// Default to ./uploads in the project root
|
|
120
|
-
return './uploads';
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Get application base URL for generating file URLs
|
|
124
|
-
* - First tries module config
|
|
125
|
-
* - Falls back to APP_URL env var
|
|
126
|
-
* - Finally constructs from PORT env var
|
|
127
|
-
*/ getAppUrl() {
|
|
128
|
-
// Try from module config first
|
|
129
|
-
if (this.options.config?.appUrl) {
|
|
130
|
-
return this.options.config.appUrl;
|
|
131
|
-
}
|
|
132
|
-
// Fallback: read directly from environment
|
|
133
|
-
if (process.env.APP_URL) {
|
|
134
|
-
return process.env.APP_URL;
|
|
135
|
-
}
|
|
136
|
-
// Last resort: construct from PORT
|
|
137
|
-
const port = process.env.PORT || '3000';
|
|
138
|
-
return `http://localhost:${port}`;
|
|
92
|
+
// ─── Private Helpers ────────────────────────────────────────────────────────
|
|
93
|
+
toMB(bytes) {
|
|
94
|
+
return (bytes / BYTES_PER_MB).toFixed(2);
|
|
139
95
|
}
|
|
140
96
|
constructor(options){
|
|
141
97
|
_define_property(this, "options", void 0);
|
|
@@ -29,8 +29,7 @@ import { MultiTenantDataSourceService } from '@flusys/nestjs-shared/modules';
|
|
|
29
29
|
import { Inject, Injectable, Logger, Optional, Scope } from '@nestjs/common';
|
|
30
30
|
import { REQUEST } from '@nestjs/core';
|
|
31
31
|
import { Request } from 'express';
|
|
32
|
-
import {
|
|
33
|
-
import { STORAGE_MODULE_OPTIONS } from '../config/storage.constants';
|
|
32
|
+
import { StorageConfigService } from './storage-config.service';
|
|
34
33
|
export class StorageDataSourceProvider extends MultiTenantDataSourceService {
|
|
35
34
|
// Factory Methods
|
|
36
35
|
/** Build parent options from StorageModuleOptions */ static buildParentOptions(options) {
|
|
@@ -42,14 +41,11 @@ export class StorageDataSourceProvider extends MultiTenantDataSourceService {
|
|
|
42
41
|
};
|
|
43
42
|
}
|
|
44
43
|
// Feature Flags
|
|
45
|
-
/** Get global enable company feature flag */ getEnableCompanyFeature() {
|
|
46
|
-
return this.storageOptions.bootstrapAppConfig?.enableCompanyFeature ?? false;
|
|
47
|
-
}
|
|
48
44
|
/**
|
|
49
45
|
* Get enable company feature for specific tenant
|
|
50
46
|
* Falls back to global setting if not specified per-tenant
|
|
51
47
|
*/ getEnableCompanyFeatureForTenant(tenant) {
|
|
52
|
-
return tenant?.enableCompanyFeature ?? this.
|
|
48
|
+
return tenant?.enableCompanyFeature ?? this.configService.isCompanyFeatureEnabled();
|
|
53
49
|
}
|
|
54
50
|
/**
|
|
55
51
|
* Get enable company feature for current request context
|
|
@@ -62,22 +58,16 @@ export class StorageDataSourceProvider extends MultiTenantDataSourceService {
|
|
|
62
58
|
* For TypeORM repositories, we always use the base entities (FileManager, etc.)
|
|
63
59
|
* but for migrations, we need the correct entity based on the feature flag.
|
|
64
60
|
*/ async getStorageEntities(enableCompanyFeature) {
|
|
65
|
-
const enable = enableCompanyFeature ?? this.
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
];
|
|
76
|
-
}
|
|
77
|
-
return [
|
|
78
|
-
FileManager,
|
|
79
|
-
Folder,
|
|
80
|
-
StorageConfig
|
|
61
|
+
const enable = enableCompanyFeature ?? this.configService.isCompanyFeatureEnabled();
|
|
62
|
+
const entities = await import('../entities');
|
|
63
|
+
return enable ? [
|
|
64
|
+
entities.FileManagerWithCompany,
|
|
65
|
+
entities.FolderWithCompany,
|
|
66
|
+
entities.StorageConfigWithCompany
|
|
67
|
+
] : [
|
|
68
|
+
entities.FileManager,
|
|
69
|
+
entities.Folder,
|
|
70
|
+
entities.StorageConfig
|
|
81
71
|
];
|
|
82
72
|
}
|
|
83
73
|
// Overrides
|
|
@@ -138,8 +128,8 @@ export class StorageDataSourceProvider extends MultiTenantDataSourceService {
|
|
|
138
128
|
StorageDataSourceProvider.connectionLocks.delete(tenant.id);
|
|
139
129
|
}
|
|
140
130
|
}
|
|
141
|
-
constructor(
|
|
142
|
-
super(StorageDataSourceProvider.buildParentOptions(
|
|
131
|
+
constructor(configService, request){
|
|
132
|
+
super(StorageDataSourceProvider.buildParentOptions(configService.getOptions()), request), _define_property(this, "configService", void 0), _define_property(this, "logger", void 0), this.configService = configService, this.logger = new Logger(StorageDataSourceProvider.name);
|
|
143
133
|
}
|
|
144
134
|
}
|
|
145
135
|
// Override parent's static properties to have Storage-specific cache
|
|
@@ -153,12 +143,12 @@ StorageDataSourceProvider = _ts_decorate([
|
|
|
153
143
|
Injectable({
|
|
154
144
|
scope: Scope.REQUEST
|
|
155
145
|
}),
|
|
156
|
-
_ts_param(0, Inject(
|
|
146
|
+
_ts_param(0, Inject(StorageConfigService)),
|
|
157
147
|
_ts_param(1, Optional()),
|
|
158
148
|
_ts_param(1, Inject(REQUEST)),
|
|
159
149
|
_ts_metadata("design:type", Function),
|
|
160
150
|
_ts_metadata("design:paramtypes", [
|
|
161
|
-
typeof
|
|
151
|
+
typeof StorageConfigService === "undefined" ? Object : StorageConfigService,
|
|
162
152
|
typeof Request === "undefined" ? Object : Request
|
|
163
153
|
])
|
|
164
154
|
], StorageDataSourceProvider);
|
|
@@ -27,8 +27,9 @@ function _ts_param(paramIndex, decorator) {
|
|
|
27
27
|
}
|
|
28
28
|
import { RequestScopedApiService, HybridCache } from '@flusys/nestjs-shared/classes';
|
|
29
29
|
import { UtilsService } from '@flusys/nestjs-shared/modules';
|
|
30
|
+
import { applyCompanyFilter, buildCompanyWhereCondition } from '@flusys/nestjs-shared/utils';
|
|
30
31
|
import { Inject, Injectable, Scope } from '@nestjs/common';
|
|
31
|
-
import { StorageConfigService } from '
|
|
32
|
+
import { StorageConfigService } from './storage-config.service';
|
|
32
33
|
import { StorageConfig, StorageConfigWithCompany } from '../entities';
|
|
33
34
|
import { StorageDataSourceProvider } from './storage-datasource.provider';
|
|
34
35
|
export class StorageProviderConfigService extends RequestScopedApiService {
|
|
@@ -38,16 +39,13 @@ export class StorageProviderConfigService extends RequestScopedApiService {
|
|
|
38
39
|
getDataSourceProvider() {
|
|
39
40
|
return this.dataSourceProvider;
|
|
40
41
|
}
|
|
41
|
-
// Entity Conversion
|
|
42
42
|
async convertSingleDtoToEntity(dto, user) {
|
|
43
43
|
const entity = await super.convertSingleDtoToEntity(dto, user);
|
|
44
|
-
// Set companyId from user context if company feature enabled
|
|
45
44
|
if (this.storageConfig.isCompanyFeatureEnabled()) {
|
|
46
45
|
entity.companyId = user?.companyId ?? null;
|
|
47
46
|
}
|
|
48
47
|
return entity;
|
|
49
48
|
}
|
|
50
|
-
// Query Customization
|
|
51
49
|
async getSelectQuery(query, _user, select) {
|
|
52
50
|
if (!select?.length) {
|
|
53
51
|
select = [
|
|
@@ -55,6 +53,8 @@ export class StorageProviderConfigService extends RequestScopedApiService {
|
|
|
55
53
|
'name',
|
|
56
54
|
'storage',
|
|
57
55
|
'config',
|
|
56
|
+
'isActive',
|
|
57
|
+
'isDefault',
|
|
58
58
|
'createdAt',
|
|
59
59
|
'updatedAt'
|
|
60
60
|
];
|
|
@@ -70,19 +70,14 @@ export class StorageProviderConfigService extends RequestScopedApiService {
|
|
|
70
70
|
}
|
|
71
71
|
async getExtraManipulateQuery(query, filterDto, user) {
|
|
72
72
|
const result = await super.getExtraManipulateQuery(query, filterDto, user);
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
73
|
+
applyCompanyFilter(query, {
|
|
74
|
+
isCompanyFeatureEnabled: this.storageConfig.isCompanyFeatureEnabled(),
|
|
75
|
+
entityAlias: 'storageConfig'
|
|
76
|
+
}, user);
|
|
78
77
|
query.orderBy(`${this.entityName}.createdAt`, 'DESC');
|
|
79
78
|
return result;
|
|
80
79
|
}
|
|
81
|
-
|
|
82
|
-
* Find storage config by ID without throwing (returns null if not found)
|
|
83
|
-
* Uses direct repository query - bypasses company filtering
|
|
84
|
-
* Use for internal operations like file deletion where config ID is already known
|
|
85
|
-
*/ async findByIdDirect(id) {
|
|
80
|
+
async findByIdDirect(id) {
|
|
86
81
|
await this.ensureRepositoryInitialized();
|
|
87
82
|
return await this.repository.findOne({
|
|
88
83
|
where: {
|
|
@@ -90,21 +85,15 @@ export class StorageProviderConfigService extends RequestScopedApiService {
|
|
|
90
85
|
}
|
|
91
86
|
});
|
|
92
87
|
}
|
|
93
|
-
|
|
94
|
-
* Get default storage configuration (scoped to user's company if enabled)
|
|
95
|
-
* Falls back to any available config if 'default' not found
|
|
96
|
-
*/ async getDefaultConfig(user) {
|
|
88
|
+
async getDefaultConfig(user) {
|
|
97
89
|
await this.ensureRepositoryInitialized();
|
|
98
|
-
const baseWhere = {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
baseWhere.companyId = user.companyId;
|
|
102
|
-
}
|
|
103
|
-
// First try to find config named 'default'
|
|
90
|
+
const baseWhere = buildCompanyWhereCondition({
|
|
91
|
+
isActive: true
|
|
92
|
+
}, this.storageConfig.isCompanyFeatureEnabled(), user);
|
|
104
93
|
const defaultConfig = await this.repository.findOne({
|
|
105
94
|
where: {
|
|
106
95
|
...baseWhere,
|
|
107
|
-
|
|
96
|
+
isDefault: true
|
|
108
97
|
},
|
|
109
98
|
order: {
|
|
110
99
|
createdAt: 'ASC'
|
|
@@ -113,7 +102,6 @@ export class StorageProviderConfigService extends RequestScopedApiService {
|
|
|
113
102
|
if (defaultConfig) {
|
|
114
103
|
return defaultConfig;
|
|
115
104
|
}
|
|
116
|
-
// Fall back to any available config for this company/user
|
|
117
105
|
return await this.repository.findOne({
|
|
118
106
|
where: baseWhere,
|
|
119
107
|
order: {
|
|
@@ -121,17 +109,12 @@ export class StorageProviderConfigService extends RequestScopedApiService {
|
|
|
121
109
|
}
|
|
122
110
|
});
|
|
123
111
|
}
|
|
124
|
-
|
|
125
|
-
* Get storage configuration by type (scoped to user's company if enabled)
|
|
126
|
-
*/ async getConfigByType(storage, user) {
|
|
112
|
+
async getConfigByType(storage, user) {
|
|
127
113
|
await this.ensureRepositoryInitialized();
|
|
128
|
-
const where = {
|
|
129
|
-
storage
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if (this.storageConfig.isCompanyFeatureEnabled() && user?.companyId) {
|
|
133
|
-
where.companyId = user.companyId;
|
|
134
|
-
}
|
|
114
|
+
const where = buildCompanyWhereCondition({
|
|
115
|
+
storage,
|
|
116
|
+
isActive: true
|
|
117
|
+
}, this.storageConfig.isCompanyFeatureEnabled(), user);
|
|
135
118
|
return await this.repository.find({
|
|
136
119
|
where
|
|
137
120
|
});
|