use DB-adapter service

This commit is contained in:
2025-04-25 14:33:47 +02:00
parent 6b4b9ce973
commit 9e02317ab1
7 changed files with 130 additions and 65 deletions

View File

@@ -1,4 +1,9 @@
GOOGLE_CLIENT_ID=""
GOOGLE_CLIENT_SECRET=""
GOOGLE_CALLBACK_URI="http://localhost:5173/login/google/callback"
DB_ADAPTER=""
GOOGLE_CALLBACK_URI="http://localhost:3000/login/google/callback"
DB_ADAPTER="http://localhost:5237"
CF_ACCESS_CLIENT_SECRET=""
CF_ACCESS_CLIENT_ID=""
NODE_ENV="development"
PORT="3000"
HOST="0.0.0.0"

View File

@@ -0,0 +1,10 @@
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 || "",
}
});

View File

@@ -13,7 +13,6 @@ export async function validateSessionToken(
): Promise<SessionValidationResult> {
const sessionId = encodeHexLowerCase(sha256(new TextEncoder().encode(token)));
const session: Session | null = await sessions.get(sessionId, { type: 'json' });
if (!session) {
return null;
}
@@ -21,6 +20,7 @@ export async function validateSessionToken(
if (Date.now() >= session.expiresAt.getTime() - 1000 * 60 * 60 * 24 * 15) {
await sessions.put(sessionId, JSON.stringify(session), { expirationTtl: EXPIRATION_TTL });
}
return session;
}
@@ -64,7 +64,7 @@ export function generateSessionToken(): string {
export async function createSession(
token: string,
userId: string,
userId: number,
sessions: KVNamespace
): Promise<Session> {
const sessionId = `${userId}:${encodeHexLowerCase(sha256(new TextEncoder().encode(token)))}`;
@@ -80,7 +80,7 @@ export async function createSession(
export interface Session {
id: string;
expiresAt: Date;
userId: string;
userId: number;
}
type SessionValidationResult = Session | null;

View File

@@ -1,14 +1,31 @@
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 { browser } from '$app/environment';
export async function load(event: RequestEvent) {
if (event.locals.session === null /*|| event.locals.familytree === nul*/) {
return redirect(302, '/login');
}
return {
// TODO - Add Family Graph
};
//prevent loading in developer mode, due to some issues with universal load, even if this is a server only ts,it will still run on client in dev mode idk
if (browser) {
return {};
}
client.GET('/family-tree-with-spouses', {
params: {
header: { "X-User-ID": event.locals.session },
}
}).then((response) => {
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 = {

View File

@@ -1,5 +1,6 @@
<script lang="ts">
import { title, family_tree } from '$lib/paraglide/messages.js';
import type { PageData } from './$types';
import {
SvelteFlowProvider,
Background,
@@ -9,7 +10,7 @@
MiniMap
} from '@xyflow/svelte';
import type { Node, Edge, NodeTypes, NodeProps } from '@xyflow/svelte';
let data: PageData = $props();
let nodes = $state.raw<Node[]>([]);
let edges = $state.raw<Edge[]>([]);
</script>

View File

@@ -1,9 +1,8 @@
import { google } from '$lib/server/oauth';
import { ObjectParser } from '@pilcrowjs/object-parser';
import { createUser, getUserFromGoogleId } from '$lib/server/user';
import { DB } from '$lib/server/db';
import { browser } from '$app/environment';
import { Date as neoDate } from 'neo4j-driver';
import { client } from '$lib/api/client';
import { type components } from '$lib/api/api.gen';
import { createSession, generateSessionToken, setSessionTokenCookie } from '$lib/server/session';
import { decodeIdToken } from 'arctic';
import {
@@ -48,10 +47,6 @@ export const load: PageServerLoad = async (event: RequestEvent) => {
return error(400, { message: 'Failed to validate authorization code with ' + e });
}
// if (!event.platform || !event.platform.env || !event.platform.env.GH_SESSIONS) {
// return error(500, { message: "Server configuration error. GH_SESSIONS KeyValue store missing" });
// }
const claims = decodeIdToken(tokens.idToken());
const claimsParser = new ObjectParser(claims);
@@ -60,27 +55,44 @@ export const load: PageServerLoad = async (event: RequestEvent) => {
const first_name = claimsParser.getString('given_name');
const email = claimsParser.getString('email');
const dbSession = DB.session();
const existingUser = await getUserFromGoogleId(dbSession, sub);
dbSession.close();
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
});
}
let eUser = existingUser.records.pop();
if (eUser !== null && eUser?.get('elementId') !== undefined) {
const sessionToken = generateSessionToken();
// const session = await createSession(sessionToken, eUser.get('elementId'), event.platform.env.GH_SESSIONS);
// setSessionTokenCookie(event, sessionToken, session.expiresAt);
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 redirect(302, '/');
}
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'
});
}
setSessionTokenCookie(event, sessionToken, session.expiresAt);
return redirect(302, '/');
});
}
})
let personP: PersonProperties = {
google_id: sub,
first_name: first_name,
last_name: family_name,
email: email,
allow_admin_access: false,
limit: StorageLimit,
verified: false
};
return {
@@ -94,9 +106,10 @@ 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 (!event.platform || !event.platform.env || !event.platform.env.GH_SESSIONS) {
return fail(500, { message: "Server configuration error. GH_SESSIONS KeyValue store missing" });
}
const google_id = data.get('google_id');
if (google_id === null) {
return fail(400, {
@@ -156,35 +169,63 @@ async function register(event: RequestEvent) {
const parsed_date = new Date(birth_date as string);
let personP: PersonProperties = {
google_id: google_id 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: new neoDate(
parsed_date.getFullYear(),
parsed_date.getUTCMonth(),
parsed_date.getUTCDate()
),
born: parsed_date.toISOString(),
mothers_first_name: mothers_first_name_f as string,
mothers_last_name: mothers_last_name_f as string,
allow_admin_access: false,
limit: StorageLimit,
verified: false
};
const dbSession = DB.session();
const user = (await createUser(dbSession, personP)).records.pop();
if (user === null || user === undefined) {
dbSession.close();
client.POST('/person/google/{google_id}',
{
params: {
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
})
});
}
return fail(500, { message: failed_to_create_user() });
}
dbSession.close();
const sessionToken = generateSessionToken();
if (!response.data?.Id) {
return fail(400, {
message: failed_to_create_user({
error: 'No user ID returned'
})
});
}
const sessionToken = generateSessionToken();
// const session = await createSession(sessionToken, user.get('elementId'), event.platform.env.GH_SESSIONS);
// setSessionTokenCookie(event, sessionToken, session.expiresAt);
if (!event.platform) {
return fail(500, {
message: 'Server configuration error. GH_SESSIONS KeyValue store missing'
});
}
return redirect(302, '/');
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, '/');
});
}).catch((error) => {
return fail(500, {
message: failed_to_create_user({
error: error.message
})
});
})
}

View File

@@ -67,13 +67,13 @@
</div>
{/if}
<label class="fieldset-label" for="email">Email</label>
<input type="email" class="input" placeholder="Email" value={data.props.email} />
<input type="email" class="input" placeholder="Email" value={data.props?.email} />
<input
type="text"
class="hidden"
id="google_id"
placeholder="Google ID"
value={data.props.google_id}
value={data.props?.google_id}
/>
<label class="fieldset-label" for="first_name">{first_name()}</label>
<input
@@ -81,7 +81,7 @@
class="input"
id="first_name"
placeholder={first_name()}
value={data.props.first_name}
value={data.props?.first_name}
/>
<label class="fieldset-label" for="last_name">{last_name()}</label>
<input
@@ -89,16 +89,7 @@
class="input"
id="last_name"
placeholder={last_name()}
value={data.props.last_name}
/>
<label class="fieldset-label" for="allow_admin_access"
>{allow_family_tree_admin_access()}</label
>
<input
type="checkbox"
class="input"
id="allow_admin_access"
checked={data.props.allow_admin_access}
value={data.props?.last_name}
/>
<label class="fieldset-label" for="birth_date">{born()}</label>
<input