refactor: simplify user permission checks across application

This commit is contained in:
Mauricio Siu 2025-02-21 00:40:35 -06:00
parent 24c9d3f7ad
commit a317f0c4cc
19 changed files with 52 additions and 34 deletions

View File

@ -83,7 +83,7 @@ export const ShowProjects = () => {
</CardDescription>
</CardHeader>
{(auth?.role === "owner" || auth?.user?.canCreateProjects) && (
{(auth?.role === "owner" || auth?.canCreateProjects) && (
<div className="">
<HandleProject />
</div>
@ -286,7 +286,7 @@ export const ShowProjects = () => {
onClick={(e) => e.stopPropagation()}
>
{(auth?.role === "owner" ||
auth?.user?.canDeleteProjects) && (
auth?.canDeleteProjects) && (
<AlertDialog>
<AlertDialogTrigger className="w-full">
<DropdownMenuItem

View File

@ -92,8 +92,7 @@ export const UserNav = () => {
>
Monitoring
</DropdownMenuItem>
{(data?.role === "owner" ||
data?.user?.canAccessToTraefikFiles) && (
{(data?.role === "owner" || data?.canAccessToTraefikFiles) && (
<DropdownMenuItem
className="cursor-pointer"
onClick={() => {
@ -103,7 +102,7 @@ export const UserNav = () => {
Traefik
</DropdownMenuItem>
)}
{(data?.role === "owner" || data?.user?.canAccessToDocker) && (
{(data?.role === "owner" || data?.canAccessToDocker) && (
<DropdownMenuItem
className="cursor-pointer"
onClick={() => {

View File

@ -58,7 +58,7 @@ export async function getServerSideProps(
userId: user.id,
});
if (!userR.canAccessToDocker) {
if (!userR?.canAccessToDocker) {
return {
redirect: {
permanent: true,

View File

@ -328,7 +328,7 @@ const Project = (
</CardTitle>
<CardDescription>{data?.description}</CardDescription>
</CardHeader>
{(auth?.role === "owner" || auth?.user?.canCreateServices) && (
{(auth?.role === "owner" || auth?.canCreateServices) && (
<div className="flex flex-row gap-4 flex-wrap">
<ProjectEnvironment projectId={projectId}>
<Button variant="outline">Project Environment</Button>

View File

@ -178,8 +178,7 @@ const Service = (
<div className="flex flex-row gap-2 justify-end">
<UpdateApplication applicationId={applicationId} />
{(auth?.role === "owner" ||
auth?.user?.canDeleteServices) && (
{(auth?.role === "owner" || auth?.canDeleteServices) && (
<DeleteService id={applicationId} type="application" />
)}
</div>

View File

@ -173,8 +173,7 @@ const Service = (
<div className="flex flex-row gap-2 justify-end">
<UpdateCompose composeId={composeId} />
{(auth?.role === "owner" ||
auth?.user?.canDeleteServices) && (
{(auth?.role === "owner" || auth?.canDeleteServices) && (
<DeleteService id={composeId} type="compose" />
)}
</div>

View File

@ -147,8 +147,7 @@ const Mariadb = (
</div>
<div className="flex flex-row gap-2 justify-end">
<UpdateMariadb mariadbId={mariadbId} />
{(auth?.role === "owner" ||
auth?.user?.canDeleteServices) && (
{(auth?.role === "owner" || auth?.canDeleteServices) && (
<DeleteService id={mariadbId} type="mariadb" />
)}
</div>

View File

@ -148,8 +148,7 @@ const Mongo = (
<div className="flex flex-row gap-2 justify-end">
<UpdateMongo mongoId={mongoId} />
{(auth?.role === "owner" ||
auth?.user?.canDeleteServices) && (
{(auth?.role === "owner" || auth?.canDeleteServices) && (
<DeleteService id={mongoId} type="mongo" />
)}
</div>

View File

@ -148,8 +148,7 @@ const MySql = (
<div className="flex flex-row gap-2 justify-end">
<UpdateMysql mysqlId={mysqlId} />
{(auth?.role === "owner" ||
auth?.user?.canDeleteServices) && (
{(auth?.role === "owner" || auth?.canDeleteServices) && (
<DeleteService id={mysqlId} type="mysql" />
)}
</div>

View File

@ -147,8 +147,7 @@ const Postgresql = (
<div className="flex flex-row gap-2 justify-end">
<UpdatePostgres postgresId={postgresId} />
{(auth?.role === "owner" ||
auth?.user?.canDeleteServices) && (
{(auth?.role === "owner" || auth?.canDeleteServices) && (
<DeleteService id={postgresId} type="postgres" />
)}
</div>

View File

@ -147,8 +147,7 @@ const Redis = (
<div className="flex flex-row gap-2 justify-end">
<UpdateRedis redisId={redisId} />
{(auth?.role === "owner" ||
auth?.user?.canDeleteServices) && (
{(auth?.role === "owner" || auth?.canDeleteServices) && (
<DeleteService id={redisId} type="redis" />
)}
</div>

View File

@ -54,7 +54,7 @@ export async function getServerSideProps(
userId: user.id,
});
if (!userR.canAccessToGitProviders) {
if (!userR?.canAccessToGitProviders) {
return {
redirect: {
permanent: true,

View File

@ -20,9 +20,7 @@ const Page = () => {
<div className="w-full">
<div className="h-full rounded-xl max-w-5xl mx-auto flex flex-col gap-4">
<ProfileForm />
{(data?.user?.canAccessToAPI || data?.role === "owner") && (
<GenerateToken />
)}
{(data?.canAccessToAPI || data?.role === "owner") && <GenerateToken />}
{isCloud && <RemoveSelfAccount />}
</div>

View File

@ -55,7 +55,7 @@ export async function getServerSideProps(
userId: user.id,
});
if (!userR.canAccessToSSHKeys) {
if (!userR?.canAccessToSSHKeys) {
return {
redirect: {
permanent: true,

View File

@ -58,7 +58,7 @@ export async function getServerSideProps(
userId: user.id,
});
if (!userR.canAccessToDocker) {
if (!userR?.canAccessToDocker) {
return {
redirect: {
permanent: true,

View File

@ -58,7 +58,7 @@ export async function getServerSideProps(
userId: user.id,
});
if (!userR.canAccessToTraefikFiles) {
if (!userR?.canAccessToTraefikFiles) {
return {
redirect: {
permanent: true,

View File

@ -63,7 +63,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
userId: user.id,
});
if (!userR.canAccessToAPI) {
if (!userR?.canAccessToAPI) {
return {
redirect: {
permanent: true,

View File

@ -8,6 +8,7 @@ import {
applications,
compose,
mariadb,
member,
mongo,
mysql,
postgres,
@ -29,8 +30,8 @@ import {
findUserByAuthId,
findUserById,
updateProjectById,
findMemberById,
} from "@dokploy/server";
export const projectRouter = createTRPCRouter({
create: protectedProcedure
.input(apiCreateProject)
@ -71,7 +72,10 @@ export const projectRouter = createTRPCRouter({
.input(apiFindOneProject)
.query(async ({ input, ctx }) => {
if (ctx.user.rol === "member") {
const { accessedServices } = await findUserById(ctx.user.id);
const { accessedServices } = await findMemberById(
ctx.user.id,
ctx.session.activeOrganizationId,
);
await checkProjectAccess(ctx.user.id, "access", input.projectId);
@ -129,8 +133,9 @@ export const projectRouter = createTRPCRouter({
all: protectedProcedure.query(async ({ ctx }) => {
// console.log(ctx.user);
if (ctx.user.rol === "member") {
const { accessedProjects, accessedServices } = await findUserById(
const { accessedProjects, accessedServices } = await findMemberById(
ctx.user.id,
ctx.session.activeOrganizationId,
);
if (accessedProjects.length === 0) {

View File

@ -1,7 +1,7 @@
import { db } from "@dokploy/server/db";
import type { users_temp } from "@dokploy/server/db/schema";
import { type users_temp, member } from "@dokploy/server/db/schema";
import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";
import { and, eq } from "drizzle-orm";
import { findUserById } from "./admin";
export type User = typeof users_temp.$inferSelect;
@ -191,3 +191,26 @@ export const checkProjectAccess = async (
});
}
};
export const findMemberById = async (
userId: string,
organizationId: string,
) => {
const result = await db.query.member.findFirst({
where: and(
eq(member.userId, userId),
eq(member.organizationId, organizationId),
),
with: {
user: true,
},
});
if (!result) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "Permission denied",
});
}
return result;
};