Skip to content

Commit

Permalink
feat(audit-service): add support for multiple actedon and actiongroup (
Browse files Browse the repository at this point in the history
…#2124)

add support for multiple actedon and actiongroup

GH-2119

Co-authored-by: yeshamavani <[email protected]>
  • Loading branch information
Surbhi-sharma1 and yeshamavani committed Jul 2, 2024
1 parent 5ef082c commit 2a2891d
Show file tree
Hide file tree
Showing 8 changed files with 252 additions and 37 deletions.
16 changes: 15 additions & 1 deletion services/audit-service/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"info": {
"title": "Audit Service",
"version": "1.0.0",
"description": "Audit logging microservice",
"description": "Audit logging Microservice",
"contact": {
"name": "Sourcefuse"
}
Expand Down Expand Up @@ -544,6 +544,20 @@
},
"actedOn": {
"type": "string"
},
"actedOnList": {
"type": "array",
"uniqueItems": true,
"items": {
"type": "string"
}
},
"actionGroupList": {
"type": "array",
"uniqueItems": true,
"items": {
"type": "string"
}
}
},
"additionalProperties": false,
Expand Down
36 changes: 31 additions & 5 deletions services/audit-service/openapi.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ headingLevel: 2

> Scroll down for code samples, example requests and responses. Select a language for code samples from the tabs above or the mobile navigation menu.
Audit logging microservice
Audit logging Microservice

Base URLs:

Expand All @@ -46,7 +46,13 @@ const inputBody = '{
},
"deleted": true,
"entityId": "string",
"actedOn": "string"
"actedOn": "string",
"actedOnList": [
"string"
],
"actionGroupList": [
"string"
]
}';
const headers = {
'Content-Type':'application/json',
Expand Down Expand Up @@ -77,7 +83,13 @@ const inputBody = {
},
"deleted": true,
"entityId": "string",
"actedOn": "string"
"actedOn": "string",
"actedOnList": [
"string"
],
"actionGroupList": [
"string"
]
};
const headers = {
'Content-Type':'application/json',
Expand Down Expand Up @@ -116,7 +128,13 @@ fetch('/audit-logs/archive',
},
"deleted": true,
"entityId": "string",
"actedOn": "string"
"actedOn": "string",
"actedOnList": [
"string"
],
"actionGroupList": [
"string"
]
}
```

Expand Down Expand Up @@ -953,7 +971,13 @@ AuditLogWithRelations
},
"deleted": true,
"entityId": "string",
"actedOn": "string"
"actedOn": "string",
"actedOnList": [
"string"
],
"actionGroupList": [
"string"
]
}

```
Expand All @@ -970,6 +994,8 @@ CustomFilter
|deleted|boolean|false|none|none|
|entityId|string|false|none|none|
|actedOn|string|false|none|none|
|actedOnList|[string]|false|none|none|
|actionGroupList|[string]|false|none|none|

