1
0
Fork 0
mirror of https://github.com/seanmorley15/AdventureLog.git synced 2025-08-05 05:05:17 +02:00

Update email verification and password reset flows; refactor Docker Compose and enhance email management

This commit is contained in:
Sean Morley 2024-12-12 11:01:09 -05:00
parent 0272c6b076
commit 2ccbf4be83
13 changed files with 197 additions and 137 deletions

View file

@ -0,0 +1,37 @@
import { fetchCSRFToken } from '$lib/index.server';
import { fail, type Actions } from '@sveltejs/kit';
const PUBLIC_SERVER_URL = process.env['PUBLIC_SERVER_URL'];
const endpoint = PUBLIC_SERVER_URL || 'http://localhost:8000';
export const actions: Actions = {
forgotPassword: async (event) => {
const formData = await event.request.formData();
const email = formData.get('email') as string | null | undefined;
if (!email) {
return fail(400, { message: 'missing_email' });
}
let csrfToken = await fetchCSRFToken();
let res = await fetch(`${endpoint}/_allauth/browser/v1/auth/password/request`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken,
Cookie: `csrftoken=${csrfToken}`
},
body: JSON.stringify({
email
})
});
if (!res.ok) {
let message = await res.json();
return fail(res.status, message);
}
return { success: true };
}
};

View file

@ -0,0 +1,35 @@
<script lang="ts">
import { enhance } from '$app/forms';
import { page } from '$app/stores';
import { t } from 'svelte-i18n';
</script>
<h1 class="text-center font-extrabold text-4xl mb-6">{$t('settings.reset_password')}</h1>
<div class="flex justify-center">
<form method="post" action="?/forgotPassword" class="w-full max-w-xs" use:enhance>
<label for="email">{$t('auth.email')}</label>
<input
name="email"
type="email"
id="email"
class="block mb-2 input input-bordered w-full max-w-xs"
/><br />
<button class="py-2 px-4 btn btn-primary mr-2">{$t('settings.reset_password')}</button>
{#if $page.form?.message}
<div class="text-center text-error mt-4">
{$t(`settings.${$page.form?.message}`)}
</div>
{/if}
{#if $page.form?.success}
<div class="text-center text-success mt-4">
{$t('settings.possible_reset')}
</div>
{/if}
</form>
</div>
<svelte:head>
<title>Forgot Password</title>
<meta name="description" content="Reset your password for AdventureLog." />
</svelte:head>

View file

@ -0,0 +1,55 @@
import { fail, redirect } from '@sveltejs/kit';
import { fetchCSRFToken } from '$lib/index.server';
import type { PageServerLoad, Actions } from './$types';
export const load = (async ({ params }) => {
const key = params.key;
if (!key) {
throw redirect(302, '/');
}
return { key };
}) satisfies PageServerLoad;
export const actions: Actions = {
default: async (event) => {
const formData = await event.request.formData();
const password = formData.get('password');
const confirm_password = formData.get('confirm_password');
const key = event.params.key;
if (!password || !confirm_password) {
return fail(400, { message: 'both_passwords_required' });
}
if (password !== confirm_password) {
return fail(400, { message: 'passwords_not_match' });
}
const PUBLIC_SERVER_URL = process.env['PUBLIC_SERVER_URL'];
const serverEndpoint = PUBLIC_SERVER_URL || 'http://localhost:8000';
const csrfToken = await fetchCSRFToken();
const response = await event.fetch(
`${serverEndpoint}/_allauth/browser/v1/auth/password/reset`,
{
headers: {
'Content-Type': 'application/json',
Cookie: `csrftoken=${csrfToken}`,
'X-CSRFToken': csrfToken
},
method: 'POST',
credentials: 'include',
body: JSON.stringify({ key: key, password: password })
}
);
if (response.status !== 401) {
const error_message = await response.json();
console.error(error_message);
console.log(response);
return fail(response.status, { message: 'reset_failed' });
}
return redirect(302, '/login');
}
};

View file

@ -0,0 +1,47 @@
<script lang="ts">
import { enhance } from '$app/forms';
import { page } from '$app/stores';
import type { PageData } from '../../../$types';
import { t } from 'svelte-i18n';
export let data: PageData;
</script>
<h1 class="text-center font-bold text-4xl mb-4">{$t('settings.change_password')}</h1>
<form method="POST" use:enhance>
<div class="mb-4">
<label for="password" class="block mb-2">{$t('auth.new_password')}</label>
<input
type="password"
id="password"
name="password"
required
class="w-full p-2 border rounded"
/>
</div>
<div class="mb-4">
<label for="confirm_password" class="block mb-2">{$t('auth.confirm_password')}</label>
<input
type="password"
id="confirm_password"
name="confirm_password"
required
class="w-full p-2 border rounded"
/>
</div>
<button type="submit" class="bg-blue-500 text-white px-4 py-2 rounded"
>{$t('auth.reset_password')}</button
>
{#if $page.form?.message}
<div class="text-center text-error mt-4">
{$page.form?.message}
</div>
{/if}
</form>
<svelte:head>
<title>Password Reset Confirm</title>
<meta name="description" content="Confirm your password reset and make a new password." />
</svelte:head>

View file

@ -0,0 +1,33 @@
import { fetchCSRFToken } from '$lib/index.server';
import type { PageServerLoad } from './$types';
export const load = (async (event) => {
// get key from route params
const key = event.params.key;
if (!key) {
return { status: 404 };
}
const PUBLIC_SERVER_URL = process.env['PUBLIC_SERVER_URL'];
const serverEndpoint = PUBLIC_SERVER_URL || 'http://localhost:8000';
const csrfToken = await fetchCSRFToken();
let verifyFetch = await event.fetch(`${serverEndpoint}/_allauth/browser/v1/auth/email/verify`, {
headers: {
Cookie: `csrftoken=${csrfToken}`,
'X-CSRFToken': csrfToken
},
method: 'POST',
credentials: 'include',
body: JSON.stringify({ key: key })
});
if (!verifyFetch.ok) {
let error_message = await verifyFetch.json();
console.error(error_message);
console.error('Failed to verify email');
return { status: 404 };
}
return {
verified: true
};
}) satisfies PageServerLoad;

View file

@ -0,0 +1,13 @@
<script lang="ts">
import type { PageData } from '../$types';
export let data: PageData;
</script>
{#if data.verified}
<h1>Email verified</h1>
<p>Your email has been verified. You can now log in.</p>
{:else}
<h1>Email verification failed</h1>
<p>Your email could not be verified. Please try again.</p>
{/if}