127 lines
3.0 KiB
TypeScript
127 lines
3.0 KiB
TypeScript
import { database } from '@/db';
|
|
import { account } from '@/db/schema';
|
|
import { createServerFn } from '@tanstack/react-start';
|
|
import { createInsertSchema } from 'drizzle-zod';
|
|
import { z } from 'zod/v4';
|
|
import { useAppSession } from '../utils/session';
|
|
import { eq } from 'drizzle-orm';
|
|
import { password } from 'bun';
|
|
import {
|
|
handleServerFnValidation,
|
|
unauthorizedError,
|
|
validationError,
|
|
} from '../utils/http';
|
|
import { m } from '@/paraglide/messages';
|
|
|
|
export const ChangePasswordSchema = createInsertSchema(account)
|
|
.pick({
|
|
password: true,
|
|
})
|
|
.extend({
|
|
newPassword: z.string(),
|
|
newPasswordConfirm: z.string(),
|
|
})
|
|
.refine((value) => value.newPassword === value.password, {
|
|
message: "Passwords don't match",
|
|
path: ['newPassword'],
|
|
});
|
|
|
|
export const changePassword = createServerFn({
|
|
method: 'POST',
|
|
response: 'data',
|
|
})
|
|
.validator((payload: z.infer<typeof ChangePasswordSchema>) =>
|
|
handleServerFnValidation(ChangePasswordSchema, payload),
|
|
)
|
|
.handler(async ({ data }) => {
|
|
const appSession = await useAppSession();
|
|
|
|
if (!appSession.data.sessionToken) {
|
|
throw unauthorizedError();
|
|
}
|
|
|
|
const session = await database.query.session.findFirst({
|
|
where: {
|
|
id: {
|
|
eq: appSession.data.sessionToken,
|
|
},
|
|
},
|
|
with: {
|
|
user: true,
|
|
},
|
|
});
|
|
|
|
if (!session || !session.user) {
|
|
throw unauthorizedError();
|
|
}
|
|
|
|
if (!(await password.verify(data.password, session.user.password))) {
|
|
throw validationError({
|
|
password: [m['validation.invalid-credentials']()],
|
|
});
|
|
}
|
|
|
|
await database
|
|
.update(account)
|
|
.set({
|
|
password: await password.hash(data.newPassword, 'argon2id'),
|
|
})
|
|
.where(eq(account.id, session.user.id));
|
|
|
|
return {
|
|
message: m['change-password.mutation.success'](),
|
|
};
|
|
});
|
|
|
|
export const ChangeEmailSchema = createInsertSchema(account).pick({
|
|
email: true,
|
|
password: true,
|
|
});
|
|
|
|
export const changeEmail = createServerFn({
|
|
method: 'POST',
|
|
response: 'data',
|
|
})
|
|
.validator((payload: z.infer<typeof ChangeEmailSchema>) =>
|
|
handleServerFnValidation(ChangeEmailSchema, payload),
|
|
)
|
|
.handler(async ({ data }) => {
|
|
const appSession = await useAppSession();
|
|
|
|
if (!appSession.data.sessionToken) {
|
|
throw unauthorizedError();
|
|
}
|
|
|
|
const session = await database.query.session.findFirst({
|
|
where: {
|
|
id: {
|
|
eq: appSession.data.sessionToken,
|
|
},
|
|
},
|
|
with: {
|
|
user: true,
|
|
},
|
|
});
|
|
|
|
if (!session || !session.user) {
|
|
throw unauthorizedError();
|
|
}
|
|
|
|
if (!(await password.verify(data.password, session.user.password))) {
|
|
throw validationError({
|
|
password: [m['validation.invalid-credentials']()],
|
|
});
|
|
}
|
|
|
|
await database
|
|
.update(account)
|
|
.set({
|
|
email: data.email,
|
|
})
|
|
.where(eq(account.id, session.user.id));
|
|
|
|
return {
|
|
message: m['change-email.mutation.success'](),
|
|
};
|
|
});
|