Browse Source

Merge pull request #1457 from finn-auto/audit-logs-apis

Audit logs for apis
pull/1521/head
աɨռɢӄաօռɢ 2 years ago committed by GitHub
parent
commit
98c7216549
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      packages/nc-gui/components/project/spreadsheet/apis/restApi.js
  2. 8
      packages/nc-gui/plugins/ncApis/restApi.js
  3. 3
      packages/nocodb/src/lib/dataMapper/lib/sql/BaseModelSql.ts
  4. 125
      packages/nocodb/src/lib/noco/common/BaseModel.ts

8
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
}

8
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
}

3
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)) {

125
packages/nocodb/src/lib/noco/common/BaseModel.ts

@ -26,59 +26,108 @@ class BaseModel<T extends BaseApiBuilder<any>> extends BaseModelSql {
public async afterInsert(data: any, _trx: any, req): Promise<void> {
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<void> {
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<void> {
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(`<span class="">${key}</span>
: <span class="text-decoration-line-through red px-2 lighten-4 black--text">${oldData[key]}</span>
<span class="black--text green lighten-4 px-2">${data[key]}</span>`);
}
});
return result.join(',<br/>');
})();
}
public async beforeDelete(data: any, _trx: any, req): Promise<void> {
await this.handleHooks('before.delete', data, req);
}
public async afterDelete(data: any, _trx: any, req): Promise<void> {
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);
}

Loading…
Cancel
Save