mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2024-11-23 07:38:07 -05:00
Merge pull request #3289 from benjiwheeler/join-flow-validate-email-remotely
Join flow validate email remotely
This commit is contained in:
commit
8f11de675d
3 changed files with 100 additions and 7 deletions
|
@ -4,9 +4,9 @@ const React = require('react');
|
|||
const PropTypes = require('prop-types');
|
||||
import {Formik} from 'formik';
|
||||
const {injectIntl, intlShape} = require('react-intl');
|
||||
const emailValidator = require('email-validator');
|
||||
const FormattedMessage = require('react-intl').FormattedMessage;
|
||||
|
||||
const validate = require('../../lib/validate');
|
||||
const JoinFlowStep = require('./join-flow-step.jsx');
|
||||
const FormikInput = require('../../components/formik-forms/formik-input.jsx');
|
||||
const FormikCheckbox = require('../../components/formik-forms/formik-checkbox.jsx');
|
||||
|
@ -75,11 +75,16 @@ class EmailStep extends React.Component {
|
|||
}
|
||||
validateEmail (email) {
|
||||
if (!email) return this.props.intl.formatMessage({id: 'general.required'});
|
||||
const isValidLocally = emailValidator.validate(email);
|
||||
if (isValidLocally) {
|
||||
return null; // TODO: validate email address remotely
|
||||
}
|
||||
return this.props.intl.formatMessage({id: 'registration.validationEmailInvalid'});
|
||||
const localResult = validate.validateEmailLocally(email);
|
||||
if (!localResult.valid) return this.props.intl.formatMessage({id: localResult.errMsgId});
|
||||
return validate.validateEmailRemotely(email).then(
|
||||
remoteResult => {
|
||||
if (remoteResult.valid === true) {
|
||||
return null;
|
||||
}
|
||||
return this.props.intl.formatMessage({id: remoteResult.errMsgId});
|
||||
}
|
||||
);
|
||||
}
|
||||
validateForm () {
|
||||
return {};
|
||||
|
@ -119,6 +124,8 @@ class EmailStep extends React.Component {
|
|||
handleSubmit,
|
||||
isSubmitting,
|
||||
setFieldError,
|
||||
setFieldTouched,
|
||||
setFieldValue,
|
||||
validateField
|
||||
} = props;
|
||||
return (
|
||||
|
@ -161,7 +168,11 @@ class EmailStep extends React.Component {
|
|||
validationClassName="validation-full-width-input"
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
onBlur={() => validateField('email')}
|
||||
onFocus={() => setFieldError('email', null)}
|
||||
onChange={e => {
|
||||
setFieldValue('email', e.target.value);
|
||||
setFieldTouched('email');
|
||||
setFieldError('email', null);
|
||||
}}
|
||||
/* eslint-enable react/jsx-no-bind */
|
||||
onSetRef={this.handleSetEmailRef}
|
||||
/>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
module.exports = {};
|
||||
const api = require('./api');
|
||||
const emailValidator = require('email-validator');
|
||||
|
||||
module.exports.validateUsernameLocally = username => {
|
||||
if (!username || username === '') {
|
||||
|
@ -67,3 +68,36 @@ module.exports.validatePasswordConfirm = (password, passwordConfirm) => {
|
|||
}
|
||||
return {valid: true};
|
||||
};
|
||||
|
||||
module.exports.validateEmailLocally = email => {
|
||||
if (!email || email === '') {
|
||||
return {valid: false, errMsgId: 'general.required'};
|
||||
} else if (emailValidator.validate(email)) {
|
||||
return {valid: true};
|
||||
}
|
||||
return ({valid: false, errMsgId: 'registration.validationEmailInvalid'});
|
||||
};
|
||||
|
||||
module.exports.validateEmailRemotely = email => (
|
||||
new Promise(resolve => {
|
||||
api({
|
||||
host: '', // not handled by API; use existing infrastructure
|
||||
params: {email: email},
|
||||
uri: '/accounts/check_email/'
|
||||
}, (err, body, res) => {
|
||||
if (err || res.statusCode !== 200 || !body || body.length < 1 || !body[0].msg) {
|
||||
resolve({valid: false, errMsgId: 'general.apiError'});
|
||||
}
|
||||
switch (body[0].msg) {
|
||||
case 'valid email':
|
||||
resolve({valid: true});
|
||||
break;
|
||||
case 'Scratch is not allowed to send email to this address.': // e.g., bad TLD or block-listed
|
||||
case 'Enter a valid email address.':
|
||||
default:
|
||||
resolve({valid: false, errMsgId: 'registration.validationEmailInvalid'});
|
||||
break;
|
||||
}
|
||||
});
|
||||
})
|
||||
);
|
||||
|
|
|
@ -63,4 +63,52 @@ describe('unit test lib/validate.js', () => {
|
|||
response = validate.validatePasswordConfirm('', 'abcdefg');
|
||||
expect(response).toEqual({valid: false, errMsgId: 'registration.validationPasswordConfirmNotEquals'});
|
||||
});
|
||||
|
||||
test('validate email address locally', () => {
|
||||
let response;
|
||||
expect(typeof validate.validateEmailLocally).toBe('function');
|
||||
|
||||
// permitted addresses:
|
||||
response = validate.validateEmailLocally('abc@def.com');
|
||||
expect(response).toEqual({valid: true});
|
||||
response = validate.validateEmailLocally('abcdefghijklmnopqrst@abcdefghijklmnopqrst.info');
|
||||
expect(response).toEqual({valid: true});
|
||||
response = validate.validateEmailLocally('abc-def-ghi@jkl-mno.org');
|
||||
expect(response).toEqual({valid: true});
|
||||
response = validate.validateEmailLocally('_______@example.com');
|
||||
expect(response).toEqual({valid: true});
|
||||
response = validate.validateEmailLocally('email@example.museum');
|
||||
expect(response).toEqual({valid: true});
|
||||
response = validate.validateEmailLocally('email@example.co.jp');
|
||||
expect(response).toEqual({valid: true});
|
||||
|
||||
// non-permitted addresses:
|
||||
response = validate.validateEmailLocally('');
|
||||
expect(response).toEqual({valid: false, errMsgId: 'general.required'});
|
||||
response = validate.validateEmailLocally('a');
|
||||
expect(response).toEqual({valid: false, errMsgId: 'registration.validationEmailInvalid'});
|
||||
response = validate.validateEmailLocally('abc@def');
|
||||
expect(response).toEqual({valid: false, errMsgId: 'registration.validationEmailInvalid'});
|
||||
response = validate.validateEmailLocally('abc@def.c');
|
||||
expect(response).toEqual({valid: false, errMsgId: 'registration.validationEmailInvalid'});
|
||||
response = validate.validateEmailLocally('abc😄def@emoji.pizza');
|
||||
expect(response).toEqual({valid: false, errMsgId: 'registration.validationEmailInvalid'});
|
||||
response = validate.validateEmailLocally('あいうえお@example.com');
|
||||
expect(response).toEqual({valid: false, errMsgId: 'registration.validationEmailInvalid'});
|
||||
response = validate.validateEmailLocally('Abc..123@example.com');
|
||||
expect(response).toEqual({valid: false, errMsgId: 'registration.validationEmailInvalid'});
|
||||
response = validate.validateEmailLocally('Joe Smith <email@example.com>');
|
||||
expect(response).toEqual({valid: false, errMsgId: 'registration.validationEmailInvalid'});
|
||||
response = validate.validateEmailLocally('email@example@example.com');
|
||||
expect(response).toEqual({valid: false, errMsgId: 'registration.validationEmailInvalid'});
|
||||
response = validate.validateEmailLocally('email@example..com');
|
||||
expect(response).toEqual({valid: false, errMsgId: 'registration.validationEmailInvalid'});
|
||||
|
||||
// edge cases:
|
||||
// these are strictly legal according to email addres spec, but rejected by library we use:
|
||||
response = validate.validateEmailLocally('email@123.123.123.123');
|
||||
expect(response).toEqual({valid: false, errMsgId: 'registration.validationEmailInvalid'});
|
||||
response = validate.validateEmailLocally('much."more unusual"@example.com');
|
||||
expect(response).toEqual({valid: false, errMsgId: 'registration.validationEmailInvalid'});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue