diff --git a/sample.env.local b/.env.example similarity index 56% rename from sample.env.local rename to .env.example index 79aa9e4..c861bb7 100644 --- a/sample.env.local +++ b/.env.example @@ -1,9 +1,10 @@ # rename file to .env.local -## Postgres -CONNECTION_STRING='' - ## Google Auth GOOGLE_CLIENT_ID='' GOOGLE_CLIENT_SECRET='' -REDIRECT_URI='' \ No newline at end of file +REDIRECT_URI='' + +## TURSO +TURSO_CONNECTION_URL='' +TURSO_AUTH_TOKEN='' \ No newline at end of file diff --git a/.gitignore b/.gitignore index 6635cf5..fe6a775 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,4 @@ node_modules .env.* !.env.example vite.config.js.timestamp-* -vite.config.ts.timestamp-* +vite.config.ts.timestamp-* \ No newline at end of file diff --git a/src/hooks.server.ts b/src/hooks.server.ts index a10cb63..cce8fad 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -1,7 +1,7 @@ import { lucia } from "$lib/server/auth"; import type { Handle } from "@sveltejs/kit"; -let sessionAndUserInfo:any = {} +const sessionAndUserInfo: { [key: string]: App.Locals } = {}; export const handle: Handle = async ({ event, resolve }) => { console.time('hook.server') @@ -15,16 +15,16 @@ export const handle: Handle = async ({ event, resolve }) => { console.log('session id exists') console.time('validate') - let {session, user} = sessionAndUserInfo[sessionId]|| {} - if(!session || !user){ - ({ session, user } = await lucia.validateSession(sessionId)) - sessionAndUserInfo[sessionId] = {session,user} + let { session, user } = sessionAndUserInfo[sessionId] || {} + if (!session || !user) { + ({ session, user } = await lucia.validateSession(sessionId)) + sessionAndUserInfo[sessionId] = { session, user } } console.timeEnd('validate') //session exists in db & has not expired - if (session && session.fresh) { + if (session?.fresh) { const sessionCookie = lucia.createSessionCookie(session.id); event.cookies.set(sessionCookie.name, sessionCookie.value, { path: ".", diff --git a/src/lib/common.util.ts b/src/lib/common.util.ts index f57e8b7..c1ea8fa 100644 --- a/src/lib/common.util.ts +++ b/src/lib/common.util.ts @@ -1,4 +1,10 @@ +import type { Session, User } from "lucia"; + // for debugging & simulating real-world delays export function sleep(ms: number) { return new Promise(resolve => setTimeout(resolve, ms)); } + +export function sessionExists(locals: App.Locals): locals is App.Locals & { session: Session, user: User } { + return !!locals?.session?.id && !!locals?.user?.id +} \ No newline at end of file diff --git a/src/lib/db/tables/card.table.ts b/src/lib/db/tables/card.table.ts index 18f553c..9882d99 100644 --- a/src/lib/db/tables/card.table.ts +++ b/src/lib/db/tables/card.table.ts @@ -1,6 +1,6 @@ import { db } from '$lib/db/turso.db'; import { cardTable } from '$lib/db/turso.schema'; -import { eq } from 'drizzle-orm'; +import { and, eq } from 'drizzle-orm'; export const insertCard = async (values: { id: string; @@ -25,5 +25,16 @@ export const getCards = async (userId: string) => { return data } catch (err) { console.error('getCards ~ err:', err) + return [] } } + +export const deleteCard = async ({ cardId, userId }: { cardId: string, userId: string }) => { + try { + console.time('deleteCard') + await db.delete(cardTable).where(and(eq(cardTable.id, cardId), eq(cardTable.userId, userId))) + console.timeEnd('deleteCard') + } catch (err) { + console.error('deleteCard ~ err:', err) + } +} \ No newline at end of file diff --git a/src/routes/(auth)/+layout.server.ts b/src/routes/(auth)/+layout.server.ts index 36ef9c5..1ef4f99 100644 --- a/src/routes/(auth)/+layout.server.ts +++ b/src/routes/(auth)/+layout.server.ts @@ -1,9 +1,10 @@ +import { sessionExists } from "$lib/common.util.js"; import { ROUTES } from "$lib/routes.util.js"; import { redirect } from "@sveltejs/kit"; export async function load({ locals }) { console.log('auth') - if (locals.user) { + if (sessionExists(locals)) { redirect(302, ROUTES.HOME) } } \ No newline at end of file diff --git a/src/routes/(auth)/login/google/callback/+server.ts b/src/routes/(auth)/login/google/callback/+server.ts index d64e32f..201e94a 100644 --- a/src/routes/(auth)/login/google/callback/+server.ts +++ b/src/routes/(auth)/login/google/callback/+server.ts @@ -3,6 +3,7 @@ import { google, lucia } from "$lib/server/auth"; import type { RequestEvent } from "@sveltejs/kit"; import { getGoogleUserWhereEmail, insertOrUpdateGoogleUser } from "$lib/db/tables/user.table"; +import { ROUTES } from "$lib/routes.util"; export async function GET(event: RequestEvent): Promise { const code = event.url.searchParams.get("code"); @@ -27,34 +28,32 @@ export async function GET(event: RequestEvent): Promise { const user = await response.json(); const existingUser = await getGoogleUserWhereEmail(user.email); + let userId = null; if (existingUser) { await insertOrUpdateGoogleUser({ id: existingUser.id, ...user }); - const session = await lucia.createSession(existingUser.id, {}); - const sessionCookie = lucia.createSessionCookie(session.id); - event.cookies.set(sessionCookie.name, sessionCookie.value, { - path: ".", - ...sessionCookie.attributes - }); + userId = existingUser.id; } else { - const userId = crypto.randomUUID(); + const newUserId = crypto.randomUUID(); await insertOrUpdateGoogleUser({ - id: userId, + id: newUserId, ...user }); - const session = await lucia.createSession(userId, {}); - const sessionCookie = lucia.createSessionCookie(session.id); - event.cookies.set(sessionCookie.name, sessionCookie.value, { - path: ".", - ...sessionCookie.attributes - }); + userId = newUserId; } + + const session = await lucia.createSession(userId, {}); + const sessionCookie = lucia.createSessionCookie(session.id); + event.cookies.set(sessionCookie.name, sessionCookie.value, { + path: ".", + ...sessionCookie.attributes + }); return new Response(null, { status: 302, headers: { - Location: "/" + Location: ROUTES.HOME } }); } catch (e) { diff --git a/src/routes/(protected)/+layout.server.ts b/src/routes/(protected)/+layout.server.ts index b6e9b8d..f61dfa4 100644 --- a/src/routes/(protected)/+layout.server.ts +++ b/src/routes/(protected)/+layout.server.ts @@ -1,9 +1,10 @@ +import { sessionExists } from "$lib/common.util.js"; import { ROUTES } from "$lib/routes.util.js"; import { redirect } from "@sveltejs/kit"; export async function load({ locals }) { console.log('protected') - if (!locals.user) { + if (!sessionExists(locals)) { redirect(302, ROUTES.LOGIN) } } \ No newline at end of file diff --git a/src/routes/(protected)/all/+page.server.ts b/src/routes/(protected)/all/+page.server.ts new file mode 100644 index 0000000..aa7ed74 --- /dev/null +++ b/src/routes/(protected)/all/+page.server.ts @@ -0,0 +1,35 @@ +import { sessionExists } from '$lib/common.util.js'; +import { deleteCard, getCards } from '$lib/db/tables/card.table.js'; +import { ROUTES } from '$lib/routes.util.js'; +import { redirect } from '@sveltejs/kit'; + +export async function load({ locals }) { + if (!sessionExists(locals)) { + redirect(302, ROUTES.LOGIN) + } + const cards = await getCards(locals.user.id) + return { cards }; +} + +export const actions = { + delete: async function ({ locals, request }) { + const data = await request.formData(); + const id = data.get('id') as string + + try { + if (!sessionExists(locals)) { + redirect(302, ROUTES.LOGIN); + } + if (!id) { + return { status: 400, body: { message: 'No id provided' } }; + } + await deleteCard({ + cardId: id, + userId: locals.user.id, + }); + redirect(302, ROUTES.HOME); + } catch (err) { + console.error('delete ~ err:', err); + } + } +} \ No newline at end of file diff --git a/src/routes/(protected)/all/+page.svelte b/src/routes/(protected)/all/+page.svelte new file mode 100644 index 0000000..f6e171b --- /dev/null +++ b/src/routes/(protected)/all/+page.svelte @@ -0,0 +1,15 @@ + + +{#each data.cards as card} +
+
{card.front}
+
{card.back}
+
+ + +
+
+
+{/each} diff --git a/src/routes/(protected)/home/+page.server.ts b/src/routes/(protected)/home/+page.server.ts index 9efa6c4..dfe20e7 100644 --- a/src/routes/(protected)/home/+page.server.ts +++ b/src/routes/(protected)/home/+page.server.ts @@ -7,10 +7,11 @@ import { ROUTES } from "$lib/routes.util.js"; import type { RequestEvent } from "./$types.js"; import { getCards, insertCard } from "$lib/db/tables/card.table.js"; import { cardAddSchema, cardReviewSchema } from "$lib/schemas.js"; +import { sessionExists } from "$lib/common.util.js"; export async function load({ locals }) { - if (!locals?.user?.id) { + if (!sessionExists(locals)) { redirect(302, ROUTES.LOGIN) } @@ -30,8 +31,9 @@ export const actions = { } async function add(event: RequestEvent) { + const { locals } = event try { - if (!event.locals.user) { + if (!sessionExists(locals)) { redirect(302, ROUTES.LOGIN); } @@ -44,7 +46,7 @@ async function add(event: RequestEvent) { id: crypto.randomUUID(), front: form.data.front, back: form.data.back, - userId: event.locals.user.id + userId: locals.user.id }); redirect(302, ROUTES.HOME); @@ -54,8 +56,9 @@ async function add(event: RequestEvent) { } async function review(event: RequestEvent) { + const { locals } = event try { - if (!event.locals.user) { + if (!sessionExists(locals)) { redirect(302, ROUTES.LOGIN); } diff --git a/src/routes/(protected)/home/+page.svelte b/src/routes/(protected)/home/+page.svelte index 35585aa..21275e1 100644 --- a/src/routes/(protected)/home/+page.svelte +++ b/src/routes/(protected)/home/+page.svelte @@ -5,13 +5,18 @@ export let data; +User's display +

Hey {data.user?.name},

+

  1. - + {#if data.cards.length > 0} + + {/if} Total cards: {data.cards?.length}
  2. @@ -19,6 +24,9 @@

    Others