From 479e8bb551bb0b226a8c7477d7d732ab73ff409e Mon Sep 17 00:00:00 2001 From: Shuvo Date: Mon, 17 Aug 2026 12:41:58 +0600 Subject: [PATCH 1/4] feat: refactor serviceColumns for project access and enhance data retrieval --- apps/dokploy/server/api/routers/project.ts | 25 ++++++++++++++++++++++ packages/server/src/services/project.ts | 18 ++++++++-------- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/apps/dokploy/server/api/routers/project.ts b/apps/dokploy/server/api/routers/project.ts index 2e35aee2a..43d2cf792 100644 --- a/apps/dokploy/server/api/routers/project.ts +++ b/apps/dokploy/server/api/routers/project.ts @@ -38,6 +38,7 @@ import { checkProjectAccess, findMemberByUserId, } from "@dokploy/server/services/permission"; +import { serviceColumns } from "@dokploy/server/services/project"; import { TRPCError } from "@trpc/server"; import { and, desc, eq, ilike, or, sql } from "drizzle-orm"; import type { AnyPgColumn } from "drizzle-orm/pg-core"; @@ -130,39 +131,63 @@ export const projectRouter = createTRPCRouter({ environments: { with: { applications: { + columns: { + ...serviceColumns, + applicationId: true, + icon: true, + }, + with: { server: { columns: { name: true } } }, where: buildServiceFilter( applications.applicationId, accessedServices, ), }, compose: { + columns: { + ...serviceColumns, + composeId: true, + composeStatus: true, + }, + with: { server: { columns: { name: true } } }, where: buildServiceFilter( compose.composeId, accessedServices, ), }, libsql: { + columns: { ...serviceColumns, libsqlId: true }, + with: { server: { columns: { name: true } } }, where: buildServiceFilter(libsql.libsqlId, accessedServices), }, mariadb: { + columns: { ...serviceColumns, mariadbId: true }, + with: { server: { columns: { name: true } } }, where: buildServiceFilter( mariadb.mariadbId, accessedServices, ), }, mongo: { + columns: { ...serviceColumns, mongoId: true }, + with: { server: { columns: { name: true } } }, where: buildServiceFilter(mongo.mongoId, accessedServices), }, mysql: { + columns: { ...serviceColumns, mysqlId: true }, + with: { server: { columns: { name: true } } }, where: buildServiceFilter(mysql.mysqlId, accessedServices), }, postgres: { + columns: { ...serviceColumns, postgresId: true }, + with: { server: { columns: { name: true } } }, where: buildServiceFilter( postgres.postgresId, accessedServices, ), }, redis: { + columns: { ...serviceColumns, redisId: true }, + with: { server: { columns: { name: true } } }, where: buildServiceFilter(redis.redisId, accessedServices), }, }, diff --git a/packages/server/src/services/project.ts b/packages/server/src/services/project.ts index 52ef679b4..04a628a86 100644 --- a/packages/server/src/services/project.ts +++ b/packages/server/src/services/project.ts @@ -47,16 +47,16 @@ export const createProject = async ( }; }; -export const findProjectById = async (projectId: string) => { - const serviceColumns = { - name: true, - description: true, - appName: true, - createdAt: true, - serverId: true, - applicationStatus: true, - } as const; +export const serviceColumns = { + name: true, + description: true, + appName: true, + createdAt: true, + serverId: true, + applicationStatus: true, +} as const; +export const findProjectById = async (projectId: string) => { const project = await db.query.projects.findFirst({ where: eq(projects.projectId, projectId), with: { From dada3049a84768c134f127c447e4489fb9bfd87e Mon Sep 17 00:00:00 2001 From: Shuvo Date: Mon, 31 Aug 2026 22:33:08 +0600 Subject: [PATCH 2/4] feat: allow reset-password script to target a specific user by email Previously reset-password only reset the owner account's password. Passing an email as an argument now resets that specific user's password instead, while omitting it keeps the existing owner-reset behavior. Also scopes the update to the credential (password-based) account row via providerId, and fixes the success check to verify a row was actually updated instead of always reporting success. --- CONTRIBUTING.md | 10 +++++++++- apps/dokploy/reset-password.ts | 32 ++++++++++++++++++++++++++------ 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4fa0dd358..daf538b1a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -120,12 +120,20 @@ pnpm run docker:push ## Password Reset -In the case you lost your password, you can reset it using the following command +In the case you lost your password, you can reset the owner's password using the following command ```bash pnpm run reset-password ``` +To reset the password of a specific user instead, pass their email as an argument + +```bash +pnpm run reset-password -- user@example.com +``` + +Both commands print the new randomly generated password to the console. + If you want to test the webhooks on development mode using localtunnel, make sure to install [`localtunnel`](https://localtunnel.app/) ```bash diff --git a/apps/dokploy/reset-password.ts b/apps/dokploy/reset-password.ts index 5b1db9bcf..9d42ac8d9 100644 --- a/apps/dokploy/reset-password.ts +++ b/apps/dokploy/reset-password.ts @@ -1,30 +1,50 @@ import { findOwner, generateRandomPassword } from "@dokploy/server"; import { db } from "@dokploy/server/db"; -import { account } from "@dokploy/server/db/schema"; -import { eq } from "drizzle-orm"; +import { account, user } from "@dokploy/server/db/schema"; +import { and, eq } from "drizzle-orm"; (async () => { try { + const email = process.argv[2]; + const randomPassword = await generateRandomPassword(); - const result = await findOwner(); + let userId: string; + + if (email) { + const foundUser = await db.query.user.findFirst({ + where: eq(user.email, email), + }); + + if (!foundUser) { + console.log(`User not found for email: ${email}`); + process.exit(1); + } + + userId = foundUser.id; + } else { + const owner = await findOwner(); + userId = owner.userId; + } const update = await db .update(account) .set({ password: randomPassword.hashedPassword, }) - .where(eq(account.userId, result.userId)); + .where(and(eq(account.userId, userId), eq(account.providerId, "credential"))); - if (update) { + if (update.count > 0) { console.log("Password reset successful"); console.log("New password: ", randomPassword.randomPassword); } else { - console.log("Password reset failed"); + console.log("Password reset failed: no credential account found for this user"); + process.exit(1); } process.exit(0); } catch (error) { console.log("Error resetting password", error); + process.exit(1); } })(); From 714bf032441390c6a3afb066a54d8a55a228913d Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 31 Aug 2026 16:33:47 +0000 Subject: [PATCH 3/4] [autofix.ci] apply automated fixes --- .../components/dashboard/docker/logs/terminal-line.tsx | 4 +++- apps/dokploy/reset-password.ts | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/dokploy/components/dashboard/docker/logs/terminal-line.tsx b/apps/dokploy/components/dashboard/docker/logs/terminal-line.tsx index 458f4f051..6efe0a118 100644 --- a/apps/dokploy/components/dashboard/docker/logs/terminal-line.tsx +++ b/apps/dokploy/components/dashboard/docker/logs/terminal-line.tsx @@ -64,7 +64,9 @@ export function TerminalLine({ log, noTimestamp, searchTerm }: LogLineProps) { const tooltip = (color: string, timestamp: string | null) => { const square = ( -
+
); return timestamp ? ( diff --git a/apps/dokploy/reset-password.ts b/apps/dokploy/reset-password.ts index 9d42ac8d9..3c08d89b6 100644 --- a/apps/dokploy/reset-password.ts +++ b/apps/dokploy/reset-password.ts @@ -32,13 +32,17 @@ import { and, eq } from "drizzle-orm"; .set({ password: randomPassword.hashedPassword, }) - .where(and(eq(account.userId, userId), eq(account.providerId, "credential"))); + .where( + and(eq(account.userId, userId), eq(account.providerId, "credential")), + ); if (update.count > 0) { console.log("Password reset successful"); console.log("New password: ", randomPassword.randomPassword); } else { - console.log("Password reset failed: no credential account found for this user"); + console.log( + "Password reset failed: no credential account found for this user", + ); process.exit(1); } From 8db39a8d1584d37f8c4b2dfb673f7712272d0ea2 Mon Sep 17 00:00:00 2001 From: Shuvo Date: Mon, 31 Aug 2026 22:46:09 +0600 Subject: [PATCH 4/4] fix: normalize email argument before lookup in reset-password Trims and lowercases the CLI email arg to match the normalization used elsewhere for user emails, so a differently-cased or whitespace-padded email no longer falsely reports "User not found". --- apps/dokploy/reset-password.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/dokploy/reset-password.ts b/apps/dokploy/reset-password.ts index 3c08d89b6..4dded1f7c 100644 --- a/apps/dokploy/reset-password.ts +++ b/apps/dokploy/reset-password.ts @@ -5,7 +5,7 @@ import { and, eq } from "drizzle-orm"; (async () => { try { - const email = process.argv[2]; + const email = process.argv[2]?.trim().toLowerCase(); const randomPassword = await generateRandomPassword();