<h2 id="tocS_loopback.Count">loopback.Count</h2>
<!-- backwards compatibility -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('POST /audit-logs/archive', () => {
afterEach(async () => {
await app.stop();
});
it('archive logs when all 3 parameters are provided and deleted is false', async () => {
it('archive logs when 3 parameters are provided and deleted is false', async () => {
const customFilter: CustomFilter = new CustomFilter({
date: {
fromDate: testFromDate,
Expand All @@ -67,7 +67,7 @@ describe('POST /audit-logs/archive', () => {
actualResult.length + controllerResult.numberOfEntriesArchived,
).to.be.equal(archiveLogs.length);
});
it('archive logs when all 3 parameters are provided and deleted is true', async () => {
it('archive logs when 3 parameters are provided and deleted is true', async () => {
const customFilter: CustomFilter = new CustomFilter({
date: {
fromDate: testFromDate,
Expand Down Expand Up @@ -176,7 +176,7 @@ describe('POST /audit-logs/archive', () => {
actualResult.length + controllerResult.numberOfEntriesArchived,
).to.be.equal(archiveLogs.length);
});
it('archive logs when only actedOn parameter is provided', async () => {
it('archive logs when only date parameter is provided', async () => {
const customFilter: CustomFilter = new CustomFilter({
date: {
fromDate: testFromDate,
Expand Down Expand Up @@ -204,6 +204,58 @@ describe('POST /audit-logs/archive', () => {
const mappingLogFetch = mappingLogRepositoryStub.stubs.create;
mappingLogFetch.resolves(mappingLog);

const controllerResult = await auditLogController.archive(customFilter);
const actualResult = await auditLogRepository.find();
expect(
actualResult.length + controllerResult.numberOfEntriesArchived,
).to.be.equal(archiveLogs.length);
});
it('archive logs when actedOnList parameter is provided', async () => {
const customFilter: CustomFilter = new CustomFilter({
actedOnList: ['Product'],
});
const {auditLogController} = getTestAuditController(app);
const mappingLogRepositoryStub = createStubInstance(MappingLogRepository);
const mappingLogFetch = mappingLogRepositoryStub.stubs.create;
mappingLogFetch.resolves(mappingLog);

const controllerResult = await auditLogController.archive(customFilter);
const actualResult = await auditLogRepository.find();
const expectedIds = ['6'];

expect(actualResult).to.be.containDeep(expectedIds.map(id => ({id})));
expect(
actualResult.length + controllerResult.numberOfEntriesArchived,
).to.be.equal(archiveLogs.length);
});
it('archive logs when actedOnList parameter is provided and deleted is true', async () => {
const customFilter: CustomFilter = new CustomFilter({
actedOnList: ['Product'],
deleted: true,
});
const {auditLogController} = getTestAuditController(app);
const mappingLogRepositoryStub = createStubInstance(MappingLogRepository);
const mappingLogFetch = mappingLogRepositoryStub.stubs.create;
mappingLogFetch.resolves(mappingLog);

const controllerResult = await auditLogController.archive(customFilter);
const actualResult = await auditLogRepository.find();
const expectedIds = ['3', '6'];

expect(actualResult).to.be.containDeep(expectedIds.map(id => ({id})));
expect(
actualResult.length + controllerResult.numberOfEntriesArchived,
).to.be.equal(archiveLogs.length);
});
it('archive logs when actionGroupList parameter is provided', async () => {
const customFilter: CustomFilter = new CustomFilter({
actionGroupList: ['Product_group'],
});
const {auditLogController} = getTestAuditController(app);
const mappingLogRepositoryStub = createStubInstance(MappingLogRepository);
const mappingLogFetch = mappingLogRepositoryStub.stubs.create;
mappingLogFetch.resolves(mappingLog);

const controllerResult = await auditLogController.archive(customFilter);
const actualResult = await auditLogRepository.find();
expect(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export const archive1: AuditLog[] = [
qty: 0,
deleted: false,
} as JSONObject,
actionGroup: 'Product_group',
}),
new AuditLog({
id: '12',
Expand All @@ -155,6 +156,7 @@ export const archive1: AuditLog[] = [
qty: 0,
deleted: false,
} as JSONObject,
actionGroup: 'Product_group',
}),
new AuditLog({
id: '13',
Expand All @@ -172,6 +174,7 @@ export const archive1: AuditLog[] = [
qty: 0,
deleted: false,
} as JSONObject,
actionGroup: 'Product_group',
}),
];
export const archive2: AuditLog[] = [
Expand Down
25 changes: 25 additions & 0 deletions services/audit-service/src/models/custom-filter.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,31 @@ export class CustomFilter extends CoreModel<CustomFilter> {
type: 'string',
})
actedOn?: string;

/** Both actedOnList and actionGroupList parameters accepts a
* list of values that you want to archive */

@property({
jsonSchema: {
type: 'array',
uniqueItems: true,
items: {
type: 'string',
},
},
})
actedOnList?: string[]; //to avoid breaking change

@property({
jsonSchema: {
type: 'array',
uniqueItems: true,
items: {
type: 'string',
},
},
})
actionGroupList?: string[];
}

export type CustomFilterWithRelations = CustomFilter;
74 changes: 48 additions & 26 deletions services/audit-service/src/services/job-processing.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import {BindingScope, inject, injectable} from '@loopback/core';
import {EntityCrudRepository, Filter, repository} from '@loopback/repository';
import {
AnyObject,
EntityCrudRepository,
Filter,
repository,
} from '@loopback/repository';
import {HttpErrors} from '@loopback/rest';
import {FileStatusKey} from '../enums/file-status-key.enum';
import {OperationKey} from '../enums/operation-key.enum';
Expand All @@ -24,6 +29,12 @@ import {
ColumnBuilderFn,
QuerySelectedFilesFn,
} from '../types';
import {
checkActedOn,
checkActionGroup,
checkDates,
checkEntityId,
} from '../utils/file-check';
@injectable({scope: BindingScope.TRANSIENT})
export class JobProcessingService {
constructor(
Expand Down Expand Up @@ -51,38 +62,18 @@ export class JobProcessingService {
const customFilter = new CustomFilter();
if (filter?.where && 'and' in filter.where) {
const andArray = filter.where?.and;
for (const condition of andArray) {
if (condition.actedAt?.between) {
const [start, end] = condition.actedAt.between;
customFilter.date = {
fromDate: start,
toDate: end,
};
}
if (condition.actedOn) {
customFilter.actedOn = condition.actedOn;
}
if (condition.entityId) {
customFilter.entityId = condition.entityId;
}
}
this.buildCustomFilter(andArray, customFilter);
}
const mappingLogs: MappingLog[] = await this.mappingLogRepository.find();
const finalData: AuditLog[] = [];
/*Creating a for loop over all the archived files*/
for (const mappingLog of mappingLogs) {
const filterUsed: CustomFilter = mappingLog.filterUsed as CustomFilter;
if (
(customFilter.actedOn == null ||
filterUsed.actedOn == null ||
filterUsed.actedOn === customFilter.actedOn) &&
(customFilter.entityId ??
filterUsed.entityId ??
filterUsed.entityId === customFilter.entityId) &&
(customFilter.date == null ||
filterUsed.date == null ||
(filterUsed.date?.fromDate <= customFilter.date?.toDate &&
filterUsed.date?.toDate >= customFilter.date?.fromDate))
checkActedOn(filterUsed, customFilter) &&
checkActionGroup(filterUsed, customFilter) &&
checkEntityId(filterUsed, customFilter) &&
checkDates(filterUsed, customFilter)
) {
//logs from s3
finalData.push(
Expand All @@ -106,4 +97,35 @@ export class JobProcessingService {
throw new HttpErrors.UnprocessableEntity(error.message);
}
}
getFilter(inquiredFilter: string | AnyObject): string[] {
if (typeof inquiredFilter === 'string') {
return [inquiredFilter];
} else return inquiredFilter.inq;
}

haveCommonElements(arr1: string[], arr2: string[]): boolean {
return arr1.some(item => arr2.includes(item));
}

buildCustomFilter(andArray: AnyObject[], customFilter: CustomFilter) {
for (const condition of andArray) {
if (condition.actedAt?.between) {
const [start, end] = condition.actedAt.between;
customFilter.date = {
fromDate: start,
toDate: end,
};
}
if (condition.actedOn) {
//even if actedOn is a string, it is converted to an array for easy comparision
customFilter.actedOnList = this.getFilter(condition.actedOn);
}
if (condition.actionGroup) {
customFilter.actionGroupList = this.getFilter(condition.actionGroup);
}
if (condition.entityId) {
customFilter.entityId = condition.entityId;
}
}
}
}
14 changes: 12 additions & 2 deletions services/audit-service/src/utils/construct-where.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,19 @@ export async function constructWhere(customFilter: CustomFilter) {
});
}

if (customFilter.actedOn) {
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
if (customFilter.actedOn || customFilter.actedOnList) {
const array = customFilter.actedOn
? [customFilter.actedOn]
: customFilter.actedOnList;
where.and.push({
actedOn: customFilter.actedOn,
actedOn: {inq: array},
});
}

if (customFilter.actionGroupList) {
where.and.push({
actionGroup: {inq: customFilter.actionGroupList},
});
}
return where;
Expand Down
Loading

0 comments on commit 2a2891d

Please sign in to comment.