@flusys/nestjs-storage 3.0.0 → 4.0.0-rc
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 +1 -1
- package/cjs/config/index.js +1 -0
- package/cjs/config/message-keys.js +90 -0
- package/cjs/controllers/file-manager.controller.js +7 -1
- package/cjs/controllers/folder.controller.js +1 -0
- package/cjs/controllers/storage-config.controller.js +1 -0
- package/cjs/controllers/upload.controller.js +9 -4
- package/cjs/middlewares/file-serve.middleware.js +39 -15
- package/cjs/modules/storage.module.js +2 -2
- package/cjs/providers/azure-provider.optional.js +8 -5
- package/cjs/providers/local-provider.js +16 -14
- package/cjs/providers/s3-provider.optional.js +8 -5
- package/cjs/providers/sftp-provider.optional.js +13 -11
- package/cjs/providers/storage-factory.service.js +19 -10
- package/cjs/services/file-manager.service.js +30 -23
- package/cjs/services/folder.service.js +2 -1
- package/cjs/services/storage-datasource.provider.js +6 -2
- package/cjs/services/storage-provider-config.service.js +2 -1
- package/cjs/services/upload.service.js +129 -79
- package/cjs/utils/file-validator.util.js +4 -22
- package/config/index.d.ts +1 -0
- package/config/message-keys.d.ts +114 -0
- package/controllers/folder.controller.d.ts +7 -7
- package/controllers/storage-config.controller.d.ts +7 -7
- package/controllers/upload.controller.d.ts +1 -1
- package/fesm/config/index.js +1 -0
- package/fesm/config/message-keys.js +64 -0
- package/fesm/controllers/file-manager.controller.js +7 -1
- package/fesm/controllers/folder.controller.js +1 -0
- package/fesm/controllers/storage-config.controller.js +1 -0
- package/fesm/controllers/upload.controller.js +9 -4
- package/fesm/middlewares/file-serve.middleware.js +40 -16
- package/fesm/modules/storage.module.js +2 -2
- package/fesm/providers/azure-provider.optional.js +9 -6
- package/fesm/providers/local-provider.js +28 -26
- package/fesm/providers/s3-provider.optional.js +9 -6
- package/fesm/providers/sftp-provider.optional.js +26 -24
- package/fesm/providers/storage-factory.service.js +20 -11
- package/fesm/services/file-manager.service.js +31 -24
- package/fesm/services/folder.service.js +2 -1
- package/fesm/services/storage-datasource.provider.js +7 -3
- package/fesm/services/storage-provider-config.service.js +2 -1
- package/fesm/services/upload.service.js +131 -81
- package/fesm/utils/file-validator.util.js +3 -21
- package/middlewares/file-serve.middleware.d.ts +0 -1
- package/package.json +3 -3
- package/providers/azure-provider.optional.d.ts +0 -1
- package/providers/local-provider.d.ts +0 -1
- package/providers/s3-provider.optional.d.ts +0 -1
- package/providers/sftp-provider.optional.d.ts +0 -1
- package/providers/storage-factory.service.d.ts +0 -1
- package/services/file-manager.service.d.ts +2 -2
- package/services/storage-datasource.provider.d.ts +0 -2
- package/services/upload.service.d.ts +0 -1
- package/utils/file-validator.util.d.ts +0 -1
package/config/index.d.ts
CHANGED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
export declare const FILE_MESSAGES: {
|
|
2
|
+
readonly CREATE_SUCCESS: "file.create.success";
|
|
3
|
+
readonly CREATE_MANY_SUCCESS: "file.create.many.success";
|
|
4
|
+
readonly GET_SUCCESS: "file.get.success";
|
|
5
|
+
readonly GET_ALL_SUCCESS: "file.get.all.success";
|
|
6
|
+
readonly UPDATE_SUCCESS: "file.update.success";
|
|
7
|
+
readonly UPDATE_MANY_SUCCESS: "file.update.many.success";
|
|
8
|
+
readonly DELETE_SUCCESS: "file.delete.success";
|
|
9
|
+
readonly RESTORE_SUCCESS: "file.restore.success";
|
|
10
|
+
readonly NOT_FOUND: "file.not.found";
|
|
11
|
+
readonly UPLOAD_SUCCESS: "file.upload.success";
|
|
12
|
+
readonly UPLOAD_MANY_SUCCESS: "file.upload.many.success";
|
|
13
|
+
readonly DOWNLOAD_SUCCESS: "file.download.success";
|
|
14
|
+
readonly MOVE_SUCCESS: "file.move.success";
|
|
15
|
+
readonly COPY_SUCCESS: "file.copy.success";
|
|
16
|
+
};
|
|
17
|
+
export declare const FOLDER_MESSAGES: {
|
|
18
|
+
readonly CREATE_SUCCESS: "folder.create.success";
|
|
19
|
+
readonly CREATE_MANY_SUCCESS: "folder.create.many.success";
|
|
20
|
+
readonly GET_SUCCESS: "folder.get.success";
|
|
21
|
+
readonly GET_ALL_SUCCESS: "folder.get.all.success";
|
|
22
|
+
readonly UPDATE_SUCCESS: "folder.update.success";
|
|
23
|
+
readonly UPDATE_MANY_SUCCESS: "folder.update.many.success";
|
|
24
|
+
readonly DELETE_SUCCESS: "folder.delete.success";
|
|
25
|
+
readonly RESTORE_SUCCESS: "folder.restore.success";
|
|
26
|
+
readonly NOT_FOUND: "folder.not.found";
|
|
27
|
+
readonly TREE_SUCCESS: "folder.tree.success";
|
|
28
|
+
readonly CONTENTS_SUCCESS: "folder.contents.success";
|
|
29
|
+
};
|
|
30
|
+
export declare const STORAGE_CONFIG_MESSAGES: {
|
|
31
|
+
readonly CREATE_SUCCESS: "storage.config.create.success";
|
|
32
|
+
readonly CREATE_MANY_SUCCESS: "storage.config.create.many.success";
|
|
33
|
+
readonly GET_SUCCESS: "storage.config.get.success";
|
|
34
|
+
readonly GET_ALL_SUCCESS: "storage.config.get.all.success";
|
|
35
|
+
readonly UPDATE_SUCCESS: "storage.config.update.success";
|
|
36
|
+
readonly UPDATE_MANY_SUCCESS: "storage.config.update.many.success";
|
|
37
|
+
readonly DELETE_SUCCESS: "storage.config.delete.success";
|
|
38
|
+
readonly RESTORE_SUCCESS: "storage.config.restore.success";
|
|
39
|
+
readonly NOT_FOUND: "storage.config.not.found";
|
|
40
|
+
readonly ACTIVE_SUCCESS: "storage.config.active.success";
|
|
41
|
+
readonly TEST_SUCCESS: "storage.config.test.success";
|
|
42
|
+
readonly TEST_FAILED: "storage.config.test.failed";
|
|
43
|
+
};
|
|
44
|
+
export declare const UPLOAD_MESSAGES: {
|
|
45
|
+
readonly SUCCESS: "upload.success";
|
|
46
|
+
readonly MANY_SUCCESS: "upload.many.success";
|
|
47
|
+
readonly FAILED: "upload.failed";
|
|
48
|
+
readonly FILE_TOO_LARGE: "upload.file.too.large";
|
|
49
|
+
readonly INVALID_TYPE: "upload.invalid.type";
|
|
50
|
+
readonly CHUNK_SUCCESS: "upload.chunk.success";
|
|
51
|
+
readonly COMPLETE_SUCCESS: "upload.complete.success";
|
|
52
|
+
readonly NO_FILES_PROVIDED: "upload.no.files.provided";
|
|
53
|
+
readonly NO_FILE_PATH: "upload.no.file.path";
|
|
54
|
+
readonly INVALID_FILE_PATH: "upload.invalid.file.path";
|
|
55
|
+
readonly CONFIG_NOT_FOUND: "upload.config.not.found";
|
|
56
|
+
};
|
|
57
|
+
export declare const STORAGE_MODULE_MESSAGES: {
|
|
58
|
+
readonly FILE: {
|
|
59
|
+
readonly CREATE_SUCCESS: "file.create.success";
|
|
60
|
+
readonly CREATE_MANY_SUCCESS: "file.create.many.success";
|
|
61
|
+
readonly GET_SUCCESS: "file.get.success";
|
|
62
|
+
readonly GET_ALL_SUCCESS: "file.get.all.success";
|
|
63
|
+
readonly UPDATE_SUCCESS: "file.update.success";
|
|
64
|
+
readonly UPDATE_MANY_SUCCESS: "file.update.many.success";
|
|
65
|
+
readonly DELETE_SUCCESS: "file.delete.success";
|
|
66
|
+
readonly RESTORE_SUCCESS: "file.restore.success";
|
|
67
|
+
readonly NOT_FOUND: "file.not.found";
|
|
68
|
+
readonly UPLOAD_SUCCESS: "file.upload.success";
|
|
69
|
+
readonly UPLOAD_MANY_SUCCESS: "file.upload.many.success";
|
|
70
|
+
readonly DOWNLOAD_SUCCESS: "file.download.success";
|
|
71
|
+
readonly MOVE_SUCCESS: "file.move.success";
|
|
72
|
+
readonly COPY_SUCCESS: "file.copy.success";
|
|
73
|
+
};
|
|
74
|
+
readonly FOLDER: {
|
|
75
|
+
readonly CREATE_SUCCESS: "folder.create.success";
|
|
76
|
+
readonly CREATE_MANY_SUCCESS: "folder.create.many.success";
|
|
77
|
+
readonly GET_SUCCESS: "folder.get.success";
|
|
78
|
+
readonly GET_ALL_SUCCESS: "folder.get.all.success";
|
|
79
|
+
readonly UPDATE_SUCCESS: "folder.update.success";
|
|
80
|
+
readonly UPDATE_MANY_SUCCESS: "folder.update.many.success";
|
|
81
|
+
readonly DELETE_SUCCESS: "folder.delete.success";
|
|
82
|
+
readonly RESTORE_SUCCESS: "folder.restore.success";
|
|
83
|
+
readonly NOT_FOUND: "folder.not.found";
|
|
84
|
+
readonly TREE_SUCCESS: "folder.tree.success";
|
|
85
|
+
readonly CONTENTS_SUCCESS: "folder.contents.success";
|
|
86
|
+
};
|
|
87
|
+
readonly STORAGE_CONFIG: {
|
|
88
|
+
readonly CREATE_SUCCESS: "storage.config.create.success";
|
|
89
|
+
readonly CREATE_MANY_SUCCESS: "storage.config.create.many.success";
|
|
90
|
+
readonly GET_SUCCESS: "storage.config.get.success";
|
|
91
|
+
readonly GET_ALL_SUCCESS: "storage.config.get.all.success";
|
|
92
|
+
readonly UPDATE_SUCCESS: "storage.config.update.success";
|
|
93
|
+
readonly UPDATE_MANY_SUCCESS: "storage.config.update.many.success";
|
|
94
|
+
readonly DELETE_SUCCESS: "storage.config.delete.success";
|
|
95
|
+
readonly RESTORE_SUCCESS: "storage.config.restore.success";
|
|
96
|
+
readonly NOT_FOUND: "storage.config.not.found";
|
|
97
|
+
readonly ACTIVE_SUCCESS: "storage.config.active.success";
|
|
98
|
+
readonly TEST_SUCCESS: "storage.config.test.success";
|
|
99
|
+
readonly TEST_FAILED: "storage.config.test.failed";
|
|
100
|
+
};
|
|
101
|
+
readonly UPLOAD: {
|
|
102
|
+
readonly SUCCESS: "upload.success";
|
|
103
|
+
readonly MANY_SUCCESS: "upload.many.success";
|
|
104
|
+
readonly FAILED: "upload.failed";
|
|
105
|
+
readonly FILE_TOO_LARGE: "upload.file.too.large";
|
|
106
|
+
readonly INVALID_TYPE: "upload.invalid.type";
|
|
107
|
+
readonly CHUNK_SUCCESS: "upload.chunk.success";
|
|
108
|
+
readonly COMPLETE_SUCCESS: "upload.complete.success";
|
|
109
|
+
readonly NO_FILES_PROVIDED: "upload.no.files.provided";
|
|
110
|
+
readonly NO_FILE_PATH: "upload.no.file.path";
|
|
111
|
+
readonly INVALID_FILE_PATH: "upload.invalid.file.path";
|
|
112
|
+
readonly CONFIG_NOT_FOUND: "upload.config.not.found";
|
|
113
|
+
};
|
|
114
|
+
};
|
|
@@ -2,13 +2,13 @@ import { CreateFolderDto, FolderResponseDto, UpdateFolderDto } from '../dtos';
|
|
|
2
2
|
import { FolderService } from '../services/folder.service';
|
|
3
3
|
declare const FolderController_base: abstract new (service: FolderService) => {
|
|
4
4
|
service: FolderService;
|
|
5
|
-
insert(addDto: CreateFolderDto, user: import("@flusys/nestjs-shared
|
|
6
|
-
insertMany(addDto: CreateFolderDto[], user: import("@flusys/nestjs-shared
|
|
7
|
-
getById(id: string, body: import("@flusys/nestjs-shared
|
|
8
|
-
update(updateDto: UpdateFolderDto, user: import("@flusys/nestjs-shared
|
|
9
|
-
updateMany(updateDtos: UpdateFolderDto[], user: import("@flusys/nestjs-shared
|
|
10
|
-
getAll(filterAndPaginationDto: import("@flusys/nestjs-shared
|
|
11
|
-
delete(deleteDto: import("@flusys/nestjs-shared
|
|
5
|
+
insert(addDto: CreateFolderDto, user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").SingleResponseDto<FolderResponseDto>>;
|
|
6
|
+
insertMany(addDto: CreateFolderDto[], user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").BulkResponseDto<FolderResponseDto>>;
|
|
7
|
+
getById(id: string, body: import("@flusys/nestjs-shared").GetByIdBodyDto, user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").SingleResponseDto<FolderResponseDto>>;
|
|
8
|
+
update(updateDto: UpdateFolderDto, user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").SingleResponseDto<FolderResponseDto>>;
|
|
9
|
+
updateMany(updateDtos: UpdateFolderDto[], user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").BulkResponseDto<FolderResponseDto>>;
|
|
10
|
+
getAll(filterAndPaginationDto: import("@flusys/nestjs-shared").FilterAndPaginationDto, user: import("@flusys/nestjs-shared").ILoggedUserInfo | null, search?: string): Promise<import("@flusys/nestjs-shared").ListResponseDto<FolderResponseDto>>;
|
|
11
|
+
delete(deleteDto: import("@flusys/nestjs-shared").DeleteDto, user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").MessageResponseDto>;
|
|
12
12
|
};
|
|
13
13
|
export declare class FolderController extends FolderController_base {
|
|
14
14
|
folderService: FolderService;
|
|
@@ -2,13 +2,13 @@ import { CreateStorageConfigDto, StorageConfigResponseDto, UpdateStorageConfigDt
|
|
|
2
2
|
import { StorageProviderConfigService } from '../services/storage-provider-config.service';
|
|
3
3
|
declare const StorageConfigController_base: abstract new (service: StorageProviderConfigService) => {
|
|
4
4
|
service: StorageProviderConfigService;
|
|
5
|
-
insert(addDto: CreateStorageConfigDto, user: import("@flusys/nestjs-shared
|
|
6
|
-
insertMany(addDto: CreateStorageConfigDto[], user: import("@flusys/nestjs-shared
|
|
7
|
-
getById(id: string, body: import("@flusys/nestjs-shared
|
|
8
|
-
update(updateDto: UpdateStorageConfigDto, user: import("@flusys/nestjs-shared
|
|
9
|
-
updateMany(updateDtos: UpdateStorageConfigDto[], user: import("@flusys/nestjs-shared
|
|
10
|
-
getAll(filterAndPaginationDto: import("@flusys/nestjs-shared
|
|
11
|
-
delete(deleteDto: import("@flusys/nestjs-shared
|
|
5
|
+
insert(addDto: CreateStorageConfigDto, user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").SingleResponseDto<StorageConfigResponseDto>>;
|
|
6
|
+
insertMany(addDto: CreateStorageConfigDto[], user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").BulkResponseDto<StorageConfigResponseDto>>;
|
|
7
|
+
getById(id: string, body: import("@flusys/nestjs-shared").GetByIdBodyDto, user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").SingleResponseDto<StorageConfigResponseDto>>;
|
|
8
|
+
update(updateDto: UpdateStorageConfigDto, user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").SingleResponseDto<StorageConfigResponseDto>>;
|
|
9
|
+
updateMany(updateDtos: UpdateStorageConfigDto[], user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").BulkResponseDto<StorageConfigResponseDto>>;
|
|
10
|
+
getAll(filterAndPaginationDto: import("@flusys/nestjs-shared").FilterAndPaginationDto, user: import("@flusys/nestjs-shared").ILoggedUserInfo | null, search?: string): Promise<import("@flusys/nestjs-shared").ListResponseDto<StorageConfigResponseDto>>;
|
|
11
|
+
delete(deleteDto: import("@flusys/nestjs-shared").DeleteDto, user: import("@flusys/nestjs-shared").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared").MessageResponseDto>;
|
|
12
12
|
};
|
|
13
13
|
export declare class StorageConfigController extends StorageConfigController_base {
|
|
14
14
|
storageConfigService: StorageProviderConfigService;
|
|
@@ -5,7 +5,7 @@ import { UploadService } from '../services/upload.service';
|
|
|
5
5
|
export declare class UploadController {
|
|
6
6
|
private readonly uploadService;
|
|
7
7
|
constructor(uploadService: UploadService);
|
|
8
|
-
private
|
|
8
|
+
private buildFileResponse;
|
|
9
9
|
uploadSingleFile(file: Express.Multer.File, options: UploadOptionsDto, user: ILoggedUserInfo): Promise<SingleResponseDto<FileUploadResponsePayloadDto>>;
|
|
10
10
|
uploadMultipleFiles(files: Express.Multer.File[], options: UploadOptionsDto, user: ILoggedUserInfo): Promise<SingleResponseDto<FileUploadResponsePayloadDto[]>>;
|
|
11
11
|
deleteSingleFile(dto: DeleteSingleFileDto, user: ILoggedUserInfo): Promise<SingleResponseDto<boolean>>;
|
package/fesm/config/index.js
CHANGED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// ==================== STORAGE MODULE MESSAGE KEYS ====================
|
|
2
|
+
export const FILE_MESSAGES = {
|
|
3
|
+
CREATE_SUCCESS: 'file.create.success',
|
|
4
|
+
CREATE_MANY_SUCCESS: 'file.create.many.success',
|
|
5
|
+
GET_SUCCESS: 'file.get.success',
|
|
6
|
+
GET_ALL_SUCCESS: 'file.get.all.success',
|
|
7
|
+
UPDATE_SUCCESS: 'file.update.success',
|
|
8
|
+
UPDATE_MANY_SUCCESS: 'file.update.many.success',
|
|
9
|
+
DELETE_SUCCESS: 'file.delete.success',
|
|
10
|
+
RESTORE_SUCCESS: 'file.restore.success',
|
|
11
|
+
NOT_FOUND: 'file.not.found',
|
|
12
|
+
UPLOAD_SUCCESS: 'file.upload.success',
|
|
13
|
+
UPLOAD_MANY_SUCCESS: 'file.upload.many.success',
|
|
14
|
+
DOWNLOAD_SUCCESS: 'file.download.success',
|
|
15
|
+
MOVE_SUCCESS: 'file.move.success',
|
|
16
|
+
COPY_SUCCESS: 'file.copy.success'
|
|
17
|
+
};
|
|
18
|
+
export const FOLDER_MESSAGES = {
|
|
19
|
+
CREATE_SUCCESS: 'folder.create.success',
|
|
20
|
+
CREATE_MANY_SUCCESS: 'folder.create.many.success',
|
|
21
|
+
GET_SUCCESS: 'folder.get.success',
|
|
22
|
+
GET_ALL_SUCCESS: 'folder.get.all.success',
|
|
23
|
+
UPDATE_SUCCESS: 'folder.update.success',
|
|
24
|
+
UPDATE_MANY_SUCCESS: 'folder.update.many.success',
|
|
25
|
+
DELETE_SUCCESS: 'folder.delete.success',
|
|
26
|
+
RESTORE_SUCCESS: 'folder.restore.success',
|
|
27
|
+
NOT_FOUND: 'folder.not.found',
|
|
28
|
+
TREE_SUCCESS: 'folder.tree.success',
|
|
29
|
+
CONTENTS_SUCCESS: 'folder.contents.success'
|
|
30
|
+
};
|
|
31
|
+
export const STORAGE_CONFIG_MESSAGES = {
|
|
32
|
+
CREATE_SUCCESS: 'storage.config.create.success',
|
|
33
|
+
CREATE_MANY_SUCCESS: 'storage.config.create.many.success',
|
|
34
|
+
GET_SUCCESS: 'storage.config.get.success',
|
|
35
|
+
GET_ALL_SUCCESS: 'storage.config.get.all.success',
|
|
36
|
+
UPDATE_SUCCESS: 'storage.config.update.success',
|
|
37
|
+
UPDATE_MANY_SUCCESS: 'storage.config.update.many.success',
|
|
38
|
+
DELETE_SUCCESS: 'storage.config.delete.success',
|
|
39
|
+
RESTORE_SUCCESS: 'storage.config.restore.success',
|
|
40
|
+
NOT_FOUND: 'storage.config.not.found',
|
|
41
|
+
ACTIVE_SUCCESS: 'storage.config.active.success',
|
|
42
|
+
TEST_SUCCESS: 'storage.config.test.success',
|
|
43
|
+
TEST_FAILED: 'storage.config.test.failed'
|
|
44
|
+
};
|
|
45
|
+
export const UPLOAD_MESSAGES = {
|
|
46
|
+
SUCCESS: 'upload.success',
|
|
47
|
+
MANY_SUCCESS: 'upload.many.success',
|
|
48
|
+
FAILED: 'upload.failed',
|
|
49
|
+
FILE_TOO_LARGE: 'upload.file.too.large',
|
|
50
|
+
INVALID_TYPE: 'upload.invalid.type',
|
|
51
|
+
CHUNK_SUCCESS: 'upload.chunk.success',
|
|
52
|
+
COMPLETE_SUCCESS: 'upload.complete.success',
|
|
53
|
+
NO_FILES_PROVIDED: 'upload.no.files.provided',
|
|
54
|
+
NO_FILE_PATH: 'upload.no.file.path',
|
|
55
|
+
INVALID_FILE_PATH: 'upload.invalid.file.path',
|
|
56
|
+
CONFIG_NOT_FOUND: 'upload.config.not.found'
|
|
57
|
+
};
|
|
58
|
+
// Aggregated export for backward compatibility
|
|
59
|
+
export const STORAGE_MODULE_MESSAGES = {
|
|
60
|
+
FILE: FILE_MESSAGES,
|
|
61
|
+
FOLDER: FOLDER_MESSAGES,
|
|
62
|
+
STORAGE_CONFIG: STORAGE_CONFIG_MESSAGES,
|
|
63
|
+
UPLOAD: UPLOAD_MESSAGES
|
|
64
|
+
};
|
|
@@ -27,6 +27,7 @@ function _ts_param(paramIndex, decorator) {
|
|
|
27
27
|
}
|
|
28
28
|
import { BadRequestException, Body, Controller, HttpCode, Inject, Post, Req, UseGuards } from '@nestjs/common';
|
|
29
29
|
import { createApiController, FILE_PERMISSIONS } from '@flusys/nestjs-shared/classes';
|
|
30
|
+
import { FILE_MESSAGES, UPLOAD_MESSAGES } from '../config';
|
|
30
31
|
import { CurrentUser } from '@flusys/nestjs-shared/decorators';
|
|
31
32
|
import { SingleResponseDto } from '@flusys/nestjs-shared/dtos';
|
|
32
33
|
import { JwtAuthGuard } from '@flusys/nestjs-shared/guards';
|
|
@@ -36,6 +37,7 @@ import { ApiBearerAuth, ApiBody, ApiOperation, ApiResponse, ApiTags } from '@nes
|
|
|
36
37
|
import { Request } from 'express';
|
|
37
38
|
import { FileManagerService } from '../services/file-manager.service';
|
|
38
39
|
export class FileManagerController extends createApiController(CreateFileManagerDto, UpdateFileManagerDto, FileManagerResponseDto, {
|
|
40
|
+
entityName: 'file',
|
|
39
41
|
security: {
|
|
40
42
|
insert: {
|
|
41
43
|
level: 'permission',
|
|
@@ -83,13 +85,17 @@ export class FileManagerController extends createApiController(CreateFileManager
|
|
|
83
85
|
}) {
|
|
84
86
|
async getFiles(dto, req, user) {
|
|
85
87
|
if (!dto || !dto.length) {
|
|
86
|
-
throw new BadRequestException(
|
|
88
|
+
throw new BadRequestException({
|
|
89
|
+
message: 'No files provided',
|
|
90
|
+
messageKey: UPLOAD_MESSAGES.NO_FILES_PROVIDED
|
|
91
|
+
});
|
|
87
92
|
}
|
|
88
93
|
// Fetch files from service
|
|
89
94
|
const files = await this.fileService.getFiles(dto, req.protocol, req.get('host') || req.hostname, user);
|
|
90
95
|
return {
|
|
91
96
|
success: true,
|
|
92
97
|
message: 'Files retrieved successfully',
|
|
98
|
+
messageKey: FILE_MESSAGES.GET_ALL_SUCCESS,
|
|
93
99
|
data: files
|
|
94
100
|
};
|
|
95
101
|
}
|
|
@@ -31,6 +31,7 @@ import { Controller, Inject } from '@nestjs/common';
|
|
|
31
31
|
import { ApiTags } from '@nestjs/swagger';
|
|
32
32
|
import { FolderService } from '../services/folder.service';
|
|
33
33
|
export class FolderController extends createApiController(CreateFolderDto, UpdateFolderDto, FolderResponseDto, {
|
|
34
|
+
entityName: 'folder',
|
|
34
35
|
security: {
|
|
35
36
|
insert: {
|
|
36
37
|
level: 'permission',
|
|
@@ -31,6 +31,7 @@ import { Controller, Inject } from '@nestjs/common';
|
|
|
31
31
|
import { ApiTags } from '@nestjs/swagger';
|
|
32
32
|
import { StorageProviderConfigService } from '../services/storage-provider-config.service';
|
|
33
33
|
export class StorageConfigController extends createApiController(CreateStorageConfigDto, UpdateStorageConfigDto, StorageConfigResponseDto, {
|
|
34
|
+
entityName: 'storageConfig',
|
|
34
35
|
security: {
|
|
35
36
|
insert: {
|
|
36
37
|
level: 'permission',
|
|
@@ -25,8 +25,9 @@ function _ts_param(paramIndex, decorator) {
|
|
|
25
25
|
decorator(target, key, paramIndex);
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
|
-
import {
|
|
28
|
+
import { FILE_MESSAGES, UPLOAD_MESSAGES } from '../config';
|
|
29
29
|
import { ApiResponseDto, CurrentUser, RequirePermission } from '@flusys/nestjs-shared/decorators';
|
|
30
|
+
import { JwtAuthGuard } from '@flusys/nestjs-shared/guards';
|
|
30
31
|
import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
|
|
31
32
|
import { DeleteMultipleFileDto, DeleteSingleFileDto, FileUploadResponsePayloadDto, UploadOptionsDto } from '../dtos';
|
|
32
33
|
import { Body, Controller, Inject, Post, Query, UploadedFile, UploadedFiles, UseGuards, UseInterceptors } from '@nestjs/common';
|
|
@@ -34,7 +35,7 @@ import { FileInterceptor, FilesInterceptor } from '@nestjs/platform-express';
|
|
|
34
35
|
import { ApiBearerAuth, ApiBody, ApiConsumes, ApiOperation, ApiQuery, ApiTags } from '@nestjs/swagger';
|
|
35
36
|
import { UploadService } from '../services/upload.service';
|
|
36
37
|
export class UploadController {
|
|
37
|
-
|
|
38
|
+
buildFileResponse(file) {
|
|
38
39
|
return {
|
|
39
40
|
size: this.uploadService.bytesToKb(file.size),
|
|
40
41
|
name: file.name,
|
|
@@ -49,7 +50,8 @@ export class UploadController {
|
|
|
49
50
|
return {
|
|
50
51
|
success: true,
|
|
51
52
|
message: 'File uploaded successfully',
|
|
52
|
-
|
|
53
|
+
messageKey: UPLOAD_MESSAGES.SUCCESS,
|
|
54
|
+
data: this.buildFileResponse(result)
|
|
53
55
|
};
|
|
54
56
|
}
|
|
55
57
|
async uploadMultipleFiles(files, options, user) {
|
|
@@ -57,7 +59,8 @@ export class UploadController {
|
|
|
57
59
|
return {
|
|
58
60
|
success: true,
|
|
59
61
|
message: 'Files uploaded successfully',
|
|
60
|
-
|
|
62
|
+
messageKey: UPLOAD_MESSAGES.MANY_SUCCESS,
|
|
63
|
+
data: uploadResponses.map((file)=>this.buildFileResponse(file))
|
|
61
64
|
};
|
|
62
65
|
}
|
|
63
66
|
async deleteSingleFile(dto, user) {
|
|
@@ -65,6 +68,7 @@ export class UploadController {
|
|
|
65
68
|
return {
|
|
66
69
|
success: true,
|
|
67
70
|
message: 'File deleted successfully',
|
|
71
|
+
messageKey: FILE_MESSAGES.DELETE_SUCCESS,
|
|
68
72
|
data
|
|
69
73
|
};
|
|
70
74
|
}
|
|
@@ -73,6 +77,7 @@ export class UploadController {
|
|
|
73
77
|
return {
|
|
74
78
|
success: true,
|
|
75
79
|
message: 'Files deleted successfully',
|
|
80
|
+
messageKey: FILE_MESSAGES.DELETE_SUCCESS,
|
|
76
81
|
data
|
|
77
82
|
};
|
|
78
83
|
}
|
|
@@ -25,10 +25,11 @@ function _ts_param(paramIndex, decorator) {
|
|
|
25
25
|
decorator(target, key, paramIndex);
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
|
-
import { Injectable,
|
|
28
|
+
import { Injectable, NotFoundException, BadRequestException, Inject } from '@nestjs/common';
|
|
29
29
|
import { createReadStream, existsSync, statSync } from 'fs';
|
|
30
30
|
import { join, resolve } from 'path';
|
|
31
31
|
import * as mime from 'mime-types';
|
|
32
|
+
import { FILE_MESSAGES, UPLOAD_MESSAGES } from '../config';
|
|
32
33
|
import { UploadService } from '../services/upload.service';
|
|
33
34
|
/** MIME type prefixes that can be displayed inline in browser */ const VIEWABLE_TYPE_PREFIXES = [
|
|
34
35
|
'image/',
|
|
@@ -46,7 +47,13 @@ export class FileServeMiddleware {
|
|
|
46
47
|
const fullPath = await this.resolveFilePath(normalizedPath);
|
|
47
48
|
const stats = statSync(fullPath);
|
|
48
49
|
if (!stats.isFile()) {
|
|
49
|
-
throw new NotFoundException(
|
|
50
|
+
throw new NotFoundException({
|
|
51
|
+
message: `Not a file: ${normalizedPath}`,
|
|
52
|
+
messageKey: FILE_MESSAGES.NOT_FOUND,
|
|
53
|
+
messageParams: {
|
|
54
|
+
path: normalizedPath
|
|
55
|
+
}
|
|
56
|
+
});
|
|
50
57
|
}
|
|
51
58
|
const mimeType = this.getMimeType(fullPath);
|
|
52
59
|
this.setResponseHeaders(res, stats.size, mimeType, normalizedPath);
|
|
@@ -60,19 +67,23 @@ export class FileServeMiddleware {
|
|
|
60
67
|
const match = urlPath.match(/\/storage\/upload\/file\/(.+)/);
|
|
61
68
|
const normalizedPath = match ? match[1] : '';
|
|
62
69
|
if (!normalizedPath) {
|
|
63
|
-
throw new
|
|
70
|
+
throw new BadRequestException({
|
|
71
|
+
message: 'File path is required',
|
|
72
|
+
messageKey: UPLOAD_MESSAGES.NO_FILE_PATH
|
|
73
|
+
});
|
|
64
74
|
}
|
|
65
|
-
this.logger.debug(`Attempting to serve file, normalizedPath: ${normalizedPath}`);
|
|
66
75
|
return normalizedPath;
|
|
67
76
|
}
|
|
68
77
|
/** Resolve file path using multiple fallback strategies */ async resolveFilePath(normalizedPath) {
|
|
69
78
|
// Strategy 1: Path relative to CWD (new format: key includes basePath)
|
|
70
79
|
let fullPath = join(this.uploadDir, normalizedPath);
|
|
71
80
|
const resolvedPath = resolve(fullPath);
|
|
72
|
-
this.logger.debug(`Strategy 1 - CWD relative: ${fullPath}`);
|
|
73
81
|
// Prevent path traversal attacks
|
|
74
82
|
if (!resolvedPath.startsWith(this.uploadDir)) {
|
|
75
|
-
throw new
|
|
83
|
+
throw new BadRequestException({
|
|
84
|
+
message: 'Invalid file path',
|
|
85
|
+
messageKey: UPLOAD_MESSAGES.INVALID_FILE_PATH
|
|
86
|
+
});
|
|
76
87
|
}
|
|
77
88
|
if (existsSync(fullPath)) {
|
|
78
89
|
return fullPath;
|
|
@@ -85,7 +96,13 @@ export class FileServeMiddleware {
|
|
|
85
96
|
return fallbackPath;
|
|
86
97
|
}
|
|
87
98
|
}
|
|
88
|
-
throw new NotFoundException(
|
|
99
|
+
throw new NotFoundException({
|
|
100
|
+
message: `File not found: ${normalizedPath}`,
|
|
101
|
+
messageKey: FILE_MESSAGES.NOT_FOUND,
|
|
102
|
+
messageParams: {
|
|
103
|
+
path: normalizedPath
|
|
104
|
+
}
|
|
105
|
+
});
|
|
89
106
|
}
|
|
90
107
|
/** Try basePath-based fallback strategies */ tryFallbackPaths(normalizedPath, basePath) {
|
|
91
108
|
const normalizedBasePath = basePath.replace(/^\.\//, '').replace(/\/$/, '');
|
|
@@ -94,12 +111,10 @@ export class FileServeMiddleware {
|
|
|
94
111
|
// Strategy 2: basePath + remaining path
|
|
95
112
|
const remainingPath = normalizedPath.substring(normalizedBasePath.length).replace(/^\//, '');
|
|
96
113
|
const fallbackPath = join(basePath, remainingPath);
|
|
97
|
-
this.logger.debug(`Strategy 2 - basePath + remaining: ${fallbackPath}`);
|
|
98
114
|
if (existsSync(fallbackPath)) return fallbackPath;
|
|
99
115
|
} else {
|
|
100
116
|
// Strategy 3: Old format - prepend basePath
|
|
101
117
|
const fallbackPath = join(basePath, normalizedPath);
|
|
102
|
-
this.logger.debug(`Strategy 3 - basePath + full key (old format): ${fallbackPath}`);
|
|
103
118
|
if (existsSync(fallbackPath)) return fallbackPath;
|
|
104
119
|
}
|
|
105
120
|
return null;
|
|
@@ -128,20 +143,31 @@ export class FileServeMiddleware {
|
|
|
128
143
|
/** Stream file to response with error handling */ streamFile(res, fullPath, normalizedPath) {
|
|
129
144
|
const stream = createReadStream(fullPath);
|
|
130
145
|
stream.pipe(res);
|
|
131
|
-
stream.on('error', (
|
|
132
|
-
this.logger.error('File stream error', err);
|
|
146
|
+
stream.on('error', ()=>{
|
|
133
147
|
if (!res.headersSent) {
|
|
134
|
-
this.sendErrorResponse(res, new NotFoundException(
|
|
148
|
+
this.sendErrorResponse(res, new NotFoundException({
|
|
149
|
+
message: `Failed to serve file: ${normalizedPath}`,
|
|
150
|
+
messageKey: FILE_MESSAGES.NOT_FOUND,
|
|
151
|
+
messageParams: {
|
|
152
|
+
path: normalizedPath
|
|
153
|
+
}
|
|
154
|
+
}));
|
|
135
155
|
}
|
|
136
156
|
});
|
|
137
157
|
res.on('close', ()=>stream.destroy());
|
|
138
158
|
}
|
|
139
159
|
/** Send consistent error response */ sendErrorResponse(res, error) {
|
|
140
|
-
this.logger.error('File retrieval error:', error);
|
|
141
160
|
if (!res.headersSent) {
|
|
142
|
-
const
|
|
161
|
+
const isNotFound = error instanceof NotFoundException;
|
|
162
|
+
const response = isNotFound ? error.getResponse() : null;
|
|
163
|
+
const message = response?.message ?? 'File not found';
|
|
164
|
+
const messageKey = response?.messageKey ?? FILE_MESSAGES.NOT_FOUND;
|
|
165
|
+
const messageParams = response?.messageParams;
|
|
143
166
|
res.status(404).json({
|
|
167
|
+
success: false,
|
|
144
168
|
message,
|
|
169
|
+
messageKey,
|
|
170
|
+
messageParams,
|
|
145
171
|
error: 'Not Found',
|
|
146
172
|
statusCode: 404
|
|
147
173
|
});
|
|
@@ -149,10 +175,8 @@ export class FileServeMiddleware {
|
|
|
149
175
|
}
|
|
150
176
|
constructor(uploadService){
|
|
151
177
|
_define_property(this, "uploadService", void 0);
|
|
152
|
-
_define_property(this, "logger", void 0);
|
|
153
178
|
_define_property(this, "uploadDir", void 0);
|
|
154
179
|
this.uploadService = uploadService;
|
|
155
|
-
this.logger = new Logger(FileServeMiddleware.name);
|
|
156
180
|
this.uploadDir = process.cwd();
|
|
157
181
|
}
|
|
158
182
|
}
|
|
@@ -15,7 +15,6 @@ import { StorageFactoryService, StorageProviderRegistry } from '../providers';
|
|
|
15
15
|
import { LocalProvider } from '../providers/local-provider';
|
|
16
16
|
import { FileManagerService, FolderService, StorageDataSourceProvider, UploadService } from '../services';
|
|
17
17
|
import { StorageProviderConfigService } from '../services/storage-provider-config.service';
|
|
18
|
-
// ─── Module Constants ─────────────────────────────────────────────────────────
|
|
19
18
|
const logger = new Logger('StorageModule');
|
|
20
19
|
const CONTROLLERS = [
|
|
21
20
|
FileManagerController,
|
|
@@ -32,9 +31,10 @@ const EXPORTED_SERVICES = [
|
|
|
32
31
|
UploadService,
|
|
33
32
|
StorageFactoryService
|
|
34
33
|
];
|
|
35
|
-
//
|
|
34
|
+
// Register built-in provider
|
|
36
35
|
StorageProviderRegistry.register(FileLocationEnum.LOCAL, LocalProvider);
|
|
37
36
|
logger.log('Registered LocalProvider');
|
|
37
|
+
// Register optional providers (skip if dependencies not installed)
|
|
38
38
|
const OPTIONAL_PROVIDERS = [
|
|
39
39
|
{
|
|
40
40
|
location: FileLocationEnum.AWS,
|
|
@@ -14,7 +14,8 @@ function _define_property(obj, key, value) {
|
|
|
14
14
|
/**
|
|
15
15
|
* Optional Azure Blob Storage Provider
|
|
16
16
|
* Requires: npm install @azure/storage-blob
|
|
17
|
-
*/ import {
|
|
17
|
+
*/ import { InternalServerErrorException } from '@nestjs/common';
|
|
18
|
+
import { SYSTEM_MESSAGES } from '@flusys/nestjs-shared/constants';
|
|
18
19
|
import { v4 as uuidv4 } from 'uuid';
|
|
19
20
|
import { ImageCompressor } from '../utils/image-compressor.util';
|
|
20
21
|
export class AzureProvider {
|
|
@@ -26,9 +27,14 @@ export class AzureProvider {
|
|
|
26
27
|
this.blobServiceClient = config.connectionString ? BlobServiceClient.fromConnectionString(config.connectionString) : new BlobServiceClient(`https://${config.accountName}.blob.core.windows.net`, new StorageSharedKeyCredential(config.accountName, config.accountKey));
|
|
27
28
|
this.containerClient = this.blobServiceClient.getContainerClient(config.containerName);
|
|
28
29
|
await this.containerClient.createIfNotExists();
|
|
29
|
-
this.logger.log(`Azure Provider initialized: account=${config.accountName}, container=${config.containerName}`);
|
|
30
30
|
} catch {
|
|
31
|
-
throw new
|
|
31
|
+
throw new InternalServerErrorException({
|
|
32
|
+
message: 'Azure Storage SDK not found',
|
|
33
|
+
messageKey: SYSTEM_MESSAGES.SDK_NOT_INSTALLED,
|
|
34
|
+
messageParams: {
|
|
35
|
+
sdk: '@azure/storage-blob'
|
|
36
|
+
}
|
|
37
|
+
});
|
|
32
38
|
}
|
|
33
39
|
}
|
|
34
40
|
async uploadFile(file, options) {
|
|
@@ -63,11 +69,9 @@ export class AzureProvider {
|
|
|
63
69
|
}
|
|
64
70
|
async deleteFile(key) {
|
|
65
71
|
await this.containerClient.getBlockBlobClient(key).deleteIfExists();
|
|
66
|
-
this.logger.log(`Deleted file from Azure: ${key}`);
|
|
67
72
|
}
|
|
68
73
|
async deleteMultipleFiles(keys) {
|
|
69
74
|
await Promise.all(keys.map((key)=>this.deleteFile(key)));
|
|
70
|
-
this.logger.log(`Deleted ${keys.length} files from Azure`);
|
|
71
75
|
}
|
|
72
76
|
async generatePresignedUrl(key, expiresInSeconds = 3600) {
|
|
73
77
|
const { BlobSASPermissions, generateBlobSASQueryParameters } = await import('@azure/storage-blob');
|
|
@@ -92,7 +96,6 @@ export class AzureProvider {
|
|
|
92
96
|
}
|
|
93
97
|
}
|
|
94
98
|
constructor(){
|
|
95
|
-
_define_property(this, "logger", new Logger(AzureProvider.name));
|
|
96
99
|
_define_property(this, "blobServiceClient", void 0);
|
|
97
100
|
_define_property(this, "containerClient", void 0);
|
|
98
101
|
_define_property(this, "containerName", '');
|