mirror of
https://github.com/vcscsvcscs/GenerationsHeritage.git
synced 2025-08-12 22:09:07 +02:00
fixup login and registration
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"preview": "npm run build && wrangler pages dev",
|
||||
"preview": "npm run build && wrangler pages dev --port 5173",
|
||||
"prepare": "svelte-kit sync || echo ''",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
|
@@ -6,7 +6,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover" class="bg-base-200">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
<body data-sveltekit-preload-data="hover" style="width: 100vw; height: 100vh" class="bg-base-200">
|
||||
<div style="display: contents;width: 100vw; height: 100vh" class="bg-base-200">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -27,6 +27,8 @@ const authHandle: Handle = async ({ event, resolve }) => {
|
||||
if (session !== null) {
|
||||
setSessionTokenCookie(event, token, session.expiresAt);
|
||||
} else {
|
||||
console.log('Session token is invalid');
|
||||
console.log(session, token);
|
||||
deleteSessionTokenCookie(event);
|
||||
}
|
||||
|
||||
|
@@ -1,10 +1,11 @@
|
||||
import createClient from "openapi-fetch";
|
||||
import type { paths } from "$lib/api/api.gen"; // generated by openapi-typescript
|
||||
import createClient from 'openapi-fetch';
|
||||
import type { paths } from '$lib/api/api.gen'; // generated by openapi-typescript
|
||||
import { DB_ADAPTER, CF_ACCESS_CLIENT_ID, CF_ACCESS_CLIENT_SECRET } from '$env/static/private';
|
||||
|
||||
export const client = createClient<paths>({
|
||||
baseUrl: DB_ADAPTER || "http://localhost:5237", headers: {
|
||||
"CF-Access-Client-Secret": CF_ACCESS_CLIENT_SECRET || "",
|
||||
"CF-Access-Client-Id": CF_ACCESS_CLIENT_ID || "",
|
||||
}
|
||||
});
|
||||
baseUrl: DB_ADAPTER || 'http://localhost:5237',
|
||||
headers: {
|
||||
'CF-Access-Client-Secret': CF_ACCESS_CLIENT_SECRET || '',
|
||||
'CF-Access-Client-Id': CF_ACCESS_CLIENT_ID || ''
|
||||
}
|
||||
});
|
||||
|
8
apps/app/src/lib/logout.svelte
Normal file
8
apps/app/src/lib/logout.svelte
Normal file
@@ -0,0 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { logout } from '$lib/paraglide/messages.js';
|
||||
export let show = false;
|
||||
</script>
|
||||
|
||||
{#if show}
|
||||
<a class="btn btn-error btn-xs" href="/logout">{logout()}</a>
|
||||
{/if}
|
@@ -11,14 +11,13 @@ export async function validateSessionToken(
|
||||
token: string,
|
||||
sessions: KVNamespace
|
||||
): Promise<SessionValidationResult> {
|
||||
const sessionId = encodeHexLowerCase(sha256(new TextEncoder().encode(token)));
|
||||
const session: Session | null = await sessions.get(sessionId, { type: 'json' });
|
||||
const session: Session | null = await sessions.get(token, { type: 'json' });
|
||||
if (!session) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Date.now() >= session.expiresAt.getTime() - 1000 * 60 * 60 * 24 * 15) {
|
||||
await sessions.put(sessionId, JSON.stringify(session), { expirationTtl: EXPIRATION_TTL });
|
||||
if (Date.now() >= session.expiresAt - 1000 * 60 * 60 * 24 * 15) {
|
||||
await sessions.put(token, JSON.stringify(session), { expirationTtl: EXPIRATION_TTL });
|
||||
}
|
||||
|
||||
return session;
|
||||
@@ -35,13 +34,13 @@ export async function invalidateUserSessions(userId: number, sessions: KVNamespa
|
||||
}
|
||||
}
|
||||
|
||||
export function setSessionTokenCookie(event: RequestEvent, token: string, expiresAt: Date): void {
|
||||
export function setSessionTokenCookie(event: RequestEvent, token: string, expiresAt: EpochTimeStamp): void {
|
||||
event.cookies.set('session', token, {
|
||||
httpOnly: true,
|
||||
path: '/',
|
||||
secure: import.meta.env.PROD,
|
||||
sameSite: 'lax',
|
||||
expires: expiresAt
|
||||
expires: new Date(expiresAt)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -55,11 +54,11 @@ export function deleteSessionTokenCookie(event: RequestEvent): void {
|
||||
});
|
||||
}
|
||||
|
||||
export function generateSessionToken(): string {
|
||||
export function generateSessionToken(userId: string): string {
|
||||
const tokenBytes = new Uint8Array(20);
|
||||
crypto.getRandomValues(tokenBytes);
|
||||
const token = encodeBase32(tokenBytes).toLowerCase();
|
||||
return token;
|
||||
return `${userId}:${encodeHexLowerCase(sha256(new TextEncoder().encode(token)))}`;
|
||||
}
|
||||
|
||||
export async function createSession(
|
||||
@@ -67,19 +66,19 @@ export async function createSession(
|
||||
userId: number,
|
||||
sessions: KVNamespace
|
||||
): Promise<Session> {
|
||||
const sessionId = `${userId}:${encodeHexLowerCase(sha256(new TextEncoder().encode(token)))}`;
|
||||
const session: Session = {
|
||||
id: sessionId,
|
||||
id: token,
|
||||
userId,
|
||||
expiresAt: new Date(Date.now() + 1000 * EXPIRATION_TTL)
|
||||
expiresAt: Date.now() + 1000 * EXPIRATION_TTL
|
||||
};
|
||||
await sessions.put(sessionId, JSON.stringify(session), { expirationTtl: EXPIRATION_TTL });
|
||||
await sessions.put(token, JSON.stringify(session), { expirationTtl: EXPIRATION_TTL });
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
export interface Session {
|
||||
id: string;
|
||||
expiresAt: Date;
|
||||
expiresAt: EpochTimeStamp;
|
||||
userId: number;
|
||||
}
|
||||
|
||||
|
@@ -4,11 +4,14 @@
|
||||
import { ParaglideJS } from '@inlang/paraglide-sveltekit';
|
||||
let { children } = $props();
|
||||
import ThemeButton from '$lib/theme-select.svelte';
|
||||
import Logout from '$lib/logout.svelte';
|
||||
import { page } from '$app/state';
|
||||
</script>
|
||||
|
||||
<ParaglideJS {i18n}>
|
||||
{@render children()}
|
||||
<div class="absolute top-2 right-2">
|
||||
<div class="flex flex-row absolute top-2 right-2">
|
||||
<ThemeButton />
|
||||
<Logout show={!page.url.pathname.includes("login")}/>
|
||||
</div>
|
||||
</ParaglideJS>
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import { fail, redirect } from '@sveltejs/kit';
|
||||
import { deleteSessionTokenCookie, invalidateSession } from '$lib/server/session';
|
||||
import { client } from '$lib/api/client';
|
||||
import type { Actions, RequestEvent } from './$types';
|
||||
import type { RequestEvent } from './$types';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
export async function load(event: RequestEvent) {
|
||||
@@ -14,36 +13,19 @@ export async function load(event: RequestEvent) {
|
||||
return {};
|
||||
}
|
||||
|
||||
client.GET('/family-tree-with-spouses', {
|
||||
params: {
|
||||
header: { "X-User-ID": event.locals.session },
|
||||
}
|
||||
}).then((response) => {
|
||||
const response = await client
|
||||
.GET('/family-tree-with-spouses', {
|
||||
params: {
|
||||
header: { 'X-User-ID': event.locals.session.userId },
|
||||
}
|
||||
})
|
||||
|
||||
if (response.response.status === 200) {
|
||||
return response.data;
|
||||
} else {
|
||||
return fail(response.response.status, { message: response.error?.msg || 'An error occurred' });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export const actions: Actions = {
|
||||
logout: logout
|
||||
};
|
||||
|
||||
async function logout(event: RequestEvent) {
|
||||
if (event.locals.session === null) {
|
||||
return fail(401);
|
||||
}
|
||||
|
||||
if (event.platform && event.platform.env && event.platform.env.GH_SESSIONS) {
|
||||
invalidateSession(event.locals.session.id, event.platform.env.GH_SESSIONS);
|
||||
if (response.response.status === 200) {
|
||||
return response.data;
|
||||
} else {
|
||||
return fail(500, { message: 'Server configuration error' });
|
||||
return fail(response.response.status, {
|
||||
message: response.error?.msg || 'An error occurred'
|
||||
});
|
||||
}
|
||||
|
||||
deleteSessionTokenCookie(event);
|
||||
|
||||
return redirect(302, '/login');
|
||||
}
|
||||
|
@@ -11,7 +11,24 @@
|
||||
} from '@xyflow/svelte';
|
||||
import type { Node, Edge, NodeTypes, NodeProps } from '@xyflow/svelte';
|
||||
let data: PageData = $props();
|
||||
let nodes = $state.raw<Node[]>([]);
|
||||
let nodes = $state.raw<Node[]>([
|
||||
{
|
||||
id: '1',
|
||||
type: 'input',
|
||||
data: { label: 'Input Node' },
|
||||
position: { x: 0, y: 0 }
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
data: { label: 'Default Node' },
|
||||
position: { x: 100, y: 100 }
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
data: { label: 'Output Node' },
|
||||
position: { x: 200, y: 200 }
|
||||
}
|
||||
]);
|
||||
let edges = $state.raw<Edge[]>([]);
|
||||
</script>
|
||||
|
||||
@@ -19,11 +36,11 @@
|
||||
<title>{title({ page: family_tree() })}</title>
|
||||
</svelte:head>
|
||||
|
||||
<div style="height:100vh;">
|
||||
<div style="height:100vh;" class="flex flex-col bg-base-200">
|
||||
<SvelteFlowProvider>
|
||||
<SvelteFlow bind:nodes bind:edges class="bg-base-100" fitView onlyRenderVisibleElements>
|
||||
<Controls class="bg-base-300 text-base-content" />
|
||||
<MiniMap class="bg-base-200" />
|
||||
<SvelteFlow bind:nodes bind:edges class="bg-base-200" fitView onlyRenderVisibleElements>
|
||||
<MiniMap />
|
||||
<Controls />
|
||||
</SvelteFlow>
|
||||
</SvelteFlowProvider>
|
||||
</div>
|
||||
|
@@ -15,7 +15,7 @@ import {
|
||||
failed_to_create_user
|
||||
} from '$lib/paraglide/messages';
|
||||
|
||||
import type { PageServerLoad, Actions, RequestEvent, PageData } from './$types';
|
||||
import type { PageServerLoad, Actions, RequestEvent } from './$types';
|
||||
import type { OAuth2Tokens } from 'arctic';
|
||||
import type { PersonProperties } from '$lib/model';
|
||||
import { error, redirect, fail } from '@sveltejs/kit';
|
||||
@@ -55,44 +55,41 @@ export const load: PageServerLoad = async (event: RequestEvent) => {
|
||||
const first_name = claimsParser.getString('given_name');
|
||||
const email = claimsParser.getString('email');
|
||||
|
||||
client.GET('/person/google/{google_id}',
|
||||
{
|
||||
params: {
|
||||
path: { google_id: sub },
|
||||
},
|
||||
}
|
||||
).then((response) => {
|
||||
if (response.response.status !== 200) {
|
||||
return error(500, {
|
||||
message: "Failed to get user from Google ID: " + response.error?.msg
|
||||
});
|
||||
const response = await client.GET('/person/google/{google_id}', {
|
||||
params: {
|
||||
path: { google_id: sub }
|
||||
}
|
||||
});
|
||||
|
||||
if (response.response.status === 200) {
|
||||
if (response.data?.Id) {
|
||||
if (!event.platform || !event.platform.env || !event.platform.env.GH_SESSIONS) {
|
||||
return error(500, { message: "Server configuration error. GH_SESSIONS KeyValue store missing" });
|
||||
return error(500, {
|
||||
message: 'Server configuration error. GH_SESSIONS KeyValue store missing'
|
||||
});
|
||||
}
|
||||
|
||||
const sessionToken = generateSessionToken();
|
||||
createSession(sessionToken, response.data.Id, event.platform.env.GH_SESSIONS).then((session) => {
|
||||
if (session === null) {
|
||||
return error(500, {
|
||||
message: 'Failed to create session'
|
||||
});
|
||||
}
|
||||
const sessionToken = generateSessionToken(String(response.data.Id));
|
||||
const session = await createSession(sessionToken, response.data.Id, event.platform.env.GH_SESSIONS)
|
||||
if (session === null) {
|
||||
return error(500, {
|
||||
message: 'Failed to create session'
|
||||
});
|
||||
}
|
||||
|
||||
setSessionTokenCookie(event, sessionToken, session.expiresAt);
|
||||
setSessionTokenCookie(event, sessionToken, session.expiresAt);
|
||||
|
||||
return redirect(302, '/');
|
||||
});
|
||||
return redirect(302, '/');
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
let personP: PersonProperties = {
|
||||
google_id: sub,
|
||||
first_name: first_name,
|
||||
last_name: family_name,
|
||||
email: email,
|
||||
email: email
|
||||
};
|
||||
|
||||
return {
|
||||
@@ -105,37 +102,44 @@ export const actions: Actions = {
|
||||
};
|
||||
|
||||
async function register(event: RequestEvent) {
|
||||
const data = await event.request.formData();
|
||||
if (!event.platform || !event.platform.env || !event.platform.env.GH_SESSIONS) {
|
||||
return fail(500, { message: "Server configuration error. GH_SESSIONS KeyValue store missing" });
|
||||
if (browser) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const google_id = data.get('google_id');
|
||||
if (google_id === null) {
|
||||
return fail(400, {
|
||||
message: missing_field({
|
||||
field: 'google_id'
|
||||
})
|
||||
});
|
||||
const data = await event.request.formData();
|
||||
if (!event.platform || !event.platform.env || !event.platform.env.GH_SESSIONS) {
|
||||
return fail(500, { message: 'Server configuration error. GH_SESSIONS KeyValue store missing' });
|
||||
}
|
||||
|
||||
const first_name_f = data.get('first_name');
|
||||
if (first_name_f === null) {
|
||||
if (first_name_f === null || first_name_f === '') {
|
||||
return fail(400, {
|
||||
message: missing_field({
|
||||
field: first_name()
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
const google_id = data.get('google_id');
|
||||
if (google_id === null || google_id === '') {
|
||||
return fail(400, {
|
||||
message: missing_field({
|
||||
field: 'google_id'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
const last_name_f = data.get('last_name');
|
||||
if (last_name_f === null) {
|
||||
if (last_name_f === null || last_name_f === '') {
|
||||
return fail(400, {
|
||||
message: missing_field({
|
||||
field: last_name()
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
const email = data.get('email');
|
||||
if (email === null) {
|
||||
if (email === null || email === '') {
|
||||
return fail(400, {
|
||||
message: missing_field({
|
||||
field: 'Email'
|
||||
@@ -143,7 +147,7 @@ async function register(event: RequestEvent) {
|
||||
});
|
||||
}
|
||||
const birth_date = data.get('birth_date');
|
||||
if (birth_date === null) {
|
||||
if (birth_date === null || birth_date === '') {
|
||||
return fail(400, {
|
||||
message: missing_field({
|
||||
field: born()
|
||||
@@ -151,7 +155,7 @@ async function register(event: RequestEvent) {
|
||||
});
|
||||
}
|
||||
const mothers_first_name_f = data.get('mothers_first_name');
|
||||
if (mothers_first_name_f === null) {
|
||||
if (mothers_first_name_f === null || mothers_first_name_f === '') {
|
||||
return fail(400, {
|
||||
message: missing_field({
|
||||
field: mothers_first_name()
|
||||
@@ -168,64 +172,56 @@ async function register(event: RequestEvent) {
|
||||
}
|
||||
|
||||
const parsed_date = new Date(birth_date as string);
|
||||
|
||||
let personP: components['schemas']['PersonRegistration'] = {
|
||||
first_name: first_name_f as string,
|
||||
last_name: last_name_f as string,
|
||||
email: email as string,
|
||||
born: parsed_date.toISOString(),
|
||||
born: parsed_date.toISOString().split('T')[0],
|
||||
mothers_first_name: mothers_first_name_f as string,
|
||||
mothers_last_name: mothers_last_name_f as string,
|
||||
limit: StorageLimit,
|
||||
limit: StorageLimit
|
||||
};
|
||||
|
||||
client.POST('/person/google/{google_id}',
|
||||
{
|
||||
let response = await client
|
||||
.POST('/person/google/{google_id}', {
|
||||
params: {
|
||||
path: { google_id: google_id.toString() },
|
||||
path: { google_id: google_id.toString() }
|
||||
},
|
||||
body: personP
|
||||
}
|
||||
).then((response) => {
|
||||
if (response.response.status !== 200) {
|
||||
return fail(400, {
|
||||
message: failed_to_create_user({
|
||||
error: response.error?.msg
|
||||
})
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
const sessionToken = generateSessionToken();
|
||||
if (!response.data?.Id) {
|
||||
return fail(400, {
|
||||
message: failed_to_create_user({
|
||||
error: 'No user ID returned'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
if (!event.platform) {
|
||||
return fail(500, {
|
||||
message: 'Server configuration error. GH_SESSIONS KeyValue store missing'
|
||||
});
|
||||
}
|
||||
|
||||
const session = createSession(sessionToken, response.data.Id, event.platform.env.GH_SESSIONS).then((session) => {
|
||||
if (session === null) {
|
||||
return fail(500, {
|
||||
message: 'Failed to create session'
|
||||
});
|
||||
}
|
||||
|
||||
setSessionTokenCookie(event, sessionToken, session.expiresAt);
|
||||
|
||||
return redirect(302, '/');
|
||||
if (response.response.status !== 200) {
|
||||
return fail(400, {
|
||||
message: failed_to_create_user() + response.error?.msg
|
||||
});
|
||||
}).catch((error) => {
|
||||
}
|
||||
|
||||
const sessionToken = generateSessionToken();
|
||||
if (!response.data?.Id) {
|
||||
console.log(response.data)
|
||||
return fail(400, {
|
||||
message: failed_to_create_user() + 'No user ID returned'
|
||||
});
|
||||
}
|
||||
|
||||
if (!event.platform) {
|
||||
return fail(500, {
|
||||
message: failed_to_create_user({
|
||||
error: error.message
|
||||
})
|
||||
message: 'Server configuration error. GH_SESSIONS KeyValue store missing'
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
const session = await createSession(
|
||||
sessionToken,
|
||||
response.data.Id,
|
||||
event.platform.env.GH_SESSIONS
|
||||
)
|
||||
if (session === null) {
|
||||
return fail(500, {
|
||||
message: failed_to_create_user() + 'Failed to create session'
|
||||
});
|
||||
}
|
||||
|
||||
setSessionTokenCookie(event, sessionToken, session.expiresAt);
|
||||
|
||||
return redirect(302, '/');
|
||||
}
|
||||
|
@@ -11,20 +11,32 @@
|
||||
mothers_last_name,
|
||||
last_name,
|
||||
first_name,
|
||||
email,
|
||||
allow_family_tree_admin_access
|
||||
email
|
||||
} from '$lib/paraglide/messages';
|
||||
import { onMount } from 'svelte';
|
||||
import { enhance } from '$app/forms';
|
||||
import FamilyTree from '../../highresolution_icon_no_background_croped.png';
|
||||
let { data, form }: PageProps = $props();
|
||||
import Pikaday from 'pikaday';
|
||||
|
||||
let birth_date: HTMLInputElement;
|
||||
$effect(() => {
|
||||
let birth_date_value: HTMLInputElement;
|
||||
onMount(() => {
|
||||
if (birth_date) {
|
||||
const picker = new Pikaday({
|
||||
field: birth_date
|
||||
import('pikaday').then(({ default: Pikaday }) => {
|
||||
const picker = new Pikaday({
|
||||
format: 'YYYY-MM-DD',
|
||||
minDate: new Date(1900, 0, 1),
|
||||
field: birth_date,
|
||||
onOpen: function () {
|
||||
birth_date_value.placeholder = '';
|
||||
},
|
||||
onSelect: function (date) {
|
||||
birth_date_value.value = date.toISOString();
|
||||
}
|
||||
});
|
||||
// Clean up when component unmounts
|
||||
return () => picker.destroy();
|
||||
});
|
||||
return () => picker.destroy();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -35,8 +47,8 @@
|
||||
|
||||
<div class="hero bg-base-200 min-h-screen">
|
||||
<div class="hero-content flex-col lg:flex-row-reverse">
|
||||
<div class="text-center lg:text-left">
|
||||
<figure class="top-margin-10 px-10 pt-10">
|
||||
<div class="max-w-xxl flex flex-col items-center justify-center text-center">
|
||||
<figure class="top-margin-10 max-w-sm px-10 pt-10">
|
||||
<img src={FamilyTree} alt={family_tree()} class="rounded-xl" />
|
||||
</figure>
|
||||
<h1 class="text-5xl font-bold">{welcome()}</h1>
|
||||
@@ -46,7 +58,7 @@
|
||||
</div>
|
||||
<div class="card bg-base-100 w-full max-w-sm shrink-0 shadow-2xl">
|
||||
<div class="card-body">
|
||||
<form method="POST" action="/register">
|
||||
<form method="POST" action="?/register" use:enhance>
|
||||
<fieldset class="fieldset">
|
||||
{#if form?.message}
|
||||
<div role="alert" class="alert alert-error">
|
||||
@@ -66,10 +78,17 @@
|
||||
<span>{form.message}</span>
|
||||
</div>
|
||||
{/if}
|
||||
<label class="fieldset-label" for="email">Email</label>
|
||||
<input type="email" class="input" placeholder="Email" value={data.props?.email} />
|
||||
<label class="fieldset-label" for="email">{email()}</label>
|
||||
<input
|
||||
type="email"
|
||||
name="email"
|
||||
class="input"
|
||||
placeholder={email()}
|
||||
value={data.props?.email}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
name="google_id"
|
||||
class="hidden"
|
||||
id="google_id"
|
||||
placeholder="Google ID"
|
||||
@@ -79,6 +98,7 @@
|
||||
<input
|
||||
type="text"
|
||||
class="input"
|
||||
name="first_name"
|
||||
id="first_name"
|
||||
placeholder={first_name()}
|
||||
value={data.props?.first_name}
|
||||
@@ -87,6 +107,7 @@
|
||||
<input
|
||||
type="text"
|
||||
class="input"
|
||||
name="last_name"
|
||||
id="last_name"
|
||||
placeholder={last_name()}
|
||||
value={data.props?.last_name}
|
||||
@@ -96,13 +117,15 @@
|
||||
type="text"
|
||||
class="input pika-single"
|
||||
id="birth_date"
|
||||
bind:this={birth_date}
|
||||
value={born()}
|
||||
bind:this={birth_date}
|
||||
/>
|
||||
<input type="text" class="hidden" name="birth_date" bind:this={birth_date_value} />
|
||||
<label class="fieldset-label" for="mothers_last_name">{mothers_last_name()}</label>
|
||||
<input
|
||||
type="text"
|
||||
class="input"
|
||||
name="mothers_last_name"
|
||||
id="mothers_last_name"
|
||||
placeholder={mothers_last_name()}
|
||||
/>
|
||||
@@ -110,6 +133,7 @@
|
||||
<input
|
||||
type="text"
|
||||
class="input"
|
||||
name="mothers_first_name"
|
||||
id="mothers_first_name"
|
||||
placeholder={mothers_first_name()}
|
||||
/>
|
||||
|
20
apps/app/src/routes/logout/+server.ts
Normal file
20
apps/app/src/routes/logout/+server.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { error, redirect } from '@sveltejs/kit';
|
||||
import { invalidateSession, deleteSessionTokenCookie } from '$lib/server/session';
|
||||
|
||||
import type { RequestEvent } from './$types';
|
||||
|
||||
export function GET(event: RequestEvent): Response {
|
||||
if (event.locals.session === null) {
|
||||
return error(401, { message: 'Unauthorized' });
|
||||
}
|
||||
|
||||
if (event.platform && event.platform.env && event.platform.env.GH_SESSIONS) {
|
||||
invalidateSession(event.locals.session.id, event.platform.env.GH_SESSIONS);
|
||||
} else {
|
||||
return error(500, { message: 'Server configuration error' });
|
||||
}
|
||||
|
||||
deleteSessionTokenCookie(event);
|
||||
|
||||
return redirect(302, '/login');
|
||||
}
|
@@ -5,7 +5,9 @@
|
||||
{
|
||||
"$schema": "node_modules/wrangler/config-schema.json",
|
||||
"name": "generations-heritage",
|
||||
"compatibility_flags": ["nodejs_compat"],
|
||||
"compatibility_flags": [
|
||||
"nodejs_compat"
|
||||
],
|
||||
"compatibility_date": "2025-02-14",
|
||||
"pages_build_output_dir": ".svelte-kit/cloudflare",
|
||||
"observability": {
|
||||
@@ -26,11 +28,13 @@
|
||||
*/
|
||||
"kv_namespaces": [
|
||||
{
|
||||
"id": "6f793c8813ab46549234572f4c6ae5a1",
|
||||
"binding": "GH_SESSIONS"
|
||||
}
|
||||
],
|
||||
"r2_buckets": [
|
||||
{
|
||||
"bucket_name": "ghstaging",
|
||||
"binding": "GH_MEDIA"
|
||||
}
|
||||
],
|
||||
@@ -49,14 +53,14 @@
|
||||
},
|
||||
"kv_namespaces": [
|
||||
{
|
||||
"binding": "GH_SESSIONS",
|
||||
"id": "6f793c8813ab46549234572f4c6ae5a1"
|
||||
"id": "6f793c8813ab46549234572f4c6ae5a1",
|
||||
"binding": "GH_SESSIONS"
|
||||
}
|
||||
],
|
||||
"r2_buckets": [
|
||||
{
|
||||
"binding": "GH_MEDIA",
|
||||
"bucket_name": "ghstaging"
|
||||
"bucket_name": "ghstaging",
|
||||
"binding": "GH_MEDIA"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -69,14 +73,14 @@
|
||||
},
|
||||
"kv_namespaces": [
|
||||
{
|
||||
"binding": "GH_SESSIONS",
|
||||
"id": "4cedee65c36d49d7afc654bcc798d169"
|
||||
"id": "4cedee65c36d49d7afc654bcc798d169",
|
||||
"binding": "GH_SESSIONS"
|
||||
}
|
||||
],
|
||||
"r2_buckets": [
|
||||
{
|
||||
"binding": "GH_MEDIA",
|
||||
"bucket_name": "generations-heritage"
|
||||
"bucket_name": "generations-heritage",
|
||||
"binding": "GH_MEDIA"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -95,4 +99,4 @@
|
||||
* https://developers.cloudflare.com/workers/wrangler/configuration/#service-bindings
|
||||
*/
|
||||
// "services": [{ "binding": "MY_SERVICE", "service": "my-service" }]
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user