mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-24 06:35:49 +03:00
Create SettingsUserController
addresses #2422 - creates settings user controller - creates user model object - updates user fixture to be compatible with user model - updates settings/user template - add validator to Ember Admin - use validator to validate user model is valid - add mock response to /users/me/ path - creates models/base file for all models to inherit from - add mock response to /ghost/changepw/ path
This commit is contained in:
parent
79a333b480
commit
81eb705a37
12
Gruntfile.js
12
Gruntfile.js
@ -170,7 +170,9 @@ var path = require('path'),
|
||||
"Ember": true,
|
||||
"Em": true,
|
||||
"DS": true,
|
||||
"$": true
|
||||
"$": true,
|
||||
"validator": true,
|
||||
"ic": true
|
||||
},
|
||||
// node environment
|
||||
node: false,
|
||||
@ -577,17 +579,17 @@ var path = require('path'),
|
||||
'bower_components/ember/ember.js',
|
||||
'bower_components/ember-resolver/dist/ember-resolver.js',
|
||||
'bower_components/ic-ajax/dist/globals/main.js',
|
||||
|
||||
'bower_components/validator-js/validator.js',
|
||||
'bower_components/codemirror/lib/codemirror.js',
|
||||
'bower_components/codemirror/addon/mode/overlay.js',
|
||||
'bower_components/codemirror/mode/markdown/markdown.js',
|
||||
'bower_components/codemirror/mode/gfm/gfm.js',
|
||||
'bower_components/showdown/src/showdown.js',
|
||||
'bower_components/moment/moment.js',
|
||||
|
||||
'core/clientold/assets/lib/showdown/extensions/ghostdown.js',
|
||||
'core/shared/lib/showdown/extensions/typography.js',
|
||||
'core/shared/lib/showdown/extensions/github.js',
|
||||
|
||||
'bower_components/moment/moment.js'
|
||||
'core/shared/lib/showdown/extensions/github.js'
|
||||
]
|
||||
}
|
||||
},
|
||||
|
65
core/client/controllers/settings/user.js
Normal file
65
core/client/controllers/settings/user.js
Normal file
@ -0,0 +1,65 @@
|
||||
/*global alert */
|
||||
|
||||
var SettingsUserController = Ember.Controller.extend({
|
||||
cover: function () {
|
||||
// @TODO: add {{asset}} subdir path
|
||||
return this.user.getWithDefault('cover', '/shared/img/user-cover.png');
|
||||
}.property('user.cover'),
|
||||
|
||||
coverTitle: function () {
|
||||
return this.get('user.name') + '\'s Cover Image';
|
||||
}.property('user.name'),
|
||||
|
||||
image: function () {
|
||||
// @TODO: add {{asset}} subdir path
|
||||
return 'background-image: url(' + this.user.getWithDefault('image', '/shared/img/user-image.png') + ')';
|
||||
}.property('user.image'),
|
||||
|
||||
actions: {
|
||||
cover: function () {
|
||||
alert('@TODO: Show Upload modal for cover');
|
||||
},
|
||||
|
||||
image: function () {
|
||||
alert('@TODO: Show Upload modal for image');
|
||||
},
|
||||
|
||||
save: function () {
|
||||
alert('@TODO: Saving user...');
|
||||
|
||||
if (this.user.validate().get('isValid')) {
|
||||
this.user.save().then(function (response) {
|
||||
alert('Done saving' + JSON.stringify(response));
|
||||
}, function () {
|
||||
alert('Error saving.');
|
||||
});
|
||||
} else {
|
||||
alert('Errors found! ' + JSON.stringify(this.user.get('errors')));
|
||||
}
|
||||
},
|
||||
|
||||
password: function () {
|
||||
alert('@TODO: Changing password...');
|
||||
var passwordProperties = this.getProperties('password', 'newpassword', 'ne2password');
|
||||
|
||||
if (this.user.validatePassword(passwordProperties).get('passwordIsValid')) {
|
||||
this.user.saveNewPassword(passwordProperties).then(function () {
|
||||
alert('Success!');
|
||||
// Clear properties from view
|
||||
this.setProperties({
|
||||
'password': '',
|
||||
'newpassword': '',
|
||||
'ne2password': ''
|
||||
});
|
||||
}.bind(this), function (errors) {
|
||||
alert('Errors ' + JSON.stringify(errors));
|
||||
});
|
||||
} else {
|
||||
alert('Errors found! ' + JSON.stringify(this.user.get('passwordErrors')));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
export default SettingsUserController;
|
@ -1,4 +1,3 @@
|
||||
/*global ic */
|
||||
import postFixtures from 'ghost/fixtures/posts';
|
||||
import userFixtures from 'ghost/fixtures/users';
|
||||
|
||||
@ -36,6 +35,10 @@ var defineFixtures = function (status) {
|
||||
ic.ajax.defineFixture('/ghost/api/v0.1/posts/1', post(1, status));
|
||||
ic.ajax.defineFixture('/ghost/api/v0.1/posts/2', post(2, status));
|
||||
ic.ajax.defineFixture('/ghost/api/v0.1/signin', user(status));
|
||||
ic.ajax.defineFixture('/ghost/api/v0.1/users/me/', user(status));
|
||||
ic.ajax.defineFixture('/ghost/changepw/', response({
|
||||
msg: 'Password changed successfully'
|
||||
}));
|
||||
};
|
||||
|
||||
export default defineFixtures;
|
@ -5,16 +5,16 @@ var users = [
|
||||
"name": "some-user",
|
||||
"slug": "some-user",
|
||||
"email": "some@email.com",
|
||||
"image": null,
|
||||
"cover": null,
|
||||
"bio": "",
|
||||
"image": undefined,
|
||||
"cover": undefined,
|
||||
"bio": "Example bio",
|
||||
"website": "",
|
||||
"location": "",
|
||||
"accessibility": null,
|
||||
"location": "Imaginationland",
|
||||
"accessibility": undefined,
|
||||
"status": "active",
|
||||
"language": "en_US",
|
||||
"meta_title": null,
|
||||
"meta_description": null,
|
||||
"meta_title": undefined,
|
||||
"meta_description": undefined,
|
||||
"created_at": "2014-02-15T20:02:25.000Z",
|
||||
"updated_at": "2014-03-11T14:06:43.000Z"
|
||||
}
|
||||
|
@ -1,14 +1,11 @@
|
||||
import User from 'ghost/models/user';
|
||||
import userFixtures from 'ghost/fixtures/users';
|
||||
|
||||
var currentUser = {
|
||||
name: 'currentUser',
|
||||
|
||||
initialize: function (container) {
|
||||
var userFixture = userFixtures.findBy("id", 1);
|
||||
|
||||
container.register('user:current', Ember.Object.extend(userFixture));
|
||||
// Todo: remove userFixture
|
||||
// Todo: use model User instead of Ember.Object once model layer exists
|
||||
container.register('user:current', User);
|
||||
}
|
||||
};
|
||||
|
||||
@ -17,6 +14,9 @@ var injectCurrentUser = {
|
||||
|
||||
initialize: function (container) {
|
||||
if (container.lookup('user:current')) {
|
||||
// @TODO: remove userFixture
|
||||
container.lookup('user:current').setProperties(userFixtures.findBy('id', 1));
|
||||
|
||||
container.injection('route', 'user', 'user:current');
|
||||
container.injection('controller', 'user', 'user:current');
|
||||
}
|
||||
|
18
core/client/models/base.js
Normal file
18
core/client/models/base.js
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
function ghostPaths() {
|
||||
var path = window.location.pathname,
|
||||
subdir = path.substr(0, path.search('/ghost/'));
|
||||
|
||||
return {
|
||||
subdir: subdir,
|
||||
apiRoot: subdir + '/ghost/api/v0.1'
|
||||
};
|
||||
}
|
||||
|
||||
var BaseModel = Ember.Object.extend({
|
||||
});
|
||||
|
||||
BaseModel.apiRoot = ghostPaths().apiRoot;
|
||||
BaseModel.subdir = ghostPaths().subdir;
|
||||
|
||||
export default BaseModel;
|
80
core/client/models/user.js
Normal file
80
core/client/models/user.js
Normal file
@ -0,0 +1,80 @@
|
||||
import BaseModel from 'ghost/models/base';
|
||||
|
||||
var UserModel = BaseModel.extend({
|
||||
url: BaseModel.apiRoot + '/users/me/',
|
||||
|
||||
save: function () {
|
||||
return ic.ajax.request(this.url, {
|
||||
type: 'POST',
|
||||
data: this.getProperties(Ember.keys(this))
|
||||
});
|
||||
},
|
||||
|
||||
validate: function () {
|
||||
var validationErrors = [];
|
||||
|
||||
if (!validator.isLength(this.get('name'), 0, 150)) {
|
||||
validationErrors.push({message: "Name is too long"});
|
||||
}
|
||||
|
||||
if (!validator.isLength(this.get('bio'), 0, 200)) {
|
||||
validationErrors.push({message: "Bio is too long"});
|
||||
}
|
||||
|
||||
if (!validator.isEmail(this.get('email'))) {
|
||||
validationErrors.push({message: "Please supply a valid email address"});
|
||||
}
|
||||
|
||||
if (!validator.isLength(this.get('location'), 0, 150)) {
|
||||
validationErrors.push({message: "Location is too long"});
|
||||
}
|
||||
|
||||
if (this.get('website').length) {
|
||||
if (!validator.isURL(this.get('website')) ||
|
||||
!validator.isLength(this.get('website'), 0, 2000)) {
|
||||
validationErrors.push({message: "Please use a valid url"});
|
||||
}
|
||||
}
|
||||
|
||||
if (validationErrors.length > 0) {
|
||||
this.set('isValid', false);
|
||||
} else {
|
||||
this.set('isValid', true);
|
||||
}
|
||||
|
||||
this.set('errors', validationErrors);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
saveNewPassword: function (password) {
|
||||
return ic.ajax.request(BaseModel.subdir + '/ghost/changepw/', {
|
||||
type: 'POST',
|
||||
data: password
|
||||
});
|
||||
},
|
||||
|
||||
validatePassword: function (password) {
|
||||
var validationErrors = [];
|
||||
|
||||
if (!validator.equals(password.newpassword, password.ne2password)) {
|
||||
validationErrors.push("Your new passwords do not match");
|
||||
}
|
||||
|
||||
if (!validator.isLength(password.newpassword, 8)) {
|
||||
validationErrors.push("Your password is not long enough. It must be at least 8 characters long.");
|
||||
}
|
||||
|
||||
if (validationErrors.length > 0) {
|
||||
this.set('passwordIsValid', false);
|
||||
} else {
|
||||
this.set('passwordIsValid', true);
|
||||
}
|
||||
|
||||
this.set('passwordErrors', validationErrors);
|
||||
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
export default UserModel;
|
@ -2,18 +2,16 @@
|
||||
<button class="button-back">Back</button>
|
||||
<h2 class="title">Your Profile</h2>
|
||||
<section class="page-actions">
|
||||
<button class="button-save">Save</button>
|
||||
<button class="button-save" {{action 'save'}}>Save</button>
|
||||
</section>
|
||||
</header>
|
||||
|
||||
<section class="content no-padding">
|
||||
|
||||
<header class="user-profile-header">
|
||||
{{!-- @TODO: once we have asset helper in place we can restore this, right now it errors
|
||||
<img id="user-cover" class="cover-image" src="{{#if cover}}{{cover}}{{else}}{{asset "shared/img/user-cover.png"}}{{/if}}" title="{{name}}'s Cover Image"/>
|
||||
--}}
|
||||
<img id="user-cover" class="cover-image" {{bind-attr src=cover title=coverTitle}} />
|
||||
|
||||
<a class="edit-cover-image js-modal-cover button" href="#">Change Cover</a>
|
||||
<a class="edit-cover-image js-modal-cover button" {{action 'cover'}}>Change Cover</a>
|
||||
</header>
|
||||
|
||||
<form class="user-profile" novalidate="novalidate">
|
||||
@ -21,15 +19,13 @@
|
||||
<fieldset class="user-details-top">
|
||||
|
||||
<figure class="user-image">
|
||||
{{!-- @TODO: once we have asset helper in place we can restore this, right now it errors
|
||||
<div id="user-image" class="img" style="background-image: url({{#if image}}{{image}}{{else}}{{asset "shared/img/user-image.png"}}{{/if}});" href="#"><span class="hidden">{{name}}'s Picture</span></div>
|
||||
--}}
|
||||
<a href="#" class="edit-user-image js-modal-image">Edit Picture</a>
|
||||
<div id="user-image" class="img" {{bind-attr style=image}} href="#"><span class="hidden">{{name}}'s Picture</span></div>
|
||||
<a {{action 'image'}} class="edit-user-image js-modal-image">Edit Picture</a>
|
||||
</figure>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="user-name" class="hidden">Full Name</label>
|
||||
<input type="url" value="{{name}}" id="user-name" placeholder="Full Name" autocorrect="off" />
|
||||
{{input value=user.name id="user-name" placeholder="Full Name" autocorrect="off"}}
|
||||
<p>Use your real name so people can recognise you</p>
|
||||
</div>
|
||||
|
||||
@ -39,28 +35,28 @@
|
||||
|
||||
<div class="form-group">
|
||||
<label for"user-email">Email</label>
|
||||
{{input type="email" value=email id="user-email" placeholder="Email Address" autocapitalize="off" autocorrect="off"}}
|
||||
{{input type="email" value=user.email id="user-email" placeholder="Email Address" autocapitalize="off" autocorrect="off"}}
|
||||
<p>Used for notifications</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="user-location">Location</label>
|
||||
{{input type="text" value=location id="user-location"}}
|
||||
{{input type="text" value=user.location id="user-location"}}
|
||||
<p>Where in the world do you live?</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="user-website">Website</label>
|
||||
{{input type="text" value=website id="user-website" autocapitalize="off" autocorrect="off"}}
|
||||
{{input type="text" value=user.website id="user-website" autocapitalize="off" autocorrect="off"}}
|
||||
<p>Have a website or blog other than this one? Link it!</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group bio-container">
|
||||
<label for="user-bio">Bio</label>
|
||||
{{textarea id="user-bio" value=bio}}
|
||||
{{textarea id="user-bio" value=user.bio}}
|
||||
<p>
|
||||
Write about you, in 200 characters or less.
|
||||
<span class="word-count">0</span>
|
||||
<span class="word-count">{{count-words user.bio}}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@ -72,20 +68,20 @@
|
||||
|
||||
<div class="form-group">
|
||||
<label for="user-password-old">Old Password</label>
|
||||
{{input type="password" id="user-password-old"}}
|
||||
{{input value=password type="password" id="user-password-old"}}
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="user-password-new">New Password</label>
|
||||
{{input type="password" id="user-password-new"}}
|
||||
{{input value=newpassword type="password" id="user-password-new"}}
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="user-new-password-verification">Verify Password</label>
|
||||
{{input type="password" id="user-new-password-verification"}}
|
||||
{{input value=ne2password type="password" id="user-new-password-verification"}}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="button" class="button-delete button-change-password">Change Password</button>
|
||||
<button type="button" class="button-delete button-change-password" {{action 'password'}}>Change Password</button>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
|
Loading…
Reference in New Issue
Block a user