Skip to content

Commit 58b7520

Browse files
authored
Merge pull request #3327 from Dokploy/refactor/separate-settings-from-users-table
refactor(settings): migrate user settings to webServerSettings schema…
2 parents 260efdc + 9e03625 commit 58b7520

File tree

29 files changed

+7505
-316
lines changed

29 files changed

+7505
-316
lines changed

apps/dokploy/__test__/traefik/server/update-server-config.test.ts

Lines changed: 22 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,27 @@ vi.mock("node:fs", () => ({
55
default: fs,
66
}));
77

8-
import type { FileConfig, User } from "@dokploy/server";
8+
import type { FileConfig } from "@dokploy/server";
99
import {
1010
createDefaultServerTraefikConfig,
1111
loadOrCreateConfig,
1212
updateServerTraefik,
1313
} from "@dokploy/server";
14+
import type { webServerSettings } from "@dokploy/server/db/schema";
1415
import { beforeEach, expect, test, vi } from "vitest";
1516

16-
const baseAdmin: User = {
17+
type WebServerSettings = typeof webServerSettings.$inferSelect;
18+
19+
const baseSettings: WebServerSettings = {
20+
id: "",
1721
https: false,
18-
enablePaidFeatures: false,
19-
allowImpersonation: false,
20-
role: "user",
21-
firstName: "",
22-
lastName: "",
22+
certificateType: "none",
23+
host: null,
24+
serverIp: null,
25+
letsEncryptEmail: null,
26+
sshPrivateKey: null,
27+
enableDockerCleanup: false,
28+
logCleanupCron: null,
2329
metricsConfig: {
2430
containers: {
2531
refreshRate: 20,
@@ -45,29 +51,8 @@ const baseAdmin: User = {
4551
cleanupCacheApplications: false,
4652
cleanupCacheOnCompose: false,
4753
cleanupCacheOnPreviews: false,
48-
createdAt: new Date(),
49-
serverIp: null,
50-
certificateType: "none",
51-
host: null,
52-
letsEncryptEmail: null,
53-
sshPrivateKey: null,
54-
enableDockerCleanup: false,
55-
logCleanupCron: null,
56-
serversQuantity: 0,
57-
stripeCustomerId: "",
58-
stripeSubscriptionId: "",
59-
banExpires: new Date(),
60-
banned: true,
61-
banReason: "",
62-
email: "",
63-
expirationDate: "",
64-
id: "",
65-
isRegistered: false,
66-
createdAt2: new Date().toISOString(),
67-
emailVerified: false,
68-
image: "",
54+
createdAt: null,
6955
updatedAt: new Date(),
70-
twoFactorEnabled: false,
7156
};
7257

7358
beforeEach(() => {
@@ -85,7 +70,7 @@ test("Should read the configuration file", () => {
8570
test("Should apply redirect-to-https", () => {
8671
updateServerTraefik(
8772
{
88-
...baseAdmin,
73+
...baseSettings,
8974
https: true,
9075
certificateType: "letsencrypt",
9176
},
@@ -100,7 +85,7 @@ test("Should apply redirect-to-https", () => {
10085
});
10186

10287
test("Should change only host when no certificate", () => {
103-
updateServerTraefik(baseAdmin, "example.com");
88+
updateServerTraefik(baseSettings, "example.com");
10489

10590
const config: FileConfig = loadOrCreateConfig("dokploy");
10691

@@ -110,7 +95,7 @@ test("Should change only host when no certificate", () => {
11095
test("Should not touch config without host", () => {
11196
const originalConfig: FileConfig = loadOrCreateConfig("dokploy");
11297

113-
updateServerTraefik(baseAdmin, null);
98+
updateServerTraefik(baseSettings, null);
11499

115100
const config: FileConfig = loadOrCreateConfig("dokploy");
116101

@@ -119,11 +104,14 @@ test("Should not touch config without host", () => {
119104

120105
test("Should remove websecure if https rollback to http", () => {
121106
updateServerTraefik(
122-
{ ...baseAdmin, certificateType: "letsencrypt" },
107+
{ ...baseSettings, certificateType: "letsencrypt" },
123108
"example.com",
124109
);
125110

126-
updateServerTraefik({ ...baseAdmin, certificateType: "none" }, "example.com");
111+
updateServerTraefik(
112+
{ ...baseSettings, certificateType: "none" },
113+
"example.com",
114+
);
127115

128116
const config: FileConfig = loadOrCreateConfig("dokploy");
129117

apps/dokploy/components/dashboard/settings/servers/actions/toggle-docker-cleanup.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ interface Props {
77
serverId?: string;
88
}
99
export const ToggleDockerCleanup = ({ serverId }: Props) => {
10-
const { data, refetch } = api.user.get.useQuery(undefined, {
11-
enabled: !serverId,
12-
});
10+
const { data, refetch } = api.settings.getWebServerSettings.useQuery(
11+
undefined,
12+
{
13+
enabled: !serverId,
14+
},
15+
);
1316

1417
const { data: server, refetch: refetchServer } = api.server.one.useQuery(
1518
{
@@ -22,15 +25,18 @@ export const ToggleDockerCleanup = ({ serverId }: Props) => {
2225

2326
const enabled = serverId
2427
? server?.enableDockerCleanup
25-
: data?.user.enableDockerCleanup;
28+
: data?.enableDockerCleanup;
2629

2730
const { mutateAsync } = api.settings.updateDockerCleanup.useMutation();
2831

2932
const handleToggle = async (checked: boolean) => {
3033
try {
3134
await mutateAsync({
3235
enableDockerCleanup: checked,
33-
serverId: serverId,
36+
...(serverId && { serverId }),
37+
} as {
38+
enableDockerCleanup: boolean;
39+
serverId?: string;
3440
});
3541
if (serverId) {
3642
await refetchServer();

apps/dokploy/components/dashboard/settings/servers/setup-monitoring.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ const Schema = z.object({
8080
type Schema = z.infer<typeof Schema>;
8181

8282
export const SetupMonitoring = ({ serverId }: Props) => {
83-
const { data } = serverId
83+
const { data: serverData } = serverId
8484
? api.server.one.useQuery(
8585
{
8686
serverId: serverId || "",
@@ -89,7 +89,14 @@ export const SetupMonitoring = ({ serverId }: Props) => {
8989
enabled: !!serverId,
9090
},
9191
)
92-
: api.user.getServerMetrics.useQuery();
92+
: { data: null };
93+
94+
const { data: webServerSettings } =
95+
api.settings.getWebServerSettings.useQuery(undefined, {
96+
enabled: !serverId,
97+
});
98+
99+
const data = serverId ? serverData : webServerSettings;
93100

94101
const url = useUrl();
95102

apps/dokploy/components/dashboard/settings/web-domain.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ type AddServerDomain = z.infer<typeof addServerDomain>;
6767

6868
export const WebDomain = () => {
6969
const { t } = useTranslation("settings");
70-
const { data, refetch } = api.user.get.useQuery();
70+
const { data, refetch } = api.settings.getWebServerSettings.useQuery();
7171
const { mutateAsync, isLoading } =
7272
api.settings.assignDomainServer.useMutation();
7373

@@ -82,15 +82,15 @@ export const WebDomain = () => {
8282
});
8383
const https = form.watch("https");
8484
const domain = form.watch("domain") || "";
85-
const host = data?.user?.host || "";
85+
const host = data?.host || "";
8686
const hasChanged = domain !== host;
8787
useEffect(() => {
8888
if (data) {
8989
form.reset({
90-
domain: data?.user?.host || "",
91-
certificateType: data?.user?.certificateType,
92-
letsEncryptEmail: data?.user?.letsEncryptEmail || "",
93-
https: data?.user?.https || false,
90+
domain: data?.host || "",
91+
certificateType: data?.certificateType || "none",
92+
letsEncryptEmail: data?.letsEncryptEmail || "",
93+
https: data?.https || false,
9494
});
9595
}
9696
}, [form, form.reset, data]);

apps/dokploy/components/dashboard/settings/web-server.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ import { UpdateServer } from "./web-server/update-server";
1616

1717
export const WebServer = () => {
1818
const { t } = useTranslation("settings");
19-
const { data } = api.user.get.useQuery();
19+
const { data: webServerSettings } =
20+
api.settings.getWebServerSettings.useQuery();
2021

2122
const { data: dokployVersion } = api.settings.getDokployVersion.useQuery();
2223

@@ -53,7 +54,7 @@ export const WebServer = () => {
5354

5455
<div className="flex items-center flex-wrap justify-between gap-4">
5556
<span className="text-sm text-muted-foreground">
56-
Server IP: {data?.user.serverIp}
57+
Server IP: {webServerSettings?.serverIp}
5758
</span>
5859
<span className="text-sm text-muted-foreground">
5960
Version: {dokployVersion}

apps/dokploy/components/dashboard/settings/web-server/update-server-ip.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,29 +46,27 @@ interface Props {
4646
export const UpdateServerIp = ({ children }: Props) => {
4747
const [isOpen, setIsOpen] = useState(false);
4848

49-
const { data } = api.user.get.useQuery();
49+
const { data, refetch } = api.settings.getWebServerSettings.useQuery();
5050
const { data: ip } = api.server.publicIp.useQuery();
5151

5252
const { mutateAsync, isLoading, error, isError } =
53-
api.user.update.useMutation();
53+
api.settings.updateServerIp.useMutation();
5454

5555
const form = useForm<Schema>({
5656
defaultValues: {
57-
serverIp: data?.user.serverIp || "",
57+
serverIp: data?.serverIp || "",
5858
},
5959
resolver: zodResolver(schema),
6060
});
6161

6262
useEffect(() => {
6363
if (data) {
6464
form.reset({
65-
serverIp: data.user.serverIp || "",
65+
serverIp: data.serverIp || "",
6666
});
6767
}
6868
}, [form, form.reset, data]);
6969

70-
const utils = api.useUtils();
71-
7270
const setCurrentIp = () => {
7371
if (!ip) return;
7472
form.setValue("serverIp", ip);
@@ -80,7 +78,7 @@ export const UpdateServerIp = ({ children }: Props) => {
8078
})
8179
.then(async () => {
8280
toast.success("Server IP Updated");
83-
await utils.user.get.invalidate();
81+
await refetch();
8482
setIsOpen(false);
8583
})
8684
.catch(() => {
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
CREATE TABLE "webServerSettings" (
2+
"id" text PRIMARY KEY NOT NULL,
3+
"serverIp" text,
4+
"certificateType" "certificateType" DEFAULT 'none' NOT NULL,
5+
"https" boolean DEFAULT false NOT NULL,
6+
"host" text,
7+
"letsEncryptEmail" text,
8+
"sshPrivateKey" text,
9+
"enableDockerCleanup" boolean DEFAULT true NOT NULL,
10+
"logCleanupCron" text DEFAULT '0 0 * * *',
11+
"metricsConfig" jsonb DEFAULT '{"server":{"type":"Dokploy","refreshRate":60,"port":4500,"token":"","retentionDays":2,"cronJob":"","urlCallback":"","thresholds":{"cpu":0,"memory":0}},"containers":{"refreshRate":60,"services":{"include":[],"exclude":[]}}}'::jsonb NOT NULL,
12+
"cleanupCacheApplications" boolean DEFAULT false NOT NULL,
13+
"cleanupCacheOnPreviews" boolean DEFAULT false NOT NULL,
14+
"cleanupCacheOnCompose" boolean DEFAULT false NOT NULL,
15+
"created_at" timestamp DEFAULT now(),
16+
"updated_at" timestamp DEFAULT now() NOT NULL
17+
);
18+
19+
-- Migrate data from user table to webServerSettings
20+
-- Get the owner user's data and insert into webServerSettings
21+
INSERT INTO "webServerSettings" (
22+
"id",
23+
"serverIp",
24+
"certificateType",
25+
"https",
26+
"host",
27+
"letsEncryptEmail",
28+
"sshPrivateKey",
29+
"enableDockerCleanup",
30+
"logCleanupCron",
31+
"metricsConfig",
32+
"cleanupCacheApplications",
33+
"cleanupCacheOnPreviews",
34+
"cleanupCacheOnCompose",
35+
"created_at",
36+
"updated_at"
37+
)
38+
SELECT
39+
gen_random_uuid()::text as "id",
40+
u."serverIp",
41+
COALESCE(u."certificateType", 'none') as "certificateType",
42+
COALESCE(u."https", false) as "https",
43+
u."host",
44+
u."letsEncryptEmail",
45+
u."sshPrivateKey",
46+
COALESCE(u."enableDockerCleanup", true) as "enableDockerCleanup",
47+
COALESCE(u."logCleanupCron", '0 0 * * *') as "logCleanupCron",
48+
COALESCE(
49+
u."metricsConfig",
50+
'{"server":{"type":"Dokploy","refreshRate":60,"port":4500,"token":"","retentionDays":2,"cronJob":"","urlCallback":"","thresholds":{"cpu":0,"memory":0}},"containers":{"refreshRate":60,"services":{"include":[],"exclude":[]}}}'::jsonb
51+
) as "metricsConfig",
52+
COALESCE(u."cleanupCacheApplications", false) as "cleanupCacheApplications",
53+
COALESCE(u."cleanupCacheOnPreviews", false) as "cleanupCacheOnPreviews",
54+
COALESCE(u."cleanupCacheOnCompose", false) as "cleanupCacheOnCompose",
55+
NOW() as "created_at",
56+
NOW() as "updated_at"
57+
FROM "user" u
58+
INNER JOIN "member" m ON u."id" = m."user_id"
59+
WHERE m."role" = 'owner'
60+
ORDER BY m."created_at" ASC
61+
LIMIT 1;
62+
63+
-- If no owner found, create a default entry
64+
INSERT INTO "webServerSettings" (
65+
"id",
66+
"serverIp",
67+
"certificateType",
68+
"https",
69+
"host",
70+
"letsEncryptEmail",
71+
"sshPrivateKey",
72+
"enableDockerCleanup",
73+
"logCleanupCron",
74+
"metricsConfig",
75+
"cleanupCacheApplications",
76+
"cleanupCacheOnPreviews",
77+
"cleanupCacheOnCompose",
78+
"created_at",
79+
"updated_at"
80+
)
81+
SELECT
82+
gen_random_uuid()::text as "id",
83+
NULL as "serverIp",
84+
'none' as "certificateType",
85+
false as "https",
86+
NULL as "host",
87+
NULL as "letsEncryptEmail",
88+
NULL as "sshPrivateKey",
89+
true as "enableDockerCleanup",
90+
'0 0 * * *' as "logCleanupCron",
91+
'{"server":{"type":"Dokploy","refreshRate":60,"port":4500,"token":"","retentionDays":2,"cronJob":"","urlCallback":"","thresholds":{"cpu":0,"memory":0}},"containers":{"refreshRate":60,"services":{"include":[],"exclude":[]}}}'::jsonb as "metricsConfig",
92+
false as "cleanupCacheApplications",
93+
false as "cleanupCacheOnPreviews",
94+
false as "cleanupCacheOnCompose",
95+
NOW() as "created_at",
96+
NOW() as "updated_at"
97+
WHERE NOT EXISTS (
98+
SELECT 1 FROM "webServerSettings"
99+
);
100+
101+
102+
--> statement-breakpoint
103+
ALTER TABLE "user" DROP COLUMN "serverIp";--> statement-breakpoint
104+
ALTER TABLE "user" DROP COLUMN "certificateType";--> statement-breakpoint
105+
ALTER TABLE "user" DROP COLUMN "https";--> statement-breakpoint
106+
ALTER TABLE "user" DROP COLUMN "host";--> statement-breakpoint
107+
ALTER TABLE "user" DROP COLUMN "letsEncryptEmail";--> statement-breakpoint
108+
ALTER TABLE "user" DROP COLUMN "sshPrivateKey";--> statement-breakpoint
109+
ALTER TABLE "user" DROP COLUMN "enableDockerCleanup";--> statement-breakpoint
110+
ALTER TABLE "user" DROP COLUMN "logCleanupCron";--> statement-breakpoint
111+
ALTER TABLE "user" DROP COLUMN "metricsConfig";--> statement-breakpoint
112+
ALTER TABLE "user" DROP COLUMN "cleanupCacheApplications";--> statement-breakpoint
113+
ALTER TABLE "user" DROP COLUMN "cleanupCacheOnPreviews";--> statement-breakpoint
114+
ALTER TABLE "user" DROP COLUMN "cleanupCacheOnCompose";

0 commit comments

Comments
 (0)