From 0bd11ca02f268a740e05a886ed34d0321bfddac0 Mon Sep 17 00:00:00 2001 From: Vijay Kumar Rathore Date: Mon, 21 Mar 2022 15:09:42 +0100 Subject: [PATCH 1/2] create api logs for apis as well Signed-off-by: Vijay Kumar Rathore --- .../project/spreadsheet/apis/restApi.js | 8 -- packages/nc-gui/plugins/ncApis/restApi.js | 8 -- .../nocodb/src/lib/noco/common/BaseModel.ts | 125 ++++++++++++------ 3 files changed, 87 insertions(+), 54 deletions(-) diff --git a/packages/nc-gui/components/project/spreadsheet/apis/restApi.js b/packages/nc-gui/components/project/spreadsheet/apis/restApi.js index 5a1208463f..ccc87c4d6f 100644 --- a/packages/nc-gui/components/project/spreadsheet/apis/restApi.js +++ b/packages/nc-gui/components/project/spreadsheet/apis/restApi.js @@ -67,14 +67,6 @@ export default class RestApi { url: `/nc/${this.$ctx.$route.params.project_id}/api/v1/${this.table}/${id}`, data }) - const colName = Object.keys(data)[0] - this.$ctx.$store.dispatch('sqlMgr/ActSqlOp', [{ dbAlias: this.$ctx.nodes.dbAlias }, 'xcAuditCreate', { - tn: this.table, - cn: colName, - pk: id, - value: data[colName], - prevValue: oldData[colName] - }]) return res } diff --git a/packages/nc-gui/plugins/ncApis/restApi.js b/packages/nc-gui/plugins/ncApis/restApi.js index b26c9bf13b..7bb2aff503 100644 --- a/packages/nc-gui/plugins/ncApis/restApi.js +++ b/packages/nc-gui/plugins/ncApis/restApi.js @@ -70,14 +70,6 @@ export default class RestApi { url: `/nc/${this.$ctx.projectId}/api/v1/${this.table}/${encodeURIComponent(id)}`, data }) - const colName = Object.keys(data)[0] - this.$ctx.$store.dispatch('sqlMgr/ActSqlOp', [{ dbAlias: this.$ctx.dbAlias }, 'xcAuditCreate', { - tn: this.table, - cn: colName, - pk: id, - value: data[colName], - prevValue: oldData[colName] - }]) return res.data } diff --git a/packages/nocodb/src/lib/noco/common/BaseModel.ts b/packages/nocodb/src/lib/noco/common/BaseModel.ts index faaa2cbbc0..2f259e0938 100644 --- a/packages/nocodb/src/lib/noco/common/BaseModel.ts +++ b/packages/nocodb/src/lib/noco/common/BaseModel.ts @@ -26,59 +26,108 @@ class BaseModel> extends BaseModelSql { public async afterInsert(data: any, _trx: any, req): Promise { await this.handleHooks('after.insert', data, req); - if (req?.headers?.['xc-gui']) { - const id = this._extractPksValues(data); - this.builder - .getXcMeta() - .audit( - this.builder?.getProjectId(), - this.builder?.getDbAlias(), - 'nc_audit', - { - model_name: this._tn, - model_id: id, - op_type: 'DATA', - op_sub_type: 'INSERT', - description: `${id} inserted into ${this._tn}`, - // details: JSON.stringify(data), - ip: req?.clientIp, - user: req?.user?.email - } - ); - } + const id = this._extractPksValues(data); + this.builder + .getXcMeta() + .audit( + this.builder?.getProjectId(), + this.builder?.getDbAlias(), + 'nc_audit', + { + model_name: this._tn, + model_id: id, + op_type: 'DATA', + op_sub_type: 'INSERT', + description: `${id} inserted into ${this._tn}`, + // details: JSON.stringify(data), + ip: req?.clientIp, + user: req?.user?.email + } + ); } public async beforeUpdate(data: any, _trx: any, req): Promise { + req = req || {}; + req['oldData'] = await this.readByPk(req['params'].id); await this.handleHooks('before.update', data, req); } public async afterUpdate(data: any, _trx: any, req): Promise { + this.builder + .getXcMeta() + .audit( + this.builder?.getProjectId(), + this.builder?.getDbAlias(), + 'nc_audit', + { + model_name: this._tn, + model_id: req['params'].id, + op_type: 'DATA', + op_sub_type: 'UPDATE', + description: this._updateAuditDescription( + req['params'].id, + req['oldData'], + req['body'] + ), + details: this._updateAuditDetails(req['oldData'], req['body']), + ip: req.clientIp, + user: req.user?.email + } + ); await this.handleHooks('after.update', data, req); } + private _updateAuditDescription(id, oldData: any, data: any) { + return `Table ${this._tn} : ${id} ${(() => { + const keys = Object.keys(data); + const result = []; + keys.forEach(key => { + if (oldData[key] !== data[key]) { + result.push( + `field ${key} got changed from ${oldData[key]} to ${data[key]}` + ); + } + }); + return result.join(',\n'); + })()}`; + } + + private _updateAuditDetails(oldData: any, data: any) { + return (() => { + const keys = Object.keys(data); + const result = []; + keys.forEach(key => { + if (oldData[key] !== data[key]) { + result.push(`${key} + : ${oldData[key]} + ${data[key]}`); + } + }); + return result.join(',
'); + })(); + } + public async beforeDelete(data: any, _trx: any, req): Promise { await this.handleHooks('before.delete', data, req); } public async afterDelete(data: any, _trx: any, req): Promise { - if (req?.headers?.['xc-gui']) { - this.builder - .getXcMeta() - .audit( - this.builder?.getProjectId(), - this.builder?.getDbAlias(), - 'nc_audit', - { - model_name: this._tn, - model_id: req?.params?.id, - op_type: 'DATA', - op_sub_type: 'DELETE', - description: `${req?.params.id} deleted from ${this._tn}`, - ip: req?.clientIp, - user: req?.user?.email - } - ); - } + this.builder + .getXcMeta() + .audit( + this.builder?.getProjectId(), + this.builder?.getDbAlias(), + 'nc_audit', + { + model_name: this._tn, + model_id: req?.params?.id, + op_type: 'DATA', + op_sub_type: 'DELETE', + description: `${req?.params.id} deleted from ${this._tn}`, + ip: req?.clientIp, + user: req?.user?.email + } + ); await this.handleHooks('after.delete', data, req); } From da45cc38a5ddebc4ef7b32ee80c5d32368abbac8 Mon Sep 17 00:00:00 2001 From: Vijay Kumar Rathore Date: Mon, 21 Mar 2022 15:14:02 +0100 Subject: [PATCH 2/2] correct audit logs when primary key is not id column Signed-off-by: Vijay Kumar Rathore --- packages/nocodb/src/lib/dataMapper/lib/sql/BaseModelSql.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/nocodb/src/lib/dataMapper/lib/sql/BaseModelSql.ts b/packages/nocodb/src/lib/dataMapper/lib/sql/BaseModelSql.ts index 1723b1ed58..ff2d9aa546 100644 --- a/packages/nocodb/src/lib/dataMapper/lib/sql/BaseModelSql.ts +++ b/packages/nocodb/src/lib/dataMapper/lib/sql/BaseModelSql.ts @@ -309,12 +309,13 @@ class BaseModelSql extends BaseModel { response = data; } } else if (ai) { - response = await this.nestedRead( + const nestedResponse = await this.nestedRead( Array.isArray(response) ? response?.[0]?.[ai._cn] : response?.[ai._cn], this.defaultNestedBtQueryParams ); + response = !_.isEmpty(nestedResponse) ? nestedResponse : response; } if (Array.isArray(response)) {