@hed-hog/core 0.0.291 → 0.0.293
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/auth/auth.controller.d.ts +5 -5
- package/dist/auth/auth.service.d.ts +5 -5
- package/dist/challenge/challenge.service.d.ts +2 -2
- package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +2 -2
- package/dist/install/dto/install.dto.d.ts +2 -0
- package/dist/install/dto/install.dto.d.ts.map +1 -1
- package/dist/install/dto/install.dto.js +12 -0
- package/dist/install/dto/install.dto.js.map +1 -1
- package/dist/install/install.controller.d.ts +1 -0
- package/dist/install/install.controller.d.ts.map +1 -1
- package/dist/install/install.service.d.ts +6 -2
- package/dist/install/install.service.d.ts.map +1 -1
- package/dist/install/install.service.js +52 -4
- package/dist/install/install.service.js.map +1 -1
- package/dist/profile/profile.controller.d.ts +6 -6
- package/dist/profile/profile.service.d.ts +6 -6
- package/dist/session/session.controller.d.ts +2 -2
- package/dist/session/session.service.d.ts +3 -3
- package/dist/setting/setting.controller.d.ts +9 -9
- package/dist/setting/setting.service.d.ts +10 -10
- package/dist/user/user.controller.d.ts +6 -6
- package/dist/user/user.service.d.ts +12 -12
- package/hedhog/data/dashboard_component_role.yaml +223 -223
- package/hedhog/data/dashboard_role.yaml +18 -18
- package/hedhog/data/setting_group.yaml +11 -0
- package/hedhog/frontend/app/dashboard/[slug]/dashboard-content.tsx.ejs +0 -2
- package/hedhog/frontend/app/dashboard/components/widgets/permissions-chart.tsx.ejs +62 -62
- package/hedhog/frontend/app/dashboard/page.tsx.ejs +29 -29
- package/hedhog/frontend/app/mail/template/page.tsx.ejs +17 -2
- package/package.json +7 -7
- package/src/ai/ai.service.ts +3 -3
- package/src/auth/auth.controller.ts +11 -11
- package/src/auth/auth.service.ts +8 -8
- package/src/install/dto/install.dto.ts +15 -1
- package/src/install/install.service.ts +67 -3
- package/src/task/task.service.ts +5 -5
|
@@ -4,21 +4,21 @@
|
|
|
4
4
|
role_id:
|
|
5
5
|
where:
|
|
6
6
|
slug: admin-access
|
|
7
|
-
- dashboard_id:
|
|
8
|
-
where:
|
|
9
|
-
slug: user
|
|
10
|
-
role_id:
|
|
11
|
-
where:
|
|
12
|
-
slug: user
|
|
13
|
-
- dashboard_id:
|
|
14
|
-
where:
|
|
15
|
-
slug: user
|
|
16
|
-
role_id:
|
|
17
|
-
where:
|
|
18
|
-
slug: admin-access
|
|
19
|
-
- dashboard_id:
|
|
20
|
-
where:
|
|
21
|
-
slug: config
|
|
22
|
-
role_id:
|
|
23
|
-
where:
|
|
24
|
-
slug: admin
|
|
7
|
+
- dashboard_id:
|
|
8
|
+
where:
|
|
9
|
+
slug: user
|
|
10
|
+
role_id:
|
|
11
|
+
where:
|
|
12
|
+
slug: user
|
|
13
|
+
- dashboard_id:
|
|
14
|
+
where:
|
|
15
|
+
slug: user
|
|
16
|
+
role_id:
|
|
17
|
+
where:
|
|
18
|
+
slug: admin-access
|
|
19
|
+
- dashboard_id:
|
|
20
|
+
where:
|
|
21
|
+
slug: config
|
|
22
|
+
role_id:
|
|
23
|
+
where:
|
|
24
|
+
slug: admin
|
|
@@ -28,6 +28,17 @@
|
|
|
28
28
|
pt: A URL da API do sistema
|
|
29
29
|
value: http://localhost:3100
|
|
30
30
|
user_override: false
|
|
31
|
+
- slug: installed
|
|
32
|
+
type: boolean
|
|
33
|
+
component: switch
|
|
34
|
+
name:
|
|
35
|
+
en: Installed
|
|
36
|
+
pt: Instalado
|
|
37
|
+
description:
|
|
38
|
+
en: Whether the system has already been installed
|
|
39
|
+
pt: Se o sistema ja foi instalado
|
|
40
|
+
value: false
|
|
41
|
+
user_override: false
|
|
31
42
|
- slug: maintenance
|
|
32
43
|
icon: database-cog
|
|
33
44
|
name:
|
|
@@ -37,24 +37,24 @@ function CustomTooltip({
|
|
|
37
37
|
);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
interface PermissionsChartProps {
|
|
41
|
-
widget?: {
|
|
42
|
-
name?: string;
|
|
43
|
-
} | null;
|
|
44
|
-
onRemove?: () => void;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
interface PermissionDistributionItem {
|
|
48
|
-
name: string;
|
|
49
|
-
value: number;
|
|
50
|
-
color: string;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
interface UserStatsData {
|
|
54
|
-
charts?: {
|
|
55
|
-
permissionDistribution?: PermissionDistributionItem[];
|
|
56
|
-
};
|
|
57
|
-
}
|
|
40
|
+
interface PermissionsChartProps {
|
|
41
|
+
widget?: {
|
|
42
|
+
name?: string;
|
|
43
|
+
} | null;
|
|
44
|
+
onRemove?: () => void;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface PermissionDistributionItem {
|
|
48
|
+
name: string;
|
|
49
|
+
value: number;
|
|
50
|
+
color: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
interface UserStatsData {
|
|
54
|
+
charts?: {
|
|
55
|
+
permissionDistribution?: PermissionDistributionItem[];
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
58
|
|
|
59
59
|
export default function PermissionsChart({
|
|
60
60
|
widget,
|
|
@@ -70,10 +70,10 @@ export default function PermissionsChart({
|
|
|
70
70
|
} = useWidgetData<UserStatsData>({
|
|
71
71
|
endpoint: '/dashboard-core/stats/overview/users',
|
|
72
72
|
queryKey: 'dashboard-stats-users',
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
const data = statsData?.charts?.permissionDistribution || [];
|
|
76
|
-
const total = data.reduce((sum, item) => sum + item.value, 0);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const data = statsData?.charts?.permissionDistribution || [];
|
|
76
|
+
const total = data.reduce((sum, item) => sum + item.value, 0);
|
|
77
77
|
|
|
78
78
|
return (
|
|
79
79
|
<WidgetWrapper
|
|
@@ -90,19 +90,19 @@ export default function PermissionsChart({
|
|
|
90
90
|
>
|
|
91
91
|
<IconGripVertical className="text-muted-foreground/50 size-4 shrink-0" />
|
|
92
92
|
</div>
|
|
93
|
-
<CardHeader className="pb-2 pt-4 pl-10">
|
|
94
|
-
<CardTitle className="text-base font-semibold">
|
|
95
|
-
{t('permissionsDistributionTitle')}
|
|
96
|
-
</CardTitle>
|
|
93
|
+
<CardHeader className="pb-2 pt-4 pl-10">
|
|
94
|
+
<CardTitle className="text-base font-semibold">
|
|
95
|
+
{t('permissionsDistributionTitle')}
|
|
96
|
+
</CardTitle>
|
|
97
97
|
<CardDescription>
|
|
98
98
|
{t('permissionsDistributionDescription')}
|
|
99
99
|
</CardDescription>
|
|
100
|
-
</CardHeader>
|
|
101
|
-
<CardContent className="flex-1 pt-0">
|
|
102
|
-
<div className="flex h-full items-center justify-between gap-4 overflow-hidden">
|
|
103
|
-
<div className="relative h-[280px] w-[280px] shrink-0">
|
|
104
|
-
<ResponsiveContainer width="100%" height="100%">
|
|
105
|
-
<PieChart>
|
|
100
|
+
</CardHeader>
|
|
101
|
+
<CardContent className="flex-1 pt-0">
|
|
102
|
+
<div className="flex h-full items-center justify-between gap-4 overflow-hidden">
|
|
103
|
+
<div className="relative h-[280px] w-[280px] shrink-0">
|
|
104
|
+
<ResponsiveContainer width="100%" height="100%">
|
|
105
|
+
<PieChart>
|
|
106
106
|
<Pie
|
|
107
107
|
data={data}
|
|
108
108
|
cx="50%"
|
|
@@ -110,14 +110,14 @@ export default function PermissionsChart({
|
|
|
110
110
|
innerRadius={70}
|
|
111
111
|
outerRadius={110}
|
|
112
112
|
paddingAngle={4}
|
|
113
|
-
dataKey="value"
|
|
114
|
-
animationDuration={1200}
|
|
115
|
-
strokeWidth={0}
|
|
116
|
-
>
|
|
117
|
-
{data.map((entry, index: number) => (
|
|
118
|
-
<Cell key={`cell-${index}`} fill={entry.color} />
|
|
119
|
-
))}
|
|
120
|
-
</Pie>
|
|
113
|
+
dataKey="value"
|
|
114
|
+
animationDuration={1200}
|
|
115
|
+
strokeWidth={0}
|
|
116
|
+
>
|
|
117
|
+
{data.map((entry, index: number) => (
|
|
118
|
+
<Cell key={`cell-${index}`} fill={entry.color} />
|
|
119
|
+
))}
|
|
120
|
+
</Pie>
|
|
121
121
|
<Tooltip content={<CustomTooltip />} />
|
|
122
122
|
</PieChart>
|
|
123
123
|
</ResponsiveContainer>
|
|
@@ -125,28 +125,28 @@ export default function PermissionsChart({
|
|
|
125
125
|
<span className="text-2xl font-bold text-foreground">
|
|
126
126
|
{total}
|
|
127
127
|
</span>
|
|
128
|
-
<span className="text-[10px] text-muted-foreground">
|
|
129
|
-
{t('total')}
|
|
130
|
-
</span>
|
|
131
|
-
</div>
|
|
132
|
-
</div>
|
|
133
|
-
<div className="grid max-h-[280px] min-w-0 flex-1 grid-cols-2 content-start gap-x-4 gap-y-2 overflow-y-auto pr-2">
|
|
134
|
-
{data.map((item) => (
|
|
135
|
-
<div key={item.name} className="flex min-w-0 items-start gap-2.5">
|
|
136
|
-
<div
|
|
137
|
-
className="mt-1 h-2.5 w-2.5 shrink-0 rounded-sm"
|
|
138
|
-
style={{ backgroundColor: item.color }}
|
|
139
|
-
/>
|
|
140
|
-
<div className="flex min-w-0 flex-col">
|
|
141
|
-
<span className="break-words text-xs font-medium leading-tight text-foreground">
|
|
142
|
-
{item.name}
|
|
143
|
-
</span>
|
|
144
|
-
<span className="text-[11px] text-muted-foreground">
|
|
145
|
-
{item.value} ({total ? Math.round((item.value / total) * 100) : 0}%)
|
|
146
|
-
</span>
|
|
147
|
-
</div>
|
|
148
|
-
</div>
|
|
149
|
-
))}
|
|
128
|
+
<span className="text-[10px] text-muted-foreground">
|
|
129
|
+
{t('total')}
|
|
130
|
+
</span>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
<div className="grid max-h-[280px] min-w-0 flex-1 grid-cols-2 content-start gap-x-4 gap-y-2 overflow-y-auto pr-2">
|
|
134
|
+
{data.map((item) => (
|
|
135
|
+
<div key={item.name} className="flex min-w-0 items-start gap-2.5">
|
|
136
|
+
<div
|
|
137
|
+
className="mt-1 h-2.5 w-2.5 shrink-0 rounded-sm"
|
|
138
|
+
style={{ backgroundColor: item.color }}
|
|
139
|
+
/>
|
|
140
|
+
<div className="flex min-w-0 flex-col">
|
|
141
|
+
<span className="break-words text-xs font-medium leading-tight text-foreground">
|
|
142
|
+
{item.name}
|
|
143
|
+
</span>
|
|
144
|
+
<span className="text-[11px] text-muted-foreground">
|
|
145
|
+
{item.value} ({total ? Math.round((item.value / total) * 100) : 0}%)
|
|
146
|
+
</span>
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
))}
|
|
150
150
|
</div>
|
|
151
151
|
</div>
|
|
152
152
|
</CardContent>
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { Dashboard } from '@hed-hog/api-types';
|
|
4
|
-
import { useApp, useQuery } from '@hed-hog/next-app-provider';
|
|
5
|
-
import { useRouter } from 'next/navigation';
|
|
6
|
-
import { useEffect } from 'react';
|
|
7
|
-
|
|
8
|
-
export default function DashboardRedirectPage() {
|
|
9
|
-
const router = useRouter();
|
|
10
|
-
const { request, currentLocaleCode } = useApp();
|
|
11
|
-
|
|
12
|
-
const { data: dashboardData, isLoading } = useQuery<Dashboard | null>({
|
|
13
|
-
queryKey: ['dashboard-home-redirect', currentLocaleCode],
|
|
14
|
-
queryFn: async () => {
|
|
15
|
-
const response = await request<Dashboard>({
|
|
16
|
-
url: '/dashboard-core/home',
|
|
17
|
-
});
|
|
18
|
-
return response.data ?? null;
|
|
19
|
-
},
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
useEffect(() => {
|
|
23
|
-
if (isLoading) return;
|
|
24
|
-
|
|
25
|
-
router.replace(`/core/dashboard/${dashboardData?.slug ?? 'default'}`);
|
|
26
|
-
}, [dashboardData?.slug, isLoading, router]);
|
|
27
|
-
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Dashboard } from '@hed-hog/api-types';
|
|
4
|
+
import { useApp, useQuery } from '@hed-hog/next-app-provider';
|
|
5
|
+
import { useRouter } from 'next/navigation';
|
|
6
|
+
import { useEffect } from 'react';
|
|
7
|
+
|
|
8
|
+
export default function DashboardRedirectPage() {
|
|
9
|
+
const router = useRouter();
|
|
10
|
+
const { request, currentLocaleCode } = useApp();
|
|
11
|
+
|
|
12
|
+
const { data: dashboardData, isLoading } = useQuery<Dashboard | null>({
|
|
13
|
+
queryKey: ['dashboard-home-redirect', currentLocaleCode],
|
|
14
|
+
queryFn: async () => {
|
|
15
|
+
const response = await request<Dashboard>({
|
|
16
|
+
url: '/dashboard-core/home',
|
|
17
|
+
});
|
|
18
|
+
return response.data ?? null;
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (isLoading) return;
|
|
24
|
+
|
|
25
|
+
router.replace(`/core/dashboard/${dashboardData?.slug ?? 'default'}`);
|
|
26
|
+
}, [dashboardData?.slug, isLoading, router]);
|
|
27
|
+
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
+
import dynamic from 'next/dynamic';
|
|
3
4
|
import type React from 'react';
|
|
4
5
|
|
|
5
6
|
import {
|
|
@@ -9,7 +10,6 @@ import {
|
|
|
9
10
|
PaginationFooter,
|
|
10
11
|
SearchBar,
|
|
11
12
|
} from '@/components/entity-list';
|
|
12
|
-
import { RichTextEditor } from '@/components/rich-text-editor';
|
|
13
13
|
import {
|
|
14
14
|
AlertDialog,
|
|
15
15
|
AlertDialogAction,
|
|
@@ -70,6 +70,19 @@ import { useTranslations } from 'next-intl';
|
|
|
70
70
|
import { useEffect, useState } from 'react';
|
|
71
71
|
import { toast } from 'sonner';
|
|
72
72
|
|
|
73
|
+
const RichTextEditor = dynamic(
|
|
74
|
+
() =>
|
|
75
|
+
import('@/components/rich-text-editor').then((mod) => ({
|
|
76
|
+
default: mod.RichTextEditor,
|
|
77
|
+
})),
|
|
78
|
+
{
|
|
79
|
+
ssr: false,
|
|
80
|
+
loading: () => (
|
|
81
|
+
<div className="min-h-48 bg-muted rounded-md animate-pulse" />
|
|
82
|
+
),
|
|
83
|
+
}
|
|
84
|
+
);
|
|
85
|
+
|
|
73
86
|
interface Mail {
|
|
74
87
|
id: number;
|
|
75
88
|
slug: string;
|
|
@@ -779,7 +792,9 @@ export default function EmailTemplatesPage() {
|
|
|
779
792
|
<TableHead>{t('tableSubject')}</TableHead>
|
|
780
793
|
<TableHead>{t('tableVariables')}</TableHead>
|
|
781
794
|
<TableHead>{t('tableUpdated')}</TableHead>
|
|
782
|
-
<TableHead className="text-right">
|
|
795
|
+
<TableHead className="text-right">
|
|
796
|
+
{t('tableActions')}
|
|
797
|
+
</TableHead>
|
|
783
798
|
</TableRow>
|
|
784
799
|
</TableHeader>
|
|
785
800
|
<TableBody>
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hed-hog/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.293",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@aws-sdk/client-s3": "^3.
|
|
8
|
-
"@aws-sdk/s3-request-presigner": "^3.
|
|
7
|
+
"@aws-sdk/client-s3": "^3.1014.0",
|
|
8
|
+
"@aws-sdk/s3-request-presigner": "^3.1014.0",
|
|
9
9
|
"@azure/storage-blob": "^12.27.0",
|
|
10
10
|
"@google-cloud/storage": "^7.16.0",
|
|
11
11
|
"@nestjs/axios": "*",
|
|
@@ -30,12 +30,12 @@
|
|
|
30
30
|
"sharp": "^0.34.2",
|
|
31
31
|
"speakeasy": "^2.0.0",
|
|
32
32
|
"uuid": "^11.1.0",
|
|
33
|
-
"@hed-hog/api-types": "0.0.1",
|
|
34
|
-
"@hed-hog/api-pagination": "0.0.6",
|
|
35
33
|
"@hed-hog/api": "0.0.4",
|
|
34
|
+
"@hed-hog/api-pagination": "0.0.6",
|
|
35
|
+
"@hed-hog/api-locale": "0.0.13",
|
|
36
|
+
"@hed-hog/api-types": "0.0.1",
|
|
36
37
|
"@hed-hog/api-mail": "0.0.8",
|
|
37
|
-
"@hed-hog/api-prisma": "0.0.5"
|
|
38
|
-
"@hed-hog/api-locale": "0.0.13"
|
|
38
|
+
"@hed-hog/api-prisma": "0.0.5"
|
|
39
39
|
},
|
|
40
40
|
"exports": {
|
|
41
41
|
".": {
|
package/src/ai/ai.service.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { PaginationDTO } from '@hed-hog/api-pagination';
|
|
2
|
-
import { Prisma, PrismaService } from '@hed-hog/api-prisma';
|
|
1
|
+
import { PaginationDTO } from '@hed-hog/api-pagination';
|
|
2
|
+
import { Prisma, PrismaService } from '@hed-hog/api-prisma';
|
|
3
3
|
import {
|
|
4
4
|
BadRequestException,
|
|
5
5
|
forwardRef,
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
Logger,
|
|
9
9
|
NotFoundException,
|
|
10
10
|
} from '@nestjs/common';
|
|
11
|
-
import axios from 'axios';
|
|
11
|
+
import axios from 'axios';
|
|
12
12
|
import { createHash } from 'crypto';
|
|
13
13
|
import pdfParse from 'pdf-parse';
|
|
14
14
|
import { DeleteDTO } from '../dto/delete.dto';
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { Public, Role, User, UserOptional } from '@hed-hog/api';
|
|
2
2
|
import { Locale } from '@hed-hog/api-locale';
|
|
3
|
-
import {
|
|
4
|
-
BadRequestException,
|
|
5
|
-
Body,
|
|
6
|
-
Controller,
|
|
7
|
-
forwardRef,
|
|
3
|
+
import {
|
|
4
|
+
BadRequestException,
|
|
5
|
+
Body,
|
|
6
|
+
Controller,
|
|
7
|
+
forwardRef,
|
|
8
8
|
Get,
|
|
9
9
|
Headers,
|
|
10
10
|
Inject,
|
|
11
|
-
Ip,
|
|
12
|
-
Post,
|
|
13
|
-
Req,
|
|
14
|
-
Res,
|
|
15
|
-
UnauthorizedException,
|
|
16
|
-
} from '@nestjs/common';
|
|
11
|
+
Ip,
|
|
12
|
+
Post,
|
|
13
|
+
Req,
|
|
14
|
+
Res,
|
|
15
|
+
UnauthorizedException,
|
|
16
|
+
} from '@nestjs/common';
|
|
17
17
|
import { TokenService } from '../token/token.service';
|
|
18
18
|
import { CreateWithEmailAndPasswordDTO } from '../user/dto/create-with-email-and-password.dto';
|
|
19
19
|
import { UserService } from '../user/user.service';
|
package/src/auth/auth.service.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { getLocaleText } from '@hed-hog/api-locale';
|
|
2
2
|
import { PrismaService } from '@hed-hog/api-prisma';
|
|
3
3
|
import { User } from '@hed-hog/api-types';
|
|
4
|
-
import {
|
|
5
|
-
BadRequestException,
|
|
6
|
-
forwardRef,
|
|
7
|
-
Inject,
|
|
8
|
-
Injectable,
|
|
9
|
-
NotFoundException,
|
|
10
|
-
UnauthorizedException,
|
|
11
|
-
} from '@nestjs/common';
|
|
4
|
+
import {
|
|
5
|
+
BadRequestException,
|
|
6
|
+
forwardRef,
|
|
7
|
+
Inject,
|
|
8
|
+
Injectable,
|
|
9
|
+
NotFoundException,
|
|
10
|
+
UnauthorizedException,
|
|
11
|
+
} from '@nestjs/common';
|
|
12
12
|
import { ChallengeService } from '../challenge/challenge.service';
|
|
13
13
|
import { MailService as MailManagerService } from '../mail/mail.service';
|
|
14
14
|
import { SecurityService } from '../security/security.service';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getLocaleText } from '@hed-hog/api-locale';
|
|
2
|
-
import { IsOptional, IsString, MinLength } from 'class-validator';
|
|
2
|
+
import { IsOptional, IsString, IsUrl, MinLength } from 'class-validator';
|
|
3
3
|
import { IsEmailWithSettings } from '../../validators/is-email-with-settings.validator';
|
|
4
4
|
|
|
5
5
|
export class InstallDTO {
|
|
@@ -26,4 +26,18 @@ export class InstallDTO {
|
|
|
26
26
|
@IsString({ message: 'Senha deve ter pelo menos 6 caracteres' })
|
|
27
27
|
@MinLength(6, { message: 'Senha deve ter pelo menos 6 caracteres' })
|
|
28
28
|
password?: string = 'changeme';
|
|
29
|
+
|
|
30
|
+
@IsOptional()
|
|
31
|
+
@IsUrl(
|
|
32
|
+
{ require_protocol: true, require_tld: false },
|
|
33
|
+
{ message: 'URL da admin invalida' },
|
|
34
|
+
)
|
|
35
|
+
adminUrl?: string = 'http://localhost:3200';
|
|
36
|
+
|
|
37
|
+
@IsOptional()
|
|
38
|
+
@IsUrl(
|
|
39
|
+
{ require_protocol: true, require_tld: false },
|
|
40
|
+
{ message: 'URL da API invalida' },
|
|
41
|
+
)
|
|
42
|
+
apiUrl?: string = 'http://localhost:3100';
|
|
29
43
|
}
|
|
@@ -5,6 +5,7 @@ import { existsSync, readFileSync } from 'fs';
|
|
|
5
5
|
import { writeFile } from 'fs/promises';
|
|
6
6
|
import { resolve } from 'path';
|
|
7
7
|
import { SecurityService } from '../security/security.service';
|
|
8
|
+
import { SettingService } from '../setting/setting.service';
|
|
8
9
|
import { InstallDTO } from './dto/install.dto';
|
|
9
10
|
|
|
10
11
|
@Injectable()
|
|
@@ -15,9 +16,14 @@ export class InstallService {
|
|
|
15
16
|
constructor(
|
|
16
17
|
private readonly security: SecurityService,
|
|
17
18
|
private readonly prisma: PrismaService,
|
|
18
|
-
|
|
19
|
+
private readonly configService: ConfigService,
|
|
20
|
+
private readonly settingService: SettingService,
|
|
19
21
|
) { }
|
|
20
22
|
|
|
23
|
+
private normalizeUrl(value: string) {
|
|
24
|
+
return value.trim().replace(/\/$/, '');
|
|
25
|
+
}
|
|
26
|
+
|
|
21
27
|
private async forceReset() {
|
|
22
28
|
|
|
23
29
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
@@ -56,6 +62,19 @@ export class InstallService {
|
|
|
56
62
|
}
|
|
57
63
|
|
|
58
64
|
private async checkInstallation() {
|
|
65
|
+
const installedSetting = await this.prisma.setting.findFirst({
|
|
66
|
+
where: {
|
|
67
|
+
slug: 'installed',
|
|
68
|
+
},
|
|
69
|
+
select: {
|
|
70
|
+
value: true,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
if (installedSetting?.value === 'true') {
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
|
|
59
78
|
const usersCount = await this.prisma.user.count();
|
|
60
79
|
return usersCount > 0;
|
|
61
80
|
}
|
|
@@ -135,12 +154,23 @@ export class InstallService {
|
|
|
135
154
|
return Buffer.from(str).toString('base64');
|
|
136
155
|
}
|
|
137
156
|
|
|
138
|
-
async install({
|
|
157
|
+
async install({
|
|
158
|
+
adminUrl,
|
|
159
|
+
apiUrl,
|
|
160
|
+
appName,
|
|
161
|
+
email,
|
|
162
|
+
password,
|
|
163
|
+
slogan,
|
|
164
|
+
userName,
|
|
165
|
+
}: InstallDTO) {
|
|
139
166
|
|
|
140
167
|
if (await this.checkInstallation()) {
|
|
141
168
|
throw new BadRequestException('Application is already installed.');
|
|
142
169
|
}
|
|
143
170
|
|
|
171
|
+
const normalizedAdminUrl = this.normalizeUrl(adminUrl ?? 'http://localhost:3200');
|
|
172
|
+
const normalizedApiUrl = this.normalizeUrl(apiUrl ?? 'http://localhost:3100');
|
|
173
|
+
|
|
144
174
|
await this.prisma.$transaction(async (prisma) => {
|
|
145
175
|
|
|
146
176
|
this.logger.log('Starting installation process...');
|
|
@@ -167,6 +197,24 @@ export class InstallService {
|
|
|
167
197
|
}
|
|
168
198
|
});
|
|
169
199
|
|
|
200
|
+
await prisma.setting.update({
|
|
201
|
+
where: {
|
|
202
|
+
slug: 'url',
|
|
203
|
+
},
|
|
204
|
+
data: {
|
|
205
|
+
value: normalizedAdminUrl,
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
await prisma.setting.update({
|
|
210
|
+
where: {
|
|
211
|
+
slug: 'api-url',
|
|
212
|
+
},
|
|
213
|
+
data: {
|
|
214
|
+
value: normalizedApiUrl,
|
|
215
|
+
},
|
|
216
|
+
});
|
|
217
|
+
|
|
170
218
|
this.logger.log('System slogan set.');
|
|
171
219
|
|
|
172
220
|
this.logger.log(`Setting system email to: ${email}`);
|
|
@@ -236,6 +284,17 @@ export class InstallService {
|
|
|
236
284
|
|
|
237
285
|
this.logger.log(`Roles assigned to user ID: ${user.id}`);
|
|
238
286
|
|
|
287
|
+
await prisma.setting.update({
|
|
288
|
+
where: {
|
|
289
|
+
slug: 'installed',
|
|
290
|
+
},
|
|
291
|
+
data: {
|
|
292
|
+
value: 'true',
|
|
293
|
+
},
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
this.logger.log('Installation flag set to true.');
|
|
297
|
+
|
|
239
298
|
const isDevelopment = process.env.NODE_ENV !== 'production';
|
|
240
299
|
if (isDevelopment) {
|
|
241
300
|
await this.updateEnvSecrets(pepper);
|
|
@@ -250,12 +309,17 @@ export class InstallService {
|
|
|
250
309
|
|
|
251
310
|
});
|
|
252
311
|
|
|
312
|
+
this.settingService.clearCache();
|
|
313
|
+
|
|
253
314
|
return { success: true };
|
|
254
315
|
|
|
255
316
|
}
|
|
256
317
|
|
|
257
318
|
async check() {
|
|
258
|
-
return {
|
|
319
|
+
return {
|
|
320
|
+
success: true,
|
|
321
|
+
installed: await this.checkInstallation(),
|
|
322
|
+
};
|
|
259
323
|
}
|
|
260
324
|
|
|
261
325
|
async generateMailMigration({
|
package/src/task/task.service.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Prisma, PrismaService } from '@hed-hog/api-prisma';
|
|
2
|
-
import { Injectable, Logger } from '@nestjs/common';
|
|
3
|
-
import { Cron, CronExpression } from '@nestjs/schedule';
|
|
4
|
-
import { SettingService } from '../setting/setting.service';
|
|
1
|
+
import { Prisma, PrismaService } from '@hed-hog/api-prisma';
|
|
2
|
+
import { Injectable, Logger } from '@nestjs/common';
|
|
3
|
+
import { Cron, CronExpression } from '@nestjs/schedule';
|
|
4
|
+
import { SettingService } from '../setting/setting.service';
|
|
5
5
|
|
|
6
6
|
@Injectable()
|
|
7
7
|
export class TasksService {
|
|
@@ -225,4 +225,4 @@ export class TasksService {
|
|
|
225
225
|
`Unverified MFA with expired challenges cleaned up in ${Date.now() - startAt}ms`,
|
|
226
226
|
);
|
|
227
227
|
}
|
|
228
|
-
}
|
|
228
|
+
}
|