/** * Module Dependencies. */ var loopback = require('../loopback'); var ModelBuilder = require('loopback-datasource-juggler').ModelBuilder; var modeler = new ModelBuilder(); /** * Define the built in loopback.Model. */ var Model = module.exports = modeler.define('Model'); Model.shared = true; /*! * Called when a model is extended. */ Model.setup = function () { var ModelCtor = this; // each model has its // own access control // list ModelCtor.acl = []; ModelCtor.sharedCtor = function (data, id, fn) { if(typeof data === 'function') { fn = data; data = null; id = null; } else if (typeof id === 'function') { fn = id; if(typeof data !== 'object') { id = data; data = null; } else { id = null; } } if(id && data) { var model = new ModelCtor(data); model.id = id; fn(null, model); } else if(data) { fn(null, new ModelCtor(data)); } else if(id) { ModelCtor.findById(id, function (err, model) { if(err) { fn(err); } else if(model) { fn(null, model); } else { err = new Error('could not find a model with id ' + id); err.statusCode = 404; fn(err); } }); } else { fn(new Error('must specify an id or data')); } } // before remote hook ModelCtor.beforeRemote = function (name, fn) { var self = this; if(this.app) { var remotes = this.app.remotes(); remotes.before(self.pluralModelName + '.' + name, function (ctx, next) { fn(ctx, ctx.result, next); }); } else { var args = arguments; this.once('attached', function () { self.beforeRemote.apply(self, args); }); } }; // after remote hook ModelCtor.afterRemote = function (name, fn) { var self = this; if(this.app) { var remotes = this.app.remotes(); remotes.after(self.pluralModelName + '.' + name, function (ctx, next) { fn(ctx, ctx.result, next); }); } else { var args = arguments; this.once('attached', function () { self.afterRemote.apply(self, args); }); } }; // Map the prototype method to /:id with data in the body ModelCtor.sharedCtor.accepts = [ {arg: 'id', type: 'any', http: {source: 'path'}} // {arg: 'instance', type: 'object', http: {source: 'body'}} ]; ModelCtor.sharedCtor.http = [ {path: '/:id'} ]; ModelCtor.sharedCtor.returns = {root: true}; return ModelCtor; }; /*! * Get the reference to ACL in a lazy fashion to avoid race condition in require */ var ACL = null; function getACL() { return ACL || (ACL = require('./acl').ACL); } /** * Check if the given access token can invoke the method * * @param {AccessToken} token The access token * @param {*} modelId The model id * @param {String} method The method name * @param callback The callback function * * @callback callback * @param {String|Error} err The error object * @param {Boolean} allowed is the request allowed */ Model.checkAccess = function(token, modelId, method, callback) { var ACL = getACL(); var methodName = 'string' === typeof method? method: method && method.name; ACL.checkAccessForToken(token, this.modelName, modelId, methodName, callback); }; // setup the initial model Model.setup();