openframe-apiserver
Version:
The Openframe API Server.
208 lines (189 loc) • 7.7 kB
JavaScript
var debug = require('debug')('openframe:model:Frame');
module.exports = function(Frame) {
Frame.disableRemoteMethodByName('createChangeStream');
// whenever a Frame model is saved, broadcast an update event
Frame.observe('after save', function(ctx, next) {
if (ctx.instance && Frame.app.pubsub) {
debug('Saved %s %s', ctx.Model.modelName, ctx.instance.id);
if (ctx.isNewInstance) {
debug('New Frame, publishing: /user/' + ctx.instance.ownerId + '/frame/new');
Frame.app.pubsub.publish('/user/' + ctx.instance.ownerId + '/frame/new', ctx.instance.id);
} else {
debug('Existing Frame, publishing: /frame/' + ctx.instance.id + '/db_updated');
// debug(ctx.instance);
Frame.findById(ctx.instance.id, { include: 'current_artwork' }, function(err, frame) {
debug(err, frame);
Frame.app.pubsub.publish('/frame/' + frame.id + '/db_updated', frame);
});
}
}
next();
});
// Ouch. Ow. Yowsers. Serisously?
function removeManagers(frame, managers) {
return new Promise((resolve, reject) => {
frame.managers(function(err, current_managers) {
debug(current_managers);
if (current_managers.length) {
var count = 0,
total = current_managers.length;
current_managers.forEach(function(cur_man) {
debug(cur_man);
if (managers.indexOf(cur_man.username) === -1) {
debug('removing %s', cur_man.username);
frame.managers.remove(cur_man, function(err) {
if (err) debug(err);
count++;
if (count === total) {
// all who are no longer present in the new list have been removed
resolve();
}
});
} else {
count++;
if (count === total) {
// all who are no longer present in the new list have been removed
resolve();
}
}
});
} else {
// there are no current managers
resolve();
}
});
});
}
// Painful painful painful -- so gross. Why loopback, why!?
function addManagers(frame, managers) {
var OpenframeUser = Frame.app.models.OpenframeUser;
return new Promise((resolve, reject) => {
OpenframeUser.find({ where: { username: { inq: managers }}}, function(err, users) {
if (err) {
debug(err);
}
var count = 0,
total = users.length;
if (total === 0) {
// no managers found by username, return frame including current managers
Frame.findById(frame.id, {include: 'managers'}, function(err, frame) {
debug(err, frame);
resolve(frame);
});
} else {
// managers found by username, add them to frame, then
// return frame including current managers
// XXX: Unfortunately loopback doesn't seem to provide a way to batch
// update hasAndBelongsToMany relationships :/
users.forEach(function(user) {
frame.managers.add(user, function(err) {
count++;
if (count === total) {
Frame.findById(frame.id, {include: 'managers'}, function(err, frame) {
debug(err, frame);
resolve(frame);
});
}
});
});
}
});
});
}
// Update managers by username
//
// XXX: This is incredibly ugly. Loopback doesn't provide a good way to update
// this type of relationship all in one go, which makes it a huge messy pain. Given
// time, I may fix this.
Frame.prototype.update_managers_by_username = function(managers, cb) {
debug(managers);
var self = this;
removeManagers(self, managers)
.then(function() {
addManagers(self, managers)
.then(function(frame) {
cb(null, frame);
})
.catch(debug);
}).catch(debug);
};
// Expose update_managers_by_username remote method
Frame.remoteMethod(
'prototype.update_managers_by_username', {
description: 'Add a related item by username for managers.',
accepts: {
arg: 'managers',
type: 'array',
http: {
source: 'body'
}
},
http: {
verb: 'put',
path: '/managers/by_username'
},
returns: {
arg: 'frame',
type: 'Object'
}
}
);
/**
* Update the current artwork by artwork ID
* @param {String} currentArtworkId
* @param {Function} callback
*/
Frame.prototype.update_current_artwork = function(currentArtworkId, cb) {
debug(currentArtworkId);
var self = this;
self.updateAttribute('currentArtworkId', currentArtworkId, function(err, instance) {
cb(err, instance);
});
};
Frame.remoteMethod(
'prototype.update_current_artwork', {
description: 'Set the current artwork for this frame',
accepts: {
arg: 'currentArtworkId',
type: 'any',
required: true,
http: {
source: 'path'
}
},
http: {
verb: 'put',
path: '/current_artwork/:currentArtworkId'
},
returns: {
arg: 'frame',
type: 'Object'
}
}
);
/**
* Override toJSON in order to remove inclusion of email address for users that are
* not the currently logged-in user.
*
* @return {Object} Plain JS Object which will be transformed to JSON for output.
*/
// Frame.prototype.toJSON = function() {
// // TODO: this seems awfully fragile... not very clear when context is available
// var ctx = loopback.getCurrentContext(),
// user = ctx.get('currentUser'),
// userId = user && user.id,
// obj = this.toObject(false, true, false);
// debug('FRAME toJSON', userId, obj);
// // Remove email from managers
// if (obj.managers && obj.managers.length) {
// obj.managers.forEach((manager) => {
// delete manager.email;
// });
// }
// // Remove email from owner unless it's the currently logged in user.
// if (obj.owner && userId !== obj.owner.id) {
// delete obj.owner.email;
// }
// return obj;
// };
};