diff --git a/packages/component-user-manager/src/routes/users/resetPassword.js b/packages/component-user-manager/src/routes/users/resetPassword.js index 47e21eaf77b4ee9fa3f05a95afa3e6cbc7a30811..70257a1fb7ba13bddc50c8e8043f4a533f06d2a7 100644 --- a/packages/component-user-manager/src/routes/users/resetPassword.js +++ b/packages/component-user-manager/src/routes/users/resetPassword.js @@ -23,9 +23,6 @@ module.exports = models => async (req, res) => { let { user } = validateResponse - if (user.isConfirmed) - return res.status(400).json({ error: 'User is already confirmed' }) - req.body.isConfirmed = true delete user.passwordResetToken delete user.passwordResetTimestamp diff --git a/packages/component-user-manager/src/tests/users/forgotPassword.test.js b/packages/component-user-manager/src/tests/users/forgotPassword.test.js index cb115917542489188e45a393ed1764b61ee8ccba..e6f51c974dabb9e51ff1dc0063c43a8b99ada457 100644 --- a/packages/component-user-manager/src/tests/users/forgotPassword.test.js +++ b/packages/component-user-manager/src/tests/users/forgotPassword.test.js @@ -63,7 +63,7 @@ describe('Users forgot password route handler', () => { `A password reset email has been sent to ${body.email}.`, ) }) - it('should return success if the email is non-existant', async () => { + it('should return success if the email is non-existent', async () => { body.email = 'email@example.com' const req = httpMocks.createRequest({ body }) const res = httpMocks.createResponse() diff --git a/packages/component-user-manager/src/tests/users/resetPassword.test.js b/packages/component-user-manager/src/tests/users/resetPassword.test.js index 12d6e07bc25a0e4a03737d08f09519c1a443d659..130526eb7f9bca6bf3cb00fd24a7e96cd3d8e2b7 100644 --- a/packages/component-user-manager/src/tests/users/resetPassword.test.js +++ b/packages/component-user-manager/src/tests/users/resetPassword.test.js @@ -9,7 +9,7 @@ const fixturesService = require('pubsweet-component-fixture-service') const { Model, fixtures } = fixturesService const chance = new Chance() -const { user, author } = fixtures.users +const { user } = fixtures.users jest.mock('pubsweet-component-mail-service', () => ({ sendSimpleEmail: jest.fn(), sendNotificationEmail: jest.fn(), @@ -78,16 +78,6 @@ describe('Users password reset route handler', () => { const data = JSON.parse(res._getData()) expect(data.error).toEqual('invalid request') }) - it('should return an error when the user is already confirmed', async () => { - body.email = author.email - body.token = author.passwordResetToken - const req = httpMocks.createRequest({ body }) - const res = httpMocks.createResponse() - await require(resetPasswordPath)(models)(req, res) - expect(res.statusCode).toBe(400) - const data = JSON.parse(res._getData()) - expect(data.error).toEqual('User is already confirmed') - }) it('should return success when the body is correct', async () => { const req = httpMocks.createRequest({ body }) const res = httpMocks.createResponse() diff --git a/packages/components-faraday/src/components/AppBar/AppBar.js b/packages/components-faraday/src/components/AppBar/AppBar.js index d03ed85d76d597adb0b2c46f208342e5c6879b07..22f1f147483990676db2bebf431ade8038b2ce4e 100644 --- a/packages/components-faraday/src/components/AppBar/AppBar.js +++ b/packages/components-faraday/src/components/AppBar/AppBar.js @@ -136,12 +136,12 @@ const User = styled.div` const Dropdown = styled.div` background-color: ${th('colorBackground')}; - border: ${th('borderWidth')} ${th('borderStyle')} ${th('colorBorder')}; position: absolute; right: 20px; top: 60px; width: calc(${th('gridUnit')} * 8); z-index: 10; + border: ${th('borderWidth')} ${th('borderStyle')} ${th('colorBorder')}; ` const DropdownOption = styled.div` diff --git a/packages/components-faraday/src/components/SignUp/ConfirmAccount.js b/packages/components-faraday/src/components/SignUp/ConfirmAccount.js index b370b739b151337170a5bd673b00bb8764487a00..2a685b927f621271162a134a24794a56b8fcfc54 100644 --- a/packages/components-faraday/src/components/SignUp/ConfirmAccount.js +++ b/packages/components-faraday/src/components/SignUp/ConfirmAccount.js @@ -8,7 +8,7 @@ import { compose, lifecycle, withState } from 'recompose' import { parseSearchParams } from '../utils' import { confirmUser } from '../../redux/users' -const ConfirmAccount = ({ location, message, history }) => ( +const ConfirmAccount = ({ message, history }) => ( <Root> <Title>{message}</Title> <Button onClick={() => history.replace('/')} primary> diff --git a/packages/components-faraday/src/components/SignUp/SignUpInvitationPage.js b/packages/components-faraday/src/components/SignUp/SignUpInvitationPage.js index b0f56d4f1368a3f29855c3096ca35df09080dede..12462b277554942af36262523997b6e070ab51b6 100644 --- a/packages/components-faraday/src/components/SignUp/SignUpInvitationPage.js +++ b/packages/components-faraday/src/components/SignUp/SignUpInvitationPage.js @@ -1,62 +1,13 @@ -import { omit } from 'lodash' import { withJournal } from 'xpub-journal' -import { create } from 'pubsweet-client/src/helpers/api' -import { loginUser } from 'pubsweet-component-login/actions' import { compose, withState, withProps, withHandlers } from 'recompose' import SignUpInvitation from './SignUpInvitationForm' -import { parseSignupAuthor, handleFormError } from '../utils' - -const login = (dispatch, values, history) => - dispatch(loginUser(values)) - .then(() => { - history.push('/') - }) - .catch(handleFormError) - -const confirmUser = (email, token, history) => (values, dispatch) => { - const request = { ...values, email, token } - if (values) { - return create('/users/reset-password', omit(request, ['confirmPassword'])) - .then(r => { - const { username } = r - const { password } = values - login(dispatch, { username, password }, history) - }) - .catch(handleFormError) - } -} - -const signUpUser = history => (values, dispatch) => - create('/users', parseSignupAuthor(values)) - .then(r => { - const { username } = r - const { password } = values - login(dispatch, { username, password }, history).then(() => { - create('/emails', { - email: values.email, - type: 'signup', - }) - }) - }) - .catch(handleFormError) - -const resetUserPassword = history => ({ email }, dispatch) => - create(`/users/forgot-password`, { email }) - .then(r => { - // go to dedicated route - history.push('/') - }) - .catch(handleFormError) - -const setNewPassword = history => ({ email, token, password }, dispatch) => - create(`/users/reset-password`, { email, token, password }) - .then(() => { - login(dispatch, { username: email, password }, history).then(() => - history.push('/'), - ) - }) - .catch(handleFormError) +import { + confirmUser, + signUpUser, + resetUserPassword, + setNewPassword, +} from './utils' export default compose( withJournal, diff --git a/packages/components-faraday/src/components/SignUp/utils.js b/packages/components-faraday/src/components/SignUp/utils.js index 4f264402c54df9f81ce41908b74ce063b72d3e73..a46f99096ef2210e92ffa5c292846780009635da 100644 --- a/packages/components-faraday/src/components/SignUp/utils.js +++ b/packages/components-faraday/src/components/SignUp/utils.js @@ -1,4 +1,26 @@ /* eslint-disable */ +import { omit, get } from 'lodash' +import { create } from 'pubsweet-client/src/helpers/api' +import { loginUser } from 'pubsweet-component-login/actions' + +import { handleFormError } from '../utils' + +const generatePasswordHash = () => + Array.from({ length: 4 }, () => + Math.random() + .toString(36) + .slice(4), + ).join('') + +export const parseSignupAuthor = ({ token, confirmPassword, ...values }) => ({ + ...values, + admin: false, + isConfirmed: false, + editorInChief: false, + handlingEditor: false, + username: values.email, + confirmationToken: generatePasswordHash(), +}) export const parseSearchParams = url => { const params = new URLSearchParams(url) @@ -8,3 +30,60 @@ export const parseSearchParams = url => { } return parsedObject } + +export const login = (dispatch, values, history) => + dispatch(loginUser(values)) + .then(() => { + history.push('/') + }) + .catch(handleFormError) + +export const confirmUser = (email, token, history) => (values, dispatch) => { + const request = { ...values, email, token } + if (values) { + return create('/users/reset-password', omit(request, ['confirmPassword'])) + .then(r => { + const { username } = r + const { password } = values + login(dispatch, { username, password }, history) + }) + .catch(handleFormError) + } +} + +export const signUpUser = history => (values, dispatch) => + create('/users', parseSignupAuthor(values)) + .then(r => { + const { username } = r + const { password } = values + login(dispatch, { username, password }, history).then(() => { + create('/emails', { + email: values.email, + type: 'signup', + }) + }) + }) + .catch(handleFormError) + +export const resetUserPassword = history => ({ email }, dispatch) => + create(`/users/forgot-password`, { email }) + .then(r => { + const message = get(r, 'message') || 'Password reset email has been sent.' + history.push('/info-page', { + title: 'Reset Password', + content: message, + }) + }) + .catch(handleFormError) + +export const setNewPassword = history => ( + { email, token, password }, + dispatch, +) => + create(`/users/reset-password`, { email, token, password }) + .then(() => { + login(dispatch, { username: email, password }, history).then(() => + history.push('/'), + ) + }) + .catch(handleFormError) diff --git a/packages/components-faraday/src/components/UIComponents/ConfirmationPage.js b/packages/components-faraday/src/components/UIComponents/ConfirmationPage.js index 3f974da8f2e7384d696cdde1db84f56aa6b6dcdc..3c893e825b13c2dfa75564ee9a3b5f67f9f5aa01 100644 --- a/packages/components-faraday/src/components/UIComponents/ConfirmationPage.js +++ b/packages/components-faraday/src/components/UIComponents/ConfirmationPage.js @@ -81,6 +81,6 @@ const Title = styled.div` color: ${th('colorPrimary')}; font-size: ${th('fontSizeHeading5')}; font-family: ${th('fontHeading')}; - margin: 10px auto; + margin: ${th('gridUnit')} auto; ` // #endregion diff --git a/packages/components-faraday/src/components/UIComponents/InfoPage.js b/packages/components-faraday/src/components/UIComponents/InfoPage.js new file mode 100644 index 0000000000000000000000000000000000000000..38e16bb14a1a49e448470ae2860cd9b87f102bdd --- /dev/null +++ b/packages/components-faraday/src/components/UIComponents/InfoPage.js @@ -0,0 +1,52 @@ +import React from 'react' +import styled from 'styled-components' +import { Button, th } from '@pubsweet/ui' + +const InfoPage = ({ + location: { + state: { + title = 'Successfully', + content = '', + path = '/', + buttonText = 'Go to Dashboard', + }, + }, + history, +}) => ( + <Root> + <Title>{title}</Title> + <Content>{content}</Content> + <Button onClick={() => history.push(path)} primary> + {buttonText} + </Button> + </Root> +) + +export default InfoPage + +// #region styles +const Root = styled.div` + color: ${th('colorText')}; + margin: 0 auto; + text-align: center; + width: 70vw; + + a { + color: ${th('colorText')}; + } +` + +const Title = styled.div` + color: ${th('colorPrimary')}; + font-size: ${th('fontSizeHeading5')}; + font-family: ${th('fontHeading')}; + margin: ${th('gridUnit')} auto; +` + +const Content = styled.p` + color: ${th('colorPrimary')}; + font-family: ${th('fontReading')}; + font-size: ${th('fontSizeBase')}; + margin: ${th('gridUnit')} auto; +` +// #endregion diff --git a/packages/components-faraday/src/components/UIComponents/index.js b/packages/components-faraday/src/components/UIComponents/index.js index 7ccd5732e09478b2c6463473098039f151a19754..5f22ea1c71cc274efe11bf2fdc777e0649a7377b 100644 --- a/packages/components-faraday/src/components/UIComponents/index.js +++ b/packages/components-faraday/src/components/UIComponents/index.js @@ -4,6 +4,7 @@ export { FormItems } export { default as Logo } from './Logo' export { default as Spinner } from './Spinner' export { default as NotFound } from './NotFound' +export { default as InfoPage } from './InfoPage' export { default as ErrorPage } from './ErrorPage' export { default as DateParser } from './DateParser' export { default as ConfirmationPage } from './ConfirmationPage' diff --git a/packages/components-faraday/src/components/utils.js b/packages/components-faraday/src/components/utils.js index 49b33a507b7b597b2eb5bf72078024eb5fcae83f..60a5639770622876a45f7c913667856f5be5b5fd 100644 --- a/packages/components-faraday/src/components/utils.js +++ b/packages/components-faraday/src/components/utils.js @@ -79,13 +79,6 @@ export const redirectToError = redirectFn => err => { redirectFn('/error-page', errorText || 'Oops! Something went wrong.') } -const generatePasswordHash = () => - Array.from({ length: 4 }, () => - Math.random() - .toString(36) - .slice(4), - ).join('') - export const passwordValidator = values => { const errors = {} if (!values.password) { @@ -100,16 +93,6 @@ export const passwordValidator = values => { return errors } -export const parseSignupAuthor = ({ token, confirmPassword, ...values }) => ({ - ...values, - admin: false, - isConfirmed: false, - editorInChief: false, - handlingEditor: false, - username: values.email, - confirmationToken: generatePasswordHash(), -}) - export const parseSearchParams = url => { const params = new URLSearchParams(url) const parsedObject = {} diff --git a/packages/xpub-faraday/app/routes.js b/packages/xpub-faraday/app/routes.js index 04c38a85b76e6dfdfe76a7eee25d600118f31b98..98d8d460a2558e90eb0670bb9e6965a0c63f5519 100644 --- a/packages/xpub-faraday/app/routes.js +++ b/packages/xpub-faraday/app/routes.js @@ -9,6 +9,7 @@ import { ManuscriptPage } from 'pubsweet-component-manuscript/src/components' import DashboardPage from 'pubsweet-components-faraday/src/components/Dashboard' import { NotFound, + InfoPage, ErrorPage, ConfirmationPage, } from 'pubsweet-components-faraday/src/components/UIComponents/' @@ -108,6 +109,7 @@ const Routes = () => ( /> <Route component={ErrorPage} exact path="/error-page" /> + <Route component={InfoPage} exact path="/info-page" /> <Route component={NotFound} /> </Switch> </FaradayApp>