mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
- Updated the user role property from `rol` to `role` across multiple TRPC context and router files to ensure consistency and clarity in role management. - Adjusted conditional checks for user roles in various procedures to reflect the updated property name, enhancing code readability and maintainability.
762 lines
21 KiB
TypeScript
762 lines
21 KiB
TypeScript
import {
|
|
createTRPCRouter,
|
|
protectedProcedure,
|
|
uploadProcedure,
|
|
} from "@/server/api/trpc";
|
|
import { db } from "@/server/db";
|
|
import {
|
|
apiCreateApplication,
|
|
apiFindMonitoringStats,
|
|
apiFindOneApplication,
|
|
apiReloadApplication,
|
|
apiSaveBitbucketProvider,
|
|
apiSaveBuildType,
|
|
apiSaveDockerProvider,
|
|
apiSaveEnvironmentVariables,
|
|
apiSaveGitProvider,
|
|
apiSaveGiteaProvider,
|
|
apiSaveGithubProvider,
|
|
apiSaveGitlabProvider,
|
|
apiUpdateApplication,
|
|
applications,
|
|
} 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 { uploadFileSchema } from "@/utils/schema";
|
|
import {
|
|
IS_CLOUD,
|
|
addNewService,
|
|
checkServiceAccess,
|
|
createApplication,
|
|
deleteAllMiddlewares,
|
|
findApplicationById,
|
|
findProjectById,
|
|
getApplicationStats,
|
|
mechanizeDockerContainer,
|
|
readConfig,
|
|
readRemoteConfig,
|
|
removeDeployments,
|
|
removeDirectoryCode,
|
|
removeMonitoringDirectory,
|
|
removeService,
|
|
removeTraefikConfig,
|
|
startService,
|
|
startServiceRemote,
|
|
stopService,
|
|
stopServiceRemote,
|
|
unzipDrop,
|
|
updateApplication,
|
|
updateApplicationStatus,
|
|
writeConfig,
|
|
writeConfigRemote,
|
|
// uploadFileSchema
|
|
} from "@dokploy/server";
|
|
import { TRPCError } from "@trpc/server";
|
|
import { eq } from "drizzle-orm";
|
|
import { nanoid } from "nanoid";
|
|
import { z } from "zod";
|
|
|
|
export const applicationRouter = createTRPCRouter({
|
|
create: protectedProcedure
|
|
.input(apiCreateApplication)
|
|
.mutation(async ({ input, ctx }) => {
|
|
try {
|
|
if (ctx.user.role === "member") {
|
|
await checkServiceAccess(
|
|
ctx.user.id,
|
|
input.projectId,
|
|
ctx.session.activeOrganizationId,
|
|
"create",
|
|
);
|
|
}
|
|
|
|
if (IS_CLOUD && !input.serverId) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You need to use a server to create an application",
|
|
});
|
|
}
|
|
|
|
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") {
|
|
await addNewService(
|
|
ctx.user.id,
|
|
newApplication.applicationId,
|
|
project.organizationId,
|
|
);
|
|
}
|
|
return newApplication;
|
|
} catch (error: unknown) {
|
|
if (error instanceof TRPCError) {
|
|
throw error;
|
|
}
|
|
throw new TRPCError({
|
|
code: "BAD_REQUEST",
|
|
message: "Error creating the application",
|
|
cause: error,
|
|
});
|
|
}
|
|
}),
|
|
one: protectedProcedure
|
|
.input(apiFindOneApplication)
|
|
.query(async ({ input, ctx }) => {
|
|
if (ctx.user.role === "member") {
|
|
await checkServiceAccess(
|
|
ctx.user.id,
|
|
input.applicationId,
|
|
ctx.session.activeOrganizationId,
|
|
"access",
|
|
);
|
|
}
|
|
const application = await findApplicationById(input.applicationId);
|
|
if (
|
|
application.project.organizationId !== ctx.session.activeOrganizationId
|
|
) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You are not authorized to access this application",
|
|
});
|
|
}
|
|
return application;
|
|
}),
|
|
|
|
reload: protectedProcedure
|
|
.input(apiReloadApplication)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const application = await findApplicationById(input.applicationId);
|
|
|
|
try {
|
|
if (
|
|
application.project.organizationId !==
|
|
ctx.session.activeOrganizationId
|
|
) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You are not authorized to reload this application",
|
|
});
|
|
}
|
|
|
|
if (application.serverId) {
|
|
await stopServiceRemote(application.serverId, input.appName);
|
|
} else {
|
|
await stopService(input.appName);
|
|
}
|
|
|
|
await updateApplicationStatus(input.applicationId, "idle");
|
|
await mechanizeDockerContainer(application);
|
|
await updateApplicationStatus(input.applicationId, "done");
|
|
return true;
|
|
} catch (error) {
|
|
await updateApplicationStatus(input.applicationId, "error");
|
|
throw new TRPCError({
|
|
code: "INTERNAL_SERVER_ERROR",
|
|
message: "Error reloading application",
|
|
cause: error,
|
|
});
|
|
}
|
|
}),
|
|
|
|
delete: protectedProcedure
|
|
.input(apiFindOneApplication)
|
|
.mutation(async ({ input, ctx }) => {
|
|
if (ctx.user.role === "member") {
|
|
await checkServiceAccess(
|
|
ctx.user.id,
|
|
input.applicationId,
|
|
ctx.session.activeOrganizationId,
|
|
"delete",
|
|
);
|
|
}
|
|
const application = await findApplicationById(input.applicationId);
|
|
|
|
if (
|
|
application.project.organizationId !== ctx.session.activeOrganizationId
|
|
) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You are not authorized to delete this application",
|
|
});
|
|
}
|
|
|
|
const result = await db
|
|
.delete(applications)
|
|
.where(eq(applications.applicationId, input.applicationId))
|
|
.returning();
|
|
|
|
const cleanupOperations = [
|
|
async () => await deleteAllMiddlewares(application),
|
|
async () => await removeDeployments(application),
|
|
async () =>
|
|
await removeDirectoryCode(application.appName, application.serverId),
|
|
async () =>
|
|
await removeMonitoringDirectory(
|
|
application.appName,
|
|
application.serverId,
|
|
),
|
|
async () =>
|
|
await removeTraefikConfig(application.appName, application.serverId),
|
|
async () =>
|
|
await removeService(application?.appName, application.serverId),
|
|
];
|
|
|
|
for (const operation of cleanupOperations) {
|
|
try {
|
|
await operation();
|
|
} catch (_) {}
|
|
}
|
|
|
|
return result[0];
|
|
}),
|
|
|
|
stop: protectedProcedure
|
|
.input(apiFindOneApplication)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const service = await findApplicationById(input.applicationId);
|
|
if (service.project.organizationId !== ctx.session.activeOrganizationId) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You are not authorized to stop this application",
|
|
});
|
|
}
|
|
if (service.serverId) {
|
|
await stopServiceRemote(service.serverId, service.appName);
|
|
} else {
|
|
await stopService(service.appName);
|
|
}
|
|
await updateApplicationStatus(input.applicationId, "idle");
|
|
|
|
return service;
|
|
}),
|
|
|
|
start: protectedProcedure
|
|
.input(apiFindOneApplication)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const service = await findApplicationById(input.applicationId);
|
|
if (service.project.organizationId !== ctx.session.activeOrganizationId) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You are not authorized to start this application",
|
|
});
|
|
}
|
|
|
|
if (service.serverId) {
|
|
await startServiceRemote(service.serverId, service.appName);
|
|
} else {
|
|
await startService(service.appName);
|
|
}
|
|
await updateApplicationStatus(input.applicationId, "done");
|
|
|
|
return service;
|
|
}),
|
|
|
|
redeploy: protectedProcedure
|
|
.input(apiFindOneApplication)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const application = await findApplicationById(input.applicationId);
|
|
if (
|
|
application.project.organizationId !== ctx.session.activeOrganizationId
|
|
) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You are not authorized to redeploy this application",
|
|
});
|
|
}
|
|
const jobData: DeploymentJob = {
|
|
applicationId: input.applicationId,
|
|
titleLog: "Rebuild deployment",
|
|
descriptionLog: "",
|
|
type: "redeploy",
|
|
applicationType: "application",
|
|
server: !!application.serverId,
|
|
};
|
|
|
|
if (IS_CLOUD && application.serverId) {
|
|
jobData.serverId = application.serverId;
|
|
await deploy(jobData);
|
|
return true;
|
|
}
|
|
await myQueue.add(
|
|
"deployments",
|
|
{ ...jobData },
|
|
{
|
|
removeOnComplete: true,
|
|
removeOnFail: true,
|
|
},
|
|
);
|
|
}),
|
|
saveEnvironment: protectedProcedure
|
|
.input(apiSaveEnvironmentVariables)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const application = await findApplicationById(input.applicationId);
|
|
if (
|
|
application.project.organizationId !== ctx.session.activeOrganizationId
|
|
) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You are not authorized to save this environment",
|
|
});
|
|
}
|
|
await updateApplication(input.applicationId, {
|
|
env: input.env,
|
|
buildArgs: input.buildArgs,
|
|
});
|
|
return true;
|
|
}),
|
|
saveBuildType: protectedProcedure
|
|
.input(apiSaveBuildType)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const application = await findApplicationById(input.applicationId);
|
|
if (
|
|
application.project.organizationId !== ctx.session.activeOrganizationId
|
|
) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You are not authorized to save this build type",
|
|
});
|
|
}
|
|
await updateApplication(input.applicationId, {
|
|
buildType: input.buildType,
|
|
dockerfile: input.dockerfile,
|
|
publishDirectory: input.publishDirectory,
|
|
dockerContextPath: input.dockerContextPath,
|
|
dockerBuildStage: input.dockerBuildStage,
|
|
herokuVersion: input.herokuVersion,
|
|
});
|
|
|
|
return true;
|
|
}),
|
|
saveGithubProvider: protectedProcedure
|
|
.input(apiSaveGithubProvider)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const application = await findApplicationById(input.applicationId);
|
|
if (
|
|
application.project.organizationId !== ctx.session.activeOrganizationId
|
|
) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You are not authorized to save this github provider",
|
|
});
|
|
}
|
|
await updateApplication(input.applicationId, {
|
|
repository: input.repository,
|
|
branch: input.branch,
|
|
sourceType: "github",
|
|
owner: input.owner,
|
|
buildPath: input.buildPath,
|
|
applicationStatus: "idle",
|
|
githubId: input.githubId,
|
|
watchPaths: input.watchPaths,
|
|
triggerType: input.triggerType,
|
|
enableSubmodules: input.enableSubmodules,
|
|
});
|
|
|
|
return true;
|
|
}),
|
|
saveGitlabProvider: protectedProcedure
|
|
.input(apiSaveGitlabProvider)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const application = await findApplicationById(input.applicationId);
|
|
if (
|
|
application.project.organizationId !== ctx.session.activeOrganizationId
|
|
) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You are not authorized to save this gitlab provider",
|
|
});
|
|
}
|
|
await updateApplication(input.applicationId, {
|
|
gitlabRepository: input.gitlabRepository,
|
|
gitlabOwner: input.gitlabOwner,
|
|
gitlabBranch: input.gitlabBranch,
|
|
gitlabBuildPath: input.gitlabBuildPath,
|
|
sourceType: "gitlab",
|
|
applicationStatus: "idle",
|
|
gitlabId: input.gitlabId,
|
|
gitlabProjectId: input.gitlabProjectId,
|
|
gitlabPathNamespace: input.gitlabPathNamespace,
|
|
watchPaths: input.watchPaths,
|
|
enableSubmodules: input.enableSubmodules,
|
|
});
|
|
|
|
return true;
|
|
}),
|
|
saveBitbucketProvider: protectedProcedure
|
|
.input(apiSaveBitbucketProvider)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const application = await findApplicationById(input.applicationId);
|
|
if (
|
|
application.project.organizationId !== ctx.session.activeOrganizationId
|
|
) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You are not authorized to save this bitbucket provider",
|
|
});
|
|
}
|
|
await updateApplication(input.applicationId, {
|
|
bitbucketRepository: input.bitbucketRepository,
|
|
bitbucketOwner: input.bitbucketOwner,
|
|
bitbucketBranch: input.bitbucketBranch,
|
|
bitbucketBuildPath: input.bitbucketBuildPath,
|
|
sourceType: "bitbucket",
|
|
applicationStatus: "idle",
|
|
bitbucketId: input.bitbucketId,
|
|
watchPaths: input.watchPaths,
|
|
enableSubmodules: input.enableSubmodules,
|
|
});
|
|
|
|
return true;
|
|
}),
|
|
saveGiteaProvider: protectedProcedure
|
|
.input(apiSaveGiteaProvider)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const application = await findApplicationById(input.applicationId);
|
|
if (
|
|
application.project.organizationId !== ctx.session.activeOrganizationId
|
|
) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You are not authorized to save this gitea provider",
|
|
});
|
|
}
|
|
await updateApplication(input.applicationId, {
|
|
giteaRepository: input.giteaRepository,
|
|
giteaOwner: input.giteaOwner,
|
|
giteaBranch: input.giteaBranch,
|
|
giteaBuildPath: input.giteaBuildPath,
|
|
sourceType: "gitea",
|
|
applicationStatus: "idle",
|
|
giteaId: input.giteaId,
|
|
watchPaths: input.watchPaths,
|
|
enableSubmodules: input.enableSubmodules,
|
|
});
|
|
|
|
return true;
|
|
}),
|
|
saveDockerProvider: protectedProcedure
|
|
.input(apiSaveDockerProvider)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const application = await findApplicationById(input.applicationId);
|
|
if (
|
|
application.project.organizationId !== ctx.session.activeOrganizationId
|
|
) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You are not authorized to save this docker provider",
|
|
});
|
|
}
|
|
await updateApplication(input.applicationId, {
|
|
dockerImage: input.dockerImage,
|
|
username: input.username,
|
|
password: input.password,
|
|
sourceType: "docker",
|
|
applicationStatus: "idle",
|
|
registryUrl: input.registryUrl,
|
|
});
|
|
|
|
return true;
|
|
}),
|
|
saveGitProdiver: protectedProcedure
|
|
.input(apiSaveGitProvider)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const application = await findApplicationById(input.applicationId);
|
|
if (
|
|
application.project.organizationId !== ctx.session.activeOrganizationId
|
|
) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You are not authorized to save this git provider",
|
|
});
|
|
}
|
|
await updateApplication(input.applicationId, {
|
|
customGitBranch: input.customGitBranch,
|
|
customGitBuildPath: input.customGitBuildPath,
|
|
customGitUrl: input.customGitUrl,
|
|
customGitSSHKeyId: input.customGitSSHKeyId,
|
|
sourceType: "git",
|
|
applicationStatus: "idle",
|
|
watchPaths: input.watchPaths,
|
|
enableSubmodules: input.enableSubmodules,
|
|
});
|
|
|
|
return true;
|
|
}),
|
|
markRunning: protectedProcedure
|
|
.input(apiFindOneApplication)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const application = await findApplicationById(input.applicationId);
|
|
if (
|
|
application.project.organizationId !== ctx.session.activeOrganizationId
|
|
) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You are not authorized to mark this application as running",
|
|
});
|
|
}
|
|
await updateApplicationStatus(input.applicationId, "running");
|
|
}),
|
|
update: protectedProcedure
|
|
.input(apiUpdateApplication)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const application = await findApplicationById(input.applicationId);
|
|
if (
|
|
application.project.organizationId !== ctx.session.activeOrganizationId
|
|
) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You are not authorized to update this application",
|
|
});
|
|
}
|
|
const { applicationId, ...rest } = input;
|
|
const updateApp = await updateApplication(applicationId, {
|
|
...rest,
|
|
});
|
|
|
|
if (!updateApp) {
|
|
throw new TRPCError({
|
|
code: "BAD_REQUEST",
|
|
message: "Error updating application",
|
|
});
|
|
}
|
|
|
|
return true;
|
|
}),
|
|
refreshToken: protectedProcedure
|
|
.input(apiFindOneApplication)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const application = await findApplicationById(input.applicationId);
|
|
if (
|
|
application.project.organizationId !== ctx.session.activeOrganizationId
|
|
) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You are not authorized to refresh this application",
|
|
});
|
|
}
|
|
await updateApplication(input.applicationId, {
|
|
refreshToken: nanoid(),
|
|
});
|
|
return true;
|
|
}),
|
|
deploy: protectedProcedure
|
|
.input(apiFindOneApplication)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const application = await findApplicationById(input.applicationId);
|
|
if (
|
|
application.project.organizationId !== ctx.session.activeOrganizationId
|
|
) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You are not authorized to deploy this application",
|
|
});
|
|
}
|
|
const jobData: DeploymentJob = {
|
|
applicationId: input.applicationId,
|
|
titleLog: "Manual deployment",
|
|
descriptionLog: "",
|
|
type: "deploy",
|
|
applicationType: "application",
|
|
server: !!application.serverId,
|
|
};
|
|
if (IS_CLOUD && application.serverId) {
|
|
jobData.serverId = application.serverId;
|
|
await deploy(jobData);
|
|
|
|
return true;
|
|
}
|
|
await myQueue.add(
|
|
"deployments",
|
|
{ ...jobData },
|
|
{
|
|
removeOnComplete: true,
|
|
removeOnFail: true,
|
|
},
|
|
);
|
|
}),
|
|
|
|
cleanQueues: protectedProcedure
|
|
.input(apiFindOneApplication)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const application = await findApplicationById(input.applicationId);
|
|
if (
|
|
application.project.organizationId !== ctx.session.activeOrganizationId
|
|
) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You are not authorized to clean this application",
|
|
});
|
|
}
|
|
await cleanQueuesByApplication(input.applicationId);
|
|
}),
|
|
|
|
readTraefikConfig: protectedProcedure
|
|
.input(apiFindOneApplication)
|
|
.query(async ({ input, ctx }) => {
|
|
const application = await findApplicationById(input.applicationId);
|
|
if (
|
|
application.project.organizationId !== ctx.session.activeOrganizationId
|
|
) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You are not authorized to read this application",
|
|
});
|
|
}
|
|
|
|
let traefikConfig = null;
|
|
if (application.serverId) {
|
|
traefikConfig = await readRemoteConfig(
|
|
application.serverId,
|
|
application.appName,
|
|
);
|
|
} else {
|
|
traefikConfig = readConfig(application.appName);
|
|
}
|
|
return traefikConfig;
|
|
}),
|
|
|
|
dropDeployment: protectedProcedure
|
|
.meta({
|
|
openapi: {
|
|
path: "/drop-deployment",
|
|
method: "POST",
|
|
override: true,
|
|
enabled: false,
|
|
},
|
|
})
|
|
.use(uploadProcedure)
|
|
.input(uploadFileSchema)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const zipFile = input.zip;
|
|
|
|
const app = await findApplicationById(input.applicationId as string);
|
|
|
|
if (app.project.organizationId !== ctx.session.activeOrganizationId) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You are not authorized to deploy this application",
|
|
});
|
|
}
|
|
|
|
await updateApplication(input.applicationId as string, {
|
|
sourceType: "drop",
|
|
dropBuildPath: input.dropBuildPath || "",
|
|
});
|
|
|
|
await unzipDrop(zipFile, app);
|
|
const jobData: DeploymentJob = {
|
|
applicationId: app.applicationId,
|
|
titleLog: "Manual deployment",
|
|
descriptionLog: "",
|
|
type: "deploy",
|
|
applicationType: "application",
|
|
server: !!app.serverId,
|
|
};
|
|
if (IS_CLOUD && app.serverId) {
|
|
jobData.serverId = app.serverId;
|
|
await deploy(jobData);
|
|
return true;
|
|
}
|
|
|
|
await myQueue.add(
|
|
"deployments",
|
|
{ ...jobData },
|
|
{
|
|
removeOnComplete: true,
|
|
removeOnFail: true,
|
|
},
|
|
);
|
|
return true;
|
|
}),
|
|
updateTraefikConfig: protectedProcedure
|
|
.input(z.object({ applicationId: z.string(), traefikConfig: z.string() }))
|
|
.mutation(async ({ input, ctx }) => {
|
|
const application = await findApplicationById(input.applicationId);
|
|
|
|
if (
|
|
application.project.organizationId !== ctx.session.activeOrganizationId
|
|
) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You are not authorized to update this application",
|
|
});
|
|
}
|
|
|
|
if (application.serverId) {
|
|
await writeConfigRemote(
|
|
application.serverId,
|
|
application.appName,
|
|
input.traefikConfig,
|
|
);
|
|
} else {
|
|
writeConfig(application.appName, input.traefikConfig);
|
|
}
|
|
return true;
|
|
}),
|
|
readAppMonitoring: protectedProcedure
|
|
.input(apiFindMonitoringStats)
|
|
.query(async ({ input }) => {
|
|
if (IS_CLOUD) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "Functionality not available in cloud version",
|
|
});
|
|
}
|
|
const stats = await getApplicationStats(input.appName);
|
|
|
|
return stats;
|
|
}),
|
|
move: protectedProcedure
|
|
.input(
|
|
z.object({
|
|
applicationId: z.string(),
|
|
targetProjectId: z.string(),
|
|
}),
|
|
)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const application = await findApplicationById(input.applicationId);
|
|
if (
|
|
application.project.organizationId !== ctx.session.activeOrganizationId
|
|
) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You are not authorized to move this application",
|
|
});
|
|
}
|
|
|
|
const targetProject = await findProjectById(input.targetProjectId);
|
|
if (targetProject.organizationId !== ctx.session.activeOrganizationId) {
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "You are not authorized to move to this project",
|
|
});
|
|
}
|
|
|
|
// Update the application's projectId
|
|
const updatedApplication = await db
|
|
.update(applications)
|
|
.set({
|
|
projectId: input.targetProjectId,
|
|
})
|
|
.where(eq(applications.applicationId, input.applicationId))
|
|
.returning()
|
|
.then((res) => res[0]);
|
|
|
|
if (!updatedApplication) {
|
|
throw new TRPCError({
|
|
code: "INTERNAL_SERVER_ERROR",
|
|
message: "Failed to move application",
|
|
});
|
|
}
|
|
|
|
return updatedApplication;
|
|
}),
|
|
});
|