tango-app-api-audit 1.0.5 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +3 -1
- package/package.json +2 -2
- package/src/controllers/audit.controllers.js +76 -5
- package/src/controllers/auditMetrics.controllers.js +1 -0
- package/src/controllers/client.controllers.js +42 -0
- package/src/docs/audit.docs.js +52 -2
- package/src/docs/client.docs.js +33 -0
- package/src/dtos/audit.dtos.js +24 -0
- package/src/dtos/auditMetrics.dtos.js +1 -1
- package/src/dtos/client.dtos.js +13 -0
- package/src/routes/audit.routes.js +8 -6
- package/src/routes/client.routes.js +10 -0
- package/src/service/client.service.js +4 -0
- package/src/validation/audit.validation.js +43 -1
package/index.js
CHANGED
|
@@ -4,8 +4,10 @@ import { auditRouter } from './src/routes/audit.routes.js';
|
|
|
4
4
|
import { auditMetricsRouter } from './src/routes/auditMetrics.routes.js';
|
|
5
5
|
import { auditMetricsDocs } from './src/docs/auditMetrics.docs.js';
|
|
6
6
|
import { auditDocs } from './src/docs/audit.docs.js';
|
|
7
|
+
import clientRouter from './src/routes/client.routes.js';
|
|
8
|
+
import { clientDocs } from './src/docs/client.docs.js';
|
|
7
9
|
|
|
8
10
|
|
|
9
|
-
export { auditRouter, auditMetricsRouter, auditMetricsDocs, auditDocs };
|
|
11
|
+
export { auditRouter, auditMetricsRouter, auditMetricsDocs, auditDocs, clientRouter, clientDocs };
|
|
10
12
|
|
|
11
13
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tango-app-api-audit",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "audit & audit metrics apis",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"nodemon": "^3.1.3",
|
|
24
24
|
"swagger-ui-express": "^5.0.1",
|
|
25
25
|
"tango-api-schema": "^2.0.117",
|
|
26
|
-
"tango-app-api-middleware": "^3.1.
|
|
26
|
+
"tango-app-api-middleware": "^3.1.23",
|
|
27
27
|
"winston": "^3.13.0",
|
|
28
28
|
"winston-daily-rotate-file": "^5.0.0"
|
|
29
29
|
},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { chunkArray, getJsonFileData, getUTC, listFileByPath, listFileWithoutLimit, signedUrl } from 'tango-app-api-middleware';
|
|
1
|
+
import { chunkArray, getJsonFileData, getOpenSearchData, getUTC, insertOpenSearchData, listFileByPath, listFileWithoutLimit, signedUrl } from 'tango-app-api-middleware';
|
|
2
2
|
import { aggregateUserAudit, createUserAudit, findOneUserAudit, updateOneUserAudit } from '../service/userAudit.service.js';
|
|
3
3
|
import { aggregateAssignAudit, updateOneAssignAudit } from '../service/assignAudit.service.js';
|
|
4
4
|
import { findOneUser } from '../service/user.service.js';
|
|
@@ -248,8 +248,10 @@ export async function getAuditFile( req, res ) {
|
|
|
248
248
|
if ( inputData.nextId ) {
|
|
249
249
|
fetchData.ContinuationToken = decodeURIComponent( inputData.nextId );
|
|
250
250
|
}
|
|
251
|
-
const
|
|
252
|
-
|
|
251
|
+
const list = await listFileByPath( fetchData );
|
|
252
|
+
const folderPath = list.data;
|
|
253
|
+
const nextQuery = list.pageToken;
|
|
254
|
+
logger.info( { nextQuery: folderPath } );
|
|
253
255
|
if ( folderPath?.length > 0 ) {
|
|
254
256
|
for ( let i = 0; i < folderPath.length; i++ ) {
|
|
255
257
|
const img = folderPath[i].Key.split( '/' );
|
|
@@ -745,7 +747,9 @@ export async function getQueueDetailList( req, res ) {
|
|
|
745
747
|
|
|
746
748
|
export async function saveDraft( req, res ) {
|
|
747
749
|
try {
|
|
750
|
+
const openSearch = JSON.parse( process.env.OPENSEARCH );
|
|
748
751
|
const inputData = req.body;
|
|
752
|
+
inputData.userId = req.user._id;
|
|
749
753
|
const getUserAuditData = await findOneUserAudit( { _id: inputData.auditId } );
|
|
750
754
|
if ( !getUserAuditData ) {
|
|
751
755
|
return res.sendError( 'No Data Found', 204 );
|
|
@@ -797,15 +801,82 @@ export async function saveDraft( req, res ) {
|
|
|
797
801
|
auditId: inputData.auditId,
|
|
798
802
|
},
|
|
799
803
|
};
|
|
804
|
+
await insertOpenSearchData( openSearch.activityLog, logData );
|
|
800
805
|
logger.info( { logData: logData } ); // need to insert to os
|
|
801
806
|
}
|
|
802
|
-
|
|
807
|
+
await insertOpenSearchData( openSearch.auditLog, inputData );
|
|
803
808
|
await updateOneUserAudit( userQuery, userRecord );
|
|
804
809
|
await updateOneStoreAudit( storeQuery, storeRecord );
|
|
805
|
-
return res.sendSuccess(
|
|
810
|
+
return res.sendSuccess( { result: 'The file has been drafted successfully' } );
|
|
806
811
|
} catch ( error ) {
|
|
807
812
|
const err = error.message || 'Internal Server Error';
|
|
808
813
|
logger.error( { error: error, message: req.body, function: 'saveDraft' } );
|
|
809
814
|
return res.sendError( err, 500 );
|
|
810
815
|
}
|
|
811
816
|
}
|
|
817
|
+
|
|
818
|
+
export async function getDraftedData( req, res ) {
|
|
819
|
+
try {
|
|
820
|
+
const openSearch = JSON.parse( process.env.OPENSEARCH );
|
|
821
|
+
const inputData = req.query;
|
|
822
|
+
logger.info( { inputData: inputData } );
|
|
823
|
+
const getLog = await getOpenSearchData( openSearch.auditLog,
|
|
824
|
+
{
|
|
825
|
+
'size': 1,
|
|
826
|
+
'query': {
|
|
827
|
+
'bool': {
|
|
828
|
+
'must': [
|
|
829
|
+
{
|
|
830
|
+
'term': {
|
|
831
|
+
'fileDate.keyword': inputData.fileDate,
|
|
832
|
+
},
|
|
833
|
+
},
|
|
834
|
+
{
|
|
835
|
+
'term': {
|
|
836
|
+
'storeId.keyword': inputData.storeId,
|
|
837
|
+
},
|
|
838
|
+
},
|
|
839
|
+
{
|
|
840
|
+
'term': {
|
|
841
|
+
'userId.keyword': req.user._id,
|
|
842
|
+
},
|
|
843
|
+
},
|
|
844
|
+
|
|
845
|
+
],
|
|
846
|
+
|
|
847
|
+
},
|
|
848
|
+
},
|
|
849
|
+
|
|
850
|
+
'sort': [
|
|
851
|
+
{
|
|
852
|
+
'timestamp': {
|
|
853
|
+
'order': 'desc',
|
|
854
|
+
},
|
|
855
|
+
},
|
|
856
|
+
],
|
|
857
|
+
|
|
858
|
+
} );
|
|
859
|
+
const result = getLog?.body?.hits?.hits;
|
|
860
|
+
if ( result.length ==0 ) {
|
|
861
|
+
return res.sendError( 'No Data Found', 500 );
|
|
862
|
+
}
|
|
863
|
+
return res.sendSuccess( { result: result } );
|
|
864
|
+
} catch ( error ) {
|
|
865
|
+
const err = error.message || 'Internal Server Error';
|
|
866
|
+
logger.error( { error: error, message: req.query, function: 'getDraftedData' } );
|
|
867
|
+
return res.sendError( err, 500 );
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
export async function save( req, res ) {
|
|
872
|
+
try {
|
|
873
|
+
const inputData = req.body;
|
|
874
|
+
return res.sendSuccess( { result: inputData } );
|
|
875
|
+
} catch ( error ) {
|
|
876
|
+
const err= error.message || 'Internal Server Error';
|
|
877
|
+
logger.error( { error: error, message: req.body, function: 'save' } );
|
|
878
|
+
return res.sendError( err );
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { logger } from 'tango-app-api-middleware';
|
|
2
|
+
import { aggregateClient } from '../service/client.service.js';
|
|
3
|
+
|
|
4
|
+
export async function clients( req, res ) {
|
|
5
|
+
try {
|
|
6
|
+
const inputData = req.query;
|
|
7
|
+
const query =[
|
|
8
|
+
{
|
|
9
|
+
$match: {
|
|
10
|
+
'status': { $in: [ 'active', 'hold' ] },
|
|
11
|
+
'auditConfigs.audit': true,
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
$project: {
|
|
16
|
+
_id: 0,
|
|
17
|
+
clientName: 1,
|
|
18
|
+
clientId: 1,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const count = await aggregateClient( query );
|
|
24
|
+
if ( count.length == 0 ) {
|
|
25
|
+
return res.sendError( 'No Data Found', 204 );
|
|
26
|
+
}
|
|
27
|
+
if ( inputData.limit ) {
|
|
28
|
+
const offset = inputData.offset ? ( inputData.offset - 1 ) * inputData.limit : 0;
|
|
29
|
+
query.push(
|
|
30
|
+
{ $skip: offset },
|
|
31
|
+
{ $limit: limit },
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
const getAuditClients = await aggregateClient( query );
|
|
35
|
+
|
|
36
|
+
return res.sendSuccess( { result: getAuditClients, count: count.length } );
|
|
37
|
+
} catch ( error ) {
|
|
38
|
+
const err = error.message || 'Internal Server Error';
|
|
39
|
+
logger.info( { error: error, messgae: req.query, function: 'clients' } );
|
|
40
|
+
return res.sendError( err, 500 );
|
|
41
|
+
}
|
|
42
|
+
}
|
package/src/docs/audit.docs.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getFileSchema, saveDraftSchema } from '../dtos/audit.dtos.js';
|
|
1
|
+
import { getDraftedDataSchema, getFileSchema, saveDraftSchema, saveSchema } from '../dtos/audit.dtos.js';
|
|
2
2
|
import j2s from 'joi-to-swagger';
|
|
3
3
|
|
|
4
4
|
export const auditDocs = {
|
|
@@ -28,7 +28,7 @@ export const auditDocs = {
|
|
|
28
28
|
},
|
|
29
29
|
],
|
|
30
30
|
responses: {
|
|
31
|
-
200: { description: '
|
|
31
|
+
200: { description: 'Successful' },
|
|
32
32
|
401: { description: 'Unauthorized User' },
|
|
33
33
|
422: { description: 'Field Error' },
|
|
34
34
|
500: { description: 'Server Error' },
|
|
@@ -58,4 +58,54 @@ export const auditDocs = {
|
|
|
58
58
|
},
|
|
59
59
|
},
|
|
60
60
|
},
|
|
61
|
+
'/v3/audit/get-drafted-data': {
|
|
62
|
+
get: {
|
|
63
|
+
tags: [ 'Audit' ],
|
|
64
|
+
description: 'Get a saved file via DB',
|
|
65
|
+
operationId: 'get-drafted-data',
|
|
66
|
+
parameters: [
|
|
67
|
+
{
|
|
68
|
+
in: 'query',
|
|
69
|
+
name: 'fileDate',
|
|
70
|
+
scema: j2s( getDraftedDataSchema ).swagger,
|
|
71
|
+
require: true,
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
in: 'query',
|
|
75
|
+
name: 'storeId',
|
|
76
|
+
scema: j2s( getDraftedDataSchema ).swagger,
|
|
77
|
+
require: false,
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
responses: {
|
|
81
|
+
200: { description: 'Successful' },
|
|
82
|
+
401: { description: 'Unauthorized User' },
|
|
83
|
+
422: { description: 'Field Error' },
|
|
84
|
+
500: { description: 'Server Error' },
|
|
85
|
+
204: { description: 'Not Found' },
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
'/v3/audit/save': {
|
|
90
|
+
post: {
|
|
91
|
+
tags: [ 'Audit' ],
|
|
92
|
+
description: `submit the audit file. which is store in the bucket in the json format`,
|
|
93
|
+
operationId: 'save',
|
|
94
|
+
parameters: {},
|
|
95
|
+
requestBody: {
|
|
96
|
+
content: {
|
|
97
|
+
'application/json': {
|
|
98
|
+
schema: j2s( saveSchema ).swagger,
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
responses: {
|
|
103
|
+
200: { description: 'The Audited file has been submited successfully ' },
|
|
104
|
+
401: { description: 'Unauthorized User' },
|
|
105
|
+
422: { description: 'Field Error' },
|
|
106
|
+
500: { description: 'Server Error' },
|
|
107
|
+
204: { description: 'Not Found' },
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
},
|
|
61
111
|
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import j2s from 'joi-to-swagger';
|
|
2
|
+
import { clientSchema } from '../dtos/client.dtos.js';
|
|
3
|
+
|
|
4
|
+
export const clientDocs = {
|
|
5
|
+
'/v3/audit/client/clients': {
|
|
6
|
+
get: {
|
|
7
|
+
tags: [ 'Audit/Client' ],
|
|
8
|
+
description: 'Get client list which is enable for audit',
|
|
9
|
+
operationId: 'clients',
|
|
10
|
+
parameters: [
|
|
11
|
+
{
|
|
12
|
+
in: 'query',
|
|
13
|
+
name: 'limit',
|
|
14
|
+
scema: j2s( clientSchema ).swagger,
|
|
15
|
+
require: false,
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
in: 'query',
|
|
19
|
+
name: 'offset',
|
|
20
|
+
scema: j2s( clientSchema ).swagger,
|
|
21
|
+
require: false,
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
responses: {
|
|
25
|
+
200: { description: 'Successful' },
|
|
26
|
+
401: { description: 'Unauthorized User' },
|
|
27
|
+
422: { description: 'Field Error' },
|
|
28
|
+
500: { description: 'Server Error' },
|
|
29
|
+
204: { description: 'Not Found' },
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
};
|
package/src/dtos/audit.dtos.js
CHANGED
|
@@ -29,6 +29,7 @@ export const saveDraftSchema = joi.object(
|
|
|
29
29
|
customerCount: joi.number().optional(),
|
|
30
30
|
customer: joi.array().optional(),
|
|
31
31
|
retagCount: joi.number().optional(),
|
|
32
|
+
retagImage: joi.array().optional(),
|
|
32
33
|
},
|
|
33
34
|
);
|
|
34
35
|
|
|
@@ -36,6 +37,29 @@ export const saveDraftValid = {
|
|
|
36
37
|
body: saveDraftSchema,
|
|
37
38
|
};
|
|
38
39
|
|
|
40
|
+
export const getDraftedDataSchema = joi.object(
|
|
41
|
+
{
|
|
42
|
+
storeId: joi.string().required(),
|
|
43
|
+
fileDate: joi.string().required(),
|
|
44
|
+
},
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
export const getDraftedDataValid = {
|
|
48
|
+
query: getDraftedDataSchema,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const saveSchema = joi.object(
|
|
52
|
+
{
|
|
53
|
+
auditId: joi.string().required(),
|
|
54
|
+
storeId: joi.string().required(),
|
|
55
|
+
fileDate: joi.string().required(),
|
|
56
|
+
},
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
export const saveValid = {
|
|
60
|
+
body: saveSchema,
|
|
61
|
+
};
|
|
62
|
+
|
|
39
63
|
export const getQueueDetailListSchema = joi.object(
|
|
40
64
|
{
|
|
41
65
|
searchValue: joi.string().optional(),
|
|
@@ -47,7 +47,7 @@ export const clientMetricsSchema = joi.object(
|
|
|
47
47
|
toDate: joi.string().required(),
|
|
48
48
|
searchValue: joi.string().optional(),
|
|
49
49
|
filterByClient: joi.array().required(),
|
|
50
|
-
|
|
50
|
+
filterByStatus: joi.array().optional(),
|
|
51
51
|
sortColumnName: joi.string().optional(),
|
|
52
52
|
sortBy: joi.number().optional(),
|
|
53
53
|
limit: joi.number().optional(),
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
|
-
import { isExistsQueue } from '../validation/audit.validation.js';
|
|
2
|
+
import { isExistsQueue, validateUserAudit } from '../validation/audit.validation.js';
|
|
3
3
|
import { isAllowedSessionHandler, validate } from 'tango-app-api-middleware';
|
|
4
|
-
import { getAuditFile, getQueueDetailList, saveDraft } from '../controllers/audit.controllers.js';
|
|
5
|
-
import { getFileValid, getQueueDetailListValid, saveDraftValid } from '../dtos/audit.dtos.js';
|
|
4
|
+
import { getAuditFile, getDraftedData, getQueueDetailList, save, saveDraft } from '../controllers/audit.controllers.js';
|
|
5
|
+
import { getDraftedDataValid, getFileValid, getQueueDetailListValid, saveDraftValid, saveValid } from '../dtos/audit.dtos.js';
|
|
6
6
|
|
|
7
7
|
export const auditRouter = express.Router();
|
|
8
8
|
|
|
9
|
-
auditRouter.get( '/get-file', validate( getFileValid ),
|
|
10
|
-
auditRouter.post( '/save-draft', validate( saveDraftValid ),
|
|
11
|
-
auditRouter.get( '/get-
|
|
9
|
+
auditRouter.get( '/get-file', isAllowedSessionHandler, validate( getFileValid ), isExistsQueue, getAuditFile );
|
|
10
|
+
auditRouter.post( '/save-draft', isAllowedSessionHandler, validate( saveDraftValid ), saveDraft );
|
|
11
|
+
auditRouter.get( '/get-drafted-data', isAllowedSessionHandler, validate( getDraftedDataValid ), getDraftedData );
|
|
12
|
+
auditRouter.post( '/save', isAllowedSessionHandler, validate( saveValid ), validateUserAudit, save );
|
|
13
|
+
auditRouter.get( '/get-queue-detail-list', isAllowedSessionHandler, validate( getQueueDetailListValid ), getQueueDetailList );
|
|
12
14
|
|
|
13
15
|
export default auditRouter;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { isAllowedSessionHandler, validate } from 'tango-app-api-middleware';
|
|
3
|
+
import { clients } from '../controllers/client.controllers.js';
|
|
4
|
+
import { clientValid } from '../dtos/client.dtos.js';
|
|
5
|
+
|
|
6
|
+
export const clientRouter = Router();
|
|
7
|
+
|
|
8
|
+
clientRouter.get( '/clients', isAllowedSessionHandler, validate( clientValid ), clients );
|
|
9
|
+
|
|
10
|
+
export default clientRouter;
|
|
@@ -4,3 +4,7 @@ import clientModel from 'tango-api-schema/schema/client.model.js';
|
|
|
4
4
|
export function aggregateClient( query ) {
|
|
5
5
|
return clientModel.aggregate( query, { collation: { locale: 'en', strength: 2 } } );
|
|
6
6
|
}
|
|
7
|
+
|
|
8
|
+
export function findClient( query, fields, sort={ createdAt: -1 } ) {
|
|
9
|
+
return clientModel.find( query, fields ).sort( sort );
|
|
10
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { getQueueUrl, logger } from 'tango-app-api-middleware';
|
|
1
|
+
import { checkFileExist, getQueueUrl, logger } from 'tango-app-api-middleware';
|
|
2
|
+
import { findOneUserAudit } from '../service/userAudit.service.js';
|
|
2
3
|
|
|
3
4
|
export async function isExistsQueue( req, res, next ) {
|
|
4
5
|
try {
|
|
@@ -14,3 +15,44 @@ export async function isExistsQueue( req, res, next ) {
|
|
|
14
15
|
return res.sendError( error, 500 );
|
|
15
16
|
}
|
|
16
17
|
}
|
|
18
|
+
|
|
19
|
+
export async function validateUserAudit( req, res, next ) {
|
|
20
|
+
try {
|
|
21
|
+
const inputData = req.body;
|
|
22
|
+
const userAuditDetails = findOneUserAudit( { _id: inputData.auditId } );
|
|
23
|
+
if ( !userAuditDetails ) {
|
|
24
|
+
return res.sendError( 'No Data Available' );
|
|
25
|
+
} else if ( userAuditDetails && userAuditDetails.auditStatus == 'skipped' ) {
|
|
26
|
+
return res.sendError( 'The Audit file Assigned to some one else', 203 );
|
|
27
|
+
}
|
|
28
|
+
req.body.userAudit = userAuditDetails;
|
|
29
|
+
next();
|
|
30
|
+
} catch ( error ) {
|
|
31
|
+
const err = error.message || 'Internal Server Error';
|
|
32
|
+
logger.error( { error: error, message: req.query, function: 'validateUserAudit' } );
|
|
33
|
+
return res.sendError( err, 500 );
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function isMasterJsonExists( req, res, next ) {
|
|
38
|
+
try {
|
|
39
|
+
const bucket = JSON.parse( process.env.BUCKET );
|
|
40
|
+
const inputData = req.body;
|
|
41
|
+
params={
|
|
42
|
+
Bucket: bucket.masterJson,
|
|
43
|
+
Key: `${inputData.storeId}/${inputData.fileDate}/${bucket.masterJsonFile}`,
|
|
44
|
+
};
|
|
45
|
+
const isExist = await checkFileExist( params );
|
|
46
|
+
if ( isExist ) {
|
|
47
|
+
next();
|
|
48
|
+
} else {
|
|
49
|
+
return res.sendError( `NO_MASTER_JSON_AVAILABLE : ${inputData.storeId}/${inputData.fileDate}/${bucketName.masterJsonFile}`, 400 );
|
|
50
|
+
}
|
|
51
|
+
} catch ( error ) {
|
|
52
|
+
const err = error.message || 'Internal Server Error';
|
|
53
|
+
logger.error( { error: error, message: req.query, function: 'isMasterJsonExists' } );
|
|
54
|
+
return res.sendError( err, 500 );
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|