mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
refactor: update webhooks and added validation to prevent deploy when the server is inactive
This commit is contained in:
parent
1907e7e59c
commit
fbda00f059
@ -8,7 +8,7 @@ export const deployJobSchema = z.discriminatedUnion("applicationType", [
|
|||||||
server: z.boolean().optional(),
|
server: z.boolean().optional(),
|
||||||
type: z.enum(["deploy", "redeploy"]),
|
type: z.enum(["deploy", "redeploy"]),
|
||||||
applicationType: z.literal("application"),
|
applicationType: z.literal("application"),
|
||||||
serverId: z.string(),
|
serverId: z.string().min(1),
|
||||||
}),
|
}),
|
||||||
z.object({
|
z.object({
|
||||||
composeId: z.string(),
|
composeId: z.string(),
|
||||||
@ -17,7 +17,7 @@ export const deployJobSchema = z.discriminatedUnion("applicationType", [
|
|||||||
server: z.boolean().optional(),
|
server: z.boolean().optional(),
|
||||||
type: z.enum(["deploy", "redeploy"]),
|
type: z.enum(["deploy", "redeploy"]),
|
||||||
applicationType: z.literal("compose"),
|
applicationType: z.literal("compose"),
|
||||||
serverId: z.string(),
|
serverId: z.string().min(1),
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -96,7 +96,6 @@ export const ShowBilling = () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{products?.map((product) => {
|
{products?.map((product) => {
|
||||||
const featured = true;
|
const featured = true;
|
||||||
return (
|
return (
|
||||||
|
@ -118,6 +118,7 @@ export const ShowServers = () => {
|
|||||||
<TableBody>
|
<TableBody>
|
||||||
{data?.map((server) => {
|
{data?.map((server) => {
|
||||||
const canDelete = server.totalSum === 0;
|
const canDelete = server.totalSum === 0;
|
||||||
|
const isActive = server.serverStatus === "active";
|
||||||
return (
|
return (
|
||||||
<TableRow key={server.serverId}>
|
<TableRow key={server.serverId}>
|
||||||
<TableCell className="w-[100px]">{server.name}</TableCell>
|
<TableCell className="w-[100px]">{server.name}</TableCell>
|
||||||
@ -164,18 +165,25 @@ export const ShowServers = () => {
|
|||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent align="end">
|
<DropdownMenuContent align="end">
|
||||||
<DropdownMenuLabel>Actions</DropdownMenuLabel>
|
<DropdownMenuLabel>Actions</DropdownMenuLabel>
|
||||||
{server.sshKeyId && (
|
|
||||||
<TerminalModal serverId={server.serverId}>
|
{isActive && (
|
||||||
<span>Enter the terminal</span>
|
<>
|
||||||
</TerminalModal>
|
{server.sshKeyId && (
|
||||||
|
<TerminalModal serverId={server.serverId}>
|
||||||
|
<span>Enter the terminal</span>
|
||||||
|
</TerminalModal>
|
||||||
|
)}
|
||||||
|
<SetupServer serverId={server.serverId} />
|
||||||
|
|
||||||
|
<UpdateServer serverId={server.serverId} />
|
||||||
|
{server.sshKeyId && (
|
||||||
|
<ShowServerActions
|
||||||
|
serverId={server.serverId}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<SetupServer serverId={server.serverId} />
|
|
||||||
|
|
||||||
<UpdateServer serverId={server.serverId} />
|
|
||||||
{server.sshKeyId && (
|
|
||||||
<ShowServerActions serverId={server.serverId} />
|
|
||||||
)}
|
|
||||||
<DialogAction
|
<DialogAction
|
||||||
disabled={!canDelete}
|
disabled={!canDelete}
|
||||||
title={
|
title={
|
||||||
@ -220,17 +228,21 @@ export const ShowServers = () => {
|
|||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DialogAction>
|
</DialogAction>
|
||||||
|
|
||||||
{server.sshKeyId && (
|
{isActive && (
|
||||||
<>
|
<>
|
||||||
<DropdownMenuSeparator />
|
{server.sshKeyId && (
|
||||||
<DropdownMenuLabel>Extra</DropdownMenuLabel>
|
<>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
<DropdownMenuLabel>Extra</DropdownMenuLabel>
|
||||||
|
|
||||||
<ShowTraefikFileSystemModal
|
<ShowTraefikFileSystemModal
|
||||||
serverId={server.serverId}
|
serverId={server.serverId}
|
||||||
/>
|
/>
|
||||||
<ShowDockerContainersModal
|
<ShowDockerContainersModal
|
||||||
serverId={server.serverId}
|
serverId={server.serverId}
|
||||||
/>
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
|
@ -75,21 +75,7 @@ export default async function handler(
|
|||||||
return res.status(400).send("Webhook Error: Admin not found");
|
return res.status(400).send("Webhook Error: Admin not found");
|
||||||
}
|
}
|
||||||
const newServersQuantity = admin.serversQuantity;
|
const newServersQuantity = admin.serversQuantity;
|
||||||
const servers = await findServersByAdminIdSorted(admin.adminId);
|
await updateServersBasedOnQuantity(admin.adminId, newServersQuantity);
|
||||||
|
|
||||||
if (servers.length > newServersQuantity) {
|
|
||||||
for (const [index, server] of servers.entries()) {
|
|
||||||
if (index < newServersQuantity) {
|
|
||||||
await activateServer(server.serverId);
|
|
||||||
} else {
|
|
||||||
await deactivateServer(server.serverId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (const server of servers) {
|
|
||||||
await activateServer(server.serverId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "customer.subscription.created": {
|
case "customer.subscription.created": {
|
||||||
@ -101,20 +87,11 @@ export default async function handler(
|
|||||||
serversQuantity: newSubscription?.items?.data?.[0]?.quantity ?? 0,
|
serversQuantity: newSubscription?.items?.data?.[0]?.quantity ?? 0,
|
||||||
stripeCustomerId: newSubscription.customer as string,
|
stripeCustomerId: newSubscription.customer as string,
|
||||||
})
|
})
|
||||||
.where(
|
.where(eq(admins.stripeCustomerId, newSubscription.customer as string))
|
||||||
eq(
|
|
||||||
admins.stripeCustomerId,
|
|
||||||
typeof newSubscription.customer === "string"
|
|
||||||
? newSubscription.customer
|
|
||||||
: "",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.returning();
|
.returning();
|
||||||
|
|
||||||
const admin = await findAdminByStripeCustomerId(
|
const admin = await findAdminByStripeCustomerId(
|
||||||
typeof newSubscription.customer === "string"
|
newSubscription.customer as string,
|
||||||
? newSubscription.customer
|
|
||||||
: "",
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!admin) {
|
if (!admin) {
|
||||||
@ -122,26 +99,7 @@ export default async function handler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const newServersQuantity = admin.serversQuantity;
|
const newServersQuantity = admin.serversQuantity;
|
||||||
const servers = await findServersByAdminIdSorted(admin.adminId);
|
await updateServersBasedOnQuantity(admin.adminId, newServersQuantity);
|
||||||
|
|
||||||
// 4 > 3
|
|
||||||
if (servers.length > newServersQuantity) {
|
|
||||||
for (const [index, server] of servers.entries()) {
|
|
||||||
// 0 < 3 = true
|
|
||||||
// 1 < 3 = true
|
|
||||||
// 2 < 3 = true
|
|
||||||
// 3 < 3 = false
|
|
||||||
if (index < newServersQuantity) {
|
|
||||||
await activateServer(server.serverId);
|
|
||||||
} else {
|
|
||||||
await deactivateServer(server.serverId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (const server of servers) {
|
|
||||||
await activateServer(server.serverId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -155,19 +113,10 @@ export default async function handler(
|
|||||||
stripeSubscriptionId: null,
|
stripeSubscriptionId: null,
|
||||||
serversQuantity: 0,
|
serversQuantity: 0,
|
||||||
})
|
})
|
||||||
.where(
|
.where(eq(admins.stripeCustomerId, newSubscription.customer as string));
|
||||||
eq(
|
|
||||||
admins.stripeCustomerId,
|
|
||||||
typeof newSubscription.customer === "string"
|
|
||||||
? newSubscription.customer
|
|
||||||
: "",
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
const admin = await findAdminByStripeCustomerId(
|
const admin = await findAdminByStripeCustomerId(
|
||||||
typeof newSubscription.customer === "string"
|
newSubscription.customer as string,
|
||||||
? newSubscription.customer
|
|
||||||
: "",
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!admin) {
|
if (!admin) {
|
||||||
@ -179,25 +128,15 @@ export default async function handler(
|
|||||||
}
|
}
|
||||||
case "customer.subscription.updated": {
|
case "customer.subscription.updated": {
|
||||||
const newSubscription = event.data.object as Stripe.Subscription;
|
const newSubscription = event.data.object as Stripe.Subscription;
|
||||||
|
|
||||||
await db
|
await db
|
||||||
.update(admins)
|
.update(admins)
|
||||||
.set({
|
.set({
|
||||||
serversQuantity: newSubscription?.items?.data?.[0]?.quantity ?? 0,
|
serversQuantity: newSubscription?.items?.data?.[0]?.quantity ?? 0,
|
||||||
})
|
})
|
||||||
.where(
|
.where(eq(admins.stripeCustomerId, newSubscription.customer as string));
|
||||||
eq(
|
|
||||||
admins.stripeCustomerId,
|
|
||||||
typeof newSubscription.customer === "string"
|
|
||||||
? newSubscription.customer
|
|
||||||
: "",
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
const admin = await findAdminByStripeCustomerId(
|
const admin = await findAdminByStripeCustomerId(
|
||||||
typeof newSubscription.customer === "string"
|
newSubscription.customer as string,
|
||||||
? newSubscription.customer
|
|
||||||
: "",
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!admin) {
|
if (!admin) {
|
||||||
@ -205,21 +144,7 @@ export default async function handler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const newServersQuantity = admin.serversQuantity;
|
const newServersQuantity = admin.serversQuantity;
|
||||||
const servers = await findServersByAdminIdSorted(admin.adminId);
|
await updateServersBasedOnQuantity(admin.adminId, newServersQuantity);
|
||||||
|
|
||||||
if (servers.length > newServersQuantity) {
|
|
||||||
for (const [index, server] of servers.entries()) {
|
|
||||||
if (index < newServersQuantity) {
|
|
||||||
await activateServer(server.serverId);
|
|
||||||
} else {
|
|
||||||
await deactivateServer(server.serverId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (const server of servers) {
|
|
||||||
await activateServer(server.serverId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -245,21 +170,7 @@ export default async function handler(
|
|||||||
return res.status(400).send("Webhook Error: Admin not found");
|
return res.status(400).send("Webhook Error: Admin not found");
|
||||||
}
|
}
|
||||||
const newServersQuantity = admin.serversQuantity;
|
const newServersQuantity = admin.serversQuantity;
|
||||||
const servers = await findServersByAdminIdSorted(admin.adminId);
|
await updateServersBasedOnQuantity(admin.adminId, newServersQuantity);
|
||||||
if (servers.length > newServersQuantity) {
|
|
||||||
for (const [index, server] of servers.entries()) {
|
|
||||||
if (index < newServersQuantity) {
|
|
||||||
await activateServer(server.serverId);
|
|
||||||
} else {
|
|
||||||
await deactivateServer(server.serverId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (const server of servers) {
|
|
||||||
await activateServer(server.serverId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "invoice.payment_failed": {
|
case "invoice.payment_failed": {
|
||||||
@ -269,15 +180,10 @@ export default async function handler(
|
|||||||
.set({
|
.set({
|
||||||
serversQuantity: 0,
|
serversQuantity: 0,
|
||||||
})
|
})
|
||||||
.where(
|
.where(eq(admins.stripeCustomerId, newInvoice.customer as string));
|
||||||
eq(
|
|
||||||
admins.stripeCustomerId,
|
|
||||||
typeof newInvoice.customer === "string" ? newInvoice.customer : "",
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
const admin = await findAdminByStripeCustomerId(
|
const admin = await findAdminByStripeCustomerId(
|
||||||
typeof newInvoice.customer === "string" ? newInvoice.customer : "",
|
newInvoice.customer as string,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!admin) {
|
if (!admin) {
|
||||||
@ -308,7 +214,6 @@ export default async function handler(
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
console.log(`Unhandled event type: ${event.type}`);
|
console.log(`Unhandled event type: ${event.type}`);
|
||||||
}
|
}
|
||||||
@ -354,3 +259,23 @@ export const findServersByAdminIdSorted = async (adminId: string) => {
|
|||||||
|
|
||||||
return servers;
|
return servers;
|
||||||
};
|
};
|
||||||
|
export const updateServersBasedOnQuantity = async (
|
||||||
|
adminId: string,
|
||||||
|
newServersQuantity: number,
|
||||||
|
) => {
|
||||||
|
const servers = await findServersByAdminIdSorted(adminId);
|
||||||
|
|
||||||
|
if (servers.length > newServersQuantity) {
|
||||||
|
for (const [index, server] of servers.entries()) {
|
||||||
|
if (index < newServersQuantity) {
|
||||||
|
await activateServer(server.serverId);
|
||||||
|
} else {
|
||||||
|
await deactivateServer(server.serverId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (const server of servers) {
|
||||||
|
await activateServer(server.serverId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -22,13 +22,20 @@ import {
|
|||||||
BreadcrumbItem,
|
BreadcrumbItem,
|
||||||
BreadcrumbLink,
|
BreadcrumbLink,
|
||||||
} from "@/components/ui/breadcrumb";
|
} from "@/components/ui/breadcrumb";
|
||||||
|
import { Label } from "@/components/ui/label";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
|
import {
|
||||||
|
Tooltip,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipProvider,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from "@/components/ui/tooltip";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { appRouter } from "@/server/api/root";
|
import { appRouter } from "@/server/api/root";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { validateRequest } from "@dokploy/server";
|
import { validateRequest } from "@dokploy/server";
|
||||||
import { createServerSideHelpers } from "@trpc/react-query/server";
|
import { createServerSideHelpers } from "@trpc/react-query/server";
|
||||||
import { GlobeIcon } from "lucide-react";
|
import { GlobeIcon, HelpCircle } from "lucide-react";
|
||||||
import type {
|
import type {
|
||||||
GetServerSidePropsContext,
|
GetServerSidePropsContext,
|
||||||
InferGetServerSidePropsType,
|
InferGetServerSidePropsType,
|
||||||
@ -100,8 +107,38 @@ const Service = (
|
|||||||
</h1>
|
</h1>
|
||||||
<span className="text-sm">{data?.appName}</span>
|
<span className="text-sm">{data?.appName}</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="flex flex-row h-fit w-fit gap-2">
|
||||||
<Badge>{data?.server?.name || "Dokploy Server"}</Badge>
|
<Badge
|
||||||
|
variant={
|
||||||
|
data?.server?.serverStatus === "active"
|
||||||
|
? "default"
|
||||||
|
: "destructive"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{data?.server?.name || "Dokploy Server"}
|
||||||
|
</Badge>
|
||||||
|
{data?.server?.serverStatus === "inactive" && (
|
||||||
|
<TooltipProvider delayDuration={0}>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Label className="break-all w-fit flex flex-row gap-1 items-center">
|
||||||
|
<HelpCircle className="size-4 text-muted-foreground" />
|
||||||
|
</Label>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent
|
||||||
|
className="z-[999] w-[300px]"
|
||||||
|
align="start"
|
||||||
|
side="top"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
You cannot, deploy this application because the server
|
||||||
|
is inactive, please upgrade your plan to add more
|
||||||
|
servers.
|
||||||
|
</span>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{data?.description && (
|
{data?.description && (
|
||||||
|
@ -16,13 +16,21 @@ import {
|
|||||||
BreadcrumbItem,
|
BreadcrumbItem,
|
||||||
BreadcrumbLink,
|
BreadcrumbLink,
|
||||||
} from "@/components/ui/breadcrumb";
|
} from "@/components/ui/breadcrumb";
|
||||||
|
import { Label } from "@/components/ui/label";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
|
import {
|
||||||
|
Tooltip,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipProvider,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from "@/components/ui/tooltip";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { appRouter } from "@/server/api/root";
|
import { appRouter } from "@/server/api/root";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { validateRequest } from "@dokploy/server";
|
import { validateRequest } from "@dokploy/server";
|
||||||
import { createServerSideHelpers } from "@trpc/react-query/server";
|
import { createServerSideHelpers } from "@trpc/react-query/server";
|
||||||
import { CircuitBoard } from "lucide-react";
|
import { CircuitBoard } from "lucide-react";
|
||||||
|
import { HelpCircle } from "lucide-react";
|
||||||
import type {
|
import type {
|
||||||
GetServerSidePropsContext,
|
GetServerSidePropsContext,
|
||||||
InferGetServerSidePropsType,
|
InferGetServerSidePropsType,
|
||||||
@ -94,8 +102,38 @@ const Service = (
|
|||||||
</h1>
|
</h1>
|
||||||
<span className="text-sm">{data?.appName}</span>
|
<span className="text-sm">{data?.appName}</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="flex flex-row h-fit w-fit gap-2">
|
||||||
<Badge>{data?.server?.name || "Dokploy Server"}</Badge>
|
<Badge
|
||||||
|
variant={
|
||||||
|
data?.server?.serverStatus === "active"
|
||||||
|
? "default"
|
||||||
|
: "destructive"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{data?.server?.name || "Dokploy Server"}
|
||||||
|
</Badge>
|
||||||
|
{data?.server?.serverStatus === "inactive" && (
|
||||||
|
<TooltipProvider delayDuration={0}>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Label className="break-all w-fit flex flex-row gap-1 items-center">
|
||||||
|
<HelpCircle className="size-4 text-muted-foreground" />
|
||||||
|
</Label>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent
|
||||||
|
className="z-[999] w-[300px]"
|
||||||
|
align="start"
|
||||||
|
side="top"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
You cannot, deploy this application because the server
|
||||||
|
is inactive, please upgrade your plan to add more
|
||||||
|
servers.
|
||||||
|
</span>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{data?.description && (
|
{data?.description && (
|
||||||
<p className="text-sm text-muted-foreground max-w-6xl">
|
<p className="text-sm text-muted-foreground max-w-6xl">
|
||||||
|
@ -17,12 +17,20 @@ import {
|
|||||||
BreadcrumbItem,
|
BreadcrumbItem,
|
||||||
BreadcrumbLink,
|
BreadcrumbLink,
|
||||||
} from "@/components/ui/breadcrumb";
|
} from "@/components/ui/breadcrumb";
|
||||||
|
import { Label } from "@/components/ui/label";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
|
import {
|
||||||
|
Tooltip,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipProvider,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from "@/components/ui/tooltip";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { appRouter } from "@/server/api/root";
|
import { appRouter } from "@/server/api/root";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { validateRequest } from "@dokploy/server";
|
import { validateRequest } from "@dokploy/server";
|
||||||
import { createServerSideHelpers } from "@trpc/react-query/server";
|
import { createServerSideHelpers } from "@trpc/react-query/server";
|
||||||
|
import { HelpCircle } from "lucide-react";
|
||||||
import type {
|
import type {
|
||||||
GetServerSidePropsContext,
|
GetServerSidePropsContext,
|
||||||
InferGetServerSidePropsType,
|
InferGetServerSidePropsType,
|
||||||
@ -82,8 +90,38 @@ const Mariadb = (
|
|||||||
</h1>
|
</h1>
|
||||||
<span className="text-sm">{data?.appName}</span>
|
<span className="text-sm">{data?.appName}</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="flex flex-row h-fit w-fit gap-2">
|
||||||
<Badge>{data?.server?.name || "Dokploy Server"}</Badge>
|
<Badge
|
||||||
|
variant={
|
||||||
|
data?.server?.serverStatus === "active"
|
||||||
|
? "default"
|
||||||
|
: "destructive"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{data?.server?.name || "Dokploy Server"}
|
||||||
|
</Badge>
|
||||||
|
{data?.server?.serverStatus === "inactive" && (
|
||||||
|
<TooltipProvider delayDuration={0}>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Label className="break-all w-fit flex flex-row gap-1 items-center">
|
||||||
|
<HelpCircle className="size-4 text-muted-foreground" />
|
||||||
|
</Label>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent
|
||||||
|
className="z-[999] w-[300px]"
|
||||||
|
align="start"
|
||||||
|
side="top"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
You cannot, deploy this application because the server
|
||||||
|
is inactive, please upgrade your plan to add more
|
||||||
|
servers.
|
||||||
|
</span>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{data?.description && (
|
{data?.description && (
|
||||||
<p className="text-sm text-muted-foreground max-w-6xl">
|
<p className="text-sm text-muted-foreground max-w-6xl">
|
||||||
|
@ -17,12 +17,20 @@ import {
|
|||||||
BreadcrumbItem,
|
BreadcrumbItem,
|
||||||
BreadcrumbLink,
|
BreadcrumbLink,
|
||||||
} from "@/components/ui/breadcrumb";
|
} from "@/components/ui/breadcrumb";
|
||||||
|
import { Label } from "@/components/ui/label";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
|
import {
|
||||||
|
Tooltip,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipProvider,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from "@/components/ui/tooltip";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { appRouter } from "@/server/api/root";
|
import { appRouter } from "@/server/api/root";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { validateRequest } from "@dokploy/server";
|
import { validateRequest } from "@dokploy/server";
|
||||||
import { createServerSideHelpers } from "@trpc/react-query/server";
|
import { createServerSideHelpers } from "@trpc/react-query/server";
|
||||||
|
import { HelpCircle } from "lucide-react";
|
||||||
import type {
|
import type {
|
||||||
GetServerSidePropsContext,
|
GetServerSidePropsContext,
|
||||||
InferGetServerSidePropsType,
|
InferGetServerSidePropsType,
|
||||||
@ -83,8 +91,38 @@ const Mongo = (
|
|||||||
</h1>
|
</h1>
|
||||||
<span className="text-sm">{data?.appName}</span>
|
<span className="text-sm">{data?.appName}</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="flex flex-row h-fit w-fit gap-2">
|
||||||
<Badge>{data?.server?.name || "Dokploy Server"}</Badge>
|
<Badge
|
||||||
|
variant={
|
||||||
|
data?.server?.serverStatus === "active"
|
||||||
|
? "default"
|
||||||
|
: "destructive"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{data?.server?.name || "Dokploy Server"}
|
||||||
|
</Badge>
|
||||||
|
{data?.server?.serverStatus === "inactive" && (
|
||||||
|
<TooltipProvider delayDuration={0}>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Label className="break-all w-fit flex flex-row gap-1 items-center">
|
||||||
|
<HelpCircle className="size-4 text-muted-foreground" />
|
||||||
|
</Label>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent
|
||||||
|
className="z-[999] w-[300px]"
|
||||||
|
align="start"
|
||||||
|
side="top"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
You cannot, deploy this application because the server
|
||||||
|
is inactive, please upgrade your plan to add more
|
||||||
|
servers.
|
||||||
|
</span>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{data?.description && (
|
{data?.description && (
|
||||||
<p className="text-sm text-muted-foreground max-w-6xl">
|
<p className="text-sm text-muted-foreground max-w-6xl">
|
||||||
|
@ -17,12 +17,20 @@ import {
|
|||||||
BreadcrumbItem,
|
BreadcrumbItem,
|
||||||
BreadcrumbLink,
|
BreadcrumbLink,
|
||||||
} from "@/components/ui/breadcrumb";
|
} from "@/components/ui/breadcrumb";
|
||||||
|
import { Label } from "@/components/ui/label";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
|
import {
|
||||||
|
Tooltip,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipProvider,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from "@/components/ui/tooltip";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { appRouter } from "@/server/api/root";
|
import { appRouter } from "@/server/api/root";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { validateRequest } from "@dokploy/server";
|
import { validateRequest } from "@dokploy/server";
|
||||||
import { createServerSideHelpers } from "@trpc/react-query/server";
|
import { createServerSideHelpers } from "@trpc/react-query/server";
|
||||||
|
import { HelpCircle } from "lucide-react";
|
||||||
import type {
|
import type {
|
||||||
GetServerSidePropsContext,
|
GetServerSidePropsContext,
|
||||||
InferGetServerSidePropsType,
|
InferGetServerSidePropsType,
|
||||||
@ -81,8 +89,38 @@ const MySql = (
|
|||||||
</h1>
|
</h1>
|
||||||
<span className="text-sm">{data?.appName}</span>
|
<span className="text-sm">{data?.appName}</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="flex flex-row h-fit w-fit gap-2">
|
||||||
<Badge>{data?.server?.name || "Dokploy Server"}</Badge>
|
<Badge
|
||||||
|
variant={
|
||||||
|
data?.server?.serverStatus === "active"
|
||||||
|
? "default"
|
||||||
|
: "destructive"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{data?.server?.name || "Dokploy Server"}
|
||||||
|
</Badge>
|
||||||
|
{data?.server?.serverStatus === "inactive" && (
|
||||||
|
<TooltipProvider delayDuration={0}>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Label className="break-all w-fit flex flex-row gap-1 items-center">
|
||||||
|
<HelpCircle className="size-4 text-muted-foreground" />
|
||||||
|
</Label>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent
|
||||||
|
className="z-[999] w-[300px]"
|
||||||
|
align="start"
|
||||||
|
side="top"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
You cannot, deploy this application because the server
|
||||||
|
is inactive, please upgrade your plan to add more
|
||||||
|
servers.
|
||||||
|
</span>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{data?.description && (
|
{data?.description && (
|
||||||
<p className="text-sm text-muted-foreground max-w-6xl">
|
<p className="text-sm text-muted-foreground max-w-6xl">
|
||||||
|
@ -17,12 +17,20 @@ import {
|
|||||||
BreadcrumbItem,
|
BreadcrumbItem,
|
||||||
BreadcrumbLink,
|
BreadcrumbLink,
|
||||||
} from "@/components/ui/breadcrumb";
|
} from "@/components/ui/breadcrumb";
|
||||||
|
import { Label } from "@/components/ui/label";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
|
import {
|
||||||
|
Tooltip,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipProvider,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from "@/components/ui/tooltip";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { appRouter } from "@/server/api/root";
|
import { appRouter } from "@/server/api/root";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { validateRequest } from "@dokploy/server";
|
import { validateRequest } from "@dokploy/server";
|
||||||
import { createServerSideHelpers } from "@trpc/react-query/server";
|
import { createServerSideHelpers } from "@trpc/react-query/server";
|
||||||
|
import { HelpCircle } from "lucide-react";
|
||||||
import type {
|
import type {
|
||||||
GetServerSidePropsContext,
|
GetServerSidePropsContext,
|
||||||
InferGetServerSidePropsType,
|
InferGetServerSidePropsType,
|
||||||
@ -82,8 +90,38 @@ const Postgresql = (
|
|||||||
</h1>
|
</h1>
|
||||||
<span className="text-sm">{data?.appName}</span>
|
<span className="text-sm">{data?.appName}</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="flex flex-row h-fit w-fit gap-2">
|
||||||
<Badge>{data?.server?.name || "Dokploy Server"}</Badge>
|
<Badge
|
||||||
|
variant={
|
||||||
|
data?.server?.serverStatus === "active"
|
||||||
|
? "default"
|
||||||
|
: "destructive"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{data?.server?.name || "Dokploy Server"}
|
||||||
|
</Badge>
|
||||||
|
{data?.server?.serverStatus === "inactive" && (
|
||||||
|
<TooltipProvider delayDuration={0}>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Label className="break-all w-fit flex flex-row gap-1 items-center">
|
||||||
|
<HelpCircle className="size-4 text-muted-foreground" />
|
||||||
|
</Label>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent
|
||||||
|
className="z-[999] w-[300px]"
|
||||||
|
align="start"
|
||||||
|
side="top"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
You cannot, deploy this application because the server
|
||||||
|
is inactive, please upgrade your plan to add more
|
||||||
|
servers.
|
||||||
|
</span>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{data?.description && (
|
{data?.description && (
|
||||||
<p className="text-sm text-muted-foreground max-w-6xl">
|
<p className="text-sm text-muted-foreground max-w-6xl">
|
||||||
|
@ -16,12 +16,20 @@ import {
|
|||||||
BreadcrumbItem,
|
BreadcrumbItem,
|
||||||
BreadcrumbLink,
|
BreadcrumbLink,
|
||||||
} from "@/components/ui/breadcrumb";
|
} from "@/components/ui/breadcrumb";
|
||||||
|
import { Label } from "@/components/ui/label";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
|
import {
|
||||||
|
Tooltip,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipProvider,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from "@/components/ui/tooltip";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { appRouter } from "@/server/api/root";
|
import { appRouter } from "@/server/api/root";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { validateRequest } from "@dokploy/server";
|
import { validateRequest } from "@dokploy/server";
|
||||||
import { createServerSideHelpers } from "@trpc/react-query/server";
|
import { createServerSideHelpers } from "@trpc/react-query/server";
|
||||||
|
import { HelpCircle } from "lucide-react";
|
||||||
import type {
|
import type {
|
||||||
GetServerSidePropsContext,
|
GetServerSidePropsContext,
|
||||||
InferGetServerSidePropsType,
|
InferGetServerSidePropsType,
|
||||||
@ -81,8 +89,38 @@ const Redis = (
|
|||||||
</h1>
|
</h1>
|
||||||
<span className="text-sm">{data?.appName}</span>
|
<span className="text-sm">{data?.appName}</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="flex flex-row h-fit w-fit gap-2">
|
||||||
<Badge>{data?.server?.name || "Dokploy Server"}</Badge>
|
<Badge
|
||||||
|
variant={
|
||||||
|
data?.server?.serverStatus === "active"
|
||||||
|
? "default"
|
||||||
|
: "destructive"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{data?.server?.name || "Dokploy Server"}
|
||||||
|
</Badge>
|
||||||
|
{data?.server?.serverStatus === "inactive" && (
|
||||||
|
<TooltipProvider delayDuration={0}>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Label className="break-all w-fit flex flex-row gap-1 items-center">
|
||||||
|
<HelpCircle className="size-4 text-muted-foreground" />
|
||||||
|
</Label>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent
|
||||||
|
className="z-[999] w-[300px]"
|
||||||
|
align="start"
|
||||||
|
side="top"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
You cannot, deploy this application because the server
|
||||||
|
is inactive, please upgrade your plan to add more
|
||||||
|
servers.
|
||||||
|
</span>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{data?.description && (
|
{data?.description && (
|
||||||
<p className="text-sm text-muted-foreground max-w-6xl">
|
<p className="text-sm text-muted-foreground max-w-6xl">
|
||||||
|
@ -14,6 +14,7 @@ import {
|
|||||||
findMongoByBackupId,
|
findMongoByBackupId,
|
||||||
findMySqlByBackupId,
|
findMySqlByBackupId,
|
||||||
findPostgresByBackupId,
|
findPostgresByBackupId,
|
||||||
|
findServerById,
|
||||||
removeBackupById,
|
removeBackupById,
|
||||||
removeScheduleBackup,
|
removeScheduleBackup,
|
||||||
runMariadbBackup,
|
runMariadbBackup,
|
||||||
@ -36,6 +37,25 @@ export const backupRouter = createTRPCRouter({
|
|||||||
const backup = await findBackupById(newBackup.backupId);
|
const backup = await findBackupById(newBackup.backupId);
|
||||||
|
|
||||||
if (IS_CLOUD && backup.enabled) {
|
if (IS_CLOUD && backup.enabled) {
|
||||||
|
const databaseType = backup.databaseType;
|
||||||
|
let serverId = "";
|
||||||
|
if (databaseType === "postgres" && backup.postgres?.serverId) {
|
||||||
|
serverId = backup.postgres.serverId;
|
||||||
|
} else if (databaseType === "mysql" && backup.mysql?.serverId) {
|
||||||
|
serverId = backup.mysql.serverId;
|
||||||
|
} else if (databaseType === "mongo" && backup.mongo?.serverId) {
|
||||||
|
serverId = backup.mongo.serverId;
|
||||||
|
} else if (databaseType === "mariadb" && backup.mariadb?.serverId) {
|
||||||
|
serverId = backup.mariadb.serverId;
|
||||||
|
}
|
||||||
|
const server = await findServerById(serverId);
|
||||||
|
|
||||||
|
if (server.serverStatus === "inactive") {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "NOT_FOUND",
|
||||||
|
message: "Server is inactive",
|
||||||
|
});
|
||||||
|
}
|
||||||
await schedule({
|
await schedule({
|
||||||
cronSchedule: backup.schedule,
|
cronSchedule: backup.schedule,
|
||||||
backupId: backup.backupId,
|
backupId: backup.backupId,
|
||||||
|
@ -18,6 +18,7 @@ import {
|
|||||||
deployMariadb,
|
deployMariadb,
|
||||||
findMariadbById,
|
findMariadbById,
|
||||||
findProjectById,
|
findProjectById,
|
||||||
|
findServerById,
|
||||||
removeMariadbById,
|
removeMariadbById,
|
||||||
removeService,
|
removeService,
|
||||||
startService,
|
startService,
|
||||||
@ -151,6 +152,7 @@ export const mariadbRouter = createTRPCRouter({
|
|||||||
message: "You are not authorized to deploy this mariadb",
|
message: "You are not authorized to deploy this mariadb",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return deployMariadb(input.mariadbId);
|
return deployMariadb(input.mariadbId);
|
||||||
}),
|
}),
|
||||||
changeStatus: protectedProcedure
|
changeStatus: protectedProcedure
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { updateServersBasedOnQuantity } from "@/pages/api/stripe/webhook";
|
||||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||||
import { db } from "@/server/db";
|
import { db } from "@/server/db";
|
||||||
import {
|
import {
|
||||||
@ -15,15 +16,17 @@ import {
|
|||||||
server,
|
server,
|
||||||
} from "@/server/db/schema";
|
} from "@/server/db/schema";
|
||||||
import {
|
import {
|
||||||
|
IS_CLOUD,
|
||||||
createServer,
|
createServer,
|
||||||
deleteServer,
|
deleteServer,
|
||||||
|
findAdminById,
|
||||||
findServerById,
|
findServerById,
|
||||||
|
findServersByAdminId,
|
||||||
haveActiveServices,
|
haveActiveServices,
|
||||||
removeDeploymentsByServerId,
|
removeDeploymentsByServerId,
|
||||||
serverSetup,
|
serverSetup,
|
||||||
updateServerById,
|
updateServerById,
|
||||||
} from "@dokploy/server";
|
} from "@dokploy/server";
|
||||||
// import { serverSetup } from "@/server/setup/server-setup";
|
|
||||||
import { TRPCError } from "@trpc/server";
|
import { TRPCError } from "@trpc/server";
|
||||||
import { and, desc, eq, getTableColumns, isNotNull, sql } from "drizzle-orm";
|
import { and, desc, eq, getTableColumns, isNotNull, sql } from "drizzle-orm";
|
||||||
|
|
||||||
@ -32,6 +35,14 @@ export const serverRouter = createTRPCRouter({
|
|||||||
.input(apiCreateServer)
|
.input(apiCreateServer)
|
||||||
.mutation(async ({ ctx, input }) => {
|
.mutation(async ({ ctx, input }) => {
|
||||||
try {
|
try {
|
||||||
|
const admin = await findAdminById(ctx.user.adminId);
|
||||||
|
const servers = await findServersByAdminId(admin.adminId);
|
||||||
|
if (IS_CLOUD && servers.length >= admin.serversQuantity) {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "BAD_REQUEST",
|
||||||
|
message: "You cannot create more servers",
|
||||||
|
});
|
||||||
|
}
|
||||||
const project = await createServer(input, ctx.user.adminId);
|
const project = await createServer(input, ctx.user.adminId);
|
||||||
return project;
|
return project;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -77,13 +88,17 @@ export const serverRouter = createTRPCRouter({
|
|||||||
return result;
|
return result;
|
||||||
}),
|
}),
|
||||||
withSSHKey: protectedProcedure.query(async ({ ctx }) => {
|
withSSHKey: protectedProcedure.query(async ({ ctx }) => {
|
||||||
return await db.query.server.findMany({
|
const result = await db.query.server.findMany({
|
||||||
orderBy: desc(server.createdAt),
|
orderBy: desc(server.createdAt),
|
||||||
where: and(
|
where: IS_CLOUD
|
||||||
isNotNull(server.sshKeyId),
|
? and(
|
||||||
eq(server.adminId, ctx.user.adminId),
|
isNotNull(server.sshKeyId),
|
||||||
),
|
eq(server.adminId, ctx.user.adminId),
|
||||||
|
eq(server.serverStatus, "active"),
|
||||||
|
)
|
||||||
|
: and(isNotNull(server.sshKeyId), eq(server.adminId, ctx.user.adminId)),
|
||||||
});
|
});
|
||||||
|
return result;
|
||||||
}),
|
}),
|
||||||
setup: protectedProcedure
|
setup: protectedProcedure
|
||||||
.input(apiFindOneServer)
|
.input(apiFindOneServer)
|
||||||
@ -124,7 +139,12 @@ export const serverRouter = createTRPCRouter({
|
|||||||
const currentServer = await findServerById(input.serverId);
|
const currentServer = await findServerById(input.serverId);
|
||||||
await removeDeploymentsByServerId(currentServer);
|
await removeDeploymentsByServerId(currentServer);
|
||||||
await deleteServer(input.serverId);
|
await deleteServer(input.serverId);
|
||||||
|
const admin = await findAdminById(ctx.user.adminId);
|
||||||
|
|
||||||
|
await updateServersBasedOnQuantity(
|
||||||
|
admin.adminId,
|
||||||
|
admin.serversQuantity,
|
||||||
|
);
|
||||||
return currentServer;
|
return currentServer;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error;
|
throw error;
|
||||||
@ -141,6 +161,13 @@ export const serverRouter = createTRPCRouter({
|
|||||||
message: "You are not authorized to update this server",
|
message: "You are not authorized to update this server",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (server.serverStatus === "inactive") {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "NOT_FOUND",
|
||||||
|
message: "Server is inactive",
|
||||||
|
});
|
||||||
|
}
|
||||||
const currentServer = await updateServerById(input.serverId, {
|
const currentServer = await updateServerById(input.serverId, {
|
||||||
...input,
|
...input,
|
||||||
});
|
});
|
||||||
|
@ -221,6 +221,13 @@ export const settingsRouter = createTRPCRouter({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (server.enableDockerCleanup) {
|
if (server.enableDockerCleanup) {
|
||||||
|
const server = await findServerById(input.serverId);
|
||||||
|
if (server.serverStatus === "inactive") {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "NOT_FOUND",
|
||||||
|
message: "Server is inactive",
|
||||||
|
});
|
||||||
|
}
|
||||||
if (IS_CLOUD) {
|
if (IS_CLOUD) {
|
||||||
await schedule({
|
await schedule({
|
||||||
cronSchedule: "0 0 * * *",
|
cronSchedule: "0 0 * * *",
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { admins } from "@/server/db/schema";
|
|
||||||
import { getStripeItems } from "@/server/utils/stripe";
|
import { getStripeItems } from "@/server/utils/stripe";
|
||||||
import {
|
import {
|
||||||
IS_CLOUD,
|
IS_CLOUD,
|
||||||
@ -7,7 +6,6 @@ import {
|
|||||||
updateAdmin,
|
updateAdmin,
|
||||||
} from "@dokploy/server";
|
} from "@dokploy/server";
|
||||||
import { TRPCError } from "@trpc/server";
|
import { TRPCError } from "@trpc/server";
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
import Stripe from "stripe";
|
import Stripe from "stripe";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { adminProcedure, createTRPCRouter } from "../trpc";
|
import { adminProcedure, createTRPCRouter } from "../trpc";
|
||||||
@ -56,7 +54,7 @@ export const stripeRouter = createTRPCRouter({
|
|||||||
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY || "", {
|
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY || "", {
|
||||||
apiVersion: "2024-09-30.acacia",
|
apiVersion: "2024-09-30.acacia",
|
||||||
});
|
});
|
||||||
// await updateAdmin(ctx.user.a, {
|
// await updateAdmin(ctx.user.authId, {
|
||||||
// stripeCustomerId: null,
|
// stripeCustomerId: null,
|
||||||
// stripeSubscriptionId: null,
|
// stripeSubscriptionId: null,
|
||||||
// serversQuantity: 0,
|
// serversQuantity: 0,
|
||||||
@ -110,55 +108,7 @@ export const stripeRouter = createTRPCRouter({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
success: adminProcedure.query(async ({ ctx }) => {
|
|
||||||
const sessionId = ctx.req.query.sessionId as string;
|
|
||||||
|
|
||||||
if (!sessionId) {
|
|
||||||
throw new Error("No session_id provided");
|
|
||||||
}
|
|
||||||
|
|
||||||
// const session = await stripe.checkout.sessions.retrieve(sessionId);
|
|
||||||
|
|
||||||
// if (session.payment_status === "paid") {
|
|
||||||
// const admin = await findAdminById(ctx.user.adminId);
|
|
||||||
|
|
||||||
// // if (admin.stripeSubscriptionId) {
|
|
||||||
// // const subscription = await stripe.subscriptions.retrieve(
|
|
||||||
// // admin.stripeSubscriptionId,
|
|
||||||
// // );
|
|
||||||
// // if (subscription.status === "active") {
|
|
||||||
// // await stripe.subscriptions.update(admin.stripeSubscriptionId, {
|
|
||||||
// // cancel_at_period_end: true,
|
|
||||||
// // });
|
|
||||||
// // }
|
|
||||||
// // }
|
|
||||||
// console.log("Payment successful!");
|
|
||||||
|
|
||||||
// const stripeCustomerId = session.customer as string;
|
|
||||||
// console.log("Stripe Customer ID:", stripeCustomerId);
|
|
||||||
|
|
||||||
// const stripeSubscriptionId = session.subscription as string;
|
|
||||||
// const suscription =
|
|
||||||
// await stripe.subscriptions.retrieve(stripeSubscriptionId);
|
|
||||||
// console.log("Stripe Subscription ID:", stripeSubscriptionId);
|
|
||||||
|
|
||||||
// await db
|
|
||||||
// ?.update(admins)
|
|
||||||
// .set({
|
|
||||||
// stripeCustomerId,
|
|
||||||
// stripeSubscriptionId,
|
|
||||||
// serversQuantity: suscription?.items?.data?.[0]?.quantity ?? 0,
|
|
||||||
// })
|
|
||||||
// .where(eq(admins.adminId, ctx.user.adminId))
|
|
||||||
// .returning();
|
|
||||||
// } else {
|
|
||||||
// console.log("Payment not completed or failed.");
|
|
||||||
// }
|
|
||||||
|
|
||||||
ctx.res.redirect("/dashboard/settings/billing");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}),
|
|
||||||
canCreateMoreServers: adminProcedure.query(async ({ ctx }) => {
|
canCreateMoreServers: adminProcedure.query(async ({ ctx }) => {
|
||||||
const admin = await findAdminById(ctx.user.adminId);
|
const admin = await findAdminById(ctx.user.adminId);
|
||||||
const servers = await findServersByAdminId(admin.adminId);
|
const servers = await findServersByAdminId(admin.adminId);
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
|
import { findServerById } from "@dokploy/server";
|
||||||
import type { DeploymentJob } from "../queues/deployments-queue";
|
import type { DeploymentJob } from "../queues/deployments-queue";
|
||||||
|
|
||||||
export const deploy = async (jobData: DeploymentJob) => {
|
export const deploy = async (jobData: DeploymentJob) => {
|
||||||
try {
|
try {
|
||||||
|
const server = await findServerById(jobData.serverId as string);
|
||||||
|
if (server.serverStatus === "inactive") {
|
||||||
|
throw new Error("Server is inactive");
|
||||||
|
}
|
||||||
const result = await fetch(`${process.env.SERVER_URL}/deploy`, {
|
const result = await fetch(`${process.env.SERVER_URL}/deploy`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
|
@ -3,6 +3,7 @@ import {
|
|||||||
cleanUpSystemPrune,
|
cleanUpSystemPrune,
|
||||||
cleanUpUnusedImages,
|
cleanUpUnusedImages,
|
||||||
findBackupById,
|
findBackupById,
|
||||||
|
findServerById,
|
||||||
runMariadbBackup,
|
runMariadbBackup,
|
||||||
runMongoBackup,
|
runMongoBackup,
|
||||||
runMySqlBackup,
|
runMySqlBackup,
|
||||||
@ -21,22 +22,47 @@ export const runJobs = async (job: QueueJob) => {
|
|||||||
const { backupId } = job;
|
const { backupId } = job;
|
||||||
const backup = await findBackupById(backupId);
|
const backup = await findBackupById(backupId);
|
||||||
const { databaseType, postgres, mysql, mongo, mariadb } = backup;
|
const { databaseType, postgres, mysql, mongo, mariadb } = backup;
|
||||||
|
|
||||||
if (databaseType === "postgres" && postgres) {
|
if (databaseType === "postgres" && postgres) {
|
||||||
|
const server = await findServerById(postgres.serverId as string);
|
||||||
|
if (server.serverStatus === "inactive") {
|
||||||
|
logger.info("Server is inactive");
|
||||||
|
return;
|
||||||
|
}
|
||||||
await runPostgresBackup(postgres, backup);
|
await runPostgresBackup(postgres, backup);
|
||||||
} else if (databaseType === "mysql" && mysql) {
|
} else if (databaseType === "mysql" && mysql) {
|
||||||
|
const server = await findServerById(mysql.serverId as string);
|
||||||
|
if (server.serverStatus === "inactive") {
|
||||||
|
logger.info("Server is inactive");
|
||||||
|
return;
|
||||||
|
}
|
||||||
await runMySqlBackup(mysql, backup);
|
await runMySqlBackup(mysql, backup);
|
||||||
} else if (databaseType === "mongo" && mongo) {
|
} else if (databaseType === "mongo" && mongo) {
|
||||||
|
const server = await findServerById(mongo.serverId as string);
|
||||||
|
if (server.serverStatus === "inactive") {
|
||||||
|
logger.info("Server is inactive");
|
||||||
|
return;
|
||||||
|
}
|
||||||
await runMongoBackup(mongo, backup);
|
await runMongoBackup(mongo, backup);
|
||||||
} else if (databaseType === "mariadb" && mariadb) {
|
} else if (databaseType === "mariadb" && mariadb) {
|
||||||
|
const server = await findServerById(mariadb.serverId as string);
|
||||||
|
if (server.serverStatus === "inactive") {
|
||||||
|
logger.info("Server is inactive");
|
||||||
|
return;
|
||||||
|
}
|
||||||
await runMariadbBackup(mariadb, backup);
|
await runMariadbBackup(mariadb, backup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (job.type === "server") {
|
if (job.type === "server") {
|
||||||
const { serverId } = job;
|
const { serverId } = job;
|
||||||
|
const server = await findServerById(serverId);
|
||||||
|
if (server.serverStatus === "inactive") {
|
||||||
|
logger.info("Server is inactive");
|
||||||
|
return;
|
||||||
|
}
|
||||||
await cleanUpUnusedImages(serverId);
|
await cleanUpUnusedImages(serverId);
|
||||||
await cleanUpDockerBuilder(serverId);
|
await cleanUpDockerBuilder(serverId);
|
||||||
await cleanUpSystemPrune(serverId);
|
await cleanUpSystemPrune(serverId);
|
||||||
// await sendDockerCleanupNotifications();
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(error);
|
logger.error(error);
|
||||||
|
Loading…
Reference in New Issue
Block a user