mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
refactor: simplify user permission checks across application
This commit is contained in:
@@ -83,7 +83,7 @@ export const ShowProjects = () => {
|
|||||||
</CardDescription>
|
</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|
||||||
{(auth?.role === "owner" || auth?.user?.canCreateProjects) && (
|
{(auth?.role === "owner" || auth?.canCreateProjects) && (
|
||||||
<div className="">
|
<div className="">
|
||||||
<HandleProject />
|
<HandleProject />
|
||||||
</div>
|
</div>
|
||||||
@@ -286,7 +286,7 @@ export const ShowProjects = () => {
|
|||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
>
|
>
|
||||||
{(auth?.role === "owner" ||
|
{(auth?.role === "owner" ||
|
||||||
auth?.user?.canDeleteProjects) && (
|
auth?.canDeleteProjects) && (
|
||||||
<AlertDialog>
|
<AlertDialog>
|
||||||
<AlertDialogTrigger className="w-full">
|
<AlertDialogTrigger className="w-full">
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
|
|||||||
@@ -92,8 +92,7 @@ export const UserNav = () => {
|
|||||||
>
|
>
|
||||||
Monitoring
|
Monitoring
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
{(data?.role === "owner" ||
|
{(data?.role === "owner" || data?.canAccessToTraefikFiles) && (
|
||||||
data?.user?.canAccessToTraefikFiles) && (
|
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
className="cursor-pointer"
|
className="cursor-pointer"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@@ -103,7 +102,7 @@ export const UserNav = () => {
|
|||||||
Traefik
|
Traefik
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
)}
|
)}
|
||||||
{(data?.role === "owner" || data?.user?.canAccessToDocker) && (
|
{(data?.role === "owner" || data?.canAccessToDocker) && (
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
className="cursor-pointer"
|
className="cursor-pointer"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export async function getServerSideProps(
|
|||||||
userId: user.id,
|
userId: user.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!userR.canAccessToDocker) {
|
if (!userR?.canAccessToDocker) {
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
permanent: true,
|
permanent: true,
|
||||||
|
|||||||
@@ -328,7 +328,7 @@ const Project = (
|
|||||||
</CardTitle>
|
</CardTitle>
|
||||||
<CardDescription>{data?.description}</CardDescription>
|
<CardDescription>{data?.description}</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
{(auth?.role === "owner" || auth?.user?.canCreateServices) && (
|
{(auth?.role === "owner" || auth?.canCreateServices) && (
|
||||||
<div className="flex flex-row gap-4 flex-wrap">
|
<div className="flex flex-row gap-4 flex-wrap">
|
||||||
<ProjectEnvironment projectId={projectId}>
|
<ProjectEnvironment projectId={projectId}>
|
||||||
<Button variant="outline">Project Environment</Button>
|
<Button variant="outline">Project Environment</Button>
|
||||||
|
|||||||
@@ -178,8 +178,7 @@ const Service = (
|
|||||||
|
|
||||||
<div className="flex flex-row gap-2 justify-end">
|
<div className="flex flex-row gap-2 justify-end">
|
||||||
<UpdateApplication applicationId={applicationId} />
|
<UpdateApplication applicationId={applicationId} />
|
||||||
{(auth?.role === "owner" ||
|
{(auth?.role === "owner" || auth?.canDeleteServices) && (
|
||||||
auth?.user?.canDeleteServices) && (
|
|
||||||
<DeleteService id={applicationId} type="application" />
|
<DeleteService id={applicationId} type="application" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -173,8 +173,7 @@ const Service = (
|
|||||||
<div className="flex flex-row gap-2 justify-end">
|
<div className="flex flex-row gap-2 justify-end">
|
||||||
<UpdateCompose composeId={composeId} />
|
<UpdateCompose composeId={composeId} />
|
||||||
|
|
||||||
{(auth?.role === "owner" ||
|
{(auth?.role === "owner" || auth?.canDeleteServices) && (
|
||||||
auth?.user?.canDeleteServices) && (
|
|
||||||
<DeleteService id={composeId} type="compose" />
|
<DeleteService id={composeId} type="compose" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -147,8 +147,7 @@ const Mariadb = (
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row gap-2 justify-end">
|
<div className="flex flex-row gap-2 justify-end">
|
||||||
<UpdateMariadb mariadbId={mariadbId} />
|
<UpdateMariadb mariadbId={mariadbId} />
|
||||||
{(auth?.role === "owner" ||
|
{(auth?.role === "owner" || auth?.canDeleteServices) && (
|
||||||
auth?.user?.canDeleteServices) && (
|
|
||||||
<DeleteService id={mariadbId} type="mariadb" />
|
<DeleteService id={mariadbId} type="mariadb" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -148,8 +148,7 @@ const Mongo = (
|
|||||||
|
|
||||||
<div className="flex flex-row gap-2 justify-end">
|
<div className="flex flex-row gap-2 justify-end">
|
||||||
<UpdateMongo mongoId={mongoId} />
|
<UpdateMongo mongoId={mongoId} />
|
||||||
{(auth?.role === "owner" ||
|
{(auth?.role === "owner" || auth?.canDeleteServices) && (
|
||||||
auth?.user?.canDeleteServices) && (
|
|
||||||
<DeleteService id={mongoId} type="mongo" />
|
<DeleteService id={mongoId} type="mongo" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -148,8 +148,7 @@ const MySql = (
|
|||||||
|
|
||||||
<div className="flex flex-row gap-2 justify-end">
|
<div className="flex flex-row gap-2 justify-end">
|
||||||
<UpdateMysql mysqlId={mysqlId} />
|
<UpdateMysql mysqlId={mysqlId} />
|
||||||
{(auth?.role === "owner" ||
|
{(auth?.role === "owner" || auth?.canDeleteServices) && (
|
||||||
auth?.user?.canDeleteServices) && (
|
|
||||||
<DeleteService id={mysqlId} type="mysql" />
|
<DeleteService id={mysqlId} type="mysql" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -147,8 +147,7 @@ const Postgresql = (
|
|||||||
|
|
||||||
<div className="flex flex-row gap-2 justify-end">
|
<div className="flex flex-row gap-2 justify-end">
|
||||||
<UpdatePostgres postgresId={postgresId} />
|
<UpdatePostgres postgresId={postgresId} />
|
||||||
{(auth?.role === "owner" ||
|
{(auth?.role === "owner" || auth?.canDeleteServices) && (
|
||||||
auth?.user?.canDeleteServices) && (
|
|
||||||
<DeleteService id={postgresId} type="postgres" />
|
<DeleteService id={postgresId} type="postgres" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -147,8 +147,7 @@ const Redis = (
|
|||||||
|
|
||||||
<div className="flex flex-row gap-2 justify-end">
|
<div className="flex flex-row gap-2 justify-end">
|
||||||
<UpdateRedis redisId={redisId} />
|
<UpdateRedis redisId={redisId} />
|
||||||
{(auth?.role === "owner" ||
|
{(auth?.role === "owner" || auth?.canDeleteServices) && (
|
||||||
auth?.user?.canDeleteServices) && (
|
|
||||||
<DeleteService id={redisId} type="redis" />
|
<DeleteService id={redisId} type="redis" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export async function getServerSideProps(
|
|||||||
userId: user.id,
|
userId: user.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!userR.canAccessToGitProviders) {
|
if (!userR?.canAccessToGitProviders) {
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
permanent: true,
|
permanent: true,
|
||||||
|
|||||||
@@ -20,9 +20,7 @@ const Page = () => {
|
|||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<div className="h-full rounded-xl max-w-5xl mx-auto flex flex-col gap-4">
|
<div className="h-full rounded-xl max-w-5xl mx-auto flex flex-col gap-4">
|
||||||
<ProfileForm />
|
<ProfileForm />
|
||||||
{(data?.user?.canAccessToAPI || data?.role === "owner") && (
|
{(data?.canAccessToAPI || data?.role === "owner") && <GenerateToken />}
|
||||||
<GenerateToken />
|
|
||||||
)}
|
|
||||||
|
|
||||||
{isCloud && <RemoveSelfAccount />}
|
{isCloud && <RemoveSelfAccount />}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export async function getServerSideProps(
|
|||||||
userId: user.id,
|
userId: user.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!userR.canAccessToSSHKeys) {
|
if (!userR?.canAccessToSSHKeys) {
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
permanent: true,
|
permanent: true,
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export async function getServerSideProps(
|
|||||||
userId: user.id,
|
userId: user.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!userR.canAccessToDocker) {
|
if (!userR?.canAccessToDocker) {
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
permanent: true,
|
permanent: true,
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export async function getServerSideProps(
|
|||||||
userId: user.id,
|
userId: user.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!userR.canAccessToTraefikFiles) {
|
if (!userR?.canAccessToTraefikFiles) {
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
permanent: true,
|
permanent: true,
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
|
|||||||
userId: user.id,
|
userId: user.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!userR.canAccessToAPI) {
|
if (!userR?.canAccessToAPI) {
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
permanent: true,
|
permanent: true,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
applications,
|
applications,
|
||||||
compose,
|
compose,
|
||||||
mariadb,
|
mariadb,
|
||||||
|
member,
|
||||||
mongo,
|
mongo,
|
||||||
mysql,
|
mysql,
|
||||||
postgres,
|
postgres,
|
||||||
@@ -29,8 +30,8 @@ import {
|
|||||||
findUserByAuthId,
|
findUserByAuthId,
|
||||||
findUserById,
|
findUserById,
|
||||||
updateProjectById,
|
updateProjectById,
|
||||||
|
findMemberById,
|
||||||
} from "@dokploy/server";
|
} from "@dokploy/server";
|
||||||
|
|
||||||
export const projectRouter = createTRPCRouter({
|
export const projectRouter = createTRPCRouter({
|
||||||
create: protectedProcedure
|
create: protectedProcedure
|
||||||
.input(apiCreateProject)
|
.input(apiCreateProject)
|
||||||
@@ -71,7 +72,10 @@ export const projectRouter = createTRPCRouter({
|
|||||||
.input(apiFindOneProject)
|
.input(apiFindOneProject)
|
||||||
.query(async ({ input, ctx }) => {
|
.query(async ({ input, ctx }) => {
|
||||||
if (ctx.user.rol === "member") {
|
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);
|
await checkProjectAccess(ctx.user.id, "access", input.projectId);
|
||||||
|
|
||||||
@@ -129,8 +133,9 @@ export const projectRouter = createTRPCRouter({
|
|||||||
all: protectedProcedure.query(async ({ ctx }) => {
|
all: protectedProcedure.query(async ({ ctx }) => {
|
||||||
// console.log(ctx.user);
|
// console.log(ctx.user);
|
||||||
if (ctx.user.rol === "member") {
|
if (ctx.user.rol === "member") {
|
||||||
const { accessedProjects, accessedServices } = await findUserById(
|
const { accessedProjects, accessedServices } = await findMemberById(
|
||||||
ctx.user.id,
|
ctx.user.id,
|
||||||
|
ctx.session.activeOrganizationId,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (accessedProjects.length === 0) {
|
if (accessedProjects.length === 0) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { db } from "@dokploy/server/db";
|
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 { TRPCError } from "@trpc/server";
|
||||||
import { eq } from "drizzle-orm";
|
import { and, eq } from "drizzle-orm";
|
||||||
import { findUserById } from "./admin";
|
import { findUserById } from "./admin";
|
||||||
|
|
||||||
export type User = typeof users_temp.$inferSelect;
|
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;
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user