This commit is contained in:
parent
8f118748b6
commit
e0fa7609cb
|
@ -12,60 +12,75 @@ module.exports = function(Self) {
|
|||
});
|
||||
|
||||
Self.observe('before save', async function(ctx) {
|
||||
const appModels = ctx.Model.app.models;
|
||||
const loopBackContext = LoopBackContext.getCurrentContext();
|
||||
const models = ctx.Model.app.models;
|
||||
const definition = ctx.Model.definition;
|
||||
const options = {};
|
||||
const Model = models[definition.name];
|
||||
const settings = definition.settings;
|
||||
let opts = ctx.options;
|
||||
if (!opts) opts = ctx.options = {};
|
||||
|
||||
// Check for transactions
|
||||
if (ctx.options && ctx.options.transaction)
|
||||
options.transaction = ctx.options.transaction;
|
||||
|
||||
let oldInstance;
|
||||
let newInstance;
|
||||
|
||||
if (ctx.data) {
|
||||
const changes = pick(ctx.currentInstance, Object.keys(ctx.data));
|
||||
newInstance = ctx.data;
|
||||
oldInstance = changes;
|
||||
|
||||
if (ctx.where && !ctx.currentInstance) {
|
||||
const fields = Object.keys(ctx.data);
|
||||
const modelName = definition.name;
|
||||
|
||||
ctx.oldInstances = await appModels[modelName].find({
|
||||
where: ctx.where,
|
||||
fields: fields
|
||||
}, options);
|
||||
}
|
||||
let tx;
|
||||
if (!opts.transaction) {
|
||||
opts.transaction = tx = await Model.beginTransaction({});
|
||||
opts.tx = true;
|
||||
}
|
||||
|
||||
// Get changes from created instance
|
||||
if (ctx.isNewInstance)
|
||||
newInstance = ctx.instance.__data;
|
||||
try {
|
||||
// Check if grabUser is active
|
||||
if (loopBackContext && settings.log && settings.log.grabUser) {
|
||||
const userId = loopBackContext.active.accessToken.userId;
|
||||
const user = await models.Account.findById(userId, {fields: ['name']}, opts);
|
||||
await Model.rawSql(`CALL account.myUser_loginWithName(?)`, [user.name], opts);
|
||||
}
|
||||
|
||||
ctx.hookState.oldInstance = oldInstance;
|
||||
ctx.hookState.newInstance = newInstance;
|
||||
let oldInstance;
|
||||
let newInstance;
|
||||
if (ctx.data) {
|
||||
const changes = pick(ctx.currentInstance, Object.keys(ctx.data));
|
||||
newInstance = ctx.data;
|
||||
oldInstance = changes;
|
||||
|
||||
if (ctx.where && !ctx.currentInstance) {
|
||||
const fields = Object.keys(ctx.data);
|
||||
|
||||
ctx.oldInstances = await Model.find({
|
||||
where: ctx.where,
|
||||
fields: fields
|
||||
}, opts);
|
||||
}
|
||||
}
|
||||
|
||||
// Get changes from created instance
|
||||
if (ctx.isNewInstance)
|
||||
newInstance = ctx.instance.__data;
|
||||
|
||||
ctx.hookState.oldInstance = oldInstance;
|
||||
ctx.hookState.newInstance = newInstance;
|
||||
} catch (e) {
|
||||
if (tx) await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
Self.observe('before delete', async function(ctx) {
|
||||
const appModels = ctx.Model.app.models;
|
||||
const models = ctx.Model.app.models;
|
||||
const definition = ctx.Model.definition;
|
||||
const relations = ctx.Model.relations;
|
||||
|
||||
let options = {};
|
||||
if (ctx.options && ctx.options.transaction)
|
||||
options.transaction = ctx.options.transaction;
|
||||
let opts = ctx.options;
|
||||
if (!opts) opts = ctx.options = {};
|
||||
|
||||
if (ctx.where) {
|
||||
let affectedModel = definition.name;
|
||||
let deletedInstances = await appModels[affectedModel].find({
|
||||
const affectedModel = definition.name;
|
||||
let deletedInstances = await models[affectedModel].find({
|
||||
where: ctx.where
|
||||
}, options);
|
||||
}, opts);
|
||||
|
||||
let relation = definition.settings.log.relation;
|
||||
const relation = definition.settings.log.relation;
|
||||
|
||||
if (relation) {
|
||||
let primaryKey = relations[relation].keyFrom;
|
||||
const primaryKey = relations[relation].keyFrom;
|
||||
|
||||
let arrangedDeletedInstances = [];
|
||||
for (let i = 0; i < deletedInstances.length; i++) {
|
||||
|
@ -81,24 +96,23 @@ module.exports = function(Self) {
|
|||
|
||||
Self.observe('after delete', async function(ctx) {
|
||||
const loopBackContext = LoopBackContext.getCurrentContext();
|
||||
if (ctx.hookState.oldInstance)
|
||||
logDeletedInstances(ctx, loopBackContext);
|
||||
if (ctx.hookState.oldInstance) logDeletedInstances(ctx, loopBackContext);
|
||||
});
|
||||
|
||||
async function logDeletedInstances(ctx, loopBackContext) {
|
||||
const appModels = ctx.Model.app.models;
|
||||
const models = ctx.Model.app.models;
|
||||
const definition = ctx.Model.definition;
|
||||
let options = {};
|
||||
if (ctx.options && ctx.options.transaction)
|
||||
options.transaction = ctx.options.transaction;
|
||||
const settings = definition.settings;
|
||||
let opts = ctx.options;
|
||||
if (!opts) opts = ctx.options = {};
|
||||
|
||||
ctx.hookState.oldInstance.forEach(async instance => {
|
||||
let userFk;
|
||||
if (loopBackContext)
|
||||
userFk = loopBackContext.active.accessToken.userId;
|
||||
|
||||
let changedModelValue = definition.settings.log.changedModelValue;
|
||||
let logRecord = {
|
||||
const changedModelValue = settings.log.changedModelValue;
|
||||
const logRecord = {
|
||||
originFk: instance.originFk,
|
||||
userFk: userFk,
|
||||
action: 'delete',
|
||||
|
@ -111,33 +125,28 @@ module.exports = function(Self) {
|
|||
|
||||
delete instance.originFk;
|
||||
|
||||
let logModel = definition.settings.log.model;
|
||||
await appModels[logModel].create(logRecord, options);
|
||||
const logModel = settings.log.model;
|
||||
await models[logModel].create(logRecord, opts);
|
||||
});
|
||||
}
|
||||
|
||||
// Get log values from a foreign key
|
||||
async function fkToValue(instance, ctx) {
|
||||
const appModels = ctx.Model.app.models;
|
||||
const models = ctx.Model.app.models;
|
||||
const relations = ctx.Model.relations;
|
||||
let options = {};
|
||||
|
||||
// Check for transactions
|
||||
if (ctx.options && ctx.options.transaction)
|
||||
options.transaction = ctx.options.transaction;
|
||||
let opts = ctx.options;
|
||||
if (!opts) opts = ctx.options = {};
|
||||
|
||||
const instanceCopy = JSON.parse(JSON.stringify(instance));
|
||||
const result = {};
|
||||
for (const key in instanceCopy) {
|
||||
let value = instanceCopy[key];
|
||||
|
||||
if (value instanceof Object)
|
||||
if (value instanceof Object || value === undefined)
|
||||
continue;
|
||||
|
||||
if (value === undefined) continue;
|
||||
|
||||
if (value) {
|
||||
for (let relationName in relations) {
|
||||
for (const relationName in relations) {
|
||||
const relation = relations[relationName];
|
||||
if (relation.keyFrom == key && key != 'id') {
|
||||
const model = relation.modelTo;
|
||||
|
@ -145,7 +154,7 @@ module.exports = function(Self) {
|
|||
const properties = model && model.definition.properties;
|
||||
const settings = model && model.definition.settings;
|
||||
|
||||
const recordSet = await appModels[modelName].findById(value, null, options);
|
||||
const recordSet = await models[modelName].findById(value, null, opts);
|
||||
|
||||
const hasShowField = settings.log && settings.log.showField;
|
||||
let showField = hasShowField && recordSet
|
||||
|
@ -185,104 +194,121 @@ module.exports = function(Self) {
|
|||
}
|
||||
|
||||
async function logInModel(ctx, loopBackContext) {
|
||||
const appModels = ctx.Model.app.models;
|
||||
const models = ctx.Model.app.models;
|
||||
const definition = ctx.Model.definition;
|
||||
const defSettings = ctx.Model.definition.settings;
|
||||
const Model = models[definition.name];
|
||||
const settings = ctx.Model.definition.settings;
|
||||
const relations = ctx.Model.relations;
|
||||
|
||||
const options = {};
|
||||
if (ctx.options && ctx.options.transaction)
|
||||
options.transaction = ctx.options.transaction;
|
||||
let opts = ctx.options;
|
||||
if (!opts) opts = ctx.options = {};
|
||||
|
||||
let primaryKey;
|
||||
for (let property in definition.properties) {
|
||||
if (definition.properties[property].id) {
|
||||
primaryKey = property;
|
||||
break;
|
||||
// Check for transactions
|
||||
let tx;
|
||||
if (opts.tx === true) tx = opts.transaction;
|
||||
|
||||
try {
|
||||
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 (!primaryKey) throw new Error('Primary key not found');
|
||||
let originId;
|
||||
|
||||
// RELATIONS LOG
|
||||
let changedModelId;
|
||||
// RELATIONS LOG
|
||||
let changedModelId;
|
||||
|
||||
if (ctx.instance && !defSettings.log.relation) {
|
||||
originId = ctx.instance.id;
|
||||
changedModelId = ctx.instance.id;
|
||||
} else if (defSettings.log.relation) {
|
||||
primaryKey = relations[defSettings.log.relation].keyFrom;
|
||||
|
||||
if (ctx.where && ctx.where[primaryKey])
|
||||
originId = ctx.where[primaryKey];
|
||||
else if (ctx.instance) {
|
||||
originId = ctx.instance[primaryKey];
|
||||
if (ctx.instance && !settings.log.relation) {
|
||||
originId = ctx.instance.id;
|
||||
changedModelId = ctx.instance.id;
|
||||
} else if (settings.log.relation) {
|
||||
primaryKey = relations[settings.log.relation].keyFrom;
|
||||
|
||||
if (ctx.where && ctx.where[primaryKey])
|
||||
originId = ctx.where[primaryKey];
|
||||
else if (ctx.instance) {
|
||||
originId = ctx.instance[primaryKey];
|
||||
changedModelId = ctx.instance.id;
|
||||
}
|
||||
} else {
|
||||
originId = ctx.currentInstance.id;
|
||||
changedModelId = ctx.currentInstance.id;
|
||||
}
|
||||
} else {
|
||||
originId = ctx.currentInstance.id;
|
||||
changedModelId = ctx.currentInstance.id;
|
||||
|
||||
// Sets the changedModelValue to save and the instances changed in case its an updateAll
|
||||
let showField = settings.log.showField;
|
||||
let where;
|
||||
if (showField && (!ctx.instance || !ctx.instance[showField]) && ctx.where) {
|
||||
changedModelId = [];
|
||||
where = [];
|
||||
let changedInstances = await models[definition.name].find({
|
||||
where: ctx.where,
|
||||
fields: ['id', showField, primaryKey]
|
||||
}, opts);
|
||||
|
||||
changedInstances.forEach(element => {
|
||||
where.push(element[showField]);
|
||||
changedModelId.push(element.id);
|
||||
originId = element[primaryKey];
|
||||
});
|
||||
} else if (ctx.hookState.oldInstance)
|
||||
where = ctx.instance[showField];
|
||||
|
||||
// Set oldInstance, newInstance, userFk and action
|
||||
let oldInstance = {};
|
||||
if (ctx.hookState.oldInstance)
|
||||
Object.assign(oldInstance, ctx.hookState.oldInstance);
|
||||
|
||||
let newInstance = {};
|
||||
if (ctx.hookState.newInstance)
|
||||
Object.assign(newInstance, ctx.hookState.newInstance);
|
||||
|
||||
let userFk;
|
||||
if (loopBackContext)
|
||||
userFk = loopBackContext.active.accessToken.userId;
|
||||
|
||||
const action = setActionType(ctx);
|
||||
|
||||
removeUnloggable(definition, oldInstance);
|
||||
removeUnloggable(definition, newInstance);
|
||||
|
||||
oldInstance = await fkToValue(oldInstance, ctx);
|
||||
newInstance = await fkToValue(newInstance, ctx);
|
||||
|
||||
// Prevent log with no new changes
|
||||
const hasNewChanges = Object.keys(newInstance).length;
|
||||
if (!hasNewChanges) return;
|
||||
|
||||
let logRecord = {
|
||||
originFk: originId,
|
||||
userFk: userFk,
|
||||
action: action,
|
||||
changedModel: definition.name,
|
||||
changedModelId: changedModelId, // Model property with an different data type will throw a NaN error
|
||||
changedModelValue: where,
|
||||
oldInstance: oldInstance,
|
||||
newInstance: newInstance
|
||||
};
|
||||
|
||||
const logsToSave = setLogsToSave(where, changedModelId, logRecord, ctx);
|
||||
const logModel = settings.log.model;
|
||||
await models[logModel].create(logsToSave, opts);
|
||||
|
||||
// Check if grabUser is active
|
||||
if (settings.log && settings.log.grabUser) await Model.rawSql(`CALL account.myUser_logout()`, null, opts);
|
||||
if (tx) {
|
||||
await tx.commit();
|
||||
delete opts.transaction;
|
||||
delete opts.tx;
|
||||
}
|
||||
} catch (e) {
|
||||
if (tx) await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
|
||||
// Sets the changedModelValue to save and the instances changed in case its an updateAll
|
||||
let showField = defSettings.log.showField;
|
||||
let where;
|
||||
if (showField && (!ctx.instance || !ctx.instance[showField]) && ctx.where) {
|
||||
changedModelId = [];
|
||||
where = [];
|
||||
let changedInstances = await appModels[definition.name].find({
|
||||
where: ctx.where,
|
||||
fields: ['id', showField, primaryKey]
|
||||
}, options);
|
||||
|
||||
changedInstances.forEach(element => {
|
||||
where.push(element[showField]);
|
||||
changedModelId.push(element.id);
|
||||
originId = element[primaryKey];
|
||||
});
|
||||
} else if (ctx.hookState.oldInstance)
|
||||
where = ctx.instance[showField];
|
||||
|
||||
// Set oldInstance, newInstance, userFk and action
|
||||
let oldInstance = {};
|
||||
if (ctx.hookState.oldInstance)
|
||||
Object.assign(oldInstance, ctx.hookState.oldInstance);
|
||||
|
||||
let newInstance = {};
|
||||
if (ctx.hookState.newInstance)
|
||||
Object.assign(newInstance, ctx.hookState.newInstance);
|
||||
let userFk;
|
||||
if (loopBackContext)
|
||||
userFk = loopBackContext.active.accessToken.userId;
|
||||
|
||||
let action = setActionType(ctx);
|
||||
|
||||
removeUnloggable(definition, oldInstance);
|
||||
removeUnloggable(definition, newInstance);
|
||||
|
||||
oldInstance = await fkToValue(oldInstance, ctx);
|
||||
newInstance = await fkToValue(newInstance, ctx);
|
||||
|
||||
// Prevent log with no new changes
|
||||
const hasNewChanges = Object.keys(newInstance).length;
|
||||
if (!hasNewChanges) return;
|
||||
|
||||
let logRecord = {
|
||||
originFk: originId,
|
||||
userFk: userFk,
|
||||
action: action,
|
||||
changedModel: definition.name,
|
||||
changedModelId: changedModelId, // Model property with an different data type will throw a NaN error
|
||||
changedModelValue: where,
|
||||
oldInstance: oldInstance,
|
||||
newInstance: newInstance
|
||||
};
|
||||
|
||||
let logsToSave = setLogsToSave(where, changedModelId, logRecord, ctx);
|
||||
let logModel = defSettings.log.model;
|
||||
|
||||
await appModels[logModel].create(logsToSave, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -297,7 +323,6 @@ module.exports = function(Self) {
|
|||
|
||||
for (let property in definition.properties) {
|
||||
const propertyDef = definition.properties[property];
|
||||
|
||||
propDefs.set(property, propertyDef);
|
||||
}
|
||||
|
||||
|
@ -311,7 +336,7 @@ module.exports = function(Self) {
|
|||
|
||||
if (!propertyDef) continue;
|
||||
|
||||
if (propertyDef.log === false || isPrivate)
|
||||
if (propertyDef.log === false)
|
||||
delete properties[property];
|
||||
else if (propertyDef.logValue === false)
|
||||
properties[property] = null;
|
||||
|
|
Loading…
Reference in New Issue