const pick = require('object.pick'); const LoopBackContext = require('loopback-context'); module.exports = function(Self) { Self.setup = function() { Self.super_.setup.call(this); }; Self.observe('after save', async function(ctx) { const loopBackContext = LoopBackContext.getCurrentContext(); await logInModel(ctx, loopBackContext); }); Self.observe('before save', async function(ctx) { let oldInstance; let oldInstanceFk; let newInstance; if (ctx.data) { oldInstanceFk = pick(ctx.currentInstance, Object.keys(ctx.data)); newInstance = await fkToValue(ctx.data, ctx); oldInstance = await fkToValue(oldInstanceFk, ctx); } if (ctx.isNewInstance) { newInstance = await fkToValue(ctx.instance.__data, ctx); } ctx.hookState.oldInstance = oldInstance; ctx.hookState.newInstance = newInstance; }); /* Self.observe('before delete', async function(ctx, next) { let oldInstance; if (ctx.instance) { oldInstance = await fkToValue(ctx.data, ctx); } await logInModel(ctx); next(); }); Self.observe('after delete', async function(ctx, next) { let oldInstance; if (ctx.instance) { oldInstance = await fkToValue(ctx.data, ctx); } await logInModel(ctx); next(); }); */ async function fkToValue(instance, ctx) { let result = {}; for (let key in instance) { if (key == 'id') continue; let val = instance[key]; if (val === undefined) continue; for (let key1 in ctx.Model.relations) { let val1 = ctx.Model.relations[key1]; if (val1.keyFrom == key) { let recordSet = await val1.modelTo.findById(val); val = recordSet.name; // FIXME preparar todos los modelos con campo name break; } } result[key] = val; } return result; } async function logInModel(ctx, loopBackContext) { let definition = ctx.Model.definition; let primaryKey; for (let property in definition.properties) { if (definition.properties[property].id) { primaryKey = property; break; } } if (!primaryKey) throw new Error('Primary key not found'); let originId; if (definition.settings.log.relation) { // RELATIONS LOG primaryKey = ctx.Model.relations[definition.settings.log.relation].keyFrom; if(ctx.where && ctx.where[primaryKey]) originId = ctx.where[primaryKey] else originId = ctx.instance[primaryKey]; } else { if (ctx.instance) { originId = ctx.instance.id; } else { originId = ctx.currentInstance.id; } } // This adds the originDescription field if it doesnt exists in the instances let originDescription = definition.settings.log.originDescription; if (originDescription && (!ctx.instance || !ctx.instance[originDescription])) await Self.modelBuilder.models[definition.name].findById() if (ctx.hookState.oldInstance && !ctx.hookState.oldInstance[originDescription]){ ctx.hookState.oldInstance[originDescription] = ctx.instance[originDescription]; ctx.hookState.newInstance[originDescription] = ctx.instance[originDescription]; } // This put some order in the intances putting the originDescription in first place let oldInstance = {}; if (ctx.hookState.oldInstance) { oldInstance[originDescription] = ctx.hookState.oldInstance[originDescription]; delete ctx.hookState.oldInstance[originDescription]; Object.assign(oldInstance, ctx.hookState.oldInstance); } let newInstance = {}; if (ctx.hookState.newInstance) { newInstance[originDescription] = ctx.hookState.newInstance[originDescription]; delete ctx.hookState.newInstance[originDescription]; Object.assign(newInstance, ctx.hookState.newInstance) } let userFk; if (!loopBackContext) userFk = null; else userFk = loopBackContext.active.accessToken.userId; let action = setActionType(ctx); let logRecord = { originFk: originId, userFk: userFk, model: ctx.Model.definition.name, action: action, oldInstance: oldInstance, newInstance: newInstance }; let logModel = definition.settings.log.model await Self.modelBuilder.models[logModel].create(logRecord); } function setActionType(ctx) { let oldInstance = ctx.hookState.oldInstance; let newInstance = ctx.hookState.newInstance; if (oldInstance && newInstance) { return 'update'; } else if (!oldInstance && newInstance) { return 'insert'; } } };