mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-06-15 20:25:23 +02:00
Updated the orderBy clause in the schedules query to sort by the createdAt field instead of the name, ensuring schedules are returned in the order they were created.
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.createdAt)],
|
|
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",
|
|
});
|
|
}
|
|
}),
|
|
});
|