mirror of
https://github.com/andwati/dokploy.git
synced 2026-11-10 14:05:18 +00:00
fix: prevent Postgres 100-argument limit crash and restore data parity for restricted-member project access
The application table has 101 columns. The restricted-member branch of project.one (apps/dokploy/server/api/routers/project.ts) queried the applications relation with no columns narrowing, so Drizzle's relational query builder generated a json_build_array call with one argument per column, exceeding Postgres's FUNC_MAX_ARGS (100). Any non-owner/admin member with limited access to a project containing at least one application hit an opaque INTERNAL_SERVER_ERROR and got redirected away from the project/environment page instead of seeing their project. The same branch was also missing the "server" relation that the owner/admin path (findProjectById) already includes, so restricted members saw different (incomplete) data than owners/admins for the same project. Fixes this by extracting the existing serviceColumns column-selection constant to a module-level export in packages/server/src/services/project.ts and applying it (plus the server relation) to all 8 service relations in the restricted-member query path, matching the owner/admin path.
This commit is contained in:
@@ -38,6 +38,7 @@ import {
|
|||||||
checkProjectAccess,
|
checkProjectAccess,
|
||||||
findMemberByUserId,
|
findMemberByUserId,
|
||||||
} from "@dokploy/server/services/permission";
|
} from "@dokploy/server/services/permission";
|
||||||
|
import { serviceColumns } from "@dokploy/server/services/project";
|
||||||
import { TRPCError } from "@trpc/server";
|
import { TRPCError } from "@trpc/server";
|
||||||
import { and, desc, eq, ilike, or, sql } from "drizzle-orm";
|
import { and, desc, eq, ilike, or, sql } from "drizzle-orm";
|
||||||
import type { AnyPgColumn } from "drizzle-orm/pg-core";
|
import type { AnyPgColumn } from "drizzle-orm/pg-core";
|
||||||
@@ -130,39 +131,63 @@ export const projectRouter = createTRPCRouter({
|
|||||||
environments: {
|
environments: {
|
||||||
with: {
|
with: {
|
||||||
applications: {
|
applications: {
|
||||||
|
columns: {
|
||||||
|
...serviceColumns,
|
||||||
|
applicationId: true,
|
||||||
|
icon: true,
|
||||||
|
},
|
||||||
|
with: { server: { columns: { name: true } } },
|
||||||
where: buildServiceFilter(
|
where: buildServiceFilter(
|
||||||
applications.applicationId,
|
applications.applicationId,
|
||||||
accessedServices,
|
accessedServices,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
compose: {
|
compose: {
|
||||||
|
columns: {
|
||||||
|
...serviceColumns,
|
||||||
|
composeId: true,
|
||||||
|
composeStatus: true,
|
||||||
|
},
|
||||||
|
with: { server: { columns: { name: true } } },
|
||||||
where: buildServiceFilter(
|
where: buildServiceFilter(
|
||||||
compose.composeId,
|
compose.composeId,
|
||||||
accessedServices,
|
accessedServices,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
libsql: {
|
libsql: {
|
||||||
|
columns: { ...serviceColumns, libsqlId: true },
|
||||||
|
with: { server: { columns: { name: true } } },
|
||||||
where: buildServiceFilter(libsql.libsqlId, accessedServices),
|
where: buildServiceFilter(libsql.libsqlId, accessedServices),
|
||||||
},
|
},
|
||||||
mariadb: {
|
mariadb: {
|
||||||
|
columns: { ...serviceColumns, mariadbId: true },
|
||||||
|
with: { server: { columns: { name: true } } },
|
||||||
where: buildServiceFilter(
|
where: buildServiceFilter(
|
||||||
mariadb.mariadbId,
|
mariadb.mariadbId,
|
||||||
accessedServices,
|
accessedServices,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
mongo: {
|
mongo: {
|
||||||
|
columns: { ...serviceColumns, mongoId: true },
|
||||||
|
with: { server: { columns: { name: true } } },
|
||||||
where: buildServiceFilter(mongo.mongoId, accessedServices),
|
where: buildServiceFilter(mongo.mongoId, accessedServices),
|
||||||
},
|
},
|
||||||
mysql: {
|
mysql: {
|
||||||
|
columns: { ...serviceColumns, mysqlId: true },
|
||||||
|
with: { server: { columns: { name: true } } },
|
||||||
where: buildServiceFilter(mysql.mysqlId, accessedServices),
|
where: buildServiceFilter(mysql.mysqlId, accessedServices),
|
||||||
},
|
},
|
||||||
postgres: {
|
postgres: {
|
||||||
|
columns: { ...serviceColumns, postgresId: true },
|
||||||
|
with: { server: { columns: { name: true } } },
|
||||||
where: buildServiceFilter(
|
where: buildServiceFilter(
|
||||||
postgres.postgresId,
|
postgres.postgresId,
|
||||||
accessedServices,
|
accessedServices,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
redis: {
|
redis: {
|
||||||
|
columns: { ...serviceColumns, redisId: true },
|
||||||
|
with: { server: { columns: { name: true } } },
|
||||||
where: buildServiceFilter(redis.redisId, accessedServices),
|
where: buildServiceFilter(redis.redisId, accessedServices),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -47,16 +47,16 @@ export const createProject = async (
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const findProjectById = async (projectId: string) => {
|
export const serviceColumns = {
|
||||||
const serviceColumns = {
|
name: true,
|
||||||
name: true,
|
description: true,
|
||||||
description: true,
|
appName: true,
|
||||||
appName: true,
|
createdAt: true,
|
||||||
createdAt: true,
|
serverId: true,
|
||||||
serverId: true,
|
applicationStatus: true,
|
||||||
applicationStatus: true,
|
} as const;
|
||||||
} as const;
|
|
||||||
|
|
||||||
|
export const findProjectById = async (projectId: string) => {
|
||||||
const project = await db.query.projects.findFirst({
|
const project = await db.query.projects.findFirst({
|
||||||
where: eq(projects.projectId, projectId),
|
where: eq(projects.projectId, projectId),
|
||||||
with: {
|
with: {
|
||||||
|
|||||||
Reference in New Issue
Block a user