tango-app-api-store-zone 3.3.1-beta.0 → 3.3.1-beta.10

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/app.js ADDED
@@ -0,0 +1,43 @@
1
+
2
+ import express from 'express';
3
+ import { zoneTaggingRouter } from './index.js';
4
+
5
+ import dotenv from 'dotenv';
6
+ import { logger } from 'tango-app-api-middleware';
7
+ import { connectdb } from './config/database/database.js';
8
+ import responseMiddleware from './config/response/response.js';
9
+ import errorMiddleware from './config/response/error.js';
10
+ import pkg from 'body-parser';
11
+ import cors from 'cors';
12
+ // import swagger from 'swagger-ui-express';
13
+ // import { swaggerConfig } from './config/swagger/swagger.js';
14
+
15
+ const { json, urlencoded } = pkg;
16
+
17
+ const env=dotenv.config();
18
+
19
+ const app = express();
20
+ const PORT = process.env.PORT || 3000;
21
+
22
+
23
+ if ( env.error ) {
24
+ logger.error( '.env not found' );
25
+ process.exit( 1 );
26
+ }
27
+ app.use( cors() );
28
+ app.use( responseMiddleware );
29
+ app.use( errorMiddleware );
30
+ app.use( json( { limit: '500mb' } ) );
31
+ app.use(
32
+ urlencoded( {
33
+ extended: true,
34
+ } ),
35
+ );
36
+ app.use( '/zoneTagging', zoneTaggingRouter );
37
+ // app.use( '/api-docs', swagger.serve, swagger.setup( swaggerConfig ) );
38
+
39
+ app.listen( PORT, () => {
40
+ connectdb();
41
+ } );
42
+
43
+
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "tango-app-api-store-zone",
3
- "version": "3.3.1-beta.0",
3
+ "version": "3.3.1-beta.10",
4
4
  "description": "zone",
5
- "main": "index.js",
5
+ "main": "app.js",
6
6
  "type": "module",
7
7
  "scripts": {
8
- "start": "nodemon --exec \"eslint --fix . && node index.js\""
8
+ "start": "nodemon --exec \"eslint --fix . && node app.js\""
9
9
  },
10
10
  "engines": {
11
11
  "node": ">=18.10.0"
@@ -17,12 +17,12 @@
17
17
  "dotenv": "^16.4.5",
18
18
  "express": "^4.19.2",
19
19
  "handlebars": "^4.7.8",
20
- "joi-to-swagger": "^6.2.0",
20
+ "joi": "^17.12.1",
21
21
  "mongodb": "^6.5.0",
22
22
  "nodemon": "^3.1.0",
23
23
  "swagger-ui-express": "^5.0.0",
24
- "tango-api-schema": "^2.0.115",
25
- "tango-app-api-middleware": "^3.1.19",
24
+ "tango-api-schema": "^2.3.26",
25
+ "tango-app-api-middleware": "^3.1.43-alpha.6",
26
26
  "winston": "^3.13.0",
27
27
  "winston-daily-rotate-file": "^5.0.0"
28
28
  },
@@ -5,6 +5,8 @@ import * as storeService from '../services/store.service.js';
5
5
  import * as clientService from '../services/client.service.js';
6
6
  import * as externalService from '../services/external.service.js';
7
7
  import { signedUrl, listFileByPath, fileUpload, insertOpenSearchData } from 'tango-app-api-middleware';
8
+ import * as processedchecklistconfigService from '../services/processedchecklistconfig.services.js';
9
+
8
10
  import axios from 'axios';
