mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
feat: initial commit
This commit is contained in:
166
server/api/routers/admin.ts
Normal file
166
server/api/routers/admin.ts
Normal file
@@ -0,0 +1,166 @@
|
||||
import {
|
||||
apiAssignPermissions,
|
||||
apiCreateUserInvitation,
|
||||
apiFindOneToken,
|
||||
apiGetBranches,
|
||||
apiRemoveUser,
|
||||
users,
|
||||
} from "@/server/db/schema";
|
||||
import {
|
||||
createInvitation,
|
||||
findAdmin,
|
||||
getUserByToken,
|
||||
removeUserByAuthId,
|
||||
updateAdmin,
|
||||
} from "../services/admin";
|
||||
import {
|
||||
adminProcedure,
|
||||
createTRPCRouter,
|
||||
protectedProcedure,
|
||||
publicProcedure,
|
||||
} from "../trpc";
|
||||
import { db } from "@/server/db";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { Octokit } from "octokit";
|
||||
import { createAppAuth } from "@octokit/auth-app";
|
||||
import { haveGithubRequirements } from "@/server/utils/providers/github";
|
||||
|
||||
export const adminRouter = createTRPCRouter({
|
||||
one: adminProcedure.query(async () => {
|
||||
const { sshPrivateKey, ...rest } = await findAdmin();
|
||||
return {
|
||||
haveSSH: !!sshPrivateKey,
|
||||
...rest,
|
||||
};
|
||||
}),
|
||||
createUserInvitation: adminProcedure
|
||||
.input(apiCreateUserInvitation)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
await createInvitation(input);
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message:
|
||||
"Error to create this user\ncheck if the email is not registered",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
removeUser: adminProcedure
|
||||
.input(apiRemoveUser)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
return await removeUserByAuthId(input.authId);
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to delete this user",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
getUserByToken: publicProcedure
|
||||
.input(apiFindOneToken)
|
||||
.query(async ({ input }) => {
|
||||
return await getUserByToken(input.token);
|
||||
}),
|
||||
assignPermissions: adminProcedure
|
||||
.input(apiAssignPermissions)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
await db
|
||||
.update(users)
|
||||
.set({
|
||||
...input,
|
||||
})
|
||||
.where(eq(users.userId, input.userId));
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to assign permissions",
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
cleanGithubApp: adminProcedure.mutation(async ({ ctx }) => {
|
||||
try {
|
||||
return await updateAdmin(ctx.user.authId, {
|
||||
githubAppName: "",
|
||||
githubClientId: "",
|
||||
githubClientSecret: "",
|
||||
githubInstallationId: "",
|
||||
});
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to delete this github app",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
getRepositories: protectedProcedure.query(async () => {
|
||||
const admin = await findAdmin();
|
||||
|
||||
const completeRequirements = haveGithubRequirements(admin);
|
||||
|
||||
if (!completeRequirements) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Admin need to setup correctly github account",
|
||||
});
|
||||
}
|
||||
|
||||
const octokit = new Octokit({
|
||||
authStrategy: createAppAuth,
|
||||
auth: {
|
||||
appId: admin.githubAppId,
|
||||
privateKey: admin.githubPrivateKey,
|
||||
installationId: admin.githubInstallationId,
|
||||
},
|
||||
});
|
||||
|
||||
const repositories = (await octokit.paginate(
|
||||
octokit.rest.apps.listReposAccessibleToInstallation,
|
||||
)) as unknown as Awaited<
|
||||
ReturnType<typeof octokit.rest.apps.listReposAccessibleToInstallation>
|
||||
>["data"]["repositories"];
|
||||
|
||||
return repositories;
|
||||
}),
|
||||
getBranches: protectedProcedure
|
||||
.input(apiGetBranches)
|
||||
.query(async ({ input }) => {
|
||||
const admin = await findAdmin();
|
||||
|
||||
const completeRequirements = haveGithubRequirements(admin);
|
||||
|
||||
if (!completeRequirements) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Admin need to setup correctly github account",
|
||||
});
|
||||
}
|
||||
|
||||
const octokit = new Octokit({
|
||||
authStrategy: createAppAuth,
|
||||
auth: {
|
||||
appId: admin.githubAppId,
|
||||
privateKey: admin.githubPrivateKey,
|
||||
installationId: admin.githubInstallationId,
|
||||
},
|
||||
});
|
||||
const branches = await octokit.rest.repos.listBranches({
|
||||
owner: input.owner,
|
||||
repo: input.repo,
|
||||
});
|
||||
return branches.data;
|
||||
}),
|
||||
haveGithubConfigured: protectedProcedure.query(async () => {
|
||||
const adminResponse = await findAdmin();
|
||||
|
||||
return haveGithubRequirements(adminResponse);
|
||||
}),
|
||||
});
|
||||
339
server/api/routers/application.ts
Normal file
339
server/api/routers/application.ts
Normal file
@@ -0,0 +1,339 @@
|
||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||
import { db } from "@/server/db";
|
||||
import {
|
||||
apiCreateApplication,
|
||||
apiFindMonitoringStats,
|
||||
apiFindOneApplication,
|
||||
apiReloadApplication,
|
||||
apiSaveBuildType,
|
||||
apiSaveDockerProvider,
|
||||
apiSaveEnviromentVariables,
|
||||
apiSaveGitProvider,
|
||||
apiSaveGithubProvider,
|
||||
apiUpdateApplication,
|
||||
applications,
|
||||
} from "@/server/db/schema/application";
|
||||
import {
|
||||
cleanQueuesByApplication,
|
||||
type DeploymentJob,
|
||||
} from "@/server/queues/deployments-queue";
|
||||
import { myQueue } from "@/server/queues/queueSetup";
|
||||
import {
|
||||
removeService,
|
||||
startService,
|
||||
stopService,
|
||||
} from "@/server/utils/docker/utils";
|
||||
import {
|
||||
removeDirectoryCode,
|
||||
removeMonitoringDirectory,
|
||||
} from "@/server/utils/filesystem/directory";
|
||||
import {
|
||||
generateSSHKey,
|
||||
readRSAFile,
|
||||
removeRSAFiles,
|
||||
} from "@/server/utils/filesystem/ssh";
|
||||
import {
|
||||
readConfig,
|
||||
removeTraefikConfig,
|
||||
writeConfig,
|
||||
} from "@/server/utils/traefik/application";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { eq } from "drizzle-orm";
|
||||
import {
|
||||
createApplication,
|
||||
findApplicationById,
|
||||
getApplicationStats,
|
||||
updateApplication,
|
||||
updateApplicationStatus,
|
||||
} from "../services/application";
|
||||
import { removeDeployments } from "../services/deployment";
|
||||
import { deleteAllMiddlewares } from "@/server/utils/traefik/middleware";
|
||||
import { z } from "zod";
|
||||
import { nanoid } from "nanoid";
|
||||
import { addNewService, checkServiceAccess } from "../services/user";
|
||||
|
||||
export const applicationRouter = createTRPCRouter({
|
||||
create: protectedProcedure
|
||||
.input(apiCreateApplication)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
if (ctx.user.rol === "user") {
|
||||
await checkServiceAccess(ctx.user.authId, input.projectId, "create");
|
||||
}
|
||||
const newApplication = await createApplication(input);
|
||||
|
||||
if (ctx.user.rol === "user") {
|
||||
await addNewService(ctx.user.authId, newApplication.applicationId);
|
||||
}
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to create the application",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
one: protectedProcedure
|
||||
.input(apiFindOneApplication)
|
||||
.query(async ({ input, ctx }) => {
|
||||
if (ctx.user.rol === "user") {
|
||||
await checkServiceAccess(
|
||||
ctx.user.authId,
|
||||
input.applicationId,
|
||||
"access",
|
||||
);
|
||||
}
|
||||
return await findApplicationById(input.applicationId);
|
||||
}),
|
||||
|
||||
reload: protectedProcedure
|
||||
.input(apiReloadApplication)
|
||||
.mutation(async ({ input }) => {
|
||||
await stopService(input.appName);
|
||||
await updateApplicationStatus(input.applicationId, "idle");
|
||||
await startService(input.appName);
|
||||
await updateApplicationStatus(input.applicationId, "done");
|
||||
return true;
|
||||
}),
|
||||
|
||||
delete: protectedProcedure
|
||||
.input(apiFindOneApplication)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
if (ctx.user.rol === "user") {
|
||||
await checkServiceAccess(
|
||||
ctx.user.authId,
|
||||
input.applicationId,
|
||||
"delete",
|
||||
);
|
||||
}
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
|
||||
const result = await db
|
||||
.delete(applications)
|
||||
.where(eq(applications.applicationId, input.applicationId))
|
||||
.returning();
|
||||
|
||||
const cleanupOperations = [
|
||||
async () => deleteAllMiddlewares(application),
|
||||
async () => await removeDeployments(application),
|
||||
async () => await removeDirectoryCode(application?.appName),
|
||||
async () => await removeMonitoringDirectory(application?.appName),
|
||||
async () => await removeTraefikConfig(application?.appName),
|
||||
async () => await removeService(application?.appName),
|
||||
async () => await removeRSAFiles(application?.appName),
|
||||
];
|
||||
|
||||
for (const operation of cleanupOperations) {
|
||||
try {
|
||||
await operation();
|
||||
} catch (error) {}
|
||||
}
|
||||
|
||||
return result[0];
|
||||
}),
|
||||
|
||||
stop: protectedProcedure
|
||||
.input(apiFindOneApplication)
|
||||
.mutation(async ({ input }) => {
|
||||
const service = await findApplicationById(input.applicationId);
|
||||
await stopService(service.appName);
|
||||
await updateApplicationStatus(input.applicationId, "idle");
|
||||
|
||||
return service;
|
||||
}),
|
||||
|
||||
start: protectedProcedure
|
||||
.input(apiFindOneApplication)
|
||||
.mutation(async ({ input }) => {
|
||||
const service = await findApplicationById(input.applicationId);
|
||||
|
||||
await startService(service.appName);
|
||||
await updateApplicationStatus(input.applicationId, "done");
|
||||
|
||||
return service;
|
||||
}),
|
||||
|
||||
redeploy: protectedProcedure
|
||||
.input(apiFindOneApplication)
|
||||
.mutation(async ({ input }) => {
|
||||
const jobData: DeploymentJob = {
|
||||
applicationId: input.applicationId,
|
||||
titleLog: "Rebuild deployment",
|
||||
type: "redeploy",
|
||||
};
|
||||
await myQueue.add(
|
||||
"deployments",
|
||||
{ ...jobData },
|
||||
{
|
||||
removeOnComplete: true,
|
||||
removeOnFail: true,
|
||||
},
|
||||
);
|
||||
}),
|
||||
saveEnviroment: protectedProcedure
|
||||
.input(apiSaveEnviromentVariables)
|
||||
.mutation(async ({ input }) => {
|
||||
await updateApplication(input.applicationId, {
|
||||
env: input.env,
|
||||
});
|
||||
return true;
|
||||
}),
|
||||
saveBuildType: protectedProcedure
|
||||
.input(apiSaveBuildType)
|
||||
.mutation(async ({ input }) => {
|
||||
await updateApplication(input.applicationId, {
|
||||
buildType: input.buildType,
|
||||
dockerfile: input.dockerfile,
|
||||
});
|
||||
|
||||
return true;
|
||||
}),
|
||||
saveGithubProvider: protectedProcedure
|
||||
.input(apiSaveGithubProvider)
|
||||
.mutation(async ({ input }) => {
|
||||
await updateApplication(input.applicationId, {
|
||||
repository: input.repository,
|
||||
branch: input.branch,
|
||||
sourceType: "github",
|
||||
owner: input.owner,
|
||||
buildPath: input.buildPath,
|
||||
applicationStatus: "idle",
|
||||
});
|
||||
|
||||
return true;
|
||||
}),
|
||||
saveDockerProvider: protectedProcedure
|
||||
.input(apiSaveDockerProvider)
|
||||
.mutation(async ({ input }) => {
|
||||
await updateApplication(input.applicationId, {
|
||||
dockerImage: input.dockerImage,
|
||||
username: input.username,
|
||||
password: input.password,
|
||||
sourceType: "docker",
|
||||
applicationStatus: "idle",
|
||||
});
|
||||
|
||||
return true;
|
||||
}),
|
||||
saveGitProdiver: protectedProcedure
|
||||
.input(apiSaveGitProvider)
|
||||
.mutation(async ({ input }) => {
|
||||
await updateApplication(input.applicationId, {
|
||||
customGitBranch: input.customGitBranch,
|
||||
customGitBuildPath: input.customGitBuildPath,
|
||||
customGitUrl: input.customGitUrl,
|
||||
sourceType: "git",
|
||||
applicationStatus: "idle",
|
||||
});
|
||||
|
||||
return true;
|
||||
}),
|
||||
generateSSHKey: protectedProcedure
|
||||
.input(apiFindOneApplication)
|
||||
.mutation(async ({ input }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
try {
|
||||
await generateSSHKey(application.appName);
|
||||
const file = await readRSAFile(application.appName);
|
||||
|
||||
await updateApplication(input.applicationId, {
|
||||
customGitSSHKey: file,
|
||||
});
|
||||
} catch (error) {}
|
||||
|
||||
return true;
|
||||
}),
|
||||
removeSSHKey: protectedProcedure
|
||||
.input(apiFindOneApplication)
|
||||
.mutation(async ({ input }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
await removeRSAFiles(application.appName);
|
||||
await updateApplication(input.applicationId, {
|
||||
customGitSSHKey: null,
|
||||
});
|
||||
|
||||
return true;
|
||||
}),
|
||||
markRunning: protectedProcedure
|
||||
.input(apiFindOneApplication)
|
||||
.mutation(async ({ input }) => {
|
||||
await updateApplicationStatus(input.applicationId, "running");
|
||||
}),
|
||||
update: protectedProcedure
|
||||
.input(apiUpdateApplication)
|
||||
.mutation(async ({ input }) => {
|
||||
const { applicationId, ...rest } = input;
|
||||
const application = await updateApplication(applicationId, {
|
||||
...rest,
|
||||
});
|
||||
|
||||
if (!application) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Update: Error to update application",
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}),
|
||||
refreshToken: protectedProcedure
|
||||
.input(apiFindOneApplication)
|
||||
.mutation(async ({ input }) => {
|
||||
await updateApplication(input.applicationId, {
|
||||
refreshToken: nanoid(),
|
||||
});
|
||||
return true;
|
||||
}),
|
||||
deploy: protectedProcedure
|
||||
.input(apiFindOneApplication)
|
||||
.mutation(async ({ input }) => {
|
||||
const jobData: DeploymentJob = {
|
||||
applicationId: input.applicationId,
|
||||
titleLog: "Manual deployment",
|
||||
type: "deploy",
|
||||
};
|
||||
await myQueue.add(
|
||||
"deployments",
|
||||
{ ...jobData },
|
||||
{
|
||||
removeOnComplete: true,
|
||||
removeOnFail: true,
|
||||
},
|
||||
);
|
||||
}),
|
||||
|
||||
cleanQueues: protectedProcedure
|
||||
.input(apiFindOneApplication)
|
||||
.mutation(async ({ input }) => {
|
||||
await cleanQueuesByApplication(input.applicationId);
|
||||
}),
|
||||
|
||||
readTraefikConfig: protectedProcedure
|
||||
.input(apiFindOneApplication)
|
||||
.query(async ({ input }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
|
||||
const traefikConfig = readConfig(application.appName);
|
||||
return traefikConfig;
|
||||
}),
|
||||
|
||||
updateTraefikConfig: protectedProcedure
|
||||
.input(z.object({ applicationId: z.string(), traefikConfig: z.string() }))
|
||||
.mutation(async ({ input }) => {
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
writeConfig(application.appName, input.traefikConfig);
|
||||
return true;
|
||||
}),
|
||||
readAppMonitoring: protectedProcedure
|
||||
.input(apiFindMonitoringStats)
|
||||
.query(async ({ input }) => {
|
||||
const stats = await getApplicationStats(input.appName);
|
||||
|
||||
return stats;
|
||||
}),
|
||||
});
|
||||
|
||||
// Paketo Buildpacks: paketobuildpacks/builder-jammy-full Ubuntu 22.04 Jammy Jellyfish full image with buildpacks for Apache HTTPD, Go, Java, Java Native Image, .NET, NGINX, Node.js, PHP, Procfile, Python, and Ruby
|
||||
// Heroku: heroku/builder:22 Heroku-22 (Ubuntu 22.04) base image with buildpacks for Go, Java, Node.js, PHP, Python, Ruby & Scala.
|
||||
// pack build imageName --path ./ --builder paketobuildpacks/builder-jammy-full
|
||||
// pack build prueba-pack --path ./ --builder heroku/builder:22
|
||||
199
server/api/routers/auth.ts
Normal file
199
server/api/routers/auth.ts
Normal file
@@ -0,0 +1,199 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import * as bcrypt from "bcrypt";
|
||||
import {
|
||||
adminProcedure,
|
||||
createTRPCRouter,
|
||||
protectedProcedure,
|
||||
publicProcedure,
|
||||
} from "../trpc";
|
||||
import { lucia, validateRequest } from "@/server/auth/auth";
|
||||
import {
|
||||
apiCreateAdmin,
|
||||
apiCreateUser,
|
||||
apiFindOneAuth,
|
||||
apiUpdateAuthByAdmin,
|
||||
apiLogin,
|
||||
apiUpdateAuth,
|
||||
apiVerify2FA,
|
||||
apiVerifyLogin2FA,
|
||||
} from "@/server/db/schema";
|
||||
import {
|
||||
createAdmin,
|
||||
createUser,
|
||||
findAuthByEmail,
|
||||
findAuthById,
|
||||
generate2FASecret,
|
||||
updateAuthById,
|
||||
verify2FA,
|
||||
} from "../services/auth";
|
||||
|
||||
export const authRouter = createTRPCRouter({
|
||||
createAdmin: publicProcedure
|
||||
.input(apiCreateAdmin)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
try {
|
||||
const newAdmin = await createAdmin(input);
|
||||
const session = await lucia.createSession(newAdmin.id || "", {});
|
||||
ctx.res.appendHeader(
|
||||
"Set-Cookie",
|
||||
lucia.createSessionCookie(session.id).serialize(),
|
||||
);
|
||||
return true;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to create the main admin",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
createUser: publicProcedure
|
||||
.input(apiCreateUser)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
try {
|
||||
const newUser = await createUser(input);
|
||||
const session = await lucia.createSession(newUser?.authId || "", {});
|
||||
ctx.res.appendHeader(
|
||||
"Set-Cookie",
|
||||
lucia.createSessionCookie(session.id).serialize(),
|
||||
);
|
||||
return true;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to create the user",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
login: publicProcedure.input(apiLogin).mutation(async ({ ctx, input }) => {
|
||||
try {
|
||||
const auth = await findAuthByEmail(input.email);
|
||||
|
||||
const correctPassword = bcrypt.compareSync(
|
||||
input.password,
|
||||
auth?.password || "",
|
||||
);
|
||||
|
||||
if (!correctPassword) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Credentials do not match",
|
||||
});
|
||||
}
|
||||
|
||||
if (auth?.is2FAEnabled) {
|
||||
return {
|
||||
is2FAEnabled: true,
|
||||
authId: auth.id,
|
||||
};
|
||||
}
|
||||
|
||||
const session = await lucia.createSession(auth?.id || "", {});
|
||||
|
||||
ctx.res.appendHeader(
|
||||
"Set-Cookie",
|
||||
lucia.createSessionCookie(session.id).serialize(),
|
||||
);
|
||||
return {
|
||||
is2FAEnabled: false,
|
||||
authId: auth?.id,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Credentials do not match",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
get: protectedProcedure.query(async ({ ctx }) => {
|
||||
const auth = await findAuthById(ctx.user.authId);
|
||||
return auth;
|
||||
}),
|
||||
|
||||
logout: protectedProcedure.mutation(async ({ ctx }) => {
|
||||
const { req, res } = ctx;
|
||||
const { session } = await validateRequest(req, res);
|
||||
if (!session) return false;
|
||||
|
||||
await lucia.invalidateSession(session.id);
|
||||
res.setHeader("Set-Cookie", lucia.createBlankSessionCookie().serialize());
|
||||
return true;
|
||||
}),
|
||||
|
||||
update: protectedProcedure
|
||||
.input(apiUpdateAuth)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const auth = await updateAuthById(ctx.user.authId, {
|
||||
...(input.email && { email: input.email }),
|
||||
...(input.password && {
|
||||
password: bcrypt.hashSync(input.password, 10),
|
||||
}),
|
||||
...(input.image && { image: input.image }),
|
||||
});
|
||||
|
||||
return auth;
|
||||
}),
|
||||
|
||||
one: adminProcedure.input(apiFindOneAuth).query(async ({ input }) => {
|
||||
const auth = await findAuthById(input.id);
|
||||
return auth;
|
||||
}),
|
||||
|
||||
updateByAdmin: protectedProcedure
|
||||
.input(apiUpdateAuthByAdmin)
|
||||
.mutation(async ({ input }) => {
|
||||
const auth = await updateAuthById(input.id, {
|
||||
...(input.email && { email: input.email }),
|
||||
...(input.password && {
|
||||
password: bcrypt.hashSync(input.password, 10),
|
||||
}),
|
||||
...(input.image && { image: input.image }),
|
||||
});
|
||||
|
||||
return auth;
|
||||
}),
|
||||
generate2FASecret: protectedProcedure.query(async ({ ctx }) => {
|
||||
return await generate2FASecret(ctx.user.authId);
|
||||
}),
|
||||
verify2FASetup: protectedProcedure
|
||||
.input(apiVerify2FA)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const auth = await findAuthById(ctx.user.authId);
|
||||
|
||||
await verify2FA(auth, input.secret, input.pin);
|
||||
await updateAuthById(auth.id, {
|
||||
is2FAEnabled: true,
|
||||
secret: input.secret,
|
||||
});
|
||||
return auth;
|
||||
}),
|
||||
|
||||
verifyLogin2FA: publicProcedure
|
||||
.input(apiVerifyLogin2FA)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const auth = await findAuthById(input.id);
|
||||
|
||||
await verify2FA(auth, auth.secret || "", input.pin);
|
||||
|
||||
const session = await lucia.createSession(auth.id, {});
|
||||
|
||||
ctx.res.appendHeader(
|
||||
"Set-Cookie",
|
||||
lucia.createSessionCookie(session.id).serialize(),
|
||||
);
|
||||
|
||||
return auth;
|
||||
}),
|
||||
disable2FA: protectedProcedure.mutation(async ({ ctx }) => {
|
||||
const auth = await findAuthById(ctx.user.authId);
|
||||
await updateAuthById(auth.id, {
|
||||
is2FAEnabled: false,
|
||||
secret: null,
|
||||
});
|
||||
return auth;
|
||||
}),
|
||||
});
|
||||
152
server/api/routers/backup.ts
Normal file
152
server/api/routers/backup.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||
import {
|
||||
apiCreateBackup,
|
||||
apiFindOneBackup,
|
||||
apiRemoveBackup,
|
||||
apiUpdateBackup,
|
||||
} from "@/server/db/schema";
|
||||
import { runMariadbBackup } from "@/server/utils/backups/mariadb";
|
||||
import { runMongoBackup } from "@/server/utils/backups/mongo";
|
||||
import { runMySqlBackup } from "@/server/utils/backups/mysql";
|
||||
import { runPostgresBackup } from "@/server/utils/backups/postgres";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import {
|
||||
createBackup,
|
||||
findBackupById,
|
||||
removeBackupById,
|
||||
updateBackupById,
|
||||
} from "../services/backup";
|
||||
import { findMariadbByBackupId } from "../services/mariadb";
|
||||
import { findMongoByBackupId } from "../services/mongo";
|
||||
import { findMySqlByBackupId } from "../services/mysql";
|
||||
import { findPostgresByBackupId } from "../services/postgres";
|
||||
import {
|
||||
removeScheduleBackup,
|
||||
scheduleBackup,
|
||||
} from "@/server/utils/backups/utils";
|
||||
|
||||
export const backupRouter = createTRPCRouter({
|
||||
create: protectedProcedure
|
||||
.input(apiCreateBackup)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
const newBackup = await createBackup(input);
|
||||
|
||||
const backup = await findBackupById(newBackup.backupId);
|
||||
|
||||
if (backup.enabled) {
|
||||
scheduleBackup(backup);
|
||||
}
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to create the Backup",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
one: protectedProcedure.input(apiFindOneBackup).query(async ({ input }) => {
|
||||
const backup = await findBackupById(input.backupId);
|
||||
return backup;
|
||||
}),
|
||||
update: protectedProcedure
|
||||
.input(apiUpdateBackup)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
await updateBackupById(input.backupId, input);
|
||||
const backup = await findBackupById(input.backupId);
|
||||
|
||||
if (backup.enabled) {
|
||||
scheduleBackup(backup);
|
||||
} else {
|
||||
removeScheduleBackup(input.backupId);
|
||||
}
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to update this Backup",
|
||||
});
|
||||
}
|
||||
}),
|
||||
remove: protectedProcedure
|
||||
.input(apiRemoveBackup)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
const value = await removeBackupById(input.backupId);
|
||||
removeScheduleBackup(input.backupId);
|
||||
return value;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to delete this Backup",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
manualBackupPostgres: protectedProcedure
|
||||
.input(apiFindOneBackup)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
const backup = await findBackupById(input.backupId);
|
||||
const postgres = await findPostgresByBackupId(backup.backupId);
|
||||
await runPostgresBackup(postgres, backup);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to run manual postgres backup ",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
manualBackupMySql: protectedProcedure
|
||||
.input(apiFindOneBackup)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
const backup = await findBackupById(input.backupId);
|
||||
const mysql = await findMySqlByBackupId(backup.backupId);
|
||||
await runMySqlBackup(mysql, backup);
|
||||
return true;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to run manual mysql backup ",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
manualBackupMariadb: protectedProcedure
|
||||
.input(apiFindOneBackup)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
const backup = await findBackupById(input.backupId);
|
||||
const mariadb = await findMariadbByBackupId(backup.backupId);
|
||||
await runMariadbBackup(mariadb, backup);
|
||||
return true;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to run manual mariadb backup ",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
manualBackupMongo: protectedProcedure
|
||||
.input(apiFindOneBackup)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
const backup = await findBackupById(input.backupId);
|
||||
const mongo = await findMongoByBackupId(backup.backupId);
|
||||
await runMongoBackup(mongo, backup);
|
||||
return true;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to run manual mongo backup ",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
});
|
||||
29
server/api/routers/certificate.ts
Normal file
29
server/api/routers/certificate.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { adminProcedure, createTRPCRouter } from "@/server/api/trpc";
|
||||
import { apiCreateCertificate, apiFindCertificate } from "@/server/db/schema";
|
||||
import {
|
||||
createCertificate,
|
||||
findCertificates,
|
||||
findCertificateById,
|
||||
removeCertificateById,
|
||||
} from "../services/certificate";
|
||||
|
||||
export const certificateRouter = createTRPCRouter({
|
||||
create: adminProcedure
|
||||
.input(apiCreateCertificate)
|
||||
.mutation(async ({ input }) => {
|
||||
return await createCertificate(input);
|
||||
}),
|
||||
|
||||
one: adminProcedure.input(apiFindCertificate).query(async ({ input }) => {
|
||||
return await findCertificateById(input.certificateId);
|
||||
}),
|
||||
remove: adminProcedure
|
||||
.input(apiFindCertificate)
|
||||
.mutation(async ({ input }) => {
|
||||
await removeCertificateById(input.certificateId);
|
||||
return true;
|
||||
}),
|
||||
all: adminProcedure.query(async () => {
|
||||
return findCertificates();
|
||||
}),
|
||||
});
|
||||
11
server/api/routers/deployment.ts
Normal file
11
server/api/routers/deployment.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { apiFindAllByApplication } from "@/server/db/schema";
|
||||
import { findAllDeploymentsByApplicationId } from "../services/deployment";
|
||||
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
||||
|
||||
export const deploymentRouter = createTRPCRouter({
|
||||
all: protectedProcedure
|
||||
.input(apiFindAllByApplication)
|
||||
.query(async ({ input }) => {
|
||||
return await findAllDeploymentsByApplicationId(input.applicationId);
|
||||
}),
|
||||
});
|
||||
99
server/api/routers/destination.ts
Normal file
99
server/api/routers/destination.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import {
|
||||
adminProcedure,
|
||||
createTRPCRouter,
|
||||
protectedProcedure,
|
||||
} from "@/server/api/trpc";
|
||||
import { db } from "@/server/db";
|
||||
import {
|
||||
apiCreateDestination,
|
||||
apiFindOneDestination,
|
||||
apiRemoveDestination,
|
||||
apiUpdateDestination,
|
||||
} from "@/server/db/schema";
|
||||
import { HeadBucketCommand, S3Client } from "@aws-sdk/client-s3";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import {
|
||||
createDestintation,
|
||||
findDestinationById,
|
||||
removeDestinationById,
|
||||
updateDestinationById,
|
||||
} from "../services/destination";
|
||||
import { findAdmin } from "../services/admin";
|
||||
|
||||
export const destinationRouter = createTRPCRouter({
|
||||
create: adminProcedure
|
||||
.input(apiCreateDestination)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
await createDestintation(input);
|
||||
return await findAdmin();
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to create the destination",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
testConnection: adminProcedure
|
||||
.input(apiCreateDestination)
|
||||
.mutation(async ({ input }) => {
|
||||
const { secretAccessKey, bucket, region, endpoint, accessKey } = input;
|
||||
const s3Client = new S3Client({
|
||||
region: region,
|
||||
...(endpoint && {
|
||||
endpoint: endpoint,
|
||||
}),
|
||||
credentials: {
|
||||
accessKeyId: accessKey,
|
||||
secretAccessKey: secretAccessKey,
|
||||
},
|
||||
forcePathStyle: true,
|
||||
});
|
||||
const headBucketCommand = new HeadBucketCommand({ Bucket: bucket });
|
||||
|
||||
try {
|
||||
await s3Client.send(headBucketCommand);
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to connect to bucket",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
one: protectedProcedure
|
||||
.input(apiFindOneDestination)
|
||||
.query(async ({ input }) => {
|
||||
const destination = await findDestinationById(input.destinationId);
|
||||
return destination;
|
||||
}),
|
||||
all: adminProcedure.query(async () => {
|
||||
return await db.query.destinations.findMany({});
|
||||
}),
|
||||
remove: adminProcedure
|
||||
.input(apiRemoveDestination)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
return await removeDestinationById(input.destinationId);
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to delete this destination",
|
||||
});
|
||||
}
|
||||
}),
|
||||
update: adminProcedure
|
||||
.input(apiUpdateDestination)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
return await updateDestinationById(input.destinationId, input);
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to update this destination",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
});
|
||||
44
server/api/routers/docker.ts
Normal file
44
server/api/routers/docker.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { z } from "zod";
|
||||
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
||||
import {
|
||||
getConfig,
|
||||
getContainersByAppLabel,
|
||||
getContainers,
|
||||
getContainersByAppNameMatch,
|
||||
} from "../services/docker";
|
||||
|
||||
export const dockerRouter = createTRPCRouter({
|
||||
getContainers: protectedProcedure.query(async () => {
|
||||
return await getContainers();
|
||||
}),
|
||||
|
||||
getConfig: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
containerId: z.string().min(1),
|
||||
}),
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
return await getConfig(input.containerId);
|
||||
}),
|
||||
|
||||
getContainersByAppNameMatch: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
appName: z.string().min(1),
|
||||
}),
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
return await getContainersByAppNameMatch(input.appName);
|
||||
}),
|
||||
|
||||
getContainersByAppLabel: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
appName: z.string().min(1),
|
||||
}),
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
return await getContainersByAppLabel(input.appName);
|
||||
}),
|
||||
});
|
||||
59
server/api/routers/domain.ts
Normal file
59
server/api/routers/domain.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||
import {
|
||||
apiCreateDomain,
|
||||
apiFindDomain,
|
||||
apiFindDomainByApplication,
|
||||
apiUpdateDomain,
|
||||
} from "@/server/db/schema";
|
||||
import { manageDomain, removeDomain } from "@/server/utils/traefik/domain";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { findApplicationById } from "../services/application";
|
||||
import {
|
||||
createDomain,
|
||||
findDomainById,
|
||||
findDomainsByApplicationId,
|
||||
removeDomainById,
|
||||
updateDomainById,
|
||||
} from "../services/domain";
|
||||
|
||||
export const domainRouter = createTRPCRouter({
|
||||
create: protectedProcedure
|
||||
.input(apiCreateDomain)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
await createDomain(input);
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to create the domain",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
byApplicationId: protectedProcedure
|
||||
.input(apiFindDomainByApplication)
|
||||
.query(async ({ input }) => {
|
||||
return await findDomainsByApplicationId(input.applicationId);
|
||||
}),
|
||||
update: protectedProcedure
|
||||
.input(apiUpdateDomain)
|
||||
.mutation(async ({ input }) => {
|
||||
const result = await updateDomainById(input.domainId, input);
|
||||
const domain = await findDomainById(input.domainId);
|
||||
const application = await findApplicationById(domain.applicationId);
|
||||
await manageDomain(application, domain);
|
||||
return result;
|
||||
}),
|
||||
one: protectedProcedure.input(apiFindDomain).query(async ({ input }) => {
|
||||
return await findDomainById(input.domainId);
|
||||
}),
|
||||
delete: protectedProcedure
|
||||
.input(apiFindDomain)
|
||||
.mutation(async ({ input }) => {
|
||||
const domain = await findDomainById(input.domainId);
|
||||
const result = await removeDomainById(input.domainId);
|
||||
removeDomain(domain.application.appName, domain.uniqueConfigKey);
|
||||
|
||||
return result;
|
||||
}),
|
||||
});
|
||||
183
server/api/routers/mariadb.ts
Normal file
183
server/api/routers/mariadb.ts
Normal file
@@ -0,0 +1,183 @@
|
||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||
import {
|
||||
apiChangeMariaDBStatus,
|
||||
apiCreateMariaDB,
|
||||
apiDeployMariaDB,
|
||||
apiFindOneMariaDB,
|
||||
apiResetMariadb,
|
||||
apiSaveEnviromentVariablesMariaDB,
|
||||
apiSaveExternalPortMariaDB,
|
||||
apiUpdateMariaDB,
|
||||
} from "@/server/db/schema/mariadb";
|
||||
import {
|
||||
removeService,
|
||||
startService,
|
||||
stopService,
|
||||
} from "@/server/utils/docker/utils";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import {
|
||||
createMariadb,
|
||||
deployMariadb,
|
||||
findMariadbById,
|
||||
removeMariadbById,
|
||||
updateMariadbById,
|
||||
} from "../services/mariadb";
|
||||
import { addNewService, checkServiceAccess } from "../services/user";
|
||||
import { createMount } from "../services/mount";
|
||||
|
||||
export const mariadbRouter = createTRPCRouter({
|
||||
create: protectedProcedure
|
||||
.input(apiCreateMariaDB)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
if (ctx.user.rol === "user") {
|
||||
await checkServiceAccess(ctx.user.authId, input.projectId, "create");
|
||||
}
|
||||
|
||||
const newMariadb = await createMariadb(input);
|
||||
if (ctx.user.rol === "user") {
|
||||
await addNewService(ctx.user.authId, newMariadb.mariadbId);
|
||||
}
|
||||
|
||||
await createMount({
|
||||
serviceId: newMariadb.mariadbId,
|
||||
serviceType: "mariadb",
|
||||
volumeName: `${newMariadb.appName}-data`,
|
||||
mountPath: "/var/lib/mysql",
|
||||
type: "volume",
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error input: Inserting mariadb database",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
one: protectedProcedure
|
||||
.input(apiFindOneMariaDB)
|
||||
.query(async ({ input, ctx }) => {
|
||||
if (ctx.user.rol === "user") {
|
||||
await checkServiceAccess(ctx.user.authId, input.mariadbId, "access");
|
||||
}
|
||||
return await findMariadbById(input.mariadbId);
|
||||
}),
|
||||
|
||||
start: protectedProcedure
|
||||
.input(apiFindOneMariaDB)
|
||||
.mutation(async ({ input }) => {
|
||||
const service = await findMariadbById(input.mariadbId);
|
||||
|
||||
await startService(service.appName);
|
||||
await updateMariadbById(input.mariadbId, {
|
||||
applicationStatus: "done",
|
||||
});
|
||||
|
||||
return service;
|
||||
}),
|
||||
stop: protectedProcedure
|
||||
.input(apiFindOneMariaDB)
|
||||
.mutation(async ({ input }) => {
|
||||
const mongo = await findMariadbById(input.mariadbId);
|
||||
await stopService(mongo.appName);
|
||||
await updateMariadbById(input.mariadbId, {
|
||||
applicationStatus: "idle",
|
||||
});
|
||||
|
||||
return mongo;
|
||||
}),
|
||||
saveExternalPort: protectedProcedure
|
||||
.input(apiSaveExternalPortMariaDB)
|
||||
.mutation(async ({ input }) => {
|
||||
const mongo = await findMariadbById(input.mariadbId);
|
||||
await updateMariadbById(input.mariadbId, {
|
||||
externalPort: input.externalPort,
|
||||
});
|
||||
await deployMariadb(input.mariadbId);
|
||||
return mongo;
|
||||
}),
|
||||
deploy: protectedProcedure
|
||||
.input(apiDeployMariaDB)
|
||||
.mutation(async ({ input }) => {
|
||||
return deployMariadb(input.mariadbId);
|
||||
}),
|
||||
changeStatus: protectedProcedure
|
||||
.input(apiChangeMariaDBStatus)
|
||||
.mutation(async ({ input }) => {
|
||||
const mongo = await findMariadbById(input.mariadbId);
|
||||
await updateMariadbById(input.mariadbId, {
|
||||
applicationStatus: input.applicationStatus,
|
||||
});
|
||||
return mongo;
|
||||
}),
|
||||
remove: protectedProcedure
|
||||
.input(apiFindOneMariaDB)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
if (ctx.user.rol === "user") {
|
||||
await checkServiceAccess(ctx.user.authId, input.mariadbId, "delete");
|
||||
}
|
||||
|
||||
const mongo = await findMariadbById(input.mariadbId);
|
||||
|
||||
const cleanupOperations = [
|
||||
async () => await removeService(mongo?.appName),
|
||||
async () => await removeMariadbById(input.mariadbId),
|
||||
];
|
||||
|
||||
for (const operation of cleanupOperations) {
|
||||
try {
|
||||
await operation();
|
||||
} catch (error) {}
|
||||
}
|
||||
|
||||
return mongo;
|
||||
}),
|
||||
saveEnviroment: protectedProcedure
|
||||
.input(apiSaveEnviromentVariablesMariaDB)
|
||||
.mutation(async ({ input }) => {
|
||||
const service = await updateMariadbById(input.mariadbId, {
|
||||
env: input.env,
|
||||
});
|
||||
|
||||
if (!service) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Update: Error to add enviroment variables",
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}),
|
||||
reload: protectedProcedure
|
||||
.input(apiResetMariadb)
|
||||
.mutation(async ({ input }) => {
|
||||
await stopService(input.appName);
|
||||
await updateMariadbById(input.mariadbId, {
|
||||
applicationStatus: "idle",
|
||||
});
|
||||
await startService(input.appName);
|
||||
await updateMariadbById(input.mariadbId, {
|
||||
applicationStatus: "done",
|
||||
});
|
||||
return true;
|
||||
}),
|
||||
update: protectedProcedure
|
||||
.input(apiUpdateMariaDB)
|
||||
.mutation(async ({ input }) => {
|
||||
const { mariadbId, ...rest } = input;
|
||||
const service = await updateMariadbById(mariadbId, {
|
||||
...rest,
|
||||
});
|
||||
|
||||
if (!service) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Update: Error to update mariadb",
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}),
|
||||
});
|
||||
184
server/api/routers/mongo.ts
Normal file
184
server/api/routers/mongo.ts
Normal file
@@ -0,0 +1,184 @@
|
||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||
import {
|
||||
apiChangeMongoStatus,
|
||||
apiCreateMongo,
|
||||
apiDeployMongo,
|
||||
apiFindOneMongo,
|
||||
apiResetMongo,
|
||||
apiSaveEnviromentVariablesMongo,
|
||||
apiSaveExternalPortMongo,
|
||||
apiUpdateMongo,
|
||||
} from "@/server/db/schema/mongo";
|
||||
import {
|
||||
removeService,
|
||||
startService,
|
||||
stopService,
|
||||
} from "@/server/utils/docker/utils";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import {
|
||||
createMongo,
|
||||
deployMongo,
|
||||
findMongoById,
|
||||
removeMongoById,
|
||||
updateMongoById,
|
||||
} from "../services/mongo";
|
||||
import { addNewService, checkServiceAccess } from "../services/user";
|
||||
import { createMount } from "../services/mount";
|
||||
|
||||
export const mongoRouter = createTRPCRouter({
|
||||
create: protectedProcedure
|
||||
.input(apiCreateMongo)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
if (ctx.user.rol === "user") {
|
||||
await checkServiceAccess(ctx.user.authId, input.projectId, "create");
|
||||
}
|
||||
|
||||
const newMongo = await createMongo(input);
|
||||
if (ctx.user.rol === "user") {
|
||||
await addNewService(ctx.user.authId, newMongo.mongoId);
|
||||
}
|
||||
|
||||
await createMount({
|
||||
serviceId: newMongo.mongoId,
|
||||
serviceType: "mongo",
|
||||
volumeName: `${newMongo.appName}-data`,
|
||||
mountPath: "/data/db",
|
||||
type: "volume",
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error input: Inserting mongo database",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
one: protectedProcedure
|
||||
.input(apiFindOneMongo)
|
||||
.query(async ({ input, ctx }) => {
|
||||
if (ctx.user.rol === "user") {
|
||||
await checkServiceAccess(ctx.user.authId, input.mongoId, "access");
|
||||
}
|
||||
|
||||
return await findMongoById(input.mongoId);
|
||||
}),
|
||||
|
||||
start: protectedProcedure
|
||||
.input(apiFindOneMongo)
|
||||
.mutation(async ({ input }) => {
|
||||
const service = await findMongoById(input.mongoId);
|
||||
|
||||
await startService(service.appName);
|
||||
await updateMongoById(input.mongoId, {
|
||||
applicationStatus: "done",
|
||||
});
|
||||
|
||||
return service;
|
||||
}),
|
||||
stop: protectedProcedure
|
||||
.input(apiFindOneMongo)
|
||||
.mutation(async ({ input }) => {
|
||||
const mongo = await findMongoById(input.mongoId);
|
||||
await stopService(mongo.appName);
|
||||
await updateMongoById(input.mongoId, {
|
||||
applicationStatus: "idle",
|
||||
});
|
||||
|
||||
return mongo;
|
||||
}),
|
||||
saveExternalPort: protectedProcedure
|
||||
.input(apiSaveExternalPortMongo)
|
||||
.mutation(async ({ input }) => {
|
||||
const mongo = await findMongoById(input.mongoId);
|
||||
await updateMongoById(input.mongoId, {
|
||||
externalPort: input.externalPort,
|
||||
});
|
||||
await deployMongo(input.mongoId);
|
||||
return mongo;
|
||||
}),
|
||||
deploy: protectedProcedure
|
||||
.input(apiDeployMongo)
|
||||
.mutation(async ({ input }) => {
|
||||
return deployMongo(input.mongoId);
|
||||
}),
|
||||
changeStatus: protectedProcedure
|
||||
.input(apiChangeMongoStatus)
|
||||
.mutation(async ({ input }) => {
|
||||
const mongo = await findMongoById(input.mongoId);
|
||||
await updateMongoById(input.mongoId, {
|
||||
applicationStatus: input.applicationStatus,
|
||||
});
|
||||
return mongo;
|
||||
}),
|
||||
reload: protectedProcedure
|
||||
.input(apiResetMongo)
|
||||
.mutation(async ({ input }) => {
|
||||
await stopService(input.appName);
|
||||
await updateMongoById(input.mongoId, {
|
||||
applicationStatus: "idle",
|
||||
});
|
||||
await startService(input.appName);
|
||||
await updateMongoById(input.mongoId, {
|
||||
applicationStatus: "done",
|
||||
});
|
||||
return true;
|
||||
}),
|
||||
remove: protectedProcedure
|
||||
.input(apiFindOneMongo)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
if (ctx.user.rol === "user") {
|
||||
await checkServiceAccess(ctx.user.authId, input.mongoId, "delete");
|
||||
}
|
||||
|
||||
const mongo = await findMongoById(input.mongoId);
|
||||
|
||||
const cleanupOperations = [
|
||||
async () => await removeService(mongo?.appName),
|
||||
async () => await removeMongoById(input.mongoId),
|
||||
];
|
||||
|
||||
for (const operation of cleanupOperations) {
|
||||
try {
|
||||
await operation();
|
||||
} catch (error) {}
|
||||
}
|
||||
|
||||
return mongo;
|
||||
}),
|
||||
saveEnviroment: protectedProcedure
|
||||
.input(apiSaveEnviromentVariablesMongo)
|
||||
.mutation(async ({ input }) => {
|
||||
const service = await updateMongoById(input.mongoId, {
|
||||
env: input.env,
|
||||
});
|
||||
|
||||
if (!service) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Update: Error to add enviroment variables",
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}),
|
||||
update: protectedProcedure
|
||||
.input(apiUpdateMongo)
|
||||
.mutation(async ({ input }) => {
|
||||
const { mongoId, ...rest } = input;
|
||||
const service = await updateMongoById(mongoId, {
|
||||
...rest,
|
||||
});
|
||||
|
||||
if (!service) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Update: Error to update mongo",
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}),
|
||||
});
|
||||
17
server/api/routers/mount.ts
Normal file
17
server/api/routers/mount.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { apiCreateMount, apiRemoveMount } from "@/server/db/schema";
|
||||
import { createMount, deleteMount } from "../services/mount";
|
||||
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
||||
|
||||
export const mountRouter = createTRPCRouter({
|
||||
create: protectedProcedure
|
||||
.input(apiCreateMount)
|
||||
.mutation(async ({ input }) => {
|
||||
await createMount(input);
|
||||
return true;
|
||||
}),
|
||||
remove: protectedProcedure
|
||||
.input(apiRemoveMount)
|
||||
.mutation(async ({ input }) => {
|
||||
return await deleteMount(input.mountId);
|
||||
}),
|
||||
});
|
||||
183
server/api/routers/mysql.ts
Normal file
183
server/api/routers/mysql.ts
Normal file
@@ -0,0 +1,183 @@
|
||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||
import {
|
||||
apiChangeMySqlStatus,
|
||||
apiCreateMySql,
|
||||
apiDeployMySql,
|
||||
apiFindOneMySql,
|
||||
apiResetMysql,
|
||||
apiSaveEnviromentVariablesMySql,
|
||||
apiSaveExternalPortMySql,
|
||||
apiUpdateMySql,
|
||||
} from "@/server/db/schema/mysql";
|
||||
import {
|
||||
removeService,
|
||||
startService,
|
||||
stopService,
|
||||
} from "@/server/utils/docker/utils";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import {
|
||||
createMysql,
|
||||
deployMySql,
|
||||
findMySqlById,
|
||||
removeMySqlById,
|
||||
updateMySqlById,
|
||||
} from "../services/mysql";
|
||||
import { addNewService, checkServiceAccess } from "../services/user";
|
||||
import { createMount } from "../services/mount";
|
||||
import { z } from "zod";
|
||||
|
||||
export const mysqlRouter = createTRPCRouter({
|
||||
create: protectedProcedure
|
||||
.input(apiCreateMySql)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
if (ctx.user.rol === "user") {
|
||||
await checkServiceAccess(ctx.user.authId, input.projectId, "create");
|
||||
}
|
||||
|
||||
const newMysql = await createMysql(input);
|
||||
if (ctx.user.rol === "user") {
|
||||
await addNewService(ctx.user.authId, newMysql.mysqlId);
|
||||
}
|
||||
|
||||
await createMount({
|
||||
serviceId: newMysql.mysqlId,
|
||||
serviceType: "mysql",
|
||||
volumeName: `${newMysql.appName}-data`,
|
||||
mountPath: "/var/lib/mysql",
|
||||
type: "volume",
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error input: Inserting mysql database",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
one: protectedProcedure
|
||||
.input(apiFindOneMySql)
|
||||
.query(async ({ input, ctx }) => {
|
||||
if (ctx.user.rol === "user") {
|
||||
await checkServiceAccess(ctx.user.authId, input.mysqlId, "access");
|
||||
}
|
||||
return await findMySqlById(input.mysqlId);
|
||||
}),
|
||||
|
||||
start: protectedProcedure
|
||||
.input(apiFindOneMySql)
|
||||
.mutation(async ({ input }) => {
|
||||
const service = await findMySqlById(input.mysqlId);
|
||||
|
||||
await startService(service.appName);
|
||||
await updateMySqlById(input.mysqlId, {
|
||||
applicationStatus: "done",
|
||||
});
|
||||
|
||||
return service;
|
||||
}),
|
||||
stop: protectedProcedure
|
||||
.input(apiFindOneMySql)
|
||||
.mutation(async ({ input }) => {
|
||||
const mongo = await findMySqlById(input.mysqlId);
|
||||
await stopService(mongo.appName);
|
||||
await updateMySqlById(input.mysqlId, {
|
||||
applicationStatus: "idle",
|
||||
});
|
||||
|
||||
return mongo;
|
||||
}),
|
||||
saveExternalPort: protectedProcedure
|
||||
.input(apiSaveExternalPortMySql)
|
||||
.mutation(async ({ input }) => {
|
||||
const mongo = await findMySqlById(input.mysqlId);
|
||||
await updateMySqlById(input.mysqlId, {
|
||||
externalPort: input.externalPort,
|
||||
});
|
||||
await deployMySql(input.mysqlId);
|
||||
return mongo;
|
||||
}),
|
||||
deploy: protectedProcedure
|
||||
.input(apiDeployMySql)
|
||||
.mutation(async ({ input }) => {
|
||||
return deployMySql(input.mysqlId);
|
||||
}),
|
||||
changeStatus: protectedProcedure
|
||||
.input(apiChangeMySqlStatus)
|
||||
.mutation(async ({ input }) => {
|
||||
const mongo = await findMySqlById(input.mysqlId);
|
||||
await updateMySqlById(input.mysqlId, {
|
||||
applicationStatus: input.applicationStatus,
|
||||
});
|
||||
return mongo;
|
||||
}),
|
||||
reload: protectedProcedure
|
||||
.input(apiResetMysql)
|
||||
.mutation(async ({ input }) => {
|
||||
await stopService(input.appName);
|
||||
await updateMySqlById(input.mysqlId, {
|
||||
applicationStatus: "idle",
|
||||
});
|
||||
await startService(input.appName);
|
||||
await updateMySqlById(input.mysqlId, {
|
||||
applicationStatus: "done",
|
||||
});
|
||||
return true;
|
||||
}),
|
||||
remove: protectedProcedure
|
||||
.input(apiFindOneMySql)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
if (ctx.user.rol === "user") {
|
||||
await checkServiceAccess(ctx.user.authId, input.mysqlId, "delete");
|
||||
}
|
||||
const mongo = await findMySqlById(input.mysqlId);
|
||||
|
||||
const cleanupOperations = [
|
||||
async () => await removeService(mongo?.appName),
|
||||
async () => await removeMySqlById(input.mysqlId),
|
||||
];
|
||||
|
||||
for (const operation of cleanupOperations) {
|
||||
try {
|
||||
await operation();
|
||||
} catch (error) {}
|
||||
}
|
||||
|
||||
return mongo;
|
||||
}),
|
||||
saveEnviroment: protectedProcedure
|
||||
.input(apiSaveEnviromentVariablesMySql)
|
||||
.mutation(async ({ input }) => {
|
||||
const service = await updateMySqlById(input.mysqlId, {
|
||||
env: input.env,
|
||||
});
|
||||
|
||||
if (!service) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Update: Error to add enviroment variables",
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}),
|
||||
update: protectedProcedure
|
||||
.input(apiUpdateMySql)
|
||||
.mutation(async ({ input }) => {
|
||||
const { mysqlId, ...rest } = input;
|
||||
const service = await updateMySqlById(mysqlId, {
|
||||
...rest,
|
||||
});
|
||||
|
||||
if (!service) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Update: Error to update mysql",
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}),
|
||||
});
|
||||
65
server/api/routers/port.ts
Normal file
65
server/api/routers/port.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||
import {
|
||||
apiCreatePort,
|
||||
apiFindOnePort,
|
||||
apiUpdatePort,
|
||||
} from "@/server/db/schema/port";
|
||||
import {
|
||||
createPort,
|
||||
finPortById,
|
||||
removePortById,
|
||||
updatePortById,
|
||||
} from "../services/port";
|
||||
|
||||
export const portRouter = createTRPCRouter({
|
||||
create: protectedProcedure
|
||||
.input(apiCreatePort)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
await createPort(input);
|
||||
return true;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error input: Inserting port",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
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,
|
||||
});
|
||||
}
|
||||
}),
|
||||
delete: protectedProcedure
|
||||
.input(apiFindOnePort)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
return removePortById(input.portId);
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error input: Deleting port",
|
||||
});
|
||||
}
|
||||
}),
|
||||
update: protectedProcedure
|
||||
.input(apiUpdatePort)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
return updatePortById(input.portId, input);
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to updating port",
|
||||
});
|
||||
}
|
||||
}),
|
||||
});
|
||||
179
server/api/routers/postgres.ts
Normal file
179
server/api/routers/postgres.ts
Normal file
@@ -0,0 +1,179 @@
|
||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||
import {
|
||||
apiChangePostgresStatus,
|
||||
apiCreatePostgres,
|
||||
apiDeployPostgres,
|
||||
apiFindOnePostgres,
|
||||
apiResetPostgres,
|
||||
apiSaveEnviromentVariablesPostgres,
|
||||
apiSaveExternalPortPostgres,
|
||||
apiUpdatePostgres,
|
||||
} from "@/server/db/schema/postgres";
|
||||
import {
|
||||
removeService,
|
||||
startService,
|
||||
stopService,
|
||||
} from "@/server/utils/docker/utils";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import {
|
||||
createPostgres,
|
||||
deployPostgres,
|
||||
findPostgresById,
|
||||
removePostgresById,
|
||||
updatePostgresById,
|
||||
} from "../services/postgres";
|
||||
import { addNewService, checkServiceAccess } from "../services/user";
|
||||
import { createMount } from "../services/mount";
|
||||
|
||||
export const postgresRouter = createTRPCRouter({
|
||||
create: protectedProcedure
|
||||
.input(apiCreatePostgres)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
if (ctx.user.rol === "user") {
|
||||
await checkServiceAccess(ctx.user.authId, input.projectId, "create");
|
||||
}
|
||||
|
||||
const newPostgres = await createPostgres(input);
|
||||
if (ctx.user.rol === "user") {
|
||||
await addNewService(ctx.user.authId, newPostgres.postgresId);
|
||||
}
|
||||
|
||||
await createMount({
|
||||
serviceId: newPostgres.postgresId,
|
||||
serviceType: "postgres",
|
||||
volumeName: `${newPostgres.appName}-data`,
|
||||
mountPath: "/var/lib/postgresql/data",
|
||||
type: "volume",
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error input: Inserting postgresql database",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
one: protectedProcedure
|
||||
.input(apiFindOnePostgres)
|
||||
.query(async ({ input, ctx }) => {
|
||||
if (ctx.user.rol === "user") {
|
||||
await checkServiceAccess(ctx.user.authId, input.postgresId, "access");
|
||||
}
|
||||
|
||||
return await findPostgresById(input.postgresId);
|
||||
}),
|
||||
|
||||
start: protectedProcedure
|
||||
.input(apiFindOnePostgres)
|
||||
.mutation(async ({ input }) => {
|
||||
const service = await findPostgresById(input.postgresId);
|
||||
|
||||
await startService(service.appName);
|
||||
await updatePostgresById(input.postgresId, {
|
||||
applicationStatus: "done",
|
||||
});
|
||||
|
||||
return service;
|
||||
}),
|
||||
stop: protectedProcedure
|
||||
.input(apiFindOnePostgres)
|
||||
.mutation(async ({ input }) => {
|
||||
const postgres = await findPostgresById(input.postgresId);
|
||||
await stopService(postgres.appName);
|
||||
await updatePostgresById(input.postgresId, {
|
||||
applicationStatus: "idle",
|
||||
});
|
||||
|
||||
return postgres;
|
||||
}),
|
||||
saveExternalPort: protectedProcedure
|
||||
.input(apiSaveExternalPortPostgres)
|
||||
.mutation(async ({ input }) => {
|
||||
const postgres = await findPostgresById(input.postgresId);
|
||||
await updatePostgresById(input.postgresId, {
|
||||
externalPort: input.externalPort,
|
||||
});
|
||||
await deployPostgres(input.postgresId);
|
||||
return postgres;
|
||||
}),
|
||||
deploy: protectedProcedure
|
||||
.input(apiDeployPostgres)
|
||||
.mutation(async ({ input }) => {
|
||||
return deployPostgres(input.postgresId);
|
||||
}),
|
||||
changeStatus: protectedProcedure
|
||||
.input(apiChangePostgresStatus)
|
||||
.mutation(async ({ input }) => {
|
||||
const postgres = await findPostgresById(input.postgresId);
|
||||
await updatePostgresById(input.postgresId, {
|
||||
applicationStatus: input.applicationStatus,
|
||||
});
|
||||
return postgres;
|
||||
}),
|
||||
remove: protectedProcedure
|
||||
.input(apiFindOnePostgres)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
if (ctx.user.rol === "user") {
|
||||
await checkServiceAccess(ctx.user.authId, input.postgresId, "delete");
|
||||
}
|
||||
const postgres = await findPostgresById(input.postgresId);
|
||||
|
||||
const cleanupOperations = [
|
||||
removeService(postgres.appName),
|
||||
removePostgresById(input.postgresId),
|
||||
];
|
||||
|
||||
await Promise.allSettled(cleanupOperations);
|
||||
|
||||
return postgres;
|
||||
}),
|
||||
saveEnviroment: protectedProcedure
|
||||
.input(apiSaveEnviromentVariablesPostgres)
|
||||
.mutation(async ({ input }) => {
|
||||
const service = await updatePostgresById(input.postgresId, {
|
||||
env: input.env,
|
||||
});
|
||||
|
||||
if (!service) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Update: Error to add enviroment variables",
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}),
|
||||
reload: protectedProcedure
|
||||
.input(apiResetPostgres)
|
||||
.mutation(async ({ input }) => {
|
||||
await stopService(input.appName);
|
||||
await updatePostgresById(input.postgresId, {
|
||||
applicationStatus: "idle",
|
||||
});
|
||||
await startService(input.appName);
|
||||
await updatePostgresById(input.postgresId, {
|
||||
applicationStatus: "done",
|
||||
});
|
||||
return true;
|
||||
}),
|
||||
update: protectedProcedure
|
||||
.input(apiUpdatePostgres)
|
||||
.mutation(async ({ input }) => {
|
||||
const { postgresId, ...rest } = input;
|
||||
const service = await updatePostgresById(postgresId, {
|
||||
...rest,
|
||||
});
|
||||
|
||||
if (!service) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Update: Error to update postgres",
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}),
|
||||
});
|
||||
197
server/api/routers/project.ts
Normal file
197
server/api/routers/project.ts
Normal file
@@ -0,0 +1,197 @@
|
||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||
import { db } from "@/server/db";
|
||||
import {
|
||||
apiCreateProject,
|
||||
apiFindOneProject,
|
||||
apiRemoveProject,
|
||||
apiUpdateProject,
|
||||
projects,
|
||||
} from "@/server/db/schema/project";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { desc, eq, sql } from "drizzle-orm";
|
||||
import {
|
||||
createProject,
|
||||
deleteProject,
|
||||
findProjectById,
|
||||
updateProjectById,
|
||||
} from "../services/project";
|
||||
import {
|
||||
addNewProject,
|
||||
checkProjectAccess,
|
||||
findUserByAuthId,
|
||||
} from "../services/user";
|
||||
import {
|
||||
applications,
|
||||
mariadb,
|
||||
mongo,
|
||||
mysql,
|
||||
postgres,
|
||||
redis,
|
||||
} from "@/server/db/schema";
|
||||
import type { AnyPgColumn } from "drizzle-orm/pg-core";
|
||||
|
||||
export const projectRouter = createTRPCRouter({
|
||||
create: protectedProcedure
|
||||
.input(apiCreateProject)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
try {
|
||||
if (ctx.user.rol === "user") {
|
||||
await checkProjectAccess(ctx.user.authId, "create");
|
||||
}
|
||||
const project = await createProject(input);
|
||||
if (ctx.user.rol === "user") {
|
||||
await addNewProject(ctx.user.authId, project.projectId);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to create the project",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
one: protectedProcedure
|
||||
.input(apiFindOneProject)
|
||||
.query(async ({ input, ctx }) => {
|
||||
if (ctx.user.rol === "user") {
|
||||
const { accesedServices } = await findUserByAuthId(ctx.user.authId);
|
||||
|
||||
await checkProjectAccess(ctx.user.authId, "access", input.projectId);
|
||||
|
||||
const service = await db.query.projects.findFirst({
|
||||
where: eq(projects.projectId, input.projectId),
|
||||
with: {
|
||||
applications: {
|
||||
where: buildServiceFilter(
|
||||
applications.applicationId,
|
||||
accesedServices,
|
||||
),
|
||||
},
|
||||
mariadb: {
|
||||
where: buildServiceFilter(mariadb.mariadbId, accesedServices),
|
||||
},
|
||||
mongo: {
|
||||
where: buildServiceFilter(mongo.mongoId, accesedServices),
|
||||
},
|
||||
mysql: {
|
||||
where: buildServiceFilter(mysql.mysqlId, accesedServices),
|
||||
},
|
||||
postgres: {
|
||||
where: buildServiceFilter(postgres.postgresId, accesedServices),
|
||||
},
|
||||
redis: {
|
||||
where: buildServiceFilter(redis.redisId, accesedServices),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!service) {
|
||||
throw new TRPCError({
|
||||
code: "NOT_FOUND",
|
||||
message: "Project not found",
|
||||
});
|
||||
}
|
||||
return service;
|
||||
}
|
||||
const project = await findProjectById(input.projectId);
|
||||
return project;
|
||||
}),
|
||||
all: protectedProcedure.query(async ({ ctx }) => {
|
||||
if (ctx.user.rol === "user") {
|
||||
const { accesedProjects, accesedServices } = await findUserByAuthId(
|
||||
ctx.user.authId,
|
||||
);
|
||||
|
||||
if (accesedProjects.length === 0) {
|
||||
return [];
|
||||
}
|
||||
const query = await db.query.projects.findMany({
|
||||
where: sql`${projects.projectId} IN (${sql.join(
|
||||
accesedProjects.map((projectId) => sql`${projectId}`),
|
||||
sql`, `,
|
||||
)})`,
|
||||
with: {
|
||||
applications: {
|
||||
where: buildServiceFilter(
|
||||
applications.applicationId,
|
||||
accesedServices,
|
||||
),
|
||||
},
|
||||
mariadb: {
|
||||
where: buildServiceFilter(mariadb.mariadbId, accesedServices),
|
||||
},
|
||||
mongo: {
|
||||
where: buildServiceFilter(mongo.mongoId, accesedServices),
|
||||
},
|
||||
mysql: {
|
||||
where: buildServiceFilter(mysql.mysqlId, accesedServices),
|
||||
},
|
||||
postgres: {
|
||||
where: buildServiceFilter(postgres.postgresId, accesedServices),
|
||||
},
|
||||
redis: {
|
||||
where: buildServiceFilter(redis.redisId, accesedServices),
|
||||
},
|
||||
},
|
||||
orderBy: desc(projects.createdAt),
|
||||
});
|
||||
|
||||
return query;
|
||||
}
|
||||
return await db.query.projects.findMany({
|
||||
with: {
|
||||
applications: true,
|
||||
mariadb: true,
|
||||
mongo: true,
|
||||
mysql: true,
|
||||
postgres: true,
|
||||
redis: true,
|
||||
},
|
||||
orderBy: desc(projects.createdAt),
|
||||
});
|
||||
}),
|
||||
remove: protectedProcedure
|
||||
.input(apiRemoveProject)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
if (ctx.user.rol === "user") {
|
||||
await checkProjectAccess(ctx.user.authId, "delete");
|
||||
}
|
||||
const project = await deleteProject(input.projectId);
|
||||
|
||||
return project;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to delete this project",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
update: protectedProcedure
|
||||
.input(apiUpdateProject)
|
||||
.mutation(async ({ input }) => {
|
||||
try {
|
||||
const project = updateProjectById(input.projectId, {
|
||||
...input,
|
||||
});
|
||||
|
||||
return project;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error to update this project",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
});
|
||||
function buildServiceFilter(fieldName: AnyPgColumn, accesedServices: string[]) {
|
||||
return accesedServices.length > 0
|
||||
? sql`${fieldName} IN (${sql.join(
|
||||
accesedServices.map((serviceId) => sql`${serviceId}`),
|
||||
sql`, `,
|
||||
)})`
|
||||
: sql`1 = 0`; // Always false condition
|
||||
}
|
||||
33
server/api/routers/redirects.ts
Normal file
33
server/api/routers/redirects.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
||||
import {
|
||||
apiCreateRedirect,
|
||||
apiFindOneRedirect,
|
||||
apiUpdateRedirect,
|
||||
} from "@/server/db/schema";
|
||||
import {
|
||||
createRedirect,
|
||||
findRedirectById,
|
||||
removeRedirectById,
|
||||
updateRedirectById,
|
||||
} from "../services/redirect";
|
||||
|
||||
export const redirectsRouter = createTRPCRouter({
|
||||
create: protectedProcedure
|
||||
.input(apiCreateRedirect)
|
||||
.mutation(async ({ input }) => {
|
||||
return await createRedirect(input);
|
||||
}),
|
||||
one: protectedProcedure.input(apiFindOneRedirect).query(async ({ input }) => {
|
||||
return findRedirectById(input.redirectId);
|
||||
}),
|
||||
delete: protectedProcedure
|
||||
.input(apiFindOneRedirect)
|
||||
.mutation(async ({ input }) => {
|
||||
return removeRedirectById(input.redirectId);
|
||||
}),
|
||||
update: protectedProcedure
|
||||
.input(apiUpdateRedirect)
|
||||
.mutation(async ({ input }) => {
|
||||
return updateRedirectById(input.redirectId, input);
|
||||
}),
|
||||
});
|
||||
183
server/api/routers/redis.ts
Normal file
183
server/api/routers/redis.ts
Normal file
@@ -0,0 +1,183 @@
|
||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||
import {
|
||||
apiChangeRedisStatus,
|
||||
apiCreateRedis,
|
||||
apiDeployRedis,
|
||||
apiFindOneRedis,
|
||||
apiResetRedis,
|
||||
apiSaveEnviromentVariablesRedis,
|
||||
apiSaveExternalPortRedis,
|
||||
apiUpdateRedis,
|
||||
} from "@/server/db/schema/redis";
|
||||
import {
|
||||
removeService,
|
||||
startService,
|
||||
stopService,
|
||||
} from "@/server/utils/docker/utils";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import {
|
||||
createRedis,
|
||||
deployRedis,
|
||||
findRedisById,
|
||||
removeRedisById,
|
||||
updateRedisById,
|
||||
} from "../services/redis";
|
||||
import { addNewService, checkServiceAccess } from "../services/user";
|
||||
import { createMount } from "../services/mount";
|
||||
|
||||
export const redisRouter = createTRPCRouter({
|
||||
create: protectedProcedure
|
||||
.input(apiCreateRedis)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
if (ctx.user.rol === "user") {
|
||||
await checkServiceAccess(ctx.user.authId, input.projectId, "create");
|
||||
}
|
||||
|
||||
const newRedis = await createRedis(input);
|
||||
if (ctx.user.rol === "user") {
|
||||
await addNewService(ctx.user.authId, newRedis.redisId);
|
||||
}
|
||||
|
||||
await createMount({
|
||||
serviceId: newRedis.redisId,
|
||||
serviceType: "redis",
|
||||
volumeName: `${newRedis.appName}-data`,
|
||||
mountPath: "/data",
|
||||
type: "volume",
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error input: Inserting redis database",
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
}),
|
||||
one: protectedProcedure
|
||||
.input(apiFindOneRedis)
|
||||
.query(async ({ input, ctx }) => {
|
||||
if (ctx.user.rol === "user") {
|
||||
await checkServiceAccess(ctx.user.authId, input.redisId, "access");
|
||||
}
|
||||
return await findRedisById(input.redisId);
|
||||
}),
|
||||
|
||||
start: protectedProcedure
|
||||
.input(apiFindOneRedis)
|
||||
.mutation(async ({ input }) => {
|
||||
const redis = await findRedisById(input.redisId);
|
||||
await startService(redis.appName);
|
||||
await updateRedisById(input.redisId, {
|
||||
applicationStatus: "done",
|
||||
});
|
||||
|
||||
return redis;
|
||||
}),
|
||||
reload: protectedProcedure
|
||||
.input(apiResetRedis)
|
||||
.mutation(async ({ input }) => {
|
||||
await stopService(input.appName);
|
||||
await updateRedisById(input.redisId, {
|
||||
applicationStatus: "idle",
|
||||
});
|
||||
await startService(input.appName);
|
||||
await updateRedisById(input.redisId, {
|
||||
applicationStatus: "done",
|
||||
});
|
||||
return true;
|
||||
}),
|
||||
|
||||
stop: protectedProcedure
|
||||
.input(apiFindOneRedis)
|
||||
.mutation(async ({ input }) => {
|
||||
const mongo = await findRedisById(input.redisId);
|
||||
await stopService(mongo.appName);
|
||||
await updateRedisById(input.redisId, {
|
||||
applicationStatus: "idle",
|
||||
});
|
||||
|
||||
return mongo;
|
||||
}),
|
||||
saveExternalPort: protectedProcedure
|
||||
.input(apiSaveExternalPortRedis)
|
||||
.mutation(async ({ input }) => {
|
||||
const mongo = await findRedisById(input.redisId);
|
||||
await updateRedisById(input.redisId, {
|
||||
externalPort: input.externalPort,
|
||||
});
|
||||
await deployRedis(input.redisId);
|
||||
return mongo;
|
||||
}),
|
||||
deploy: protectedProcedure
|
||||
.input(apiDeployRedis)
|
||||
.mutation(async ({ input }) => {
|
||||
return deployRedis(input.redisId);
|
||||
}),
|
||||
changeStatus: protectedProcedure
|
||||
.input(apiChangeRedisStatus)
|
||||
.mutation(async ({ input }) => {
|
||||
const mongo = await findRedisById(input.redisId);
|
||||
await updateRedisById(input.redisId, {
|
||||
applicationStatus: input.applicationStatus,
|
||||
});
|
||||
return mongo;
|
||||
}),
|
||||
remove: protectedProcedure
|
||||
.input(apiFindOneRedis)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
if (ctx.user.rol === "user") {
|
||||
await checkServiceAccess(ctx.user.authId, input.redisId, "delete");
|
||||
}
|
||||
|
||||
const redis = await findRedisById(input.redisId);
|
||||
|
||||
const cleanupOperations = [
|
||||
async () => await removeService(redis?.appName),
|
||||
async () => await removeRedisById(input.redisId),
|
||||
];
|
||||
|
||||
for (const operation of cleanupOperations) {
|
||||
try {
|
||||
await operation();
|
||||
} catch (error) {}
|
||||
}
|
||||
|
||||
return redis;
|
||||
}),
|
||||
saveEnviroment: protectedProcedure
|
||||
.input(apiSaveEnviromentVariablesRedis)
|
||||
.mutation(async ({ input }) => {
|
||||
const redis = await updateRedisById(input.redisId, {
|
||||
env: input.env,
|
||||
});
|
||||
|
||||
if (!redis) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Update: Error to add enviroment variables",
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}),
|
||||
update: protectedProcedure
|
||||
.input(apiUpdateRedis)
|
||||
.mutation(async ({ input }) => {
|
||||
const { redisId, ...rest } = input;
|
||||
const redis = await updateRedisById(redisId, {
|
||||
...rest,
|
||||
});
|
||||
|
||||
if (!redis) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Update: Error to update redis",
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}),
|
||||
});
|
||||
33
server/api/routers/security.ts
Normal file
33
server/api/routers/security.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
||||
import {
|
||||
apiCreateSecurity,
|
||||
apiFindOneSecurity,
|
||||
apiUpdateSecurity,
|
||||
} from "@/server/db/schema";
|
||||
import {
|
||||
createSecurity,
|
||||
deleteSecurityById,
|
||||
findSecurityById,
|
||||
updateSecurityById,
|
||||
} from "../services/security";
|
||||
|
||||
export const securityRouter = createTRPCRouter({
|
||||
create: protectedProcedure
|
||||
.input(apiCreateSecurity)
|
||||
.mutation(async ({ input }) => {
|
||||
return await createSecurity(input);
|
||||
}),
|
||||
one: protectedProcedure.input(apiFindOneSecurity).query(async ({ input }) => {
|
||||
return await findSecurityById(input.securityId);
|
||||
}),
|
||||
delete: protectedProcedure
|
||||
.input(apiFindOneSecurity)
|
||||
.mutation(async ({ input }) => {
|
||||
return await deleteSecurityById(input.securityId);
|
||||
}),
|
||||
update: protectedProcedure
|
||||
.input(apiUpdateSecurity)
|
||||
.mutation(async ({ input }) => {
|
||||
return await updateSecurityById(input.securityId, input);
|
||||
}),
|
||||
});
|
||||
240
server/api/routers/settings.ts
Normal file
240
server/api/routers/settings.ts
Normal file
@@ -0,0 +1,240 @@
|
||||
import { docker, MAIN_TRAEFIK_PATH } from "@/server/constants";
|
||||
import { adminProcedure, createTRPCRouter, protectedProcedure } from "../trpc";
|
||||
import {
|
||||
cleanStoppedContainers,
|
||||
cleanUpDockerBuilder,
|
||||
cleanUpSystemPrune,
|
||||
cleanUpUnusedImages,
|
||||
cleanUpUnusedVolumes,
|
||||
startService,
|
||||
stopService,
|
||||
} from "@/server/utils/docker/utils";
|
||||
import {
|
||||
apiAssignDomain,
|
||||
apiModifyTraefikConfig,
|
||||
apiReadTraefikConfig,
|
||||
apiSaveSSHKey,
|
||||
apiTraefikConfig,
|
||||
apiUpdateDockerCleanup,
|
||||
} from "@/server/db/schema";
|
||||
import { scheduledJobs, scheduleJob } from "node-schedule";
|
||||
import {
|
||||
readMainConfig,
|
||||
updateLetsEncryptEmail,
|
||||
updateServerTraefik,
|
||||
writeMainConfig,
|
||||
} from "@/server/utils/traefik/web-server";
|
||||
import {
|
||||
readConfig,
|
||||
readConfigInPath,
|
||||
writeConfig,
|
||||
writeTraefikConfigInPath,
|
||||
} from "@/server/utils/traefik/application";
|
||||
import { spawnAsync } from "@/server/utils/process/spawnAsync";
|
||||
import { findAdmin, updateAdmin } from "../services/admin";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import {
|
||||
getDokployVersion,
|
||||
getDokployImage,
|
||||
pullLatestRelease,
|
||||
readDirectory,
|
||||
} from "../services/settings";
|
||||
import { canAccessToTraefikFiles } from "../services/user";
|
||||
|
||||
export const settingsRouter = createTRPCRouter({
|
||||
reloadServer: adminProcedure.mutation(async () => {
|
||||
await spawnAsync("docker", [
|
||||
"service",
|
||||
"update",
|
||||
"--force",
|
||||
"--image",
|
||||
getDokployImage(),
|
||||
"dokploy",
|
||||
]);
|
||||
return true;
|
||||
}),
|
||||
reloadTraefik: adminProcedure.mutation(async () => {
|
||||
await stopService("dokploy-traefik");
|
||||
await startService("dokploy-traefik");
|
||||
return true;
|
||||
}),
|
||||
cleanUnusedImages: adminProcedure.mutation(async () => {
|
||||
await cleanUpUnusedImages();
|
||||
return true;
|
||||
}),
|
||||
cleanUnusedVolumes: adminProcedure.mutation(async () => {
|
||||
await cleanUpUnusedVolumes();
|
||||
return true;
|
||||
}),
|
||||
cleanStoppedContainers: adminProcedure.mutation(async () => {
|
||||
await cleanStoppedContainers();
|
||||
return true;
|
||||
}),
|
||||
cleanDockerBuilder: adminProcedure.mutation(async () => {
|
||||
await cleanUpDockerBuilder();
|
||||
}),
|
||||
cleanDockerPrune: adminProcedure.mutation(async () => {
|
||||
await cleanUpSystemPrune();
|
||||
await cleanUpDockerBuilder();
|
||||
|
||||
return true;
|
||||
}),
|
||||
cleanAll: adminProcedure.mutation(async () => {
|
||||
await cleanUpUnusedImages();
|
||||
await cleanUpDockerBuilder();
|
||||
await cleanUpSystemPrune();
|
||||
return true;
|
||||
}),
|
||||
saveSSHPrivateKey: adminProcedure
|
||||
.input(apiSaveSSHKey)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
await updateAdmin(ctx.user.authId, {
|
||||
sshPrivateKey: input.sshPrivateKey,
|
||||
});
|
||||
|
||||
return true;
|
||||
}),
|
||||
assignDomainServer: adminProcedure
|
||||
.input(apiAssignDomain)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const admin = await updateAdmin(ctx.user.authId, {
|
||||
host: input.host,
|
||||
letsEncryptEmail: input.letsEncryptEmail,
|
||||
certificateType: input.certificateType,
|
||||
});
|
||||
|
||||
if (!admin) {
|
||||
throw new TRPCError({
|
||||
code: "NOT_FOUND",
|
||||
message: "Admin not found",
|
||||
});
|
||||
}
|
||||
|
||||
updateServerTraefik(admin, input.host);
|
||||
updateLetsEncryptEmail(admin.letsEncryptEmail);
|
||||
return admin;
|
||||
}),
|
||||
cleanSSHPrivateKey: adminProcedure.mutation(async ({ ctx }) => {
|
||||
await updateAdmin(ctx.user.authId, {
|
||||
sshPrivateKey: null,
|
||||
});
|
||||
return true;
|
||||
}),
|
||||
updateDockerCleanup: adminProcedure
|
||||
.input(apiUpdateDockerCleanup)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
await updateAdmin(ctx.user.authId, {
|
||||
enableDockerCleanup: input.enableDockerCleanup,
|
||||
});
|
||||
|
||||
const admin = await findAdmin();
|
||||
|
||||
if (admin.enableDockerCleanup) {
|
||||
scheduleJob("docker-cleanup", "0 0 * * *", async () => {
|
||||
console.log(
|
||||
`Docker Cleanup ${new Date().toLocaleString()}] Running...`,
|
||||
);
|
||||
await cleanUpUnusedImages();
|
||||
await cleanUpDockerBuilder();
|
||||
await cleanUpSystemPrune();
|
||||
});
|
||||
} else {
|
||||
const currentJob = scheduledJobs["docker-cleanup"];
|
||||
currentJob?.cancel();
|
||||
}
|
||||
|
||||
return true;
|
||||
}),
|
||||
|
||||
readTraefikConfig: adminProcedure.query(() => {
|
||||
const traefikConfig = readMainConfig();
|
||||
return traefikConfig;
|
||||
}),
|
||||
|
||||
updateTraefikConfig: adminProcedure
|
||||
.input(apiTraefikConfig)
|
||||
.mutation(async ({ input }) => {
|
||||
writeMainConfig(input.traefikConfig);
|
||||
return true;
|
||||
}),
|
||||
|
||||
readWebServerTraefikConfig: adminProcedure.query(() => {
|
||||
const traefikConfig = readConfig("dokploy");
|
||||
return traefikConfig;
|
||||
}),
|
||||
updateWebServerTraefikConfig: adminProcedure
|
||||
.input(apiTraefikConfig)
|
||||
.mutation(async ({ input }) => {
|
||||
writeConfig("dokploy", input.traefikConfig);
|
||||
return true;
|
||||
}),
|
||||
|
||||
readMiddlewareTraefikConfig: adminProcedure.query(() => {
|
||||
const traefikConfig = readConfig("middlewares");
|
||||
return traefikConfig;
|
||||
}),
|
||||
|
||||
updateMiddlewareTraefikConfig: adminProcedure
|
||||
.input(apiTraefikConfig)
|
||||
.mutation(async ({ input }) => {
|
||||
writeConfig("middlewares", input.traefikConfig);
|
||||
return true;
|
||||
}),
|
||||
|
||||
checkAndUpdateImage: adminProcedure.query(async () => {
|
||||
return await pullLatestRelease();
|
||||
}),
|
||||
updateServer: adminProcedure.mutation(async () => {
|
||||
await spawnAsync("docker", [
|
||||
"service",
|
||||
"update",
|
||||
"--force",
|
||||
"--image",
|
||||
getDokployImage(),
|
||||
"dokploy",
|
||||
]);
|
||||
return true;
|
||||
}),
|
||||
|
||||
getDokployVersion: adminProcedure.query(() => {
|
||||
return getDokployVersion();
|
||||
}),
|
||||
readDirectories: protectedProcedure.query(async ({ ctx }) => {
|
||||
if (ctx.user.rol === "user") {
|
||||
const canAccess = await canAccessToTraefikFiles(ctx.user.authId);
|
||||
|
||||
if (!canAccess) {
|
||||
throw new TRPCError({ code: "UNAUTHORIZED" });
|
||||
}
|
||||
}
|
||||
const result = readDirectory(MAIN_TRAEFIK_PATH);
|
||||
return result || [];
|
||||
}),
|
||||
|
||||
updateTraefikFile: protectedProcedure
|
||||
.input(apiModifyTraefikConfig)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
if (ctx.user.rol === "user") {
|
||||
const canAccess = await canAccessToTraefikFiles(ctx.user.authId);
|
||||
|
||||
if (!canAccess) {
|
||||
throw new TRPCError({ code: "UNAUTHORIZED" });
|
||||
}
|
||||
}
|
||||
writeTraefikConfigInPath(input.path, input.traefikConfig);
|
||||
return true;
|
||||
}),
|
||||
|
||||
readTraefikFile: protectedProcedure
|
||||
.input(apiReadTraefikConfig)
|
||||
.query(async ({ input, ctx }) => {
|
||||
if (ctx.user.rol === "user") {
|
||||
const canAccess = await canAccessToTraefikFiles(ctx.user.authId);
|
||||
|
||||
if (!canAccess) {
|
||||
throw new TRPCError({ code: "UNAUTHORIZED" });
|
||||
}
|
||||
}
|
||||
return readConfigInPath(input.path);
|
||||
}),
|
||||
});
|
||||
20
server/api/routers/user.ts
Normal file
20
server/api/routers/user.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { apiFindOneUser, apiFindOneUserByAuth } from "@/server/db/schema";
|
||||
import { adminProcedure, createTRPCRouter, protectedProcedure } from "../trpc";
|
||||
|
||||
import { findUserByAuthId, findUserById, findUsers } from "../services/user";
|
||||
|
||||
export const userRouter = createTRPCRouter({
|
||||
all: adminProcedure.query(async () => {
|
||||
return await findUsers();
|
||||
}),
|
||||
byAuthId: protectedProcedure
|
||||
.input(apiFindOneUserByAuth)
|
||||
.query(async ({ input }) => {
|
||||
return await findUserByAuthId(input.authId);
|
||||
}),
|
||||
byUserId: protectedProcedure
|
||||
.input(apiFindOneUser)
|
||||
.query(async ({ input }) => {
|
||||
return await findUserById(input.userId);
|
||||
}),
|
||||
});
|
||||
Reference in New Issue
Block a user