mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-14 09:52:09 +03:00
d8da21520f
Ember.ObjectController (and Ember.ArrayController) will be deprecated in Ember 1.11 (and removed from core in Ember 2.0). The reasoning is detailed in the Ember 2.0 RFC. This PR does the following: * Updates templates/controllers/views to explicitly reference model properties (instead of relying on proxying behavior). * Clearly delineate where certain properties are being set or retrieved from (for example it was not clear exactly where `scratch` and `titleScratch` were stored). * Remove usage of `Ember.ObjectController`. * Add JSCS rule to prevent future PR's from adding regressions.
231 lines
8.3 KiB
JavaScript
231 lines
8.3 KiB
JavaScript
import SlugGenerator from 'ghost/models/slug-generator';
|
|
import isNumber from 'ghost/utils/isNumber';
|
|
import boundOneWay from 'ghost/utils/bound-one-way';
|
|
|
|
var SettingsUserController = Ember.Controller.extend({
|
|
|
|
user: Ember.computed.alias('model'),
|
|
|
|
email: Ember.computed.readOnly('model.email'),
|
|
|
|
slugValue: boundOneWay('model.slug'),
|
|
|
|
lastPromise: null,
|
|
|
|
coverDefault: Ember.computed('ghostPaths', function () {
|
|
return this.get('ghostPaths.url').asset('/shared/img/user-cover.png');
|
|
}),
|
|
|
|
userDefault: Ember.computed('ghostPaths', function () {
|
|
return this.get('ghostPaths.url').asset('/shared/img/user-image.png');
|
|
}),
|
|
|
|
cover: Ember.computed('user.cover', 'coverDefault', function () {
|
|
var cover = this.get('user.cover');
|
|
|
|
if (Ember.isBlank(cover)) {
|
|
cover = this.get('coverDefault');
|
|
}
|
|
|
|
return 'background-image: url(' + cover + ')';
|
|
}),
|
|
|
|
coverTitle: Ember.computed('user.name', function () {
|
|
return this.get('user.name') + '\'s Cover Image';
|
|
}),
|
|
|
|
image: Ember.computed('imageUrl', function () {
|
|
return 'background-image: url(' + this.get('imageUrl') + ')';
|
|
}),
|
|
|
|
imageUrl: Ember.computed('user.image', function () {
|
|
return this.get('user.image') || this.get('userDefault');
|
|
}),
|
|
|
|
last_login: Ember.computed('user.last_login', function () {
|
|
var lastLogin = this.get('user.last_login');
|
|
|
|
return lastLogin ? lastLogin.fromNow() : '(Never)';
|
|
}),
|
|
|
|
created_at: Ember.computed('user.created_at', function () {
|
|
var createdAt = this.get('user.created_at');
|
|
|
|
return createdAt ? createdAt.fromNow() : '';
|
|
}),
|
|
|
|
// Lazy load the slug generator for slugPlaceholder
|
|
slugGenerator: Ember.computed(function () {
|
|
return SlugGenerator.create({
|
|
ghostPaths: this.get('ghostPaths'),
|
|
slugType: 'user'
|
|
});
|
|
}),
|
|
|
|
actions: {
|
|
changeRole: function (newRole) {
|
|
this.set('model.role', newRole);
|
|
},
|
|
|
|
revoke: function () {
|
|
var self = this,
|
|
model = this.get('model'),
|
|
email = this.get('email');
|
|
|
|
// reload the model to get the most up-to-date user information
|
|
model.reload().then(function () {
|
|
if (model.get('invited')) {
|
|
model.destroyRecord().then(function () {
|
|
var notificationText = 'Invitation revoked. (' + email + ')';
|
|
self.notifications.showSuccess(notificationText, false);
|
|
}).catch(function (error) {
|
|
self.notifications.showAPIError(error);
|
|
});
|
|
} else {
|
|
// if the user is no longer marked as "invited", then show a warning and reload the route
|
|
self.get('target').send('reload');
|
|
self.notifications.showError('This user has already accepted the invitation.', {delayed: 500});
|
|
}
|
|
});
|
|
},
|
|
|
|
resend: function () {
|
|
var self = this;
|
|
|
|
this.get('model').resendInvite().then(function (result) {
|
|
var notificationText = 'Invitation resent! (' + self.get('email') + ')';
|
|
// If sending the invitation email fails, the API will still return a status of 201
|
|
// but the user's status in the response object will be 'invited-pending'.
|
|
if (result.users[0].status === 'invited-pending') {
|
|
self.notifications.showWarn('Invitation email was not sent. Please try resending.');
|
|
} else {
|
|
self.get('model').set('status', result.users[0].status);
|
|
self.notifications.showSuccess(notificationText);
|
|
}
|
|
}).catch(function (error) {
|
|
self.notifications.showAPIError(error);
|
|
});
|
|
},
|
|
|
|
save: function () {
|
|
var user = this.get('user'),
|
|
slugValue = this.get('slugValue'),
|
|
afterUpdateSlug = this.get('lastPromise'),
|
|
promise,
|
|
slugChanged,
|
|
self = this;
|
|
|
|
if (user.get('slug') !== slugValue) {
|
|
slugChanged = true;
|
|
user.set('slug', slugValue);
|
|
}
|
|
|
|
promise = Ember.RSVP.resolve(afterUpdateSlug).then(function () {
|
|
return user.save({format: false});
|
|
}).then(function (model) {
|
|
var currentPath,
|
|
newPath;
|
|
|
|
self.notifications.showSuccess('Settings successfully saved.');
|
|
|
|
// If the user's slug has changed, change the URL and replace
|
|
// the history so refresh and back button still work
|
|
if (slugChanged) {
|
|
currentPath = window.history.state.path;
|
|
|
|
newPath = currentPath.split('/');
|
|
newPath[newPath.length - 2] = model.get('slug');
|
|
newPath = newPath.join('/');
|
|
|
|
window.history.replaceState({path: newPath}, '', newPath);
|
|
}
|
|
|
|
return model;
|
|
}).catch(function (errors) {
|
|
self.notifications.showErrors(errors);
|
|
});
|
|
|
|
this.set('lastPromise', promise);
|
|
},
|
|
|
|
password: function () {
|
|
var user = this.get('user'),
|
|
self = this;
|
|
|
|
if (user.get('isPasswordValid')) {
|
|
user.saveNewPassword().then(function (model) {
|
|
// Clear properties from view
|
|
user.setProperties({
|
|
password: '',
|
|
newPassword: '',
|
|
ne2Password: ''
|
|
});
|
|
|
|
self.notifications.showSuccess('Password updated.');
|
|
|
|
return model;
|
|
}).catch(function (errors) {
|
|
self.notifications.showAPIError(errors);
|
|
});
|
|
} else {
|
|
self.notifications.showErrors(user.get('passwordValidationErrors'));
|
|
}
|
|
},
|
|
|
|
updateSlug: function (newSlug) {
|
|
var self = this,
|
|
afterSave = this.get('lastPromise'),
|
|
promise;
|
|
|
|
promise = Ember.RSVP.resolve(afterSave).then(function () {
|
|
var slug = self.get('model.slug');
|
|
|
|
newSlug = newSlug || slug;
|
|
|
|
newSlug = newSlug.trim();
|
|
|
|
// Ignore unchanged slugs or candidate slugs that are empty
|
|
if (!newSlug || slug === newSlug) {
|
|
self.set('slugValue', slug);
|
|
|
|
return;
|
|
}
|
|
|
|
return self.get('slugGenerator').generateSlug(newSlug).then(function (serverSlug) {
|
|
// If after getting the sanitized and unique slug back from the API
|
|
// we end up with a slug that matches the existing slug, abort the change
|
|
if (serverSlug === slug) {
|
|
return;
|
|
}
|
|
|
|
// Because the server transforms the candidate slug by stripping
|
|
// certain characters and appending a number onto the end of slugs
|
|
// to enforce uniqueness, there are cases where we can get back a
|
|
// candidate slug that is a duplicate of the original except for
|
|
// the trailing incrementor (e.g., this-is-a-slug and this-is-a-slug-2)
|
|
|
|
// get the last token out of the slug candidate and see if it's a number
|
|
var slugTokens = serverSlug.split('-'),
|
|
check = Number(slugTokens.pop());
|
|
|
|
// if the candidate slug is the same as the existing slug except
|
|
// for the incrementor then the existing slug should be used
|
|
if (isNumber(check) && check > 0) {
|
|
if (slug === slugTokens.join('-') && serverSlug !== newSlug) {
|
|
self.set('slugValue', slug);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
self.set('slugValue', serverSlug);
|
|
});
|
|
});
|
|
|
|
this.set('lastPromise', promise);
|
|
}
|
|
}
|
|
});
|
|
|
|
export default SettingsUserController;
|