tango-app-api-infra 3.0.39-dev → 3.0.41-dev
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/app.js +41 -0
- package/package.json +6 -5
- package/src/controllers/infra.controllers.js +105 -7
- package/src/controllers/internalInfra.controller.js +337 -9
- package/src/hbs/closeTicekt.hbs +289 -0
- package/src/hbs/createTicket.hbs +288 -0
- package/src/hbs/dailyInfraReport.hbs +315 -0
- package/src/hbs/refreshTicket.hbs +292 -0
- package/src/routes/internalInfra.routes.js +2 -1
- package/src/validations/infra.validation.js +7 -1
package/app.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
|
|
2
|
+
import express from 'express';
|
|
3
|
+
import { infraRouter, internalInfraRouter, userInfraRouter, storeInfraRouter, clientInfraRouter } from './index.js';
|
|
4
|
+
import dotenv from 'dotenv';
|
|
5
|
+
import responseMiddleware from './config/response/response.js';
|
|
6
|
+
import errorMiddleware from './config/response/error.js';
|
|
7
|
+
import { connectdb } from './config/database/database.js';
|
|
8
|
+
import pkg from 'body-parser';
|
|
9
|
+
import cors from 'cors';
|
|
10
|
+
const { json, urlencoded } = pkg;
|
|
11
|
+
import fileUpload from 'express-fileupload';
|
|
12
|
+
const env=dotenv.config();
|
|
13
|
+
const app = express();
|
|
14
|
+
const PORT = process.env.PORT || 3000;
|
|
15
|
+
app.use( fileUpload() );
|
|
16
|
+
|
|
17
|
+
if ( env.error ) {
|
|
18
|
+
logger.error( '.env not found' );
|
|
19
|
+
process.exit( 1 );
|
|
20
|
+
}
|
|
21
|
+
app.use( json( { limit: '500mb' } ) );
|
|
22
|
+
app.use(
|
|
23
|
+
urlencoded( {
|
|
24
|
+
extended: true,
|
|
25
|
+
} ),
|
|
26
|
+
);
|
|
27
|
+
app.use( cors() );
|
|
28
|
+
app.use( responseMiddleware );
|
|
29
|
+
app.use( errorMiddleware );
|
|
30
|
+
app.use( '/infra', infraRouter );
|
|
31
|
+
app.use( '/internalInfra', internalInfraRouter );
|
|
32
|
+
app.use( '/userInfra', userInfraRouter );
|
|
33
|
+
app.use( '/storeInfra', storeInfraRouter );
|
|
34
|
+
app.use( '/clientInfra', clientInfraRouter );
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
app.listen( PORT, () => {
|
|
38
|
+
console.log( `server is running on port= ${PORT} ` );
|
|
39
|
+
connectdb();
|
|
40
|
+
} );
|
|
41
|
+
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tango-app-api-infra",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.41-dev",
|
|
4
4
|
"description": "infra",
|
|
5
|
-
"main": "
|
|
5
|
+
"main": "app.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"start": "nodemon --exec \"eslint --fix . && node
|
|
8
|
+
"start": "nodemon --exec \"eslint --fix . && node app.js\""
|
|
9
9
|
},
|
|
10
10
|
"engines": {
|
|
11
11
|
"node": ">=18.10.0"
|
|
@@ -17,13 +17,14 @@
|
|
|
17
17
|
"cors": "^2.8.5",
|
|
18
18
|
"dayjs": "^1.11.10",
|
|
19
19
|
"dotenv": "^16.4.5",
|
|
20
|
+
"excel4node": "^1.8.2",
|
|
20
21
|
"express": "^4.18.3",
|
|
21
22
|
"express-fileupload": "^1.5.0",
|
|
22
23
|
"handlebars": "^4.7.8",
|
|
23
24
|
"mongodb": "^6.4.0",
|
|
24
25
|
"nodemon": "^3.1.0",
|
|
25
|
-
"tango-api-schema": "^2.0.
|
|
26
|
-
"tango-app-api-middleware": "^1.0.
|
|
26
|
+
"tango-api-schema": "^2.0.77",
|
|
27
|
+
"tango-app-api-middleware": "^1.0.54-dev",
|
|
27
28
|
"winston": "^3.12.0",
|
|
28
29
|
"winston-daily-rotate-file": "^5.0.0"
|
|
29
30
|
},
|
|
@@ -2,11 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
import { createTangoTicket, findOneTangoTicket, updateOneTangoTicket } from '../services/tangoTicket.service.js';
|
|
4
4
|
import { createinfraReason, findinfraReason } from '../services/infraReason.service.js';
|
|
5
|
-
import { updateOneStore } from '../services/store.service.js';
|
|
6
|
-
import { logger, fileUpload, signedUrl } from 'tango-app-api-middleware';
|
|
5
|
+
import { updateOneStore, findStore } from '../services/store.service.js';
|
|
6
|
+
import { logger, fileUpload, signedUrl, sendEmailWithSES, getOpenSearchData, appConfig } from 'tango-app-api-middleware';
|
|
7
7
|
import { aggregateUser, updateOneUser } from '../services/user.service.js';
|
|
8
8
|
import { updateoneClient } from '../services/client.service.js';
|
|
9
9
|
import dayjs from 'dayjs';
|
|
10
|
+
import { readFileSync } from 'fs';
|
|
11
|
+
import { join } from 'path';
|
|
12
|
+
import handlebars from 'handlebars';
|
|
13
|
+
import { findOneGroup } from '../services/group.service.js';
|
|
10
14
|
export async function createTicket( req, res ) {
|
|
11
15
|
try {
|
|
12
16
|
req.body.issueDate = new Date( req.body.Date );
|
|
@@ -22,7 +26,55 @@ export async function createTicket( req, res ) {
|
|
|
22
26
|
if ( req.body.issueType == 'installation' ) {
|
|
23
27
|
req.body.ticketId = 'TE_INS_' + new Date().valueOf();
|
|
24
28
|
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
let downTimeQuery = {
|
|
32
|
+
'size': 1,
|
|
33
|
+
'query': {
|
|
34
|
+
'bool': {
|
|
35
|
+
'must': [
|
|
36
|
+
{
|
|
37
|
+
'term': {
|
|
38
|
+
'doc.date.keyword': dayjs( req.body.issueDate ).format( 'DD-MM-YYYY' ),
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
'term': {
|
|
43
|
+
'doc.store_id.keyword': req.body.basicDetails.storeId,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
],
|
|
48
|
+
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
let downtimetotal;
|
|
53
|
+
const downtime = await getOpenSearchData( 'live_downtime_hourly', downTimeQuery );
|
|
54
|
+
let streamwiseDowntime = downtime.body.hits.hits.length > 0 ? downtime.body.hits.hits[0]._source.doc.streamwise_downtime : [];
|
|
55
|
+
if ( streamwiseDowntime.length > 0 ) {
|
|
56
|
+
const sum = streamwiseDowntime.reduce( ( accumulator, currentValue ) => {
|
|
57
|
+
return accumulator + currentValue.down_time;
|
|
58
|
+
}, 0 );
|
|
59
|
+
const average = sum / streamwiseDowntime.length;
|
|
60
|
+
downtimetotal = Math.round( average );
|
|
61
|
+
} else {
|
|
62
|
+
downtimetotal = 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
25
66
|
let create = await createTangoTicket( req.body );
|
|
67
|
+
let Timestamp = dayjs().format( 'YYYY-MM-DD HH:mm' );
|
|
68
|
+
const attachments = null;
|
|
69
|
+
const subject = `Tango Eye - Ticket Created for ${req.body.basicDetails.storeName}`;
|
|
70
|
+
const fileContent = readFileSync( join() + '/src/hbs/createTicket.hbs', 'utf8' );
|
|
71
|
+
const htmlContent = handlebars.compile( fileContent );
|
|
72
|
+
let Uidomain = `${appConfig.url.domain}/manage/stores/infra-ticket?storeId=${req.body.basicDetails.storeId}`;
|
|
73
|
+
|
|
74
|
+
const html = htmlContent( { ...req.body, Uidomain: Uidomain, domain: appConfig.url.apiDomain, date: dayjs( req.body.issueDate ).format( 'YYYY-MM-DD' ), downtimetotal: downtimetotal, Timestamp: Timestamp } );
|
|
75
|
+
await sendEmailWithSES( req.body.spocEmail, subject, html, attachments, appConfig.cloud.aws.ses.adminEmail );
|
|
76
|
+
|
|
77
|
+
|
|
26
78
|
if ( create ) {
|
|
27
79
|
res.sendSuccess( 'Ticket Created Successfully' );
|
|
28
80
|
}
|
|
@@ -148,7 +200,29 @@ export async function secondaryReason( req, res ) {
|
|
|
148
200
|
|
|
149
201
|
export async function updateTicketIssue( req, res ) {
|
|
150
202
|
try {
|
|
151
|
-
let
|
|
203
|
+
let query = {};
|
|
204
|
+
if ( req.user.userType == 'client' ) {
|
|
205
|
+
query = {
|
|
206
|
+
'ticketActivity': req.body.ticketActivity,
|
|
207
|
+
'cameraList': req.body.cameraList,
|
|
208
|
+
'ticketDetails.issueIdentifiedDate': new Date(),
|
|
209
|
+
'ticketDetails.issueIdentifiedBy': req.body.issueIdentifiedBy,
|
|
210
|
+
'ticketDetails.addressingClient': req.user._id,
|
|
211
|
+
'ticketDetails.issueStatus': 'identified',
|
|
212
|
+
'status': 'inprogress',
|
|
213
|
+
};
|
|
214
|
+
} else {
|
|
215
|
+
query = {
|
|
216
|
+
'ticketActivity': req.body.ticketActivity,
|
|
217
|
+
'cameraList': req.body.cameraList,
|
|
218
|
+
'ticketDetails.issueIdentifiedDate': new Date(),
|
|
219
|
+
'ticketDetails.issueIdentifiedBy': req.body.issueIdentifiedBy,
|
|
220
|
+
'ticketDetails.addressingUser': req.user._id,
|
|
221
|
+
'ticketDetails.issueStatus': 'identified',
|
|
222
|
+
'status': 'inprogress',
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
let updateTicket = await updateOneTangoTicket( { ticketId: req.body.ticketId }, query );
|
|
152
226
|
if ( req.body.ticketDetails.ticketType === 'refreshticket' ) {
|
|
153
227
|
await updateOneTangoTicket( { ticketId: req.body.ticketId }, { 'ticketDetails.refreshTicketStatus': 'identified' } );
|
|
154
228
|
}
|
|
@@ -311,7 +385,7 @@ export async function emailUserList( req, res ) {
|
|
|
311
385
|
$match: {
|
|
312
386
|
userType: 'client',
|
|
313
387
|
clientId: inputData.clientId,
|
|
314
|
-
|
|
388
|
+
role: inputData.role,
|
|
315
389
|
},
|
|
316
390
|
},
|
|
317
391
|
{
|
|
@@ -332,12 +406,15 @@ export async function emailUserList( req, res ) {
|
|
|
332
406
|
{
|
|
333
407
|
$group: {
|
|
334
408
|
_id: null,
|
|
409
|
+
assignedValue: { $push: '$assignedValue' },
|
|
410
|
+
assignedType: { $first: '$assignedType' },
|
|
335
411
|
storeList: { $push: '$assignedValue' },
|
|
336
412
|
},
|
|
337
413
|
},
|
|
338
414
|
{
|
|
339
415
|
$project: {
|
|
340
|
-
|
|
416
|
+
assignedType: 1,
|
|
417
|
+
assignedValue: 1,
|
|
341
418
|
assignedStore: { $size: '$storeList' },
|
|
342
419
|
},
|
|
343
420
|
},
|
|
@@ -353,6 +430,8 @@ export async function emailUserList( req, res ) {
|
|
|
353
430
|
email: 1,
|
|
354
431
|
role: 1,
|
|
355
432
|
emailAlert: 1,
|
|
433
|
+
assignedValue: '$assigned.assignedValue',
|
|
434
|
+
assignedType: { $ifNull: [ '$assigned.assignedType', 0 ] },
|
|
356
435
|
infraAlert: { $ifNull: [ '$emailAlert.infra', false ] },
|
|
357
436
|
assigned: { $ifNull: [ '$assigned.assignedStore', 0 ] },
|
|
358
437
|
isActive: 1,
|
|
@@ -384,6 +463,25 @@ export async function emailUserList( req, res ) {
|
|
|
384
463
|
);
|
|
385
464
|
}
|
|
386
465
|
const result = await aggregateUser( query );
|
|
466
|
+
for ( let user of result ) {
|
|
467
|
+
if ( user.role == 'superadmin' ) {
|
|
468
|
+
let storelist = await findStore( { clientId: inputData.clientId, status: 'active' }, { storeName: 1 } );
|
|
469
|
+
user.assigned = storelist.length;
|
|
470
|
+
user.assignedValue = storelist;
|
|
471
|
+
} else if ( user.role != 'superadmin' ) {
|
|
472
|
+
if ( user.assignedType == 'group' ) {
|
|
473
|
+
for ( let group of user.assignedValue ) {
|
|
474
|
+
let groupdata = await findOneGroup( { groupName: group } );
|
|
475
|
+
let storelist = await findStore( { clientId: inputData.clientId, storeId: { $in: groupdata.storeList } }, { storeName: 1 } );
|
|
476
|
+
user.assigned = storelist.length;
|
|
477
|
+
user.assignedValue = storelist;
|
|
478
|
+
}
|
|
479
|
+
} else if ( user.assignedType == 'store' ) {
|
|
480
|
+
let storelist = await findStore( { clientId: inputData.clientId, storeId: { $in: user.assignedValue } }, { storeName: 1 } );
|
|
481
|
+
user.assignedValue = storelist;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
387
485
|
res.sendSuccess( { count: count.length, result: result } );
|
|
388
486
|
} catch ( error ) {
|
|
389
487
|
logger.error( { error: error, function: 'emailUserList' } );
|
|
@@ -394,13 +492,13 @@ export async function saveInfraEmailConfig( req, res ) {
|
|
|
394
492
|
try {
|
|
395
493
|
let inputData = req.body;
|
|
396
494
|
|
|
397
|
-
|
|
495
|
+
await updateoneClient( { clientId: inputData.clientId }, {
|
|
398
496
|
'ticketConfigs.infraReport': {
|
|
399
497
|
start: inputData.start,
|
|
400
498
|
end: inputData.end,
|
|
401
499
|
},
|
|
402
500
|
} );
|
|
403
|
-
|
|
501
|
+
|
|
404
502
|
if ( inputData.userList && inputData.userList.length > 0 ) {
|
|
405
503
|
for ( let user of inputData.userList ) {
|
|
406
504
|
await updateOneUser( { email: user.email }, {
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
|
|
2
|
-
import { logger } from 'tango-app-api-middleware';
|
|
2
|
+
import { logger, getOpenSearchData, appConfig } from 'tango-app-api-middleware';
|
|
3
3
|
import dayjs from 'dayjs';
|
|
4
4
|
import utc from 'dayjs/plugin/utc.js';
|
|
5
5
|
import timezone from 'dayjs/plugin/timezone.js';
|
|
6
6
|
import 'dayjs/locale/en.js';
|
|
7
|
+
import { readFileSync } from 'fs';
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
import handlebars from 'handlebars';
|
|
7
10
|
dayjs.extend( utc );
|
|
8
11
|
dayjs.extend( timezone );
|
|
12
|
+
import { sendEmailWithSES } from 'tango-app-api-middleware';
|
|
9
13
|
import { createClient, findClient, aggregateClient } from '../services/client.service.js';
|
|
10
|
-
import { createStore, findStore, updateOneStore } from '../services/store.service.js';
|
|
11
|
-
import { findTangoTicket, findOneTangoTicket, updateOneTangoTicket } from '../services/tangoTicket.service.js';
|
|
14
|
+
import { createStore, findStore, updateOneStore, findOneStore } from '../services/store.service.js';
|
|
15
|
+
import { findTangoTicket, findOneTangoTicket, countDocumentsTangoTicket, aggregateTangoTicket, updateOneTangoTicket } from '../services/tangoTicket.service.js';
|
|
12
16
|
import { findOneGroup } from '../services/group.service.js';
|
|
13
|
-
|
|
17
|
+
import { findinfraReason } from '../services/infraReason.service.js';
|
|
18
|
+
import { findOneUser } from '../services/user.service.js';
|
|
19
|
+
import xl from 'excel4node';
|
|
14
20
|
|
|
15
21
|
export async function migrateClient() {
|
|
16
22
|
try {
|
|
@@ -144,8 +150,61 @@ export async function assigntoUser( req, res ) {
|
|
|
144
150
|
export async function updateRefreshTicket( req, res ) {
|
|
145
151
|
try {
|
|
146
152
|
for ( let ticket of req.body.TicketList ) {
|
|
153
|
+
let getTicket = await findOneTangoTicket( { ticketId: ticket.ticketId } );
|
|
147
154
|
await updateOneTangoTicket( { ticketId: ticket.ticketId }, { 'ticketDetails.ticketType': 'refreshticket' } );
|
|
155
|
+
let downTimeQuery = {
|
|
156
|
+
'size': 1,
|
|
157
|
+
'query': {
|
|
158
|
+
'bool': {
|
|
159
|
+
'must': [
|
|
160
|
+
{
|
|
161
|
+
'term': {
|
|
162
|
+
'doc.date.keyword': dayjs( getTicket.issueDate ).format( 'DD-MM-YYYY' ),
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
'term': {
|
|
167
|
+
'doc.store_id.keyword': getTicket.basicDetails.storeId,
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
],
|
|
172
|
+
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
let downtimetotal;
|
|
177
|
+
const downtime = await getOpenSearchData( 'live_downtime_hourly', downTimeQuery );
|
|
178
|
+
let streamwiseDowntime = downtime.body.hits.hits.length > 0 ? downtime.body.hits.hits[0]._source.doc.streamwise_downtime : [];
|
|
179
|
+
if ( streamwiseDowntime.length > 0 ) {
|
|
180
|
+
const sum = streamwiseDowntime.reduce( ( accumulator, currentValue ) => {
|
|
181
|
+
return accumulator + currentValue.down_time;
|
|
182
|
+
}, 0 );
|
|
183
|
+
const average = sum / streamwiseDowntime.length;
|
|
184
|
+
downtimetotal = Math.round( average );
|
|
185
|
+
} else {
|
|
186
|
+
downtimetotal = 0;
|
|
187
|
+
}
|
|
188
|
+
let Timestamp = dayjs().format( 'YYYY-MM-DD HH:mm' );
|
|
189
|
+
const attachments = null;
|
|
190
|
+
const subject = `Tango Eye - Infra Ticket Closed for ${getTicket.basicDetails.storeName} `;
|
|
191
|
+
const fileContent = readFileSync( join() + '/src/hbs/refreshTicket.hbs', 'utf8' );
|
|
192
|
+
const htmlContent = handlebars.compile( fileContent );
|
|
193
|
+
let store = await findOneStore( { storeId: getTicket.basicDetails.storeId } );
|
|
194
|
+
if ( store.spocDetails && store.spocDetails.length > 0 ) {
|
|
195
|
+
let spocEmail = store.spocDetails[0].email;
|
|
196
|
+
let spocName = store.spocDetails[0].name;
|
|
197
|
+
let Issue = getTicket.ticketActivity.filter( ( a ) => a.actionType == 'issueUpdate' );
|
|
198
|
+
let primaryIssue = 'Not Identified';
|
|
199
|
+
if ( Issue.length > 0 && Issue[0].reasons.length > 0 ) {
|
|
200
|
+
primaryIssue = Issue[0].reasons[0].primaryIssue;
|
|
201
|
+
}
|
|
202
|
+
let Uidomain = `${appConfig.url.domain}/manage/stores/infra-ticket?storeId=${getTicket.basicDetails.storeId}`;
|
|
203
|
+
const html = htmlContent( { ...getTicket, Uidomain: Uidomain, primary: primaryIssue, storeName: getTicket.basicDetails.storeName, hibernation: '', spocName: spocName, date: dayjs( getTicket.issueDate ).format( 'YYYY-MM-DD' ), downtimetotal: downtimetotal, Timestamp: Timestamp, domain: appConfig.url.apiDomain } );
|
|
204
|
+
await sendEmailWithSES( spocEmail, subject, html, attachments, appConfig.cloud.aws.ses.adminEmail );
|
|
205
|
+
}
|
|
148
206
|
}
|
|
207
|
+
|
|
149
208
|
res.sendSuccess( 'updated Successfully' );
|
|
150
209
|
} catch ( error ) {
|
|
151
210
|
logger.error( { error: error, function: 'updateRefreshTicket' } );
|
|
@@ -169,7 +228,61 @@ export async function closeTicket( req, res ) {
|
|
|
169
228
|
issueClosedDate: new Date(),
|
|
170
229
|
},
|
|
171
230
|
);
|
|
231
|
+
let downTimeQuery = {
|
|
232
|
+
'size': 1,
|
|
233
|
+
'query': {
|
|
234
|
+
'bool': {
|
|
235
|
+
'must': [
|
|
236
|
+
{
|
|
237
|
+
'term': {
|
|
238
|
+
'doc.date.keyword': dayjs( getTicket.issueDate ).format( 'DD-MM-YYYY' ),
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
'term': {
|
|
243
|
+
'doc.store_id.keyword': getTicket.basicDetails.storeId,
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
|
|
247
|
+
],
|
|
248
|
+
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
};
|
|
252
|
+
let downtimetotal;
|
|
253
|
+
const downtime = await getOpenSearchData( 'live_downtime_hourly', downTimeQuery );
|
|
254
|
+
let streamwiseDowntime = downtime.body.hits.hits.length > 0 ? downtime.body.hits.hits[0]._source.doc.streamwise_downtime : [];
|
|
255
|
+
if ( streamwiseDowntime.length > 0 ) {
|
|
256
|
+
const sum = streamwiseDowntime.reduce( ( accumulator, currentValue ) => {
|
|
257
|
+
return accumulator + currentValue.down_time;
|
|
258
|
+
}, 0 );
|
|
259
|
+
const average = sum / streamwiseDowntime.length;
|
|
260
|
+
downtimetotal = Math.round( average );
|
|
261
|
+
} else {
|
|
262
|
+
downtimetotal = 0;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
let Issue = getTicket.ticketActivity.filter( ( a ) => a.actionType == 'issueUpdate' );
|
|
266
|
+
let primaryIssue = '';
|
|
267
|
+
|
|
268
|
+
if ( Issue.length > 0 && Issue[0].reasons.length > 0 ) {
|
|
269
|
+
primaryIssue = Issue[0].reasons[0].primaryIssue;
|
|
270
|
+
}
|
|
271
|
+
let Timestamp = dayjs().format( 'YYYY-MM-DD HH:mm' );
|
|
272
|
+
const attachments = null;
|
|
273
|
+
const subject = `Tango Eye - Infra Ticket Closed for ${getTicket.basicDetails.storeName} `;
|
|
274
|
+
const fileContent = readFileSync( join() + '/src/hbs/closeTicekt.hbs', 'utf8' );
|
|
275
|
+
const htmlContent = handlebars.compile( fileContent );
|
|
276
|
+
let store = await findOneStore( { storeId: getTicket.basicDetails.storeId } );
|
|
277
|
+
if ( store.spocDetails && store.spocDetails.length > 0 ) {
|
|
278
|
+
let spocEmail = store.spocDetails[0].email;
|
|
279
|
+
let spocName = store.spocDetails[0].name;
|
|
280
|
+
let Uidomain = `${appConfig.url.domain}/manage/stores/infra-ticket?storeId=${getTicket.basicDetails.storeId}`;
|
|
281
|
+
const html = htmlContent( { ...getTicket, Uidomain: Uidomain, primaryIssue: primaryIssue, storeName: getTicket.basicDetails.storeName, spocName: spocName, date: dayjs( getTicket.issueDate ).format( 'YYYY-MM-DD HH:mm' ), downtimetotal: downtimetotal, Timestamp: Timestamp, domain: appConfig.url.apiDomain } );
|
|
282
|
+
await sendEmailWithSES( spocEmail, subject, html, attachments, appConfig.cloud.aws.ses.adminEmail );
|
|
283
|
+
}
|
|
172
284
|
}
|
|
285
|
+
|
|
173
286
|
res.sendSuccess( 'updated Successfully' );
|
|
174
287
|
} catch ( error ) {
|
|
175
288
|
logger.error( { error: error, function: 'closeTicket' } );
|
|
@@ -181,7 +294,8 @@ export async function emailUserList( req, res ) {
|
|
|
181
294
|
let clientList = await aggregateClient( [
|
|
182
295
|
{
|
|
183
296
|
$match: {
|
|
184
|
-
status: 'active',
|
|
297
|
+
'status': 'active',
|
|
298
|
+
|
|
185
299
|
// clientId:{ req.body.clientId},
|
|
186
300
|
},
|
|
187
301
|
},
|
|
@@ -201,8 +315,8 @@ export async function emailUserList( req, res ) {
|
|
|
201
315
|
'$expr': {
|
|
202
316
|
$and: [
|
|
203
317
|
{ '$eq': [ '$clientId', '$$clientId' ] },
|
|
204
|
-
{ '$eq': [ '$
|
|
205
|
-
|
|
318
|
+
{ '$eq': [ '$clientId', '$$clientId' ] },
|
|
319
|
+
{ '$eq': [ '$emailAlert.infra', true ] },
|
|
206
320
|
],
|
|
207
321
|
},
|
|
208
322
|
},
|
|
@@ -260,6 +374,7 @@ export async function emailUserList( req, res ) {
|
|
|
260
374
|
'clientId': 1,
|
|
261
375
|
'ticketConfigs': 1,
|
|
262
376
|
'email': '$user.email',
|
|
377
|
+
'userName': '$user.userName',
|
|
263
378
|
'role': '$user.role',
|
|
264
379
|
'assignedValue': '$assignedstore.assignedValue',
|
|
265
380
|
'assignedType': '$assignedstore.assignedType',
|
|
@@ -271,6 +386,7 @@ export async function emailUserList( req, res ) {
|
|
|
271
386
|
'clientId': { $first: '$clientId' },
|
|
272
387
|
'ticketConfigs': { $first: '$ticketConfigs' },
|
|
273
388
|
'email': { $first: '$email' },
|
|
389
|
+
'userName': { $first: '$userName' },
|
|
274
390
|
'role': { $first: '$role' },
|
|
275
391
|
'assignedValue': { $push: '$assignedValue' },
|
|
276
392
|
'assignedType': { $first: '$assignedType' },
|
|
@@ -280,7 +396,7 @@ export async function emailUserList( req, res ) {
|
|
|
280
396
|
let response = [];
|
|
281
397
|
for ( let user of clientList ) {
|
|
282
398
|
if ( user.role == 'superadmin' ) {
|
|
283
|
-
let storelist = await findStore( { clientId: user.clientId }, { 'storeId': 1, 'storeProfile.timeZone': 1 } );
|
|
399
|
+
let storelist = await findStore( { clientId: user.clientId, status: 'active' }, { 'storeId': 1, 'storeProfile.timeZone': 1 } );
|
|
284
400
|
user.storeList = storelist;
|
|
285
401
|
} else if ( user.role != 'superadmin' ) {
|
|
286
402
|
if ( user.assignedType == 'store' ) {
|
|
@@ -296,9 +412,11 @@ export async function emailUserList( req, res ) {
|
|
|
296
412
|
}
|
|
297
413
|
}
|
|
298
414
|
}
|
|
299
|
-
|
|
415
|
+
|
|
416
|
+
if ( user.storeList && user.storeList.length > 0 && user.ticketConfigs && user.ticketConfigs.infraReport ) {
|
|
300
417
|
response.push( {
|
|
301
418
|
email: user.email,
|
|
419
|
+
userName: user.userName,
|
|
302
420
|
clientId: user.clientId,
|
|
303
421
|
role: user.role,
|
|
304
422
|
storeList: user.storeList,
|
|
@@ -312,3 +430,213 @@ export async function emailUserList( req, res ) {
|
|
|
312
430
|
res.sendError( error, 500 );
|
|
313
431
|
}
|
|
314
432
|
}
|
|
433
|
+
export async function infraReportSent( req, res ) {
|
|
434
|
+
try {
|
|
435
|
+
let date;
|
|
436
|
+
if ( req.body.type == 'start' ) {
|
|
437
|
+
date = dayjs().subtract( 1, 'day' ).format( 'YYYY-MM-DD' );
|
|
438
|
+
} else if ( req.body.storeList == 'start' ) {
|
|
439
|
+
date = dayjs().format( 'YYYY-MM-DD' );
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
let query = [ {
|
|
443
|
+
$match: {
|
|
444
|
+
$and: [
|
|
445
|
+
{ issueDate: new Date( date ) },
|
|
446
|
+
{ 'basicDetails.storeId': { $in: req.body.storeList } },
|
|
447
|
+
{ issueType: 'infra' },
|
|
448
|
+
{ 'ticketDetails.issueStatus': 'identified' },
|
|
449
|
+
],
|
|
450
|
+
},
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
$project: {
|
|
454
|
+
ticketId: 1,
|
|
455
|
+
basicDetails: 1,
|
|
456
|
+
createdAt: 1,
|
|
457
|
+
status: 1,
|
|
458
|
+
ticketDetails: 1,
|
|
459
|
+
issueClosedDate: 1,
|
|
460
|
+
primaryIssue: {
|
|
461
|
+
$filter: {
|
|
462
|
+
input: '$ticketActivity',
|
|
463
|
+
as: 'item',
|
|
464
|
+
cond: { $eq: [ '$$item.actionType', 'issueUpdate' ] },
|
|
465
|
+
},
|
|
466
|
+
},
|
|
467
|
+
},
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
$unwind: {
|
|
471
|
+
path: '$primaryIssue', preserveNullAndEmptyArrays: true,
|
|
472
|
+
},
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
$unwind: {
|
|
476
|
+
path: '$primaryIssue.reasons', preserveNullAndEmptyArrays: true,
|
|
477
|
+
},
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
$unwind: {
|
|
481
|
+
path: '$primaryIssue.reasons.secondaryIssue', preserveNullAndEmptyArrays: true,
|
|
482
|
+
},
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
$project: {
|
|
486
|
+
ticketId: 1,
|
|
487
|
+
basicDetails: 1,
|
|
488
|
+
createdAt: 1,
|
|
489
|
+
status: 1,
|
|
490
|
+
ticketDetails: 1,
|
|
491
|
+
issueClosedDate: 1,
|
|
492
|
+
primaryIssue: { $ifNull: [ '$primaryIssue.reasons.primaryIssue', '-' ] },
|
|
493
|
+
secondaryIssue: { $ifNull: [ '$primaryIssue.reasons.secondaryIssue.name', '-' ] },
|
|
494
|
+
},
|
|
495
|
+
},
|
|
496
|
+
{
|
|
497
|
+
$group: {
|
|
498
|
+
_id: '$ticketId',
|
|
499
|
+
ticketDetails: { $first: '$ticketDetails' },
|
|
500
|
+
issueClosedDate: { $first: '$issueClosedDate' },
|
|
501
|
+
basicDetails: { $first: '$basicDetails' },
|
|
502
|
+
primaryIssue: { $last: '$primaryIssue' },
|
|
503
|
+
secondaryIssue: { $last: '$secondaryIssue' },
|
|
504
|
+
createdAt: { $first: '$createdAt' },
|
|
505
|
+
status: { $last: '$status' },
|
|
506
|
+
|
|
507
|
+
},
|
|
508
|
+
},
|
|
509
|
+
];
|
|
510
|
+
|
|
511
|
+
let ticketList = await aggregateTangoTicket( query );
|
|
512
|
+
const exportdata = [];
|
|
513
|
+
for ( let element of ticketList ) {
|
|
514
|
+
let clientuser = await findOneUser( { _id: element.ticketDetails.addressingClient } );
|
|
515
|
+
let tangouser = await findOneUser( { _id: element.ticketDetails.addressingUser } );
|
|
516
|
+
exportdata.push( {
|
|
517
|
+
'Client ID': element.basicDetails.clientId,
|
|
518
|
+
'Client Name': element.basicDetails.clientName,
|
|
519
|
+
'Created Date & Time': dayjs( element.createdAt ).format( 'YYYY-MM-DD HH:mm A' ),
|
|
520
|
+
'Store ID': element.basicDetails.clientName,
|
|
521
|
+
'Store Name': element.basicDetails.clientName,
|
|
522
|
+
'Issue ': element.primaryIssue,
|
|
523
|
+
'Secondary Issue': element.secondaryIssue,
|
|
524
|
+
'Issue Date & Time': dayjs( element.date ).format( 'YYYY-MM-DD' ),
|
|
525
|
+
'Status ': element.status,
|
|
526
|
+
'Responded By': clientuser && clientuser.userName ? clientuser.userName : '-',
|
|
527
|
+
'Resolved By': tangouser && tangouser.userName ? tangouser.userName : '-',
|
|
528
|
+
'Closed Date & Time': element.issueClosedDate?dayjs( element.issueClosedDate ).format( 'YYYY-MM-DD HH:mm A' ):'-',
|
|
529
|
+
'Latest Comment': '',
|
|
530
|
+
'Activity Log': '',
|
|
531
|
+
} );
|
|
532
|
+
}
|
|
533
|
+
let issueCount = await countDocumentsTangoTicket( {
|
|
534
|
+
|
|
535
|
+
$and: [
|
|
536
|
+
{ issueDate: new Date( date ) },
|
|
537
|
+
{ 'basicDetails.storeId': { $in: req.body.storeList } },
|
|
538
|
+
{ issueType: 'infra' },
|
|
539
|
+
{ 'ticketDetails.issueStatus': 'identified' },
|
|
540
|
+
],
|
|
541
|
+
|
|
542
|
+
} );
|
|
543
|
+
let finalcount = 0;
|
|
544
|
+
for ( let storedata of req.body.storeList ) {
|
|
545
|
+
let downTimeQuery = {
|
|
546
|
+
'size': 1,
|
|
547
|
+
'query': {
|
|
548
|
+
'bool': {
|
|
549
|
+
'must': [
|
|
550
|
+
{
|
|
551
|
+
'term': {
|
|
552
|
+
'doc.date.keyword': dayjs( date ).format( 'DD-MM-YYYY' ),
|
|
553
|
+
},
|
|
554
|
+
},
|
|
555
|
+
{
|
|
556
|
+
'term': {
|
|
557
|
+
'doc.store_id.keyword': storedata,
|
|
558
|
+
},
|
|
559
|
+
},
|
|
560
|
+
|
|
561
|
+
],
|
|
562
|
+
|
|
563
|
+
},
|
|
564
|
+
},
|
|
565
|
+
};
|
|
566
|
+
let downtimetotal;
|
|
567
|
+
const downtime = await getOpenSearchData( 'live_downtime_hourly', downTimeQuery );
|
|
568
|
+
let streamwiseDowntime = downtime.body.hits.hits.length > 0 ? downtime.body.hits.hits[0]._source.doc.streamwise_downtime : [];
|
|
569
|
+
if ( streamwiseDowntime.length > 0 ) {
|
|
570
|
+
const sum = streamwiseDowntime.reduce( ( accumulator, currentValue ) => {
|
|
571
|
+
return accumulator + currentValue.down_time;
|
|
572
|
+
}, 0 );
|
|
573
|
+
const average = sum / streamwiseDowntime.length;
|
|
574
|
+
downtimetotal = Math.round( average );
|
|
575
|
+
} else {
|
|
576
|
+
downtimetotal = 0;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
finalcount = finalcount + downtimetotal;
|
|
580
|
+
}
|
|
581
|
+
let avgDownTime = Math.round( finalcount / req.body.storeList.length );
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
let issueList = await findinfraReason( { parentId: { '$exists': false } } );
|
|
585
|
+
const categoryCounts = {};
|
|
586
|
+
let response;
|
|
587
|
+
if ( ticketList.length > 0 ) {
|
|
588
|
+
ticketList.forEach( ( item ) => {
|
|
589
|
+
const categoryName = item.primaryIssue;
|
|
590
|
+
if ( categoryCounts[categoryName] ) {
|
|
591
|
+
categoryCounts[categoryName]++;
|
|
592
|
+
} else {
|
|
593
|
+
categoryCounts[categoryName] = 1;
|
|
594
|
+
}
|
|
595
|
+
} );
|
|
596
|
+
response = issueList.map( ( category ) => ( {
|
|
597
|
+
name: category.name,
|
|
598
|
+
count: categoryCounts[category.name] || 0,
|
|
599
|
+
} ) );
|
|
600
|
+
} else {
|
|
601
|
+
response = issueList.map( ( category ) => ( {
|
|
602
|
+
name: category.name,
|
|
603
|
+
count: 0,
|
|
604
|
+
} ) );
|
|
605
|
+
}
|
|
606
|
+
let reportdate = dayjs().format( 'YYYY-MM-DD' );
|
|
607
|
+
const wb = new xl.Workbook();
|
|
608
|
+
const ws = wb.addWorksheet( 'Daily report' );
|
|
609
|
+
const headers = Object.keys( exportdata[0] );
|
|
610
|
+
|
|
611
|
+
for ( let i = 0; i < headers.length; i++ ) {
|
|
612
|
+
ws.cell( 1, i + 1 ).string( headers[i] );
|
|
613
|
+
};
|
|
614
|
+
for ( let i = 0; i < exportdata.length; i++ ) {
|
|
615
|
+
const dataRow = exportdata[i];
|
|
616
|
+
for ( let j = 0; j < headers.length; j++ ) {
|
|
617
|
+
const header = headers[j];
|
|
618
|
+
const value = dataRow[header];
|
|
619
|
+
ws.cell( i + 2, j + 1 ).string( value?.toString() );
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
let buffer = await wb.writeToBuffer();
|
|
623
|
+
|
|
624
|
+
const attachments = {
|
|
625
|
+
filename: `dailyInfraReport- ${reportdate}.xlsx`,
|
|
626
|
+
content: buffer,
|
|
627
|
+
contentType: 'application/xlsx', // e.g., 'application/pdf'
|
|
628
|
+
};
|
|
629
|
+
const subject = `Daily Digest - Infra Downtime Report - ${reportdate}`;
|
|
630
|
+
const fileContent = readFileSync( join() + '/src/hbs/dailyInfraReport.hbs', 'utf8' );
|
|
631
|
+
const htmlContent = handlebars.compile( fileContent );
|
|
632
|
+
let Uidomain = `${appConfig.url.domain}`;
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
const html = htmlContent( { ...req.body, Uidomain: Uidomain, issueCount: issueCount, avgDownTime: avgDownTime, reportdate: reportdate, content: response, date: date, domain: appConfig.url.apiDomain } );
|
|
636
|
+
const result = await sendEmailWithSES( req.body.email, subject, html, attachments, appConfig.cloud.aws.ses.adminEmail );
|
|
637
|
+
res.sendSuccess( result );
|
|
638
|
+
} catch ( error ) {
|
|
639
|
+
logger.error( { error: error, function: 'infraReportSent' } );
|
|
640
|
+
res.sendError( error, 500 );
|
|
641
|
+
}
|
|
642
|
+
}
|