mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-06-26 17:45:49 +02:00
Schedules were returned in arbitrary order from the database. Add orderBy clause to sort them alphabetically by name.
212 lines
5.7 KiB
TypeScript
212 lines
5.7 KiB
TypeScript
import { IS_CLOUD, removeScheduleJob, scheduleJob } from "@dokploy/server";
|
|
import { db } from "@dokploy/server/db";
|
|
import { deployments } from "@dokploy/server/db/schema/deployment";
|
|
import {
|
|
createScheduleSchema,
|
|
schedules,
|
|
updateScheduleSchema,
|
|
} from "@dokploy/server/db/schema/schedule";
|
|
import { runCommand } from "@dokploy/server/index";
|
|
import {
|
|
createSchedule,
|
|
deleteSchedule,
|
|
findScheduleById,
|
|
updateSchedule,
|
|
} from "@dokploy/server/services/schedule";
|
|
import { TRPCError } from "@trpc/server";
|
|
import { asc, desc, eq } from "drizzle-orm";
|
|
import { z } from "zod";
|
|
import { audit } from "@/server/api/utils/audit";
|
|
import { removeJob, schedule } from "@/server/utils/backup";
|
|
import { checkServicePermissionAndAccess } from "@dokploy/server/services/permission";
|
|
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
|
export const scheduleRouter = createTRPCRouter({
|
|
create: protectedProcedure
|
|
.input(createScheduleSchema)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const serviceId = input.applicationId || input.composeId;
|
|
if (serviceId) {
|
|
await checkServicePermissionAndAccess(ctx, serviceId, {
|
|
schedule: ["create"],
|
|
});
|
|
}
|
|
const newSchedule = await createSchedule(input);
|
|
|
|
if (newSchedule?.enabled) {
|
|
if (IS_CLOUD) {
|
|
schedule({
|
|
scheduleId: newSchedule.scheduleId,
|
|
type: "schedule",
|
|
cronSchedule: newSchedule.cronExpression,
|
|
timezone: newSchedule.timezone,
|
|
});
|
|
} else {
|
|
scheduleJob(newSchedule);
|
|
}
|
|
}
|
|
await audit(ctx, {
|
|
action: "create",
|
|
resourceType: "schedule",
|
|
resourceId: newSchedule?.scheduleId,
|
|
resourceName: newSchedule?.name,
|
|
});
|
|
return newSchedule;
|
|
}),
|
|
|
|
update: protectedProcedure
|
|
.input(updateScheduleSchema)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const existingSchedule = await findScheduleById(input.scheduleId);
|
|
const serviceId =
|
|
existingSchedule.applicationId || existingSchedule.composeId;
|
|
if (serviceId) {
|
|
await checkServicePermissionAndAccess(ctx, serviceId, {
|
|
schedule: ["update"],
|
|
});
|
|
}
|
|
const updatedSchedule = await updateSchedule(input);
|
|
|
|
if (IS_CLOUD) {
|
|
if (updatedSchedule?.enabled) {
|
|
schedule({
|
|
scheduleId: updatedSchedule.scheduleId,
|
|
type: "schedule",
|
|
cronSchedule: updatedSchedule.cronExpression,
|
|
timezone: updatedSchedule.timezone,
|
|
});
|
|
} else {
|
|
await removeJob({
|
|
cronSchedule: updatedSchedule.cronExpression,
|
|
scheduleId: updatedSchedule.scheduleId,
|
|
type: "schedule",
|
|
});
|
|
}
|
|
} else {
|
|
if (updatedSchedule?.enabled) {
|
|
removeScheduleJob(updatedSchedule.scheduleId);
|
|
scheduleJob(updatedSchedule);
|
|
} else {
|
|
removeScheduleJob(updatedSchedule.scheduleId);
|
|
}
|
|
}
|
|
await audit(ctx, {
|
|
action: "update",
|
|
resourceType: "schedule",
|
|
resourceId: updatedSchedule.scheduleId,
|
|
resourceName: updatedSchedule.name,
|
|
});
|
|
return updatedSchedule;
|
|
}),
|
|
|
|
delete: protectedProcedure
|
|
.input(z.object({ scheduleId: z.string() }))
|
|
.mutation(async ({ input, ctx }) => {
|
|
const scheduleItem = await findScheduleById(input.scheduleId);
|
|
const serviceId = scheduleItem.applicationId || scheduleItem.composeId;
|
|
if (serviceId) {
|
|
await checkServicePermissionAndAccess(ctx, serviceId, {
|
|
schedule: ["delete"],
|
|
});
|
|
}
|
|
await deleteSchedule(input.scheduleId);
|
|
|
|
if (IS_CLOUD) {
|
|
await removeJob({
|
|
cronSchedule: scheduleItem.cronExpression,
|
|
scheduleId: scheduleItem.scheduleId,
|
|
type: "schedule",
|
|
});
|
|
} else {
|
|
removeScheduleJob(scheduleItem.scheduleId);
|
|
}
|
|
await audit(ctx, {
|
|
action: "delete",
|
|
resourceType: "schedule",
|
|
resourceId: scheduleItem.scheduleId,
|
|
resourceName: scheduleItem.name,
|
|
});
|
|
return true;
|
|
}),
|
|
|
|
list: protectedProcedure
|
|
.input(
|
|
z.object({
|
|
id: z.string(),
|
|
scheduleType: z.enum([
|
|
"application",
|
|
"compose",
|
|
"server",
|
|
"dokploy-server",
|
|
]),
|
|
}),
|
|
)
|
|
.query(async ({ input, ctx }) => {
|
|
if (
|
|
input.scheduleType === "application" ||
|
|
input.scheduleType === "compose"
|
|
) {
|
|
await checkServicePermissionAndAccess(ctx, input.id, {
|
|
schedule: ["read"],
|
|
});
|
|
}
|
|
const where = {
|
|
application: eq(schedules.applicationId, input.id),
|
|
compose: eq(schedules.composeId, input.id),
|
|
server: eq(schedules.serverId, input.id),
|
|
"dokploy-server": eq(schedules.userId, input.id),
|
|
};
|
|
return db.query.schedules.findMany({
|
|
where: where[input.scheduleType],
|
|
orderBy: [asc(schedules.name)],
|
|
with: {
|
|
application: true,
|
|
server: true,
|
|
compose: true,
|
|
deployments: {
|
|
orderBy: [desc(deployments.createdAt)],
|
|
},
|
|
},
|
|
});
|
|
}),
|
|
|
|
one: protectedProcedure
|
|
.input(z.object({ scheduleId: z.string() }))
|
|
.query(async ({ input, ctx }) => {
|
|
const schedule = await findScheduleById(input.scheduleId);
|
|
const serviceId = schedule.applicationId || schedule.composeId;
|
|
if (serviceId) {
|
|
await checkServicePermissionAndAccess(ctx, serviceId, {
|
|
schedule: ["read"],
|
|
});
|
|
}
|
|
return schedule;
|
|
}),
|
|
|
|
runManually: protectedProcedure
|
|
.input(z.object({ scheduleId: z.string().min(1) }))
|
|
.mutation(async ({ input, ctx }) => {
|
|
const scheduleItem = await findScheduleById(input.scheduleId);
|
|
const serviceId = scheduleItem.applicationId || scheduleItem.composeId;
|
|
if (serviceId) {
|
|
await checkServicePermissionAndAccess(ctx, serviceId, {
|
|
schedule: ["create"],
|
|
});
|
|
}
|
|
try {
|
|
await runCommand(input.scheduleId);
|
|
await audit(ctx, {
|
|
action: "run",
|
|
resourceType: "schedule",
|
|
resourceId: input.scheduleId,
|
|
});
|
|
return true;
|
|
} catch (error) {
|
|
throw new TRPCError({
|
|
code: "INTERNAL_SERVER_ERROR",
|
|
message:
|
|
error instanceof Error ? error.message : "Error running schedule",
|
|
});
|
|
}
|
|
}),
|
|
});
|