backend changed verification model
This commit is contained in:
17
frontend/src/routes/auth/confirming/+page.svelte
Normal file
17
frontend/src/routes/auth/confirming/+page.svelte
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<script>
|
||||||
|
import { page } from '$app/state';
|
||||||
|
import { t } from 'svelte-i18n';
|
||||||
|
let message = '';
|
||||||
|
if (page.url.search) {
|
||||||
|
message = page.url.search.split('=')[1].replaceAll('%20', ' ');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="content">
|
||||||
|
<h1 class="step-title title">{$t('email_sent')}</h1>
|
||||||
|
<h4 class="step-subtitle normal">
|
||||||
|
{$t(message)}
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
33
frontend/src/routes/auth/password/change/+page.server.js
Normal file
33
frontend/src/routes/auth/password/change/+page.server.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { BASE_API_URI } from '$lib/utils/constants';
|
||||||
|
import { formatError } from '$lib/utils/helpers';
|
||||||
|
import { fail, redirect } from '@sveltejs/kit';
|
||||||
|
|
||||||
|
/** @type {import('./$types').Actions} */
|
||||||
|
export const actions = {
|
||||||
|
default: async ({ fetch, request }) => {
|
||||||
|
const formData = await request.formData();
|
||||||
|
const email = String(formData.get('email'));
|
||||||
|
|
||||||
|
/** @type {RequestInit} */
|
||||||
|
const requestInitOptions = {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ email: email })
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await fetch(`${BASE_API_URI}/users/password/request-change/`, requestInitOptions);
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
const response = await res.json();
|
||||||
|
const errors = formatError(response.errors);
|
||||||
|
return fail(400, { errors: errors });
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await res.json();
|
||||||
|
|
||||||
|
// redirect the user
|
||||||
|
throw redirect(302, `/auth/confirming?message=${response.message}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
45
frontend/src/routes/auth/password/change/+page.svelte
Normal file
45
frontend/src/routes/auth/password/change/+page.svelte
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<script>
|
||||||
|
import { applyAction, enhance } from '$app/forms';
|
||||||
|
import { receive, send } from '$lib/utils/helpers';
|
||||||
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
|
/** @type {import('./$types').ActionData} */
|
||||||
|
export let form;
|
||||||
|
|
||||||
|
/** @type {import('./$types').SubmitFunction} */
|
||||||
|
const handleRequestChange = async () => {
|
||||||
|
return async ({ result }) => {
|
||||||
|
await applyAction(result);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<form class="content" method="POST" use:enhance={handleRequestChange}>
|
||||||
|
<h1 class="step-title">{$t('forgot_password')}</h1>
|
||||||
|
{#if form?.errors}
|
||||||
|
{#each form?.errors as error (error.id)}
|
||||||
|
<h4
|
||||||
|
class="step-subtitle warning"
|
||||||
|
in:receive={{ key: error.id }}
|
||||||
|
out:send={{ key: error.id }}
|
||||||
|
>
|
||||||
|
{$t(error.key)}
|
||||||
|
</h4>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div class="input-box">
|
||||||
|
<span class="label">{$t('user.email')}:</span>
|
||||||
|
<input
|
||||||
|
class="input"
|
||||||
|
type="email"
|
||||||
|
name="email"
|
||||||
|
id="email"
|
||||||
|
placeholder={$t('placeholder.email')}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button class="button-dark">{$t('confirm')}</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import { BASE_API_URI } from '$lib/utils/constants';
|
||||||
|
import { formatError } from '$lib/utils/helpers';
|
||||||
|
import { fail, redirect } from '@sveltejs/kit';
|
||||||
|
|
||||||
|
/** @type {import('./$types').Actions} */
|
||||||
|
export const actions = {
|
||||||
|
default: async ({ fetch, request }) => {
|
||||||
|
const formData = await request.formData();
|
||||||
|
const password = String(formData.get('user[password]')).trim();
|
||||||
|
const confirmPassword = String(formData.get('confirm_password')).trim();
|
||||||
|
let token = String(formData.get('token'));
|
||||||
|
const userID = String(formData.get('user_id'));
|
||||||
|
|
||||||
|
// Some validations
|
||||||
|
/** @type {string | Array<{field: string, key: string}> | Record<string, {key: string}>} */
|
||||||
|
const fieldsError = [];
|
||||||
|
if (password.length < 8) {
|
||||||
|
fieldsError.push({ field: 'user.user', key: 'validation.password' });
|
||||||
|
}
|
||||||
|
if (confirmPassword !== password) {
|
||||||
|
fieldsError.push({ field: 'user.user', key: 'validation.password_match' });
|
||||||
|
}
|
||||||
|
if (Object.keys(fieldsError).length > 0) {
|
||||||
|
return fail(400, { errors: formatError(fieldsError) });
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {RequestInit} */
|
||||||
|
const requestInitOptions = {
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ token: token, password: password })
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await fetch(`${BASE_API_URI}/users/password/change/${userID}/`, requestInitOptions);
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
const response = await res.json();
|
||||||
|
const errors = formatError(response.errors);
|
||||||
|
return fail(400, { errors: errors });
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await res.json();
|
||||||
|
|
||||||
|
// redirect the user
|
||||||
|
throw redirect(302, `/auth/login?message=${response.message}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
76
frontend/src/routes/auth/password/change/[id]/+page.svelte
Normal file
76
frontend/src/routes/auth/password/change/[id]/+page.svelte
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<script>
|
||||||
|
import { applyAction, enhance } from '$app/forms';
|
||||||
|
import { page } from '$app/state';
|
||||||
|
import { receive, send } from '$lib/utils/helpers';
|
||||||
|
|
||||||
|
import { t } from 'svelte-i18n';
|
||||||
|
import InputField from '$lib/components/InputField.svelte';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
|
let password = '',
|
||||||
|
confirm_password = '';
|
||||||
|
|
||||||
|
/** @type{string | null} */
|
||||||
|
let token = null;
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
token = page.url.searchParams.get('token');
|
||||||
|
console.log(token);
|
||||||
|
if (!token) {
|
||||||
|
form ||= { errors: [] }; // Ensure form exists with an errors array
|
||||||
|
form.errors.push({
|
||||||
|
field: 'server.general',
|
||||||
|
key: 'server.error.no_auth_token',
|
||||||
|
id: Math.random() * 1000
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/** @type {import('./$types').ActionData} */
|
||||||
|
export let form;
|
||||||
|
|
||||||
|
/** @type {import('./$types').SubmitFunction} */
|
||||||
|
const handleChange = async () => {
|
||||||
|
return async ({ result }) => {
|
||||||
|
await applyAction(result);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<form class="content" method="POST" use:enhance={handleChange}>
|
||||||
|
<h1 class="step-title title">{$t('change_password')}</h1>
|
||||||
|
{#if form?.errors}
|
||||||
|
{#each form?.errors as error (error.id)}
|
||||||
|
<h4
|
||||||
|
class="step-subtitle warning"
|
||||||
|
in:receive={{ key: error.id }}
|
||||||
|
out:send={{ key: error.id }}
|
||||||
|
>
|
||||||
|
{$t(error.key)}
|
||||||
|
</h4>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<input type="hidden" name="user_id" value={page.params.id} />
|
||||||
|
<input type="hidden" name="token" value={token} />
|
||||||
|
<InputField
|
||||||
|
name="user[password]"
|
||||||
|
type="password"
|
||||||
|
label={$t('password')}
|
||||||
|
placeholder={$t('placeholder.password')}
|
||||||
|
bind:value={password}
|
||||||
|
otherPasswordValue={confirm_password}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
name="confirm_password"
|
||||||
|
type="password"
|
||||||
|
label={$t('confirm_password')}
|
||||||
|
placeholder={$t('placeholder.password')}
|
||||||
|
bind:value={confirm_password}
|
||||||
|
otherPasswordValue={password}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<button class="button-dark">{$t('change_password')} </button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
@@ -5,9 +5,9 @@ import "time"
|
|||||||
type Verification struct {
|
type Verification struct {
|
||||||
UpdatedAt time.Time
|
UpdatedAt time.Time
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
EmailVerifiedAt *time.Time `gorm:"Default:NULL" json:"email_verified_at"`
|
VerifiedAt *time.Time `gorm:"Default:NULL" json:"verified_at"`
|
||||||
IDVerifiedAt *time.Time `gorm:"Default:NULL" json:"id_verified_at"`
|
|
||||||
VerificationToken string `json:"token"`
|
VerificationToken string `json:"token"`
|
||||||
ID uint `gorm:"primaryKey"`
|
ID uint `gorm:"primaryKey"`
|
||||||
UserID uint `gorm:"unique;" json:"user_id"`
|
UserID uint `gorm:"unique;" json:"user_id"`
|
||||||
|
Type string
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user