refactor: simplify role management by removing unused role schema and related logic; update user role checks in context and procedures

This commit is contained in:
Mauricio Siu
2025-07-13 14:00:26 -06:00
parent cee426dcf5
commit d84099108a
10 changed files with 305 additions and 373 deletions

View File

@@ -1,6 +1,6 @@
import { db } from "@/server/db";
import { invitation, member, organization, role } from "@/server/db/schema";
import { createDefaultRoles, IS_CLOUD } from "@dokploy/server/index";
import { invitation, member, organization } from "@/server/db/schema";
import { IS_CLOUD } from "@dokploy/server/index";
import { TRPCError } from "@trpc/server";
import { and, desc, eq, exists } from "drizzle-orm";
import { nanoid } from "nanoid";
@@ -38,18 +38,12 @@ export const organizationRouter = createTRPCRouter({
message: "Failed to create organization",
});
}
await createDefaultRoles(result.id);
const ownerRole = await db.query.role.findFirst({
where: and(eq(role.name, "owner"), eq(role.organizationId, result.id)),
});
await db.insert(member).values({
organizationId: result.id,
role: "owner",
createdAt: new Date(),
userId: ctx.user.id,
roleId: ownerRole?.roleId || "",
});
return result;
}),

View File

@@ -1,86 +1,75 @@
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
import { db } from "@/server/db";
import {
apiFindOneRole,
createRoleSchema,
role,
updateRoleSchema,
} from "@/server/db/schema";
import { createRole, removeRoleById, updateRoleById } from "@dokploy/server";
import { defaultPermissions } from "@dokploy/server/lib/permissions";
import { TRPCError } from "@trpc/server";
import { and, asc, eq } from "drizzle-orm";
import { createTRPCRouter } from "@/server/api/trpc";
// import { createRole, removeRoleById, updateRoleById } from "@dokploy/server";
// import { defaultPermissions } from "@dokploy/server/lib/permissions";
export const roleRouter = createTRPCRouter({
all: protectedProcedure.query(async ({ ctx }) => {
const roles = await db.query.role.findMany({
where: and(
eq(role.organizationId, ctx.session.activeOrganizationId),
eq(role.isSystem, false),
),
orderBy: [asc(role.createdAt)],
});
return roles;
}),
delete: protectedProcedure
.input(apiFindOneRole)
.mutation(async ({ input }) => {
try {
return removeRoleById(input.roleId);
} catch (error) {
const message =
error instanceof Error ? error.message : "Error input: Deleting role";
throw new TRPCError({
code: "BAD_REQUEST",
message,
});
}
}),
create: protectedProcedure
.input(createRoleSchema)
.mutation(async ({ input, ctx }) => {
try {
return await createRole(
{
...input,
},
ctx.session.activeOrganizationId,
);
} catch (error) {
console.error(error);
throw new TRPCError({
code: "BAD_REQUEST",
message: "Error input: Creating role",
cause: error,
});
}
}),
update: protectedProcedure
.input(updateRoleSchema)
.mutation(async ({ input }) => {
return await updateRoleById(input.roleId, input);
}),
getDefaultRoles: protectedProcedure.query(async ({ ctx }) => {
const roles = await db.query.role.findMany({
where: and(
eq(role.organizationId, ctx.session.activeOrganizationId),
eq(role.isSystem, true),
),
});
// add the description from the constants roles to the roles
const rolesWithDescription = defaultPermissions.map((role) => {
const roleInfo = roles.find((r) => r.name === role.name);
return {
...roleInfo,
...role,
};
});
const set = new Set(rolesWithDescription.flatMap((r) => r.permissions));
return {
roles: rolesWithDescription,
permissions: Array.from(set),
};
}),
// all: protectedProcedure.query(async ({ ctx }) => {
// const roles = await db.query.role.findMany({
// where: and(
// eq(role.organizationId, ctx.session.activeOrganizationId),
// eq(role.isSystem, false),
// ),
// orderBy: [asc(role.createdAt)],
// });
// return roles;
// }),
// delete: protectedProcedure
// .input(apiFindOneRole)
// .mutation(async ({ input }) => {
// try {
// return removeRoleById(input.roleId);
// } catch (error) {
// const message =
// error instanceof Error ? error.message : "Error input: Deleting role";
// throw new TRPCError({
// code: "BAD_REQUEST",
// message,
// });
// }
// }),
// create: protectedProcedure
// .input(createRoleSchema)
// .mutation(async ({ input, ctx }) => {
// try {
// return await createRole(
// {
// ...input,
// },
// ctx.session.activeOrganizationId,
// );
// } catch (error) {
// console.error(error);
// throw new TRPCError({
// code: "BAD_REQUEST",
// message: "Error input: Creating role",
// cause: error,
// });
// }
// }),
// update: protectedProcedure
// .input(updateRoleSchema)
// .mutation(async ({ input }) => {
// return await updateRoleById(input.roleId, input);
// }),
// getDefaultRoles: protectedProcedure.query(async ({ ctx }) => {
// const roles = await db.query.role.findMany({
// where: and(
// eq(role.organizationId, ctx.session.activeOrganizationId),
// eq(role.isSystem, true),
// ),
// });
// // add the description from the constants roles to the roles
// const rolesWithDescription = defaultPermissions.map((role) => {
// const roleInfo = roles.find((r) => r.name === role.name);
// return {
// ...roleInfo,
// ...role,
// };
// });
// const set = new Set(rolesWithDescription.flatMap((r) => r.permissions));
// return {
// roles: rolesWithDescription,
// permissions: Array.from(set),
// };
// }),
});

View File

@@ -30,17 +30,7 @@ import { ZodError } from "zod";
*/
interface CreateContextOptions {
user:
| (User & {
role: {
roleId: string;
name: string;
permissions: string[];
isSystem: boolean;
};
ownerId: string;
})
| null;
user: (User & { role: "member" | "admin" | "owner"; ownerId: string }) | null;
session:
| (Session & { activeOrganizationId: string; impersonatedBy?: string })
| null;
@@ -192,7 +182,7 @@ export const uploadProcedure = async (opts: any) => {
};
export const cliProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.session || !ctx.user || ctx.user.role.name !== "owner") {
if (!ctx.session || !ctx.user || ctx.user.role !== "owner") {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next({
@@ -206,11 +196,7 @@ export const cliProcedure = t.procedure.use(({ ctx, next }) => {
});
export const adminProcedure = t.procedure.use(({ ctx, next }) => {
if (
!ctx.session ||
!ctx.user ||
(ctx.user.role.name !== "owner" && ctx.user.role.name !== "admin")
) {
if (!ctx.session || !ctx.user || ctx.user.role !== "owner") {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next({