mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-07-17 11:55:30 +02:00
Merge branch 'canary' into multiple-admins
This commit is contained in:
@@ -4,7 +4,11 @@ import {
|
||||
apiUpdateAi,
|
||||
deploySuggestionSchema,
|
||||
} from "@dokploy/server/db/schema/ai";
|
||||
import { createDomain, createMount } from "@dokploy/server/index";
|
||||
import {
|
||||
createDomain,
|
||||
createMount,
|
||||
findEnvironmentById,
|
||||
} from "@dokploy/server/index";
|
||||
import {
|
||||
deleteAiSettings,
|
||||
getAiSettingById,
|
||||
@@ -58,6 +62,12 @@ export const aiRouter = createTRPCRouter({
|
||||
case "ollama":
|
||||
response = await fetch(`${input.apiUrl}/api/tags`, { headers });
|
||||
break;
|
||||
case "gemini":
|
||||
response = await fetch(
|
||||
`${input.apiUrl}/models?key=${encodeURIComponent(input.apiKey)}`,
|
||||
{ headers: {} },
|
||||
);
|
||||
break;
|
||||
default:
|
||||
if (!input.apiKey)
|
||||
throw new TRPCError({
|
||||
@@ -177,10 +187,12 @@ export const aiRouter = createTRPCRouter({
|
||||
deploy: protectedProcedure
|
||||
.input(deploySuggestionSchema)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const environment = await findEnvironmentById(input.environmentId);
|
||||
const project = await findProjectById(environment.projectId);
|
||||
if (ctx.user.role === "member") {
|
||||
await checkServiceAccess(
|
||||
ctx.session.activeOrganizationId,
|
||||
input.projectId,
|
||||
environment.projectId,
|
||||
"create",
|
||||
);
|
||||
}
|
||||
@@ -192,8 +204,6 @@ export const aiRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
|
||||
const project = await findProjectById(input.projectId);
|
||||
|
||||
const projectName = slugify(`${project.name} ${input.id}`);
|
||||
|
||||
const compose = await createComposeByTemplate({
|
||||
@@ -205,6 +215,7 @@ export const aiRouter = createTRPCRouter({
|
||||
sourceType: "raw",
|
||||
appName: `${projectName}-${generatePassword(6)}`,
|
||||
isolatedDeployment: true,
|
||||
environmentId: input.environmentId,
|
||||
});
|
||||
|
||||
if (input.domains && input.domains?.length > 0) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
createApplication,
|
||||
deleteAllMiddlewares,
|
||||
findApplicationById,
|
||||
findEnvironmentById,
|
||||
findGitProviderById,
|
||||
findProjectById,
|
||||
getApplicationStats,
|
||||
@@ -23,6 +24,7 @@ import {
|
||||
unzipDrop,
|
||||
updateApplication,
|
||||
updateApplicationStatus,
|
||||
updateDeploymentStatus,
|
||||
writeConfig,
|
||||
writeConfigRemote,
|
||||
// uploadFileSchema
|
||||
@@ -39,8 +41,10 @@ import {
|
||||
import { db } from "@/server/db";
|
||||
import {
|
||||
apiCreateApplication,
|
||||
apiDeployApplication,
|
||||
apiFindMonitoringStats,
|
||||
apiFindOneApplication,
|
||||
apiRedeployApplication,
|
||||
apiReloadApplication,
|
||||
apiSaveBitbucketProvider,
|
||||
apiSaveBuildType,
|
||||
@@ -55,7 +59,7 @@ import {
|
||||
} from "@/server/db/schema";
|
||||
import type { DeploymentJob } from "@/server/queues/queue-types";
|
||||
import { cleanQueuesByApplication, myQueue } from "@/server/queues/queueSetup";
|
||||
import { deploy } from "@/server/utils/deploy";
|
||||
import { cancelDeployment, deploy } from "@/server/utils/deploy";
|
||||
import { uploadFileSchema } from "@/utils/schema";
|
||||
|
||||
export const applicationRouter = createTRPCRouter({
|
||||
@@ -63,10 +67,14 @@ export const applicationRouter = createTRPCRouter({
|
||||
.input(apiCreateApplication)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
// Get project from environment
|
||||
const environment = await findEnvironmentById(input.environmentId);
|
||||
const project = await findProjectById(environment.projectId);
|
||||
|
||||
if (ctx.user.role === "member") {
|
||||
await checkServiceAccess(
|
||||
ctx.user.id,
|
||||
input.projectId,
|
||||
project.projectId,
|
||||
ctx.session.activeOrganizationId,
|
||||
"create",
|
||||
);
|
||||
@@ -79,13 +87,13 @@ export const applicationRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
|
||||
const project = await findProjectById(input.projectId);
|
||||
if (project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this project",
|
||||
});
|
||||
}
|
||||
|
||||
const newApplication = await createApplication(input);
|
||||
|
||||
if (ctx.user.role === "member") {
|
||||
@@ -97,6 +105,7 @@ export const applicationRouter = createTRPCRouter({
|
||||
}
|
||||
return newApplication;
|
||||
} catch (error: unknown) {
|
||||
console.log("error", error);
|
||||
if (error instanceof TRPCError) {
|
||||
throw error;
|
||||
}
|
||||
@@ -120,7 +129,8 @@ export const applicationRouter = createTRPCRouter({
|
||||
}
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -175,7 +185,7 @@ export const applicationRouter = createTRPCRouter({
|
||||
|
||||
try {
|
||||
if (
|
||||
application.project.organizationId !==
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
@@ -212,7 +222,8 @@ export const applicationRouter = createTRPCRouter({
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -247,14 +258,17 @@ export const applicationRouter = createTRPCRouter({
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
return result[0];
|
||||
return application;
|
||||
}),
|
||||
|
||||
stop: protectedProcedure
|
||||
.input(apiFindOneApplication)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const service = await findApplicationById(input.applicationId);
|
||||
if (service.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
service.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to stop this application",
|
||||
@@ -274,7 +288,10 @@ export const applicationRouter = createTRPCRouter({
|
||||
.input(apiFindOneApplication)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const service = await findApplicationById(input.applicationId);
|
||||
if (service.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
service.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to start this application",
|
||||
@@ -292,11 +309,12 @@ export const applicationRouter = createTRPCRouter({
|
||||
}),
|
||||
|
||||
redeploy: protectedProcedure
|
||||
.input(apiFindOneApplication)
|
||||
.input(apiRedeployApplication)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -305,8 +323,8 @@ export const applicationRouter = createTRPCRouter({
|
||||
}
|
||||
const jobData: DeploymentJob = {
|
||||
applicationId: input.applicationId,
|
||||
titleLog: "Rebuild deployment",
|
||||
descriptionLog: "",
|
||||
titleLog: input.title || "Rebuild deployment",
|
||||
descriptionLog: input.description || "",
|
||||
type: "redeploy",
|
||||
applicationType: "application",
|
||||
server: !!application.serverId,
|
||||
@@ -331,7 +349,8 @@ export const applicationRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -341,6 +360,7 @@ export const applicationRouter = createTRPCRouter({
|
||||
await updateApplication(input.applicationId, {
|
||||
env: input.env,
|
||||
buildArgs: input.buildArgs,
|
||||
buildSecrets: input.buildSecrets,
|
||||
});
|
||||
return true;
|
||||
}),
|
||||
@@ -349,7 +369,8 @@ export const applicationRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -374,7 +395,8 @@ export const applicationRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -401,7 +423,8 @@ export const applicationRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -429,7 +452,8 @@ export const applicationRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -455,7 +479,8 @@ export const applicationRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -481,7 +506,8 @@ export const applicationRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -499,12 +525,13 @@ export const applicationRouter = createTRPCRouter({
|
||||
|
||||
return true;
|
||||
}),
|
||||
saveGitProdiver: protectedProcedure
|
||||
saveGitProvider: protectedProcedure
|
||||
.input(apiSaveGitProvider)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -529,7 +556,8 @@ export const applicationRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -590,7 +618,8 @@ export const applicationRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -604,7 +633,8 @@ export const applicationRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -630,7 +660,8 @@ export const applicationRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -643,11 +674,12 @@ export const applicationRouter = createTRPCRouter({
|
||||
return true;
|
||||
}),
|
||||
deploy: protectedProcedure
|
||||
.input(apiFindOneApplication)
|
||||
.input(apiDeployApplication)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -656,8 +688,8 @@ export const applicationRouter = createTRPCRouter({
|
||||
}
|
||||
const jobData: DeploymentJob = {
|
||||
applicationId: input.applicationId,
|
||||
titleLog: "Manual deployment",
|
||||
descriptionLog: "",
|
||||
titleLog: input.title || "Manual deployment",
|
||||
descriptionLog: input.description || "",
|
||||
type: "deploy",
|
||||
applicationType: "application",
|
||||
server: !!application.serverId,
|
||||
@@ -683,7 +715,8 @@ export const applicationRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -698,7 +731,8 @@ export const applicationRouter = createTRPCRouter({
|
||||
.query(async ({ input, ctx }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -734,7 +768,10 @@ export const applicationRouter = createTRPCRouter({
|
||||
|
||||
const app = await findApplicationById(input.applicationId as string);
|
||||
|
||||
if (app.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
app.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to deploy this application",
|
||||
@@ -777,7 +814,8 @@ export const applicationRouter = createTRPCRouter({
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -813,13 +851,14 @@ export const applicationRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
applicationId: z.string(),
|
||||
targetProjectId: z.string(),
|
||||
targetEnvironmentId: z.string(),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -827,11 +866,16 @@ export const applicationRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
|
||||
const targetProject = await findProjectById(input.targetProjectId);
|
||||
if (targetProject.organizationId !== ctx.session.activeOrganizationId) {
|
||||
const targetEnvironment = await findEnvironmentById(
|
||||
input.targetEnvironmentId,
|
||||
);
|
||||
if (
|
||||
targetEnvironment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to move to this project",
|
||||
message: "You are not authorized to move to this environment",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -839,7 +883,7 @@ export const applicationRouter = createTRPCRouter({
|
||||
const updatedApplication = await db
|
||||
.update(applications)
|
||||
.set({
|
||||
projectId: input.targetProjectId,
|
||||
environmentId: input.targetEnvironmentId,
|
||||
})
|
||||
.where(eq(applications.applicationId, input.applicationId))
|
||||
.returning()
|
||||
@@ -854,4 +898,55 @@ export const applicationRouter = createTRPCRouter({
|
||||
|
||||
return updatedApplication;
|
||||
}),
|
||||
|
||||
cancelDeployment: 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 cancel this deployment",
|
||||
});
|
||||
}
|
||||
|
||||
if (IS_CLOUD && application.serverId) {
|
||||
try {
|
||||
await updateApplicationStatus(input.applicationId, "idle");
|
||||
|
||||
if (application.deployments[0]) {
|
||||
await updateDeploymentStatus(
|
||||
application.deployments[0].deploymentId,
|
||||
"done",
|
||||
);
|
||||
}
|
||||
|
||||
await cancelDeployment({
|
||||
applicationId: input.applicationId,
|
||||
applicationType: "application",
|
||||
});
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Deployment cancellation requested",
|
||||
};
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "INTERNAL_SERVER_ERROR",
|
||||
message:
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Failed to cancel deployment",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Deployment cancellation only available in cloud version",
|
||||
});
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
} from "@dokploy/server";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
import { getPublicIpWithFallback } from "@/server/wss/terminal";
|
||||
import { getLocalServerIp } from "@/server/wss/terminal";
|
||||
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
||||
export const clusterRouter = createTRPCRouter({
|
||||
getNodes: protectedProcedure
|
||||
@@ -61,7 +61,7 @@ export const clusterRouter = createTRPCRouter({
|
||||
const result = await docker.swarmInspect();
|
||||
const docker_version = await docker.version();
|
||||
|
||||
let ip = await getPublicIpWithFallback();
|
||||
let ip = await getLocalServerIp();
|
||||
if (input.serverId) {
|
||||
const server = await findServerById(input.serverId);
|
||||
ip = server?.ipAddress;
|
||||
@@ -85,7 +85,7 @@ export const clusterRouter = createTRPCRouter({
|
||||
const result = await docker.swarmInspect();
|
||||
const docker_version = await docker.version();
|
||||
|
||||
let ip = await getPublicIpWithFallback();
|
||||
let ip = await getLocalServerIp();
|
||||
if (input.serverId) {
|
||||
const server = await findServerById(input.serverId);
|
||||
ip = server?.ipAddress;
|
||||
|
||||
@@ -3,15 +3,17 @@ import {
|
||||
addNewService,
|
||||
checkServiceAccess,
|
||||
cloneCompose,
|
||||
cloneComposeRemote,
|
||||
createCommand,
|
||||
createCompose,
|
||||
createComposeByTemplate,
|
||||
createDomain,
|
||||
createMount,
|
||||
deleteMount,
|
||||
execAsync,
|
||||
execAsyncRemote,
|
||||
findComposeById,
|
||||
findDomainsByComposeId,
|
||||
findEnvironmentById,
|
||||
findGitProviderById,
|
||||
findProjectById,
|
||||
findServerById,
|
||||
@@ -28,6 +30,7 @@ import {
|
||||
startCompose,
|
||||
stopCompose,
|
||||
updateCompose,
|
||||
updateDeploymentStatus,
|
||||
} from "@dokploy/server";
|
||||
import {
|
||||
type CompleteTemplate,
|
||||
@@ -37,25 +40,27 @@ import {
|
||||
import { processTemplate } from "@dokploy/server/templates/processors";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { dump } from "js-yaml";
|
||||
import _ from "lodash";
|
||||
import { nanoid } from "nanoid";
|
||||
import { parse } from "toml";
|
||||
import { stringify } from "yaml";
|
||||
import { z } from "zod";
|
||||
import { slugify } from "@/lib/slug";
|
||||
import { db } from "@/server/db";
|
||||
import {
|
||||
apiCreateCompose,
|
||||
apiDeleteCompose,
|
||||
apiDeployCompose,
|
||||
apiFetchServices,
|
||||
apiFindCompose,
|
||||
apiRandomizeCompose,
|
||||
apiRedeployCompose,
|
||||
apiUpdateCompose,
|
||||
compose as composeTable,
|
||||
} from "@/server/db/schema";
|
||||
import type { DeploymentJob } from "@/server/queues/queue-types";
|
||||
import { cleanQueuesByCompose, myQueue } from "@/server/queues/queueSetup";
|
||||
import { deploy } from "@/server/utils/deploy";
|
||||
import { cancelDeployment, deploy } from "@/server/utils/deploy";
|
||||
import { generatePassword } from "@/templates/utils";
|
||||
import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc";
|
||||
|
||||
@@ -64,10 +69,14 @@ export const composeRouter = createTRPCRouter({
|
||||
.input(apiCreateCompose)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
try {
|
||||
// Get project from environment
|
||||
const environment = await findEnvironmentById(input.environmentId);
|
||||
const project = await findProjectById(environment.projectId);
|
||||
|
||||
if (ctx.user.role === "member") {
|
||||
await checkServiceAccess(
|
||||
ctx.user.id,
|
||||
input.projectId,
|
||||
project.projectId,
|
||||
ctx.session.activeOrganizationId,
|
||||
"create",
|
||||
);
|
||||
@@ -79,14 +88,15 @@ export const composeRouter = createTRPCRouter({
|
||||
message: "You need to use a server to create a compose",
|
||||
});
|
||||
}
|
||||
const project = await findProjectById(input.projectId);
|
||||
if (project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this project",
|
||||
});
|
||||
}
|
||||
const newService = await createCompose(input);
|
||||
const newService = await createCompose({
|
||||
...input,
|
||||
});
|
||||
|
||||
if (ctx.user.role === "member") {
|
||||
await addNewService(
|
||||
@@ -115,7 +125,10 @@ export const composeRouter = createTRPCRouter({
|
||||
}
|
||||
|
||||
const compose = await findComposeById(input.composeId);
|
||||
if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this compose",
|
||||
@@ -166,7 +179,10 @@ export const composeRouter = createTRPCRouter({
|
||||
.input(apiUpdateCompose)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const compose = await findComposeById(input.composeId);
|
||||
if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to update this compose",
|
||||
@@ -188,7 +204,7 @@ export const composeRouter = createTRPCRouter({
|
||||
const composeResult = await findComposeById(input.composeId);
|
||||
|
||||
if (
|
||||
composeResult.project.organizationId !==
|
||||
composeResult.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
@@ -196,7 +212,6 @@ export const composeRouter = createTRPCRouter({
|
||||
message: "You are not authorized to delete this compose",
|
||||
});
|
||||
}
|
||||
4;
|
||||
|
||||
const result = await db
|
||||
.delete(composeTable)
|
||||
@@ -215,26 +230,33 @@ export const composeRouter = createTRPCRouter({
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
return result[0];
|
||||
return composeResult;
|
||||
}),
|
||||
cleanQueues: protectedProcedure
|
||||
.input(apiFindCompose)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const compose = await findComposeById(input.composeId);
|
||||
if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to clean this compose",
|
||||
});
|
||||
}
|
||||
await cleanQueuesByCompose(input.composeId);
|
||||
return { success: true, message: "Queues cleaned successfully" };
|
||||
}),
|
||||
|
||||
loadServices: protectedProcedure
|
||||
.input(apiFetchServices)
|
||||
.query(async ({ input, ctx }) => {
|
||||
const compose = await findComposeById(input.composeId);
|
||||
if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to load this compose",
|
||||
@@ -251,7 +273,10 @@ export const composeRouter = createTRPCRouter({
|
||||
)
|
||||
.query(async ({ input, ctx }) => {
|
||||
const compose = await findComposeById(input.composeId);
|
||||
if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to load this compose",
|
||||
@@ -270,17 +295,20 @@ export const composeRouter = createTRPCRouter({
|
||||
const compose = await findComposeById(input.composeId);
|
||||
|
||||
if (
|
||||
compose.project.organizationId !== ctx.session.activeOrganizationId
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to fetch this compose",
|
||||
});
|
||||
}
|
||||
|
||||
const command = await cloneCompose(compose);
|
||||
if (compose.serverId) {
|
||||
await cloneComposeRemote(compose);
|
||||
await execAsyncRemote(compose.serverId, command);
|
||||
} else {
|
||||
await cloneCompose(compose);
|
||||
await execAsync(command);
|
||||
}
|
||||
return compose.sourceType;
|
||||
} catch (err) {
|
||||
@@ -296,7 +324,10 @@ export const composeRouter = createTRPCRouter({
|
||||
.input(apiRandomizeCompose)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const compose = await findComposeById(input.composeId);
|
||||
if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to randomize this compose",
|
||||
@@ -308,7 +339,10 @@ export const composeRouter = createTRPCRouter({
|
||||
.input(apiRandomizeCompose)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const compose = await findComposeById(input.composeId);
|
||||
if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to randomize this compose",
|
||||
@@ -323,7 +357,10 @@ export const composeRouter = createTRPCRouter({
|
||||
.input(apiFindCompose)
|
||||
.query(async ({ input, ctx }) => {
|
||||
const compose = await findComposeById(input.composeId);
|
||||
if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to get this compose",
|
||||
@@ -331,17 +368,20 @@ export const composeRouter = createTRPCRouter({
|
||||
}
|
||||
const domains = await findDomainsByComposeId(input.composeId);
|
||||
const composeFile = await addDomainToCompose(compose, domains);
|
||||
return dump(composeFile, {
|
||||
return stringify(composeFile, {
|
||||
lineWidth: 1000,
|
||||
});
|
||||
}),
|
||||
|
||||
deploy: protectedProcedure
|
||||
.input(apiFindCompose)
|
||||
.input(apiDeployCompose)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const compose = await findComposeById(input.composeId);
|
||||
|
||||
if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to deploy this compose",
|
||||
@@ -349,10 +389,10 @@ export const composeRouter = createTRPCRouter({
|
||||
}
|
||||
const jobData: DeploymentJob = {
|
||||
composeId: input.composeId,
|
||||
titleLog: "Manual deployment",
|
||||
titleLog: input.title || "Manual deployment",
|
||||
type: "deploy",
|
||||
applicationType: "compose",
|
||||
descriptionLog: "",
|
||||
descriptionLog: input.description || "",
|
||||
server: !!compose.serverId,
|
||||
};
|
||||
|
||||
@@ -369,12 +409,16 @@ export const composeRouter = createTRPCRouter({
|
||||
removeOnFail: true,
|
||||
},
|
||||
);
|
||||
return { success: true, message: "Deployment queued" };
|
||||
}),
|
||||
redeploy: protectedProcedure
|
||||
.input(apiFindCompose)
|
||||
.input(apiRedeployCompose)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const compose = await findComposeById(input.composeId);
|
||||
if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to redeploy this compose",
|
||||
@@ -382,10 +426,10 @@ export const composeRouter = createTRPCRouter({
|
||||
}
|
||||
const jobData: DeploymentJob = {
|
||||
composeId: input.composeId,
|
||||
titleLog: "Rebuild deployment",
|
||||
titleLog: input.title || "Rebuild deployment",
|
||||
type: "redeploy",
|
||||
applicationType: "compose",
|
||||
descriptionLog: "",
|
||||
descriptionLog: input.description || "",
|
||||
server: !!compose.serverId,
|
||||
};
|
||||
if (IS_CLOUD && compose.serverId) {
|
||||
@@ -401,12 +445,16 @@ export const composeRouter = createTRPCRouter({
|
||||
removeOnFail: true,
|
||||
},
|
||||
);
|
||||
return { success: true, message: "Redeployment queued" };
|
||||
}),
|
||||
stop: protectedProcedure
|
||||
.input(apiFindCompose)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const compose = await findComposeById(input.composeId);
|
||||
if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to stop this compose",
|
||||
@@ -420,7 +468,10 @@ export const composeRouter = createTRPCRouter({
|
||||
.input(apiFindCompose)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const compose = await findComposeById(input.composeId);
|
||||
if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to stop this compose",
|
||||
@@ -435,7 +486,10 @@ export const composeRouter = createTRPCRouter({
|
||||
.query(async ({ input, ctx }) => {
|
||||
const compose = await findComposeById(input.composeId);
|
||||
|
||||
if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to get this compose",
|
||||
@@ -448,7 +502,10 @@ export const composeRouter = createTRPCRouter({
|
||||
.input(apiFindCompose)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const compose = await findComposeById(input.composeId);
|
||||
if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to refresh this compose",
|
||||
@@ -462,17 +519,19 @@ export const composeRouter = createTRPCRouter({
|
||||
deployTemplate: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
projectId: z.string(),
|
||||
environmentId: z.string(),
|
||||
serverId: z.string().optional(),
|
||||
id: z.string(),
|
||||
baseUrl: z.string().optional(),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const environment = await findEnvironmentById(input.environmentId);
|
||||
|
||||
if (ctx.user.role === "member") {
|
||||
await checkServiceAccess(
|
||||
ctx.user.id,
|
||||
input.projectId,
|
||||
environment.projectId,
|
||||
ctx.session.activeOrganizationId,
|
||||
"create",
|
||||
);
|
||||
@@ -490,7 +549,7 @@ export const composeRouter = createTRPCRouter({
|
||||
const admin = await findUserById(ctx.user.ownerId);
|
||||
let serverIp = admin.serverIp || "127.0.0.1";
|
||||
|
||||
const project = await findProjectById(input.projectId);
|
||||
const project = await findProjectById(environment.projectId);
|
||||
|
||||
if (input.serverId) {
|
||||
const server = await findServerById(input.serverId);
|
||||
@@ -591,7 +650,10 @@ export const composeRouter = createTRPCRouter({
|
||||
.input(apiFindCompose)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const compose = await findComposeById(input.composeId);
|
||||
if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to disconnect this git provider",
|
||||
@@ -647,30 +709,38 @@ export const composeRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
composeId: z.string(),
|
||||
targetProjectId: z.string(),
|
||||
targetEnvironmentId: z.string(),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const compose = await findComposeById(input.composeId);
|
||||
if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to move this compose",
|
||||
});
|
||||
}
|
||||
|
||||
const targetProject = await findProjectById(input.targetProjectId);
|
||||
if (targetProject.organizationId !== ctx.session.activeOrganizationId) {
|
||||
const targetEnvironment = await findEnvironmentById(
|
||||
input.targetEnvironmentId,
|
||||
);
|
||||
if (
|
||||
targetEnvironment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to move to this project",
|
||||
message: "You are not authorized to move to this environment",
|
||||
});
|
||||
}
|
||||
|
||||
const updatedCompose = await db
|
||||
.update(composeTable)
|
||||
.set({
|
||||
projectId: input.targetProjectId,
|
||||
environmentId: input.targetEnvironmentId,
|
||||
})
|
||||
.where(eq(composeTable.composeId, input.composeId))
|
||||
.returning()
|
||||
@@ -698,7 +768,8 @@ export const composeRouter = createTRPCRouter({
|
||||
const compose = await findComposeById(input.composeId);
|
||||
|
||||
if (
|
||||
compose.project.organizationId !== ctx.session.activeOrganizationId
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -769,7 +840,8 @@ export const composeRouter = createTRPCRouter({
|
||||
);
|
||||
|
||||
if (
|
||||
compose.project.organizationId !== ctx.session.activeOrganizationId
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -863,4 +935,57 @@ export const composeRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
cancelDeployment: 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 cancel this deployment",
|
||||
});
|
||||
}
|
||||
|
||||
if (IS_CLOUD && compose.serverId) {
|
||||
try {
|
||||
await updateCompose(input.composeId, {
|
||||
composeStatus: "idle",
|
||||
});
|
||||
|
||||
if (compose.deployments[0]) {
|
||||
await updateDeploymentStatus(
|
||||
compose.deployments[0].deploymentId,
|
||||
"done",
|
||||
);
|
||||
}
|
||||
|
||||
await cancelDeployment({
|
||||
composeId: input.composeId,
|
||||
applicationType: "compose",
|
||||
});
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Deployment cancellation requested",
|
||||
};
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "INTERNAL_SERVER_ERROR",
|
||||
message:
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Failed to cancel deployment",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Deployment cancellation only available in cloud version",
|
||||
});
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -29,7 +29,8 @@ export const deploymentRouter = createTRPCRouter({
|
||||
.query(async ({ input, ctx }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -43,7 +44,10 @@ export const deploymentRouter = createTRPCRouter({
|
||||
.input(apiFindAllByCompose)
|
||||
.query(async ({ input, ctx }) => {
|
||||
const compose = await findComposeById(input.composeId);
|
||||
if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this compose",
|
||||
|
||||
@@ -34,7 +34,8 @@ export const domainRouter = createTRPCRouter({
|
||||
if (input.domainType === "compose" && input.composeId) {
|
||||
const compose = await findComposeById(input.composeId);
|
||||
if (
|
||||
compose.project.organizationId !== ctx.session.activeOrganizationId
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -44,7 +45,7 @@ export const domainRouter = createTRPCRouter({
|
||||
} else if (input.domainType === "application" && input.applicationId) {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.project.organizationId !==
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
@@ -70,7 +71,8 @@ export const domainRouter = createTRPCRouter({
|
||||
.query(async ({ input, ctx }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -83,7 +85,10 @@ export const domainRouter = createTRPCRouter({
|
||||
.input(apiFindCompose)
|
||||
.query(async ({ input, ctx }) => {
|
||||
const compose = await findComposeById(input.composeId);
|
||||
if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this compose",
|
||||
@@ -122,7 +127,8 @@ export const domainRouter = createTRPCRouter({
|
||||
if (currentDomain.applicationId) {
|
||||
const newApp = await findApplicationById(currentDomain.applicationId);
|
||||
if (
|
||||
newApp.project.organizationId !== ctx.session.activeOrganizationId
|
||||
newApp.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -132,7 +138,8 @@ export const domainRouter = createTRPCRouter({
|
||||
} else if (currentDomain.composeId) {
|
||||
const newCompose = await findComposeById(currentDomain.composeId);
|
||||
if (
|
||||
newCompose.project.organizationId !== ctx.session.activeOrganizationId
|
||||
newCompose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -144,8 +151,8 @@ export const domainRouter = createTRPCRouter({
|
||||
currentDomain.previewDeploymentId,
|
||||
);
|
||||
if (
|
||||
newPreviewDeployment.application.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
newPreviewDeployment.application.environment.project
|
||||
.organizationId !== ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -175,7 +182,8 @@ export const domainRouter = createTRPCRouter({
|
||||
if (domain.applicationId) {
|
||||
const application = await findApplicationById(domain.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -184,7 +192,10 @@ export const domainRouter = createTRPCRouter({
|
||||
}
|
||||
} else if (domain.composeId) {
|
||||
const compose = await findComposeById(domain.composeId);
|
||||
if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this compose",
|
||||
@@ -200,7 +211,7 @@ export const domainRouter = createTRPCRouter({
|
||||
if (domain.applicationId) {
|
||||
const application = await findApplicationById(domain.applicationId);
|
||||
if (
|
||||
application.project.organizationId !==
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
@@ -211,7 +222,8 @@ export const domainRouter = createTRPCRouter({
|
||||
} else if (domain.composeId) {
|
||||
const compose = await findComposeById(domain.composeId);
|
||||
if (
|
||||
compose.project.organizationId !== ctx.session.activeOrganizationId
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
|
||||
349
apps/dokploy/server/api/routers/environment.ts
Normal file
349
apps/dokploy/server/api/routers/environment.ts
Normal file
@@ -0,0 +1,349 @@
|
||||
import {
|
||||
addNewEnvironment,
|
||||
checkEnvironmentAccess,
|
||||
checkEnvironmentCreationPermission,
|
||||
checkEnvironmentDeletionPermission,
|
||||
createEnvironment,
|
||||
deleteEnvironment,
|
||||
duplicateEnvironment,
|
||||
findEnvironmentById,
|
||||
findEnvironmentsByProjectId,
|
||||
findMemberById,
|
||||
updateEnvironmentById,
|
||||
} from "@dokploy/server";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||
import {
|
||||
apiCreateEnvironment,
|
||||
apiDuplicateEnvironment,
|
||||
apiFindOneEnvironment,
|
||||
apiRemoveEnvironment,
|
||||
apiUpdateEnvironment,
|
||||
} from "@/server/db/schema";
|
||||
|
||||
// Helper function to filter services within an environment based on user permissions
|
||||
const filterEnvironmentServices = (
|
||||
environment: any,
|
||||
accessedServices: string[],
|
||||
) => ({
|
||||
...environment,
|
||||
applications: environment.applications.filter((app: any) =>
|
||||
accessedServices.includes(app.applicationId),
|
||||
),
|
||||
mariadb: environment.mariadb.filter((db: any) =>
|
||||
accessedServices.includes(db.mariadbId),
|
||||
),
|
||||
mongo: environment.mongo.filter((db: any) =>
|
||||
accessedServices.includes(db.mongoId),
|
||||
),
|
||||
mysql: environment.mysql.filter((db: any) =>
|
||||
accessedServices.includes(db.mysqlId),
|
||||
),
|
||||
postgres: environment.postgres.filter((db: any) =>
|
||||
accessedServices.includes(db.postgresId),
|
||||
),
|
||||
redis: environment.redis.filter((db: any) =>
|
||||
accessedServices.includes(db.redisId),
|
||||
),
|
||||
compose: environment.compose.filter((comp: any) =>
|
||||
accessedServices.includes(comp.composeId),
|
||||
),
|
||||
});
|
||||
|
||||
export const environmentRouter = createTRPCRouter({
|
||||
create: protectedProcedure
|
||||
.input(apiCreateEnvironment)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
// Check if user has permission to create environments
|
||||
await checkEnvironmentCreationPermission(
|
||||
ctx.user.id,
|
||||
input.projectId,
|
||||
ctx.session.activeOrganizationId,
|
||||
);
|
||||
|
||||
if (input.name === "production") {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Environment name cannot be production",
|
||||
});
|
||||
}
|
||||
|
||||
const environment = await createEnvironment(input);
|
||||
|
||||
if (ctx.user.role === "member") {
|
||||
await addNewEnvironment(
|
||||
ctx.user.id,
|
||||
environment.environmentId,
|
||||
ctx.session.activeOrganizationId,
|
||||
);
|
||||
}
|
||||
return environment;
|
||||
} catch (error) {
|
||||
if (error instanceof TRPCError) {
|
||||
throw error;
|
||||
}
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: `Error creating the environment: ${error instanceof Error ? error.message : error}`,
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
one: protectedProcedure
|
||||
.input(apiFindOneEnvironment)
|
||||
.query(async ({ input, ctx }) => {
|
||||
try {
|
||||
if (ctx.user.role === "member") {
|
||||
await checkEnvironmentAccess(
|
||||
ctx.user.id,
|
||||
input.environmentId,
|
||||
ctx.session.activeOrganizationId,
|
||||
"access",
|
||||
);
|
||||
}
|
||||
const environment = await findEnvironmentById(input.environmentId);
|
||||
if (
|
||||
environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "FORBIDDEN",
|
||||
message: "You are not allowed to access this environment",
|
||||
});
|
||||
}
|
||||
|
||||
// Check environment access and filter services for members
|
||||
if (ctx.user.role === "member") {
|
||||
const { accessedEnvironments, accessedServices } =
|
||||
await findMemberById(ctx.user.id, ctx.session.activeOrganizationId);
|
||||
|
||||
if (!accessedEnvironments.includes(environment.environmentId)) {
|
||||
throw new TRPCError({
|
||||
code: "FORBIDDEN",
|
||||
message: "You are not allowed to access this environment",
|
||||
});
|
||||
}
|
||||
|
||||
// Filter services based on member permissions
|
||||
const filteredEnvironment = filterEnvironmentServices(
|
||||
environment,
|
||||
accessedServices,
|
||||
);
|
||||
|
||||
return filteredEnvironment;
|
||||
}
|
||||
|
||||
return environment;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "NOT_FOUND",
|
||||
message: "Environment not found",
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
byProjectId: protectedProcedure
|
||||
.input(z.object({ projectId: z.string() }))
|
||||
.query(async ({ input, ctx }) => {
|
||||
try {
|
||||
const environments = await findEnvironmentsByProjectId(input.projectId);
|
||||
|
||||
// Check organization access
|
||||
if (
|
||||
environments.some(
|
||||
(environment) =>
|
||||
environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId,
|
||||
)
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "FORBIDDEN",
|
||||
message: "You are not allowed to access this environment",
|
||||
});
|
||||
}
|
||||
|
||||
// Filter environments for members based on their permissions
|
||||
if (ctx.user.role === "member") {
|
||||
const { accessedEnvironments, accessedServices } =
|
||||
await findMemberById(ctx.user.id, ctx.session.activeOrganizationId);
|
||||
|
||||
// Filter environments to only show those the member has access to
|
||||
const filteredEnvironments = environments
|
||||
.filter((environment) =>
|
||||
accessedEnvironments.includes(environment.environmentId),
|
||||
)
|
||||
.map((environment) =>
|
||||
filterEnvironmentServices(environment, accessedServices),
|
||||
);
|
||||
|
||||
return filteredEnvironments;
|
||||
}
|
||||
|
||||
return environments;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: `Error fetching environments: ${error instanceof Error ? error.message : error}`,
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
remove: protectedProcedure
|
||||
.input(apiRemoveEnvironment)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
const environment = await findEnvironmentById(input.environmentId);
|
||||
if (
|
||||
environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "FORBIDDEN",
|
||||
message: "You are not allowed to access this environment",
|
||||
});
|
||||
}
|
||||
|
||||
// Check environment deletion permission
|
||||
await checkEnvironmentDeletionPermission(
|
||||
ctx.user.id,
|
||||
environment.projectId,
|
||||
ctx.session.activeOrganizationId,
|
||||
);
|
||||
|
||||
// Additional check for environment access for members
|
||||
if (ctx.user.role === "member") {
|
||||
await checkEnvironmentAccess(
|
||||
ctx.user.id,
|
||||
input.environmentId,
|
||||
ctx.session.activeOrganizationId,
|
||||
"access",
|
||||
);
|
||||
}
|
||||
|
||||
const deletedEnvironment = await deleteEnvironment(input.environmentId);
|
||||
return deletedEnvironment;
|
||||
} catch (error) {
|
||||
if (error instanceof TRPCError) {
|
||||
throw error;
|
||||
}
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: `Error deleting the environment: ${error instanceof Error ? error.message : error}`,
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
update: protectedProcedure
|
||||
.input(apiUpdateEnvironment)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
const { environmentId, ...updateData } = input;
|
||||
|
||||
if (updateData.name === "production") {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Environment name cannot be production",
|
||||
});
|
||||
}
|
||||
|
||||
if (ctx.user.role === "member") {
|
||||
await checkEnvironmentAccess(
|
||||
ctx.user.id,
|
||||
environmentId,
|
||||
ctx.session.activeOrganizationId,
|
||||
"access",
|
||||
);
|
||||
}
|
||||
const currentEnvironment = await findEnvironmentById(environmentId);
|
||||
if (
|
||||
currentEnvironment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "FORBIDDEN",
|
||||
message: "You are not allowed to access this environment",
|
||||
});
|
||||
}
|
||||
|
||||
// Check environment access for members
|
||||
if (ctx.user.role === "member") {
|
||||
const { accessedEnvironments } = await findMemberById(
|
||||
ctx.user.id,
|
||||
ctx.session.activeOrganizationId,
|
||||
);
|
||||
|
||||
if (
|
||||
!accessedEnvironments.includes(currentEnvironment.environmentId)
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "FORBIDDEN",
|
||||
message: "You are not allowed to update this environment",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const environment = await updateEnvironmentById(
|
||||
environmentId,
|
||||
updateData,
|
||||
);
|
||||
return environment;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: `Error updating the environment: ${error instanceof Error ? error.message : error}`,
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
duplicate: protectedProcedure
|
||||
.input(apiDuplicateEnvironment)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
if (ctx.user.role === "member") {
|
||||
await checkEnvironmentAccess(
|
||||
ctx.user.id,
|
||||
input.environmentId,
|
||||
ctx.session.activeOrganizationId,
|
||||
"access",
|
||||
);
|
||||
}
|
||||
const environment = await findEnvironmentById(input.environmentId);
|
||||
if (
|
||||
environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "FORBIDDEN",
|
||||
message: "You are not allowed to access this environment",
|
||||
});
|
||||
}
|
||||
|
||||
// Check environment access for members
|
||||
if (ctx.user.role === "member") {
|
||||
const { accessedEnvironments } = await findMemberById(
|
||||
ctx.user.id,
|
||||
ctx.session.activeOrganizationId,
|
||||
);
|
||||
|
||||
if (!accessedEnvironments.includes(environment.environmentId)) {
|
||||
throw new TRPCError({
|
||||
code: "FORBIDDEN",
|
||||
message: "You are not allowed to duplicate this environment",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const duplicatedEnvironment = await duplicateEnvironment(input);
|
||||
return duplicatedEnvironment;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: `Error duplicating the environment: ${error instanceof Error ? error.message : error}`,
|
||||
});
|
||||
}
|
||||
}),
|
||||
});
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
getGithubBranches,
|
||||
getGithubRepositories,
|
||||
haveGithubRequirements,
|
||||
updateGithub,
|
||||
updateGitProvider,
|
||||
} from "@dokploy/server";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
@@ -134,5 +135,9 @@ export const githubRouter = createTRPCRouter({
|
||||
name: input.name,
|
||||
organizationId: ctx.session.activeOrganizationId,
|
||||
});
|
||||
|
||||
await updateGithub(input.githubId, {
|
||||
...input,
|
||||
});
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
deployMariadb,
|
||||
findBackupsByDbId,
|
||||
findMariadbById,
|
||||
findEnvironmentById,
|
||||
findProjectById,
|
||||
IS_CLOUD,
|
||||
rebuildDatabase,
|
||||
@@ -41,10 +42,14 @@ export const mariadbRouter = createTRPCRouter({
|
||||
.input(apiCreateMariaDB)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
// Get project from environment
|
||||
const environment = await findEnvironmentById(input.environmentId);
|
||||
const project = await findProjectById(environment.projectId);
|
||||
|
||||
if (ctx.user.role === "member") {
|
||||
await checkServiceAccess(
|
||||
ctx.user.id,
|
||||
input.projectId,
|
||||
project.projectId,
|
||||
ctx.session.activeOrganizationId,
|
||||
"create",
|
||||
);
|
||||
@@ -57,14 +62,15 @@ export const mariadbRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
|
||||
const project = await findProjectById(input.projectId);
|
||||
if (project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this project",
|
||||
});
|
||||
}
|
||||
const newMariadb = await createMariadb(input);
|
||||
const newMariadb = await createMariadb({
|
||||
...input,
|
||||
});
|
||||
if (ctx.user.role === "member") {
|
||||
await addNewService(
|
||||
ctx.user.id,
|
||||
@@ -101,7 +107,10 @@ export const mariadbRouter = createTRPCRouter({
|
||||
);
|
||||
}
|
||||
const mariadb = await findMariadbById(input.mariadbId);
|
||||
if (mariadb.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mariadb.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this Mariadb",
|
||||
@@ -114,7 +123,10 @@ export const mariadbRouter = createTRPCRouter({
|
||||
.input(apiFindOneMariaDB)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const service = await findMariadbById(input.mariadbId);
|
||||
if (service.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
service.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to start this Mariadb",
|
||||
@@ -151,7 +163,10 @@ export const mariadbRouter = createTRPCRouter({
|
||||
.input(apiSaveExternalPortMariaDB)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const mongo = await findMariadbById(input.mariadbId);
|
||||
if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mongo.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to save this external port",
|
||||
@@ -167,7 +182,10 @@ export const mariadbRouter = createTRPCRouter({
|
||||
.input(apiDeployMariaDB)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const mariadb = await findMariadbById(input.mariadbId);
|
||||
if (mariadb.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mariadb.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to deploy this Mariadb",
|
||||
@@ -188,7 +206,10 @@ export const mariadbRouter = createTRPCRouter({
|
||||
.input(apiDeployMariaDB)
|
||||
.subscription(async ({ input, ctx }) => {
|
||||
const mariadb = await findMariadbById(input.mariadbId);
|
||||
if (mariadb.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mariadb.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to deploy this Mariadb",
|
||||
@@ -205,7 +226,10 @@ export const mariadbRouter = createTRPCRouter({
|
||||
.input(apiChangeMariaDBStatus)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const mongo = await findMariadbById(input.mariadbId);
|
||||
if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mongo.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to change this Mariadb status",
|
||||
@@ -229,7 +253,10 @@ export const mariadbRouter = createTRPCRouter({
|
||||
}
|
||||
|
||||
const mongo = await findMariadbById(input.mariadbId);
|
||||
if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mongo.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to delete this Mariadb",
|
||||
@@ -255,7 +282,10 @@ export const mariadbRouter = createTRPCRouter({
|
||||
.input(apiSaveEnvironmentVariablesMariaDB)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const mariadb = await findMariadbById(input.mariadbId);
|
||||
if (mariadb.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mariadb.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to save this environment",
|
||||
@@ -278,7 +308,10 @@ export const mariadbRouter = createTRPCRouter({
|
||||
.input(apiResetMariadb)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const mariadb = await findMariadbById(input.mariadbId);
|
||||
if (mariadb.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mariadb.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to reload this Mariadb",
|
||||
@@ -308,7 +341,10 @@ export const mariadbRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const { mariadbId, ...rest } = input;
|
||||
const mariadb = await findMariadbById(mariadbId);
|
||||
if (mariadb.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mariadb.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to update this Mariadb",
|
||||
@@ -331,23 +367,31 @@ export const mariadbRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
mariadbId: z.string(),
|
||||
targetProjectId: z.string(),
|
||||
targetEnvironmentId: z.string(),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const mariadb = await findMariadbById(input.mariadbId);
|
||||
if (mariadb.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mariadb.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to move this mariadb",
|
||||
});
|
||||
}
|
||||
|
||||
const targetProject = await findProjectById(input.targetProjectId);
|
||||
if (targetProject.organizationId !== ctx.session.activeOrganizationId) {
|
||||
const targetEnvironment = await findEnvironmentById(
|
||||
input.targetEnvironmentId,
|
||||
);
|
||||
if (
|
||||
targetEnvironment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to move to this project",
|
||||
message: "You are not authorized to move to this environment",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -355,7 +399,7 @@ export const mariadbRouter = createTRPCRouter({
|
||||
const updatedMariadb = await db
|
||||
.update(mariadbTable)
|
||||
.set({
|
||||
projectId: input.targetProjectId,
|
||||
environmentId: input.targetEnvironmentId,
|
||||
})
|
||||
.where(eq(mariadbTable.mariadbId, input.mariadbId))
|
||||
.returning()
|
||||
@@ -374,7 +418,10 @@ export const mariadbRouter = createTRPCRouter({
|
||||
.input(apiRebuildMariadb)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const mariadb = await findMariadbById(input.mariadbId);
|
||||
if (mariadb.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mariadb.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to rebuild this MariaDB database",
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
deployMongo,
|
||||
findBackupsByDbId,
|
||||
findMongoById,
|
||||
findEnvironmentById,
|
||||
findProjectById,
|
||||
IS_CLOUD,
|
||||
rebuildDatabase,
|
||||
@@ -41,10 +42,14 @@ export const mongoRouter = createTRPCRouter({
|
||||
.input(apiCreateMongo)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
// Get project from environment
|
||||
const environment = await findEnvironmentById(input.environmentId);
|
||||
const project = await findProjectById(environment.projectId);
|
||||
|
||||
if (ctx.user.role === "member") {
|
||||
await checkServiceAccess(
|
||||
ctx.user.id,
|
||||
input.projectId,
|
||||
project.projectId,
|
||||
ctx.session.activeOrganizationId,
|
||||
"create",
|
||||
);
|
||||
@@ -57,14 +62,15 @@ export const mongoRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
|
||||
const project = await findProjectById(input.projectId);
|
||||
if (project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this project",
|
||||
});
|
||||
}
|
||||
const newMongo = await createMongo(input);
|
||||
const newMongo = await createMongo({
|
||||
...input,
|
||||
});
|
||||
if (ctx.user.role === "member") {
|
||||
await addNewService(
|
||||
ctx.user.id,
|
||||
@@ -106,7 +112,10 @@ export const mongoRouter = createTRPCRouter({
|
||||
}
|
||||
|
||||
const mongo = await findMongoById(input.mongoId);
|
||||
if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mongo.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this mongo",
|
||||
@@ -120,7 +129,10 @@ export const mongoRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const service = await findMongoById(input.mongoId);
|
||||
|
||||
if (service.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
service.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to start this mongo",
|
||||
@@ -143,7 +155,10 @@ export const mongoRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const mongo = await findMongoById(input.mongoId);
|
||||
|
||||
if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mongo.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to stop this mongo",
|
||||
@@ -165,7 +180,10 @@ export const mongoRouter = createTRPCRouter({
|
||||
.input(apiSaveExternalPortMongo)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const mongo = await findMongoById(input.mongoId);
|
||||
if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mongo.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to save this external port",
|
||||
@@ -181,7 +199,10 @@ export const mongoRouter = createTRPCRouter({
|
||||
.input(apiDeployMongo)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const mongo = await findMongoById(input.mongoId);
|
||||
if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mongo.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to deploy this mongo",
|
||||
@@ -201,7 +222,10 @@ export const mongoRouter = createTRPCRouter({
|
||||
.input(apiDeployMongo)
|
||||
.subscription(async ({ input, ctx }) => {
|
||||
const mongo = await findMongoById(input.mongoId);
|
||||
if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mongo.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to deploy this mongo",
|
||||
@@ -218,7 +242,10 @@ export const mongoRouter = createTRPCRouter({
|
||||
.input(apiChangeMongoStatus)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const mongo = await findMongoById(input.mongoId);
|
||||
if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mongo.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to change this mongo status",
|
||||
@@ -233,7 +260,10 @@ export const mongoRouter = createTRPCRouter({
|
||||
.input(apiResetMongo)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const mongo = await findMongoById(input.mongoId);
|
||||
if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mongo.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to reload this mongo",
|
||||
@@ -272,7 +302,10 @@ export const mongoRouter = createTRPCRouter({
|
||||
|
||||
const mongo = await findMongoById(input.mongoId);
|
||||
|
||||
if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mongo.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to delete this mongo",
|
||||
@@ -298,7 +331,10 @@ export const mongoRouter = createTRPCRouter({
|
||||
.input(apiSaveEnvironmentVariablesMongo)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const mongo = await findMongoById(input.mongoId);
|
||||
if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mongo.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to save this environment",
|
||||
@@ -322,7 +358,10 @@ export const mongoRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const { mongoId, ...rest } = input;
|
||||
const mongo = await findMongoById(mongoId);
|
||||
if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mongo.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to update this mongo",
|
||||
@@ -345,23 +384,31 @@ export const mongoRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
mongoId: z.string(),
|
||||
targetProjectId: z.string(),
|
||||
targetEnvironmentId: z.string(),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const mongo = await findMongoById(input.mongoId);
|
||||
if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mongo.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to move this mongo",
|
||||
});
|
||||
}
|
||||
|
||||
const targetProject = await findProjectById(input.targetProjectId);
|
||||
if (targetProject.organizationId !== ctx.session.activeOrganizationId) {
|
||||
const targetEnvironment = await findEnvironmentById(
|
||||
input.targetEnvironmentId,
|
||||
);
|
||||
if (
|
||||
targetEnvironment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to move to this project",
|
||||
message: "You are not authorized to move to this environment",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -369,7 +416,7 @@ export const mongoRouter = createTRPCRouter({
|
||||
const updatedMongo = await db
|
||||
.update(mongoTable)
|
||||
.set({
|
||||
projectId: input.targetProjectId,
|
||||
environmentId: input.targetEnvironmentId,
|
||||
})
|
||||
.where(eq(mongoTable.mongoId, input.mongoId))
|
||||
.returning()
|
||||
@@ -388,7 +435,10 @@ export const mongoRouter = createTRPCRouter({
|
||||
.input(apiRebuildMongo)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const mongo = await findMongoById(input.mongoId);
|
||||
if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mongo.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to rebuild this MongoDB database",
|
||||
|
||||
@@ -3,9 +3,11 @@ import {
|
||||
deleteMount,
|
||||
findApplicationById,
|
||||
findMountById,
|
||||
findMountOrganizationId,
|
||||
getServiceContainer,
|
||||
updateMount,
|
||||
} from "@dokploy/server";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
apiCreateMount,
|
||||
@@ -24,16 +26,39 @@ export const mountRouter = createTRPCRouter({
|
||||
}),
|
||||
remove: protectedProcedure
|
||||
.input(apiRemoveMount)
|
||||
.mutation(async ({ input }) => {
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const organizationId = await findMountOrganizationId(input.mountId);
|
||||
if (organizationId !== ctx.session.activeOrganizationId) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to delete this mount",
|
||||
});
|
||||
}
|
||||
return await deleteMount(input.mountId);
|
||||
}),
|
||||
|
||||
one: protectedProcedure.input(apiFindOneMount).query(async ({ input }) => {
|
||||
return await findMountById(input.mountId);
|
||||
}),
|
||||
one: protectedProcedure
|
||||
.input(apiFindOneMount)
|
||||
.query(async ({ input, ctx }) => {
|
||||
const organizationId = await findMountOrganizationId(input.mountId);
|
||||
if (organizationId !== ctx.session.activeOrganizationId) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this mount",
|
||||
});
|
||||
}
|
||||
return await findMountById(input.mountId);
|
||||
}),
|
||||
update: protectedProcedure
|
||||
.input(apiUpdateMount)
|
||||
.mutation(async ({ input }) => {
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const organizationId = await findMountOrganizationId(input.mountId);
|
||||
if (organizationId !== ctx.session.activeOrganizationId) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to update this mount",
|
||||
});
|
||||
}
|
||||
return await updateMount(input.mountId, input);
|
||||
}),
|
||||
allNamedByApplicationId: protectedProcedure
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
createMysql,
|
||||
deployMySql,
|
||||
findBackupsByDbId,
|
||||
findEnvironmentById,
|
||||
findMySqlById,
|
||||
findProjectById,
|
||||
IS_CLOUD,
|
||||
@@ -42,10 +43,14 @@ export const mysqlRouter = createTRPCRouter({
|
||||
.input(apiCreateMySql)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
// Get project from environment
|
||||
const environment = await findEnvironmentById(input.environmentId);
|
||||
const project = await findProjectById(environment.projectId);
|
||||
|
||||
if (ctx.user.role === "member") {
|
||||
await checkServiceAccess(
|
||||
ctx.user.id,
|
||||
input.projectId,
|
||||
project.projectId,
|
||||
ctx.session.activeOrganizationId,
|
||||
"create",
|
||||
);
|
||||
@@ -57,8 +62,7 @@ export const mysqlRouter = createTRPCRouter({
|
||||
message: "You need to use a server to create a MySQL",
|
||||
});
|
||||
}
|
||||
1;
|
||||
const project = await findProjectById(input.projectId);
|
||||
|
||||
if (project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -66,7 +70,9 @@ export const mysqlRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
|
||||
const newMysql = await createMysql(input);
|
||||
const newMysql = await createMysql({
|
||||
...input,
|
||||
});
|
||||
if (ctx.user.role === "member") {
|
||||
await addNewService(
|
||||
ctx.user.id,
|
||||
@@ -107,7 +113,10 @@ export const mysqlRouter = createTRPCRouter({
|
||||
);
|
||||
}
|
||||
const mysql = await findMySqlById(input.mysqlId);
|
||||
if (mysql.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mysql.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this MySQL",
|
||||
@@ -120,7 +129,10 @@ export const mysqlRouter = createTRPCRouter({
|
||||
.input(apiFindOneMySql)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const service = await findMySqlById(input.mysqlId);
|
||||
if (service.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
service.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to start this MySQL",
|
||||
@@ -142,7 +154,10 @@ export const mysqlRouter = createTRPCRouter({
|
||||
.input(apiFindOneMySql)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const mongo = await findMySqlById(input.mysqlId);
|
||||
if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mongo.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to stop this MySQL",
|
||||
@@ -163,7 +178,10 @@ export const mysqlRouter = createTRPCRouter({
|
||||
.input(apiSaveExternalPortMySql)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const mongo = await findMySqlById(input.mysqlId);
|
||||
if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mongo.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to save this external port",
|
||||
@@ -179,7 +197,10 @@ export const mysqlRouter = createTRPCRouter({
|
||||
.input(apiDeployMySql)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const mysql = await findMySqlById(input.mysqlId);
|
||||
if (mysql.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mysql.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to deploy this MySQL",
|
||||
@@ -199,7 +220,10 @@ export const mysqlRouter = createTRPCRouter({
|
||||
.input(apiDeployMySql)
|
||||
.subscription(async ({ input, ctx }) => {
|
||||
const mysql = await findMySqlById(input.mysqlId);
|
||||
if (mysql.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mysql.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to deploy this MySQL",
|
||||
@@ -216,7 +240,10 @@ export const mysqlRouter = createTRPCRouter({
|
||||
.input(apiChangeMySqlStatus)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const mongo = await findMySqlById(input.mysqlId);
|
||||
if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mongo.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to change this MySQL status",
|
||||
@@ -231,7 +258,10 @@ export const mysqlRouter = createTRPCRouter({
|
||||
.input(apiResetMysql)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const mysql = await findMySqlById(input.mysqlId);
|
||||
if (mysql.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mysql.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to reload this MySQL",
|
||||
@@ -267,7 +297,10 @@ export const mysqlRouter = createTRPCRouter({
|
||||
);
|
||||
}
|
||||
const mongo = await findMySqlById(input.mysqlId);
|
||||
if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mongo.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to delete this MySQL",
|
||||
@@ -293,7 +326,10 @@ export const mysqlRouter = createTRPCRouter({
|
||||
.input(apiSaveEnvironmentVariablesMySql)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const mysql = await findMySqlById(input.mysqlId);
|
||||
if (mysql.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mysql.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to save this environment",
|
||||
@@ -317,7 +353,10 @@ export const mysqlRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const { mysqlId, ...rest } = input;
|
||||
const mysql = await findMySqlById(mysqlId);
|
||||
if (mysql.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mysql.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to update this MySQL",
|
||||
@@ -340,23 +379,31 @@ export const mysqlRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
mysqlId: z.string(),
|
||||
targetProjectId: z.string(),
|
||||
targetEnvironmentId: z.string(),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const mysql = await findMySqlById(input.mysqlId);
|
||||
if (mysql.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mysql.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to move this mysql",
|
||||
});
|
||||
}
|
||||
|
||||
const targetProject = await findProjectById(input.targetProjectId);
|
||||
if (targetProject.organizationId !== ctx.session.activeOrganizationId) {
|
||||
const targetEnvironment = await findEnvironmentById(
|
||||
input.targetEnvironmentId,
|
||||
);
|
||||
if (
|
||||
targetEnvironment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to move to this project",
|
||||
message: "You are not authorized to move to this environment",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -364,7 +411,7 @@ export const mysqlRouter = createTRPCRouter({
|
||||
const updatedMysql = await db
|
||||
.update(mysqlTable)
|
||||
.set({
|
||||
projectId: input.targetProjectId,
|
||||
environmentId: input.targetEnvironmentId,
|
||||
})
|
||||
.where(eq(mysqlTable.mysqlId, input.mysqlId))
|
||||
.returning()
|
||||
@@ -383,7 +430,10 @@ export const mysqlRouter = createTRPCRouter({
|
||||
.input(apiRebuildMysql)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const mysql = await findMySqlById(input.mysqlId);
|
||||
if (mysql.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mysql.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to rebuild this MySQL database",
|
||||
|
||||
@@ -2,6 +2,8 @@ import {
|
||||
createDiscordNotification,
|
||||
createEmailNotification,
|
||||
createGotifyNotification,
|
||||
createLarkNotification,
|
||||
createNtfyNotification,
|
||||
createSlackNotification,
|
||||
createTelegramNotification,
|
||||
findNotificationById,
|
||||
@@ -10,12 +12,16 @@ import {
|
||||
sendDiscordNotification,
|
||||
sendEmailNotification,
|
||||
sendGotifyNotification,
|
||||
sendLarkNotification,
|
||||
sendNtfyNotification,
|
||||
sendServerThresholdNotifications,
|
||||
sendSlackNotification,
|
||||
sendTelegramNotification,
|
||||
updateDiscordNotification,
|
||||
updateEmailNotification,
|
||||
updateGotifyNotification,
|
||||
updateLarkNotification,
|
||||
updateNtfyNotification,
|
||||
updateSlackNotification,
|
||||
updateTelegramNotification,
|
||||
} from "@dokploy/server";
|
||||
@@ -33,22 +39,28 @@ import {
|
||||
apiCreateDiscord,
|
||||
apiCreateEmail,
|
||||
apiCreateGotify,
|
||||
apiCreateLark,
|
||||
apiCreateNtfy,
|
||||
apiCreateSlack,
|
||||
apiCreateTelegram,
|
||||
apiFindOneNotification,
|
||||
apiTestDiscordConnection,
|
||||
apiTestEmailConnection,
|
||||
apiTestGotifyConnection,
|
||||
apiTestLarkConnection,
|
||||
apiTestNtfyConnection,
|
||||
apiTestSlackConnection,
|
||||
apiTestTelegramConnection,
|
||||
apiUpdateDiscord,
|
||||
apiUpdateEmail,
|
||||
apiUpdateGotify,
|
||||
apiUpdateLark,
|
||||
apiUpdateNtfy,
|
||||
apiUpdateSlack,
|
||||
apiUpdateTelegram,
|
||||
notifications,
|
||||
server,
|
||||
users_temp,
|
||||
user,
|
||||
} from "@/server/db/schema";
|
||||
|
||||
export const notificationRouter = createTRPCRouter({
|
||||
@@ -321,6 +333,8 @@ export const notificationRouter = createTRPCRouter({
|
||||
discord: true,
|
||||
email: true,
|
||||
gotify: true,
|
||||
ntfy: true,
|
||||
lark: true,
|
||||
},
|
||||
orderBy: desc(notifications.createdAt),
|
||||
where: eq(notifications.organizationId, ctx.session.activeOrganizationId),
|
||||
@@ -345,9 +359,9 @@ export const notificationRouter = createTRPCRouter({
|
||||
if (input.ServerType === "Dokploy") {
|
||||
const result = await db
|
||||
.select()
|
||||
.from(users_temp)
|
||||
.from(user)
|
||||
.where(
|
||||
sql`${users_temp.metricsConfig}::jsonb -> 'server' ->> 'token' = ${input.Token}`,
|
||||
sql`${user.metricsConfig}::jsonb -> 'server' ->> 'token' = ${input.Token}`,
|
||||
);
|
||||
|
||||
if (!result?.[0]?.id) {
|
||||
@@ -446,6 +460,121 @@ export const notificationRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
}),
|
||||
createNtfy: adminProcedure
|
||||
.input(apiCreateNtfy)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
return await createNtfyNotification(
|
||||
input,
|
||||
ctx.session.activeOrganizationId,
|
||||
);
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error creating the notification",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
updateNtfy: adminProcedure
|
||||
.input(apiUpdateNtfy)
|
||||
.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 updateNtfyNotification({
|
||||
...input,
|
||||
organizationId: ctx.session.activeOrganizationId,
|
||||
});
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}),
|
||||
testNtfyConnection: adminProcedure
|
||||
.input(apiTestNtfyConnection)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
await sendNtfyNotification(
|
||||
input,
|
||||
"Test Notification",
|
||||
"",
|
||||
"view, visit Dokploy on Github, https://github.com/dokploy/dokploy, clear=true;",
|
||||
"Hi, From Dokploy 👋",
|
||||
);
|
||||
return true;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error testing the notification",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
createLark: adminProcedure
|
||||
.input(apiCreateLark)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
return await createLarkNotification(
|
||||
input,
|
||||
ctx.session.activeOrganizationId,
|
||||
);
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error creating the notification",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
updateLark: adminProcedure
|
||||
.input(apiUpdateLark)
|
||||
.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 updateLarkNotification({
|
||||
...input,
|
||||
organizationId: ctx.session.activeOrganizationId,
|
||||
});
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}),
|
||||
testLarkConnection: adminProcedure
|
||||
.input(apiTestLarkConnection)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
await sendLarkNotification(input, {
|
||||
msg_type: "text",
|
||||
content: {
|
||||
text: "Hi, From Dokploy 👋",
|
||||
},
|
||||
});
|
||||
return true;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error testing the notification",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
getEmailProviders: adminProcedure.query(async ({ ctx }) => {
|
||||
return await db.query.notifications.findMany({
|
||||
where: eq(notifications.organizationId, ctx.session.activeOrganizationId),
|
||||
|
||||
@@ -41,6 +41,11 @@ export const organizationRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
|
||||
// Check if this is the user's first organization
|
||||
const existingMemberships = await db.query.member.findMany({
|
||||
where: eq(member.userId, ctx.user.id),
|
||||
});
|
||||
|
||||
await db.insert(member).values({
|
||||
organizationId: result.id,
|
||||
role: "owner",
|
||||
@@ -63,6 +68,11 @@ export const organizationRouter = createTRPCRouter({
|
||||
),
|
||||
),
|
||||
),
|
||||
with: {
|
||||
members: {
|
||||
where: eq(member.userId, ctx.user.id),
|
||||
},
|
||||
},
|
||||
});
|
||||
return memberResult;
|
||||
}),
|
||||
@@ -224,4 +234,45 @@ export const organizationRouter = createTRPCRouter({
|
||||
await db.delete(member).where(eq(member.id, input.memberId));
|
||||
return true;
|
||||
}),
|
||||
setDefault: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
organizationId: z.string().min(1),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
// Verify user is a member of this organization
|
||||
const userMember = await db.query.member.findFirst({
|
||||
where: and(
|
||||
eq(member.organizationId, input.organizationId),
|
||||
eq(member.userId, ctx.user.id),
|
||||
),
|
||||
});
|
||||
|
||||
if (!userMember) {
|
||||
throw new TRPCError({
|
||||
code: "FORBIDDEN",
|
||||
message: "You are not a member of this organization",
|
||||
});
|
||||
}
|
||||
|
||||
// First, unset all defaults for this user
|
||||
await db
|
||||
.update(member)
|
||||
.set({ isDefault: false })
|
||||
.where(eq(member.userId, ctx.user.id));
|
||||
|
||||
// Then set this organization as default
|
||||
await db
|
||||
.update(member)
|
||||
.set({ isDefault: true })
|
||||
.where(
|
||||
and(
|
||||
eq(member.organizationId, input.organizationId),
|
||||
eq(member.userId, ctx.user.id),
|
||||
),
|
||||
);
|
||||
|
||||
return { success: true };
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -27,22 +27,44 @@ export const portRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
}),
|
||||
one: protectedProcedure.input(apiFindOnePort).query(async ({ input }) => {
|
||||
try {
|
||||
return await finPortById(input.portId);
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Port not found",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
one: protectedProcedure
|
||||
.input(apiFindOnePort)
|
||||
.query(async ({ input, ctx }) => {
|
||||
try {
|
||||
const port = await finPortById(input.portId);
|
||||
if (
|
||||
port.application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this port",
|
||||
});
|
||||
}
|
||||
return port;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Port not found",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
delete: protectedProcedure
|
||||
.input(apiFindOnePort)
|
||||
.mutation(async ({ input }) => {
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const port = await finPortById(input.portId);
|
||||
if (
|
||||
port.application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to delete this port",
|
||||
});
|
||||
}
|
||||
try {
|
||||
return removePortById(input.portId);
|
||||
return await removePortById(input.portId);
|
||||
} catch (error) {
|
||||
const message =
|
||||
error instanceof Error ? error.message : "Error input: Deleting port";
|
||||
@@ -54,9 +76,19 @@ export const portRouter = createTRPCRouter({
|
||||
}),
|
||||
update: protectedProcedure
|
||||
.input(apiUpdatePort)
|
||||
.mutation(async ({ input }) => {
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const port = await finPortById(input.portId);
|
||||
if (
|
||||
port.application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to update this port",
|
||||
});
|
||||
}
|
||||
try {
|
||||
return updatePortById(input.portId, input);
|
||||
return await updatePortById(input.portId, input);
|
||||
} catch (error) {
|
||||
const message =
|
||||
error instanceof Error ? error.message : "Error updating the port";
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
createPostgres,
|
||||
deployPostgres,
|
||||
findBackupsByDbId,
|
||||
findEnvironmentById,
|
||||
findPostgresById,
|
||||
findProjectById,
|
||||
IS_CLOUD,
|
||||
@@ -41,10 +42,14 @@ export const postgresRouter = createTRPCRouter({
|
||||
.input(apiCreatePostgres)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
// Get project from environment
|
||||
const environment = await findEnvironmentById(input.environmentId);
|
||||
const project = await findProjectById(environment.projectId);
|
||||
|
||||
if (ctx.user.role === "member") {
|
||||
await checkServiceAccess(
|
||||
ctx.user.id,
|
||||
input.projectId,
|
||||
project.projectId,
|
||||
ctx.session.activeOrganizationId,
|
||||
"create",
|
||||
);
|
||||
@@ -57,14 +62,15 @@ export const postgresRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
|
||||
const project = await findProjectById(input.projectId);
|
||||
if (project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this project",
|
||||
});
|
||||
}
|
||||
const newPostgres = await createPostgres(input);
|
||||
const newPostgres = await createPostgres({
|
||||
...input,
|
||||
});
|
||||
if (ctx.user.role === "member") {
|
||||
await addNewService(
|
||||
ctx.user.id,
|
||||
@@ -107,7 +113,8 @@ export const postgresRouter = createTRPCRouter({
|
||||
|
||||
const postgres = await findPostgresById(input.postgresId);
|
||||
if (
|
||||
postgres.project.organizationId !== ctx.session.activeOrganizationId
|
||||
postgres.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -122,7 +129,10 @@ export const postgresRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const service = await findPostgresById(input.postgresId);
|
||||
|
||||
if (service.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
service.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to start this Postgres",
|
||||
@@ -145,7 +155,8 @@ export const postgresRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const postgres = await findPostgresById(input.postgresId);
|
||||
if (
|
||||
postgres.project.organizationId !== ctx.session.activeOrganizationId
|
||||
postgres.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -169,7 +180,8 @@ export const postgresRouter = createTRPCRouter({
|
||||
const postgres = await findPostgresById(input.postgresId);
|
||||
|
||||
if (
|
||||
postgres.project.organizationId !== ctx.session.activeOrganizationId
|
||||
postgres.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -187,7 +199,8 @@ export const postgresRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const postgres = await findPostgresById(input.postgresId);
|
||||
if (
|
||||
postgres.project.organizationId !== ctx.session.activeOrganizationId
|
||||
postgres.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -210,7 +223,8 @@ export const postgresRouter = createTRPCRouter({
|
||||
.subscription(async ({ input, ctx }) => {
|
||||
const postgres = await findPostgresById(input.postgresId);
|
||||
if (
|
||||
postgres.project.organizationId !== ctx.session.activeOrganizationId
|
||||
postgres.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -229,7 +243,8 @@ export const postgresRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const postgres = await findPostgresById(input.postgresId);
|
||||
if (
|
||||
postgres.project.organizationId !== ctx.session.activeOrganizationId
|
||||
postgres.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -255,7 +270,8 @@ export const postgresRouter = createTRPCRouter({
|
||||
const postgres = await findPostgresById(input.postgresId);
|
||||
|
||||
if (
|
||||
postgres.project.organizationId !== ctx.session.activeOrganizationId
|
||||
postgres.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -280,7 +296,8 @@ export const postgresRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const postgres = await findPostgresById(input.postgresId);
|
||||
if (
|
||||
postgres.project.organizationId !== ctx.session.activeOrganizationId
|
||||
postgres.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -305,7 +322,8 @@ export const postgresRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const postgres = await findPostgresById(input.postgresId);
|
||||
if (
|
||||
postgres.project.organizationId !== ctx.session.activeOrganizationId
|
||||
postgres.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -337,7 +355,8 @@ export const postgresRouter = createTRPCRouter({
|
||||
const { postgresId, ...rest } = input;
|
||||
const postgres = await findPostgresById(postgresId);
|
||||
if (
|
||||
postgres.project.organizationId !== ctx.session.activeOrganizationId
|
||||
postgres.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -361,13 +380,14 @@ export const postgresRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
postgresId: z.string(),
|
||||
targetProjectId: z.string(),
|
||||
targetEnvironmentId: z.string(),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const postgres = await findPostgresById(input.postgresId);
|
||||
if (
|
||||
postgres.project.organizationId !== ctx.session.activeOrganizationId
|
||||
postgres.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -375,11 +395,16 @@ export const postgresRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
|
||||
const targetProject = await findProjectById(input.targetProjectId);
|
||||
if (targetProject.organizationId !== ctx.session.activeOrganizationId) {
|
||||
const targetEnvironment = await findEnvironmentById(
|
||||
input.targetEnvironmentId,
|
||||
);
|
||||
if (
|
||||
targetEnvironment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to move to this project",
|
||||
message: "You are not authorized to move to this environment",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -387,7 +412,7 @@ export const postgresRouter = createTRPCRouter({
|
||||
const updatedPostgres = await db
|
||||
.update(postgresTable)
|
||||
.set({
|
||||
projectId: input.targetProjectId,
|
||||
environmentId: input.targetEnvironmentId,
|
||||
})
|
||||
.where(eq(postgresTable.postgresId, input.postgresId))
|
||||
.returning()
|
||||
@@ -407,7 +432,8 @@ export const postgresRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const postgres = await findPostgresById(input.postgresId);
|
||||
if (
|
||||
postgres.project.organizationId !== ctx.session.activeOrganizationId
|
||||
postgres.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
|
||||
@@ -15,7 +15,8 @@ export const previewDeploymentRouter = createTRPCRouter({
|
||||
.query(async ({ input, ctx }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -31,7 +32,7 @@ export const previewDeploymentRouter = createTRPCRouter({
|
||||
input.previewDeploymentId,
|
||||
);
|
||||
if (
|
||||
previewDeployment.application.project.organizationId !==
|
||||
previewDeployment.application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
@@ -49,7 +50,7 @@ export const previewDeploymentRouter = createTRPCRouter({
|
||||
input.previewDeploymentId,
|
||||
);
|
||||
if (
|
||||
previewDeployment.application.project.organizationId !==
|
||||
previewDeployment.application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
addNewEnvironment,
|
||||
addNewProject,
|
||||
checkProjectAccess,
|
||||
createApplication,
|
||||
@@ -19,6 +20,7 @@ import {
|
||||
deleteProject,
|
||||
findApplicationById,
|
||||
findComposeById,
|
||||
findEnvironmentById,
|
||||
findMariadbById,
|
||||
findMemberById,
|
||||
findMongoById,
|
||||
@@ -43,6 +45,7 @@ import {
|
||||
apiUpdateProject,
|
||||
applications,
|
||||
compose,
|
||||
environments,
|
||||
mariadb,
|
||||
mongo,
|
||||
mysql,
|
||||
@@ -80,7 +83,13 @@ export const projectRouter = createTRPCRouter({
|
||||
if (ctx.user.role === "member") {
|
||||
await addNewProject(
|
||||
ctx.user.id,
|
||||
project.projectId,
|
||||
project.project.projectId,
|
||||
ctx.session.activeOrganizationId,
|
||||
);
|
||||
|
||||
await addNewEnvironment(
|
||||
ctx.user.id,
|
||||
project?.environment?.environmentId || "",
|
||||
ctx.session.activeOrganizationId,
|
||||
);
|
||||
}
|
||||
@@ -117,29 +126,42 @@ export const projectRouter = createTRPCRouter({
|
||||
eq(projects.organizationId, ctx.session.activeOrganizationId),
|
||||
),
|
||||
with: {
|
||||
applications: {
|
||||
where: buildServiceFilter(
|
||||
applications.applicationId,
|
||||
accessedServices,
|
||||
),
|
||||
},
|
||||
compose: {
|
||||
where: buildServiceFilter(compose.composeId, accessedServices),
|
||||
},
|
||||
mariadb: {
|
||||
where: buildServiceFilter(mariadb.mariadbId, accessedServices),
|
||||
},
|
||||
mongo: {
|
||||
where: buildServiceFilter(mongo.mongoId, accessedServices),
|
||||
},
|
||||
mysql: {
|
||||
where: buildServiceFilter(mysql.mysqlId, accessedServices),
|
||||
},
|
||||
postgres: {
|
||||
where: buildServiceFilter(postgres.postgresId, accessedServices),
|
||||
},
|
||||
redis: {
|
||||
where: buildServiceFilter(redis.redisId, accessedServices),
|
||||
environments: {
|
||||
with: {
|
||||
applications: {
|
||||
where: buildServiceFilter(
|
||||
applications.applicationId,
|
||||
accessedServices,
|
||||
),
|
||||
},
|
||||
compose: {
|
||||
where: buildServiceFilter(
|
||||
compose.composeId,
|
||||
accessedServices,
|
||||
),
|
||||
},
|
||||
mariadb: {
|
||||
where: buildServiceFilter(
|
||||
mariadb.mariadbId,
|
||||
accessedServices,
|
||||
),
|
||||
},
|
||||
mongo: {
|
||||
where: buildServiceFilter(mongo.mongoId, accessedServices),
|
||||
},
|
||||
mysql: {
|
||||
where: buildServiceFilter(mysql.mysqlId, accessedServices),
|
||||
},
|
||||
postgres: {
|
||||
where: buildServiceFilter(
|
||||
postgres.postgresId,
|
||||
accessedServices,
|
||||
),
|
||||
},
|
||||
redis: {
|
||||
where: buildServiceFilter(redis.redisId, accessedServices),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -164,15 +186,22 @@ export const projectRouter = createTRPCRouter({
|
||||
}),
|
||||
all: protectedProcedure.query(async ({ ctx }) => {
|
||||
if (ctx.user.role === "member") {
|
||||
const { accessedProjects, accessedServices } = await findMemberById(
|
||||
ctx.user.id,
|
||||
ctx.session.activeOrganizationId,
|
||||
);
|
||||
const { accessedProjects, accessedEnvironments, accessedServices } =
|
||||
await findMemberById(ctx.user.id, ctx.session.activeOrganizationId);
|
||||
|
||||
if (accessedProjects.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Build environment filter
|
||||
const environmentFilter =
|
||||
accessedEnvironments.length === 0
|
||||
? sql`false`
|
||||
: sql`${environments.environmentId} IN (${sql.join(
|
||||
accessedEnvironments.map((envId) => sql`${envId}`),
|
||||
sql`, `,
|
||||
)})`;
|
||||
|
||||
return await db.query.projects.findMany({
|
||||
where: and(
|
||||
sql`${projects.projectId} IN (${sql.join(
|
||||
@@ -182,31 +211,39 @@ export const projectRouter = createTRPCRouter({
|
||||
eq(projects.organizationId, ctx.session.activeOrganizationId),
|
||||
),
|
||||
with: {
|
||||
applications: {
|
||||
where: buildServiceFilter(
|
||||
applications.applicationId,
|
||||
accessedServices,
|
||||
),
|
||||
with: { domains: true },
|
||||
},
|
||||
mariadb: {
|
||||
where: buildServiceFilter(mariadb.mariadbId, accessedServices),
|
||||
},
|
||||
mongo: {
|
||||
where: buildServiceFilter(mongo.mongoId, accessedServices),
|
||||
},
|
||||
mysql: {
|
||||
where: buildServiceFilter(mysql.mysqlId, accessedServices),
|
||||
},
|
||||
postgres: {
|
||||
where: buildServiceFilter(postgres.postgresId, accessedServices),
|
||||
},
|
||||
redis: {
|
||||
where: buildServiceFilter(redis.redisId, accessedServices),
|
||||
},
|
||||
compose: {
|
||||
where: buildServiceFilter(compose.composeId, accessedServices),
|
||||
with: { domains: true },
|
||||
environments: {
|
||||
where: environmentFilter,
|
||||
with: {
|
||||
applications: {
|
||||
where: buildServiceFilter(
|
||||
applications.applicationId,
|
||||
accessedServices,
|
||||
),
|
||||
with: { domains: true },
|
||||
},
|
||||
mariadb: {
|
||||
where: buildServiceFilter(mariadb.mariadbId, accessedServices),
|
||||
},
|
||||
mongo: {
|
||||
where: buildServiceFilter(mongo.mongoId, accessedServices),
|
||||
},
|
||||
mysql: {
|
||||
where: buildServiceFilter(mysql.mysqlId, accessedServices),
|
||||
},
|
||||
postgres: {
|
||||
where: buildServiceFilter(
|
||||
postgres.postgresId,
|
||||
accessedServices,
|
||||
),
|
||||
},
|
||||
redis: {
|
||||
where: buildServiceFilter(redis.redisId, accessedServices),
|
||||
},
|
||||
compose: {
|
||||
where: buildServiceFilter(compose.composeId, accessedServices),
|
||||
with: { domains: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: desc(projects.createdAt),
|
||||
@@ -215,19 +252,23 @@ export const projectRouter = createTRPCRouter({
|
||||
|
||||
return await db.query.projects.findMany({
|
||||
with: {
|
||||
applications: {
|
||||
environments: {
|
||||
with: {
|
||||
domains: true,
|
||||
},
|
||||
},
|
||||
mariadb: true,
|
||||
mongo: true,
|
||||
mysql: true,
|
||||
postgres: true,
|
||||
redis: true,
|
||||
compose: {
|
||||
with: {
|
||||
domains: true,
|
||||
applications: {
|
||||
with: {
|
||||
domains: true,
|
||||
},
|
||||
},
|
||||
mariadb: true,
|
||||
mongo: true,
|
||||
mysql: true,
|
||||
postgres: true,
|
||||
redis: true,
|
||||
compose: {
|
||||
with: {
|
||||
domains: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -288,7 +329,7 @@ export const projectRouter = createTRPCRouter({
|
||||
duplicate: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
sourceProjectId: z.string(),
|
||||
sourceEnvironmentId: z.string(),
|
||||
name: z.string(),
|
||||
description: z.string().optional(),
|
||||
includeServices: z.boolean().default(true),
|
||||
@@ -322,9 +363,15 @@ export const projectRouter = createTRPCRouter({
|
||||
}
|
||||
|
||||
// Get source project
|
||||
const sourceProject = await findProjectById(input.sourceProjectId);
|
||||
const sourceEnvironment = input.duplicateInSameProject
|
||||
? await findEnvironmentById(input.sourceEnvironmentId)
|
||||
: null;
|
||||
|
||||
if (sourceProject.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
input.duplicateInSameProject &&
|
||||
sourceEnvironment?.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this project",
|
||||
@@ -333,15 +380,17 @@ export const projectRouter = createTRPCRouter({
|
||||
|
||||
// Create new project or use existing one
|
||||
const targetProject = input.duplicateInSameProject
|
||||
? sourceProject
|
||||
? sourceEnvironment
|
||||
: await createProject(
|
||||
{
|
||||
name: input.name,
|
||||
description: input.description,
|
||||
env: sourceProject.env,
|
||||
env: sourceEnvironment?.project.env,
|
||||
},
|
||||
ctx.session.activeOrganizationId,
|
||||
);
|
||||
).then((value) => value.environment);
|
||||
|
||||
console.log("targetProject", targetProject);
|
||||
|
||||
if (input.includeServices) {
|
||||
const servicesToDuplicate = input.selectedServices || [];
|
||||
@@ -374,7 +423,7 @@ export const projectRouter = createTRPCRouter({
|
||||
name: input.duplicateInSameProject
|
||||
? `${application.name} (copy)`
|
||||
: application.name,
|
||||
projectId: targetProject.projectId,
|
||||
environmentId: targetProject?.environmentId || "",
|
||||
});
|
||||
|
||||
for (const domain of domains) {
|
||||
@@ -444,7 +493,7 @@ export const projectRouter = createTRPCRouter({
|
||||
name: input.duplicateInSameProject
|
||||
? `${postgres.name} (copy)`
|
||||
: postgres.name,
|
||||
projectId: targetProject.projectId,
|
||||
environmentId: targetProject?.environmentId || "",
|
||||
});
|
||||
|
||||
for (const mount of mounts) {
|
||||
@@ -480,7 +529,7 @@ export const projectRouter = createTRPCRouter({
|
||||
name: input.duplicateInSameProject
|
||||
? `${mariadb.name} (copy)`
|
||||
: mariadb.name,
|
||||
projectId: targetProject.projectId,
|
||||
environmentId: targetProject?.environmentId || "",
|
||||
});
|
||||
|
||||
for (const mount of mounts) {
|
||||
@@ -516,7 +565,7 @@ export const projectRouter = createTRPCRouter({
|
||||
name: input.duplicateInSameProject
|
||||
? `${mongo.name} (copy)`
|
||||
: mongo.name,
|
||||
projectId: targetProject.projectId,
|
||||
environmentId: targetProject?.environmentId || "",
|
||||
});
|
||||
|
||||
for (const mount of mounts) {
|
||||
@@ -552,7 +601,7 @@ export const projectRouter = createTRPCRouter({
|
||||
name: input.duplicateInSameProject
|
||||
? `${mysql.name} (copy)`
|
||||
: mysql.name,
|
||||
projectId: targetProject.projectId,
|
||||
environmentId: targetProject?.environmentId || "",
|
||||
});
|
||||
|
||||
for (const mount of mounts) {
|
||||
@@ -588,7 +637,7 @@ export const projectRouter = createTRPCRouter({
|
||||
name: input.duplicateInSameProject
|
||||
? `${redis.name} (copy)`
|
||||
: redis.name,
|
||||
projectId: targetProject.projectId,
|
||||
environmentId: targetProject?.environmentId || "",
|
||||
});
|
||||
|
||||
for (const mount of mounts) {
|
||||
@@ -623,7 +672,7 @@ export const projectRouter = createTRPCRouter({
|
||||
name: input.duplicateInSameProject
|
||||
? `${compose.name} (copy)`
|
||||
: compose.name,
|
||||
projectId: targetProject.projectId,
|
||||
environmentId: targetProject?.environmentId || "",
|
||||
});
|
||||
|
||||
for (const mount of mounts) {
|
||||
@@ -658,7 +707,7 @@ export const projectRouter = createTRPCRouter({
|
||||
if (!input.duplicateInSameProject && ctx.user.role === "member") {
|
||||
await addNewProject(
|
||||
ctx.user.id,
|
||||
targetProject.projectId,
|
||||
targetProject?.projectId || "",
|
||||
ctx.session.activeOrganizationId,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,8 @@ export const redirectsRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -34,7 +35,8 @@ export const redirectsRouter = createTRPCRouter({
|
||||
const redirect = await findRedirectById(input.redirectId);
|
||||
const application = await findApplicationById(redirect.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -49,7 +51,8 @@ export const redirectsRouter = createTRPCRouter({
|
||||
const redirect = await findRedirectById(input.redirectId);
|
||||
const application = await findApplicationById(redirect.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -64,7 +67,8 @@ export const redirectsRouter = createTRPCRouter({
|
||||
const redirect = await findRedirectById(input.redirectId);
|
||||
const application = await findApplicationById(redirect.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
createMount,
|
||||
createRedis,
|
||||
deployRedis,
|
||||
findEnvironmentById,
|
||||
findProjectById,
|
||||
findRedisById,
|
||||
IS_CLOUD,
|
||||
@@ -40,10 +41,14 @@ export const redisRouter = createTRPCRouter({
|
||||
.input(apiCreateRedis)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
// Get project from environment
|
||||
const environment = await findEnvironmentById(input.environmentId);
|
||||
const project = await findProjectById(environment.projectId);
|
||||
|
||||
if (ctx.user.role === "member") {
|
||||
await checkServiceAccess(
|
||||
ctx.user.id,
|
||||
input.projectId,
|
||||
project.projectId,
|
||||
ctx.session.activeOrganizationId,
|
||||
"create",
|
||||
);
|
||||
@@ -56,14 +61,15 @@ export const redisRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
|
||||
const project = await findProjectById(input.projectId);
|
||||
if (project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this project",
|
||||
});
|
||||
}
|
||||
const newRedis = await createRedis(input);
|
||||
const newRedis = await createRedis({
|
||||
...input,
|
||||
});
|
||||
if (ctx.user.role === "member") {
|
||||
await addNewService(
|
||||
ctx.user.id,
|
||||
@@ -98,7 +104,10 @@ export const redisRouter = createTRPCRouter({
|
||||
}
|
||||
|
||||
const redis = await findRedisById(input.redisId);
|
||||
if (redis.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
redis.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this Redis",
|
||||
@@ -111,7 +120,10 @@ export const redisRouter = createTRPCRouter({
|
||||
.input(apiFindOneRedis)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const redis = await findRedisById(input.redisId);
|
||||
if (redis.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
redis.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to start this Redis",
|
||||
@@ -133,7 +145,10 @@ export const redisRouter = createTRPCRouter({
|
||||
.input(apiResetRedis)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const redis = await findRedisById(input.redisId);
|
||||
if (redis.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
redis.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to reload this Redis",
|
||||
@@ -163,7 +178,10 @@ export const redisRouter = createTRPCRouter({
|
||||
.input(apiFindOneRedis)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const redis = await findRedisById(input.redisId);
|
||||
if (redis.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
redis.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to stop this Redis",
|
||||
@@ -184,7 +202,10 @@ export const redisRouter = createTRPCRouter({
|
||||
.input(apiSaveExternalPortRedis)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const mongo = await findRedisById(input.redisId);
|
||||
if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mongo.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to save this external port",
|
||||
@@ -200,7 +221,10 @@ export const redisRouter = createTRPCRouter({
|
||||
.input(apiDeployRedis)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const redis = await findRedisById(input.redisId);
|
||||
if (redis.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
redis.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to deploy this Redis",
|
||||
@@ -220,7 +244,10 @@ export const redisRouter = createTRPCRouter({
|
||||
.input(apiDeployRedis)
|
||||
.subscription(async ({ input, ctx }) => {
|
||||
const redis = await findRedisById(input.redisId);
|
||||
if (redis.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
redis.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to deploy this Redis",
|
||||
@@ -236,7 +263,10 @@ export const redisRouter = createTRPCRouter({
|
||||
.input(apiChangeRedisStatus)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const mongo = await findRedisById(input.redisId);
|
||||
if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
mongo.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to change this Redis status",
|
||||
@@ -261,7 +291,10 @@ export const redisRouter = createTRPCRouter({
|
||||
|
||||
const redis = await findRedisById(input.redisId);
|
||||
|
||||
if (redis.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
redis.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to delete this Redis",
|
||||
@@ -284,7 +317,10 @@ export const redisRouter = createTRPCRouter({
|
||||
.input(apiSaveEnvironmentVariablesRedis)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const redis = await findRedisById(input.redisId);
|
||||
if (redis.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
redis.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to save this environment",
|
||||
@@ -324,23 +360,31 @@ export const redisRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
redisId: z.string(),
|
||||
targetProjectId: z.string(),
|
||||
targetEnvironmentId: z.string(),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const redis = await findRedisById(input.redisId);
|
||||
if (redis.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
redis.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to move this redis",
|
||||
});
|
||||
}
|
||||
|
||||
const targetProject = await findProjectById(input.targetProjectId);
|
||||
if (targetProject.organizationId !== ctx.session.activeOrganizationId) {
|
||||
const targetEnvironment = await findEnvironmentById(
|
||||
input.targetEnvironmentId,
|
||||
);
|
||||
if (
|
||||
targetEnvironment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to move to this project",
|
||||
message: "You are not authorized to move to this environment",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -348,7 +392,7 @@ export const redisRouter = createTRPCRouter({
|
||||
const updatedRedis = await db
|
||||
.update(redisTable)
|
||||
.set({
|
||||
projectId: input.targetProjectId,
|
||||
environmentId: input.targetEnvironmentId,
|
||||
})
|
||||
.where(eq(redisTable.redisId, input.redisId))
|
||||
.returning()
|
||||
@@ -367,7 +411,10 @@ export const redisRouter = createTRPCRouter({
|
||||
.input(apiRebuildRedis)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const redis = await findRedisById(input.redisId);
|
||||
if (redis.project.organizationId !== ctx.session.activeOrganizationId) {
|
||||
if (
|
||||
redis.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to rebuild this Redis database",
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { removeRollbackById, rollback } from "@dokploy/server";
|
||||
import {
|
||||
findRollbackById,
|
||||
removeRollbackById,
|
||||
rollback,
|
||||
} from "@dokploy/server";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||
import { apiFindOneRollback } from "@/server/db/schema";
|
||||
@@ -22,8 +26,18 @@ export const rollbackRouter = createTRPCRouter({
|
||||
}),
|
||||
rollback: protectedProcedure
|
||||
.input(apiFindOneRollback)
|
||||
.mutation(async ({ input }) => {
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
const currentRollback = await findRollbackById(input.rollbackId);
|
||||
if (
|
||||
currentRollback?.deployment?.application?.environment?.project
|
||||
.organizationId !== ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to rollback this deployment",
|
||||
});
|
||||
}
|
||||
return await rollback(input.rollbackId);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
@@ -19,7 +19,8 @@ export const securityRouter = createTRPCRouter({
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -34,7 +35,8 @@ export const securityRouter = createTRPCRouter({
|
||||
const security = await findSecurityById(input.securityId);
|
||||
const application = await findApplicationById(security.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -49,7 +51,8 @@ export const securityRouter = createTRPCRouter({
|
||||
const security = await findSecurityById(input.securityId);
|
||||
const application = await findApplicationById(security.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
@@ -64,7 +67,8 @@ export const securityRouter = createTRPCRouter({
|
||||
const security = await findSecurityById(input.securityId);
|
||||
const application = await findApplicationById(security.applicationId);
|
||||
if (
|
||||
application.project.organizationId !== ctx.session.activeOrganizationId
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
|
||||
@@ -46,8 +46,8 @@ import {
|
||||
import { generateOpenApiDocument } from "@dokploy/trpc-openapi";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { eq, sql } from "drizzle-orm";
|
||||
import { dump, load } from "js-yaml";
|
||||
import { scheduledJobs, scheduleJob } from "node-schedule";
|
||||
import { parse, stringify } from "yaml";
|
||||
import { z } from "zod";
|
||||
import { db } from "@/server/db";
|
||||
import {
|
||||
@@ -657,7 +657,7 @@ export const settingsRouter = createTRPCRouter({
|
||||
const config = readMainConfig();
|
||||
|
||||
if (!config) return false;
|
||||
const parsedConfig = load(config) as {
|
||||
const parsedConfig = parse(config) as {
|
||||
accessLog?: {
|
||||
filePath: string;
|
||||
};
|
||||
@@ -678,7 +678,7 @@ export const settingsRouter = createTRPCRouter({
|
||||
const mainConfig = readMainConfig();
|
||||
if (!mainConfig) return false;
|
||||
|
||||
const currentConfig = load(mainConfig) as {
|
||||
const currentConfig = parse(mainConfig) as {
|
||||
accessLog?: {
|
||||
filePath: string;
|
||||
};
|
||||
@@ -701,7 +701,7 @@ export const settingsRouter = createTRPCRouter({
|
||||
currentConfig.accessLog = undefined;
|
||||
}
|
||||
|
||||
writeMainConfig(dump(currentConfig));
|
||||
writeMainConfig(stringify(currentConfig));
|
||||
|
||||
return true;
|
||||
}),
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
findNotificationById,
|
||||
findOrganizationById,
|
||||
findUserById,
|
||||
getDokployUrl,
|
||||
getUserByToken,
|
||||
IS_CLOUD,
|
||||
removeUserById,
|
||||
@@ -196,7 +197,16 @@ export const userRouter = createTRPCRouter({
|
||||
})
|
||||
.where(eq(account.userId, ctx.user.id));
|
||||
}
|
||||
return await updateUser(ctx.user.id, input);
|
||||
|
||||
try {
|
||||
return await updateUser(ctx.user.id, input);
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message:
|
||||
error instanceof Error ? error.message : "Failed to update user",
|
||||
});
|
||||
}
|
||||
}),
|
||||
getUserByToken: publicProcedure
|
||||
.input(apiFindOneToken)
|
||||
@@ -455,11 +465,10 @@ export const userRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
|
||||
const admin = await findAdmin();
|
||||
const host =
|
||||
process.env.NODE_ENV === "development"
|
||||
? "http://localhost:3000"
|
||||
: admin.user.host;
|
||||
: await getDokployUrl();
|
||||
const inviteLink = `${host}/invitation?token=${input.invitationId}`;
|
||||
|
||||
const organization = await findOrganizationById(
|
||||
|
||||
Reference in New Issue
Block a user