mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-29 22:01:49 +03:00
0c984e0efd
Closes #3970
228 lines
8.2 KiB
JavaScript
228 lines
8.2 KiB
JavaScript
import SlugGenerator from 'ghost/models/slug-generator';
|
|
|
|
var SettingsUserController = Ember.ObjectController.extend({
|
|
|
|
user: Ember.computed.alias('model'),
|
|
|
|
email: Ember.computed.readOnly('user.email'),
|
|
|
|
slugValue: Ember.computed.oneWay('user.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 (self.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('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;
|