9
11
  export const addCustomTag = async ( req, res ) => {
10
12
  try {
@@ -15,6 +17,9 @@ export const addCustomTag = async ( req, res ) => {
15
17
  clientId: inputData.clientId,
16
18
  storeId: inputData.storeId,
17
19
  tagName: inputData.tagName,
20
+ rgbColor: inputData.rgbColor,
21
+ productName: inputData.productName,
22
+ rgbBorderColor: inputData.rgbBorderColor,
18
23
  };
19
24
  await taggingService.deleteMany( { clientId: inputData.clientId, storeId: inputData.storeId, tagName: inputData.tagName, isDeleted: true } );
20
25
  await taggingService.create( data );
@@ -28,8 +33,8 @@ export const addCustomTag = async ( req, res ) => {
28
33
  date: new Date(),
29
34
  logType: 'zone',
30
35
  logSubType: 'addCustomTag',
31
- changes: [ `${inputData.tagName} customtag Created.` ],
32
- eventType: '',
36
+ changes: [ `${inputData.tagName} custom tag` ],
37
+ eventType: 'create',
33
38
  showTo: [ 'client', 'tango' ],
34
39
  };
35
40
  insertOpenSearchData( JSON.parse( process.env.OPENSEARCH )?.activityLog, logObj );
@@ -42,7 +47,7 @@ export const addCustomTag = async ( req, res ) => {
42
47
 
43
48
  export const customTagList = async ( req, res ) => {
44
49
  try {
45
- let customTagList = [ 'Front', 'Back' ];
50
+ let customTagList = [ 'Front', 'Back', 'Tracker-in', 'Tracker-out' ];
46
51
  let storeDetails = await storeService.findOne( { storeId: req.query.storeId }, { product: 1 } );
47
52
  let clientDetails = await clientService.findOne( { clientId: req.query.clientId }, { featureConfigs: 1 } );
48
53
  if ( clientDetails && clientDetails?.featureConfigs?.isExcludedArea ) {
@@ -54,7 +59,10 @@ export const customTagList = async ( req, res ) => {
54
59
  if ( storeDetails && storeDetails?.product.includes( 'tangoZone' ) ) {
55
60
  customTagList = customTagList.concat( [ 'Entry/Exit', 'Billing' ] );
56
61
  }
57
- let tagInfo = await taggingService.find( { clientId: req.query.clientId }, { tagName: 1 } );
62
+ let tagInfo = await taggingService.find( { clientId: req.query.clientId }, { tagName: 1, rgbColor: 1, rgbBorderColor: 1 } );
63
+
64
+ const allTags = tagInfo;
65
+
58
66
  let deletedTag = await taggingService.find( { clientId: req.query.clientId, isDeleted: true }, { storeId: 1, tagName: 1 } );
59
67
  tagInfo = [ ...new Set( tagInfo.map( ( item ) => item.tagName ) ) ];
60
68
  deletedTag.forEach( ( item ) => {
@@ -90,10 +98,13 @@ export const customTagList = async ( req, res ) => {
90
98
  tagName: '$_id',
91
99
  count: 1,
92
100
 
101
+
93
102
  },
94
103
  },
95
104
  ];
96
105
  let taggingDetails = await taggingService.aggregate( query );
106
+
107
+
97
108
  customTagList = customTagList.map( ( item ) => {
98
109
  let count = '';
99
110
  if ( taggingDetails.length ) {
@@ -107,12 +118,231 @@ export const customTagList = async ( req, res ) => {
107
118
  return { tagName: item, count: count };
108
119
  } );
109
120
  customTagList.sort( ( a, b ) => a.count > b.count ? -1 : 1 );
121
+
122
+ const allTagsMap = new Map( allTags.map( ( tag ) => [ tag.tagName, tag ] ) );
123
+
124
+ customTagList.forEach( ( i ) => {
125
+ const matchingTag = allTagsMap.get( i.tagName );
126
+ if ( matchingTag ) {
127
+ i.rgbColor = matchingTag.rgbColor;
128
+ i.rgbBorderColor = matchingTag.rgbBorderColor;
129
+ }
130
+
131
+ if ( i.tagName === 'Front' ) {
132
+ i.rgbColor = 'rgba(89, 80, 5, 0.5)';
133
+ i.rgbBorderColor = 'rgb(99, 90, 15)';
134
+ }
135
+ if ( i.tagName === 'Back' ) {
136
+ i.rgbColor = 'rgba(94, 60, 107, 0.5)';
137
+ i.rgbBorderColor = 'rgb(104, 70, 117)';
138
+ }
139
+ if ( i.tagName === 'Excluded Area' ) {
140
+ i.rgbColor = 'rgba(186, 60, 214, 0.5)';
141
+ i.rgbBorderColor = 'rgb(196, 70, 224)';
142
+ }
143
+ if ( i.tagName === 'Passer By' ) {
144
+ i.rgbColor = 'rgba(81, 153, 247, 0.5)';
145
+ i.rgbBorderColor = 'rgb(91, 163, 257)';
146
+ }
147
+ if ( i.tagName === 'Entry/Exit' ) {
148
+ i.rgbColor = 'rgba(224, 43, 170, 0.5)';
149
+ i.rgbBorderColor = 'rgb(234, 53, 180)';
150
+ }
151
+ if ( i.tagName === 'Billing' ) {
152
+ i.rgbColor = 'rgba(193, 214, 114, 0.5)';
153
+ i.rgbBorderColor = 'rgb(203, 224, 124)';
154
+ }
155
+ if ( i.tagName === 'Tracker-in' ) {
156
+ i.rgbColor = 'rgba(123, 95, 105, 0.5)';
157
+ i.rgbBorderColor = 'rgb(133, 105, 115)';
158
+ }
159
+ if ( i.tagName === 'Tracker-out' ) {
160
+ i.rgbColor = 'rgba(12, 195, 111, 0.5)';
161
+ i.rgbBorderColor = 'rgb(22, 205, 125)';
162
+ }
163
+ } );
164
+
110
165
  return res.sendSuccess( customTagList );
111
166
  } catch ( e ) {
112
167
  logger.error( { error: e, function: 'customTagList' } );
113
168
  return res.sendError( e, 500 );
114
169
  }
115
170
  };
171
+ export const customTagListv2 = async ( req, res ) => {
172
+ try {
173
+ // Step 1: Base tag list
174
+ let customTagList = [
175
+ { tagName: 'Front', productName: 'tangoTraffic' },
176
+ { tagName: 'Back', productName: 'tangoTraffic' },
177
+ { tagName: 'Tracker-in', productName: 'tangoTracker' },
178
+ { tagName: 'Tracker-out', productName: 'tangoTracker' },
179
+ ];
180
+
181
+ // Step 2: Fetch store & client details in parallel
182
+ const [ storeDetails, clientDetails ] = await Promise.all( [
183
+ storeService.findOne(
184
+ { storeId: req.query.storeId },
185
+ { product: 1 },
186
+ ),
187
+ clientService.findOne(
188
+ { clientId: req.query.clientId },
189
+ { featureConfigs: 1 },
190
+ ),
191
+ ] );
192
+
193
+ // Step 3: Add conditional tags
194
+ if ( clientDetails?.featureConfigs?.isExcludedArea ) {
195
+ customTagList.push( { tagName: 'Excluded Area', productName: 'tangoTraffic' } );
196
+ }
197
+ if ( clientDetails?.featureConfigs?.isPasserByData ) {
198
+ customTagList.push( { tagName: 'Passer By', productName: 'tangoTraffic' } );
199
+ }
200
+ if ( storeDetails?.product?.includes( 'tangoZone' ) ) {
201
+ customTagList.push(
202
+ { tagName: 'Entry/Exit', productName: 'tangoZone' },
203
+ { tagName: 'Billing', productName: 'tangoZone' },
204
+ );
205
+ }
206
+ if ( req.query.selectedProduct && req.query.selectedProduct != '' ) {
207
+ customTagList = customTagList.filter( ( ele ) => ele.productName === req.query.selectedProduct );
208
+ }
209
+ // Step 4: Fetch existing tags
210
+ const tagInfo = await taggingService.find(
211
+ { clientId: req.query.clientId, productName: req.query.selectedProduct },
212
+ { tagName: 1, rgbColor: 1, rgbBorderColor: 1, productName: 1 },
213
+ );
214
+
215
+ // Merge all tags
216
+ const mergedTags = [ ...customTagList, ...tagInfo ];
217
+
218
+ // Step 5: Build unique tag list
219
+ const uniqueTags = [ ...new Map( mergedTags.map( ( tag ) => [ tag.tagName, tag ] ) ).values() ];
220
+
221
+ // Step 6: Query counts per tag
222
+ const tagNames = uniqueTags.map( ( t ) => t.tagName );
223
+
224
+ const taggingDetails = await taggingService.aggregate( [
225
+ {
226
+ $match: {
227
+ productName: req.query.selectedProduct,
228
+ clientId: req.query.clientId,
229
+ storeId: req.query.storeId,
230
+ coordinates: { $exists: true, $ne: [] },
231
+ tagName: { $in: tagNames },
232
+ },
233
+ },
234
+ { $group: { _id: '$tagName', count: { $sum: 1 } } },
235
+ ] );
236
+
237
+ const countMap = new Map( taggingDetails.map( ( t ) => [ t._id, t.count ] ) );
238
+
239
+ // Step 7: Tag colors config (instead of many ifs)
240
+ const tagColors = {
241
+ 'Front': { rgbColor: 'rgba(89, 80, 5, 0.5)', rgbBorderColor: 'rgb(99, 90, 15)' },
242
+ 'Back': { rgbColor: 'rgba(94, 60, 107, 0.5)', rgbBorderColor: 'rgb(104, 70, 117)' },
243
+ 'Excluded Area': { rgbColor: 'rgba(186, 60, 214, 0.5)', rgbBorderColor: 'rgb(196, 70, 224)' },
244
+ 'Passer By': { rgbColor: 'rgba(81, 153, 247, 0.5)', rgbBorderColor: 'rgb(91, 163, 257)' },
245
+ 'Entry/Exit': { rgbColor: 'rgba(224, 43, 170, 0.5)', rgbBorderColor: 'rgb(234, 53, 180)' },
246
+ 'Billing': { rgbColor: 'rgba(193, 214, 114, 0.5)', rgbBorderColor: 'rgb(203, 224, 124)' },
247
+ 'Tracker-in': { rgbColor: 'rgba(123, 95, 105, 0.5)', rgbBorderColor: 'rgb(133, 105, 115)' },
248
+ 'Tracker-out': { rgbColor: 'rgba(12, 195, 111, 0.5)', rgbBorderColor: 'rgb(22, 205, 125)' },
249
+ };
250
+
251
+ // Step 8: Final processing
252
+ const finalTags = uniqueTags.map( ( tag ) => ( {
253
+ tagName: tag.tagName,
254
+ productName: tag.productName,
255
+ count: countMap.get( tag.tagName ) || 0,
256
+ rgbColor: tag.rgbColor || tagColors[tag.tagName]?.rgbColor,
257
+ rgbBorderColor: tag.rgbBorderColor || tagColors[tag.tagName]?.rgbBorderColor,
258
+ } ) );
259
+
260
+
261
+ // Step 9: Sort by count (desc)
262
+ finalTags.sort( ( a, b ) => b.count - a.count );
263
+ if ( req.query.selectedProduct && req.query.selectedProduct === 'tangoTrax' ) {
264
+ let Query = [ {
265
+ $match: {
266
+ client_id: req.query.clientId,
267
+ checkListType: { $ne: 'custom' },
268
+ },
269
+ }, {
270
+ $group: {
271
+ _id: '$sourceCheckList_id',
272
+ sourceCheckList_id: { $last: '$sourceCheckList_id' },
273
+ tagName: { $last: '$checkListName' },
274
+ },
275
+ },
276
+ {
277
+ $lookup: {
278
+ from: 'cameras',
279
+ let: { checkListName: '$tagName' },
280
+ pipeline: [
281
+ {
282
+ $match: {
283
+ $expr: {
284
+ $anyElementTrue: {
285
+ $map: {
286
+ input: { $ifNull: [ '$taggedChecklist', [] ] }, // ✅ default to empty array
287
+ as: 'tc',
288
+ in: { $eq: [ '$$tc.checkListName', '$$checkListName' ] },
289
+ },
290
+ },
291
+ },
292
+ },
293
+ },
294
+ {
295
+ $project: {
296
+ storeId: 1,
297
+ },
298
+ },
299
+ ], as: 'cameraList',
300
+ },
301
+ },
302
+
303
+ {
304
+ $project: {
305
+ tagName: 1,
306
+ type: 'checklist',
307
+ count: { $size: '$cameraList' },
308
+ },
309
+ },
310
+ {
311
+ $sort: {
312
+ count: -1,
313
+ },
314
+ },
315
+
316
+ ];
317
+ let getChecklistData = await processedchecklistconfigService.aggregate( Query );
318
+ if ( finalTags&&finalTags.length>0 ) {
319
+ let merged = getChecklistData.map( ( item ) => {
320
+ let match = finalTags.find( ( a ) => a.tagName === item.tagName );
321
+ if ( match ) {
322
+ return { ...item, ...match, count: item.count + match.count }; // add counts
323
+ }
324
+ return item;
325
+ } );
326
+
327
+ // also include any arr1 items not in arr2
328
+ finalTags.forEach( ( a ) => {
329
+ if ( !merged.find( ( m ) => m.tagName === a.tagName ) ) {
330
+ merged.push( a );
331
+ }
332
+ } );
333
+ merged.sort( ( a, b ) => b.count - a.count );
334
+ return res.sendSuccess( merged );
335
+ } else {
336
+ return res.sendSuccess( getChecklistData );
337
+ }
338
+ } else {
339
+ return res.sendSuccess( finalTags );
340
+ }
341
+ } catch ( e ) {
342
+ logger.error( { error: e, function: 'customTagList' } );
343
+ return res.sendError( e, 500 );
344
+ }
345
+ };
116
346
 
117
347
  export const tagging = async ( req, res ) => {
118
348
  try {
@@ -128,6 +358,7 @@ export const tagging = async ( req, res ) => {
128
358
  }
129
359
  } );
130
360
  let taggingDetails = await taggingService.findOne( { clientId: InputData.clientId, storeId: InputData.storeId, cameraId: InputData.cameraId, tagName: InputData.tagName, isDeleted: false } );
361
+
131
362
  if ( !taggingDetails ) {
132
363
  const logObj = {
133
364
  clientId: InputData.clientId,
@@ -137,11 +368,18 @@ export const tagging = async ( req, res ) => {
137
368
  date: new Date(),
138
369
  logType: 'zone',
139
370
  logSubType: 'addZoneTagging',
140
- changes: [ `${InputData.tagName} zone added tagging` ],
141
- eventType: '',
371
+ changes: [ `${InputData.tagName} zone tagging` ],
372
+ eventType: 'create',
142
373
  showTo: [ 'client', 'tango' ],
143
374
  };
144
375
  insertOpenSearchData( JSON.parse( process.env.OPENSEARCH )?.activityLog, logObj );
376
+ if ( InputData.coordinates[0].color ) {
377
+ InputData = { ...InputData, rgbColor: InputData.coordinates[0].color };
378
+ }
379
+
380
+ if ( InputData.coordinates[0].rgbBorderColor ) {
381
+ InputData = { ...InputData, rgbBorderColor: InputData.coordinates[0].rgbBorderColor };
382
+ }
145
383
  let response = await taggingService.create( InputData );
146
384
  await taggingService.deleteOne( { clientId: InputData.clientId, storeId: InputData.storeId, cameraId: { $exists: false }, tagName: InputData.tagName } );
147
385
  axios.post( `${JSON.parse( process.env.URL ).oldapidomain}/tagging/oldTaggingAdd`, [ response ], { headers: { Authorization: 'Bearer d47433f8-9a33-47c7-ba43-1a0fbac28f66' } } ).then( ( res ) => logger.info( res?.data ) ).catch( ( error ) => logger.error( { error: error } ) );
@@ -154,12 +392,33 @@ export const tagging = async ( req, res ) => {
154
392
  date: new Date(),
155
393
  logType: 'zone',
156
394
  logSubType: 'updateZoneTagging',
157
- changes: [ `${InputData.tagName} zone Updated tagging` ],
158
- eventType: '',
395
+ changes: [ `${InputData.tagName} zone tagging` ],
396
+ eventType: 'update',
397
+ taggingId: taggingDetails._id,
398
+ previous: [
399
+ JSON.parse( JSON.stringify( taggingDetails ) ),
400
+ ],
401
+ current: {
402
+ ...taggingDetails.toObject(),
403
+ },
404
+ oldData: {
405
+ tagName: taggingDetails.tagName,
406
+ streamName: taggingDetails.streamName,
407
+ },
408
+ newData: {
409
+ tagName: taggingDetails.tagName,
410
+ streamName: taggingDetails.streamName,
411
+ },
412
+ showTo: [ 'tango', 'client' ],
159
413
  };
414
+
415
+ delete logObj?.current?.coordinates;
416
+
160
417
  insertOpenSearchData( JSON.parse( process.env.OPENSEARCH )?.activityLog, logObj );
161
418
  taggingDetails.cameraId = InputData.cameraId;
162
419
  taggingDetails.streamName = InputData.streamName;
420
+ taggingDetails.checkListName = InputData.checkListName;
421
+ taggingDetails.productName = InputData.productName;
163
422
  // if ( req.body?.redoPoint ) {
164
423
  // taggingDetails.coordinates = InputData.coordinates[0];
165
424
  // taggingDetails.save();
@@ -192,7 +451,7 @@ export const tagging = async ( req, res ) => {
192
451
  let externalDetails = await externalService.findOne( { storeId: InputData.storeId, zoneName: InputData.tagName, clientId: InputData.clientId } );
193
452
 
194
453
  if ( !externalDetails ) {
195
- let data ={
454
+ let data = {
196
455
  'storeId': InputData.storeId,
197
456
  'clientId': InputData.clientId,
198
457
  'productName': 'tangoZone',
@@ -256,11 +515,13 @@ export const getCameraList = async ( req, res ) => {
256
515
  if ( !cameraDetails.length ) {
257
516
  return res.sendError( 'no data found', 204 );
258
517
  }
259
- const folderPath = { file_path: `${req.query.storeId}/zone_base_images/`,
518
+ const folderPath = {
519
+ file_path: `${req.query.storeId}/zone_base_images/`,
260
520
  Bucket: JSON.parse( process.env.BUCKET ).zoneBaseImage, MaxKeys: 1000,
261
521
  };
262
522
  let fileList = await listFileByPath( folderPath );
263
- const TaggedfolderPath = { file_path: `${req.query.storeId}/zone_tagged_image/`,
523
+ const TaggedfolderPath = {
524
+ file_path: `${req.query.storeId}/zone_tagged_image/`,
264
525
  Bucket: JSON.parse( process.env.BUCKET ).zoneTaggingImage, MaxKeys: 1000,
265
526
  };
266
527
  let tagFileList = await listFileByPath( TaggedfolderPath );
@@ -286,7 +547,7 @@ export const getCameraList = async ( req, res ) => {
286
547
  tagFileList.data.forEach( ( item ) => {
287
548
  if ( item.Key.length > 1 ) {
288
549
  let splitStream = item.Key.split( '/' );
289
- let getStream = splitStream[splitStream.length -1].split( '.' );
550
+ let getStream = splitStream[splitStream.length - 1].split( '.' );
290
551
 
291
552
  if ( getStream && getStream[0] == `${req.query.storeId}_${camera.streamName}` ) {
292
553
  tagPath = item.Key;
@@ -297,21 +558,23 @@ export const getCameraList = async ( req, res ) => {
297
558
  if ( fileList?.data.length ) {
298
559
  fileList.data.forEach( ( ele ) => {
299
560
  let splitStream = ele.Key.split( '/' );
300
- let getStream = splitStream[splitStream.length -1].split( '.' );
561
+ let getStream = splitStream[splitStream.length - 1].split( '.' );
301
562
  if ( getStream && getStream[0] == `${req.query.storeId}_${camera.streamName}` ) {
302
563
  imgPath = ele.Key;
303
564
  }
304
565
  } );
305
566
  }
306
567
  if ( tagPath ) {
307
- const params = { file_path: tagPath,
568
+ const params = {
569
+ file_path: tagPath,
308
570
  Bucket: JSON.parse( process.env.BUCKET ).zoneTaggingImage,
309
571
  };
310
572
  const cameraTagImage = await signedUrl( params );
311
573
  camera.tagImg = cameraTagImage;
312
574
  }
313
575
  if ( imgPath ) {
314
- const baseParams = { file_path: imgPath,
576
+ const baseParams = {
577
+ file_path: imgPath,
315
578
  Bucket: JSON.parse( process.env.BUCKET ).zoneBaseImage,
316
579
  };
317
580
  const cameraBaseImage = await signedUrl( baseParams );
@@ -327,6 +590,87 @@ export const getCameraList = async ( req, res ) => {
327
590
  return res.sendError( e, 500 );
328
591
  }
329
592
  };
593
+ export const getCameraListv2 = async ( req, res ) => {
594
+ try {
595
+ let cameraDetails = await cameraService.find( { clientId: req.query.clientId, storeId: req.query.storeId, isActivated: true, isUp: true }, { cameraNumber: 1, streamName: 1, isActivated: 1, isUp: 1, cameraName: 1, taggedChecklist: 1 } );
596
+ if ( !cameraDetails.length ) {
597
+ return res.sendError( 'no data found', 204 );
598
+ }
599
+ const folderPath = {
600
+ file_path: `${req.query.storeId}/zone_base_images/`,
601
+ Bucket: JSON.parse( process.env.BUCKET ).zoneBaseImage, MaxKeys: 1000,
602
+ };
603
+ let fileList = await listFileByPath( folderPath );
604
+ const TaggedfolderPath = {
605
+ file_path: `${req.query.storeId}/zone_tagged_image/`,
606
+ Bucket: JSON.parse( process.env.BUCKET ).zoneTaggingImage, MaxKeys: 1000,
607
+ };
608
+ let tagFileList = await listFileByPath( TaggedfolderPath );
609
+ for ( let [ index, camera ] of cameraDetails.entries() ) {
610
+ let tagList = [];
611
+ let tagPath;
612
+ let imgPath;
613
+ camera = {
614
+ ...camera._doc,
615
+ baseImg: '',
616
+ tagImg: '',
617
+ };
618
+ let taggingDetails = await taggingService.find( { cameraId: camera._id, streamName: camera.streamName, clientId: req.query.clientId, isDeleted: false }, { tagName: 1, coordinates: 1 } );
619
+ if ( taggingDetails.length ) {
620
+ tagList = taggingDetails.filter( ( item ) => item.coordinates.length ).map( ( item ) => {
621
+ if ( item.coordinates.length ) {
622
+ return { tagName: item.tagName, color: item.coordinates[0].color };
623
+ }
624
+ } );
625
+ }
626
+
627
+ if ( tagFileList.data.length ) {
628
+ tagFileList.data.forEach( ( item ) => {
629
+ if ( item.Key.length > 1 ) {
630
+ let splitStream = item.Key.split( '/' );
631
+ let getStream = splitStream[splitStream.length - 1].split( '.' );
632
+
633
+ if ( getStream && getStream[0] == `${req.query.storeId}_${camera.streamName}` ) {
634
+ tagPath = item.Key;
635
+ }
636
+ }
637
+ } );
638
+ }
639
+ if ( fileList?.data.length ) {
640
+ fileList.data.forEach( ( ele ) => {
641
+ let splitStream = ele.Key.split( '/' );
642
+ let getStream = splitStream[splitStream.length - 1].split( '.' );
643
+ if ( getStream && getStream[0] == `${req.query.storeId}_${camera.streamName}` ) {
644
+ imgPath = ele.Key;
645
+ }
646
+ } );
647
+ }
648
+ if ( tagPath ) {
649
+ const params = {
650
+ file_path: tagPath,
651
+ Bucket: JSON.parse( process.env.BUCKET ).zoneTaggingImage,
652
+ };
653
+ const cameraTagImage = await signedUrl( params );
654
+ camera.tagImg = cameraTagImage;
655
+ }
656
+ if ( imgPath ) {
657
+ const baseParams = {
658
+ file_path: imgPath,
659
+ Bucket: JSON.parse( process.env.BUCKET ).zoneBaseImage,
660
+ };
661
+ const cameraBaseImage = await signedUrl( baseParams );
662
+ camera.baseImg = cameraBaseImage;
663
+ }
664
+ camera.tagging = tagList;
665
+ cameraDetails[index] = camera;
666
+ }
667
+ cameraDetails.sort( ( a, b ) => a.tagging?.length > b.tagging?.length ? -1 : 1 );
668
+ return res.sendSuccess( cameraDetails );
669
+ } catch ( e ) {
670
+ logger.error( { error: e, function: 'getCameraListv2' } );
671
+ return res.sendError( e, 500 );
672
+ }
673
+ };
330
674
 
331
675
  export const updateTag = async ( req, res ) => {
332
676
  try {
@@ -364,17 +708,32 @@ export const updateTag = async ( req, res ) => {
364
708
  date: new Date(),
365
709
  logType: 'zone',
366
710
  logSubType: 'updateCustomTag',
367
- changes: [ `${req.body.tagName} tagName Updated` ],
368
- eventType: '',
369
- showTo: [ 'client', 'tango' ],
711
+ changes: [ `${req.body.tagName} tagName` ],
712
+ eventType: 'update',
713
+ previous: {
714
+ tagName: req.body.existTag,
715
+ },
716
+ current: {
717
+ tagName: req.body.tagName,
718
+ },
719
+ oldData: {
720
+ tagName: req.body.existTag,
721
+ },
722
+ newData: {
723
+ tagName: req.body.tagName,
724
+ },
725
+ showTo: [ 'tango', 'client' ],
370
726
  };
371
727
  insertOpenSearchData( JSON.parse( process.env.OPENSEARCH )?.activityLog, logObj );
372
728
  if ( tagUpdate.modifiedCount || tagUpdate.matchedCount ) {
729
+ await externalService.updateMany( { zoneName: req.body.existTag, clientId: req.body.clientId }, { zoneName: req.body.tagName } );
373
730
  logger.info( 'Custom Tag Updated Successfully' );
374
- return res.sendSuccess( 'Custom Tag Updated Successfully' );
731
+ updateJsonFile( req, res );
732
+ res.sendSuccess( 'Custom Tag Updated Successfully' );
733
+ } else {
734
+ logger.error( { error: 'something went wrong', function: 'updateTag' } );
735
+ return res.sendError( 'something went wrong', 500 );
375
736
  }
376
- logger.error( { error: 'something went wrong', function: 'updateTag' } );
377
- return res.sendError( 'something went wrong', 500 );
378
737
  } catch ( e ) {
379
738
  logger.error( { error: e, function: 'updateTag' } );
380
739
  return res.sendError( e, 500 );
@@ -429,9 +788,9 @@ export const deleteTag = async ( req, res ) => {
429
788
  email: req.user?.email,
430
789
  date: new Date(),
431
790
  logType: 'zone',
432
- logSubType: 'deleteTag',
433
- changes: [ `${req.body.tagName} tag Deleted` ],
434
- eventType: '',
791
+ logSubType: 'deleteCustomTag',
792
+ changes: [ `${req.body.tagName} tag` ],
793
+ eventType: 'delete',
435
794
  showTo: [ 'client', 'tango' ],
436
795
  };
437
796
  insertOpenSearchData( JSON.parse( process.env.OPENSEARCH )?.activityLog, logObj );
@@ -622,6 +981,28 @@ export const updateOldData = async ( req, res ) => {
622
981
  return res.sendError( e, 500 );
623
982
  }
624
983
  };
984
+ export async function updateCamera( req, res ) {
985
+ try {
986
+ let findoneCheckList = await processedchecklistconfigService.findOne( {
987
+ client_id: req.body.clientId, checkListName: req.body.selectedZone,
988
+ } );
989
+
990
+ let updateData = {
991
+ checkListName: req.body.selectedZone,
992
+ sourceCheckList_id: findoneCheckList?.sourceCheckList_id,
993
+ };
994
+ if ( req.body.type === 'tagCamera' ) {
995
+ await cameraService.updateOne( { _id: req.body._id }, { $push: { taggedChecklist: updateData } } );
996
+ } else {
997
+ await cameraService.updateOne( { _id: req.body._id }, { $pull: { taggedChecklist: updateData } } );
998
+ }
999
+
1000
+ res.sendSuccess( 'updated Sucessfully' );
1001
+ } catch ( e ) {
1002
+ logger.error( { error: e, function: 'updateOldData' } );
1003
+ return res.sendError( e, 500 );
1004
+ }
1005
+ };
625
1006
 
626
1007
  export const deletezoneTagging = async ( req, res ) => {
627
1008
  let data = req.body;
@@ -634,3 +1015,29 @@ export const deletezoneTagging = async ( req, res ) => {
634
1015
  await updatezoneTagging( req, res );
635
1016
  } );
636
1017
  };
1018
+
1019
+ async function updateJsonFile( req, res ) {
1020
+ if ( req.body.clientId ) {
1021
+ let tagDetails = await taggingService.find( { clientId: req.body.clientId, tagName: req.body.tagName }, { storeId: 1 } );
1022
+ if ( tagDetails.length ) {
1023
+ for ( let item of tagDetails ) {
1024
+ req.body.storeId = item.storeId;
1025
+ let camDetails = await getCamTaggingDetails( req, res );
1026
+ if ( !camDetails ) {
1027
+ logger.error( { message: 'no data', store: item.storeId } );
1028
+ }
1029
+ let fileData = {
1030
+ Key: `${req.body.storeId}/zonetagging/`,
1031
+ fileName: `${req.body.storeId}_zonetagging.json`,
1032
+ Bucket: JSON.parse( process.env.BUCKET ).zoneTaggingImage,
1033
+ body: JSON.stringify( camDetails ),
1034
+ ContentType: 'application/json',
1035
+ };
1036
+ let upload = await fileUpload( fileData );
1037
+ if ( !upload.Key ) {
1038
+ logger.error( { message: `JSON Upload Error`, store: item.storeId } );
1039
+ }
1040
+ }
1041
+ }
1042
+ }
1043
+ };
@@ -4,6 +4,9 @@ export const addTagSchema = joi.object( {
4
4
  clientId: joi.string().required(),
5
5
  tagName: joi.string().required(),
6
6
  storeId: joi.string().required(),
7
+ productName: joi.string().required(),
8
+ rgbColor: joi.string().required(),
9
+ rgbBorderColor: joi.string().required(),
7
10
  } );
8
11
 
9
12
  export const validateAddTagParams = {
@@ -50,6 +53,8 @@ export const validateTaggingSchema = joi.object( {
50
53
  streamName: joi.string().required(),
51
54
  redoPoint: joi.boolean().optional(),
52
55
  redraw: joi.boolean().optional(),
56
+ productName: joi.string().required(),
57
+ checkListName: joi.string().optional(),
53
58
  } );
54
59
 
55
60
  export const validateTaggingParams = {
@@ -1,22 +1,25 @@
1
1
 
2
2
 
3
3
  import express from 'express';
4
- import { isAllowedSessionHandler, validate, authorize } from 'tango-app-api-middleware';
4
+ import { isAllowedSessionHandler, validate, accessVerification } from 'tango-app-api-middleware';
5
5
  import * as validation from '../dtos/validation.dtos.js';
6
6
  import * as tagController from '../controllers/zoneTagging.controller.js';
7
7
 
8
8
  export const zoneTaggingRouter = express.Router();
9
9
 
10
- zoneTaggingRouter.post( '/addCustomTag', isAllowedSessionHandler, authorize( { userType: [ 'tango', 'client' ], access: [ { featureName: 'analytics', name: 'tangoZone', permissions: [ 'isEdit' ] } ] } ), validate( validation.validateAddTagParams ), tagController.addCustomTag );
11
- zoneTaggingRouter.get( '/customTagList', isAllowedSessionHandler, authorize( { userType: [ 'tango', 'client' ], access: [ { featureName: 'analytics', name: 'tangoZone', permissions: [ 'isView' ] } ] } ), validate( validation.validateTagParams ), tagController.customTagList );
12
- zoneTaggingRouter.post( '/tagging', isAllowedSessionHandler, authorize( { userType: [ 'tango', 'client' ], access: [ { featureName: 'analytics', name: 'tangoZone', permissions: [ 'isEdit' ] } ] } ), validate( validation.validateTaggingParams ), tagController.tagging );
13
- zoneTaggingRouter.get( '/cameraList', isAllowedSessionHandler, authorize( { userType: [ 'tango', 'client' ], access: [ { featureName: 'analytics', name: 'tangoZone', permissions: [ 'isView' ] } ] } ), validate( validation.validateTagParams ), tagController.getCameraList );
14
- zoneTaggingRouter.post( '/updateCustomTag', isAllowedSessionHandler, authorize( { userType: [ 'tango', 'client' ], access: [ { featureName: 'analytics', name: 'tangoZone', permissions: [ 'isEdit' ] } ] } ), validate( validation.validateUpdateTagParams ), tagController.updateTag );
15
- zoneTaggingRouter.post( '/deleteCustomTag', isAllowedSessionHandler, authorize( { userType: [ 'tango', 'client' ], access: [ { featureName: 'analytics', name: 'tangoZone', permissions: [ 'isDelete' ] } ] } ), validate( validation.validateDeleteTagParams ), tagController.deleteTag );
16
- zoneTaggingRouter.get( '/getCameraTagging', isAllowedSessionHandler, authorize( { userType: [ 'tango', 'client' ], access: [ { featureName: 'analytics', name: 'tangoZone', permissions: [ 'isView' ] } ] } ), validate( validation.validateCameraTagParams ), tagController.getCameraTagging );
17
- zoneTaggingRouter.get( '/getZoneTagging', isAllowedSessionHandler, authorize( { userType: [ 'tango', 'client' ], access: [ { featureName: 'analytics', name: 'tangoZone', permissions: [ 'isView' ] } ] } ), validate( validation.validateZonetagParams ), tagController.getZoneList );
18
- zoneTaggingRouter.post( '/updatezoneTagging', isAllowedSessionHandler, authorize( { userType: [ 'tango', 'client' ], access: [ { featureName: 'analytics', name: 'tangoZone', permissions: [ 'isEdit' ] } ] } ), validate( validation.validateCamZonetagParams ), tagController.updatezoneTagging );
19
- zoneTaggingRouter.post( '/deleteZoneTag', isAllowedSessionHandler, authorize( { userType: [ 'tango', 'client' ], access: [ { featureName: 'analytics', name: 'tangoZone', permissions: [ 'isEdit' ] } ] } ), validate( validation.updateCoordinatesParams ), tagController.deletezoneTagging );
10
+ zoneTaggingRouter.post( '/addCustomTag', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ], access: [ { featureName: 'TangoEye', name: 'ZoneTag', permissions: [ 'isAdd' ] } ] } ), validate( validation.validateAddTagParams ), tagController.addCustomTag );
11
+ zoneTaggingRouter.get( '/customTagList', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ], access: [ { featureName: 'TangoEye', name: 'ZoneTag', permissions: [ ] } ] } ), validate( validation.validateTagParams ), tagController.customTagList );
12
+ zoneTaggingRouter.get( '/customTagListv2', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ], access: [ { featureName: 'TangoEye', name: 'ZoneTag', permissions: [ ] } ] } ), tagController.customTagListv2 );
13
+ zoneTaggingRouter.post( '/tagging', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ], access: [ { featureName: 'TangoEye', name: 'ZoneTag', permissions: [ 'isEdit' ] } ] } ), validate( validation.validateTaggingParams ), tagController.tagging );
14
+ zoneTaggingRouter.get( '/cameraList', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ], access: [ { featureName: 'TangoEye', name: 'ZoneTag', permissions: [ ] } ] } ), validate( validation.validateTagParams ), tagController.getCameraList );
15
+ zoneTaggingRouter.get( '/cameraListv2', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ], access: [ { featureName: 'TangoEye', name: 'ZoneTag', permissions: [ ] } ] } ), validate( validation.validateTagParams ), tagController.getCameraListv2 );
16
+ zoneTaggingRouter.post( '/updateCustomTag', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ], access: [ { featureName: 'TangoEye', name: 'ZoneTag', permissions: [ 'isEdit' ] } ] } ), validate( validation.validateUpdateTagParams ), tagController.updateTag );
17
+ zoneTaggingRouter.post( '/deleteCustomTag', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ], access: [ { featureName: 'TangoEye', name: 'ZoneTag', permissions: [ 'isEdit' ] } ] } ), validate( validation.validateDeleteTagParams ), tagController.deleteTag );
18
+ zoneTaggingRouter.get( '/getCameraTagging', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ], access: [ { featureName: 'TangoEye', name: 'ZoneTag', permissions: [ ] } ] } ), validate( validation.validateCameraTagParams ), tagController.getCameraTagging );
19
+ zoneTaggingRouter.get( '/getZoneTagging', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ], access: [ { featureName: 'TangoEye', name: 'ZoneTag', permissions: [ ] } ] } ), validate( validation.validateZonetagParams ), tagController.getZoneList );
20
+ zoneTaggingRouter.post( '/updatezoneTagging', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ], access: [ { featureName: 'TangoEye', name: 'ZoneTag', permissions: [ 'isEdit' ] } ] } ), validate( validation.validateCamZonetagParams ), tagController.updatezoneTagging );
21
+ zoneTaggingRouter.post( '/deleteZoneTag', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ], access: [ { featureName: 'TangoEye', name: 'ZoneTag', permissions: [ 'isEdit' ] } ] } ), validate( validation.updateCoordinatesParams ), tagController.deletezoneTagging );
22
+ zoneTaggingRouter.post( '/updateCamera', isAllowedSessionHandler, accessVerification( { userType: [ 'tango', 'client' ], access: [ { featureName: 'TangoEye', name: 'ZoneTag', permissions: [ 'isEdit' ] } ] } ), tagController.updateCamera );
20
23
 
