feat: add accessedServers permission handling and server access validation

- Introduced `accessedServers` field in user permissions schema and member table.
- Implemented server access validation across various API routers to ensure users can only access permitted servers.
- Added a new query to fetch accessible server IDs based on user roles and licenses.
- Updated UI components to support server selection in user permissions.
This commit is contained in:
Mauricio Siu
2026-04-05 00:06:27 -06:00
parent c160f24765
commit bfa4ebc801
17 changed files with 8595 additions and 5 deletions

View File

@@ -167,6 +167,10 @@ export const member = pgTable("member", {
.array()
.notNull()
.default(sql`ARRAY[]::text[]`),
accessedServers: text("accessedServers")
.array()
.notNull()
.default(sql`ARRAY[]::text[]`),
});
export const memberRelations = relations(member, ({ one }) => ({

View File

@@ -131,6 +131,7 @@ export const apiAssignPermissions = createSchema
accessedEnvironments: z.array(z.string()).optional(),
accessedServices: z.array(z.string()).optional(),
accessedGitProviders: z.array(z.string()).optional(),
accessedServers: z.array(z.string()).optional(),
canCreateProjects: z.boolean().optional(),
canCreateServices: z.boolean().optional(),
canDeleteProjects: z.boolean().optional(),

View File

@@ -1,11 +1,13 @@
import { db } from "@dokploy/server/db";
import {
type apiCreateServer,
member,
organization,
server,
} from "@dokploy/server/db/schema";
import { hasValidLicense } from "@dokploy/server/services/proprietary/license-key";
import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";
import { and, eq } from "drizzle-orm";
import type { z } from "zod";
export type Server = typeof server.$inferSelect;
@@ -130,3 +132,37 @@ export const getAllServers = async () => {
const servers = await db.query.server.findMany();
return servers;
};
export const getAccessibleServerIds = async (session: {
userId: string;
activeOrganizationId: string;
}): Promise<Set<string>> => {
const { userId, activeOrganizationId } = session;
const allOrgServers = await db.query.server.findMany({
where: eq(server.organizationId, activeOrganizationId),
columns: {
serverId: true,
},
});
const memberRecord = await db.query.member.findFirst({
where: and(
eq(member.userId, userId),
eq(member.organizationId, activeOrganizationId),
),
columns: { accessedServers: true, role: true },
});
if (memberRecord?.role === "owner" || memberRecord?.role === "admin") {
return new Set(allOrgServers.map((s) => s.serverId));
}
const licensed = await hasValidLicense(activeOrganizationId);
if (!licensed) {
return new Set(allOrgServers.map((s) => s.serverId));
}
return new Set(memberRecord?.accessedServers ?? []);
};