Merge pull request #3051 from jgable/loginValidation

Add validation for signin/signup
This commit is contained in:
Hannah Wolfe 2014-06-24 09:48:33 +01:00
commit 4b610f09d3
14 changed files with 219 additions and 113 deletions

View File

@ -1,19 +1,32 @@
/*global console, alert */
import ValidationEngine from 'ghost/mixins/validation-engine';
var ForgottenController = Ember.Controller.extend({
var ForgottenController = Ember.Controller.extend(ValidationEngine, {
email: '',
submitting: false,
// ValidationEngine settings
validationType: 'forgotten',
actions: {
submit: function () {
var self = this;
self.user.fetchForgottenPasswordFor(this.email)
.then(function () {
alert('@TODO Notification: Success');
self.transitionToRoute('signin');
})
.catch(function (response) {
alert('@TODO');
console.log(response);
});
this.toggleProperty('submitting');
this.validate({ format: false }).then(function () {
self.user.fetchForgottenPasswordFor(this.email)
.then(function () {
self.toggleProperty('submitting');
self.notifications.showSuccess('Please check your email for instructions.');
self.transitionToRoute('signin');
})
.catch(function (resp) {
self.toggleProperty('submitting');
self.notifications.showAPIError(resp, 'There was a problem logging in, please try again.');
});
}).catch(function (errors) {
self.toggleProperty('submitting');
self.notifications.showErrors(errors);
});
}
}
});

View File

@ -0,0 +1,62 @@
import ajax from 'ghost/utils/ajax';
import ValidationEngine from 'ghost/mixins/validation-engine';
var SigninController = Ember.ObjectController.extend(ValidationEngine, {
needs: 'application',
email: null,
password: null,
submitting: false,
// ValidationEngine settings
validationType: 'signin',
actions: {
login: function () {
var self = this,
data = this.getProperties('email', 'password'),
//Data to check if user came in somewhere besides index
appController = this.get('controllers.application'),
loginTransition = appController.get('loginTransition');
this.toggleProperty('submitting');
this.validate({ format: false }).then(function () {
ajax({
url: self.get('ghostPaths').adminUrl('signin'),
type: 'POST',
headers: {'X-CSRF-Token': self.get('csrf')},
data: data
}).then(function (response) {
// once the email and password are pulled from the controller
// they need to be cleared, or they will reappear next time the signin
// page is visited
self.setProperties({
email: '',
password: ''
});
self.store.pushPayload({users: [response.userData]});
return self.store.find('user', response.userData.id);
}).then(function (user) {
self.send('signedIn', user);
self.notifications.clear();
if (loginTransition) {
appController.set('loginTransition', null);
loginTransition.retry();
} else {
self.transitionTo('posts');
}
}).catch(function (resp) {
self.toggleProperty('submitting');
self.notifications.showAPIError(resp, 'There was a problem logging in, please try again.');
});
}).catch(function (errors) {
self.toggleProperty('submitting');
self.notifications.clear();
self.notifications.showErrors(errors);
});
}
}
});
export default SigninController;

View File

@ -0,0 +1,50 @@
import ajax from 'ghost/utils/ajax';
import ValidationEngine from 'ghost/mixins/validation-engine';
var SignupController = Ember.ObjectController.extend(ValidationEngine, {
name: null,
email: null,
password: null,
submitting: false,
// ValidationEngine settings
validationType: 'signup',
actions: {
signup: function () {
var self = this;
this.toggleProperty('submitting');
this.validate({ format: false }).then(function () {
ajax({
url: self.get('ghostPaths').adminUrl('signup'),
type: 'POST',
headers: {
'X-CSRF-Token': self.get('csrf')
},
data: self.getProperties('name', 'email', 'password')
}).then(function (resp) {
self.toggleProperty('submitting');
if (resp && resp.userData) {
self.store.pushPayload({ users: [resp.userData]});
self.store.find('user', resp.userData.id).then(function (user) {
self.send('signedIn', user);
self.notifications.clear();
self.transitionTo('posts');
});
} else {
self.transitionTo('signin');
}
}, function (resp) {
self.toggleProperty('submitting');
self.notifications.showAPIError(resp);
});
}, function (errors) {
self.toggleProperty('submitting');
self.notifications.showErrors(errors);
});
}
}
});
export default SignupController;

View File

@ -2,15 +2,23 @@ import { getRequestErrorMessage } from 'ghost/utils/ajax';
import ValidatorExtensions from 'ghost/utils/validator-extensions';
import PostValidator from 'ghost/validators/post';
import SignupValidator from 'ghost/validators/signup';
import SigninValidator from 'ghost/validators/signin';
import ForgotValidator from 'ghost/validators/forgotten';
ValidatorExtensions.init();
var ValidationEngine = Ember.Mixin.create({
validators: {
post: PostValidator
post: PostValidator,
signup: SignupValidator,
signin: SigninValidator,
forgotten: ForgotValidator
},
validate: function () {
validate: function (opts) {
opts = opts || {};
var self = this,
type = this.get('validationType'),
validator = this.get('validators.' + type);
@ -26,7 +34,11 @@ var ValidationEngine = Ember.Mixin.create({
return resolve();
}
return reject(self.formatErrors(validationErrors));
if (opts.format !== false) {
validationErrors = self.formatErrors(validationErrors);
}
return reject(validationErrors);
});
},

View File

@ -1,58 +1,8 @@
import ajax from 'ghost/utils/ajax';
import styleBody from 'ghost/mixins/style-body';
import loadingIndicator from 'ghost/mixins/loading-indicator';
var isEmpty = Ember.isEmpty;
var SigninRoute = Ember.Route.extend(styleBody, loadingIndicator, {
classNames: ['ghost-login'],
actions: {
login: function () {
var self = this,
controller = this.get('controller'),
data = controller.getProperties('email', 'password'),
//Data to check if user came in somewhere besides index
appController = this.controllerFor('application'),
loginTransition = appController.get('loginTransition');
if (!isEmpty(data.email) && !isEmpty(data.password)) {
ajax({
url: this.get('ghostPaths').adminUrl('signin'),
type: 'POST',
headers: {'X-CSRF-Token': this.get('csrf')},
data: data
}).then(function (response) {
// once the email and password are pulled from the controller
// they need to be cleared, or they will reappear next time the signin
// page is visited
controller.setProperties({
email: '',
password: ''
});
self.store.pushPayload({users: [response.userData]});
return self.store.find('user', response.userData.id);
}).then(function (user) {
self.send('signedIn', user);
self.notifications.clear();
if (loginTransition) {
appController.set('loginTransition', null);
loginTransition.retry();
} else {
self.transitionTo('posts');
}
}).catch(function (resp) {
self.notifications.showAPIError(resp, 'There was a problem logging in, please try again.');
});
} else {
this.notifications.clear();
this.notifications.showError('Must enter email + password');
}
}
}
classNames: ['ghost-login']
});
export default SigninRoute;

View File

@ -1,49 +1,8 @@
import ajax from 'ghost/utils/ajax';
import styleBody from 'ghost/mixins/style-body';
import loadingIndicator from 'ghost/mixins/loading-indicator';
var SignupRoute = Ember.Route.extend(styleBody, loadingIndicator, {
classNames: ['ghost-signup'],
name: null,
email: null,
password: null,
actions: {
signup: function () {
var self = this,
controller = this.get('controller'),
data = controller.getProperties('name', 'email', 'password');
// TODO: Validate data
if (data.name && data.email && data.password) {
ajax({
url: '/ghost/signup/',
type: 'POST',
headers: {
'X-CSRF-Token': this.get('csrf')
},
data: data
}).then(function (resp) {
if (resp && resp.userData) {
self.store.pushPayload({ users: [resp.userData]});
self.store.find('user', resp.userData.id).then(function (user) {
self.send('signedIn', user);
self.notifications.clear();
self.transitionTo('posts');
});
} else {
self.transitionTo('signin');
}
}, function (resp) {
self.notifications.showAPIError(resp);
});
} else {
this.notifications.showError('Must provide name, email and password');
}
}
}
classNames: ['ghost-signup']
});
export default SignupRoute;

View File

@ -1,8 +1,8 @@
<section class="forgotten-box js-forgotten-box fade-in">
<form id="forgotten" class="forgotten-form" method="post" novalidate="novalidate" {{action "submit" on="submit"}}>
<form id="forgotten" class="forgotten-form" method="post" novalidate="novalidate">
<div class="email-wrap">
{{input value=email class="email" type="email" placeholder="Email Address" name="email" autofocus="autofocus" autocapitalize="off" autocorrect="off"}}
</div>
<button class="button-save" type="submit">Send new password</button>
<button class="button-save" type="submit" {{action "submit"}} {{bind-attr disabled=submitting}}>Send new password</button>
</form>
</section>

View File

@ -6,7 +6,7 @@
<div class="password-wrap">
{{input class="password" type="password" placeholder="Password" name="password" value=password}}
</div>
<button class="button-save" type="submit" {{action "login"}}>Log in</button>
<button class="button-save" type="submit" {{action "login"}} {{bind-attr disabled=submitting}}>Log in</button>
<section class="meta">
{{#link-to 'forgotten' class="forgotten-password"}}Forgotten password?{{/link-to}}
</section>

View File

@ -9,6 +9,6 @@
<div class="password-wrap">
{{input class="password" type="password" placeholder="Password" name="password" value=password }}
</div>
<button class="button-save" type="submit" {{action "signup"}}>Sign Up</button>
<button class="button-save" type="submit" {{action "signup"}} {{bind-attr disabled=submitting}}>Sign Up</button>
</form>
</section>

View File

@ -48,7 +48,7 @@ var Notifications = Ember.ArrayProxy.extend({
});
},
closeAll: function () {
window.alert('@TODO implement closeALl notifications');
this.clear();
}
});

View File

@ -0,0 +1,14 @@
var ForgotValidator = Ember.Object.create({
validate: function (model) {
var data = model.getProperties('email'),
validationErrors = [];
if (!validator.isEmail(data.email)) {
validationErrors.push('Invalid Email');
}
return validationErrors;
}
});
export default ForgotValidator;

View File

@ -0,0 +1,18 @@
var SigninValidator = Ember.Object.create({
validate: function (model) {
var data = model.getProperties('email', 'password'),
validationErrors = [];
if (!validator.isEmail(data.email)) {
validationErrors.push('Invalid Email');
}
if (!validator.isLength(data.password || '', 1)) {
validationErrors.push('Please enter a password');
}
return validationErrors;
}
});
export default SigninValidator;

View File

@ -0,0 +1,28 @@
var SignupValidator = Ember.Object.create({
validate: function (model) {
var data = model.getProperties('name', 'email', 'password'),
validationErrors = [];
if (!validator.isLength(data.name || '', 1)) {
validationErrors.push({
message: 'Please enter a name.'
});
}
if (!validator.isEmail(data.email)) {
validationErrors.push({
message: 'Invalid Email.'
});
}
if (!validator.isLength(data.password || '', 1)) {
validationErrors.push({
message: 'Please enter a password.'
});
}
return validationErrors;
}
});
export default SignupValidator;

View File

@ -81,7 +81,7 @@ CasperTest.emberBegin("Can't spam it", 4, function suite(test) {
casper.captureScreenshot('login_spam_test.png');
casper.wait(200, function doneWait() {
casper.waitForText('attempts remaining!', function then() {
this.fillAndSave("#login", falseUser);
});