21
24
  zoneTaggingRouter.get( '/updateOldZone', tagController.updateOldData );
22
25
 
@@ -17,4 +17,8 @@ export const deleteMany = async ( query = {} ) => {
17
17
  return await model.externalParameterModel.deleteMany( query );
18
18
  };
19
19
 
20
+ export const updateMany = async ( query = {}, record={} ) => {
21
+ return await model.externalParameterModel.updateMany( query, { $set: record } );
22
+ };
23
+
20
24
 
@@ -0,0 +1,35 @@
1
+ import model from 'tango-api-schema';
2
+
3
+ export const find = ( query = {}, record = {} ) => {
4
+ return model.processedchecklistconfigModel.find( query, record );
5
+ };
6
+
7
+ export const findOne = ( query = {}, record = {} ) => {
8
+ return model.processedchecklistconfigModel.findOne( query, record ).sort( { updatedAt: -1 } );
9
+ };
10
+
11
+ export const updateOne = ( query = {}, record = {} ) => {
12
+ return model.processedchecklistconfigModel.updateOne( query, { $set: record }, { upsert: true } );
13
+ };
14
+
15
+ export const updateMany = ( query = {}, record = {} ) => {
16
+ return model.processedchecklistconfigModel.updateMany( query, { $set: record } );
17
+ };
18
+
19
+ export const deleteMany = ( query = {} ) => {
20
+ return model.processedchecklistconfigModel.deleteMany( query );
21
+ };
22
+
23
+ export const aggregate = ( query = [] ) => {
24
+ return model.processedchecklistconfigModel.aggregate( query );
25
+ };
26
+
27
+ export const getClientCount = ( query = {} ) => {
28
+ return model.processedchecklistconfigModel.count( query );
29
+ };
30
+
31
+ export const insert = ( document={} ) => {
32
+ return model.processedchecklistconfigModel.create( document );
33
+ };
34
+
35
+