Merge pull request #93 from matrix-org/registration_field_validate
Do (more) client side validation of registration parameters.
This commit is contained in:
commit
a849955c51
3 changed files with 152 additions and 30 deletions
|
@ -34,7 +34,8 @@
|
||||||
"react-dom": "^0.14.2",
|
"react-dom": "^0.14.2",
|
||||||
"react-gemini-scrollbar": "^2.0.1",
|
"react-gemini-scrollbar": "^2.0.1",
|
||||||
"sanitize-html": "^1.11.1",
|
"sanitize-html": "^1.11.1",
|
||||||
"velocity-animate": "^1.2.3"
|
"velocity-animate": "^1.2.3",
|
||||||
|
"velocity-ui-pack": "^1.2.2"
|
||||||
},
|
},
|
||||||
"//deps": "The loader packages are here because webpack in a project that depends on us needs them in this package's node_modules folder",
|
"//deps": "The loader packages are here because webpack in a project that depends on us needs them in this package's node_modules folder",
|
||||||
"//depsbuglink": "https://github.com/webpack/webpack/issues/1472",
|
"//depsbuglink": "https://github.com/webpack/webpack/issues/1472",
|
||||||
|
|
|
@ -159,6 +159,15 @@ module.exports = React.createClass({
|
||||||
case "RegistrationForm.ERR_PASSWORD_LENGTH":
|
case "RegistrationForm.ERR_PASSWORD_LENGTH":
|
||||||
errMsg = `Password too short (min ${MIN_PASSWORD_LENGTH}).`;
|
errMsg = `Password too short (min ${MIN_PASSWORD_LENGTH}).`;
|
||||||
break;
|
break;
|
||||||
|
case "RegistrationForm.ERR_EMAIL_INVALID":
|
||||||
|
errMsg = "This doesn't look like a valid email address";
|
||||||
|
break;
|
||||||
|
case "RegistrationForm.ERR_USERNAME_INVALID":
|
||||||
|
errMsg = "User names may only contain letters, numbers, dots, hyphens and underscores.";
|
||||||
|
break;
|
||||||
|
case "RegistrationForm.ERR_USERNAME_BLANK":
|
||||||
|
errMsg = "You need to enter a user name";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.error("Unknown error code: %s", errCode);
|
console.error("Unknown error code: %s", errCode);
|
||||||
errMsg = "An unknown error occurred.";
|
errMsg = "An unknown error occurred.";
|
||||||
|
|
|
@ -17,8 +17,15 @@ limitations under the License.
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
|
var Velocity = require('velocity-animate');
|
||||||
|
require('velocity-ui-pack');
|
||||||
var sdk = require('../../../index');
|
var sdk = require('../../../index');
|
||||||
|
|
||||||
|
var FIELD_EMAIL = 'field_email';
|
||||||
|
var FIELD_USERNAME = 'field_username';
|
||||||
|
var FIELD_PASSWORD = 'field_password';
|
||||||
|
var FIELD_PASSWORD_CONFIRM = 'field_password_confirm';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A pure UI component which displays a registration form.
|
* A pure UI component which displays a registration form.
|
||||||
*/
|
*/
|
||||||
|
@ -50,34 +57,28 @@ module.exports = React.createClass({
|
||||||
email: this.props.defaultEmail,
|
email: this.props.defaultEmail,
|
||||||
username: this.props.defaultUsername,
|
username: this.props.defaultUsername,
|
||||||
password: null,
|
password: null,
|
||||||
passwordConfirm: null
|
passwordConfirm: null,
|
||||||
|
fieldValid: {}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
onSubmit: function(ev) {
|
onSubmit: function(ev) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
|
|
||||||
var pwd1 = this.refs.password.value.trim();
|
// validate everything, in reverse order so
|
||||||
var pwd2 = this.refs.passwordConfirm.value.trim()
|
// the error that ends up being displayed
|
||||||
|
// is the one from the first invalid field.
|
||||||
var errCode;
|
// It's not super ideal that this just calls
|
||||||
if (!pwd1 || !pwd2) {
|
// onError once for each invalid field.
|
||||||
errCode = "RegistrationForm.ERR_PASSWORD_MISSING";
|
this.validateField(FIELD_PASSWORD_CONFIRM);
|
||||||
}
|
this.validateField(FIELD_PASSWORD);
|
||||||
else if (pwd1 !== pwd2) {
|
this.validateField(FIELD_USERNAME);
|
||||||
errCode = "RegistrationForm.ERR_PASSWORD_MISMATCH";
|
this.validateField(FIELD_EMAIL);
|
||||||
}
|
|
||||||
else if (pwd1.length < this.props.minPasswordLength) {
|
|
||||||
errCode = "RegistrationForm.ERR_PASSWORD_LENGTH";
|
|
||||||
}
|
|
||||||
if (errCode) {
|
|
||||||
this.props.onError(errCode);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (this.allFieldsValid()) {
|
||||||
var promise = this.props.onRegisterClick({
|
var promise = this.props.onRegisterClick({
|
||||||
username: this.refs.username.value.trim(),
|
username: this.refs.username.value.trim(),
|
||||||
password: pwd1,
|
password: this.refs.password.value.trim(),
|
||||||
email: this.refs.email.value.trim()
|
email: this.refs.email.value.trim()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -87,15 +88,120 @@ module.exports = React.createClass({
|
||||||
ev.target.disabled = false;
|
ev.target.disabled = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if all fields were valid last time
|
||||||
|
* they were validated.
|
||||||
|
*/
|
||||||
|
allFieldsValid: function() {
|
||||||
|
var keys = Object.keys(this.state.fieldValid);
|
||||||
|
for (var i = 0; i < keys.length; ++i) {
|
||||||
|
if (this.state.fieldValid[keys[i]] == false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
validateField: function(field_id) {
|
||||||
|
var pwd1 = this.refs.password.value.trim();
|
||||||
|
var pwd2 = this.refs.passwordConfirm.value.trim()
|
||||||
|
|
||||||
|
switch (field_id) {
|
||||||
|
case FIELD_EMAIL:
|
||||||
|
this.markFieldValid(
|
||||||
|
field_id,
|
||||||
|
this.refs.email.value == '' || !!this.refs.email.value.match(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i),
|
||||||
|
"RegistrationForm.ERR_EMAIL_INVALID"
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case FIELD_USERNAME:
|
||||||
|
// XXX: SPEC-1
|
||||||
|
if (encodeURIComponent(this.refs.username.value) != this.refs.username.value) {
|
||||||
|
this.markFieldValid(
|
||||||
|
field_id,
|
||||||
|
false,
|
||||||
|
"RegistrationForm.ERR_USERNAME_INVALID"
|
||||||
|
);
|
||||||
|
} else if (this.refs.username.value == '') {
|
||||||
|
this.markFieldValid(
|
||||||
|
field_id,
|
||||||
|
false,
|
||||||
|
"RegistrationForm.ERR_USERNAME_BLANK"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.markFieldValid(field_id, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FIELD_PASSWORD:
|
||||||
|
if (pwd1 == '') {
|
||||||
|
this.markFieldValid(
|
||||||
|
field_id,
|
||||||
|
false,
|
||||||
|
"RegistrationForm.ERR_PASSWORD_MISSING"
|
||||||
|
);
|
||||||
|
} else if (pwd1.length < this.props.minPasswordLength) {
|
||||||
|
this.markFieldValid(
|
||||||
|
field_id,
|
||||||
|
false,
|
||||||
|
"RegistrationForm.ERR_PASSWORD_LENGTH"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.markFieldValid(field_id, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FIELD_PASSWORD_CONFIRM:
|
||||||
|
this.markFieldValid(
|
||||||
|
field_id, pwd1 == pwd2,
|
||||||
|
"RegistrationForm.ERR_PASSWORD_MISMATCH"
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
markFieldValid: function(field_id, val, error_code) {
|
||||||
|
var fieldValid = this.state.fieldValid;
|
||||||
|
fieldValid[field_id] = val;
|
||||||
|
this.setState({fieldValid: fieldValid});
|
||||||
|
if (!val) {
|
||||||
|
Velocity(this.fieldElementById(field_id), "callout.shake", 300);
|
||||||
|
this.props.onError(error_code);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
fieldElementById(field_id) {
|
||||||
|
switch (field_id) {
|
||||||
|
case FIELD_EMAIL:
|
||||||
|
return this.refs.email;
|
||||||
|
case FIELD_USERNAME:
|
||||||
|
return this.refs.username;
|
||||||
|
case FIELD_PASSWORD:
|
||||||
|
return this.refs.password;
|
||||||
|
case FIELD_PASSWORD_CONFIRM:
|
||||||
|
return this.refs.passwordConfirm;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_styleField: function(field_id, baseStyle) {
|
||||||
|
var style = baseStyle || {};
|
||||||
|
if (this.state.fieldValid[field_id] === false) {
|
||||||
|
style['borderColor'] = 'red';
|
||||||
|
}
|
||||||
|
return style;
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
|
var self = this;
|
||||||
var emailSection, registerButton;
|
var emailSection, registerButton;
|
||||||
if (this.props.showEmail) {
|
if (this.props.showEmail) {
|
||||||
emailSection = (
|
emailSection = (
|
||||||
<input className="mx_Login_field" type="text" ref="email"
|
<input className="mx_Login_field" type="text" ref="email"
|
||||||
autoFocus={true} placeholder="Email address"
|
autoFocus={true} placeholder="Email address"
|
||||||
defaultValue={this.state.email} />
|
defaultValue={this.state.email}
|
||||||
|
style={this._styleField(FIELD_EMAIL)}
|
||||||
|
onBlur={function() {self.validateField(FIELD_EMAIL)}} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (this.props.onRegisterClick) {
|
if (this.props.onRegisterClick) {
|
||||||
|
@ -111,13 +217,19 @@ module.exports = React.createClass({
|
||||||
<br />
|
<br />
|
||||||
<input className="mx_Login_field" type="text" ref="username"
|
<input className="mx_Login_field" type="text" ref="username"
|
||||||
placeholder="User name" defaultValue={this.state.username}
|
placeholder="User name" defaultValue={this.state.username}
|
||||||
|
style={this._styleField(FIELD_USERNAME)}
|
||||||
|
onBlur={function() {self.validateField(FIELD_USERNAME)}}
|
||||||
disabled={this.props.disableUsernameChanges} />
|
disabled={this.props.disableUsernameChanges} />
|
||||||
<br />
|
<br />
|
||||||
<input className="mx_Login_field" type="password" ref="password"
|
<input className="mx_Login_field" type="password" ref="password"
|
||||||
|
style={this._styleField(FIELD_PASSWORD)}
|
||||||
|
onBlur={function() {self.validateField(FIELD_PASSWORD)}}
|
||||||
placeholder="Password" defaultValue={this.state.password} />
|
placeholder="Password" defaultValue={this.state.password} />
|
||||||
<br />
|
<br />
|
||||||
<input className="mx_Login_field" type="password" ref="passwordConfirm"
|
<input className="mx_Login_field" type="password" ref="passwordConfirm"
|
||||||
placeholder="Confirm password"
|
placeholder="Confirm password"
|
||||||
|
style={this._styleField(FIELD_PASSWORD_CONFIRM)}
|
||||||
|
onBlur={function() {self.validateField(FIELD_PASSWORD_CONFIRM)}}
|
||||||
defaultValue={this.state.passwordConfirm} />
|
defaultValue={this.state.passwordConfirm} />
|
||||||
<br />
|
<br />
|
||||||
{registerButton}
|
{registerButton}
|
||||||
|
|
Loading…
Reference in a new issue