tango-app-api-infra 3.0.52-dev → 3.0.54-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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tango-app-api-infra",
3
- "version": "3.0.52-dev",
3
+ "version": "3.0.54-dev",
4
4
  "description": "infra",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -24,8 +24,8 @@
24
24
  "html-pdf-node": "^1.0.8",
25
25
  "mongodb": "^6.4.0",
26
26
  "nodemon": "^3.1.0",
27
- "tango-api-schema": "^2.0.77",
28
- "tango-app-api-middleware": "^1.0.54-dev",
27
+ "tango-api-schema": "^2.0.90",
28
+ "tango-app-api-middleware": "^3.1.3",
29
29
  "winston": "^3.12.0",
30
30
  "winston-daily-rotate-file": "^5.0.0"
31
31
  },
@@ -149,7 +149,7 @@ export async function infraCard( req, res ) {
149
149
  export async function installationCard( req, res ) {
150
150
  try {
151
151
  let onboardedCount = await countDocumentsStore( { clientId: { $in: req.body.clientId } } );
152
- let installedCount = await countDocumentsStore( { 'clientId': { $in: req.body.clientId }, 'edge.deployed': true } );
152
+ let installedCount = await countDocumentsStore( { 'clientId': { $in: req.body.clientId }, 'edge.firstFile': true } );
153
153
 
154
154
  let yettoInstallCount = await aggregateTangoTicket( [
155
155
  {
@@ -207,9 +207,19 @@ export async function installationCard( req, res ) {
207
207
  issueIdentifiedBy: 1,
208
208
  primaryIssue: '$primaryIssue.reasons.primaryIssue',
209
209
  },
210
+ }, {
211
+ $group: {
212
+ _id: '$ticketId',
213
+ ticketId: { $first: '$ticketId' },
214
+ issueStatus: { $first: '$issueStatus' },
215
+ ticketType: { $first: '$ticketType' },
216
+ issueIdentifiedBy: { $first: '$issueIdentifiedBy' },
217
+ primaryIssue: { $first: '$primaryIssue' },
218
+ },
210
219
  },
211
220
  ];
212
221
  let installFailedCount = await aggregateTangoTicket( query );
222
+
213
223
  let issueList = await findinfraReason( { parentId: { '$exists': false } } );
214
224
  const categoryCounts = {};
215
225
  let response;
@@ -443,6 +453,18 @@ export async function InstallationIssuesTable( req, res ) {
443
453
  primaryIssue: { $ifNull: [ '$primaryIssue.reasons.primaryIssue', '-' ] },
444
454
  },
445
455
  },
456
+ {
457
+ $group: {
458
+ _id: '$storeId',
459
+ createdAt: { $first: '$createdAt' },
460
+ clientName: { $first: '$clientName' },
461
+ storeId: { $first: '$storeId' },
462
+ clientId: { $first: '$clientId' },
463
+ storeName: { $first: '$storeName' },
464
+ status: { $first: '$status' },
465
+ primaryIssue: { $first: '$primaryIssue' },
466
+ },
467
+ },
446
468
  ];
447
469
  if ( req.body.searchValue && req.body.searchValue !== '' ) {
448
470
  query.push( {
@@ -75,7 +75,7 @@ export async function createTicket( req, res ) {
75
75
  let Uidomain = `${appConfig.url.domain}/manage/stores/infra-ticket?storeId=${req.body.basicDetails.storeId}`;
76
76
 
77
77
  const html = htmlContent( { ...req.body, Uidomain: Uidomain, domain: appConfig.url.apiDomain, date: dayjs( req.body.issueDate ).format( 'YYYY-MM-DD' ), downtimetotal: downtimetotal, Timestamp: Timestamp } );
78
- if ( req.body.spocEmail&&req.body.issueType == 'infra' ) {
78
+ if ( req.body.emailAlert&&req.body.spocEmail&&req.body.issueType == 'infra'&&isValidEmail( req.body.spocEmail ) ) {
79
79
  await sendEmailWithSES( req.body.spocEmail, subject, html, attachments, appConfig.cloud.aws.ses.adminEmail );
80
80
  }
81
81
  if ( create ) {
@@ -86,6 +86,10 @@ export async function createTicket( req, res ) {
86
86
  return res.sendError( error, 500 );
87
87
  }
88
88
  }
89
+ function isValidEmail( email ) {
90
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
91
+ return emailRegex.test( email );
92
+ }
89
93
  export async function bulkcreateTicket( req, res ) {
90
94
  try {
91
95
  let response = {};
@@ -284,7 +288,7 @@ export async function viewTicket( req, res ) {
284
288
  if ( ticket.attachments.hasOwnProperty( index ) ) {
285
289
  let file = ticket.attachments[index];
286
290
  let params = {
287
- Bucket: 'tango-client-sandbox',
291
+ Bucket: appConfig.cloud.aws.bucket.ticket,
288
292
  file_path: file.filePath,
289
293
  };
290
294
  let attachments = await signedUrl( params );
@@ -336,7 +340,7 @@ export async function uploadAttachments( req, res ) {
336
340
  for ( let singleImg in req.files.img ) {
337
341
  if ( req.files.img.hasOwnProperty( singleImg ) ) {
338
342
  let params = {
339
- Bucket: 'tango-client-sandbox',
343
+ Bucket: appConfig.cloud.aws.bucket.ticket,
340
344
  Key: req.params.ticketId + '/',
341
345
  ContentType: 'multipart/form-data',
342
346
  body: req.files.img[singleImg].data,
@@ -360,7 +364,7 @@ export async function uploadAttachments( req, res ) {
360
364
  let oldticket = await findOneTangoTicket( { ticketId: req.params.ticketId } );
361
365
  let attachments = oldticket.attachments;
362
366
  let params = {
363
- Bucket: 'tango-client-sandbox',
367
+ Bucket: appConfig.cloud.aws.bucket.ticket,
364
368
  Key: req.params.ticketId + '/',
365
369
  ContentType: 'multipart/form-data',
366
370
  body: req.files.img.data,
@@ -9,7 +9,7 @@ import { join } from 'path';
9
9
  import handlebars from 'handlebars';
10
10
  dayjs.extend( utc );
11
11
  dayjs.extend( timezone );
12
- import { sendEmailWithSES } from 'tango-app-api-middleware';
12
+ import { sendEmailWithSES, signedUrl } from 'tango-app-api-middleware';
13
13
  import { createClient, findClient, aggregateClient, findOneClient } from '../services/client.service.js';
14
14
  import { createStore, findStore, updateOneStore, findOneStore } from '../services/store.service.js';
15
15
  import { findTangoTicket, findOneTangoTicket, countDocumentsTangoTicket, aggregateTangoTicket, updateOneTangoTicket } from '../services/tangoTicket.service.js';
@@ -200,8 +200,9 @@ export async function updateRefreshTicket( req, res ) {
200
200
  primaryIssue = Issue[0].reasons[0].primaryIssue;
201
201
  }
202
202
  let Uidomain = `${appConfig.url.domain}/manage/stores/infra-ticket?storeId=${getTicket.basicDetails.storeId}`;
203
+ let getclient = await findOneClient( { clientId: getTicket.basicDetails.clientId } );
203
204
  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
- if ( spocEmail ) {
205
+ if ( getclient.ticketConfigs.emailAlert && spocEmail && isValidEmail( spocEmail ) ) {
205
206
  await sendEmailWithSES( spocEmail, subject, html, attachments, appConfig.cloud.aws.ses.adminEmail );
206
207
  }
207
208
  }
@@ -221,6 +222,7 @@ export async function closeTicket( req, res ) {
221
222
  if ( ticket.status == 'closed' ) {
222
223
  getTicket.ticketActivity.push( {
223
224
  actionType: 'dataRecived',
225
+ timeStamp: new Date(),
224
226
  actionBy: 'Tango',
225
227
  } );
226
228
  }
@@ -281,8 +283,9 @@ export async function closeTicket( req, res ) {
281
283
  let spocEmail = store.spocDetails[0].email;
282
284
  let spocName = store.spocDetails[0].name;
283
285
  let Uidomain = `${appConfig.url.domain}/manage/stores/infra-ticket?storeId=${getTicket.basicDetails.storeId}`;
286
+ let getclient = await findOneClient( { clientId: getTicket.basicDetails.clientId } );
284
287
  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 } );
285
- if ( spocEmail && spocEmail != '' &&spocEmail!='none'&& spocEmail != undefined ) {
288
+ if ( getclient.ticketConfigs.emailAlert && spocEmail && isValidEmail( spocEmail ) ) {
286
289
  await sendEmailWithSES( spocEmail, subject, html, attachments, appConfig.cloud.aws.ses.adminEmail );
287
290
  }
288
291
  }
@@ -295,6 +298,10 @@ export async function closeTicket( req, res ) {
295
298
  res.sendError( error, 500 );
296
299
  }
297
300
  }
301
+ function isValidEmail( email ) {
302
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
303
+ return emailRegex.test( email );
304
+ }
298
305
  export async function emailUserList( req, res ) {
299
306
  try {
300
307
  let clientList = await aggregateClient( [
@@ -600,7 +607,10 @@ export async function infraReportSent( req, res ) {
600
607
 
601
608
 
602
609
  const html = htmlContent( { ...req.body, Uidomain: Uidomain, issueCount: issueCount, avgDownTime: avgDownTime, reportdate: reportdate, content: response, date: date, domain: appConfig.url.apiDomain } );
603
- const result = await sendEmailWithSES( req.body.email, subject, html, attachments, appConfig.cloud.aws.ses.adminEmail );
610
+ if ( isValidEmail( req.body.email ) ) {
611
+ const result = await sendEmailWithSES( req.body.email, subject, html, attachments, appConfig.cloud.aws.ses.adminEmail );
612
+ res.sendSuccess( result );
613
+ }
604
614
  res.sendSuccess( result );
605
615
  } catch ( error ) {
606
616
  logger.error( { error: error, function: 'infraReportSent' } );
@@ -620,3 +630,108 @@ export async function spocmailchange() {
620
630
  }
621
631
  }
622
632
  }
633
+
634
+
635
+ export async function camAngleChangeReport( req, res ) {
636
+ try {
637
+ const currentDate = dayjs();
638
+
639
+
640
+ const previousDay = currentDate.subtract( 1, 'day' );
641
+
642
+
643
+ const formattedPreviousDay = previousDay.format( 'DD-MM-YYYY' );
644
+ const angleChange = await getOpenSearchData( 'camera-angle-change',
645
+ {
646
+ 'query': {
647
+ 'bool': {
648
+ 'must': [
649
+ {
650
+ 'term': {
651
+ 'date.keyword': formattedPreviousDay,
652
+ },
653
+ },
654
+ {
655
+ 'term': {
656
+ 'client_id.keyword': req.body.clientId,
657
+ },
658
+ },
659
+ ],
660
+ },
661
+ },
662
+ } );
663
+ if ( angleChange.body.hits.hits.length > 0 ) {
664
+ const exportdata = [];
665
+
666
+ for ( let camera of angleChange.body.hits.hits ) {
667
+ let result = camera._source;
668
+
669
+ if ( result && result.cameraAngleChangeStatus && result.camera_info.length > 0 ) {
670
+ for ( let stream of result.camera_info ) {
671
+ let params = {
672
+ Bucket: appConfig.cloud.aws.bucket.cameraAngle,
673
+ file_path: stream.path,
674
+ };
675
+ let Image = await signedUrl( params );
676
+
677
+
678
+ let findStore = await findOneStore( { storeId: result.store_id } );
679
+
680
+
681
+ exportdata.push( {
682
+ 'Store Name': findStore.storeName,
683
+ 'Store Code': findStore.storeId,
684
+ 'Date Changed': formattedPreviousDay,
685
+ 'ImageURL': {
686
+ url: Image,
687
+ label: 'Angle changed Image',
688
+ },
689
+ } );
690
+ }
691
+ }
692
+ }
693
+ let buffer = await download( exportdata );
694
+
695
+ let attachments = {
696
+ filename: `Camera angle change- ${formattedPreviousDay}.xlsx`,
697
+ content: buffer,
698
+ contentType: 'application/xlsx', // e.g., 'application/pdf'
699
+ };
700
+ let subject ='Camera Angle Modified';
701
+ let html = `<div>We wanted to inform you that the camera angle in your stores has been adjusted recently.</div>`;
702
+ let result = await sendEmailWithSES( req.body.toMail, subject, html, attachments, appConfig.cloud.aws.ses.adminEmail );
703
+ if ( result ) {
704
+ res.sendSuccess( 'Email send successfully' );
705
+ }
706
+ }
707
+ } catch ( error ) {
708
+ logger.error( { error: error, function: 'camAngleChangeList' } );
709
+ res.sendError( error, 500 );
710
+ }
711
+ }
712
+
713
+
714
+ export async function download( data ) {
715
+ const wb = new xl.Workbook();
716
+ const ws = wb.addWorksheet( 'Worksheet Name' );
717
+ const headers = Object.keys( data[0] );
718
+
719
+ for ( let i = 0; i < headers.length; i++ ) {
720
+ ws.cell( 1, i + 1 ).string( headers[i] );
721
+ };
722
+ for ( let i = 0; i < data.length; i++ ) {
723
+ const dataRow = data[i];
724
+ for ( let j = 0; j < headers.length; j++ ) {
725
+ const header = headers[j];
726
+ const value = dataRow[header];
727
+
728
+ if ( typeof value === 'object' && value.hasOwnProperty( 'label' ) && value.hasOwnProperty( 'url' ) ) {
729
+ ws.cell( i + 2, j + 1 ).link( value.url );
730
+ ws.cell( i + 2, j + 1 ).string( value.label );
731
+ } else {
732
+ ws.cell( i + 2, j + 1 ).string( value?.toString() );
733
+ }
734
+ }
735
+ }
736
+ return await wb.writeToBuffer();
737
+ }
@@ -4,7 +4,7 @@ import { aggregateTangoTicket } from '../services/tangoTicket.service.js';
4
4
  import { findOneStore } from '../services/store.service.js';
5
5
  import dayjs from 'dayjs';
6
6
  import { findinfraReason } from '../services/infraReason.service.js';
7
- import { signedUrl } from 'tango-app-api-middleware';
7
+ import { signedUrl, appConfig } from 'tango-app-api-middleware';
8
8
  export async function storeTicketList( req, res ) {
9
9
  try {
10
10
  let date = await getUTC( new Date( req.body.fromDate ), new Date( req.body.toDate ) );
@@ -337,7 +337,7 @@ export async function edgeAppLogTable( req, res ) {
337
337
  const average = sum / streamwiseDowntime.length;
338
338
  obj.downtime = Math.round( average );
339
339
  } else {
340
- obj.downtime = '';
340
+ obj.downtime = 0;
341
341
  }
342
342
  let appStatusQuery = {
343
343
  'size': 1,
@@ -803,7 +803,7 @@ export async function cameraAngleChange( req, res ) {
803
803
  let changeDetected = result.camera_info.filter( ( cam ) => cam.stream == req.body.StreamName );
804
804
  if ( changeDetected.length == 1 ) {
805
805
  let params = {
806
- Bucket: 'tango-client-sandbox',
806
+ Bucket: appConfig.cloud.aws.bucket.cameraAngle,
807
807
  file_path: changeDetected[0].path,
808
808
  };
809
809
  let Image = await signedUrl( params );
@@ -2,7 +2,7 @@
2
2
  import express from 'express';
3
3
  import {
4
4
  migrateClient, migrateStores, basicList, clientList, setTicketTime, downStoresList,
5
- openTicketList, assigntoUser, updateRefreshTicket, closeTicket, spocmailchange, emailUserList, infraReportSent,
5
+ openTicketList, assigntoUser, updateRefreshTicket, closeTicket, camAngleChangeReport, spocmailchange, emailUserList, infraReportSent,
6
6
  } from '../controllers/internalInfra.controller.js';
7
7
 
8
8
  export const internalInfraRouter = express.Router();
@@ -20,5 +20,6 @@ internalInfraRouter.post( '/closeTicket', closeTicket );
20
20
  internalInfraRouter.get( '/emailUserList', emailUserList );
21
21
  internalInfraRouter.post( '/infraReportSent', infraReportSent );
22
22
  internalInfraRouter.post( '/spocmailchange', spocmailchange );
23
+ internalInfraRouter.post( '/camAngleChangeReport', camAngleChangeReport );
23
24
 
24
25
 
@@ -28,7 +28,7 @@ export async function validateDetails( req, res, next ) {
28
28
  clientId: store.clientId,
29
29
  clientName: client.clientName,
30
30
  };
31
-
31
+ req.body.emailAlert = client.ticketConfigs.emailAlert;
32
32
  if ( req.body.issueType == 'infra' ) {
33
33
  let refreshdate = dayjs().add( client.ticketConfigs.refreshAlert, 'days' );
34
34
  req.body.ticketDetails = {
@@ -62,7 +62,7 @@ export async function validateTicket( req, res, next ) {
62
62
  if ( Ticket ) {
63
63
  return res.sendSuccess( 'Infra Ticket Already Exists for the day' );
64
64
  }
65
- console.log( req.body );
65
+
66
66
  let refreshTicket = await findOneTangoTicket(
67
67
  {
68
68
  'basicDetails.storeId': req.body.basicDetails.storeId,
@@ -71,7 +71,6 @@ export async function validateTicket( req, res, next ) {
71
71
  'ticketDetails.ticketRefreshTime': { $lte: new Date() },
72
72
  },
73
73
  );
74
- console.log( refreshTicket );
75
74
  if ( refreshTicket ) {
76
75
  return res.sendSuccess( 'refreshTicket Ticket Already Exists for the Store' );
77
76
  }
@@ -307,16 +306,26 @@ export async function InfrastepstoResolve( req, res, next ) {
307
306
  export async function InfraAlert( req, res, next ) {
308
307
  try {
309
308
  if ( req.body.hibernationDays ) {
310
- req.body.hibernationDays = dayjs().add( req.body.hibernationDays, 'days' ).format( 'YYYY-MM-DD' );
311
- await updateOneStore( { storeId: req.body.basicDetails.storeId }, { 'ticketConfigs.hibernation': new Date( req.body.hibernationDays ) } );
309
+ let actionBy = '';
310
+ if ( req.user.userType == 'tango' ) {
311
+ actionBy = 'Tango';
312
+ } else if ( req.user.userType == 'client' ) {
313
+ actionBy = 'User';
314
+ }
315
+
312
316
  req.body.ticketActivity.push( {
313
317
  actionType: 'statusCheckReply',
314
- actionBy: 'User',
318
+ actionBy: actionBy,
315
319
  timeStamp: new Date(),
320
+ statusCheckReply: 'No',
316
321
  IdentifiedBy: req.user.userName,
317
322
  hibernationDays: req.body.hibernationDays,
318
323
  } );
324
+ req.body.hibernationDays = dayjs().add( req.body.hibernationDays, 'days' ).format( 'YYYY-MM-DD' );
325
+ await updateOneStore( { storeId: req.body.basicDetails.storeId }, { 'ticketConfigs.hibernation': new Date( req.body.hibernationDays ) } );
326
+
319
327
  await updateOneTangoTicket( { ticketId: req.body.ticketId }, { 'hibernation': new Date( req.body.hibernationDays ) } );
328
+ console.log( req.body.ticketActivity );
320
329
  } else {
321
330
  if ( req.body.issueType == 'infra' ) {
322
331
  let client = await findOneClient( { clientId: req.body.basicDetails.clientId }, { ticketConfigs: 1 } );