diff --git a/ghost/admin/controllers/modals/transfer-owner.js b/ghost/admin/controllers/modals/transfer-owner.js index b341c62b71..c4d1cbf272 100644 --- a/ghost/admin/controllers/modals/transfer-owner.js +++ b/ghost/admin/controllers/modals/transfer-owner.js @@ -1,10 +1,11 @@ var TransferOwnerController = Ember.Controller.extend({ - actions: { confirmAccept: function () { var user = this.get('model'), self = this; + self.get('popover').closePopovers(); + // Get owner role this.store.find('role').then(function (result) { return result.findBy('name', 'Owner'); @@ -12,16 +13,16 @@ var TransferOwnerController = Ember.Controller.extend({ // remove roles and assign owner role user.get('roles').clear(); user.get('roles').pushObject(ownerRole); - return user.save({ format: false }); - }).then(function (model) { + + return user.saveOnly('roles'); + }).then(function () { self.notifications.closePassive(); - self.notifications.showSuccess('Settings successfully saved.'); - return model; + self.notifications.showSuccess('Ownership successfully transferred to ' + user.get('name')); }).catch(function (errors) { self.notifications.closePassive(); + + errors = Ember.isArray(errors) ? errors : Ember.A([errors]); self.notifications.showErrors(errors); - }).finally(function () { - self.get('popover').closePopovers(); }); }, diff --git a/ghost/admin/mixins/selective-save.js b/ghost/admin/mixins/selective-save.js new file mode 100644 index 0000000000..15a7678ca3 --- /dev/null +++ b/ghost/admin/mixins/selective-save.js @@ -0,0 +1,121 @@ +// SelectiveSaveMixin adds a saveOnly method to a DS.Model. +// +// saveOnly provides a way to save one or more properties of a model while +// preserving outstanding changes to other properties. +var SelectiveSaveMixin = Ember.Mixin.create({ + saveOnly: function () { + if (arguments.length === 0) { + return Ember.RSVP.resolve(); + } + + if (arguments.length === 1 && Ember.isArray(arguments[0])) { + return this.saveOnly.apply(this, Array.prototype.slice.call(arguments[0])); + } + + var propertiesToSave = Array.prototype.slice.call(arguments), + changed, + hasMany = {}, + belongsTo = {}, + self = this; + + changed = this.changedAttributes(); + + // disable observers so we can make changes to the model but not have + // them reflected by the UI + this.beginPropertyChanges(); + + // make a copy of any relations the model may have so they can + // be reapplied later + this.eachRelationship(function (name, meta) { + if (meta.kind === 'hasMany') { + hasMany[name] = self.get(name).slice(); + return; + } + + if (meta.kind === 'belongsTo') { + belongsTo[name] = self.get(name); + return; + } + }); + + try { + // roll back all changes to the model and then reapply only those that + // are part of the saveOnly + + self.rollback(); + + propertiesToSave.forEach(function (name) { + if (hasMany.hasOwnProperty(name)) { + self.get(name).clear(); + + hasMany[name].forEach(function (relatedType) { + self.get(name).pushObject(relatedType); + }); + + return; + } + + if (belongsTo.hasOwnProperty(name)) { + return self.updateBelongsTo(name, belongsTo[name]); + } + + if (changed.hasOwnProperty(name)) { + return self.set(name, changed[name][1]); + } + }); + } + catch (err) { + // if we were not able to get the model into the correct state + // put it back the way we found it and return a rejected promise + + Ember.keys(changed).forEach(function (name) { + self.set(name, changed[name][1]); + }); + + Ember.keys(hasMany).forEach(function (name) { + self.updateHasMany(name, hasMany[name]); + }); + + Ember.keys(belongsTo).forEach(function (name) { + self.updateBelongsTo(name, belongsTo[name]); + }); + + self.endPropertyChanges(); + + return Ember.RSVP.reject(new Error(err.message || 'Error during saveOnly. Changes NOT saved.')); + } + + return this.save().finally(function () { + // reapply any changes that were not part of the save + + Ember.keys(changed).forEach(function (name) { + if (propertiesToSave.hasOwnProperty(name)) { + return; + } + + self.set(name, changed[name][1]); + }); + + Ember.keys(hasMany).forEach(function (name) { + if (propertiesToSave.hasOwnProperty(name)) { + return; + } + + self.updateHasMany(name, hasMany[name]); + }); + + Ember.keys(belongsTo).forEach(function (name) { + if (propertiesToSave.hasOwnProperty(name)) { + return; + } + + self.updateBelongsTo(name, belongsTo[name]); + }); + + // signal that we're finished and normal model observation may continue + self.endPropertyChanges(); + }); + } +}); + +export default SelectiveSaveMixin; diff --git a/ghost/admin/models/user.js b/ghost/admin/models/user.js index c062426cd9..f9f0bc8ed7 100644 --- a/ghost/admin/models/user.js +++ b/ghost/admin/models/user.js @@ -1,7 +1,8 @@ import ValidationEngine from 'ghost/mixins/validation-engine'; import NProgressSaveMixin from 'ghost/mixins/nprogress-save'; +import SelectiveSaveMixin from 'ghost/mixins/selective-save'; -var User = DS.Model.extend(NProgressSaveMixin, ValidationEngine, { +var User = DS.Model.extend(NProgressSaveMixin, SelectiveSaveMixin, ValidationEngine, { validationType: 'user', uuid: DS.attr('string'),