mirror of
https://github.com/vcscsvcscs/GenerationsHeritage.git
synced 2025-08-12 22:09:07 +02:00
use DB-adapter service
This commit is contained in:
@@ -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"
|
10
apps/app/src/lib/api/client.ts
Normal file
10
apps/app/src/lib/api/client.ts
Normal 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 || "",
|
||||
}
|
||||
});
|
@@ -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;
|
||||
|
@@ -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 = {
|
||||
|
@@ -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>
|
||||
|
@@ -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
|
||||
})
|
||||
});
|
||||
})
|
||||
}
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user