@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
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { BadRequestException } from '@nestjs/common';
|
|
2
|
+
import { EnumProvider } from '../file/provider/provider.enum';
|
|
3
|
+
|
|
4
|
+
type Cfg = Record<string, unknown>;
|
|
5
|
+
|
|
6
|
+
export function buildMailConfigFromIntegration(
|
|
7
|
+
providerSlug: string,
|
|
8
|
+
config: unknown,
|
|
9
|
+
): any {
|
|
10
|
+
const cfg = (config as Cfg) ?? {};
|
|
11
|
+
|
|
12
|
+
switch (providerSlug.toLowerCase()) {
|
|
13
|
+
case 'smtp':
|
|
14
|
+
return {
|
|
15
|
+
global: true,
|
|
16
|
+
type: 'SMTP' as const,
|
|
17
|
+
host: String(cfg.host ?? ''),
|
|
18
|
+
port: Number(cfg.port ?? 587),
|
|
19
|
+
secure: Boolean(cfg.secure),
|
|
20
|
+
username: String(cfg.username ?? ''),
|
|
21
|
+
password: String(cfg.password ?? ''),
|
|
22
|
+
};
|
|
23
|
+
case 'gmail':
|
|
24
|
+
return {
|
|
25
|
+
global: true,
|
|
26
|
+
type: 'GMAIL' as const,
|
|
27
|
+
clientId: String(cfg.client_id ?? ''),
|
|
28
|
+
clientSecret: String(cfg.client_secret ?? ''),
|
|
29
|
+
refreshToken: String(cfg.refresh_token ?? ''),
|
|
30
|
+
from: String(cfg.from_email ?? ''),
|
|
31
|
+
};
|
|
32
|
+
case 'ses':
|
|
33
|
+
return {
|
|
34
|
+
global: true,
|
|
35
|
+
type: 'SES' as const,
|
|
36
|
+
region: String(cfg.region ?? ''),
|
|
37
|
+
accessKeyId: String(cfg.access_key_id ?? ''),
|
|
38
|
+
secretAccessKey: String(cfg.secret_access_key ?? ''),
|
|
39
|
+
from: String(cfg.from_email ?? ''),
|
|
40
|
+
};
|
|
41
|
+
default:
|
|
42
|
+
throw new BadRequestException(`Unsupported mail provider: ${providerSlug}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function getFromAddress(config: unknown): string {
|
|
47
|
+
const cfg = (config as Cfg) ?? {};
|
|
48
|
+
const fromEmail = String(cfg.from_email ?? '');
|
|
49
|
+
const fromName = String(cfg.from_name ?? '');
|
|
50
|
+
return fromName ? `${fromName} <${fromEmail}>` : fromEmail;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function getReplyToAddress(config: unknown): string | undefined {
|
|
54
|
+
const cfg = (config as Cfg) ?? {};
|
|
55
|
+
const replyToEmail = String(cfg.reply_to_email ?? '').trim();
|
|
56
|
+
if (!replyToEmail) return undefined;
|
|
57
|
+
const replyToName = String(cfg.reply_to_name ?? '').trim();
|
|
58
|
+
return replyToName ? `${replyToName} <${replyToEmail}>` : replyToEmail;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ─── Storage utilities ────────────────────────────────────────────────────────
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Maps an integration_profile config JSON to the flat settings dict that the
|
|
65
|
+
* existing provider classes (S3Provider, AzureProvider, etc.) expect.
|
|
66
|
+
*
|
|
67
|
+
* integration_provider slugs → EnumProvider:
|
|
68
|
+
* local, s3, gcs → same
|
|
69
|
+
* azure-blob → abs
|
|
70
|
+
* s3-compatible → spaces
|
|
71
|
+
*/
|
|
72
|
+
export function buildStorageConfigFromIntegration(
|
|
73
|
+
providerSlug: string,
|
|
74
|
+
config: unknown,
|
|
75
|
+
): Record<string, string> {
|
|
76
|
+
const cfg = (config as Cfg) ?? {};
|
|
77
|
+
|
|
78
|
+
switch (providerSlug.toLowerCase()) {
|
|
79
|
+
case 'local':
|
|
80
|
+
return {
|
|
81
|
+
'storage-local-path': String(cfg.base_path ?? 'storage'),
|
|
82
|
+
};
|
|
83
|
+
case 's3':
|
|
84
|
+
return {
|
|
85
|
+
'storage-s3-key': String(cfg.access_key_id ?? ''),
|
|
86
|
+
'storage-s3-secret': String(cfg.secret_access_key ?? ''),
|
|
87
|
+
'storage-s3-region': String(cfg.region ?? 'us-east-1'),
|
|
88
|
+
'storage-s3-bucket': String(cfg.bucket ?? ''),
|
|
89
|
+
};
|
|
90
|
+
case 'gcs':
|
|
91
|
+
return {
|
|
92
|
+
'storage-gcs-keyfile': String(cfg.key_file_json ?? ''),
|
|
93
|
+
'storage-gcs-bucket': String(cfg.bucket ?? ''),
|
|
94
|
+
};
|
|
95
|
+
case 'azure-blob':
|
|
96
|
+
return {
|
|
97
|
+
'storage-abs-account': String(cfg.account ?? ''),
|
|
98
|
+
'storage-abs-key': String(cfg.key ?? ''),
|
|
99
|
+
'storage-abs-container': String(cfg.container ?? ''),
|
|
100
|
+
};
|
|
101
|
+
case 's3-compatible':
|
|
102
|
+
return {
|
|
103
|
+
'storage-spaces-key': String(cfg.access_key_id ?? ''),
|
|
104
|
+
'storage-spaces-secret': String(cfg.secret_access_key ?? ''),
|
|
105
|
+
'storage-spaces-region': String(cfg.region ?? ''),
|
|
106
|
+
'storage-spaces-bucket': String(cfg.bucket ?? ''),
|
|
107
|
+
'storage-spaces-cdn': String(cfg.endpoint ?? ''),
|
|
108
|
+
};
|
|
109
|
+
default:
|
|
110
|
+
throw new BadRequestException(`Unsupported storage provider: ${providerSlug}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Maps integration_provider slug to EnumProvider. */
|
|
115
|
+
export function resolveStorageEnumProvider(providerSlug: string): EnumProvider {
|
|
116
|
+
switch (providerSlug.toLowerCase()) {
|
|
117
|
+
case 'local': return EnumProvider.LOCAL;
|
|
118
|
+
case 's3': return EnumProvider.S3;
|
|
119
|
+
case 'gcs': return EnumProvider.GCS;
|
|
120
|
+
case 'azure-blob': return EnumProvider.AZURE;
|
|
121
|
+
case 's3-compatible': return EnumProvider.SPACES;
|
|
122
|
+
default:
|
|
123
|
+
throw new BadRequestException(`Unsupported storage provider: ${providerSlug}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Maps integration_provider slug to the slug used in the file_provider table. */
|
|
128
|
+
export function resolveFileProviderSlug(providerSlug: string): string {
|
|
129
|
+
switch (providerSlug.toLowerCase()) {
|
|
130
|
+
case 'azure-blob': return 'abs';
|
|
131
|
+
case 's3-compatible': return 'spaces';
|
|
132
|
+
default: return providerSlug.toLowerCase();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ─── AI utilities ─────────────────────────────────────────────────────────────
|
|
137
|
+
|
|
138
|
+
// ─── OAuth utilities ──────────────────────────────────────────────────────────
|
|
139
|
+
|
|
140
|
+
/** Maps an integration_profile config JSON to OAuth client credentials. */
|
|
141
|
+
export function buildOAuthConfigFromIntegration(
|
|
142
|
+
_providerSlug: string,
|
|
143
|
+
config: unknown,
|
|
144
|
+
): { clientId: string; clientSecret: string; tenantId?: string } {
|
|
145
|
+
const cfg = (config as Cfg) ?? {};
|
|
146
|
+
return {
|
|
147
|
+
clientId: String(cfg.client_id ?? ''),
|
|
148
|
+
clientSecret: String(cfg.client_secret ?? ''),
|
|
149
|
+
...(cfg.tenant_id ? { tenantId: String(cfg.tenant_id) } : {}),
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ─── AI utilities ─────────────────────────────────────────────────────────────
|
|
154
|
+
|
|
155
|
+
/** Maps an integration_profile config JSON to the API key and optional org needed by AI providers. */
|
|
156
|
+
export function buildAiConfigFromIntegration(
|
|
157
|
+
providerSlug: string,
|
|
158
|
+
config: unknown,
|
|
159
|
+
): { apiKey: string; organization?: string } {
|
|
160
|
+
const cfg = (config as Cfg) ?? {};
|
|
161
|
+
switch (providerSlug.toLowerCase()) {
|
|
162
|
+
case 'openai':
|
|
163
|
+
return {
|
|
164
|
+
apiKey: String(cfg.api_key ?? ''),
|
|
165
|
+
...(cfg.organization ? { organization: String(cfg.organization) } : {}),
|
|
166
|
+
};
|
|
167
|
+
case 'gemini':
|
|
168
|
+
case 'claude':
|
|
169
|
+
return { apiKey: String(cfg.api_key ?? '') };
|
|
170
|
+
default:
|
|
171
|
+
throw new BadRequestException(`Unsupported AI provider: ${providerSlug}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
package/src/mail/mail.module.ts
CHANGED
|
@@ -15,52 +15,71 @@ import { MailService } from './mail.service';
|
|
|
15
15
|
inject: [PrismaService],
|
|
16
16
|
useFactory: async (prisma: PrismaService) => {
|
|
17
17
|
try {
|
|
18
|
-
const
|
|
19
|
-
where: {
|
|
20
|
-
|
|
18
|
+
const profileSettings = await prisma.setting.findMany({
|
|
19
|
+
where: {
|
|
20
|
+
slug: {
|
|
21
|
+
in: ['mail-integration-profile-id'],
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
select: { slug: true, value: true },
|
|
21
25
|
});
|
|
22
26
|
|
|
23
|
-
const
|
|
27
|
+
const profileSettingsMap = new Map(
|
|
28
|
+
profileSettings.map((item) => [item.slug, item.value]),
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const profileId = Number(
|
|
32
|
+
profileSettingsMap.get('mail-integration-profile-id'),
|
|
33
|
+
);
|
|
24
34
|
|
|
25
35
|
if (!profileId || profileId <= 0) {
|
|
26
36
|
return { global: true, type: 'SMTP', host: 'localhost', port: 1025, secure: false, username: '', password: '' } as MailModuleOptions;
|
|
27
37
|
}
|
|
28
38
|
|
|
29
|
-
const profile = await prisma.
|
|
39
|
+
const profile = await (prisma as any).integration_profile.findUnique({
|
|
30
40
|
where: { id: profileId },
|
|
41
|
+
include: {
|
|
42
|
+
integration_provider: { select: { slug: true } },
|
|
43
|
+
integration_type: { select: { slug: true } },
|
|
44
|
+
},
|
|
31
45
|
});
|
|
32
46
|
|
|
33
47
|
if (!profile) {
|
|
34
48
|
return { global: true, type: 'SMTP', host: 'localhost', port: 1025, secure: false, username: '', password: '' } as MailModuleOptions;
|
|
35
49
|
}
|
|
36
50
|
|
|
51
|
+
if (profile.integration_type?.slug !== 'email') {
|
|
52
|
+
return { global: true, type: 'SMTP', host: 'localhost', port: 1025, secure: false, username: '', password: '' } as MailModuleOptions;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const cfg = (profile.config as Record<string, unknown>) ?? {};
|
|
37
56
|
const base: MailModuleOptions = { global: true } as MailModuleOptions;
|
|
38
57
|
|
|
39
|
-
switch (profile.
|
|
40
|
-
case '
|
|
58
|
+
switch (profile.integration_provider.slug) {
|
|
59
|
+
case 'gmail':
|
|
41
60
|
return Object.assign(base, {
|
|
42
61
|
type: 'GMAIL',
|
|
43
|
-
clientId:
|
|
44
|
-
clientSecret:
|
|
45
|
-
refreshToken:
|
|
46
|
-
from:
|
|
62
|
+
clientId: String(cfg.client_id ?? ''),
|
|
63
|
+
clientSecret: String(cfg.client_secret ?? ''),
|
|
64
|
+
refreshToken: String(cfg.refresh_token ?? ''),
|
|
65
|
+
from: String(cfg.from_email ?? ''),
|
|
47
66
|
});
|
|
48
|
-
case '
|
|
67
|
+
case 'smtp':
|
|
49
68
|
return Object.assign(base, {
|
|
50
69
|
type: 'SMTP',
|
|
51
|
-
host:
|
|
52
|
-
port:
|
|
53
|
-
secure:
|
|
54
|
-
username:
|
|
55
|
-
password:
|
|
70
|
+
host: String(cfg.host ?? 'localhost'),
|
|
71
|
+
port: Number(cfg.port ?? 1025),
|
|
72
|
+
secure: Boolean(cfg.secure),
|
|
73
|
+
username: String(cfg.username ?? ''),
|
|
74
|
+
password: String(cfg.password ?? ''),
|
|
56
75
|
});
|
|
57
|
-
case '
|
|
76
|
+
case 'ses':
|
|
58
77
|
return Object.assign(base, {
|
|
59
78
|
type: 'SES',
|
|
60
|
-
region:
|
|
61
|
-
accessKeyId:
|
|
62
|
-
secretAccessKey:
|
|
63
|
-
from:
|
|
79
|
+
region: String(cfg.region ?? ''),
|
|
80
|
+
accessKeyId: String(cfg.access_key_id ?? ''),
|
|
81
|
+
secretAccessKey: String(cfg.secret_access_key ?? ''),
|
|
82
|
+
from: String(cfg.from_email ?? ''),
|
|
64
83
|
});
|
|
65
84
|
default:
|
|
66
85
|
return { global: true, type: 'SMTP', host: 'localhost', port: 1025, secure: false, username: '', password: '' } as MailModuleOptions;
|
package/src/mail/mail.service.ts
CHANGED
|
@@ -13,6 +13,10 @@ import {
|
|
|
13
13
|
OnModuleInit,
|
|
14
14
|
} from '@nestjs/common';
|
|
15
15
|
import * as Handlebars from 'handlebars';
|
|
16
|
+
import {
|
|
17
|
+
buildMailConfigFromIntegration,
|
|
18
|
+
getFromAddress,
|
|
19
|
+
} from '../integration-profile/integration-profile.utils';
|
|
16
20
|
import { IntegrationDeveloperApiService } from '../integration/services/integration-developer-api.service';
|
|
17
21
|
import { SettingService } from '../setting/setting.service';
|
|
18
22
|
import { CreateDTO } from './dto/create.dto';
|
|
@@ -25,6 +29,8 @@ import { UpdateDTO } from './dto/update.dto';
|
|
|
25
29
|
export class MailService implements OnModuleInit {
|
|
26
30
|
private readonly logger = new Logger(MailService.name);
|
|
27
31
|
private readonly modelName = 'mail';
|
|
32
|
+
private readonly integrationProfileSettingSlug =
|
|
33
|
+
'mail-integration-profile-id';
|
|
28
34
|
|
|
29
35
|
constructor(
|
|
30
36
|
@Inject(forwardRef(() => PrismaService))
|
|
@@ -55,11 +61,10 @@ export class MailService implements OnModuleInit {
|
|
|
55
61
|
},
|
|
56
62
|
});
|
|
57
63
|
|
|
58
|
-
void this.syncConfiguredMailFlag();
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
private isMailConfigSlug(slug: string) {
|
|
62
|
-
return slug ===
|
|
67
|
+
return slug === this.integrationProfileSettingSlug;
|
|
63
68
|
}
|
|
64
69
|
|
|
65
70
|
private isSettingEnabled(value: unknown) {
|
|
@@ -68,8 +73,10 @@ export class MailService implements OnModuleInit {
|
|
|
68
73
|
|
|
69
74
|
private async syncConfiguredMailFlag() {
|
|
70
75
|
try {
|
|
71
|
-
const settings = await this.setting.getSettingValues([
|
|
72
|
-
|
|
76
|
+
const settings = await this.setting.getSettingValues([
|
|
77
|
+
this.integrationProfileSettingSlug,
|
|
78
|
+
]);
|
|
79
|
+
const profileId = settings[this.integrationProfileSettingSlug];
|
|
73
80
|
|
|
74
81
|
if (!profileId || Number(profileId) <= 0) {
|
|
75
82
|
await this.setting.setValue('configured-mail', 'false');
|
|
@@ -96,89 +103,58 @@ export class MailService implements OnModuleInit {
|
|
|
96
103
|
|
|
97
104
|
/**
|
|
98
105
|
* Reload mail configuration from database and update MailMainService.
|
|
106
|
+
* When profileId is provided, that profile is used directly.
|
|
107
|
+
* Otherwise the global integration profile setting is read.
|
|
99
108
|
* Returns the active from address and the built config object.
|
|
100
109
|
*/
|
|
101
|
-
async reloadConfig(): Promise<{ success: boolean; provider: string; from: string; config: any }> {
|
|
110
|
+
async reloadConfig(profileId?: number): Promise<{ success: boolean; provider: string; from: string; config: any }> {
|
|
102
111
|
try {
|
|
103
|
-
|
|
104
|
-
|
|
112
|
+
let resolvedProfileId = profileId;
|
|
113
|
+
|
|
114
|
+
if (!resolvedProfileId) {
|
|
115
|
+
const settings = await this.setting.getSettingValues([
|
|
116
|
+
this.integrationProfileSettingSlug,
|
|
117
|
+
]);
|
|
118
|
+
resolvedProfileId = Number(settings[this.integrationProfileSettingSlug]);
|
|
119
|
+
}
|
|
105
120
|
|
|
106
|
-
if (!
|
|
121
|
+
if (!resolvedProfileId || resolvedProfileId <= 0) {
|
|
107
122
|
throw new BadRequestException('No mail profile configured. Set a mail profile in the Mail settings.');
|
|
108
123
|
}
|
|
109
124
|
|
|
110
|
-
const profile = await this.prismaService.
|
|
111
|
-
where: { id:
|
|
125
|
+
const profile = await this.prismaService.integration_profile.findUnique({
|
|
126
|
+
where: { id: resolvedProfileId },
|
|
127
|
+
include: {
|
|
128
|
+
integration_provider: { select: { slug: true } },
|
|
129
|
+
integration_type: { select: { slug: true } },
|
|
130
|
+
},
|
|
112
131
|
});
|
|
113
132
|
|
|
114
133
|
if (!profile) {
|
|
115
134
|
throw new NotFoundException(`Mail profile with id ${profileId} not found.`);
|
|
116
135
|
}
|
|
117
136
|
|
|
118
|
-
|
|
137
|
+
if (profile.integration_type?.slug !== 'email') {
|
|
138
|
+
throw new BadRequestException(
|
|
139
|
+
`Integration profile ${resolvedProfileId} is not an email profile.`,
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const providerSlug = profile.integration_provider.slug;
|
|
144
|
+
const config = buildMailConfigFromIntegration(providerSlug, profile.config);
|
|
119
145
|
|
|
120
146
|
this.mailMainService.setConfig(config);
|
|
121
|
-
this.logger.log(`Mail configuration reloaded from profile "${profile.name}" (${
|
|
147
|
+
this.logger.log(`Mail configuration reloaded from profile "${profile.name}" (${providerSlug})`);
|
|
122
148
|
|
|
123
|
-
const from = profile.
|
|
124
|
-
? `${profile.from_name} <${profile.from_email}>`
|
|
125
|
-
: profile.from_email;
|
|
149
|
+
const from = getFromAddress(profile.config);
|
|
126
150
|
|
|
127
|
-
return { success: true, provider:
|
|
151
|
+
return { success: true, provider: providerSlug, from, config };
|
|
128
152
|
} catch (error) {
|
|
129
153
|
this.logger.error('Error reloading mail configuration:', error);
|
|
130
154
|
throw error;
|
|
131
155
|
}
|
|
132
156
|
}
|
|
133
157
|
|
|
134
|
-
private buildMailConfig(profile: {
|
|
135
|
-
provider: string;
|
|
136
|
-
from_email: string;
|
|
137
|
-
smtp_host?: string | null;
|
|
138
|
-
smtp_port?: number | null;
|
|
139
|
-
smtp_secure?: boolean | null;
|
|
140
|
-
smtp_username?: string | null;
|
|
141
|
-
smtp_password?: string | null;
|
|
142
|
-
gmail_client_id?: string | null;
|
|
143
|
-
gmail_client_secret?: string | null;
|
|
144
|
-
gmail_refresh_token?: string | null;
|
|
145
|
-
ses_access_key_id?: string | null;
|
|
146
|
-
ses_secret_access_key?: string | null;
|
|
147
|
-
ses_region?: string | null;
|
|
148
|
-
}): any {
|
|
149
|
-
switch (profile.provider) {
|
|
150
|
-
case 'GMAIL':
|
|
151
|
-
return {
|
|
152
|
-
global: true,
|
|
153
|
-
type: 'GMAIL' as const,
|
|
154
|
-
clientId: profile.gmail_client_id ?? '',
|
|
155
|
-
clientSecret: profile.gmail_client_secret ?? '',
|
|
156
|
-
refreshToken: profile.gmail_refresh_token ?? '',
|
|
157
|
-
from: profile.from_email,
|
|
158
|
-
};
|
|
159
|
-
case 'SMTP':
|
|
160
|
-
return {
|
|
161
|
-
global: true,
|
|
162
|
-
type: 'SMTP' as const,
|
|
163
|
-
host: profile.smtp_host ?? '',
|
|
164
|
-
port: profile.smtp_port ?? 587,
|
|
165
|
-
secure: profile.smtp_secure ?? false,
|
|
166
|
-
username: profile.smtp_username ?? '',
|
|
167
|
-
password: profile.smtp_password ?? '',
|
|
168
|
-
};
|
|
169
|
-
case 'SES':
|
|
170
|
-
return {
|
|
171
|
-
global: true,
|
|
172
|
-
type: 'SES' as const,
|
|
173
|
-
region: profile.ses_region ?? '',
|
|
174
|
-
accessKeyId: profile.ses_access_key_id ?? '',
|
|
175
|
-
secretAccessKey: profile.ses_secret_access_key ?? '',
|
|
176
|
-
from: profile.from_email,
|
|
177
|
-
};
|
|
178
|
-
default:
|
|
179
|
-
throw new BadRequestException(`Invalid mail provider: ${profile.provider}`);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
158
|
|
|
183
159
|
async list(locale: string, paginationParams: PaginationDTO) {
|
|
184
160
|
const result = await this.localeService.listModelWithLocale(
|
|
@@ -38,7 +38,7 @@ export class McpAuthGuard implements CanActivate {
|
|
|
38
38
|
private async verifyApiKey(request: Request, token: string): Promise<boolean> {
|
|
39
39
|
const hash = this.security.hashWithPepper(token);
|
|
40
40
|
const apiKey = await this.prisma.mcp_api_key.findFirst({
|
|
41
|
-
where: { token_hash: hash, revoked_at: null },
|
|
41
|
+
where: { token_hash: hash, type: 'mcp', revoked_at: null },
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
if (!apiKey) {
|
|
@@ -27,9 +27,9 @@ export class McpApiKeyController {
|
|
|
27
27
|
@Post()
|
|
28
28
|
create(
|
|
29
29
|
@User() { id }: { id: number },
|
|
30
|
-
@Body() body: { name: string },
|
|
30
|
+
@Body() body: { name: string; type?: 'mcp' | 'api' },
|
|
31
31
|
) {
|
|
32
|
-
return this.mcpApiKeyService.create(id, body.name);
|
|
32
|
+
return this.mcpApiKeyService.create(id, body.name, body.type);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
@Delete(':id')
|
|
@@ -18,6 +18,7 @@ export class McpApiKeyService {
|
|
|
18
18
|
select: {
|
|
19
19
|
id: true,
|
|
20
20
|
name: true,
|
|
21
|
+
type: true,
|
|
21
22
|
token_prefix: true,
|
|
22
23
|
last_used_at: true,
|
|
23
24
|
expires_at: true,
|
|
@@ -27,8 +28,9 @@ export class McpApiKeyService {
|
|
|
27
28
|
});
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
async create(userId: number, name: string) {
|
|
31
|
-
const
|
|
31
|
+
async create(userId: number, name: string, type: 'mcp' | 'api' = 'mcp') {
|
|
32
|
+
const prefix = type === 'api' ? 'hedhog_api_' : 'hedhog_mcp_';
|
|
33
|
+
const rawToken = prefix + this.security.randomOpaque(36);
|
|
32
34
|
const tokenHash = this.security.hashWithPepper(rawToken);
|
|
33
35
|
const tokenPrefix = rawToken.substring(0, 16);
|
|
34
36
|
|
|
@@ -36,12 +38,14 @@ export class McpApiKeyService {
|
|
|
36
38
|
data: {
|
|
37
39
|
user_id: userId,
|
|
38
40
|
name,
|
|
41
|
+
type,
|
|
39
42
|
token_hash: tokenHash,
|
|
40
43
|
token_prefix: tokenPrefix,
|
|
41
44
|
},
|
|
42
45
|
select: {
|
|
43
46
|
id: true,
|
|
44
47
|
name: true,
|
|
48
|
+
type: true,
|
|
45
49
|
token_prefix: true,
|
|
46
50
|
created_at: true,
|
|
47
51
|
},
|
package/src/mcp/mcp.module.ts
CHANGED
|
@@ -6,8 +6,8 @@ import { AiModule } from '../ai/ai.module';
|
|
|
6
6
|
import { SystemModule } from '../core/system.module';
|
|
7
7
|
import { DashboardModule } from '../dashboard/dashboard.module';
|
|
8
8
|
import { FileModule } from '../file/file.module';
|
|
9
|
+
import { IntegrationProfileModule } from '../integration-profile/integration-profile.module';
|
|
9
10
|
import { MailModule } from '../mail/mail.module';
|
|
10
|
-
import { MailProfileModule } from '../mail-profile/mail-profile.module';
|
|
11
11
|
import { MailSentModule } from '../mail-sent/mail-sent.module';
|
|
12
12
|
import { McpChatService } from '../mcp-chat/mcp-chat.service';
|
|
13
13
|
import { MenuModule } from '../menu/menu.module';
|
|
@@ -37,7 +37,6 @@ import { CoreEventWebhooksMcpTools } from './tools/core-event-webhooks.mcp-tools
|
|
|
37
37
|
import { CoreFilesMcpTools } from './tools/core-files.mcp-tools';
|
|
38
38
|
import { CoreIntegrationEventsMcpTools } from './tools/core-integration-events.mcp-tools';
|
|
39
39
|
import { CoreMailMcpTools } from './tools/core-mail.mcp-tools';
|
|
40
|
-
import { CoreMailProfileMcpTools } from './tools/core-mail-profile.mcp-tools';
|
|
41
40
|
import { CoreMailSentMcpTools } from './tools/core-mail-sent.mcp-tools';
|
|
42
41
|
import { CoreMcpChatMcpTools } from './tools/core-mcp-chat.mcp-tools';
|
|
43
42
|
import { CoreMenusMcpTools } from './tools/core-menus.mcp-tools';
|
|
@@ -69,7 +68,7 @@ import { AccessLogModule } from '../access-log/access-log.module';
|
|
|
69
68
|
forwardRef(() => ScreenModule),
|
|
70
69
|
forwardRef(() => FileModule),
|
|
71
70
|
forwardRef(() => MailModule),
|
|
72
|
-
forwardRef(() =>
|
|
71
|
+
forwardRef(() => IntegrationProfileModule),
|
|
73
72
|
forwardRef(() => MailSentModule),
|
|
74
73
|
forwardRef(() => SessionModule),
|
|
75
74
|
forwardRef(() => NotificationModule),
|
|
@@ -98,7 +97,6 @@ import { AccessLogModule } from '../access-log/access-log.module';
|
|
|
98
97
|
CoreSessionsMcpTools,
|
|
99
98
|
CoreFilesMcpTools,
|
|
100
99
|
CoreMailMcpTools,
|
|
101
|
-
CoreMailProfileMcpTools,
|
|
102
100
|
CoreMailSentMcpTools,
|
|
103
101
|
CoreNotificationsMcpTools,
|
|
104
102
|
CoreDashboardMcpTools,
|
|
@@ -110,6 +108,6 @@ import { AccessLogModule } from '../access-log/access-log.module';
|
|
|
110
108
|
CoreMcpChatMcpTools,
|
|
111
109
|
CoreSystemMcpTools,
|
|
112
110
|
],
|
|
113
|
-
exports: [McpRegistryService, McpServerService],
|
|
111
|
+
exports: [McpRegistryService, McpServerService, McpApiKeyService],
|
|
114
112
|
})
|
|
115
113
|
export class McpModule {}
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
NotFoundException,
|
|
12
12
|
} from '@nestjs/common';
|
|
13
13
|
import axios from 'axios';
|
|
14
|
+
import { buildAiConfigFromIntegration } from '../integration-profile/integration-profile.utils';
|
|
14
15
|
import { McpRegistryService, McpToolEntry } from '../mcp/mcp-registry.service';
|
|
15
16
|
import { McpContext } from '../mcp/types/mcp-context.type';
|
|
16
17
|
import { SettingService } from '../setting/setting.service';
|
|
@@ -772,30 +773,32 @@ export class McpChatService {
|
|
|
772
773
|
}
|
|
773
774
|
|
|
774
775
|
private async getProviderKey(): Promise<{ provider: 'openai' | 'gemini'; apiKey: string }> {
|
|
775
|
-
const settings = await this.setting.getSettingValues([
|
|
776
|
-
|
|
777
|
-
'ai-openai-api-key',
|
|
778
|
-
'ai-gemini-api-key',
|
|
779
|
-
]);
|
|
780
|
-
const provider = ((settings['mcp-ai-provider'] as string) || 'openai') as 'openai' | 'gemini';
|
|
776
|
+
const settings = await this.setting.getSettingValues(['mcp-ai-profile-id']);
|
|
777
|
+
const profileId = Number(settings['mcp-ai-profile-id']);
|
|
781
778
|
|
|
782
|
-
if (
|
|
783
|
-
const key = settings['ai-gemini-api-key'] as string;
|
|
784
|
-
if (!key) {
|
|
785
|
-
throw new BadRequestException(
|
|
786
|
-
'Gemini API key is not configured. Please set it in Settings → AI → Gemini API Key.',
|
|
787
|
-
);
|
|
788
|
-
}
|
|
789
|
-
return { provider: 'gemini', apiKey: key };
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
const key = settings['ai-openai-api-key'] as string;
|
|
793
|
-
if (!key) {
|
|
779
|
+
if (!profileId) {
|
|
794
780
|
throw new BadRequestException(
|
|
795
|
-
'
|
|
781
|
+
'No MCP AI profile configured. Select one in Settings → MCP.',
|
|
796
782
|
);
|
|
797
783
|
}
|
|
798
|
-
|
|
784
|
+
|
|
785
|
+
const profile = await this.prisma.integration_profile.findUnique({
|
|
786
|
+
where: { id: profileId },
|
|
787
|
+
include: { integration_provider: { select: { slug: true } } },
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
if (!profile) {
|
|
791
|
+
throw new BadRequestException(`MCP AI profile ${profileId} not found.`);
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
const providerSlug = profile.integration_provider.slug;
|
|
795
|
+
const { apiKey } = buildAiConfigFromIntegration(providerSlug, profile.config);
|
|
796
|
+
|
|
797
|
+
if (!apiKey) {
|
|
798
|
+
throw new BadRequestException(`MCP AI profile ${profileId} has no API key configured.`);
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
return { provider: providerSlug === 'gemini' ? 'gemini' : 'openai', apiKey };
|
|
799
802
|
}
|
|
800
803
|
|
|
801
804
|
private async buildOpenAiTools(
|
|
@@ -87,6 +87,21 @@ export class OAuthController {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
|
|
90
|
+
@Public()
|
|
91
|
+
@Get(':provider/mobile/auth-url')
|
|
92
|
+
async mobileAuthUrl(
|
|
93
|
+
@Param('provider') provider: string,
|
|
94
|
+
@Query('redirectUri') redirectUri: string,
|
|
95
|
+
) {
|
|
96
|
+
const authUrl = await this.service.getMobileAuthUrl(
|
|
97
|
+
provider as user_account_provider_52222e2ecb_enum,
|
|
98
|
+
redirectUri,
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
return { authUrl };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
|
|
90
105
|
@Public()
|
|
91
106
|
@Get(':provider/register')
|
|
92
107
|
async register(@Param('provider') provider: string, @Res() res) {
|
|
@@ -101,7 +116,7 @@ export class OAuthController {
|
|
|
101
116
|
@Public()
|
|
102
117
|
@Get(':provider/connect')
|
|
103
118
|
async connect(@Param('provider') provider: string, @Res() res) {
|
|
104
|
-
const url = this.service.getAuthUrl(
|
|
119
|
+
const url = await this.service.getAuthUrl(
|
|
105
120
|
provider as user_account_provider_52222e2ecb_enum,
|
|
106
121
|
`/callback/${provider}/connect`,
|
|
107
122
|
);
|
|
@@ -121,6 +136,8 @@ export class OAuthController {
|
|
|
121
136
|
@Headers('x-forwarded-host') forwardedHost: string,
|
|
122
137
|
@Param('provider') provider: string,
|
|
123
138
|
@Query('code') code: string,
|
|
139
|
+
@Query('state') state: string,
|
|
140
|
+
@Query('redirectUri') redirectUri: string,
|
|
124
141
|
@Res({ passthrough: true }) res,
|
|
125
142
|
) {
|
|
126
143
|
this.logOAuthRequest('callback-login', provider, {
|
|
@@ -133,7 +150,18 @@ export class OAuthController {
|
|
|
133
150
|
code,
|
|
134
151
|
});
|
|
135
152
|
|
|
136
|
-
return this.service.handleCallback({
|
|
153
|
+
return this.service.handleCallback({
|
|
154
|
+
res,
|
|
155
|
+
locale,
|
|
156
|
+
ipAddress,
|
|
157
|
+
userAgent,
|
|
158
|
+
provider: provider as user_account_provider_52222e2ecb_enum,
|
|
159
|
+
code,
|
|
160
|
+
state,
|
|
161
|
+
type: 'login',
|
|
162
|
+
redirectUri,
|
|
163
|
+
includeRefreshTokenInBody: Boolean(redirectUri),
|
|
164
|
+
});
|
|
137
165
|
}
|
|
138
166
|
|
|
139
167
|
|