Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Video 8 #35

Open
wants to merge 1 commit into
base: video/7-enhance
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified bun.lockb
Binary file not shown.
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
"prisma"
],
"devDependencies": {
"@sveltejs/adapter-auto": "^3.0.1",
"@sveltejs/adapter-node": "^2.0.1",
"@sveltejs/adapter-node": "^2.0.2",
"@sveltejs/enhanced-img": "^0.1.7",
"@sveltejs/vite-plugin-svelte": "^3.0.1",
"@tailwindcss/forms": "^0.5.7",
Expand Down
20 changes: 19 additions & 1 deletion src/app.d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import type { Auth as AuthType } from '$lib/server/auth';
import type { PrismaClient } from '@prisma/client';
import type { AuthRequest, Session } from 'lucia';

// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
declare global {
namespace App {
// interface Error {}
// interface Locals {}
interface Locals {
db: PrismaClient;
auth: AuthRequest;
session: Session | null;
}
interface PageData {
seo?: {
title?: string;
Expand All @@ -16,6 +24,16 @@ declare global {
// interface PageState {}
// interface Platform {}
}

namespace Lucia {
type Auth = AuthType;
type DatabaseUserAttributes = {
username: string;
disallowedIngredients: string | null;
};
// eslint-disable-next-line @typescript-eslint/ban-types
type DatabaseSessionAttributes = {};
}
}

export {};
12 changes: 12 additions & 0 deletions src/hooks.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { auth } from '$lib/server/auth';
import { db } from '$lib/server/db';

import type { Handle } from '@sveltejs/kit';

export const handle: Handle = async ({ event, resolve }) => {
event.locals.db = db;
event.locals.auth = auth.handleRequest(event);
event.locals.session = await event.locals.auth.validate();

return resolve(event);
};
7 changes: 2 additions & 5 deletions src/routes/+layout.server.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import type { LayoutServerLoad } from './$types';

export const load = (async () => {
export const load = (async ({ locals }) => {
return {
user: {
username: 'Carlos',
disallowedIngredients: ['chocolat'],
},
user: locals.session?.user,
seo: {
title: 'CookConnect',
meta: {
Expand Down
15 changes: 9 additions & 6 deletions src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import type { LayoutData } from './$types';

import { enhance } from '$app/forms';
import { page } from '$app/stores';

export let data: LayoutData;
Expand Down Expand Up @@ -49,15 +50,17 @@
<nav class="flex items-center lg:order-2 sm:mx-0 mx-auto">
<ul class="contents">
<li>
<button
type="button"
class="
<form method="POST" action="/?/logout" use:enhance>
<button
type="submit"
class="
text-gray-800 hover:bg-gray-50 focus:ring-4 focus:ring-gray-300 font-medium
rounded-lg text-sm px-4 lg:px-5 py-2 lg:py-2.5 mr-2 focus:outline-none
"
>
Se déconnecter
</button>
>
Se déconnecter
</button>
</form>
</li>
<li>
<a
Expand Down
35 changes: 33 additions & 2 deletions src/routes/+page.server.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import type { PageServerLoad } from './$types';
import { fail, redirect } from '@sveltejs/kit';

import { auth } from '$lib/server/auth';

import type { Actions, PageServerLoad } from './$types';

export const load = (async ({ locals }) => {
const { session } = locals;

if (!session) {
redirect(303, '/login');
}

export const load = (async () => {
return {
seo: {
title: 'CookConnect',
Expand All @@ -11,3 +21,24 @@ export const load = (async () => {
},
};
}) satisfies PageServerLoad;

export const actions = {
logout: async ({ locals, cookies }) => {
const { session } = locals;

if (!session) {
return fail(401, { error: "Vous n'êtes pas connecté." });
}

await auth.invalidateSession(session.sessionId);

const sessionCookie = auth.createSessionCookie(null);

cookies.set(sessionCookie.name, sessionCookie.value, {
...sessionCookie.attributes,
path: sessionCookie.attributes.path ?? '/',
});

redirect(303, '/');
},
} satisfies Actions;
83 changes: 77 additions & 6 deletions src/routes/account/+page.server.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import type { PageServerLoad } from './$types';
import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library';
import { fail, redirect } from '@sveltejs/kit';

import type { Actions, PageServerLoad } from './$types';

export const load = (async ({ locals }) => {
const { session } = locals;

if (!session) {
redirect(303, '/login');
}

export const load = (async () => {
return {
user: {
username: 'Carlos',
disallowedIngredients: 'chocolat',
},
user: session.user,
seo: {
title: 'Mon profil',
meta: {
Expand All @@ -14,3 +20,68 @@ export const load = (async () => {
},
};
}) satisfies PageServerLoad;

export const actions = {
default: async ({ locals, request }) => {
const { db, session } = locals;
const data = await request.formData();

if (!session) {
redirect(303, '/login');
}

const username = data.get('username') as string;
const disallowedIngredients = data.get('disallowedIngredients') as string;

if (!username) {
return fail(422, { error: "Le nom d'utilisateur ne peut pas être vide." });
}

if (!/^[A-Za-z]+$/g.test(username)) {
return fail(422, {
error: "Le nom d'utilisateur ne doit contenir que des lettres.",
});
}

if (username.length < 3 || username.length > 20) {
return fail(400, {
error: "Le nom d'utilisateur doit être compris entre 3 et 20 caractères.",
});
}

if (disallowedIngredients) {
if (!/[a-zA-Z,]/.test(disallowedIngredients)) {
return fail(422, {
error: 'Les ingrédients ne doivent contenir que des lettres et des virgules.',
});
}
}

if (disallowedIngredients.length > 255) {
return fail(400, {
error: 'La liste des ingrédients à éviter ne peut pas dépasser 255 caractères.',
});
}

try {
await db.user.update({
where: { id: session.user.userId },
data: {
username,
disallowedIngredients,
},
});
} catch (e) {
if (e instanceof PrismaClientKnownRequestError && e.code === 'P2002') {
return fail(400, { error: "le nom d'utilisateur est déjà utilisé." });
}

// eslint-disable-next-line no-console
console.error('Error while updating user:', e);

return fail(500, {
error: "Oops... Quelque chose s'est mal passé. Veuillez réessayer plus tard.",
});
}
},
} satisfies Actions;
7 changes: 6 additions & 1 deletion src/routes/account/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@
import { prefersReducedMotion } from '$lib/utils/preferences';
import { toasts } from '$lib/utils/toats';

import type { PageData } from './$types';
import type { ActionData, PageData } from './$types';

import { enhance } from '$app/forms';

export let data: PageData;
export let form: ActionData;

$: if (form?.error) {
toasts.error(form.error);
}
</script>

<h1 class="h1">Profil</h1>
Expand Down
31 changes: 27 additions & 4 deletions src/routes/account/favourites/+page.server.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,35 @@
import { redirect } from '@sveltejs/kit';

import type { PageServerLoad } from './$types';
import type { Favourite, Recipe } from '@prisma/client';

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

export const load = (async () => {
export const load = (async ({ locals }) => {
const { session, db } = locals;

if (!session) {
redirect(303, '/login');
}

const [favourites, count] = await Promise.all([
db.favourite.findMany({
where: {
userId: session.user.userId,
},
include: {
recipe: true,
},
}),
db.favourite.count({
where: {
userId: session.user.userId,
},
}),
]);

return {
count: 0,
favourites: [] as (Favourite & { recipe: Recipe })[],
favourites,
count,
allowedPerPage: ALLOWED_PER_PAGE,
perPage: ALLOWED_PER_PAGE[0],
totalPages: 1,
Expand Down
16 changes: 14 additions & 2 deletions src/routes/login/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ import { auth } from '$lib/server/auth';

import type { Actions, PageServerLoad } from './$types';

export const load = (async () => {
export const load = (async ({ locals }) => {
const { session } = locals;

if (session) {
redirect(303, '/');
}

return {
seo: {
title: 'Se connecter',
Expand All @@ -18,7 +24,13 @@ export const load = (async () => {
}) satisfies PageServerLoad;

export const actions = {
login: async ({ request, cookies }) => {
login: async ({ request, cookies, locals }) => {
const { session } = locals;

if (session) {
redirect(303, '/');
}

const data = await request.formData();
const username = (data.get('username') ?? '') as string;
const password = (data.get('password') ?? '') as string;
Expand Down
6 changes: 3 additions & 3 deletions src/routes/recipes/[slug]/+layout.server.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library';
import { error } from '@sveltejs/kit';

import { db } from '$lib/server/db';

import type { LayoutServerLoad } from './$types';

export const load = (async ({ params }) => {
export const load = (async ({ params, locals }) => {
const { db } = locals;

try {
const recipe = await db.recipe.findUniqueOrThrow({
where: {
Expand Down
Loading