added auth
This commit is contained in:
@ -1,5 +1,9 @@
|
||||
import { CronJob } from 'cron';
|
||||
import { pullData } from './lib/united.js';
|
||||
import { auth } from '$lib/auth'; // path to your auth file
|
||||
import { svelteKitHandler } from 'better-auth/svelte-kit';
|
||||
import { building } from '$app/environment';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
|
||||
const job = new CronJob(
|
||||
'0,30 * * * *', // cronTime
|
||||
@ -10,3 +14,23 @@ const job = new CronJob(
|
||||
true, // start
|
||||
'America/Detroit' // timeZone
|
||||
);
|
||||
|
||||
export async function handle({ event, resolve }) {
|
||||
console.log('Handling request:', event.request.method, event.url.pathname);
|
||||
if (event.route.id?.startsWith('/(protected)/') && !event.url.pathname.startsWith('/api/auth')) {
|
||||
const session = await auth.api.getSession({
|
||||
headers: event.request.headers
|
||||
});
|
||||
|
||||
if (session) {
|
||||
event.locals.session = session?.session;
|
||||
event.locals.user = session?.user;
|
||||
return svelteKitHandler({ event, resolve, auth });
|
||||
} else {
|
||||
redirect(307, '/sign-in');
|
||||
}
|
||||
} else {
|
||||
console.log('Not a protected route or API auth request:', event.url.pathname);
|
||||
return svelteKitHandler({ event, resolve, auth });
|
||||
}
|
||||
}
|
||||
|
||||
7
src/lib/auth-client.ts
Normal file
7
src/lib/auth-client.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { createAuthClient } from "better-auth/svelte"
|
||||
export const authClient = createAuthClient({
|
||||
/** The base URL of the server (optional if you're using the same domain) */
|
||||
baseURL: "http://localhost:5173",
|
||||
|
||||
})
|
||||
export const { signIn, signUp, useSession } = authClient;
|
||||
17
src/lib/auth.ts
Normal file
17
src/lib/auth.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { betterAuth } from "better-auth";
|
||||
import { Pool } from "pg";
|
||||
import { sveltekitCookies } from "better-auth/svelte-kit";
|
||||
import { getRequestEvent } from "$app/server";
|
||||
|
||||
export const auth = betterAuth({
|
||||
database: new Pool({
|
||||
connectionString: 'postgresql://budget:budget@sql.caseytimm.com:5432/budget',
|
||||
}),
|
||||
account: {
|
||||
modelName: 'auth_accounts',
|
||||
},
|
||||
emailAndPassword: {
|
||||
enabled: true,
|
||||
},
|
||||
plugins: [sveltekitCookies(getRequestEvent)],
|
||||
})
|
||||
26
src/lib/login.svelte
Normal file
26
src/lib/login.svelte
Normal file
@ -0,0 +1,26 @@
|
||||
<script>
|
||||
import { signIn, signUp } from '$lib/auth-client';
|
||||
let email = $state('');
|
||||
let password = $state('');
|
||||
|
||||
async function handleLogin() {
|
||||
let res = await signIn.email({ email, password });
|
||||
console.log('Login response:', res);
|
||||
}
|
||||
</script>
|
||||
|
||||
<form>
|
||||
<div class="flex justify-center items-center h-screen">
|
||||
<fieldset class="fieldset bg-base-200 border-base-300 rounded-box w-xs border p-4">
|
||||
<legend class="fieldset-legend">Login</legend>
|
||||
|
||||
<label class="label">Username</label>
|
||||
<input type="email" class="input" placeholder="Username" bind:value={email} />
|
||||
|
||||
<label class="label">Password</label>
|
||||
<input type="password" class="input" placeholder="Password" bind:value={password} />
|
||||
|
||||
<button class="btn btn-neutral mt-4" onclick={() => handleLogin()}>Login</button>
|
||||
</fieldset>
|
||||
</div>
|
||||
</form>
|
||||
118
src/routes/(protected)/+layout.svelte
Normal file
118
src/routes/(protected)/+layout.svelte
Normal file
@ -0,0 +1,118 @@
|
||||
<script>
|
||||
import '../../app.css';
|
||||
import { setContext } from 'svelte';
|
||||
import { pwaInfo } from 'virtual:pwa-info';
|
||||
import { authClient } from '$lib/auth-client';
|
||||
import Login from '$lib/login.svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
const session = authClient.useSession();
|
||||
|
||||
console.log('PWA Info:', pwaInfo);
|
||||
const webManifestLink = $state(pwaInfo ? pwaInfo.webManifest.linkTag : '');
|
||||
$inspect(webManifestLink);
|
||||
|
||||
let { children, data } = $props();
|
||||
let budgets = $derived(data.budgets);
|
||||
let total = $derived(data.total);
|
||||
let toast = $state([]);
|
||||
|
||||
function addToast(message, type = 'info') {
|
||||
toast.push({ message, type });
|
||||
setTimeout(() => {
|
||||
toast.pop();
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
setContext('addToast', addToast);
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
{@html webManifestLink}
|
||||
</svelte:head>
|
||||
{#if $session.data}
|
||||
<div class="drawer lg:drawer-open">
|
||||
<input id="my-drawer-2" type="checkbox" class="drawer-toggle" />
|
||||
<div class="drawer-content flex flex-col m-5">
|
||||
<div class="navbar bg-base-100 shadow-sm lg:hidden">
|
||||
<div class="flex-none">
|
||||
<label
|
||||
for="my-drawer-2"
|
||||
class="btn btn-primary drawer-button lg:hidden btn-square btn-ghost"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
class="inline-block h-5 w-5 stroke-current"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 6h16M4 12h16M4 18h16"
|
||||
></path>
|
||||
</svg>
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<a class="btn btn-ghost text-xl" href="/">Timm Budget</a>
|
||||
</div>
|
||||
</div>
|
||||
{@render children()}
|
||||
</div>
|
||||
<div class="drawer-side">
|
||||
<label for="my-drawer-2" aria-label="close sidebar" class="drawer-overlay"></label>
|
||||
<ul class="menu bg-base-200 text-base-content min-h-full w-80 p-4">
|
||||
<li>
|
||||
<a href="/">
|
||||
<span class="text-lg font-bold">Timm Budget</span>
|
||||
</a>
|
||||
</li>
|
||||
<li><div class="divider">Budgets</div></li>
|
||||
{#each budgets as budget}
|
||||
<li>
|
||||
<a href={`/budget/${budget.id}`}>
|
||||
{budget.name} ({budget.sum})
|
||||
</a>
|
||||
</li>
|
||||
{/each}
|
||||
<li><div class="divider">Accounts</div></li>
|
||||
{#each data.accounts as account}
|
||||
<li>
|
||||
<a href={`/account/${account.id}`}>
|
||||
{account.name} ({account.balance})
|
||||
</a>
|
||||
</li>
|
||||
{/each}
|
||||
<li><div class="divider"></div></li>
|
||||
<li><a href="/rules">Rules</a></li>
|
||||
<li><a href="/settings">Settings</a></li>
|
||||
<li><a href="/united">United</a></li>
|
||||
<li><div class="divider"></div></li>
|
||||
<li>
|
||||
<button
|
||||
class="btn btn-primary btn-square w-100% grow"
|
||||
onclick={() =>
|
||||
authClient.signOut({
|
||||
fetchOptions: {
|
||||
onSuccess: () => goto('/')
|
||||
}
|
||||
})}
|
||||
>
|
||||
Logout</button
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toast toast-top toast-center">
|
||||
{#each toast as t}
|
||||
<div class="alert alert-{t.type}">
|
||||
<span>{t.message}</span>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<Login></Login>
|
||||
{/if}
|
||||
@ -1,95 +0,0 @@
|
||||
<script>
|
||||
import '../app.css';
|
||||
import { setContext } from 'svelte';
|
||||
import { pwaInfo } from 'virtual:pwa-info';
|
||||
|
||||
console.log('PWA Info:', pwaInfo);
|
||||
const webManifestLink = $state(pwaInfo ? pwaInfo.webManifest.linkTag : '');
|
||||
$inspect(webManifestLink);
|
||||
|
||||
let { children, data } = $props();
|
||||
let budgets = $derived(data.budgets);
|
||||
let total = $derived(data.total);
|
||||
let toast = $state([]);
|
||||
|
||||
function addToast(message, type = 'info') {
|
||||
toast.push({ message, type });
|
||||
setTimeout(() => {
|
||||
toast.pop();
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
setContext('addToast', addToast);
|
||||
</script>
|
||||
<svelte:head>
|
||||
{@html webManifestLink}
|
||||
</svelte:head>
|
||||
<div class="drawer lg:drawer-open">
|
||||
<input id="my-drawer-2" type="checkbox" class="drawer-toggle" />
|
||||
<div class="drawer-content flex flex-col m-5">
|
||||
<div class="navbar bg-base-100 shadow-sm lg:hidden">
|
||||
<div class="flex-none">
|
||||
<label
|
||||
for="my-drawer-2"
|
||||
class="btn btn-primary drawer-button lg:hidden btn-square btn-ghost"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
class="inline-block h-5 w-5 stroke-current"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 6h16M4 12h16M4 18h16"
|
||||
></path>
|
||||
</svg>
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<a class="btn btn-ghost text-xl" href="/">Timm Budget</a>
|
||||
</div>
|
||||
</div>
|
||||
{@render children()}
|
||||
</div>
|
||||
<div class="drawer-side">
|
||||
<label for="my-drawer-2" aria-label="close sidebar" class="drawer-overlay"></label>
|
||||
<ul class="menu bg-base-200 text-base-content min-h-full w-80 p-4">
|
||||
<li>
|
||||
<a href="/">
|
||||
<span class="text-lg font-bold">Timm Budget</span>
|
||||
</a>
|
||||
</li>
|
||||
<li><div class="divider">Budgets</div></li>
|
||||
{#each budgets as budget}
|
||||
<li>
|
||||
<a href={`/budget/${budget.id}`}>
|
||||
{budget.name} ({budget.sum})
|
||||
</a>
|
||||
</li>
|
||||
{/each}
|
||||
<li><div class="divider">Accounts</div></li>
|
||||
{#each data.accounts as account}
|
||||
<li>
|
||||
<a href={`/account/${account.id}`}>
|
||||
{account.name} ({account.balance})
|
||||
</a>
|
||||
</li>
|
||||
{/each}
|
||||
<li><div class="divider"></div></li>
|
||||
<li><a href="/rules">Rules</a></li>
|
||||
<li><a href="/settings">Settings</a></li>
|
||||
<li><a href="/united">United</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toast toast-top toast-center">
|
||||
{#each toast as t}
|
||||
<div class="alert alert-{t.type}">
|
||||
<span>{t.message}</span>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
Reference in New Issue
Block a user