Skip to content
Snippets Groups Projects
Commit d3e2f71f authored by Embruch, Gerd's avatar Embruch, Gerd
Browse files

fixed registration and verification

parent 30875051
Branches
No related tags found
No related merge requests found
...@@ -26,22 +26,11 @@ function AuthState({ children }) { ...@@ -26,22 +26,11 @@ function AuthState({ children }) {
// ### LOGIN // ### LOGIN
async function login(credentials) { async function login(credentials) {
let result = {}; const result = await api.post(
try { '/auth/login',
result = await api.post(
'/users/login',
credentials, credentials,
{ withCredentials: true } { withCredentials: true }
); );
} catch (error) {
result = await api.post(
'/users/adminlogin',
credentials,
{ withCredentials: true }
);
// try to match output with normal user
result.data.record = { ...result.data.admin, isAdmin: true };
}
// set current user to login and merge accessToken into currentUser // set current user to login and merge accessToken into currentUser
dispatchCurrentUser({ type: USER_ACTIONS.SET, payload: { ...result.data.record } }); dispatchCurrentUser({ type: USER_ACTIONS.SET, payload: { ...result.data.record } });
setAccessToken(result.data.token); setAccessToken(result.data.token);
...@@ -59,6 +48,11 @@ function AuthState({ children }) { ...@@ -59,6 +48,11 @@ function AuthState({ children }) {
return result; return result;
} }
// ### REQUEST RESEND VERIFICATION TOKEN
function requestVerificationToken(email) {
return api.post('/auth/verification', { email });
}
// ### REQUEST PASSWORD RESET // ### REQUEST PASSWORD RESET
function requestPasswordReset(email) { function requestPasswordReset(email) {
return api.post('/users/requestpasswordreset', { email }); return api.post('/users/requestpasswordreset', { email });
...@@ -76,6 +70,7 @@ function AuthState({ children }) { ...@@ -76,6 +70,7 @@ function AuthState({ children }) {
login, login,
currentUser, currentUser,
logout, logout,
requestVerificationToken,
requestPasswordReset, requestPasswordReset,
requestEmailReset, requestEmailReset,
USER_ACTIONS, USER_ACTIONS,
......
import { zodResolver } from '@hookform/resolvers/zod';
import React, { useRef, useState } from 'react';
import { Helmet } from 'react-helmet-async';
import { FormProvider, useForm, useFormContext } from 'react-hook-form';
import { Link } from 'react-router-dom';
import { z } from 'zod';
import Input from '../../components/form/Input';
import Submit from '../../components/form/Submit';
import { useAuth } from '../../contexts/Auth/AuthState';
import { mergeBackendValidation, setFlashMsg } from '../../utils/ErrorHandling';
import Heading from '../../components/font/Heading';
function ForgotPassword() {
// #################################
// VALIDATION SCHEMA
// #################################
const schema = z.object({
email: z.string().email(),
});
// #################################
// HOOKS
// #################################
const methods = useForm({
resolver: zodResolver(schema),
mode: 'onSubmit'
});
// #################################
// FUNCTIONS
// #################################
// ### IMPORT FUNCTION FROM AuthContext
const { requestVerificationToken } = useAuth();
// ### HANDLE SUBMITTING FORM
async function handleSendForm(inputs) {
try {
// send data to function
const result = await requestVerificationToken(inputs.email);
// set flash message
setFlashMsg(result.data?.message);
} catch (error) {
// catch the error
mergeBackendValidation(error.response.status, error.response.data, methods.setError);
}
}
// #################################
// OUTPUT
// #################################
return (
<>
{/* render page title */}
<Helmet><title>[{import.meta.env.VITE_APP_NAME}] Password forgot</title></Helmet>
<Heading level="1">resend verification token</Heading>
<FormProvider {...methods} >
<form onSubmit={methods.handleSubmit(handleSendForm)}>
<Input name='email' type='mail' title='E-Mail' className='h-16' required={true} />
<Submit value='request' />
</form>
</FormProvider>
<div className="my-4 flex justify-between">
<Link to="/signup/insertToken">Back to Verification</Link>
</div>
</>
);
}
export default React.memo(ForgotPassword);
\ No newline at end of file
...@@ -25,10 +25,10 @@ function Signup() { ...@@ -25,10 +25,10 @@ function Signup() {
password: z.string().refine((val) => val && validator.isStrongPassword(val), { password: z.string().refine((val) => val && validator.isStrongPassword(val), {
message: 'This value must be min 6 characters long and contain uppercase, lowercase, number, specialchar.', message: 'This value must be min 6 characters long and contain uppercase, lowercase, number, specialchar.',
}), }),
passwordConfirm: z.string(), confirmPassword: z.string(),
}).refine((data) => data.password === data.passwordConfirm, { }).refine((data) => data.password === data.confirmPassword, {
message: "Passwords don't match", message: "Passwords don't match",
path: ["passwordConfirm"], path: ["confirmPassword"],
}); });
// ################################# // #################################
// HOOKS // HOOKS
...@@ -49,7 +49,7 @@ function Signup() { ...@@ -49,7 +49,7 @@ function Signup() {
username: '', username: '',
email: '', email: '',
password: '', password: '',
passwordConfirm: '' confirmPassword: ''
} }
}); });
...@@ -61,9 +61,9 @@ function Signup() { ...@@ -61,9 +61,9 @@ function Signup() {
async function handleSendForm(record) { async function handleSendForm(record) {
try { try {
// send data to API // send data to API
const result = await api.post(`/users/signup`, record); const result = await api.post(`/users`, record);
// if successfull redirect to login page // if successfull redirect to login page
redirect(`/login`); redirect(`/signup/insertToken`);
// FIX: flash message not dislayed // FIX: flash message not dislayed
setFlashMsg(result.data?.message); setFlashMsg(result.data?.message);
...@@ -88,13 +88,14 @@ function Signup() { ...@@ -88,13 +88,14 @@ function Signup() {
<Input name='username' type='text' title='username' className='h-16' /> <Input name='username' type='text' title='username' className='h-16' />
<Input name='email' type='mail' title='E-Mail' className='h-16' /> <Input name='email' type='mail' title='E-Mail' className='h-16' />
<Input name='password' type='password' title='password' className='h-16' /> <Input name='password' type='password' title='password' className='h-16' />
<Input name='passwordConfirm' type='password' title='confirm password' className='h-16' /> <Input name='confirmPassword' type='password' title='confirm password' className='h-16' />
<Submit value='Signup' /> <Submit value='Signup' />
</form> </form>
</FormProvider> </FormProvider>
<div className="mt-4"> <div className="mt-4 flex justify-between">
<Link to="/login">Back to Login</Link> <Link to="/login">Back to Login</Link>
<Link to="/signup/insertToken">verify Account</Link>
</div> </div>
</> </>
); );
......
...@@ -49,7 +49,7 @@ function Verify() { ...@@ -49,7 +49,7 @@ function Verify() {
// TRY UPDATE // TRY UPDATE
try { try {
// send data // send data
const result = await api.post(`/users/confirmverification`, inputs); const result = await api.patch(`/auth/verification`, inputs);
redirect('/login'); redirect('/login');
// set flash message // set flash message
setFlashMsg(result.data?.message); setFlashMsg(result.data?.message);
...@@ -77,6 +77,7 @@ function Verify() { ...@@ -77,6 +77,7 @@ function Verify() {
<div className="my-4 flex justify-between"> <div className="my-4 flex justify-between">
<Link to="/login">Back to Login</Link> <Link to="/login">Back to Login</Link>
<Link to="/signup/resend_token">Resend Token</Link>
</div> </div>
</> </>
); );
......
...@@ -58,6 +58,7 @@ export const sitemap = [{ ...@@ -58,6 +58,7 @@ export const sitemap = [{
{ {
path: '/signup', children: [ path: '/signup', children: [
{ index: true, element: loadComponent('User/Signup') }, { index: true, element: loadComponent('User/Signup') },
{ path: 'resend_token', element: loadComponent('User/ResendVerificationToken') },
{ path: ':token', element: loadComponent('User/Verify') } { path: ':token', element: loadComponent('User/Verify') }
] ]
}, },
......
...@@ -29,21 +29,40 @@ api.interceptors.request.use( ...@@ -29,21 +29,40 @@ api.interceptors.request.use(
// ### RESPONSE INTERCEPTOR // ### RESPONSE INTERCEPTOR
// refreshes accessToken if needed // refreshes accessToken if needed
api.interceptors.response.use( api.interceptors.response.use(
async (res) => { (res) => {
switch (res.config.url) {
case '/users/refreshjwt':
case '/users/logout':
case '/users/login':
return res; return res;
default: },
const refresh = await api.get( async (err) => {
'/users/refreshjwt', // console.log(err);
// save original request config
const originalConfig = err.config;
// if access denied and not a retry already
// BUG: Infinit loop because _retry isn't set at runtime
// console.log(originalConfig);
// console.log(JSON.stringify(originalConfig));
if (originalConfig && err?.response?.status === 403 && originalConfig._retry !== true) {
// patch config to remember it's a retry
originalConfig._retry = true;
console.log('trying to refresh the accessToken and rerun the request');
// console.log('retry', err.code, originalConfig._retry);
// refresh access token
try {
const result = await api.get(
'/auth',
{}, {},
{ withCredentials: true } { withCredentials: true }
); );
localStorage.setItem("accessToken", JSON.stringify(refresh.data.token)); // TODO: don't store accessToken in localStorage, keep in memory only
return res; localStorage.setItem("accessToken", JSON.stringify(result.data.accessToken));
// run retry
return api(originalConfig);
} catch (error) {
return Promise.reject(error);
}
} }
return Promise.reject(err);
} }
); );
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment