tango-app-api-client 3.4.2-v1remove-0 → 3.5.0

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/.eslintrc.cjs CHANGED
@@ -36,7 +36,7 @@ module.exports = {
36
36
  'no-unused-vars': 'error',
37
37
  'new-cap': [ 'error', { 'newIsCap': true, 'capIsNew': false } ],
38
38
  'prefer-const': 'off',
39
- 'no-console': 'error',
39
+ // 'no-console': 'error',
40
40
  },
41
41
  };
42
42
 
package/build.js ADDED
@@ -0,0 +1,25 @@
1
+ // build.js
2
+ import fs from 'fs';
3
+
4
+ const type = process.argv[2] || 'patch'; // default to patch
5
+ const file = 'package.json';
6
+
7
+ // Read and parse package.json
8
+ const pkg = JSON.parse( fs.readFileSync( file, 'utf8' ) );
9
+
10
+ // Force "main" to be "index.js"
11
+ pkg.main = 'index.js';
12
+
13
+ // Bump version
14
+ const [ major, minor, patch ] = pkg.version.split( '.' ).map( Number );
15
+
16
+ if ( type === 'patch' ) pkg.version = `${major}.${minor}.${patch + 1}`;
17
+ else if ( type === 'minor' ) pkg.version = `${major}.${minor + 1}.0`;
18
+ else if ( type === 'major' ) pkg.version = `${major + 1}.0.0`;
19
+ else throw new Error( 'Invalid version type. Use patch, minor, or major.' );
20
+
21
+ // Write back to package.json
22
+ fs.writeFileSync( file, JSON.stringify( pkg, null, 2 ) );
23
+
24
+ // console.log( `🔧 Updated version to ${pkg.version} and set "main": "index.js"` );
25
+
package/package.json CHANGED
@@ -1,42 +1,46 @@
1
- {
2
- "name": "tango-app-api-client",
3
- "version": "3.4.2-v1remove-0",
4
- "description": "client",
5
- "main": "index.js",
6
- "type": "module",
7
- "scripts": {
8
- "start": "nodemon --exec \"eslint --fix . && node index.js\""
9
- },
10
- "engines": {
11
- "node": ">=18.10.0"
12
- },
13
- "author": "praveenraj",
14
- "license": "ISC",
15
- "dependencies": {
16
- "aws-sdk": "^2.1560.0",
17
- "cors": "^2.8.5",
18
- "dotenv": "^16.4.4",
19
- "express": "^4.18.2",
20
- "express-fileupload": "^1.4.3",
21
- "handlebars": "^4.7.8",
22
- "joi": "^17.12.1",
23
- "joi-to-swagger": "^6.2.0",
24
- "lodash": "^4.17.21",
25
- "mongodb": "^6.7.0",
26
- "nodemon": "^3.0.3",
27
- "npm": "^10.9.1",
28
- "swagger-ui-express": "^5.0.0",
29
- "tango-api-schema": "^2.2.104",
30
- "tango-app-api-middleware": "^3.1.67",
31
- "winston": "^3.11.0",
32
- "winston-daily-rotate-file": "^5.0.0"
33
- },
34
- "devDependencies": {
35
- "eslint": "^8.56.0",
36
- "eslint-config-google": "^0.14.0",
37
- "eslint-config-semistandard": "^17.0.0",
38
- "eslint-config-standard": "^17.1.0",
39
- "eslint-plugin-import": "^2.29.1",
40
- "eslint-plugin-promise": "^6.1.1"
41
- }
42
- }
1
+ {
2
+ "name": "tango-app-api-client",
3
+ "version": "3.5.0",
4
+ "description": "client",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "start": "nodemon --exec \"eslint --fix . && node app.js\"",
9
+ "build:patch": "node build.js patch && npm publish",
10
+ "build:minor": "node build.js minor && npm publish",
11
+ "build:major": "node build.js major && npm publish"
12
+ },
13
+ "engines": {
14
+ "node": ">=18.10.0"
15
+ },
16
+ "author": "praveenraj",
17
+ "license": "ISC",
18
+ "dependencies": {
19
+ "aws-sdk": "^2.1560.0",
20
+ "cors": "^2.8.5",
21
+ "dotenv": "^16.4.4",
22
+ "express": "^4.18.2",
23
+ "express-fileupload": "^1.4.3",
24
+ "handlebars": "^4.7.8",
25
+ "joi": "^17.12.1",
26
+ "joi-to-swagger": "^6.2.0",
27
+ "lodash": "^4.17.21",
28
+ "mongodb": "^6.7.0",
29
+ "nodemon": "^3.0.3",
30
+ "npm": "^10.9.1",
31
+ "sharp": "^0.34.3",
32
+ "swagger-ui-express": "^5.0.0",
33
+ "tango-api-schema": "^2.3.6",
34
+ "tango-app-api-middleware": "^3.4.2",
35
+ "winston": "^3.11.0",
36
+ "winston-daily-rotate-file": "^5.0.0"
37
+ },
38
+ "devDependencies": {
39
+ "eslint": "^8.56.0",
40
+ "eslint-config-google": "^0.14.0",
41
+ "eslint-config-semistandard": "^17.0.0",
42
+ "eslint-config-standard": "^17.1.0",
43
+ "eslint-plugin-import": "^2.29.1",
44
+ "eslint-plugin-promise": "^6.1.1"
45
+ }
46
+ }
@@ -1,5 +1,5 @@
1
1
  import { billingDetailsUpdate, brandInfoUpdate, domainDetailsConfigurationUpdate, featureConfigurationUpdate, getClientData, signatoryDetailsUpdate, ticketConfigurationUpdate, documentsUpdate, getUserData, CsmUsersGet, OpsUsersGet, userConfigurationUpdate, findClient, aggregateClient, createAuditQueue, findOne, insert, update, findOneClient, updateOneClient } from '../service/client.service.js';
2
- import { checkFileExist, fileUpload, signedUrl, chunkArray, download, logger, getOpenSearchData, insertOpenSearchData, sendEmailWithSES, createCustomer, createVirtualAccount, getUuid } from 'tango-app-api-middleware';
2
+ import { checkFileExist, signedUrl, chunkArray, download, logger, getOpenSearchData, insertOpenSearchData, sendEmailWithSES, createCustomer, createVirtualAccount, getUuid, fileRestrictedUpload, getXsscheck } from 'tango-app-api-middleware';
3
3
  import { countDocumentsUser, findOneAndUpdateUser, findOneUser, getUserNameEmailById, updateManyUser } from '../service/user.service.js';
4
4
  import { aggregateStore, countDocumentsStore, findStore, updateManyStore } from '../service/store.service.js';
5
5
  import { aggregateCamera, countDocumentsCamera } from '../service/camera.service.js';
@@ -17,6 +17,7 @@ import { createPaymentAccount } from '../service/paymentAccount.service.js';
17
17
  import { countDocumentsClusters, createclusterModel } from '../service/cluster.service.js';
18
18
  import { countDocumentsTeams } from '../service/teams.service.js';
19
19
  import { createauditConfig, updateauditConfig, aggregateAuditconfig } from '../service/auditConfig.service.js';
20
+ import { findOnerevopConfig, createrevopConfig, updaterevopConfig } from '../service/revopConfig.service.js';
20
21
 
21
22
  export async function create( req, res ) {
22
23
  try {
@@ -73,6 +74,7 @@ export async function create( req, res ) {
73
74
  'reportConfigs.reportName': generatedName,
74
75
  'auditConfigs.zoneQueueName': `${generatedName}-zone`,
75
76
  'auditConfigs.trafficQueueName': `${generatedName}-traffic`,
77
+ 'auditConfigs.trackQueueName': `${generatedName}-track`,
76
78
  'auditConfigs.traxQueueName.unattendedCustomer': `${generatedName}-unattendedCustomer`,
77
79
  'auditConfigs.traxQueueName.leftInMiddle': `${generatedName}-leftInMiddle`,
78
80
  'auditConfigs.traxQueueName.uniformDetection': `${generatedName}-uniformDetection`,
@@ -81,6 +83,7 @@ export async function create( req, res ) {
81
83
  'auditConfigs.traxQueueName.hygiene': `${generatedName}-hygiene`,
82
84
  'clientApi.apiKey': await getUuid(),
83
85
  'clientApi.status': true,
86
+ 'clientApi.allowedIps': [ '*' ],
84
87
 
85
88
  };
86
89
 
@@ -345,6 +348,7 @@ export async function create( req, res ) {
345
348
  await Promise.all( [
346
349
  createAuditQueue( `${generatedName}-zone` ),
347
350
  createAuditQueue( `${generatedName}-traffic` ),
351
+ createAuditQueue( `${generatedName}-track` ),
348
352
  createAuditQueue( `${generatedName}-unattendedCustomer` ),
349
353
  createAuditQueue( `${generatedName}-leftInMiddle` ),
350
354
  createAuditQueue( `${generatedName}-uniformDetection` ),
@@ -693,7 +697,6 @@ export async function updateBrandInfo( req, res ) {
693
697
  const openSearch = JSON.parse( process.env.OPENSEARCH );
694
698
  // const url = JSON.parse( process.env.URL );
695
699
  let updateKeys = [];
696
-
697
700
  if ( req.files?.logo ) {
698
701
  const uploadDataParams = {
699
702
  Bucket: bucket.assets,
@@ -703,7 +706,11 @@ export async function updateBrandInfo( req, res ) {
703
706
  body: req.files.logo.data,
704
707
  };
705
708
  updateKeys.push( 'Brand Logo' );
706
- await fileUpload( uploadDataParams );
709
+ let uploadStatus= await fileRestrictedUpload( uploadDataParams );
710
+
711
+ if ( uploadStatus==false ) {
712
+ return res.sendError( 'Unsupported Media Type', 415 );
713
+ }
707
714
  }
708
715
 
709
716
  if ( Object.keys( req.body ).length > 0 ) {
@@ -861,7 +868,11 @@ export async function updateBillingDetails( req, res ) {
861
868
  body: req.files.gstCertificate.data,
862
869
  };
863
870
  updateKeys.push( 'GST certificate' );
864
- await fileUpload( uploadDataParams );
871
+ let uploadStatus= await fileRestrictedUpload( uploadDataParams );
872
+
873
+ if ( uploadStatus==false ) {
874
+ return res.sendError( 'Unsupported Media Type', 415 );
875
+ }
865
876
  }
866
877
 
867
878
  if ( Object.keys( req.body ).length > 0 ) {
@@ -1111,10 +1122,7 @@ export async function updateFeatureConfiguration( req, res ) {
1111
1122
  // await postApi( `${url.oldapidomain}/oldBrandUpdate/${data?._id}`, { brandConfigs: data.brandConfigs } );
1112
1123
 
1113
1124
  const keysArray = [
1114
- 'isExcludedArea', 'isPasserByData', 'isNormalized', 'isbillingDisabled',
1115
- 'isCameraDisabled', 'isFootfallDirectory', 'isNOB', 'isNewTraffic',
1116
- 'isTrax', 'isNewZone', 'isNewReports', 'isNewDashboard', 'streamBy',
1117
- ];
1125
+ 'isExcludedArea', 'isPasserByData', 'isNormalized', 'isbillingDisabled', 'isCameraDisabled', 'isFootfallDirectory', 'isNOB', 'isNewTraffic', 'isTrax', 'isNewZone', 'isNewReports', 'isNewDashboard', 'streamBy', 'isFootfallView', 'isAIManager', 'isAIManagerAccessControl', 'isCameraEdit' ];
1118
1126
  // Map and rename keys from previous client info for UI display and logging
1119
1127
  const oldData = {
1120
1128
  StoreOpenTime: previousData?.featureConfigs?.open,
@@ -1145,10 +1153,14 @@ export async function updateFeatureConfiguration( req, res ) {
1145
1153
  Zonev2: previousData?.featureConfigs?.isNewZoneV2 == true ? 'Enabled' : 'Disabled',
1146
1154
  Reports: previousData?.featureConfigs?.isNewReports == true ? 'Enabled' : 'Disabled',
1147
1155
  Trax: previousData?.featureConfigs?.isTrax == true ? 'Enabled' : 'Disabled',
1156
+ Revops: previousData?.featureConfigs?.isRevops == true ? 'Enabled' : 'Disabled',
1148
1157
  StreamType: previousData?.featureConfigs?.streamBy == 'Edge' ? 'Edge App' : 'RTSP',
1149
1158
  FootfallDirectoryOnlyAudit: previousData?.featureConfigs?.isFootfallDirectoryAudit == true ? 'Enabled' : 'Disabled',
1150
1159
  FootfallDirectoryOnlyFew: previousData?.featureConfigs?.isFootfallDirectoryLimit == true ? 'Enabled' : 'Disabled',
1151
-
1160
+ FootfallView: previousData?.featureConfigs?.isFootfallView == true ? 'Enabled' : 'Disabled',
1161
+ AIManager: previousData?.featureConfigs?.isAIManager == true ? 'Enabled' : 'Disabled',
1162
+ AIManagerAccessControl: previousData?.featureConfigs?.isAIManagerAccessControl == true ? 'Enabled' : 'Disabled',
1163
+ CameraEdit: previousData?.featureConfigs?.isCameraEdit == true ? 'Enabled' : 'Disabled',
1152
1164
  };
1153
1165
 
1154
1166
  // Map and rename keys from current client info for UI display and logging
@@ -1181,10 +1193,14 @@ export async function updateFeatureConfiguration( req, res ) {
1181
1193
  Zonev2: postData?.featureConfigs?.isNewZoneV2 == true ? 'Enabled' : 'Disabled',
1182
1194
  Reports: postData?.featureConfigs?.isNewReports == true ? 'Enabled' : 'Disabled',
1183
1195
  Trax: postData?.featureConfigs?.isTrax == true ? 'Enabled' : 'Disabled',
1196
+ Revops: postData?.featureConfigs?.isRevops == true ? 'Enabled' : 'Disabled',
1184
1197
  StreamType: postData?.featureConfigs?.streamBy == 'Edge' ? 'Edge App' : 'RTSP',
1185
1198
  FootfallDirectoryOnlyAudit: postData?.featureConfigs?.isFootfallDirectoryAudit == true ? 'Enabled' : 'Disabled',
1186
1199
  FootfallDirectoryOnlyFew: postData?.featureConfigs?.isFootfallDirectoryLimit == true ? 'Enabled' : 'Disabled',
1187
-
1200
+ FootfallView: previousData?.featureConfigs?.isFootfallView == true ? 'Enabled' : 'Disabled',
1201
+ AIManager: previousData?.featureConfigs?.isAIManager == true ? 'Enabled' : 'Disabled',
1202
+ AIManagerAccessControl: previousData?.featureConfigs?.isAIManagerAccessControl == true ? 'Enabled' : 'Disabled',
1203
+ CameraEdit: previousData?.featureConfigs?.isCameraEdit == true ? 'Enabled' : 'Disabled',
1188
1204
  };
1189
1205
 
1190
1206
  // Prepare activity log object with all relevant details for OpenSearch logging
@@ -1342,8 +1358,17 @@ export async function updateDocuments( req, res ) {
1342
1358
  };
1343
1359
 
1344
1360
  updateKeys.push( 'Address certificate' );
1361
+ let xssCheckData=await getXsscheck( uploadDataParams.body );
1362
+
1363
+ if ( xssCheckData==true ) {
1364
+ return res.sendError( 'Unsupported Media Type', 415 );
1365
+ }
1366
+
1367
+ let uploadStatus= await fileRestrictedUpload( uploadDataParams );
1345
1368
 
1346
- await fileUpload( uploadDataParams );
1369
+ if ( uploadStatus==false ) {
1370
+ return res.sendError( 'Unsupported Media Type', 415 );
1371
+ }
1347
1372
  }
1348
1373
  if ( req.files?.gstDoc ) {
1349
1374
  const uploadDataParams = {
@@ -1356,7 +1381,17 @@ export async function updateDocuments( req, res ) {
1356
1381
 
1357
1382
  updateKeys.push( 'GST certificate' );
1358
1383
 
1359
- await fileUpload( uploadDataParams );
1384
+ let xssCheckData=await getXsscheck( uploadDataParams.body );
1385
+
1386
+ if ( xssCheckData==true ) {
1387
+ return res.sendError( 'Unsupported Media Type', 415 );
1388
+ }
1389
+
1390
+ let uploadStatus= await fileRestrictedUpload( uploadDataParams );
1391
+
1392
+ if ( uploadStatus==false ) {
1393
+ return res.sendError( 'Unsupported Media Type', 415 );
1394
+ }
1360
1395
  }
1361
1396
  if ( req.files?.panDoc ) {
1362
1397
  const uploadDataParams = {
@@ -1369,7 +1404,17 @@ export async function updateDocuments( req, res ) {
1369
1404
 
1370
1405
  updateKeys.push( 'PAN certificate' );
1371
1406
 
1372
- await fileUpload( uploadDataParams );
1407
+ let xssCheckData=await getXsscheck( uploadDataParams.body );
1408
+
1409
+ if ( xssCheckData==true ) {
1410
+ return res.sendError( 'Unsupported Media Type', 415 );
1411
+ }
1412
+
1413
+ let uploadStatus= await fileRestrictedUpload( uploadDataParams );
1414
+
1415
+ if ( uploadStatus==false ) {
1416
+ return res.sendError( 'Unsupported Media Type', 415 );
1417
+ }
1373
1418
  }
1374
1419
  if ( req.files?.cinDoc ) {
1375
1420
  const uploadDataParams = {
@@ -1382,7 +1427,11 @@ export async function updateDocuments( req, res ) {
1382
1427
 
1383
1428
  updateKeys.push( 'CIN certificate' );
1384
1429
 
1385
- await fileUpload( uploadDataParams );
1430
+ let uploadStatus= await fileRestrictedUpload( uploadDataParams );
1431
+
1432
+ if ( uploadStatus==false ) {
1433
+ return res.sendError( 'Unsupported Media Type', 415 );
1434
+ }
1386
1435
  }
1387
1436
 
1388
1437
  const updateAck = await documentsUpdate( {
@@ -2855,3 +2904,36 @@ export async function AuditConfiglist( req, res ) {
2855
2904
  return res.sendError( 'Internal Server Error', 500 );
2856
2905
  }
2857
2906
  }
2907
+
2908
+
2909
+ export async function revopconfig( req, res ) {
2910
+ try {
2911
+ let result = await findOnerevopConfig( { clientId: req.body.clientId } );
2912
+
2913
+ if ( result===null ) {
2914
+ await createrevopConfig( req.body );
2915
+ return res.sendSuccess( 'revopconfig created Sucessfully' );
2916
+ } else {
2917
+ await updaterevopConfig( { clientId: req.body.clientId }, req.body );
2918
+ return res.sendSuccess( 'revopconfig updated Sucessfully' );
2919
+ }
2920
+ } catch ( error ) {
2921
+ logger.error( { error: error, message: req.body, function: 'revopconfig' } );
2922
+ return res.sendError( 'Internal Server Error', 500 );
2923
+ }
2924
+ }
2925
+
2926
+ export async function getrevopconfig( req, res ) {
2927
+ try {
2928
+ let result = await findOnerevopConfig( { clientId: req.query.clientId } );
2929
+ if ( result===null ) {
2930
+ return res.sendError( 'no data found', 204 );
2931
+ }
2932
+ return res.sendSuccess( result );
2933
+ } catch ( error ) {
2934
+ logger.error( { error: error, message: req.query, function: 'revopconfig' } );
2935
+ return res.sendError( 'Internal Server Error', 500 );
2936
+ }
2937
+ }
2938
+
2939
+
@@ -120,10 +120,15 @@ export const featureConfigurationSchemaBody = joi.object(
120
120
  isNOB: joi.boolean().optional(),
121
121
  isNewZoneV2: joi.boolean().optional(),
122
122
  isTrax: joi.boolean().optional(),
123
+ isRevops: joi.boolean().optional(),
123
124
  isControlCenter: joi.boolean().optional(),
124
125
  isFootfallDirectoryAudit: joi.boolean().optional(),
125
126
  isFootfallDirectoryLimit: joi.boolean().optional(),
126
127
  streamBy: joi.string().optional(),
128
+ isFootfallView: joi.boolean().optional(),
129
+ isAIManager: joi.boolean().optional(),
130
+ isAIManagerAccessControl: joi.boolean().optional(),
131
+ isCameraEdit: joi.boolean().optional(),
127
132
  },
128
133
  );
129
134
 
@@ -318,3 +323,23 @@ export const AuditConfiglistValid = joi.object( {
318
323
  export const createAuditConfigValid = {
319
324
  body: createAuditConfigBody,
320
325
  };
326
+
327
+ export const revopconfigBody = joi.object( {
328
+ clientId: joi.string().required(),
329
+ issueList: joi.array().items(
330
+ joi.object( {
331
+ name: joi.string().required(),
332
+ issues: joi.array().required(),
333
+ } ),
334
+ ).required(),
335
+ } );
336
+ export const revopconfiggetBody = joi.object( {
337
+ clientId: joi.string().required(),
338
+ } );
339
+
340
+ export const revopconfigValid = {
341
+ body: revopconfigBody,
342
+ };
343
+ export const revopconfiggetValid = {
344
+ query: revopconfiggetBody,
345
+ };
@@ -1,171 +1,171 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8">
5
- <meta http-equiv="x-ua-compatible" content="ie=edge">
6
- <title>Your account was approved!</title>
7
- <meta name="viewport" content="width=device-width, initial-scale=1">
8
- <style type="text/css">
9
- @media screen {
10
- @font-face {
11
- font-family: 'Inter';
12
- font-style: normal;
13
- font-weight: 400;
14
- font-display: swap;
15
- src: local("Inter"), local("Inter-Regular"), url(https://fonts.gstatic.com/s/inter/v12/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZJhiI2B.woff2) format('woff2');
16
- unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
17
- }
18
- }
19
-
20
- body {
21
- font-family: "Inter", sans-serif !important;
22
- }
23
-
24
- body,
25
- table,
26
- td,
27
- a {
28
- -ms-text-size-adjust: 100%;
29
- -webkit-text-size-adjust: 100%;
30
- }
31
-
32
- table,
33
- td {
34
- mso-table-rspace: 0pt;
35
- mso-table-lspace: 0pt;
36
- }
37
-
38
- img {
39
- -ms-interpolation-mode: bicubic;
40
- }
41
-
42
- a[x-apple-data-detectors] {
43
- font-family: "inherit" !important;
44
- font-size: inherit !important;
45
- font-weight: inherit !important;
46
- line-height: inherit !important;
47
- color: inherit !important;
48
- text-decoration: none !important;
49
- }
50
-
51
- div[style*="margin: 16px 0;"] {
52
- margin: 0 !important;
53
- }
54
-
55
- body {
56
- width: 100% !important;
57
- height: 100% !important;
58
- padding: 0 !important;
59
- margin: 0 !important;
60
- }
61
-
62
- table {
63
- border-collapse: collapse !important;
64
- }
65
-
66
- a {
67
- color: #1a82e2;
68
- }
69
-
70
- img {
71
- height: auto;
72
- line-height: 100%;
73
- text-decoration: none;
74
- border: 0;
75
- outline: none;
76
- }
77
- </style>
78
- </head>
79
- <body style="background-color: #dbe5ea;">
80
- <div class="preheader" style="display: none; max-width: 0; max-height: 0; overflow: hidden; font-size: 1px; line-height: 1px; color: #fff; opacity: 0;"> Email Summary (Hidden) </div>
81
- <table border="0" cellpadding="0" cellspacing="0" width="100%" style="padding-left:10px;padding-right:10px">
82
- <tr>
83
- <td bgcolor="#dbe5ea" style="padding:32px 10px 0 10px">
84
- <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;" align="center">
85
- <tr>
86
- <td class="o_bg-white o_px-md o_py-md o_sans o_text" style="margin-top: 0px;margin-bottom: 0px;font-size: 16px;line-height: 24px;background-color: #ffffff;padding-left: 18px;padding-right: 24px;padding-top: 24px;padding-bottom: 24px;">
87
- <p style="margin-top: 0px;margin-bottom: 0px;">
88
- <a class="o_text-white" href="https://tangoeye.ai/" style="text-decoration: none;outline: none;color: #ffffff;">
89
- <img src={{logo}} width="200" height="100" alt="SimpleApp" style="-ms-interpolation-mode: bicubic;vertical-align: middle;border: 0;line-height: 100%;height: auto;outline: none;text-decoration: none;">
90
- </a>
91
- </p>
92
- </td>
93
- </tr>
94
- <tr>
95
- <td align="left" bgcolor="#ffffff" style="padding-left: 30px;padding-right: 24px; font-size: 14px; line-height: 24px;">
96
- <p class="o_heading o_mb-xxs" style="width: 544px;height: 0px;border: 1px solid #CBD5E1;flex: none;order: 1;flex-grow: 0;"></p>
97
- </td>
98
- </tr>
99
- </table>
100
- </td>
101
- </tr>
102
- <tr>
103
- <td align="center" bgcolor="#dbe5ea" style="padding:0 10px 0 10px">
104
- <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
105
- <tr>
106
- <td class="o_bg-white o_px-md o_py-xl o_xs-py-md" style="background-color: #ffffff;padding-left: 30px;padding-right: 24px;padding-top: 10px;padding-bottom: 10px;">
107
- <div class="o_col-6s o_sans o_text-md o_text-light o_center" style="margin-top: 0px;margin-bottom: 0px;font-size: 20px;line-height: 28px;color: #82899a;">
108
- <span class="o_heading o_text-dark o_mb-xxs" style="font-weight: 700;margin-top: 0px;margin-bottom: 4px;color: #242b3d;line-height: 39px;"> Your account was approved!</span>
109
- </div>
110
- </td>
111
- </tr>
112
- </table>
113
- </td>
114
- </tr>
115
- <tr>
116
- <td align="center" bgcolor="#dbe5ea" style="padding:0 10px 0 10px">
117
- <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
118
- <tr>
119
- <td align="left" bgcolor="#ffffff" style="padding-left: 30px;padding-right: 24px; font-size: 16px;padding-top:10px; line-height: 24px;font-weight:400;color:#384860">
120
- <p style="margin: 0;">As a verified user, you will be among the first to receive product updates, new feature announcements, enhanced security and personalised support.
121
- <br><br>
122
- Head over to the dashboard to finish your setup. </p>
123
- </td>
124
- </tr>
125
- </table>
126
- </td>
127
- </tr>
128
- <tr>
129
- <td align="center" bgcolor="#dbe5ea" style="padding:0 10px 0 10px">
130
- <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
131
- <tr>
132
- <td align="left" bgcolor="#fff" style="border-radius: 6px;padding:14px 30px">
133
- <a href={{url}} style="display: inline-block;padding: 10px 36px;font-size: 20px;color: #fff;text-decoration: none;border-radius: 6px;background-color: #00a3ff;"> Add Stores</a>
134
- </td>
135
- </tr>
136
- </table>
137
- </td>
138
- </tr>
139
- <tr>
140
- <td align="center" bgcolor="#dbe5ea" style="padding:0 10px 0 10px">
141
- <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
142
- <tr>
143
- <td align="left" bgcolor="#ffffff" style="padding-left: 30px;padding-right: 24px; font-size: 16px;padding-top:10px; line-height: 24px;font-weight:400;color:#384860">
144
- <p style="margin: 0;">Enjoy the full potential of Tango Traffic Module. If you have any questions or need assistance, our support team is here to help.
145
-
146
- <br><br>
147
-
148
- Happy exploring! </p>
149
- </td>
150
- </tr>
151
- </table>
152
- </td>
153
- </tr>
154
- <tr>
155
- <td align="center" bgcolor="#dbe5ea" style="padding:0 10px 32px 10px">
156
- <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
157
- <tr>
158
- <td class="o_bg-white o_px-md o_py-xl o_xs-py-md" style="background-color: #ffffff;padding-left: 30px;padding-right: 24px;padding-bottom:15px">
159
- <div class="o_col-6s o_sans o_text-md o_text-light o_center" style="margin-top: 0px;margin-bottom: 0px;font-size: 12px;color: #202B3C;font-style: normal;font-weight: 400;font-size: 12px;line-height: 150%;">
160
- <br>
161
- <p>If you'd rather not receive this kind of email, Don’t want any more emails from TangoEye?<u style="color:#00A3FF">Unsubscribe</u>.</p>
162
- <p> © Tango Eye. All rights reserved.</p>
163
- </div>
164
- </td>
165
- </tr>
166
- </table>
167
- </td>
168
- </tr>
169
- </table>
170
- </body>
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta http-equiv="x-ua-compatible" content="ie=edge">
6
+ <title>Your account was approved!</title>
7
+ <meta name="viewport" content="width=device-width, initial-scale=1">
8
+ <style type="text/css">
9
+ @media screen {
10
+ @font-face {
11
+ font-family: 'Inter';
12
+ font-style: normal;
13
+ font-weight: 400;
14
+ font-display: swap;
15
+ src: local("Inter"), local("Inter-Regular"), url(https://fonts.gstatic.com/s/inter/v12/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZJhiI2B.woff2) format('woff2');
16
+ unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
17
+ }
18
+ }
19
+
20
+ body {
21
+ font-family: "Inter", sans-serif !important;
22
+ }
23
+
24
+ body,
25
+ table,
26
+ td,
27
+ a {
28
+ -ms-text-size-adjust: 100%;
29
+ -webkit-text-size-adjust: 100%;
30
+ }
31
+
32
+ table,
33
+ td {
34
+ mso-table-rspace: 0pt;
35
+ mso-table-lspace: 0pt;
36
+ }
37
+
38
+ img {
39
+ -ms-interpolation-mode: bicubic;
40
+ }
41
+
42
+ a[x-apple-data-detectors] {
43
+ font-family: "inherit" !important;
44
+ font-size: inherit !important;
45
+ font-weight: inherit !important;
46
+ line-height: inherit !important;
47
+ color: inherit !important;
48
+ text-decoration: none !important;
49
+ }
50
+
51
+ div[style*="margin: 16px 0;"] {
52
+ margin: 0 !important;
53
+ }
54
+
55
+ body {
56
+ width: 100% !important;
57
+ height: 100% !important;
58
+ padding: 0 !important;
59
+ margin: 0 !important;
60
+ }
61
+
62
+ table {
63
+ border-collapse: collapse !important;
64
+ }
65
+
66
+ a {
67
+ color: #1a82e2;
68
+ }
69
+
70
+ img {
71
+ height: auto;
72
+ line-height: 100%;
73
+ text-decoration: none;
74
+ border: 0;
75
+ outline: none;
76
+ }
77
+ </style>
78
+ </head>
79
+ <body style="background-color: #dbe5ea;">
80
+ <div class="preheader" style="display: none; max-width: 0; max-height: 0; overflow: hidden; font-size: 1px; line-height: 1px; color: #fff; opacity: 0;"> Email Summary (Hidden) </div>
81
+ <table border="0" cellpadding="0" cellspacing="0" width="100%" style="padding-left:10px;padding-right:10px">
82
+ <tr>
83
+ <td bgcolor="#dbe5ea" style="padding:32px 10px 0 10px">
84
+ <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;" align="center">
85
+ <tr>
86
+ <td class="o_bg-white o_px-md o_py-md o_sans o_text" style="margin-top: 0px;margin-bottom: 0px;font-size: 16px;line-height: 24px;background-color: #ffffff;padding-left: 18px;padding-right: 24px;padding-top: 24px;padding-bottom: 24px;">
87
+ <p style="margin-top: 0px;margin-bottom: 0px;">
88
+ <a class="o_text-white" href="https://tangoeye.ai/" style="text-decoration: none;outline: none;color: #ffffff;">
89
+ <img src={{logo}} width="200" height="100" alt="SimpleApp" style="-ms-interpolation-mode: bicubic;vertical-align: middle;border: 0;line-height: 100%;height: auto;outline: none;text-decoration: none;">
90
+ </a>
91
+ </p>
92
+ </td>
93
+ </tr>
94
+ <tr>
95
+ <td align="left" bgcolor="#ffffff" style="padding-left: 30px;padding-right: 24px; font-size: 14px; line-height: 24px;">
96
+ <p class="o_heading o_mb-xxs" style="width: 544px;height: 0px;border: 1px solid #CBD5E1;flex: none;order: 1;flex-grow: 0;"></p>
97
+ </td>
98
+ </tr>
99
+ </table>
100
+ </td>
101
+ </tr>
102
+ <tr>
103
+ <td align="center" bgcolor="#dbe5ea" style="padding:0 10px 0 10px">
104
+ <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
105
+ <tr>
106
+ <td class="o_bg-white o_px-md o_py-xl o_xs-py-md" style="background-color: #ffffff;padding-left: 30px;padding-right: 24px;padding-top: 10px;padding-bottom: 10px;">
107
+ <div class="o_col-6s o_sans o_text-md o_text-light o_center" style="margin-top: 0px;margin-bottom: 0px;font-size: 20px;line-height: 28px;color: #82899a;">
108
+ <span class="o_heading o_text-dark o_mb-xxs" style="font-weight: 700;margin-top: 0px;margin-bottom: 4px;color: #242b3d;line-height: 39px;"> Your account was approved!</span>
109
+ </div>
110
+ </td>
111
+ </tr>
112
+ </table>
113
+ </td>
114
+ </tr>
115
+ <tr>
116
+ <td align="center" bgcolor="#dbe5ea" style="padding:0 10px 0 10px">
117
+ <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
118
+ <tr>
119
+ <td align="left" bgcolor="#ffffff" style="padding-left: 30px;padding-right: 24px; font-size: 16px;padding-top:10px; line-height: 24px;font-weight:400;color:#384860">
120
+ <p style="margin: 0;">As a verified user, you will be among the first to receive product updates, new feature announcements, enhanced security and personalised support.
121
+ <br><br>
122
+ Head over to the dashboard to finish your setup. </p>
123
+ </td>
124
+ </tr>
125
+ </table>
126
+ </td>
127
+ </tr>
128
+ <tr>
129
+ <td align="center" bgcolor="#dbe5ea" style="padding:0 10px 0 10px">
130
+ <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
131
+ <tr>
132
+ <td align="left" bgcolor="#fff" style="border-radius: 6px;padding:14px 30px">
133
+ <a href={{url}} style="display: inline-block;padding: 10px 36px;font-size: 20px;color: #fff;text-decoration: none;border-radius: 6px;background-color: #00a3ff;"> Add Stores</a>
134
+ </td>
135
+ </tr>
136
+ </table>
137
+ </td>
138
+ </tr>
139
+ <tr>
140
+ <td align="center" bgcolor="#dbe5ea" style="padding:0 10px 0 10px">
141
+ <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
142
+ <tr>
143
+ <td align="left" bgcolor="#ffffff" style="padding-left: 30px;padding-right: 24px; font-size: 16px;padding-top:10px; line-height: 24px;font-weight:400;color:#384860">
144
+ <p style="margin: 0;">Enjoy the full potential of Tango Traffic Module. If you have any questions or need assistance, our support team is here to help.
145
+
146
+ <br><br>
147
+
148
+ Happy exploring! </p>
149
+ </td>
150
+ </tr>
151
+ </table>
152
+ </td>
153
+ </tr>
154
+ <tr>
155
+ <td align="center" bgcolor="#dbe5ea" style="padding:0 10px 32px 10px">
156
+ <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
157
+ <tr>
158
+ <td class="o_bg-white o_px-md o_py-xl o_xs-py-md" style="background-color: #ffffff;padding-left: 30px;padding-right: 24px;padding-bottom:15px">
159
+ <div class="o_col-6s o_sans o_text-md o_text-light o_center" style="margin-top: 0px;margin-bottom: 0px;font-size: 12px;color: #202B3C;font-style: normal;font-weight: 400;font-size: 12px;line-height: 150%;">
160
+ <br>
161
+ <p>If you'd rather not receive this kind of email, Don’t want any more emails from TangoEye?<u style="color:#00A3FF">Unsubscribe</u>.</p>
162
+ <p> © Tango Eye. All rights reserved.</p>
163
+ </div>
164
+ </td>
165
+ </tr>
166
+ </table>
167
+ </td>
168
+ </tr>
169
+ </table>
170
+ </body>
171
171
  </html> `
@@ -3,9 +3,9 @@ import express from 'express';
3
3
  import { activityLogValid, auditConfigValid, billingDetailsValid, brandInfoValid, clientCreationValid, clientDetailsValid, documentsValid, domainDetailsValid, featureConfigurationValid, getAssignedClientValid, getAuditConfigValid, postClientCamApprovalValid, signatoryDetailsValid, ticketConfigurationValid, userConfigurationValid } from '../dtos/client.dtos.js';
4
4
  import { auditConfiguration, changeStatus, clientCsmAssignAction, clientDetails, create, csmAssignConfirmation, domainDetailsConfiguration, getActivityLogs, getAuditConfiguration, getClients, getCsmUsers, getOpsUsers, updateBillingDetails, updateBrandInfo, updateDocuments, updateFeatureConfiguration, updateSignatoryDetails, updateTicketConfiguration, userConfiguration } from '../controllers/client.controllers.js';
5
5
  import { accessVerification, isAllowedSessionHandler, validate } from 'tango-app-api-middleware';
6
- import { clientListValid, detailedClientCountValid, createAuditConfigValid, AuditConfiglistValid } from '../dtos/client.dtos.js';
6
+ import { clientListValid, detailedClientCountValid, createAuditConfigValid, AuditConfiglistValid, revopconfigValid, revopconfiggetValid } from '../dtos/client.dtos.js';
7
7
  import { isclientIdExists, isclientNameExists, roleVerification } from '../validations/client.validations.js';
8
- import { detailedAllClientCount, detailedClientCount, clientList, clientListV1, createAuditConfig, updateAuditConfig, AuditConfiglist } from '../controllers/client.controllers.js';
8
+ import { detailedAllClientCount, detailedClientCount, clientList, clientListV1, createAuditConfig, updateAuditConfig, AuditConfiglist, revopconfig, getrevopconfig } from '../controllers/client.controllers.js';
9
9
 
10
10
  export const clientRouter = express.Router();
11
11
 
@@ -107,3 +107,9 @@ clientRouter.put( '/updateAuditConfig/:id', isAllowedSessionHandler,
107
107
  clientRouter.post( '/AuditConfiglist', isAllowedSessionHandler,
108
108
  validate( AuditConfiglistValid ), AuditConfiglist );
109
109
 
110
+ clientRouter.post( '/revopconfig', isAllowedSessionHandler,
111
+ validate( revopconfigValid ), revopconfig );
112
+ clientRouter.get( '/revopconfig', isAllowedSessionHandler,
113
+ validate( revopconfiggetValid ), getrevopconfig );
114
+
115
+
@@ -160,10 +160,15 @@ export function featureConfigurationUpdate( query, inputData ) {
160
160
  'featureConfigs.isNOB': inputData?.isNOB,
161
161
  'featureConfigs.isNewZoneV2': inputData?.isNewZoneV2,
162
162
  'featureConfigs.isTrax': inputData?.isTrax,
163
+ 'featureConfigs.isRevops': inputData?.isRevops,
163
164
  'featureConfigs.isControlCenter': inputData?.isControlCenter,
164
165
  'featureConfigs.isFootfallDirectoryAudit': inputData?.isFootfallDirectoryAudit,
165
166
  'featureConfigs.isFootfallDirectoryLimit': inputData?.isFootfallDirectoryLimit,
166
167
  'featureConfigs.streamBy': inputData?.streamBy,
168
+ 'featureConfigs.isFootfallView': inputData?.isFootfallView,
169
+ 'featureConfigs.isAIManager': inputData?.isAIManager,
170
+ 'featureConfigs.isAIManagerAccessControl': inputData?.isAIManagerAccessControl,
171
+ 'featureConfigs.isCameraEdit': inputData?.isCameraEdit,
167
172
  },
168
173
  } );
169
174
  }
@@ -0,0 +1,16 @@
1
+ import revopConfigModel from 'tango-api-schema/schema/revopConfig.model.js';
2
+
3
+
4
+ export async function createrevopConfig( field = {} ) {
5
+ return await revopConfigModel.create( field );
6
+ };
7
+ export async function findOnerevopConfig( query = {} ) {
8
+ return await revopConfigModel.findOne( query );
9
+ };
10
+
11
+ export async function updaterevopConfig( data={}, field = {} ) {
12
+ return await revopConfigModel.updateOne( data, { $set: field } );
13
+ };
14
+ export async function aggregaterevopconfig( data ) {
15
+ return await revopConfigModel.aggregate( data );
16
+ };