From e645b31b32bcae0b9c52e6a78272155ea05477be Mon Sep 17 00:00:00 2001 From: Jonathan de Jong Date: Tue, 26 Aug 2025 07:53:20 +0200 Subject: [PATCH 001/257] change gitea permissions to new instances (#1832) --- apps/dokploy/utils/gitea-utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/dokploy/utils/gitea-utils.ts b/apps/dokploy/utils/gitea-utils.ts index ab7b82dcc..6099aaa45 100644 --- a/apps/dokploy/utils/gitea-utils.ts +++ b/apps/dokploy/utils/gitea-utils.ts @@ -22,7 +22,7 @@ export const getGiteaOAuthUrl = ( } const redirectUri = `${baseUrl}/api/providers/gitea/callback`; - const scopes = "repo repo:status read:user read:org"; + const scopes = "read:repository read:user read:organization"; return `${giteaUrl}/login/oauth/authorize?client_id=${clientId}&redirect_uri=${encodeURIComponent( redirectUri, From 6da122eab7d5f86fc6ef4c7b7cdcf970e811fc67 Mon Sep 17 00:00:00 2001 From: Vlad Vladov Date: Wed, 3 Sep 2025 17:57:44 +0300 Subject: [PATCH 002/257] feat(tags): Add support for tags from Github Packages --- .../pages/api/deploy/[refreshToken].ts | 46 +++++++++++++++---- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/apps/dokploy/pages/api/deploy/[refreshToken].ts b/apps/dokploy/pages/api/deploy/[refreshToken].ts index 3e515b182..22fabb39d 100644 --- a/apps/dokploy/pages/api/deploy/[refreshToken].ts +++ b/apps/dokploy/pages/api/deploy/[refreshToken].ts @@ -43,17 +43,19 @@ export default async function handler( if (sourceType === "docker") { const applicationDockerTag = extractImageTag(application.dockerImage); - const webhookDockerTag = extractImageTagFromRequest( + const webhookDockerTags = extractImageTagFromRequest( req.headers, req.body, ); - if ( + const isMismatch = applicationDockerTag && - webhookDockerTag && - webhookDockerTag !== applicationDockerTag - ) { + webhookDockerTags && + webhookDockerTags.length > 0 && + !webhookDockerTags.includes(applicationDockerTag); + + if (isMismatch) { res.status(301).json({ - message: `Application Image Tag (${applicationDockerTag}) doesn't match request event payload Image Tag (${webhookDockerTag}).`, + message: `Application Image Tag (${applicationDockerTag}) doesn't match request event payload Image Tag(s) (${webhookDockerTags.join(", ")}).`, }); return; } @@ -236,10 +238,38 @@ function extractImageTag(dockerImage: string | null) { export const extractImageTagFromRequest = ( headers: any, body: any, -): string | null => { +): string[] | null => { if (headers["user-agent"]?.includes("Go-http-client")) { if (body.push_data && body.repository) { - return body.push_data.tag; + return [body.push_data.tag] as string[]; + } + } + // GitHub Packages: package or registry_package events (container tags) + // See: https://docs.github.com/en/webhooks/webhook-events-and-payloads#package + const githubEvent = headers["x-github-event"]; + + if (githubEvent === "package" || githubEvent === "registry_package") { + const pkg = body?.package ?? body?.registry_package?.package ?? null; + const packageVersion = + body?.package_version ?? body?.registry_package?.package_version ?? null; + const packageType = pkg?.package_type; + + if (packageType === "container" && packageVersion) { + const tags = + packageVersion?.metadata?.container?.tags ?? + packageVersion?.container?.tags ?? + null; + if (Array.isArray(tags) && tags.length > 0) { + return tags as string[]; + } + const singleTag = + packageVersion?.metadata?.container?.tag ?? + packageVersion?.metadata?.tag ?? + packageVersion?.tag ?? + null; + if (typeof singleTag === "string") { + return [singleTag] as string[]; + } } } return null; From b4a3cbdff4ad37c4d75df0526a90ccab4ccba3f3 Mon Sep 17 00:00:00 2001 From: ischanx Date: Wed, 24 Sep 2025 00:14:06 +0800 Subject: [PATCH 003/257] feat(notifications): add lark webhook --- .../notifications/handle-notifications.tsx | 74 +- .../notifications/show-notifications.tsx | 8 +- .../components/icons/notification-icons.tsx | 27 + apps/dokploy/drizzle/0113_lark_webhook.sql | 13 + apps/dokploy/drizzle/meta/0113_snapshot.json | 6616 +++++++++++++++++ apps/dokploy/drizzle/meta/_journal.json | 7 + .../server/api/routers/notification.ts | 64 + packages/server/src/db/schema/notification.ts | 41 + packages/server/src/services/notification.ts | 92 + .../src/utils/notifications/build-error.ts | 134 +- .../src/utils/notifications/build-success.ts | 122 +- .../utils/notifications/database-backup.ts | 160 +- .../src/utils/notifications/docker-cleanup.ts | 84 +- .../utils/notifications/dokploy-restart.ts | 80 +- .../utils/notifications/server-threshold.ts | 100 +- .../server/src/utils/notifications/utils.ts | 16 + 16 files changed, 7591 insertions(+), 47 deletions(-) create mode 100644 apps/dokploy/drizzle/0113_lark_webhook.sql create mode 100644 apps/dokploy/drizzle/meta/0113_snapshot.json diff --git a/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx b/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx index 4e4171bee..c923419c7 100644 --- a/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx +++ b/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx @@ -12,6 +12,7 @@ import { toast } from "sonner"; import { z } from "zod"; import { DiscordIcon, + LarkIcon, SlackIcon, TelegramIcon, } from "@/components/icons/notification-icons"; @@ -110,6 +111,12 @@ export const notificationSchema = z.discriminatedUnion("type", [ priority: z.number().min(1).max(5).default(3), }) .merge(notificationBaseSchema), + z + .object({ + type: z.literal("lark"), + webhookUrl: z.string().min(1, { message: "Webhook URL is required" }), + }) + .merge(notificationBaseSchema), ]); export const notificationsMap = { @@ -125,6 +132,10 @@ export const notificationsMap = { icon: , label: "Discord", }, + lark: { + icon: , + label: "Lark", + }, email: { icon: , label: "Email", @@ -170,6 +181,8 @@ export const HandleNotifications = ({ notificationId }: Props) => { api.notification.testGotifyConnection.useMutation(); const { mutateAsync: testNtfyConnection, isLoading: isLoadingNtfy } = api.notification.testNtfyConnection.useMutation(); + const { mutateAsync: testLarkConnection, isLoading: isLoadingLark } = + api.notification.testLarkConnection.useMutation(); const slackMutation = notificationId ? api.notification.updateSlack.useMutation() : api.notification.createSlack.useMutation(); @@ -188,6 +201,9 @@ export const HandleNotifications = ({ notificationId }: Props) => { const ntfyMutation = notificationId ? api.notification.updateNtfy.useMutation() : api.notification.createNtfy.useMutation(); + const larkMutation = notificationId + ? api.notification.updateLark.useMutation() + : api.notification.createLark.useMutation(); const form = useForm({ defaultValues: { @@ -297,6 +313,19 @@ export const HandleNotifications = ({ notificationId }: Props) => { serverUrl: notification.ntfy?.serverUrl, name: notification.name, dockerCleanup: notification.dockerCleanup, + serverThreshold: notification.serverThreshold, + }); + } else if (notification.notificationType === "lark") { + form.reset({ + appBuildError: notification.appBuildError, + appDeploy: notification.appDeploy, + dokployRestart: notification.dokployRestart, + databaseBackup: notification.databaseBackup, + type: notification.notificationType, + webhookUrl: notification.lark?.webhookUrl, + name: notification.name, + dockerCleanup: notification.dockerCleanup, + serverThreshold: notification.serverThreshold, }); } } else { @@ -311,6 +340,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { email: emailMutation, gotify: gotifyMutation, ntfy: ntfyMutation, + lark: larkMutation, }; const onSubmit = async (data: NotificationSchema) => { @@ -413,6 +443,20 @@ export const HandleNotifications = ({ notificationId }: Props) => { dockerCleanup: dockerCleanup, notificationId: notificationId || "", ntfyId: notification?.ntfyId || "", + serverThreshold: serverThreshold, + }); + } else if (data.type === "lark") { + promise = larkMutation.mutateAsync({ + appBuildError: appBuildError, + appDeploy: appDeploy, + dokployRestart: dokployRestart, + databaseBackup: databaseBackup, + webhookUrl: data.webhookUrl, + name: data.name, + dockerCleanup: dockerCleanup, + notificationId: notificationId || "", + larkId: notification?.larkId || "", + serverThreshold: serverThreshold, }); } @@ -502,7 +546,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { />