@hed-hog/core 0.0.355 → 0.0.358
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/dist/ai/ai.service.d.ts +3 -12
- package/dist/ai/ai.service.d.ts.map +1 -1
- package/dist/ai/ai.service.js +34 -125
- package/dist/ai/ai.service.js.map +1 -1
- package/dist/auth/guards/auth.guard.d.ts +6 -1
- package/dist/auth/guards/auth.guard.d.ts.map +1 -1
- package/dist/auth/guards/auth.guard.js +33 -2
- package/dist/auth/guards/auth.guard.js.map +1 -1
- package/dist/core.module.d.ts.map +1 -1
- package/dist/core.module.js +3 -3
- package/dist/core.module.js.map +1 -1
- package/dist/file/file.controller.d.ts +4 -2
- package/dist/file/file.controller.d.ts.map +1 -1
- package/dist/file/file.controller.js +44 -38
- package/dist/file/file.controller.js.map +1 -1
- package/dist/file/file.service.d.ts +2 -2
- package/dist/file/file.service.d.ts.map +1 -1
- package/dist/file/file.service.js +58 -89
- package/dist/file/file.service.js.map +1 -1
- package/dist/file/provider/azure.provider.d.ts.map +1 -1
- package/dist/file/provider/azure.provider.js +10 -15
- package/dist/file/provider/azure.provider.js.map +1 -1
- package/dist/file/provider/gcs.provider.d.ts.map +1 -1
- package/dist/file/provider/gcs.provider.js +8 -9
- package/dist/file/provider/gcs.provider.js.map +1 -1
- package/dist/file/provider/local.provider.d.ts.map +1 -1
- package/dist/file/provider/local.provider.js +11 -10
- package/dist/file/provider/local.provider.js.map +1 -1
- package/dist/file/provider/provider.enum.d.ts +2 -1
- package/dist/file/provider/provider.enum.d.ts.map +1 -1
- package/dist/file/provider/provider.enum.js +1 -0
- package/dist/file/provider/provider.enum.js.map +1 -1
- package/dist/file/provider/provider.factory.d.ts +1 -1
- package/dist/file/provider/provider.factory.d.ts.map +1 -1
- package/dist/file/provider/provider.factory.js +18 -5
- package/dist/file/provider/provider.factory.js.map +1 -1
- package/dist/file/provider/s3.provider.d.ts.map +1 -1
- package/dist/file/provider/s3.provider.js +4 -20
- package/dist/file/provider/s3.provider.js.map +1 -1
- package/dist/file/provider/spaces.provider.d.ts +27 -0
- package/dist/file/provider/spaces.provider.d.ts.map +1 -0
- package/dist/file/provider/spaces.provider.js +203 -0
- package/dist/file/provider/spaces.provider.js.map +1 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/integration-profile/dto/create.dto.d.ts +9 -0
- package/dist/integration-profile/dto/create.dto.d.ts.map +1 -0
- package/dist/integration-profile/dto/create.dto.js +54 -0
- package/dist/integration-profile/dto/create.dto.js.map +1 -0
- package/dist/integration-profile/dto/export.dto.d.ts +5 -0
- package/dist/integration-profile/dto/export.dto.d.ts.map +1 -0
- package/dist/integration-profile/dto/export.dto.js +29 -0
- package/dist/integration-profile/dto/export.dto.js.map +1 -0
- package/dist/integration-profile/dto/import-confirm.dto.d.ts +17 -0
- package/dist/integration-profile/dto/import-confirm.dto.d.ts.map +1 -0
- package/dist/integration-profile/dto/import-confirm.dto.js +77 -0
- package/dist/integration-profile/dto/import-confirm.dto.js.map +1 -0
- package/dist/integration-profile/dto/update.dto.d.ts.map +1 -0
- package/dist/integration-profile/dto/update.dto.js.map +1 -0
- package/dist/integration-profile/integration-profile.controller.d.ts +142 -0
- package/dist/integration-profile/integration-profile.controller.d.ts.map +1 -0
- package/dist/integration-profile/integration-profile.controller.js +166 -0
- package/dist/integration-profile/integration-profile.controller.js.map +1 -0
- package/dist/integration-profile/integration-profile.module.d.ts +3 -0
- package/dist/integration-profile/integration-profile.module.d.ts.map +1 -0
- package/dist/{mail-profile/mail-profile.module.js → integration-profile/integration-profile.module.js} +11 -13
- package/dist/integration-profile/integration-profile.module.js.map +1 -0
- package/dist/integration-profile/integration-profile.service.d.ts +160 -0
- package/dist/integration-profile/integration-profile.service.d.ts.map +1 -0
- package/dist/integration-profile/integration-profile.service.js +609 -0
- package/dist/integration-profile/integration-profile.service.js.map +1 -0
- package/dist/integration-profile/integration-profile.utils.d.ts +30 -0
- package/dist/integration-profile/integration-profile.utils.d.ts.map +1 -0
- package/dist/integration-profile/integration-profile.utils.js +156 -0
- package/dist/integration-profile/integration-profile.utils.js.map +1 -0
- package/dist/mail/mail.module.d.ts.map +1 -1
- package/dist/mail/mail.module.js +36 -23
- package/dist/mail/mail.module.js.map +1 -1
- package/dist/mail/mail.service.d.ts +4 -2
- package/dist/mail/mail.service.d.ts.map +1 -1
- package/dist/mail/mail.service.js +33 -51
- package/dist/mail/mail.service.js.map +1 -1
- package/dist/mcp/guards/mcp-auth.guard.js +1 -1
- package/dist/mcp/guards/mcp-auth.guard.js.map +1 -1
- package/dist/mcp/mcp-api-key.controller.d.ts +2 -0
- package/dist/mcp/mcp-api-key.controller.d.ts.map +1 -1
- package/dist/mcp/mcp-api-key.controller.js +1 -1
- package/dist/mcp/mcp-api-key.controller.js.map +1 -1
- package/dist/mcp/mcp-api-key.service.d.ts +2 -1
- package/dist/mcp/mcp-api-key.service.d.ts.map +1 -1
- package/dist/mcp/mcp-api-key.service.js +6 -2
- package/dist/mcp/mcp-api-key.service.js.map +1 -1
- package/dist/mcp/mcp.module.d.ts.map +1 -1
- package/dist/mcp/mcp.module.js +3 -5
- package/dist/mcp/mcp.module.js.map +1 -1
- package/dist/mcp-chat/mcp-chat.service.d.ts.map +1 -1
- package/dist/mcp-chat/mcp-chat.service.js +17 -16
- package/dist/mcp-chat/mcp-chat.service.js.map +1 -1
- package/dist/oauth/interfaces/OAuthProvider.d.ts +1 -1
- package/dist/oauth/interfaces/OAuthProvider.d.ts.map +1 -1
- package/dist/oauth/oauth.controller.d.ts +4 -1
- package/dist/oauth/oauth.controller.d.ts.map +1 -1
- package/dist/oauth/oauth.controller.js +31 -5
- package/dist/oauth/oauth.controller.js.map +1 -1
- package/dist/oauth/oauth.service.d.ts +12 -1
- package/dist/oauth/oauth.service.d.ts.map +1 -1
- package/dist/oauth/oauth.service.js +125 -23
- package/dist/oauth/oauth.service.js.map +1 -1
- package/dist/oauth/providers/abstract.provider.d.ts +1 -1
- package/dist/oauth/providers/abstract.provider.d.ts.map +1 -1
- package/dist/oauth/providers/facebook.provider.d.ts +5 -2
- package/dist/oauth/providers/facebook.provider.d.ts.map +1 -1
- package/dist/oauth/providers/facebook.provider.js +34 -19
- package/dist/oauth/providers/facebook.provider.js.map +1 -1
- package/dist/oauth/providers/github.provider.d.ts +6 -2
- package/dist/oauth/providers/github.provider.d.ts.map +1 -1
- package/dist/oauth/providers/github.provider.js +43 -20
- package/dist/oauth/providers/github.provider.js.map +1 -1
- package/dist/oauth/providers/google.provider.d.ts +5 -2
- package/dist/oauth/providers/google.provider.d.ts.map +1 -1
- package/dist/oauth/providers/google.provider.js +34 -19
- package/dist/oauth/providers/google.provider.js.map +1 -1
- package/dist/oauth/providers/microsoft-entra-id.provider.d.ts +5 -2
- package/dist/oauth/providers/microsoft-entra-id.provider.d.ts.map +1 -1
- package/dist/oauth/providers/microsoft-entra-id.provider.js +43 -40
- package/dist/oauth/providers/microsoft-entra-id.provider.js.map +1 -1
- package/dist/oauth/providers/microsoft.provider.d.ts +5 -2
- package/dist/oauth/providers/microsoft.provider.d.ts.map +1 -1
- package/dist/oauth/providers/microsoft.provider.js +34 -19
- package/dist/oauth/providers/microsoft.provider.js.map +1 -1
- package/dist/profile/profile.controller.js +1 -1
- package/dist/profile/profile.controller.js.map +1 -1
- package/dist/security/security.service.d.ts +2 -0
- package/dist/security/security.service.d.ts.map +1 -1
- package/dist/security/security.service.js +21 -0
- package/dist/security/security.service.js.map +1 -1
- package/dist/setting/setting.service.d.ts +26 -1
- package/dist/setting/setting.service.d.ts.map +1 -1
- package/dist/setting/setting.service.js +240 -7
- package/dist/setting/setting.service.js.map +1 -1
- package/dist/user/user.controller.d.ts +2 -1
- package/dist/user/user.controller.d.ts.map +1 -1
- package/dist/user/user.controller.js +5 -4
- package/dist/user/user.controller.js.map +1 -1
- package/dist/user/user.service.d.ts +4 -2
- package/dist/user/user.service.d.ts.map +1 -1
- package/dist/user/user.service.js +19 -4
- package/dist/user/user.service.js.map +1 -1
- package/dist/webhook-integration/dto/webhook-action.dto.d.ts +17 -2
- package/dist/webhook-integration/dto/webhook-action.dto.d.ts.map +1 -1
- package/dist/webhook-integration/dto/webhook-action.dto.js +93 -2
- package/dist/webhook-integration/dto/webhook-action.dto.js.map +1 -1
- package/dist/webhook-integration/event-webhook.controller.d.ts +1 -0
- package/dist/webhook-integration/event-webhook.controller.d.ts.map +1 -1
- package/dist/webhook-integration/event-webhook.controller.js +10 -0
- package/dist/webhook-integration/event-webhook.controller.js.map +1 -1
- package/dist/webhook-integration/event-webhook.service.d.ts +2 -0
- package/dist/webhook-integration/event-webhook.service.d.ts.map +1 -1
- package/dist/webhook-integration/event-webhook.service.js +30 -0
- package/dist/webhook-integration/event-webhook.service.js.map +1 -1
- package/dist/webhook-integration/webhook-command.registry.d.ts +15 -0
- package/dist/webhook-integration/webhook-command.registry.d.ts.map +1 -0
- package/dist/webhook-integration/webhook-command.registry.js +36 -0
- package/dist/webhook-integration/webhook-command.registry.js.map +1 -0
- package/dist/webhook-integration/webhook-integration.controller.d.ts +20 -0
- package/dist/webhook-integration/webhook-integration.controller.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-integration.controller.js +48 -0
- package/dist/webhook-integration/webhook-integration.controller.js.map +1 -1
- package/dist/webhook-integration/webhook-integration.module.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-integration.module.js +5 -0
- package/dist/webhook-integration/webhook-integration.module.js.map +1 -1
- package/dist/webhook-integration/webhook-integration.service.d.ts +27 -2
- package/dist/webhook-integration/webhook-integration.service.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-integration.service.js +377 -50
- package/dist/webhook-integration/webhook-integration.service.js.map +1 -1
- package/hedhog/data/file_provider.yaml +9 -1
- package/hedhog/data/integration_provider.yaml +148 -0
- package/hedhog/data/integration_type.yaml +29 -0
- package/hedhog/data/menu.yaml +6 -21
- package/hedhog/data/role.yaml +8 -0
- package/hedhog/data/route.yaml +73 -373
- package/hedhog/data/setting_group.yaml +209 -365
- package/hedhog/data/setting_subgroup.yaml +21 -13
- package/hedhog/frontend/app/account/components/connected-accounts.tsx.ejs +25 -20
- package/hedhog/frontend/app/account/components/tokens.tsx.ejs +421 -0
- package/hedhog/frontend/app/account/layout.tsx.ejs +6 -3
- package/hedhog/frontend/app/account/mcp-tokens/page.tsx.ejs +2 -2
- package/hedhog/frontend/app/account/tokens/page.tsx.ejs +5 -0
- package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +938 -225
- package/hedhog/frontend/app/configurations/layout.tsx.ejs +1 -1
- package/hedhog/frontend/app/dashboard/dashboard-home-tabs.tsx.ejs +3 -1
- package/hedhog/frontend/app/integration/profiles/page.tsx.ejs +1830 -0
- package/hedhog/frontend/app/integrations-webhooks/page.tsx.ejs +829 -128
- package/hedhog/frontend/app/mail/profiles/page.tsx.ejs +1 -820
- package/hedhog/frontend/app/setting-list/page.tsx.ejs +229 -395
- package/hedhog/frontend/app/users/permissions.tsx.ejs +79 -2
- package/hedhog/frontend/app/users/user-sheet.tsx.ejs +7 -2
- package/hedhog/frontend/messages/en.json +239 -3
- package/hedhog/frontend/messages/pt.json +239 -3
- package/hedhog/table/file.yaml +1 -1
- package/hedhog/table/integration_profile.yaml +34 -0
- package/hedhog/table/integration_provider.yaml +23 -0
- package/hedhog/table/integration_type.yaml +19 -0
- package/hedhog/table/mcp_api_key.yaml +4 -0
- package/hedhog/table/webhook_action.yaml +141 -85
- package/package.json +4 -3
- package/src/ai/ai.service.ts +35 -153
- package/src/auth/guards/auth.guard.ts +32 -0
- package/src/core.module.ts +3 -3
- package/src/file/file.controller.ts +51 -42
- package/src/file/file.service.ts +67 -104
- package/src/file/provider/azure.provider.ts +14 -28
- package/src/file/provider/gcs.provider.ts +9 -9
- package/src/file/provider/local.provider.ts +10 -13
- package/src/file/provider/provider.enum.ts +1 -0
- package/src/file/provider/provider.factory.ts +21 -6
- package/src/file/provider/s3.provider.ts +4 -20
- package/src/file/provider/spaces.provider.ts +246 -0
- package/src/index.ts +6 -3
- package/src/integration-profile/dto/create.dto.ts +44 -0
- package/src/integration-profile/dto/export.dto.ts +15 -0
- package/src/integration-profile/dto/import-confirm.dto.ts +61 -0
- package/src/integration-profile/integration-profile.controller.ts +131 -0
- package/src/integration-profile/integration-profile.module.ts +16 -0
- package/src/integration-profile/integration-profile.service.ts +793 -0
- package/src/integration-profile/integration-profile.utils.ts +173 -0
- package/src/mail/mail.module.ts +41 -22
- package/src/mail/mail.service.ts +40 -64
- package/src/mcp/guards/mcp-auth.guard.ts +1 -1
- package/src/mcp/mcp-api-key.controller.ts +2 -2
- package/src/mcp/mcp-api-key.service.ts +6 -2
- package/src/mcp/mcp.module.ts +3 -5
- package/src/mcp-chat/mcp-chat.service.ts +23 -20
- package/src/oauth/interfaces/OAuthProvider.ts +1 -1
- package/src/oauth/oauth.controller.ts +30 -2
- package/src/oauth/oauth.service.ts +194 -35
- package/src/oauth/providers/abstract.provider.ts +1 -1
- package/src/oauth/providers/facebook.provider.ts +36 -20
- package/src/oauth/providers/github.provider.ts +46 -23
- package/src/oauth/providers/google.provider.ts +36 -20
- package/src/oauth/providers/microsoft-entra-id.provider.ts +42 -46
- package/src/oauth/providers/microsoft.provider.ts +36 -21
- package/src/profile/profile.controller.ts +2 -2
- package/src/security/security.service.ts +34 -1
- package/src/setting/setting.service.ts +307 -9
- package/src/user/user.controller.ts +4 -1
- package/src/user/user.service.ts +20 -2
- package/src/webhook-integration/dto/webhook-action.dto.ts +85 -4
- package/src/webhook-integration/event-webhook.controller.ts +55 -50
- package/src/webhook-integration/event-webhook.service.ts +422 -384
- package/src/webhook-integration/webhook-command.registry.ts +42 -0
- package/src/webhook-integration/webhook-integration.controller.ts +25 -0
- package/src/webhook-integration/webhook-integration.module.ts +50 -45
- package/src/webhook-integration/webhook-integration.service.ts +444 -53
- package/dist/mail-profile/dto/create.dto.d.ts +0 -23
- package/dist/mail-profile/dto/create.dto.d.ts.map +0 -1
- package/dist/mail-profile/dto/create.dto.js +0 -139
- package/dist/mail-profile/dto/create.dto.js.map +0 -1
- package/dist/mail-profile/dto/update.dto.d.ts.map +0 -1
- package/dist/mail-profile/dto/update.dto.js.map +0 -1
- package/dist/mail-profile/mail-profile.controller.d.ts +0 -94
- package/dist/mail-profile/mail-profile.controller.d.ts.map +0 -1
- package/dist/mail-profile/mail-profile.controller.js +0 -95
- package/dist/mail-profile/mail-profile.controller.js.map +0 -1
- package/dist/mail-profile/mail-profile.module.d.ts +0 -3
- package/dist/mail-profile/mail-profile.module.d.ts.map +0 -1
- package/dist/mail-profile/mail-profile.module.js.map +0 -1
- package/dist/mail-profile/mail-profile.service.d.ts +0 -109
- package/dist/mail-profile/mail-profile.service.d.ts.map +0 -1
- package/dist/mail-profile/mail-profile.service.js +0 -278
- package/dist/mail-profile/mail-profile.service.js.map +0 -1
- package/dist/mcp/tools/core-mail-profile.mcp-tools.d.ts +0 -32
- package/dist/mcp/tools/core-mail-profile.mcp-tools.d.ts.map +0 -1
- package/dist/mcp/tools/core-mail-profile.mcp-tools.js +0 -178
- package/dist/mcp/tools/core-mail-profile.mcp-tools.js.map +0 -1
- package/hedhog/data/mail_profile.yaml +0 -18
- package/hedhog/table/mail_profile.yaml +0 -75
- package/src/mail-profile/dto/create.dto.ts +0 -145
- package/src/mail-profile/mail-profile.controller.ts +0 -56
- package/src/mail-profile/mail-profile.module.ts +0 -18
- package/src/mail-profile/mail-profile.service.ts +0 -308
- package/src/mcp/tools/core-mail-profile.mcp-tools.ts +0 -128
- /package/dist/{mail-profile → integration-profile}/dto/update.dto.d.ts +0 -0
- /package/dist/{mail-profile → integration-profile}/dto/update.dto.js +0 -0
- /package/src/{mail-profile → integration-profile}/dto/update.dto.ts +0 -0
package/src/file/file.service.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
forwardRef,
|
|
7
7
|
Inject,
|
|
8
8
|
Injectable,
|
|
9
|
+
Logger,
|
|
9
10
|
NotFoundException,
|
|
10
11
|
OnModuleInit
|
|
11
12
|
} from '@nestjs/common';
|
|
@@ -13,17 +14,31 @@ import { JwtService } from '@nestjs/jwt';
|
|
|
13
14
|
import { createWriteStream, promises as fs } from 'fs';
|
|
14
15
|
import { basename, dirname } from 'path';
|
|
15
16
|
import { pipeline } from 'stream/promises';
|
|
17
|
+
import {
|
|
18
|
+
buildStorageConfigFromIntegration,
|
|
19
|
+
resolveFileProviderSlug,
|
|
20
|
+
resolveStorageEnumProvider,
|
|
21
|
+
} from '../integration-profile/integration-profile.utils';
|
|
16
22
|
import { SettingService } from '../setting/setting.service';
|
|
17
23
|
import { DeleteDTO } from './dto/delete.dto';
|
|
18
24
|
import { AbstractProvider } from './provider/abstract.provider';
|
|
19
|
-
import { EnumProvider } from './provider/provider.enum';
|
|
20
25
|
import { ProviderFactory } from './provider/provider.factory';
|
|
21
26
|
|
|
22
27
|
@Injectable()
|
|
23
28
|
export class FileService implements OnModuleInit {
|
|
24
|
-
private
|
|
29
|
+
private readonly logger = new Logger(FileService.name);
|
|
30
|
+
private providerId: number | undefined;
|
|
25
31
|
private mimetypes: Record<string, number> = {};
|
|
26
32
|
|
|
33
|
+
private resolveProviderPath(file: { location: string; path: string }): string {
|
|
34
|
+
// Supports legacy basename-only values while prioritizing full provider keys.
|
|
35
|
+
if (typeof file.path === 'string' && file.path.includes('/')) {
|
|
36
|
+
return file.path;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return `${file.location}/${file.path}`;
|
|
40
|
+
}
|
|
41
|
+
|
|
27
42
|
private hasMojibake(value: string): boolean {
|
|
28
43
|
return /Ã.|Â.|â[\u0080-\u00BF]/.test(value);
|
|
29
44
|
}
|
|
@@ -53,53 +68,60 @@ export class FileService implements OnModuleInit {
|
|
|
53
68
|
) { }
|
|
54
69
|
|
|
55
70
|
async onModuleInit() {
|
|
56
|
-
|
|
71
|
+
try {
|
|
72
|
+
await this.getProvider();
|
|
73
|
+
} catch (error) {
|
|
74
|
+
// No storage profile configured yet — server starts normally, uploads will
|
|
75
|
+
// fail until a profile is selected in Settings → File Storage.
|
|
76
|
+
this.logger.warn(
|
|
77
|
+
`Storage provider not ready on startup: ${error instanceof Error ? error.message : String(error)}`,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
57
80
|
}
|
|
58
81
|
|
|
59
82
|
async getProvider(): Promise<AbstractProvider> {
|
|
60
|
-
const settings = await this.settingService.getSettingValues([
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
'storage
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
83
|
+
const settings = await this.settingService.getSettingValues(['file-storage-profile-id']);
|
|
84
|
+
const rawProfileId = settings['file-storage-profile-id'];
|
|
85
|
+
const profileId = Number(rawProfileId);
|
|
86
|
+
|
|
87
|
+
if (!Number.isFinite(profileId) || profileId <= 0) {
|
|
88
|
+
throw new BadRequestException('No file storage profile configured. Set a storage profile in the File Storage settings.');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const profile = await this.prismaService.integration_profile.findUnique({
|
|
92
|
+
where: { id: profileId },
|
|
93
|
+
include: {
|
|
94
|
+
integration_type: { select: { slug: true } },
|
|
95
|
+
integration_provider: { select: { slug: true } },
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
if (!profile) {
|
|
100
|
+
throw new NotFoundException(`Storage profile with id ${profileId} not found.`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (profile.integration_type.slug !== 'storage') {
|
|
76
104
|
throw new BadRequestException(
|
|
77
|
-
`
|
|
105
|
+
`Integration profile with id ${profileId} is not a storage profile.`,
|
|
78
106
|
);
|
|
79
107
|
}
|
|
80
108
|
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
this.jwtService,
|
|
86
|
-
);
|
|
109
|
+
const providerSlug = profile.integration_provider.slug;
|
|
110
|
+
const config = buildStorageConfigFromIntegration(providerSlug, profile.config);
|
|
111
|
+
const enumProvider = resolveStorageEnumProvider(providerSlug);
|
|
112
|
+
const fileProviderSlug = resolveFileProviderSlug(providerSlug);
|
|
87
113
|
|
|
88
114
|
const providerData = await this.prismaService.file_provider.findFirst({
|
|
89
|
-
where: {
|
|
90
|
-
|
|
91
|
-
},
|
|
92
|
-
select: {
|
|
93
|
-
id: true,
|
|
94
|
-
},
|
|
115
|
+
where: { slug: fileProviderSlug },
|
|
116
|
+
select: { id: true },
|
|
95
117
|
});
|
|
96
118
|
|
|
97
119
|
if (!providerData) {
|
|
98
|
-
throw new BadRequestException(`Provider ${
|
|
120
|
+
throw new BadRequestException(`Provider ${fileProviderSlug} not found.`);
|
|
99
121
|
}
|
|
100
122
|
|
|
101
123
|
this.providerId = providerData.id;
|
|
102
|
-
return
|
|
124
|
+
return await ProviderFactory.create(enumProvider, config, this.jwtService);
|
|
103
125
|
}
|
|
104
126
|
|
|
105
127
|
async getMimeType(mimetype: string) {
|
|
@@ -130,58 +152,22 @@ export class FileService implements OnModuleInit {
|
|
|
130
152
|
}
|
|
131
153
|
|
|
132
154
|
async acceptMimetypes(mimetype: string) {
|
|
133
|
-
|
|
134
155
|
if (!mimetype) {
|
|
135
156
|
throw new BadRequestException(`No mimetype provided`);
|
|
136
157
|
}
|
|
137
158
|
|
|
138
|
-
await this.
|
|
139
|
-
|
|
140
|
-
const settings = await this.settingService.getSettingValues([
|
|
141
|
-
'storage',
|
|
142
|
-
'storage-local-path',
|
|
143
|
-
'storage-s3-key',
|
|
144
|
-
'storage-s3-secret',
|
|
145
|
-
'storage-s3-region',
|
|
146
|
-
'storage-s3-bucket',
|
|
147
|
-
'storage-max-size',
|
|
148
|
-
'storage-accept-mimetype',
|
|
149
|
-
'storage-abs-account',
|
|
150
|
-
'storage-abs-key',
|
|
151
|
-
'storage-abs-container',
|
|
152
|
-
'storage-gcs-keyfile',
|
|
153
|
-
]);
|
|
154
|
-
|
|
159
|
+
const settings = await this.settingService.getSettingValues(['storage-accept-mimetype']);
|
|
155
160
|
const acceptMimetypes = settings['storage-accept-mimetype'];
|
|
156
161
|
return acceptMimetypes.indexOf(mimetype) !== -1;
|
|
157
162
|
}
|
|
158
163
|
|
|
159
164
|
async maxFileSize(size: number) {
|
|
160
|
-
|
|
161
165
|
if (!size) {
|
|
162
166
|
throw new BadRequestException(`No size provided`);
|
|
163
167
|
}
|
|
164
168
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
const settings = await this.settingService.getSettingValues([
|
|
168
|
-
'storage',
|
|
169
|
-
'storage-local-path',
|
|
170
|
-
'storage-s3-key',
|
|
171
|
-
'storage-s3-secret',
|
|
172
|
-
'storage-s3-region',
|
|
173
|
-
'storage-s3-bucket',
|
|
174
|
-
'storage-max-size',
|
|
175
|
-
'storage-accept-mimetype',
|
|
176
|
-
'storage-abs-account',
|
|
177
|
-
'storage-abs-key',
|
|
178
|
-
'storage-abs-container',
|
|
179
|
-
'storage-gcs-keyfile',
|
|
180
|
-
]);
|
|
181
|
-
|
|
182
|
-
const maxSize = settings['storage-max-size'];
|
|
183
|
-
|
|
184
|
-
return size <= Number(maxSize);
|
|
169
|
+
const settings = await this.settingService.getSettingValues(['storage-max-size']);
|
|
170
|
+
return size <= Number(settings['storage-max-size']);
|
|
185
171
|
}
|
|
186
172
|
|
|
187
173
|
async uploadFromString(
|
|
@@ -230,26 +216,6 @@ export class FileService implements OnModuleInit {
|
|
|
230
216
|
return file;
|
|
231
217
|
}
|
|
232
218
|
|
|
233
|
-
async getStorage() {
|
|
234
|
-
const settings = await this.settingService.getSettingValues([
|
|
235
|
-
'storage',
|
|
236
|
-
]);
|
|
237
|
-
|
|
238
|
-
return settings['storage'];
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
private getProviderPath(storage: string, filepath: string) {
|
|
242
|
-
if (storage === EnumProvider.LOCAL) {
|
|
243
|
-
return filepath;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
try {
|
|
247
|
-
return new URL(filepath).pathname;
|
|
248
|
-
} catch {
|
|
249
|
-
return filepath;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
219
|
private mapStorageNotFoundError(error: any, fileId: number) {
|
|
254
220
|
const missingInStorage =
|
|
255
221
|
error?.name === 'NoSuchKey' ||
|
|
@@ -281,9 +247,8 @@ export class FileService implements OnModuleInit {
|
|
|
281
247
|
throw new NotFoundException(`File not found: ${fileId}`);
|
|
282
248
|
}
|
|
283
249
|
|
|
284
|
-
const storage = await this.getStorage();
|
|
285
250
|
const provider = await this.getProvider();
|
|
286
|
-
const providerPath = this.
|
|
251
|
+
const providerPath = this.resolveProviderPath(file);
|
|
287
252
|
|
|
288
253
|
let metadata: any;
|
|
289
254
|
try {
|
|
@@ -364,11 +329,8 @@ export class FileService implements OnModuleInit {
|
|
|
364
329
|
throw new NotFoundException(`File not found: ${fileId}`);
|
|
365
330
|
}
|
|
366
331
|
|
|
367
|
-
const storage = await this.getStorage();
|
|
368
|
-
|
|
369
332
|
const provider = await this.getProvider();
|
|
370
|
-
|
|
371
|
-
const providerPath = this.getProviderPath(storage, file.path);
|
|
333
|
+
const providerPath = this.resolveProviderPath(file);
|
|
372
334
|
|
|
373
335
|
let providerBuffer: Buffer;
|
|
374
336
|
try {
|
|
@@ -542,6 +504,7 @@ export class FileService implements OnModuleInit {
|
|
|
542
504
|
},
|
|
543
505
|
select: {
|
|
544
506
|
id: true,
|
|
507
|
+
location: true,
|
|
545
508
|
path: true,
|
|
546
509
|
},
|
|
547
510
|
});
|
|
@@ -551,7 +514,7 @@ export class FileService implements OnModuleInit {
|
|
|
551
514
|
}
|
|
552
515
|
|
|
553
516
|
for (const file of files) {
|
|
554
|
-
await (await this.getProvider()).delete(file
|
|
517
|
+
await (await this.getProvider()).delete(this.resolveProviderPath(file));
|
|
555
518
|
|
|
556
519
|
await this.prismaService.file.deleteMany({
|
|
557
520
|
where: {
|
|
@@ -645,8 +608,9 @@ export class FileService implements OnModuleInit {
|
|
|
645
608
|
}
|
|
646
609
|
|
|
647
610
|
const provider = await this.getProvider();
|
|
648
|
-
const
|
|
649
|
-
const
|
|
611
|
+
const providerPath = this.resolveProviderPath(file);
|
|
612
|
+
const metadata = await provider.metaData(providerPath);
|
|
613
|
+
const stream = await provider.readStream(providerPath);
|
|
650
614
|
const size = this.getFileSizeFromMetadata(metadata);
|
|
651
615
|
|
|
652
616
|
return {
|
|
@@ -674,9 +638,8 @@ export class FileService implements OnModuleInit {
|
|
|
674
638
|
);
|
|
675
639
|
}
|
|
676
640
|
|
|
677
|
-
const storage = await this.getStorage();
|
|
678
641
|
const provider = await this.getProvider();
|
|
679
|
-
const providerPath = this.
|
|
642
|
+
const providerPath = this.resolveProviderPath(file);
|
|
680
643
|
const metadata = await provider.metaData(providerPath);
|
|
681
644
|
const stream = await provider.readStream(providerPath);
|
|
682
645
|
const size = this.getFileSizeFromMetadata(metadata);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
BlobServiceClient,
|
|
3
|
+
ContainerSASPermissions,
|
|
4
|
+
generateBlobSASQueryParameters,
|
|
5
|
+
StorageSharedKeyCredential,
|
|
6
6
|
} from '@azure/storage-blob';
|
|
7
7
|
import { BadRequestException } from '@nestjs/common';
|
|
8
8
|
import { basename } from 'path';
|
|
@@ -11,7 +11,6 @@ import { AbstractProvider } from './abstract.provider';
|
|
|
11
11
|
export class AzureProvider extends AbstractProvider {
|
|
12
12
|
constructor(private setting: Record<string, string>) {
|
|
13
13
|
super();
|
|
14
|
-
this.initValidation();
|
|
15
14
|
}
|
|
16
15
|
|
|
17
16
|
async initValidation() {
|
|
@@ -68,13 +67,13 @@ export class AzureProvider extends AbstractProvider {
|
|
|
68
67
|
const containerClient = blobServiceClient.getContainerClient(
|
|
69
68
|
this.setting['storage-abs-container'],
|
|
70
69
|
);
|
|
71
|
-
const
|
|
72
|
-
const blobClient = containerClient.getBlockBlobClient(
|
|
70
|
+
const storedFilename = this.getFilename(filename);
|
|
71
|
+
const blobClient = containerClient.getBlockBlobClient([destination, storedFilename].join('/'));
|
|
73
72
|
|
|
74
73
|
await blobClient.upload(fileContent, fileContent.length, {
|
|
75
74
|
blobHTTPHeaders: { blobContentType: mimetype },
|
|
76
75
|
});
|
|
77
|
-
return
|
|
76
|
+
return storedFilename;
|
|
78
77
|
}
|
|
79
78
|
|
|
80
79
|
async upload(destination: string, file: MulterFile): Promise<any> {
|
|
@@ -82,15 +81,13 @@ export class AzureProvider extends AbstractProvider {
|
|
|
82
81
|
const containerClient = blobServiceClient.getContainerClient(
|
|
83
82
|
this.setting['storage-abs-container'],
|
|
84
83
|
);
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
);
|
|
88
|
-
const blobClient = containerClient.getBlockBlobClient(filepath);
|
|
84
|
+
const storedFilename = this.getFilename(file.originalname);
|
|
85
|
+
const blobClient = containerClient.getBlockBlobClient([destination, storedFilename].join('/'));
|
|
89
86
|
|
|
90
87
|
await blobClient.uploadData(file.buffer, {
|
|
91
88
|
blobHTTPHeaders: { blobContentType: file.mimetype },
|
|
92
89
|
});
|
|
93
|
-
return
|
|
90
|
+
return storedFilename;
|
|
94
91
|
}
|
|
95
92
|
|
|
96
93
|
async uploadFromPath(
|
|
@@ -102,10 +99,8 @@ export class AzureProvider extends AbstractProvider {
|
|
|
102
99
|
const containerClient = blobServiceClient.getContainerClient(
|
|
103
100
|
this.setting['storage-abs-container'],
|
|
104
101
|
);
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
);
|
|
108
|
-
const blobClient = containerClient.getBlockBlobClient(filepath);
|
|
102
|
+
const storedFilename = this.getFilename(options?.filename ?? basename(filePath));
|
|
103
|
+
const blobClient = containerClient.getBlockBlobClient([destination, storedFilename].join('/'));
|
|
109
104
|
|
|
110
105
|
await blobClient.uploadFile(filePath, {
|
|
111
106
|
blobHTTPHeaders: options?.mimetype
|
|
@@ -113,24 +108,15 @@ export class AzureProvider extends AbstractProvider {
|
|
|
113
108
|
: undefined,
|
|
114
109
|
});
|
|
115
110
|
|
|
116
|
-
return
|
|
111
|
+
return storedFilename;
|
|
117
112
|
}
|
|
118
113
|
|
|
119
114
|
async delete(filepath: string): Promise<any> {
|
|
120
|
-
const url = new URL(filepath);
|
|
121
|
-
|
|
122
|
-
if (!url.pathname) {
|
|
123
|
-
throw new Error(`Invalid filepath "${filepath}" for S3`);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
115
|
const blobServiceClient = await this.getClient();
|
|
127
116
|
const containerClient = blobServiceClient.getContainerClient(
|
|
128
117
|
this.setting['storage-abs-container'],
|
|
129
118
|
);
|
|
130
|
-
const blobClient = containerClient.getBlockBlobClient(
|
|
131
|
-
url.pathname.split('/').slice(1).join('/'),
|
|
132
|
-
);
|
|
133
|
-
|
|
119
|
+
const blobClient = containerClient.getBlockBlobClient(filepath);
|
|
134
120
|
return await blobClient.delete();
|
|
135
121
|
}
|
|
136
122
|
|
|
@@ -8,7 +8,6 @@ export class GCSProvider extends AbstractProvider {
|
|
|
8
8
|
|
|
9
9
|
constructor(private setting: Record<string, string>) {
|
|
10
10
|
super();
|
|
11
|
-
this.initValidation();
|
|
12
11
|
}
|
|
13
12
|
|
|
14
13
|
async initValidation() {
|
|
@@ -53,20 +52,21 @@ export class GCSProvider extends AbstractProvider {
|
|
|
53
52
|
): Promise<any> {
|
|
54
53
|
const storage = await this.getClient();
|
|
55
54
|
const bucket = storage.bucket(this.setting['storage-gcs-bucket']);
|
|
56
|
-
const
|
|
55
|
+
const storedFilename = this.getFilename(filename);
|
|
56
|
+
const file = bucket.file([destination, storedFilename].join('/'));
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
});
|
|
58
|
+
await file.save(fileContent, { contentType: mimetype });
|
|
59
|
+
return storedFilename;
|
|
61
60
|
}
|
|
61
|
+
|
|
62
62
|
async upload(destination: string, file: MulterFile): Promise<any> {
|
|
63
63
|
const storage = await this.getClient();
|
|
64
64
|
const bucket = storage.bucket(this.setting['storage-gcs-bucket']);
|
|
65
|
-
const
|
|
65
|
+
const storedFilename = this.getFilename(file.originalname);
|
|
66
|
+
const fileObject = bucket.file([destination, storedFilename].join('/'));
|
|
66
67
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
});
|
|
68
|
+
await fileObject.save(file.buffer, { contentType: file.mimetype });
|
|
69
|
+
return storedFilename;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
async uploadFromPath(
|
|
@@ -13,7 +13,6 @@ export class LocalProvider extends AbstractProvider {
|
|
|
13
13
|
private jwt: JwtService
|
|
14
14
|
) {
|
|
15
15
|
super();
|
|
16
|
-
this.initValidation();
|
|
17
16
|
}
|
|
18
17
|
|
|
19
18
|
async initValidation() {
|
|
@@ -40,7 +39,8 @@ export class LocalProvider extends AbstractProvider {
|
|
|
40
39
|
}
|
|
41
40
|
|
|
42
41
|
private resolveFilepath(filepath: string): string {
|
|
43
|
-
|
|
42
|
+
if (path.isAbsolute(filepath)) return filepath;
|
|
43
|
+
return join(this.setting['storage-local-path'], filepath);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
async uploadFromString(
|
|
@@ -67,11 +67,12 @@ export class LocalProvider extends AbstractProvider {
|
|
|
67
67
|
);
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
const
|
|
70
|
+
const storedFilename = this.getFilename(filename);
|
|
71
|
+
const filePath = join(storagePath, storedFilename);
|
|
71
72
|
|
|
72
73
|
await writeFile(filePath, fileContent);
|
|
73
74
|
|
|
74
|
-
return
|
|
75
|
+
return storedFilename;
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
async upload(destination: string, file: MulterFile): Promise<any> {
|
|
@@ -92,11 +93,9 @@ export class LocalProvider extends AbstractProvider {
|
|
|
92
93
|
`The storage path does not exist: ${storagePath}`,
|
|
93
94
|
);
|
|
94
95
|
}
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
return filePath;
|
|
96
|
+
const storedFilename = this.getFilename(file.originalname);
|
|
97
|
+
await writeFile(join(storagePath, storedFilename), file.buffer);
|
|
98
|
+
return storedFilename;
|
|
100
99
|
}
|
|
101
100
|
|
|
102
101
|
async uploadFromPath(
|
|
@@ -121,10 +120,8 @@ export class LocalProvider extends AbstractProvider {
|
|
|
121
120
|
}
|
|
122
121
|
|
|
123
122
|
const targetFilename = this.getFilename(options?.filename ?? basename(sourcePath));
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
return targetPath;
|
|
123
|
+
await copyFile(sourcePath, join(storagePath, targetFilename));
|
|
124
|
+
return targetFilename;
|
|
128
125
|
}
|
|
129
126
|
|
|
130
127
|
async delete(filepath: string): Promise<any> {
|
|
@@ -5,22 +5,37 @@ import { GCSProvider } from './gcs.provider';
|
|
|
5
5
|
import { LocalProvider } from './local.provider';
|
|
6
6
|
import { EnumProvider } from './provider.enum';
|
|
7
7
|
import { S3Provider } from './s3.provider';
|
|
8
|
+
import { SpacesProvider } from './spaces.provider';
|
|
8
9
|
|
|
9
10
|
export class ProviderFactory {
|
|
10
|
-
static create(
|
|
11
|
+
static async create(
|
|
11
12
|
providerType: EnumProvider,
|
|
12
13
|
setting: Record<string, string>,
|
|
13
14
|
jwtService: JwtService,
|
|
14
|
-
): AbstractProvider {
|
|
15
|
+
): Promise<AbstractProvider> {
|
|
16
|
+
let provider: AbstractProvider;
|
|
17
|
+
|
|
15
18
|
switch (providerType) {
|
|
16
19
|
case EnumProvider.S3:
|
|
17
|
-
|
|
20
|
+
provider = new S3Provider(setting);
|
|
21
|
+
break;
|
|
18
22
|
case EnumProvider.LOCAL:
|
|
19
|
-
|
|
23
|
+
provider = new LocalProvider(setting, jwtService);
|
|
24
|
+
break;
|
|
20
25
|
case EnumProvider.AZURE:
|
|
21
|
-
|
|
26
|
+
provider = new AzureProvider(setting);
|
|
27
|
+
break;
|
|
22
28
|
case EnumProvider.GCS:
|
|
23
|
-
|
|
29
|
+
provider = new GCSProvider(setting);
|
|
30
|
+
break;
|
|
31
|
+
case EnumProvider.SPACES:
|
|
32
|
+
provider = new SpacesProvider(setting);
|
|
33
|
+
break;
|
|
34
|
+
default:
|
|
35
|
+
throw new Error(`Unsupported provider type: ${providerType}`);
|
|
24
36
|
}
|
|
37
|
+
|
|
38
|
+
await provider.initValidation();
|
|
39
|
+
return provider;
|
|
25
40
|
}
|
|
26
41
|
}
|
|
@@ -20,28 +20,13 @@ export class S3Provider extends AbstractProvider {
|
|
|
20
20
|
|
|
21
21
|
constructor(private setting: Record<string, string>) {
|
|
22
22
|
super();
|
|
23
|
-
this.initValidation();
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
private resolveS3Key(filepath: string): string {
|
|
27
26
|
if (!filepath) {
|
|
28
27
|
throw new Error('Invalid filepath for S3');
|
|
29
28
|
}
|
|
30
|
-
|
|
31
|
-
try {
|
|
32
|
-
const url = new URL(filepath);
|
|
33
|
-
const keyFromUrl = url.pathname.split('/').filter(Boolean).join('/');
|
|
34
|
-
if (!keyFromUrl) {
|
|
35
|
-
throw new Error(`Invalid filepath "${filepath}" for S3`);
|
|
36
|
-
}
|
|
37
|
-
return keyFromUrl;
|
|
38
|
-
} catch {
|
|
39
|
-
const keyFromPath = filepath.split('/').filter(Boolean).join('/');
|
|
40
|
-
if (!keyFromPath) {
|
|
41
|
-
throw new Error(`Invalid filepath "${filepath}" for S3`);
|
|
42
|
-
}
|
|
43
|
-
return keyFromPath;
|
|
44
|
-
}
|
|
29
|
+
return filepath;
|
|
45
30
|
}
|
|
46
31
|
|
|
47
32
|
async buffer(filepath: string): Promise<Buffer> {
|
|
@@ -151,8 +136,7 @@ export class S3Provider extends AbstractProvider {
|
|
|
151
136
|
Body: fileContent,
|
|
152
137
|
});
|
|
153
138
|
await s3.send(command);
|
|
154
|
-
|
|
155
|
-
return `https://${this.setting['storage-s3-bucket']}.s3.${this.setting['storage-s3-region']}.amazonaws.com/${key}`;
|
|
139
|
+
return storedFilename;
|
|
156
140
|
}
|
|
157
141
|
|
|
158
142
|
async upload(destination: string, file: MulterFile): Promise<any> {
|
|
@@ -165,7 +149,7 @@ export class S3Provider extends AbstractProvider {
|
|
|
165
149
|
Body: file.buffer,
|
|
166
150
|
});
|
|
167
151
|
await s3.send(command);
|
|
168
|
-
return
|
|
152
|
+
return storedFilename;
|
|
169
153
|
}
|
|
170
154
|
|
|
171
155
|
async uploadFromPath(
|
|
@@ -185,7 +169,7 @@ export class S3Provider extends AbstractProvider {
|
|
|
185
169
|
});
|
|
186
170
|
|
|
187
171
|
await s3.send(command);
|
|
188
|
-
return
|
|
172
|
+
return storedFilename;
|
|
189
173
|
}
|
|
190
174
|
|
|
191
175
|
async delete(filepath: string): Promise<any> {
|