feat: add email and password change endpoints to profile routes
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { Elysia, t } from 'elysia';
|
import { Elysia, t } from 'elysia';
|
||||||
import { db } from '../db';
|
import { db } from '../db';
|
||||||
import { users, userProfiles } from '../db/schema';
|
import { users, userProfiles, accounts } from '../db/schema';
|
||||||
import { eq } from 'drizzle-orm';
|
import { eq, and } from 'drizzle-orm';
|
||||||
import type { User } from '../lib/auth';
|
import type { User } from '../lib/auth';
|
||||||
|
|
||||||
export const profileRoutes = new Elysia({ prefix: '/profile' })
|
export const profileRoutes = new Elysia({ prefix: '/profile' })
|
||||||
@@ -96,4 +96,76 @@ export const profileRoutes = new Elysia({ prefix: '/profile' })
|
|||||||
phone: t.Optional(t.String()),
|
phone: t.Optional(t.String()),
|
||||||
emailSignature: t.Optional(t.String()),
|
emailSignature: t.Optional(t.String()),
|
||||||
}),
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
// Change email
|
||||||
|
.put('/email', async ({ body, user, set }: {
|
||||||
|
body: { newEmail: string };
|
||||||
|
user: User;
|
||||||
|
set: any;
|
||||||
|
}) => {
|
||||||
|
// Check if email is already taken
|
||||||
|
const [existing] = await db.select({ id: users.id })
|
||||||
|
.from(users)
|
||||||
|
.where(eq(users.email, body.newEmail))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (existing && existing.id !== user.id) {
|
||||||
|
set.status = 400;
|
||||||
|
throw new Error('Email is already in use');
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.update(users)
|
||||||
|
.set({ email: body.newEmail, updatedAt: new Date() })
|
||||||
|
.where(eq(users.id, user.id));
|
||||||
|
|
||||||
|
return { success: true, email: body.newEmail };
|
||||||
|
}, {
|
||||||
|
body: t.Object({
|
||||||
|
newEmail: t.String({ format: 'email' }),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
// Change password
|
||||||
|
.put('/password', async ({ body, user, set }: {
|
||||||
|
body: { currentPassword: string; newPassword: string };
|
||||||
|
user: User;
|
||||||
|
set: any;
|
||||||
|
}) => {
|
||||||
|
// Get current password hash from accounts table
|
||||||
|
const [account] = await db.select({ password: accounts.password })
|
||||||
|
.from(accounts)
|
||||||
|
.where(and(
|
||||||
|
eq(accounts.userId, user.id),
|
||||||
|
eq(accounts.providerId, 'credential'),
|
||||||
|
))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (!account?.password) {
|
||||||
|
set.status = 400;
|
||||||
|
throw new Error('No password set for this account');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify current password
|
||||||
|
const isValid = await Bun.password.verify(body.currentPassword, account.password);
|
||||||
|
if (!isValid) {
|
||||||
|
set.status = 400;
|
||||||
|
throw new Error('Current password is incorrect');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash and update new password
|
||||||
|
const hashedPassword = await Bun.password.hash(body.newPassword, { algorithm: 'bcrypt', cost: 10 });
|
||||||
|
await db.update(accounts)
|
||||||
|
.set({ password: hashedPassword, updatedAt: new Date() })
|
||||||
|
.where(and(
|
||||||
|
eq(accounts.userId, user.id),
|
||||||
|
eq(accounts.providerId, 'credential'),
|
||||||
|
));
|
||||||
|
|
||||||
|
return { success: true };
|
||||||
|
}, {
|
||||||
|
body: t.Object({
|
||||||
|
currentPassword: t.String(),
|
||||||
|
newPassword: t.String({ minLength: 8 }),
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user