mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-24 19:33:02 +03:00
Added client side validation
Closes #581. * Basically adds the client side of node validator, that we're already using * Validator is plonked onto `Ghost.Validator` * Usage is identical as to https://github.com/chriso/node-validator * Has sanitizing values et al * `Ghost.Validator.error` is redefined, it populates Ghost.Validator._errors (Array) * `Ghost.Validator.handleErrors` is supposed to print out the multiple error messages, if there are multiple (this is broken due to how notifications are presented `.html` instead of `.append`), and also apply class to element * The ajax calls are wrapped in an if to prevent network traffic if something's not right on client side * Added validation to general settings and user settings screens. * On validation error, optionally adds `.input-error` to whatever element you reference, see below (if `el` exists on the error object). This is the only place where usage is different to the original implementation. Redeclared `error()` function in `init.js` * Usage: `Ghost.Validate.check(valueToCheck, {message: "the error message", el: $('#the element')}).isEmail()` * The element above will receive the `.input-error` class. `isEmail()` is one of the stuff you can check against.
This commit is contained in:
parent
d00392973f
commit
6c99b67ab3
1010
core/client/assets/vendor/validator-client.js
vendored
Normal file
1010
core/client/assets/vendor/validator-client.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
/*globals window, $, _, Backbone */
|
||||
/*globals window, $, _, Backbone, Validator */
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
Views : {},
|
||||
Collections : {},
|
||||
Models : {},
|
||||
Validate : new Validator(),
|
||||
|
||||
settings: {
|
||||
apiRoot: '/api/v0.1'
|
||||
@ -36,6 +37,25 @@
|
||||
});
|
||||
};
|
||||
|
||||
Ghost.Validate.error = function (object) {
|
||||
this._errors.push(object);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Ghost.Validate.handleErrors = function () {
|
||||
_.each(Ghost.Validate._errors, function (errorObj) {
|
||||
Ghost.notifications.addItem({
|
||||
type: 'error',
|
||||
message: errorObj.message,
|
||||
status: 'passive'
|
||||
});
|
||||
if (errorObj.hasOwnProperty('el')) {
|
||||
errorObj.el.addClass('input-error');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
window.Ghost = Ghost;
|
||||
|
||||
}());
|
||||
}());
|
||||
|
@ -69,7 +69,7 @@
|
||||
<input type="password" id="user-new-password-verification">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button class="button-delete">Change Password</button>
|
||||
<button class="button-delete button-change-password">Change Password</button>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
|
@ -23,25 +23,33 @@
|
||||
password = this.$el.find('.password').val(),
|
||||
redirect = Ghost.Views.Utils.getUrlVariables().r;
|
||||
|
||||
$.ajax({
|
||||
url: '/ghost/signin/',
|
||||
type: 'POST',
|
||||
data: {
|
||||
email: email,
|
||||
password: password,
|
||||
redirect: redirect
|
||||
},
|
||||
success: function (msg) {
|
||||
window.location.href = msg.redirect;
|
||||
},
|
||||
error: function (xhr) {
|
||||
Ghost.notifications.addItem({
|
||||
type: 'error',
|
||||
message: Ghost.Views.Utils.getRequestErrorMessage(xhr),
|
||||
status: 'passive'
|
||||
});
|
||||
}
|
||||
});
|
||||
Ghost.Validate._errors = [];
|
||||
Ghost.Validate.check(email).isEmail();
|
||||
Ghost.Validate.check(password, "Password too short").len(5);
|
||||
|
||||
if (Ghost.Validate._errors.length > 0) {
|
||||
Ghost.Validate.handleErrors();
|
||||
} else {
|
||||
$.ajax({
|
||||
url: '/ghost/signin/',
|
||||
type: 'POST',
|
||||
data: {
|
||||
email: email,
|
||||
password: password,
|
||||
redirect: redirect
|
||||
},
|
||||
success: function (msg) {
|
||||
window.location.href = msg.redirect;
|
||||
},
|
||||
error: function (xhr) {
|
||||
Ghost.notifications.addItem({
|
||||
type: 'error',
|
||||
message: Ghost.Views.Utils.getRequestErrorMessage(xhr),
|
||||
status: 'passive'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -66,24 +74,15 @@
|
||||
email = this.$el.find('.email').val(),
|
||||
password = this.$el.find('.password').val();
|
||||
|
||||
if (!name) {
|
||||
Ghost.notifications.addItem({
|
||||
type: 'error',
|
||||
message: "Please enter a name",
|
||||
status: 'passive'
|
||||
});
|
||||
} else if (!email) {
|
||||
Ghost.notifications.addItem({
|
||||
type: 'error',
|
||||
message: "Please enter an email",
|
||||
status: 'passive'
|
||||
});
|
||||
} else if (!password) {
|
||||
Ghost.notifications.addItem({
|
||||
type: 'error',
|
||||
message: "Please enter a password",
|
||||
status: 'passive'
|
||||
});
|
||||
// This is needed due to how error handling is done. If this is not here, there will not be a time
|
||||
// when there is no error.
|
||||
Ghost.Validate._errors = [];
|
||||
Ghost.Validate.check(name, "Please enter a name").len(1);
|
||||
Ghost.Validate.check(email, "Please enter a correct email address").isEmail();
|
||||
Ghost.Validate.check(password, "Please enter a password").len(5);
|
||||
|
||||
if (Ghost.Validate._errors.length > 0) {
|
||||
Ghost.Validate.handleErrors();
|
||||
} else {
|
||||
$.ajax({
|
||||
url: '/ghost/signup/',
|
||||
@ -128,24 +127,31 @@
|
||||
|
||||
var email = this.$el.find('.email').val();
|
||||
|
||||
$.ajax({
|
||||
url: '/ghost/forgotten/',
|
||||
type: 'POST',
|
||||
data: {
|
||||
email: email
|
||||
},
|
||||
success: function (msg) {
|
||||
Ghost.Validate._errors = [];
|
||||
Ghost.Validate.check(email).isEmail();
|
||||
|
||||
window.location.href = msg.redirect;
|
||||
},
|
||||
error: function (xhr) {
|
||||
Ghost.notifications.addItem({
|
||||
type: 'error',
|
||||
message: Ghost.Views.Utils.getRequestErrorMessage(xhr),
|
||||
status: 'passive'
|
||||
});
|
||||
}
|
||||
});
|
||||
if (Ghost.Validate._errors.length > 0) {
|
||||
Ghost.Validate.handleErrors();
|
||||
} else {
|
||||
$.ajax({
|
||||
url: '/ghost/forgotten/',
|
||||
type: 'POST',
|
||||
data: {
|
||||
email: email
|
||||
},
|
||||
success: function (msg) {
|
||||
|
||||
window.location.href = msg.redirect;
|
||||
},
|
||||
error: function (xhr) {
|
||||
Ghost.notifications.addItem({
|
||||
type: 'error',
|
||||
message: Ghost.Views.Utils.getRequestErrorMessage(xhr),
|
||||
status: 'passive'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}());
|
||||
|
@ -157,21 +157,45 @@
|
||||
},
|
||||
|
||||
saveSettings: function () {
|
||||
var themes = this.model.get('availableThemes');
|
||||
this.model.unset('availableThemes');
|
||||
this.model.save({
|
||||
title: this.$('#blog-title').val(),
|
||||
description: $('#blog-description').val(),
|
||||
logo: this.$('#blog-logo').attr("src"),
|
||||
cover: this.$('#blog-cover').attr("src"),
|
||||
email: this.$('#email-address').val(),
|
||||
postsPerPage: this.$('#postsPerPage').val(),
|
||||
activeTheme: this.$('#activeTheme').val()
|
||||
}, {
|
||||
success: this.saveSuccess,
|
||||
error: this.saveError
|
||||
});
|
||||
this.model.set({availableThemes: themes});
|
||||
var themes = this.model.get('availableThemes'),
|
||||
title = this.$('#blog-title').val(),
|
||||
description = this.$('#blog-description').val(),
|
||||
email = this.$('#email-address').val(),
|
||||
postsPerPage = this.$('#postsPerPage').val();
|
||||
|
||||
Ghost.Validate._errors = [];
|
||||
Ghost.Validate
|
||||
.check(title, {message: "Title is too long", el: $('#blog-title')})
|
||||
.len(0, 150);
|
||||
Ghost.Validate
|
||||
.check(description, {message: "Description is too long", el: $('#blog-description')})
|
||||
.len(0, 200);
|
||||
Ghost.Validate
|
||||
.check(email, {message: "Please supply a valid email address", el: $('#email-address')})
|
||||
.isEmail().len(0, 254);
|
||||
Ghost.Validate
|
||||
.check(postsPerPage, {message: "Please use a number", el: $('postsPerPage')})
|
||||
.isInt();
|
||||
|
||||
if (Ghost.Validate._errors.length > 0) {
|
||||
Ghost.Validate.handleErrors();
|
||||
} else {
|
||||
|
||||
this.model.unset('availableThemes');
|
||||
this.model.save({
|
||||
title: title,
|
||||
description: description,
|
||||
logo: this.$('#blog-logo').attr("src"),
|
||||
cover: this.$('#blog-cover').attr("src"),
|
||||
email: email,
|
||||
postsPerPage: postsPerPage,
|
||||
activeTheme: this.$('#activeTheme').val()
|
||||
}, {
|
||||
success: this.saveSuccess,
|
||||
error: this.saveError
|
||||
});
|
||||
this.model.set({availableThemes: themes});
|
||||
}
|
||||
},
|
||||
showLogo: function () {
|
||||
var settings = this.model.toJSON();
|
||||
@ -259,63 +283,92 @@
|
||||
|
||||
|
||||
saveUser: function () {
|
||||
this.model.save({
|
||||
'full_name': this.$('#user-name').val(),
|
||||
'email_address': this.$('#user-email').val(),
|
||||
'location': this.$('#user-location').val(),
|
||||
'url': this.$('#user-website').val(),
|
||||
'bio': this.$('#user-bio').val(),
|
||||
'profile_picture': this.$('#user-profile-picture').attr('src'),
|
||||
'cover_picture': this.$('#user-cover-picture').attr('src')
|
||||
}, {
|
||||
success: this.saveSuccess,
|
||||
error: this.saveError
|
||||
});
|
||||
var userName = this.$('#user-name').val(),
|
||||
userEmail = this.$('#user-email').val(),
|
||||
userLocation = this.$('#user-location').val(),
|
||||
userWebsite = this.$('#user-website').val(),
|
||||
userBio = this.$('#user-bio').val();
|
||||
|
||||
Ghost.Validate._errors = [];
|
||||
Ghost.Validate
|
||||
.check(userName, {message: "Name is too long", el: $('#user-name')})
|
||||
.len(0, 150);
|
||||
Ghost.Validate
|
||||
.check(userBio, {message: "Bio is too long", el: $('#user-bio')})
|
||||
.len(0, 200);
|
||||
Ghost.Validate
|
||||
.check(userEmail, {message: "Please supply a valid email address", el: $('#user-email')})
|
||||
.isEmail();
|
||||
Ghost.Validate
|
||||
.check(userLocation, {message: "Location is too long", el: $('#user-location')})
|
||||
.len(0, 150);
|
||||
if (userWebsite.length > 0) {
|
||||
Ghost.Validate
|
||||
.check(userWebsite, {message: "Please use a valid url", el: $('#user-website')})
|
||||
.isUrl()
|
||||
.len(0, 2000);
|
||||
}
|
||||
|
||||
if (Ghost.Validate._errors.length > 0) {
|
||||
Ghost.Validate.handleErrors();
|
||||
} else {
|
||||
|
||||
this.model.save({
|
||||
'full_name': userName,
|
||||
'email_address': userEmail,
|
||||
'location': userLocation,
|
||||
'url': userWebsite,
|
||||
'bio': userBio,
|
||||
'profile_picture': this.$('#user-profile-picture').attr('src'),
|
||||
'cover_picture': this.$('#user-cover-picture').attr('src')
|
||||
}, {
|
||||
success: this.saveSuccess,
|
||||
error: this.saveError
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
changePassword: function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
var self = this,
|
||||
oldPassword = this.$('#user-password-old').val(),
|
||||
newPassword = this.$('#user-password-new').val(),
|
||||
ne2Password = this.$('#user-new-password-verification').val();
|
||||
|
||||
if (newPassword !== ne2Password) {
|
||||
this.validationError('Your new passwords do not match');
|
||||
return;
|
||||
}
|
||||
Ghost.Validate._errors = [];
|
||||
Ghost.Validate.check(newPassword, {message: 'Your new passwords do not match'}).equals(ne2Password);
|
||||
Ghost.Validate.check(newPassword, {message: 'Your password is not long enough. It must be at least 8 chars long.'}).len(8);
|
||||
|
||||
if (newPassword.length < 8) {
|
||||
this.validationError('Your password is not long enough. It must be at least 8 chars long.');
|
||||
return;
|
||||
}
|
||||
if (Ghost.Validate._errors.length > 0) {
|
||||
Ghost.Validate.handleErrors();
|
||||
} else {
|
||||
|
||||
$.ajax({
|
||||
url: '/ghost/changepw/',
|
||||
type: 'POST',
|
||||
data: {
|
||||
password: oldPassword,
|
||||
newpassword: newPassword,
|
||||
ne2password: ne2Password
|
||||
},
|
||||
success: function (msg) {
|
||||
Ghost.notifications.addItem({
|
||||
type: 'success',
|
||||
message: msg.msg,
|
||||
status: 'passive',
|
||||
id: 'success-98'
|
||||
});
|
||||
self.$('#user-password-old, #user-password-new, #user-new-password-verification').val('');
|
||||
},
|
||||
error: function (xhr) {
|
||||
Ghost.notifications.addItem({
|
||||
type: 'error',
|
||||
message: Ghost.Views.Utils.getRequestErrorMessage(xhr),
|
||||
status: 'passive'
|
||||
});
|
||||
}
|
||||
});
|
||||
$.ajax({
|
||||
url: '/ghost/changepw/',
|
||||
type: 'POST',
|
||||
data: {
|
||||
password: oldPassword,
|
||||
newpassword: newPassword,
|
||||
ne2password: ne2Password
|
||||
},
|
||||
success: function (msg) {
|
||||
Ghost.notifications.addItem({
|
||||
type: 'success',
|
||||
message: msg.msg,
|
||||
status: 'passive',
|
||||
id: 'success-98'
|
||||
});
|
||||
self.$('#user-password-old, #user-password-new, #user-new-password-verification').val('');
|
||||
},
|
||||
error: function (xhr) {
|
||||
Ghost.notifications.addItem({
|
||||
type: 'error',
|
||||
message: Ghost.Views.Utils.getRequestErrorMessage(xhr),
|
||||
status: 'passive'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
templateName: 'settings/user-profile',
|
||||
|
@ -58,6 +58,7 @@
|
||||
<script src="/public/vendor/showdown/extensions/ghostdown.js"></script>
|
||||
<script src="/shared/vendor/showdown/extensions/github.js"></script>
|
||||
<script src="/public/vendor/shortcuts.js"></script>
|
||||
<script src="/public/vendor/validator-client.js"></script>
|
||||
<script src="/public/vendor/countable.js"></script>
|
||||
<script src="/public/vendor/to-title-case.js"></script>
|
||||
<script src="/public/vendor/packery.pkgd.min.js"></script>
|
||||
@ -83,8 +84,8 @@
|
||||
<script src="/public/models/uploadModal.js"></script>
|
||||
<!-- // require '/public/views/*' -->
|
||||
<script src="/public/views/base.js"></script>
|
||||
<script src="/public/models/uploadModal.js"></script>
|
||||
<script src="/public/views/post-settings.js"></script>
|
||||
<script src="/public/models/uploadModal.js"></script>
|
||||
<script src="/public/views/blog.js"></script>
|
||||
<script src="/public/views/editor.js"></script>
|
||||
<script src="/public/views/editor-tag-widget.js"></script>
|
||||
|
Loading…
Reference in New Issue
Block a user