mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-07-03 21:15:23 +02:00
Merge branch 'canary' into patches-impl
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
addNewService,
|
||||
checkServiceAccess,
|
||||
clearOldDeployments,
|
||||
createApplication,
|
||||
deleteAllMiddlewares,
|
||||
findApplicationById,
|
||||
@@ -746,6 +747,23 @@ export const applicationRouter = createTRPCRouter({
|
||||
}
|
||||
await cleanQueuesByApplication(input.applicationId);
|
||||
}),
|
||||
clearDeployments: protectedProcedure
|
||||
.input(apiFindOneApplication)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message:
|
||||
"You are not authorized to clear deployments for this application",
|
||||
});
|
||||
}
|
||||
await clearOldDeployments(application.appName, application.serverId);
|
||||
return true;
|
||||
}),
|
||||
killBuild: protectedProcedure
|
||||
.input(apiFindOneApplication)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
addDomainToCompose,
|
||||
addNewService,
|
||||
checkServiceAccess,
|
||||
clearOldDeployments,
|
||||
cloneCompose,
|
||||
createCommand,
|
||||
createCompose,
|
||||
@@ -263,6 +264,23 @@ export const composeRouter = createTRPCRouter({
|
||||
await cleanQueuesByCompose(input.composeId);
|
||||
return { success: true, message: "Queues cleaned successfully" };
|
||||
}),
|
||||
clearDeployments: protectedProcedure
|
||||
.input(apiFindCompose)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const compose = await findComposeById(input.composeId);
|
||||
if (
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message:
|
||||
"You are not authorized to clear deployments for this compose",
|
||||
});
|
||||
}
|
||||
await clearOldDeployments(compose.appName, compose.serverId);
|
||||
return true;
|
||||
}),
|
||||
killBuild: protectedProcedure
|
||||
.input(apiFindCompose)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
findComposeById,
|
||||
findDeploymentById,
|
||||
findServerById,
|
||||
removeDeployment,
|
||||
updateDeploymentStatus,
|
||||
} from "@dokploy/server";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
@@ -107,4 +108,14 @@ export const deploymentRouter = createTRPCRouter({
|
||||
|
||||
await updateDeploymentStatus(deployment.deploymentId, "error");
|
||||
}),
|
||||
|
||||
removeDeployment: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
deploymentId: z.string().min(1),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ input }) => {
|
||||
return await removeDeployment(input.deploymentId);
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
createPushoverNotification,
|
||||
createResendNotification,
|
||||
createSlackNotification,
|
||||
createTeamsNotification,
|
||||
createTelegramNotification,
|
||||
findNotificationById,
|
||||
getWebServerSettings,
|
||||
@@ -23,6 +24,7 @@ import {
|
||||
sendResendNotification,
|
||||
sendServerThresholdNotifications,
|
||||
sendSlackNotification,
|
||||
sendTeamsNotification,
|
||||
sendTelegramNotification,
|
||||
updateCustomNotification,
|
||||
updateDiscordNotification,
|
||||
@@ -33,6 +35,7 @@ import {
|
||||
updatePushoverNotification,
|
||||
updateResendNotification,
|
||||
updateSlackNotification,
|
||||
updateTeamsNotification,
|
||||
updateTelegramNotification,
|
||||
} from "@dokploy/server";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
@@ -55,6 +58,7 @@ import {
|
||||
apiCreatePushover,
|
||||
apiCreateResend,
|
||||
apiCreateSlack,
|
||||
apiCreateTeams,
|
||||
apiCreateTelegram,
|
||||
apiFindOneNotification,
|
||||
apiTestCustomConnection,
|
||||
@@ -66,6 +70,7 @@ import {
|
||||
apiTestPushoverConnection,
|
||||
apiTestResendConnection,
|
||||
apiTestSlackConnection,
|
||||
apiTestTeamsConnection,
|
||||
apiTestTelegramConnection,
|
||||
apiUpdateCustom,
|
||||
apiUpdateDiscord,
|
||||
@@ -76,6 +81,7 @@ import {
|
||||
apiUpdatePushover,
|
||||
apiUpdateResend,
|
||||
apiUpdateSlack,
|
||||
apiUpdateTeams,
|
||||
apiUpdateTelegram,
|
||||
notifications,
|
||||
server,
|
||||
@@ -413,6 +419,7 @@ export const notificationRouter = createTRPCRouter({
|
||||
custom: true,
|
||||
lark: true,
|
||||
pushover: true,
|
||||
teams: true,
|
||||
},
|
||||
orderBy: desc(notifications.createdAt),
|
||||
where: eq(notifications.organizationId, ctx.session.activeOrganizationId),
|
||||
@@ -705,6 +712,61 @@ export const notificationRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
}),
|
||||
createTeams: adminProcedure
|
||||
.input(apiCreateTeams)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
return await createTeamsNotification(
|
||||
input,
|
||||
ctx.session.activeOrganizationId,
|
||||
);
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error creating the notification",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
updateTeams: adminProcedure
|
||||
.input(apiUpdateTeams)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
const notification = await findNotificationById(input.notificationId);
|
||||
if (
|
||||
IS_CLOUD &&
|
||||
notification.organizationId !== ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to update this notification",
|
||||
});
|
||||
}
|
||||
return await updateTeamsNotification({
|
||||
...input,
|
||||
organizationId: ctx.session.activeOrganizationId,
|
||||
});
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}),
|
||||
testTeamsConnection: adminProcedure
|
||||
.input(apiTestTeamsConnection)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
await sendTeamsNotification(input, {
|
||||
title: "🤚 Test Notification",
|
||||
facts: [{ name: "Message", value: "Hi, From Dokploy 👋" }],
|
||||
});
|
||||
return true;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: `${error instanceof Error ? error.message : "Unknown error"}`,
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
createPushover: adminProcedure
|
||||
.input(apiCreatePushover)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
|
||||
@@ -55,9 +55,128 @@ export const ssoRouter = createTRPCRouter({
|
||||
samlConfig: true,
|
||||
organizationId: true,
|
||||
},
|
||||
orderBy: [asc(ssoProvider.createdAt)],
|
||||
});
|
||||
return providers;
|
||||
}),
|
||||
one: enterpriseProcedure
|
||||
.input(z.object({ providerId: z.string().min(1) }))
|
||||
.query(async ({ ctx, input }) => {
|
||||
const provider = await db.query.ssoProvider.findFirst({
|
||||
where: and(
|
||||
eq(ssoProvider.providerId, input.providerId),
|
||||
eq(ssoProvider.organizationId, ctx.session.activeOrganizationId),
|
||||
eq(ssoProvider.userId, ctx.session.userId),
|
||||
),
|
||||
columns: {
|
||||
id: true,
|
||||
providerId: true,
|
||||
issuer: true,
|
||||
domain: true,
|
||||
oidcConfig: true,
|
||||
samlConfig: true,
|
||||
organizationId: true,
|
||||
},
|
||||
});
|
||||
if (!provider) {
|
||||
throw new TRPCError({
|
||||
code: "NOT_FOUND",
|
||||
message:
|
||||
"SSO provider not found or you do not have permission to access it",
|
||||
});
|
||||
}
|
||||
return provider;
|
||||
}),
|
||||
update: enterpriseProcedure
|
||||
.input(ssoProviderBodySchema)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const existing = await db.query.ssoProvider.findFirst({
|
||||
where: and(
|
||||
eq(ssoProvider.providerId, input.providerId),
|
||||
eq(ssoProvider.organizationId, ctx.session.activeOrganizationId),
|
||||
eq(ssoProvider.userId, ctx.session.userId),
|
||||
),
|
||||
columns: {
|
||||
id: true,
|
||||
issuer: true,
|
||||
domain: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!existing) {
|
||||
throw new TRPCError({
|
||||
code: "NOT_FOUND",
|
||||
message:
|
||||
"SSO provider not found or you do not have permission to update it",
|
||||
});
|
||||
}
|
||||
|
||||
const providers = await db.query.ssoProvider.findMany({
|
||||
where: eq(ssoProvider.organizationId, ctx.session.activeOrganizationId),
|
||||
columns: { providerId: true, domain: true },
|
||||
});
|
||||
|
||||
for (const provider of providers) {
|
||||
if (provider.providerId === input.providerId) continue;
|
||||
const providerDomains = provider.domain
|
||||
.split(",")
|
||||
.map((d) => d.trim().toLowerCase());
|
||||
for (const domain of input.domains) {
|
||||
if (providerDomains.includes(domain)) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: `Domain ${domain} is already registered for another provider`,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const issuerChanged =
|
||||
normalizeTrustedOrigin(existing.issuer) !==
|
||||
normalizeTrustedOrigin(input.issuer);
|
||||
if (issuerChanged) {
|
||||
const currentUser = await db.query.user.findFirst({
|
||||
where: eq(user.id, ctx.session.userId),
|
||||
columns: { trustedOrigins: true },
|
||||
});
|
||||
const trustedOrigins = currentUser?.trustedOrigins ?? [];
|
||||
const newOrigin = normalizeTrustedOrigin(input.issuer);
|
||||
const isInTrustedOrigins = trustedOrigins.some(
|
||||
(o) => o.toLowerCase() === newOrigin.toLowerCase(),
|
||||
);
|
||||
if (!isInTrustedOrigins) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message:
|
||||
"The new Issuer URL is not in your trusted origins list. Please add it in Manage origins before saving.",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const domain = input.domains.join(",");
|
||||
const updateBody: {
|
||||
issuer: string;
|
||||
domain: string;
|
||||
oidcConfig?: (typeof input)["oidcConfig"];
|
||||
samlConfig?: (typeof input)["samlConfig"];
|
||||
} = {
|
||||
issuer: input.issuer,
|
||||
domain,
|
||||
};
|
||||
if (input.oidcConfig != null) {
|
||||
updateBody.oidcConfig = input.oidcConfig;
|
||||
}
|
||||
if (input.samlConfig != null) {
|
||||
updateBody.samlConfig = input.samlConfig;
|
||||
}
|
||||
|
||||
await auth.updateSSOProvider({
|
||||
params: { providerId: input.providerId },
|
||||
body: updateBody,
|
||||
headers: requestToHeaders(ctx.req),
|
||||
});
|
||||
return { success: true };
|
||||
}),
|
||||
deleteProvider: enterpriseProcedure
|
||||
.input(z.object({ providerId: z.string().min(1) }))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
@@ -102,24 +221,6 @@ export const ssoRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
|
||||
const currentUser = await db.query.user.findFirst({
|
||||
where: eq(user.id, ctx.session.userId),
|
||||
columns: {
|
||||
trustedOrigins: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (currentUser?.trustedOrigins) {
|
||||
const issuerOrigin = normalizeTrustedOrigin(providerToDelete.issuer);
|
||||
const updatedOrigins = currentUser.trustedOrigins.filter(
|
||||
(origin) => origin.toLowerCase() !== issuerOrigin.toLowerCase(),
|
||||
);
|
||||
|
||||
await db
|
||||
.update(user)
|
||||
.set({ trustedOrigins: updatedOrigins })
|
||||
.where(eq(user.id, ctx.session.userId));
|
||||
}
|
||||
return { success: true };
|
||||
}),
|
||||
register: enterpriseProcedure
|
||||
@@ -147,25 +248,6 @@ export const ssoRouter = createTRPCRouter({
|
||||
}
|
||||
}
|
||||
const domain = input.domains.join(",");
|
||||
const currentUser = await db.query.user.findFirst({
|
||||
where: eq(user.id, ctx.session.userId),
|
||||
columns: {
|
||||
trustedOrigins: true,
|
||||
},
|
||||
});
|
||||
|
||||
const existingOrigins = currentUser?.trustedOrigins || [];
|
||||
|
||||
const issuerOrigin = normalizeTrustedOrigin(input.issuer);
|
||||
|
||||
const newOrigins = Array.from(
|
||||
new Set([...existingOrigins, issuerOrigin]),
|
||||
);
|
||||
|
||||
await db
|
||||
.update(user)
|
||||
.set({ trustedOrigins: newOrigins })
|
||||
.where(eq(user.id, ctx.session.userId));
|
||||
|
||||
await auth.registerSSOProvider({
|
||||
body: {
|
||||
@@ -177,4 +259,65 @@ export const ssoRouter = createTRPCRouter({
|
||||
});
|
||||
return { success: true };
|
||||
}),
|
||||
addTrustedOrigin: enterpriseProcedure
|
||||
.input(z.object({ origin: z.string().min(1) }))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const normalized = normalizeTrustedOrigin(input.origin);
|
||||
const currentUser = await db.query.user.findFirst({
|
||||
where: eq(user.id, ctx.session.userId),
|
||||
columns: { trustedOrigins: true },
|
||||
});
|
||||
const existing = currentUser?.trustedOrigins || [];
|
||||
if (existing.some((o) => o.toLowerCase() === normalized.toLowerCase())) {
|
||||
return { success: true };
|
||||
}
|
||||
const next = Array.from(new Set([...existing, normalized]));
|
||||
await db
|
||||
.update(user)
|
||||
.set({ trustedOrigins: next })
|
||||
.where(eq(user.id, ctx.session.userId));
|
||||
return { success: true };
|
||||
}),
|
||||
removeTrustedOrigin: enterpriseProcedure
|
||||
.input(z.object({ origin: z.string().min(1) }))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const normalized = normalizeTrustedOrigin(input.origin);
|
||||
const currentUser = await db.query.user.findFirst({
|
||||
where: eq(user.id, ctx.session.userId),
|
||||
columns: { trustedOrigins: true },
|
||||
});
|
||||
const existing = currentUser?.trustedOrigins || [];
|
||||
const next = existing.filter(
|
||||
(o) => o.toLowerCase() !== normalized.toLowerCase(),
|
||||
);
|
||||
await db
|
||||
.update(user)
|
||||
.set({ trustedOrigins: next })
|
||||
.where(eq(user.id, ctx.session.userId));
|
||||
return { success: true };
|
||||
}),
|
||||
updateTrustedOrigin: enterpriseProcedure
|
||||
.input(
|
||||
z.object({
|
||||
oldOrigin: z.string().min(1),
|
||||
newOrigin: z.string().min(1),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const oldNorm = normalizeTrustedOrigin(input.oldOrigin);
|
||||
const newNorm = normalizeTrustedOrigin(input.newOrigin);
|
||||
const currentUser = await db.query.user.findFirst({
|
||||
where: eq(user.id, ctx.session.userId),
|
||||
columns: { trustedOrigins: true },
|
||||
});
|
||||
const existing = currentUser?.trustedOrigins || [];
|
||||
const next = existing.map((o) =>
|
||||
o.toLowerCase() === oldNorm.toLowerCase() ? newNorm : o,
|
||||
);
|
||||
await db
|
||||
.update(user)
|
||||
.set({ trustedOrigins: next })
|
||||
.where(eq(user.id, ctx.session.userId));
|
||||
return { success: true };
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -27,12 +27,17 @@ export const stripeRouter = createTRPCRouter({
|
||||
const products = await stripe.products.list({
|
||||
expand: ["data.default_price"],
|
||||
active: true,
|
||||
ids: [PRODUCT_MONTHLY_ID, PRODUCT_ANNUAL_ID],
|
||||
});
|
||||
|
||||
const filteredProducts = products.data.filter((product) => {
|
||||
return (
|
||||
product.id === PRODUCT_MONTHLY_ID || product.id === PRODUCT_ANNUAL_ID
|
||||
);
|
||||
});
|
||||
|
||||
if (!stripeCustomerId) {
|
||||
return {
|
||||
products: products.data,
|
||||
products: filteredProducts,
|
||||
subscriptions: [],
|
||||
};
|
||||
}
|
||||
@@ -44,7 +49,7 @@ export const stripeRouter = createTRPCRouter({
|
||||
});
|
||||
|
||||
return {
|
||||
products: products.data,
|
||||
products: filteredProducts,
|
||||
subscriptions: subscriptions.data,
|
||||
};
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user