From 43cbdefa2228b22485d1b03fbcef5871270faf11 Mon Sep 17 00:00:00 2001 From: Gerard Date: Wed, 3 Oct 2018 09:37:34 +0200 Subject: [PATCH] Tarea #600 loggable --- .../loopback/common/models/client-log.json | 50 ++++++ services/loopback/common/models/client.json | 5 +- services/loopback/common/models/loggable.js | 155 ++++++++++++++++++ services/loopback/common/models/loggable.json | 5 + services/loopback/server/model-config.json | 3 + 5 files changed, 217 insertions(+), 1 deletion(-) create mode 100644 services/loopback/common/models/client-log.json create mode 100644 services/loopback/common/models/loggable.js create mode 100644 services/loopback/common/models/loggable.json diff --git a/services/loopback/common/models/client-log.json b/services/loopback/common/models/client-log.json new file mode 100644 index 000000000..fd5a06329 --- /dev/null +++ b/services/loopback/common/models/client-log.json @@ -0,0 +1,50 @@ +{ + "name": "ClientLog", + "base": "VnModel", + "options": { + "mysql": { + "table": "clientLog" + } + }, + "properties": { + "id": { + "id": true, + "type": "Number", + "forceId": false + }, + "originFk": { + "type": "Number", + "required": true + }, + "userFk": { + "type": "Number", + "required": true + }, + "action": { + "type": "String", + "required": true + }, + "model": { + "type": "String", + "required": true + }, + "oldInstance": { + "type": "Object", + "required": true + }, + "newInstance": { + "type": "Object", + "required": true + }, + "creationDate": { + "type": "Date" + } + }, + "relations": { + "user": { + "type": "belongsTo", + "model": "Account", + "foreignKey": "userFk" + } + } +} diff --git a/services/loopback/common/models/client.json b/services/loopback/common/models/client.json index d80e31d9e..9c03b737b 100644 --- a/services/loopback/common/models/client.json +++ b/services/loopback/common/models/client.json @@ -1,6 +1,9 @@ { "name": "Client", - "base": "VnModel", + "base": "Loggable", + "log": { + "model":"ClientLog" + }, "options": { "mysql": { "table": "client" diff --git a/services/loopback/common/models/loggable.js b/services/loopback/common/models/loggable.js new file mode 100644 index 000000000..df1640a96 --- /dev/null +++ b/services/loopback/common/models/loggable.js @@ -0,0 +1,155 @@ +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 action = setActionType(ctx); + let userFk = loopBackContext.active.accessToken.userId; + + 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'; + } + } +}; diff --git a/services/loopback/common/models/loggable.json b/services/loopback/common/models/loggable.json new file mode 100644 index 000000000..9101532a3 --- /dev/null +++ b/services/loopback/common/models/loggable.json @@ -0,0 +1,5 @@ +{ + "name": "Loggable", + "base": "VnModel", + "validateUpsert": true +} diff --git a/services/loopback/server/model-config.json b/services/loopback/server/model-config.json index 684e4aa4e..aed0a97f9 100644 --- a/services/loopback/server/model-config.json +++ b/services/loopback/server/model-config.json @@ -45,6 +45,9 @@ "Client": { "dataSource": "vn" }, + "ClientLog": { + "dataSource": "vn" + }, "ClientCreditLimit": { "dataSource": "vn" },