mirror of
https://codeberg.org/MarkusThielker/finances.git
synced 2025-07-01 11:09:18 +00:00
Initial commit
This commit is contained in:
commit
52aed24a96
48 changed files with 6980 additions and 0 deletions
40
src/lib/actions/signIn.ts
Normal file
40
src/lib/actions/signIn.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
import { z } from 'zod';
|
||||
import { Argon2id } from 'oslo/password';
|
||||
import { lucia, prismaClient } from '@/auth';
|
||||
import { cookies } from 'next/headers';
|
||||
import { signInFormSchema } from '@/lib/form-schemas/signInFormSchema';
|
||||
import { ActionResponse } from '@/lib/actions/types/ActionResponse';
|
||||
import { URL_HOME } from '@/lib/constants';
|
||||
|
||||
export default async function signIn({username, password}: z.infer<typeof signInFormSchema>): Promise<ActionResponse> {
|
||||
'use server';
|
||||
|
||||
const existingUser = await prismaClient.user.findFirst({
|
||||
where: {
|
||||
username: username.toLowerCase(),
|
||||
},
|
||||
});
|
||||
if (!existingUser) {
|
||||
return {
|
||||
type: 'error',
|
||||
message: 'Incorrect username or password',
|
||||
};
|
||||
}
|
||||
|
||||
const validPassword = await new Argon2id().verify(existingUser.password, password);
|
||||
if (!validPassword) {
|
||||
return {
|
||||
type: 'error',
|
||||
message: 'Incorrect username or password',
|
||||
};
|
||||
}
|
||||
|
||||
const session = await lucia.createSession(existingUser.id, {});
|
||||
const sessionCookie = lucia.createSessionCookie(session.id);
|
||||
cookies().set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);
|
||||
return {
|
||||
type: 'success',
|
||||
message: 'Signed in successfully',
|
||||
redirect: URL_HOME,
|
||||
};
|
||||
}
|
26
src/lib/actions/signOut.ts
Normal file
26
src/lib/actions/signOut.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { getSession, lucia } from '@/auth';
|
||||
import { cookies } from 'next/headers';
|
||||
import { ActionResponse } from '@/lib/actions/types/ActionResponse';
|
||||
import { URL_SIGN_IN } from '@/lib/constants';
|
||||
|
||||
export default async function signOut(): Promise<ActionResponse> {
|
||||
'use server';
|
||||
|
||||
const session = await getSession();
|
||||
if (!session) {
|
||||
return {
|
||||
type: 'error',
|
||||
message: 'You aren\'t signed in',
|
||||
};
|
||||
}
|
||||
|
||||
await lucia.invalidateSession(session.id);
|
||||
|
||||
const sessionCookie = lucia.createBlankSessionCookie();
|
||||
cookies().set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);
|
||||
return {
|
||||
type: 'success',
|
||||
message: 'Signed out successfully',
|
||||
redirect: URL_SIGN_IN,
|
||||
};
|
||||
}
|
45
src/lib/actions/signUp.ts
Normal file
45
src/lib/actions/signUp.ts
Normal file
|
@ -0,0 +1,45 @@
|
|||
import { z } from 'zod';
|
||||
import { Argon2id } from 'oslo/password';
|
||||
import { generateId } from 'lucia';
|
||||
import { lucia, prismaClient } from '@/auth';
|
||||
import { cookies } from 'next/headers';
|
||||
import { signUpFormSchema } from '@/lib/form-schemas/signUpFormSchema';
|
||||
import { ActionResponse } from '@/lib/actions/types/ActionResponse';
|
||||
import { URL_HOME } from '@/lib/constants';
|
||||
|
||||
export default async function signUp({username, password}: z.infer<typeof signUpFormSchema>): Promise<ActionResponse> {
|
||||
'use server';
|
||||
|
||||
const hashedPassword = await new Argon2id().hash(password);
|
||||
const userId = generateId(15);
|
||||
|
||||
const existingUser = await prismaClient.user.findFirst({
|
||||
where: {
|
||||
username: username.toLowerCase(),
|
||||
},
|
||||
});
|
||||
|
||||
if (existingUser) {
|
||||
return {
|
||||
type: 'error',
|
||||
message: 'Username already exists',
|
||||
};
|
||||
}
|
||||
|
||||
await prismaClient.user.create({
|
||||
data: {
|
||||
id: userId,
|
||||
username: username,
|
||||
password: hashedPassword,
|
||||
},
|
||||
});
|
||||
|
||||
const session = await lucia.createSession(userId, {});
|
||||
const sessionCookie = lucia.createSessionCookie(session.id);
|
||||
cookies().set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);
|
||||
return {
|
||||
type: 'success',
|
||||
message: 'Signed up successfully',
|
||||
redirect: URL_HOME,
|
||||
};
|
||||
}
|
5
src/lib/actions/types/ActionResponse.ts
Normal file
5
src/lib/actions/types/ActionResponse.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
export interface ActionResponse {
|
||||
type: 'success' | 'info' | 'warning' | 'error';
|
||||
message: string;
|
||||
redirect?: string;
|
||||
}
|
8
src/lib/constants.ts
Normal file
8
src/lib/constants.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
// auth urls
|
||||
export const URL_AUTH = '/auth';
|
||||
export const URL_SIGN_IN = `${URL_AUTH}/signin`;
|
||||
export const URL_SIGN_UP = `${URL_AUTH}/signup`;
|
||||
|
||||
// main urls
|
||||
export const URL_HOME = '/';
|
||||
export const URL_ACCOUNT = '/account';
|
6
src/lib/form-schemas/signInFormSchema.ts
Normal file
6
src/lib/form-schemas/signInFormSchema.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
export const signInFormSchema = z.object({
|
||||
username: z.string().min(3).max(16),
|
||||
password: z.string().min(8).max(255),
|
||||
});
|
10
src/lib/form-schemas/signUpFormSchema.ts
Normal file
10
src/lib/form-schemas/signUpFormSchema.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
export const signUpFormSchema = z.object({
|
||||
username: z.string().min(3).max(16),
|
||||
password: z.string().min(8).max(255),
|
||||
confirm: z.string().min(8).max(255),
|
||||
}).refine(data => data.password === data.confirm, {
|
||||
message: 'Passwords do not match',
|
||||
path: ['confirm'],
|
||||
});
|
6
src/lib/utils.ts
Normal file
6
src/lib/utils.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
import { type ClassValue, clsx } from 'clsx';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue