profile: function(req, res) { if (!req.user) return res.forbidden(); // Lookup for records that match the specified criteria var Model = actionUtil.parseModel(req), where = _.omit(actionUtil.parseCriteria(req), 'access_token'), query = Model.find() .where(where) .limit(actionUtil.parseLimit(req)) .skip(actionUtil.parseSkip(req)) .sort(actionUtil.parseSort(req)); query.exec(function found(err, matchingRecords) { if (err) return res.serverError(err); matchingRecords = _.reject(matchingRecords, 'disabled'); var ids = matchingRecords.map(function(m) { return m.id }), reqId = req.user[0].id; async.map(ids, function(userId, cb) { sails.services.utils.user['getUser'](userId, reqId, req.user, function (err, user) { if (err) return cb(err); if (userId !== reqId && !_.contains(where.username, user.username)) { delete user.username; } delete user.emails; delete user.auths; cb(null, user); }); }, function(err, results) { if (err) { return res.send(400, err); } res.ok(results); }); }); },
module.exports = (req, res) => { _.set(req.options, 'criteria.blacklist', ['fields', 'populate', 'limit', 'skip', 'page', 'sort']); const populate = req.param('populate') ? req.param('populate').replace(/ /g, '').split(',') : []; const Model = actionUtil.parseModel(req); if(req.param('fields')){ var fields = req.param('fields') != 'all' ? req.param('fields').replace(/ /g, '').split(',') : []; } else { var fields = Model.default_return || []; } const where = actionUtil.parseCriteria(req); const limit = actionUtil.parseLimit(req); const skip = (req.param('page')-1) * limit || actionUtil.parseSkip(req); const sort = actionUtil.parseSort(req); const query = Model.find(null, fields.length > 0 ? {select: fields} : null).where(where).limit(limit).skip(skip).sort(sort); const findQuery = _.reduce(_.intersection(populate, takeAlias(Model.associations)), populateAlias, query); //??? findQuery .then(records => [records, { root: { criteria: where, limit: limit, start: skip+1, end: skip + limit, page: Math.floor(skip / limit)+1 } }]) .spread(res.ok) .catch(res.negotiate); };
.then(record => { var model = (actionUtil.parseModel(req)).adapter.identity; LogService.log(req, record.id); LogService.winstonLog('info', model + ' created', { ip: req.ip, resource: record.id }); var associations = []; _.forEach(builder._model.definition, function(value, key) { if (value.foreignKey) { associations.push(key); } }); //populate the response builder._model.find(record.id).populate(associations).exec(function(err, record) { if (err) res.negotiate(err); res.created(record[0], { meta: builder.meta(record[0]), links: builder.links(record[0]) }); }); })
constructor(req, res, many) { this.req = req; this.res = res; // Don't forget to set 'many' in blueprints/find.js (eg, new Response.ResponseGET(req, res, true); this._many = many; this._model = _actionUtil.parseModel(this.req); this.result = {}; }
module.exports = function ModelPolicy (req, res, next) { var modelCache = sails.config._modelCache; req.options.modelIdentity = actionUtil.parseModel(req).identity; if(!modelCache || modelCache.length === 0){ sails.log.verbose('ModelPolicy: Model Cache is Empty'); } if (_.isEmpty(req.options.modelIdentity)) { sails.log.verbose('ModelPolicy: Model Identity is Empty'); return next(); } req.options.modelDefinition = sails.models[req.options.modelIdentity]; req.model = modelCache[req.options.modelIdentity]; if (_.isObject(req.model) && !_.isNull(req.model.id)) { if(_.isObject(req.model.permissions) && _.isObject(req.model.permissions.public)){ var method = PermissionService.getMethod(req.method); //console.log(req.model.permissions.public, method); if(_.isObject(req.model.permissions.public[method]) && req.model.permissions.public[method].action){ sails.log.verbose("Model modelUnlocked"); req.options.modelUnlocked = true; } } return next(); } else{ } sails.log.warn('Model [', req.options.modelIdentity, '] not found in model cache'); // if the model is not found in the cache for some reason, get it from the database sails.models[sails.config.permission.modelModelIdentity].findOne({ identity: req.options.modelIdentity }) .then(function (model) { if (!_.isObject(model)) { req.options.unknownModel = true; if (!sails.config.permissions.allowUnknownModelDefinition) { return next(new Error('Model definition not found: '+ req.options.modelIdentity)); } else { model = sails.models[req.options.modelIdentity]; } } req.model = model; next(); return null; }) .catch(next); };
module.exports = function (req, res) { actionUtil.parseModel(req) .destroy(actionUtil.requirePk(req)) .then(function (records) { if (!records[0]) return res.notFound(); return res.noContent(); }) .catch(res.serverError); };
module.exports = function getCount (req, res) { var Model = actionUtil.parseModel(req); var criteria = actionUtil.parseCriteria(req); Model.count(criteria, function(error, response) { if (error) { return res.serverError('database_error', error); } res.ok({count: response}); }); };
export function expand(req, res) { var Model = actionUtil.parseModel(req); var relation = req.options.alias; if (!relation || !Model) return res.serverError(); // Allow customizable blacklist for params. req.options.criteria = req.options.criteria || {}; req.options.criteria.blacklist = req.options.criteria.blacklist || ['limit', 'skip', 'sort', 'id', 'parentid']; var parentPk = req.param('parentid'); // Determine whether to populate using a criteria, or the // specified primary key of the child record, or with no // filter at all. var childPk = actionUtil.parsePk(req); // Coerce the child PK to an integer if necessary if (childPk) { if (Model.attributes[Model.primaryKey].type == 'integer') { childPk = +childPk || 0; } } var where = childPk ? {id: [childPk]} : actionUtil.parseCriteria(req); var populate = sails.util.objCompact({ where: where, skip: actionUtil.parseSkip(req), limit: actionUtil.parseLimit(req), sort: actionUtil.parseSort(req) }); Model .findOne(parentPk) .populate(relation, populate) .exec(function found(err, matchingRecord) { if (err) return res.serverError(err); if (!matchingRecord) return res.notFound('No record found with the specified id.'); if (!matchingRecord[relation]) return res.notFound(util.format('Specified record (%s) is missing relation `%s`', parentPk, relation)); // Subcribe to instance, if relevant // TODO: only subscribe to populated attribute- not the entire model if (sails.hooks.pubsub && req.isSocket) { Model.subscribe(req, matchingRecord); actionUtil.subscribeDeep(req, matchingRecord); } return res.ok(matchingRecord[relation]); }); };
count: function count(request, response) { var Model = actionUtil.parseModel(request); Model .count(actionUtil.parseCriteria(request)) .exec(function found(error, count) { if (error) { response.negotiate(error); } else { response.ok({count: count}); } }) ; }
module.exports = function ( req, res, next ) { var blueprint = req.options.action; if ( blueprint === 'create' ) { var Model = actionUtil.parseModel( req ); if ( req.session.user.id ) { sails.log.debug( 'Policy beforeCreate: Injecting req.user.id into "' + Model.identity + '" parameters.' ); req.body[ Model.identity ].owner = req.session.user.id; } else { // exception for creating new users, otherwise any creative act needs a logged in user if ( Model.identity !== 'user' ) return res.forbidden( "Create blueprint needs an authenticated user!" ); } } next(); };
module.exports = (req, res) => { let q = req.param('query'); if (!q) return res.badRequest(null, {message: 'You should specify a "query" parameter!'}); q = decodeURI(q) var model = actionUtil.parseModel(req); _.forEach(model.definition, function(val, key) { if (val.type === 'string' && model.searchables && model.searchables.indexOf(key) !== -1) { if (key === 'slug') req.params[key] = slug(q, {lower: true}) else req.params[key] = q; } }); return find(req, res); };
module.exports = (req, res) => { // check for authorization on this action if(! sails.config.authorization.authorize_controller(req.options.controller, 'update', req.user)) return res.forbidden(); // check for authorization on this resource if(!sails.config.authorization.authorize_resource(req.record, 'update', req.user)) return res.forbidden(); const Model = actionUtil.parseModel(req); const pk = actionUtil.requirePk(req); var values = actionUtil.parseValues(req); // get the permitted fields to parse in the payload var permitted = []; var fields = sails.config.fields_helper.fieldsInfo[Model.identity]; for (var i = 0; i < fields.length; i++) { permitted.push(fields[i].name); } var notAllowed = _.without(values, permitted); var permitted = _.pull(values, notAllowed); //values = _.pick(values, permitted); Model .update(pk, permitted) .then(function(updated){ _.assign(updated, {'model': Model.identity}); // handle update of the images if the model has a file type field if(AssetsService.hasAsset(Model.identity) && (req.record[AssetsService.hasAsset(Model.identity)] != updated[0][AssetsService.hasAsset(Model.identity)])){ console.log('dentro if'); var infos = AssetsService.getAssetInfos(req.record[AssetsService.hasAsset(Model.identity)], '/'); AssetsService.deleteAssets(infos.name); var cuts = sails.config.services.assets.cuts; for (var i = 0; i < cuts[Model.identity].length; i++) { AssetsService.createCuts(updated[0][AssetsService.hasAsset(Model.identity)], cuts[Model.identity][i].name ,cuts[Model.identity][i].width, cuts[Model.identity][i].height); } } return res.ok(updated); }) .catch(function(err){ return res.negotiate(err); }); };
module.exports = function (req, res) { if (actionUtil.parsePk(req)) { return require('./findOne')(req, res); } var ThisModel = actionUtil.parseModel(req), where = actionUtil.parseCriteria(req), limit = actionUtil.parseLimit(req), skip = actionUtil.parseSkip(req), sort = actionUtil.parseSort(req), query = ThisModel.find().where(where).limit(limit).skip(skip).sort(sort); query = actionUtil.populateEach(query, req); query.exec(function (error, records) { if (error) { return res.serverError(error); } ThisModel .count(where) .exec(function (error, count) { if (error) { return res.serverError(error); } var metaInfo = { start: skip, end: skip + limit, limit: limit, total: count, criteria: where }; res.set('Content-Range', metaInfo.start + '-' + metaInfo.end + '/' + metaInfo.total); res.set('Content-Count', metaInfo.total); return res.ok(records, null, null, metaInfo); }); }); };
module.exports = function findRecords (req, res) { // Look up the model var Model = actionUtil.parseModel(req); // If an `id` param was specified, use the findOne blueprint action // to grab the particular instance with its primary key === the value // of the `id` param. (mainly here for compatibility for 0.9, where // there was no separate `findOne` action) if ( actionUtil.parsePk(req) ) { return require('./findOne')(req,res); } // Lookup for records that match the specified criteria var query = Model.find() .where( actionUtil.parseCriteria(req) ) .where({ isDeleted : false }) .sort( actionUtil.parseSort(req) ); // TODO: .populateEach(req.options); query = actionUtil.populateEach(query, req); query.exec(function found(err, matchingRecords) { if (err) return res.serverError(err); // Only `.watch()` for new instances of the model if // `autoWatch` is enabled. if (req._sails.hooks.pubsub && req.isSocket) { Model.subscribe(req, matchingRecords); if (req.options.autoWatch) { Model.watch(req); } // Also subscribe to instances of all associated models _.each(matchingRecords, function (record) { actionUtil.subscribeDeep(req, record); }); } res.ok(matchingRecords); }); };
.then(record => { var model = (actionUtil.parseModel(req)).adapter.identity; if (_.isUndefined(record[0])) { LogService.winstonLog('error', model + ' not found', { ip: req.ip }); return res.notFound(null, { meta: builder.meta(undefined), links: builder.links(undefined) }); } LogService.log(req, record[0].id); LogService.winstonLog('info', model + ' deleted', { ip: req.ip, resource: record[0].id }); res.deleted(record[0], { meta: builder.meta(), links: builder.links() }); })
module.exports = function findOneRecord (req, res) { const fn = '[findOneRecord]' var Model = actionUtil.parseModel(req); var pk = actionUtil.requirePk(req); sails.log(fn, 'looking for pk:', pk) var query = Model.findOne(pk); query = actionUtil.populateEach(query, req); query.exec(function found(err, matchingRecord) { if (err) return res.serverError(err); if(!matchingRecord) return res.notFound('No record found with the specified `id`.'); if (sails.hooks.pubsub && req.isSocket) { Model.subscribe(req, matchingRecord); actionUtil.subscribeDeep(req, matchingRecord); } res.ok(matchingRecord); }); };
module.exports = function ModelPolicy (req, res, next) { var modelCache = sails.hooks['sails-permissions']._modelCache; req.options.modelIdentity = actionUtil.parseModel(req).identity; if (_.isEmpty(req.options.modelIdentity)) { return next(); } req.options.modelDefinition = sails.models[req.options.modelIdentity]; req.model = modelCache[req.options.modelIdentity]; if (_.isObject(req.model) && !_.isNull(req.model.id)) { return next(); } sails.log.warn('Model [', req.options.modelIdentity, '] not found in model cache'); // if the model is not found in the cache for some reason, get it from the database Model.findOne({ identity: req.options.modelIdentity }) .then(function (model) { if (!_.isObject(model)) { req.options.unknownModel = true; if (!sails.config.permissions.allowUnknownModelDefinition) { return next(new Error('Model definition not found: '+ req.options.modelIdentity)); } else { model = sails.models[req.options.modelIdentity]; } } req.model = model; next(); }) .catch(next); };
module.exports = function updateOneRecord (req, res) { // Look up the model var Model = actionUtil.parseModel(req); // Locate and validate the required `id` parameter. var pk = actionUtil.requirePk(req); // Default the value blacklist to just "id", so that models that have an // "id" field that is _not_ the primary key don't have the id field // updated mistakenly. See https://github.com/balderdashy/sails/issues/3625 req.options.values = req.options.values || {}; req.options.values.blacklist = req.options.values.blacklist || ['id']; // Create `values` object (monolithic combination of all parameters) // But omit the blacklisted params (like JSONP callback param, etc.) var values = actionUtil.parseValues(req); // No matter what, don't allow changing the PK via the update blueprint // (you should just drop and re-add the record if that's what you really want) if (typeof values[Model.primaryKey] !== 'undefined' && values[Model.primaryKey] != pk) { req._sails.log.warn('Cannot change primary key via update blueprint; ignoring value sent for `' + Model.primaryKey + '`'); } // Make sure the primary key is unchanged values[Model.primaryKey] = pk; // Find and update the targeted record. // // (Note: this could be achieved in a single query, but a separate `findOne` // is used first to provide a better experience for front-end developers // integrating with the blueprint API.) var query = Model.findOne(pk); // Populate the record according to the current "populate" settings query = actionUtil.populateRequest(query, req); query.exec(function found(err, matchingRecord) { if (err) return res.serverError(err); if (!matchingRecord) return res.notFound(); // delete values.documents; return Model.update({id:pk}, values).exec(function updated(err, records) { // Differentiate between waterline-originated validation errors // and serious underlying issues. Respond with badRequest if a // validation error is encountered, w/ validation info. if (err) return res.negotiate(err); // Because this should only update a single record and update // returns an array, just use the first item. If more than one // record was returned, something is amiss. if (!records || !records.length || records.length > 1) { req._sails.log.warn( util.format('Unexpected output from `%s.update`.', Model.globalId) ); } var updatedRecord = records[0]; // If we have the pubsub hook, use the Model's publish method // to notify all subscribers about the update. if (req._sails.hooks.pubsub) { if (req.isSocket) { Model.subscribe(req, records); } Model.publishUpdate(pk, _.cloneDeep(values), !req.options.mirror && req, { previous: _.cloneDeep(matchingRecord.toJSON()) }); } // Do a final query to populate the associations of the record. // // (Note: again, this extra query could be eliminated, but it is // included by default to provide a better interface for integrating // front-end developers.) var Q = Model.findOne(updatedRecord[Model.primaryKey]); Q = actionUtil.populateRequest(Q, req); Q.exec(function foundAgain(err, populatedRecord) { if (err) return res.serverError(err); if (!populatedRecord) return res.serverError('Could not find record after updating!'); res.ok(populatedRecord); }); // </foundAgain> });// </updated> }); // </found> };
module.exports = function expand(req, res) { function getRelationModel(relation) { const association = _.find(req.options.associations, {alias: relation}); const collection = association.collection; const model = req._sails.models[collection]; return model; } const Model = actionUtil.parseModel(req); const relation = req.options.alias; if (!relation || !Model) return res.serverError(); const relationModel = getRelationModel(relation); // Allow customizable blacklist for params. req.options.criteria = req.options.criteria || {}; req.options.criteria.blacklist = req.options.criteria.blacklist || ['limit', 'skip', 'sort', 'id', 'parentid']; const parentPk = req.param('parentid'); // Determine whether to populate using a criteria, or the // specified primary key of the child record, or with no // filter at all. let childPk = actionUtil.parsePk(req); // Coerce the child PK to an integer if necessary if (childPk && Model.attributes[Model.primaryKey].type == 'integer') childPk = +childPk || 0; const where = childPk ? {id: [childPk]} : actionUtil.parseCriteria(req); const populate = sails.util.objCompact({where: where}); delete populate.where.populate; let sort = actionUtil.parseSort(req); if (_.isEmpty(sort) && relationModel.DEFAULT_SORTING) sort = relationModel.DEFAULT_SORTING; const hardLimit = 1500; const skip = actionUtil.parseSkip(req); const limit = hardLimit + skip; populate.sort = sort; populate.limit = limit; populate.skip = skip; Model.findOne(parentPk) .populate(relation, populate) .then(matchingRecord => { if (!matchingRecord) return res.notFound('No record found with the specified id.'); if (!matchingRecord[relation]) return res.notFound(util.format('Specified record (%s) is missing relation `%s`', parentPk, relation)); const count = matchingRecord[relation].length + skip; const relationsRecords = matchingRecord[relation]; const limit = actionUtil.parseLimit(req); const recordsId = _.slice(_.map(relationsRecords, 'id'), 0, limit); let populateFields = req.param('populate'); if (populateFields && !_.isArray(populateFields)) populateFields = [populateFields]; populateFields = _.filter(populateFields, f => _.some(relationModel.associations, {alias: f})); //sTODO add support for deep populate const where = {'id': recordsId}; let query = relationModel.find({where, sort}); _.forEach(populateFields, f => query = query.populate(f)); return Promise.all([query, count]) .spread((matchingRecords, count) => { //if asking for a single related entity if (childPk) if (matchingRecords.length) return res.ok(matchingRecords); else return res.notFound(); const postPopulate = _.get(Model, '_attributes.' + relation + '._postPopulate') || ((xs, id) => Promise.resolve(xs)); return postPopulate(matchingRecords, parentPk) .then(newRecords => res.ok({ count: count, items: newRecords }) ); }) .catch(err => res.serverError(err)); }) .catch(err => res.serverError(err)); };
"use strict"; /** * HeadController * @description :: Server-side logic for ... */ const actionUtil = require('sails/lib/hooks/blueprints/actionUtil'); module.exports = { head(req, res) { // const fields = req.param('fields') ? req.param('fields').replace(/ /g, '').split(',') : []; var model = actionUtil.parseModel(req); var id = req.param('id'); res.set({ 'Authorization': 'JWT [token]', 'Connection': 'keep-alive' }); if (id) { model.findOne({ id: id }).exec(function(err, record) { if (err) return res.negotiate(err); if (!record) return res.notFound; else return res.send(204); }); } res.status = 204; return res.end(); } };
module.exports = function findRecords(req, res) { // Look up the model var Model = actionUtil.parseModel(req); // Lookup for records that match the specified criteria var queryData = Model.find() .where( parseNgAdminFilter(actionUtil.parseCriteria(req)) ) .limit( actionUtil.parseLimit(req) ) .skip( actionUtil.parseSkip(req) ); var sort = actionUtil.parseSort(req); if( sort != 'undefined undefined' && sort != 'id DESC' ) { queryData.sort(actionUtil.parseSort(req)); } queryData = actionUtil.populateEach(queryData, req); var queryCount = Model.count().where(actionUtil.parseCriteria(req)); // Expose header to the client res.set('Access-Control-Expose-Headers', 'X-Total-Count'); async.parallel( { data: getData, count: getTotalCount }, function (err, results) { res.set('X-Total-Count', results.count); res.ok(results.data); } ); function getTotalCount(cb) { queryCount.exec(function (err, count) { cb(null, count); }); } function getData(cb) { queryData.exec(function found(err, matchingRecords) { if (err) return res.serverError(err); // Only `.watch()` for new instances of the model if // `autoWatch` is enabled. if (req._sails.hooks.pubsub && req.isSocket) { Model.subscribe(req, matchingRecords); if (req.options.autoWatch) { Model.watch(req); } // Also subscribe to instances of all associated models _.each(matchingRecords, function (record) { actionUtil.subscribeDeep(req, record); }); } cb(null, matchingRecords); }); } function parseNgAdminFilter(req){ if(req._filters){ if(JSON.parse(req._filters).category_id){ return JSON.parse(req._filters); }else if(JSON.parse(req._filters).q){ return {title: {like: '%'+JSON.parse(req._filters).q+'%'}}; } } return req; } };
export function addToCollection (req, res) { // Ensure a model and alias can be deduced from the request. var Model = actionUtil.parseModel(req); var relation = req.options.alias; if (!relation) { return res.serverError(new Error('Missing required route option, `req.options.alias`.')); } // The primary key of the parent record var parentPk = req.param('parentid'); // Get the model class of the child in order to figure out the name of // the primary key attribute. var associationAttr = _.findWhere(Model.associations, { alias: relation }); var ChildModel = sails.models[associationAttr.collection]; var childPkAttr = ChildModel.primaryKey; // The child record to associate is defined by either... var child; // ...a primary key: var supposedChildPk = actionUtil.parsePk(req); if (supposedChildPk) { child = {}; child[childPkAttr] = supposedChildPk; } // ...or an object of values: else { req.options.values = req.options.values || {}; req.options.values.blacklist = req.options.values.blacklist || ['limit', 'skip', 'sort', 'id', 'parentid']; child = actionUtil.parseValues(req); } if (!child) { res.badRequest('You must specify the record to add (either the primary key of an existing record to link, or a new object without a primary key which will be used to create a record then link it.)'); } var createdChild = false; async.auto({ // Look up the parent record parent: function (cb) { Model.findOne(parentPk).exec(function foundParent(err, parentRecord) { if (err) return cb(err); if (!parentRecord) return cb({status: 404}); if (!parentRecord[relation]) return cb({status: 404}); cb(null, parentRecord); }); }, // If a primary key was specified in the `child` object we parsed // from the request, look it up to make sure it exists. Send back its primary key value. // This is here because, although you can do this with `.save()`, you can't actually // get ahold of the created child record data, unless you create it first. actualChildPkValue: ['parent', function(cb) { // Below, we use the primary key attribute to pull out the primary key value // (which might not have existed until now, if the .add() resulted in a `create()`) // If the primary key was specified for the child record, we should try to find // it before we create it. if (child[childPkAttr]) { ChildModel.findOne(child[childPkAttr]).exec(function foundChild(err, childRecord) { if (err) return cb(err); // Didn't find it? Then try creating it. if (!childRecord) {return createChild();} // Otherwise use the one we found. return cb(null, childRecord[childPkAttr]); }); } // Otherwise, it must be referring to a new thing, so create it. else { return createChild(); } // Create a new instance and send out any required pubsub messages. function createChild() { ChildModel.create(child).exec(function createdNewChild (err, newChildRecord){ if (err) return cb(err); if (req._sails.hooks.pubsub) { if (req.isSocket) { ChildModel.subscribe(req, newChildRecord); ChildModel.introduce(newChildRecord); } ChildModel.publishCreate(newChildRecord, !req.options.mirror && req); } createdChild = true; return cb(null, newChildRecord[childPkAttr]); }); } }], // Add the child record to the parent's collection add: ['parent', 'actualChildPkValue', function(cb, async_data) { try { // `collection` is the parent record's collection we // want to add the child to. var collection = async_data.parent[relation]; collection.add(async_data.actualChildPkValue); return cb(); } // Ignore `insert` errors catch (err) { // if (err && err.type !== 'insert') { if (err) { return cb(err); } // else if (err) { // // if we made it here, then this child record is already // // associated with the collection. But we do nothing: // // `add` is idempotent. // } return cb(); } }] }, // Save the parent record function readyToSave (err, async_data) { if (err) return res.negotiate(err); async_data.parent.save(function saved(err) { // Ignore `insert` errors for duplicate adds // (but keep in mind, we should not publishAdd if this is the case...) var isDuplicateInsertError = (err && typeof err === 'object' && err.length && err[0] && err[0].type === 'insert'); if (err && !isDuplicateInsertError) return res.negotiate(err); // Only broadcast an update if this isn't a duplicate `add` // (otherwise connected clients will see duplicates) if (!isDuplicateInsertError && req._sails.hooks.pubsub) { // Subscribe to the model you're adding to, if this was a socket request if (req.isSocket) { Model.subscribe(req, async_data.parent); } // Publish to subscribed sockets Model.publishAdd(async_data.parent[Model.primaryKey], relation, async_data.actualChildPkValue, !req.options.mirror && req, {noReverse: createdChild}); } // Finally, look up the parent record again and populate the relevant collection. // TODO: populateEach Model.findOne(parentPk).populate(relation).exec(function(err, matchingRecord) { if (err) return res.serverError(err); if (!matchingRecord) return res.serverError(); if (!matchingRecord[relation]) return res.serverError(); return res.ok(matchingRecord); }); }); }); // </async.auto> };