Skip to content

Commit 9f74df4

Browse files
committed
Add auth + build
1 parent e9c2375 commit 9f74df4

File tree

19 files changed

+360
-48
lines changed

19 files changed

+360
-48
lines changed

bun.lockb

-792 Bytes
Binary file not shown.

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
"prisma"
66
],
77
"devDependencies": {
8-
"@sveltejs/adapter-auto": "^3.0.1",
9-
"@sveltejs/adapter-node": "^2.0.1",
8+
"@sveltejs/adapter-node": "^2.0.2",
109
"@sveltejs/enhanced-img": "^0.1.7",
1110
"@sveltejs/vite-plugin-svelte": "^3.0.1",
1211
"@tailwindcss/forms": "^0.5.7",

src/app.d.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
1+
import type { Auth as AuthType } from '$lib/server/auth';
2+
import type { PrismaClient } from '@prisma/client';
3+
import type { AuthRequest, Session } from 'lucia';
4+
15
// See https://kit.svelte.dev/docs/types#app
26
// for information about these interfaces
37
declare global {
48
namespace App {
59
// interface Error {}
6-
// interface Locals {}
10+
interface Locals {
11+
db: PrismaClient;
12+
auth: AuthRequest;
13+
session: Session | null;
14+
}
715
interface PageData {
816
seo?: {
917
title?: string;
@@ -16,6 +24,16 @@ declare global {
1624
// interface PageState {}
1725
// interface Platform {}
1826
}
27+
28+
namespace Lucia {
29+
type Auth = AuthType;
30+
type DatabaseUserAttributes = {
31+
username: string;
32+
disallowedIngredients: string | null;
33+
};
34+
// eslint-disable-next-line @typescript-eslint/ban-types
35+
type DatabaseSessionAttributes = {};
36+
}
1937
}
2038

2139
export {};

src/hooks.server.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { auth } from '$lib/server/auth';
2+
import { db } from '$lib/server/db';
3+
4+
import type { Handle } from '@sveltejs/kit';
5+
6+
export const handle: Handle = async ({ event, resolve }) => {
7+
event.locals.db = db;
8+
event.locals.auth = auth.handleRequest(event);
9+
event.locals.session = await event.locals.auth.validate();
10+
11+
return resolve(event);
12+
};

src/routes/+layout.server.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
import type { LayoutServerLoad } from './$types';
22

3-
export const load = (async () => {
3+
export const load = (async ({ locals }) => {
44
return {
5-
user: {
6-
username: 'Carlos',
7-
disallowedIngredients: ['chocolat'],
8-
},
5+
user: locals.session?.user,
96
seo: {
107
title: 'CookConnect',
118
meta: {

src/routes/+layout.svelte

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
88
import type { LayoutData } from './$types';
99
10+
import { enhance } from '$app/forms';
1011
import { page } from '$app/stores';
1112
1213
export let data: LayoutData;
@@ -49,15 +50,17 @@
4950
<nav class="flex items-center lg:order-2 sm:mx-0 mx-auto">
5051
<ul class="contents">
5152
<li>
52-
<button
53-
type="button"
54-
class="
53+
<form method="POST" action="/?/logout" use:enhance>
54+
<button
55+
type="submit"
56+
class="
5557
text-gray-800 hover:bg-gray-50 focus:ring-4 focus:ring-gray-300 font-medium
5658
rounded-lg text-sm px-4 lg:px-5 py-2 lg:py-2.5 mr-2 focus:outline-none
5759
"
58-
>
59-
Se déconnecter
60-
</button>
60+
>
61+
Se déconnecter
62+
</button>
63+
</form>
6164
</li>
6265
<li>
6366
<a

src/routes/+page.server.ts

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
1-
import type { PageServerLoad } from './$types';
1+
import { fail, redirect } from '@sveltejs/kit';
2+
3+
import { auth } from '$lib/server/auth';
4+
5+
import type { Actions, PageServerLoad } from './$types';
6+
7+
export const load = (async ({ locals }) => {
8+
const { session } = locals;
9+
10+
if (!session) {
11+
redirect(303, '/login');
12+
}
213

3-
export const load = (async () => {
414
return {
515
seo: {
616
title: 'CookConnect',
@@ -11,3 +21,24 @@ export const load = (async () => {
1121
},
1222
};
1323
}) satisfies PageServerLoad;
24+
25+
export const actions = {
26+
logout: async ({ locals, cookies }) => {
27+
const { session } = locals;
28+
29+
if (!session) {
30+
return fail(401, { error: "Vous n'êtes pas connecté." });
31+
}
32+
33+
await auth.invalidateSession(session.sessionId);
34+
35+
const sessionCookie = auth.createSessionCookie(null);
36+
37+
cookies.set(sessionCookie.name, sessionCookie.value, {
38+
...sessionCookie.attributes,
39+
path: sessionCookie.attributes.path ?? '/',
40+
});
41+
42+
redirect(303, '/');
43+
},
44+
} satisfies Actions;

src/routes/account/+page.server.ts

Lines changed: 77 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1-
import type { PageServerLoad } from './$types';
1+
import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library';
2+
import { fail, redirect } from '@sveltejs/kit';
3+
4+
import type { Actions, PageServerLoad } from './$types';
5+
6+
export const load = (async ({ locals }) => {
7+
const { session } = locals;
8+
9+
if (!session) {
10+
redirect(303, '/login');
11+
}
212

3-
export const load = (async () => {
413
return {
5-
user: {
6-
username: 'Carlos',
7-
disallowedIngredients: 'chocolat',
8-
},
14+
user: session.user,
915
seo: {
1016
title: 'Mon profil',
1117
meta: {
@@ -14,3 +20,68 @@ export const load = (async () => {
1420
},
1521
};
1622
}) satisfies PageServerLoad;
23+
24+
export const actions = {
25+
default: async ({ locals, request }) => {
26+
const { db, session } = locals;
27+
const data = await request.formData();
28+
29+
if (!session) {
30+
redirect(303, '/login');
31+
}
32+
33+
const username = data.get('username') as string;
34+
const disallowedIngredients = data.get('disallowedIngredients') as string;
35+
36+
if (!username) {
37+
return fail(422, { error: "Le nom d'utilisateur ne peut pas être vide." });
38+
}
39+
40+
if (!/^[A-Za-z]+$/g.test(username)) {
41+
return fail(422, {
42+
error: "Le nom d'utilisateur ne doit contenir que des lettres.",
43+
});
44+
}
45+
46+
if (username.length < 3 || username.length > 20) {
47+
return fail(400, {
48+
error: "Le nom d'utilisateur doit être compris entre 3 et 20 caractères.",
49+
});
50+
}
51+
52+
if (disallowedIngredients) {
53+
if (!/[a-zA-Z,]/.test(disallowedIngredients)) {
54+
return fail(422, {
55+
error: 'Les ingrédients ne doivent contenir que des lettres et des virgules.',
56+
});
57+
}
58+
}
59+
60+
if (disallowedIngredients.length > 255) {
61+
return fail(400, {
62+
error: 'La liste des ingrédients à éviter ne peut pas dépasser 255 caractères.',
63+
});
64+
}
65+
66+
try {
67+
await db.user.update({
68+
where: { id: session.user.userId },
69+
data: {
70+
username,
71+
disallowedIngredients,
72+
},
73+
});
74+
} catch (e) {
75+
if (e instanceof PrismaClientKnownRequestError && e.code === 'P2002') {
76+
return fail(400, { error: "le nom d'utilisateur est déjà utilisé." });
77+
}
78+
79+
// eslint-disable-next-line no-console
80+
console.error('Error while updating user:', e);
81+
82+
return fail(500, {
83+
error: "Oops... Quelque chose s'est mal passé. Veuillez réessayer plus tard.",
84+
});
85+
}
86+
},
87+
} satisfies Actions;

src/routes/account/+page.svelte

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,16 @@
55
import { prefersReducedMotion } from '$lib/utils/preferences';
66
import { toasts } from '$lib/utils/toats';
77
8-
import type { PageData } from './$types';
8+
import type { ActionData, PageData } from './$types';
99
1010
import { enhance } from '$app/forms';
1111
1212
export let data: PageData;
13+
export let form: ActionData;
14+
15+
$: if (form?.error) {
16+
toasts.error(form.error);
17+
}
1318
</script>
1419

1520
<h1 class="h1">Profil</h1>

src/routes/account/favourites/+page.server.ts

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,35 @@
1+
import { redirect } from '@sveltejs/kit';
2+
13
import type { PageServerLoad } from './$types';
2-
import type { Favourite, Recipe } from '@prisma/client';
34

45
const ALLOWED_PER_PAGE = [10, 25, 50, 100];
56

6-
export const load = (async () => {
7+
export const load = (async ({ locals }) => {
8+
const { session, db } = locals;
9+
10+
if (!session) {
11+
redirect(303, '/login');
12+
}
13+
14+
const [favourites, count] = await Promise.all([
15+
db.favourite.findMany({
16+
where: {
17+
userId: session.user.userId,
18+
},
19+
include: {
20+
recipe: true,
21+
},
22+
}),
23+
db.favourite.count({
24+
where: {
25+
userId: session.user.userId,
26+
},
27+
}),
28+
]);
29+
730
return {
8-
count: 0,
9-
favourites: [] as (Favourite & { recipe: Recipe })[],
31+
favourites,
32+
count,
1033
allowedPerPage: ALLOWED_PER_PAGE,
1134
perPage: ALLOWED_PER_PAGE[0],
1235
totalPages: 1,

0 commit comments

Comments
 (0)