mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
feat: improve user profile update and password change functionality
This commit adds enhanced password change validation and handling: - Add password change validation in user update route - Implement password verification before allowing changes - Update user schema to support optional password fields - Fix token display in generate token component - Disable migration script temporarily
This commit is contained in:
@@ -51,7 +51,7 @@ export const GenerateToken = () => {
|
||||
<Label>Token</Label>
|
||||
<ToggleVisibilityInput
|
||||
placeholder="Token"
|
||||
value={data || ""}
|
||||
value={data?.id || ""}
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -103,9 +103,9 @@ export const ProfileForm = () => {
|
||||
const onSubmit = async (values: Profile) => {
|
||||
await mutateAsync({
|
||||
email: values.email.toLowerCase(),
|
||||
password: values.password,
|
||||
password: values.password || undefined,
|
||||
image: values.image,
|
||||
currentPassword: values.currentPassword,
|
||||
currentPassword: values.currentPassword || undefined,
|
||||
})
|
||||
.then(async () => {
|
||||
await refetch();
|
||||
|
||||
@@ -1,149 +1,149 @@
|
||||
import { drizzle } from "drizzle-orm/postgres-js";
|
||||
import { nanoid } from "nanoid";
|
||||
import postgres from "postgres";
|
||||
import * as schema from "./server/db/schema";
|
||||
// import { drizzle } from "drizzle-orm/postgres-js";
|
||||
// import { nanoid } from "nanoid";
|
||||
// import postgres from "postgres";
|
||||
// import * as schema from "./server/db/schema";
|
||||
|
||||
const connectionString = process.env.DATABASE_URL!;
|
||||
// const connectionString = process.env.DATABASE_URL!;
|
||||
|
||||
const sql = postgres(connectionString, { max: 1 });
|
||||
const db = drizzle(sql, {
|
||||
schema,
|
||||
});
|
||||
// const sql = postgres(connectionString, { max: 1 });
|
||||
// const db = drizzle(sql, {
|
||||
// schema,
|
||||
// });
|
||||
|
||||
await db
|
||||
.transaction(async (db) => {
|
||||
const admins = await db.query.admins.findMany({
|
||||
with: {
|
||||
auth: true,
|
||||
users: {
|
||||
with: {
|
||||
auth: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
for (const admin of admins) {
|
||||
const user = await db
|
||||
.insert(schema.users_temp)
|
||||
.values({
|
||||
id: admin.adminId,
|
||||
email: admin.auth.email,
|
||||
token: admin.auth.token || "",
|
||||
emailVerified: true,
|
||||
updatedAt: new Date(),
|
||||
role: "admin",
|
||||
serverIp: admin.serverIp,
|
||||
image: admin.auth.image,
|
||||
certificateType: admin.certificateType,
|
||||
host: admin.host,
|
||||
letsEncryptEmail: admin.letsEncryptEmail,
|
||||
sshPrivateKey: admin.sshPrivateKey,
|
||||
enableDockerCleanup: admin.enableDockerCleanup,
|
||||
enableLogRotation: admin.enableLogRotation,
|
||||
enablePaidFeatures: admin.enablePaidFeatures,
|
||||
metricsConfig: admin.metricsConfig,
|
||||
cleanupCacheApplications: admin.cleanupCacheApplications,
|
||||
cleanupCacheOnPreviews: admin.cleanupCacheOnPreviews,
|
||||
cleanupCacheOnCompose: admin.cleanupCacheOnCompose,
|
||||
stripeCustomerId: admin.stripeCustomerId,
|
||||
stripeSubscriptionId: admin.stripeSubscriptionId,
|
||||
serversQuantity: admin.serversQuantity,
|
||||
})
|
||||
.returning()
|
||||
.then((user) => user[0]);
|
||||
// await db
|
||||
// .transaction(async (db) => {
|
||||
// const admins = await db.query.admins.findMany({
|
||||
// with: {
|
||||
// auth: true,
|
||||
// users: {
|
||||
// with: {
|
||||
// auth: true,
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
// for (const admin of admins) {
|
||||
// const user = await db
|
||||
// .insert(schema.users_temp)
|
||||
// .values({
|
||||
// id: admin.adminId,
|
||||
// email: admin.auth.email,
|
||||
// token: admin.auth.token || "",
|
||||
// emailVerified: true,
|
||||
// updatedAt: new Date(),
|
||||
// role: "admin",
|
||||
// serverIp: admin.serverIp,
|
||||
// image: admin.auth.image,
|
||||
// certificateType: admin.certificateType,
|
||||
// host: admin.host,
|
||||
// letsEncryptEmail: admin.letsEncryptEmail,
|
||||
// sshPrivateKey: admin.sshPrivateKey,
|
||||
// enableDockerCleanup: admin.enableDockerCleanup,
|
||||
// enableLogRotation: admin.enableLogRotation,
|
||||
// enablePaidFeatures: admin.enablePaidFeatures,
|
||||
// metricsConfig: admin.metricsConfig,
|
||||
// cleanupCacheApplications: admin.cleanupCacheApplications,
|
||||
// cleanupCacheOnPreviews: admin.cleanupCacheOnPreviews,
|
||||
// cleanupCacheOnCompose: admin.cleanupCacheOnCompose,
|
||||
// stripeCustomerId: admin.stripeCustomerId,
|
||||
// stripeSubscriptionId: admin.stripeSubscriptionId,
|
||||
// serversQuantity: admin.serversQuantity,
|
||||
// })
|
||||
// .returning()
|
||||
// .then((user) => user[0]);
|
||||
|
||||
await db.insert(schema.account).values({
|
||||
providerId: "credential",
|
||||
userId: user?.id || "",
|
||||
password: admin.auth.password,
|
||||
is2FAEnabled: admin.auth.is2FAEnabled || false,
|
||||
createdAt: new Date(admin.auth.createdAt) || new Date(),
|
||||
updatedAt: new Date(admin.auth.createdAt) || new Date(),
|
||||
});
|
||||
// await db.insert(schema.account).values({
|
||||
// providerId: "credential",
|
||||
// userId: user?.id || "",
|
||||
// password: admin.auth.password,
|
||||
// is2FAEnabled: admin.auth.is2FAEnabled || false,
|
||||
// createdAt: new Date(admin.auth.createdAt) || new Date(),
|
||||
// updatedAt: new Date(admin.auth.createdAt) || new Date(),
|
||||
// });
|
||||
|
||||
const organization = await db
|
||||
.insert(schema.organization)
|
||||
.values({
|
||||
name: "My Organization",
|
||||
slug: nanoid(),
|
||||
ownerId: user?.id || "",
|
||||
createdAt: new Date(admin.createdAt) || new Date(),
|
||||
})
|
||||
.returning()
|
||||
.then((organization) => organization[0]);
|
||||
// const organization = await db
|
||||
// .insert(schema.organization)
|
||||
// .values({
|
||||
// name: "My Organization",
|
||||
// slug: nanoid(),
|
||||
// ownerId: user?.id || "",
|
||||
// createdAt: new Date(admin.createdAt) || new Date(),
|
||||
// })
|
||||
// .returning()
|
||||
// .then((organization) => organization[0]);
|
||||
|
||||
for (const member of admin.users) {
|
||||
const userTemp = await db
|
||||
.insert(schema.users_temp)
|
||||
.values({
|
||||
id: member.userId,
|
||||
email: member.auth.email,
|
||||
token: member.token || "",
|
||||
emailVerified: true,
|
||||
updatedAt: new Date(admin.createdAt) || new Date(),
|
||||
role: "user",
|
||||
image: member.auth.image,
|
||||
createdAt: admin.createdAt,
|
||||
canAccessToAPI: member.canAccessToAPI || false,
|
||||
canAccessToDocker: member.canAccessToDocker || false,
|
||||
canAccessToGitProviders: member.canAccessToGitProviders || false,
|
||||
canAccessToSSHKeys: member.canAccessToSSHKeys || false,
|
||||
canAccessToTraefikFiles: member.canAccessToTraefikFiles || false,
|
||||
canCreateProjects: member.canCreateProjects || false,
|
||||
canCreateServices: member.canCreateServices || false,
|
||||
canDeleteProjects: member.canDeleteProjects || false,
|
||||
canDeleteServices: member.canDeleteServices || false,
|
||||
accessedProjects: member.accessedProjects || [],
|
||||
accessedServices: member.accessedServices || [],
|
||||
})
|
||||
.returning()
|
||||
.then((userTemp) => userTemp[0]);
|
||||
// for (const member of admin.users) {
|
||||
// const userTemp = await db
|
||||
// .insert(schema.users_temp)
|
||||
// .values({
|
||||
// id: member.userId,
|
||||
// email: member.auth.email,
|
||||
// token: member.token || "",
|
||||
// emailVerified: true,
|
||||
// updatedAt: new Date(admin.createdAt) || new Date(),
|
||||
// role: "user",
|
||||
// image: member.auth.image,
|
||||
// createdAt: admin.createdAt,
|
||||
// canAccessToAPI: member.canAccessToAPI || false,
|
||||
// canAccessToDocker: member.canAccessToDocker || false,
|
||||
// canAccessToGitProviders: member.canAccessToGitProviders || false,
|
||||
// canAccessToSSHKeys: member.canAccessToSSHKeys || false,
|
||||
// canAccessToTraefikFiles: member.canAccessToTraefikFiles || false,
|
||||
// canCreateProjects: member.canCreateProjects || false,
|
||||
// canCreateServices: member.canCreateServices || false,
|
||||
// canDeleteProjects: member.canDeleteProjects || false,
|
||||
// canDeleteServices: member.canDeleteServices || false,
|
||||
// accessedProjects: member.accessedProjects || [],
|
||||
// accessedServices: member.accessedServices || [],
|
||||
// })
|
||||
// .returning()
|
||||
// .then((userTemp) => userTemp[0]);
|
||||
|
||||
await db.insert(schema.account).values({
|
||||
providerId: "credential",
|
||||
userId: member?.userId || "",
|
||||
password: member.auth.password,
|
||||
is2FAEnabled: member.auth.is2FAEnabled || false,
|
||||
createdAt: new Date(member.auth.createdAt) || new Date(),
|
||||
updatedAt: new Date(member.auth.createdAt) || new Date(),
|
||||
});
|
||||
// await db.insert(schema.account).values({
|
||||
// providerId: "credential",
|
||||
// userId: member?.userId || "",
|
||||
// password: member.auth.password,
|
||||
// is2FAEnabled: member.auth.is2FAEnabled || false,
|
||||
// createdAt: new Date(member.auth.createdAt) || new Date(),
|
||||
// updatedAt: new Date(member.auth.createdAt) || new Date(),
|
||||
// });
|
||||
|
||||
await db.insert(schema.member).values({
|
||||
organizationId: organization?.id || "",
|
||||
userId: userTemp?.id || "",
|
||||
role: "admin",
|
||||
createdAt: new Date(member.createdAt) || new Date(),
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
console.log("Migration finished");
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
});
|
||||
// await db.insert(schema.member).values({
|
||||
// organizationId: organization?.id || "",
|
||||
// userId: userTemp?.id || "",
|
||||
// role: "admin",
|
||||
// createdAt: new Date(member.createdAt) || new Date(),
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
// .then(() => {
|
||||
// console.log("Migration finished");
|
||||
// })
|
||||
// .catch((error) => {
|
||||
// console.error(error);
|
||||
// });
|
||||
|
||||
await db
|
||||
.transaction(async (db) => {
|
||||
const projects = await db.query.projects.findMany({
|
||||
with: {
|
||||
user: {
|
||||
with: {
|
||||
organizations: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
for (const project of projects) {
|
||||
const _user = await db.update(schema.projects).set({
|
||||
organizationId: project.user.organizations[0]?.id || "",
|
||||
});
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
console.log("Migration finished");
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
});
|
||||
// await db
|
||||
// .transaction(async (db) => {
|
||||
// const projects = await db.query.projects.findMany({
|
||||
// with: {
|
||||
// user: {
|
||||
// with: {
|
||||
// organizations: true,
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
// for (const project of projects) {
|
||||
// const _user = await db.update(schema.projects).set({
|
||||
// organizationId: project.user.organizations[0]?.id || "",
|
||||
// });
|
||||
// }
|
||||
// })
|
||||
// .then(() => {
|
||||
// console.log("Migration finished");
|
||||
// })
|
||||
// .catch((error) => {
|
||||
// console.error(error);
|
||||
// });
|
||||
|
||||
@@ -8,12 +8,14 @@ import {
|
||||
} from "@dokploy/server";
|
||||
import { db } from "@dokploy/server/db";
|
||||
import {
|
||||
account,
|
||||
apiAssignPermissions,
|
||||
apiFindOneToken,
|
||||
apiUpdateUser,
|
||||
invitation,
|
||||
member,
|
||||
} from "@dokploy/server/db/schema";
|
||||
import * as bcrypt from "bcrypt";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { and, asc, eq, gt } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
@@ -81,6 +83,35 @@ export const userRouter = createTRPCRouter({
|
||||
update: protectedProcedure
|
||||
.input(apiUpdateUser)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
if (input.password || input.currentPassword) {
|
||||
const currentAuth = await db.query.account.findFirst({
|
||||
where: eq(account.userId, ctx.user.id),
|
||||
});
|
||||
const correctPassword = bcrypt.compareSync(
|
||||
input.currentPassword || "",
|
||||
currentAuth?.password || "",
|
||||
);
|
||||
|
||||
if (!correctPassword) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Current password is incorrect",
|
||||
});
|
||||
}
|
||||
|
||||
if (!input.password) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "New password is required",
|
||||
});
|
||||
}
|
||||
await db
|
||||
.update(account)
|
||||
.set({
|
||||
password: bcrypt.hashSync(input.password, 10),
|
||||
})
|
||||
.where(eq(account.userId, ctx.user.id));
|
||||
}
|
||||
return await updateUser(ctx.user.id, input);
|
||||
}),
|
||||
getUserByToken: publicProcedure
|
||||
|
||||
Reference in New Issue
Block a user