tango-app-api-analysis-zone 3.0.0-alpha.5 → 3.0.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { logger, download } from 'tango-app-api-middleware';
|
|
2
|
+
|
|
3
|
+
// Lamda Service Call //
|
|
4
|
+
async function LamdaServiceCall( url, data ) {
|
|
5
|
+
try {
|
|
6
|
+
const requestOptions = {
|
|
7
|
+
method: 'POST',
|
|
8
|
+
headers: {
|
|
9
|
+
'Content-Type': 'application/json',
|
|
10
|
+
},
|
|
11
|
+
body: JSON.stringify( data ),
|
|
12
|
+
};
|
|
13
|
+
const response = await fetch( url, requestOptions );
|
|
14
|
+
if ( !response.ok ) {
|
|
15
|
+
throw new Error( `Response status: ${response.status}` );
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
const json = await response.json();
|
|
19
|
+
return json;
|
|
20
|
+
} catch ( error ) {
|
|
21
|
+
console.log( 'error =>', error );
|
|
22
|
+
logger.error( { error: error, message: data, function: 'LamdaServiceCall' } );
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// ///// V1 API's ///////
|
|
27
|
+
export const cardsAgeAnalysisV1 = async ( req, res ) => {
|
|
28
|
+
try {
|
|
29
|
+
let reqestData = req.body;
|
|
30
|
+
let LamdaURL = 'https://oybi27bocyk4zysjdcni7ueaxe0gzunc.lambda-url.ap-south-1.on.aws/';
|
|
31
|
+
let resultData = await LamdaServiceCall( LamdaURL, reqestData );
|
|
32
|
+
if ( resultData ) {
|
|
33
|
+
if ( resultData.status_code == '200' ) {
|
|
34
|
+
return res.sendSuccess( resultData );
|
|
35
|
+
} else {
|
|
36
|
+
return res.sendError( 'No Content', 204 );
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
return res.sendError( 'No Content', 204 );
|
|
40
|
+
}
|
|
41
|
+
} catch ( error ) {
|
|
42
|
+
logger.error( { error: error, message: req.query, function: 'cardsFunnelV1' } );
|
|
43
|
+
return res.sendError( { error: error }, 500 );
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const topPerformingZonesV1 = async ( req, res ) => {
|
|
48
|
+
try {
|
|
49
|
+
let reqestData = req.body;
|
|
50
|
+
let LamdaURL = 'https://qcv73azgbnc4f33fbbi4yjosp40aaevs.lambda-url.ap-south-1.on.aws/';
|
|
51
|
+
let resultData = await LamdaServiceCall( LamdaURL, reqestData );
|
|
52
|
+
if ( resultData ) {
|
|
53
|
+
if ( resultData.status_code == '200' ) {
|
|
54
|
+
return res.sendSuccess( resultData );
|
|
55
|
+
} else {
|
|
56
|
+
return res.sendError( 'No Content', 204 );
|
|
57
|
+
}
|
|
58
|
+
} else {
|
|
59
|
+
return res.sendError( 'No Content', 204 );
|
|
60
|
+
}
|
|
61
|
+
} catch ( error ) {
|
|
62
|
+
logger.error( { error: error, message: req.query, function: 'topPerformingZonesV1' } );
|
|
63
|
+
return res.sendError( { error: error }, 500 );
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const topPerformingStoresV1 = async ( req, res ) => {
|
|
68
|
+
try {
|
|
69
|
+
let reqestData = req.body;
|
|
70
|
+
let LamdaURL = 'https://judkzgsc2tipbvwhgs7h7rxmfq0bedpy.lambda-url.ap-south-1.on.aws/';
|
|
71
|
+
let resultData = await LamdaServiceCall( LamdaURL, reqestData );
|
|
72
|
+
if ( resultData ) {
|
|
73
|
+
if ( resultData.status_code == '200' ) {
|
|
74
|
+
if ( reqestData.export ) {
|
|
75
|
+
if ( resultData.topPerformingStores.length>0 ) {
|
|
76
|
+
const exportdata = [];
|
|
77
|
+
resultData.topPerformingStores.forEach( ( element ) => {
|
|
78
|
+
exportdata.push( {
|
|
79
|
+
'Store Name': element.storeName,
|
|
80
|
+
'Zone Name': element.zoneName,
|
|
81
|
+
'Concentration Rate': element.concentrationRate,
|
|
82
|
+
'Overall Footfall': element.overallFootfall,
|
|
83
|
+
'Zone Footfall': element.zoneFootfall,
|
|
84
|
+
'AVG DwellTime': element.avgDwellTime,
|
|
85
|
+
} );
|
|
86
|
+
} );
|
|
87
|
+
return await download( exportdata, res );
|
|
88
|
+
} else {
|
|
89
|
+
return res.sendError( 'No Content', 204 );
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
return res.sendSuccess( resultData );
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
return res.sendError( 'No Content', 204 );
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
return res.sendError( 'No Content', 204 );
|
|
99
|
+
}
|
|
100
|
+
} catch ( error ) {
|
|
101
|
+
logger.error( { error: error, message: req.query, function: 'topPerformingStoresV1' } );
|
|
102
|
+
return res.sendError( { error: error }, 500 );
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export const zoneSummaryTableV1 = async ( req, res ) => {
|
|
107
|
+
try {
|
|
108
|
+
let reqestData = req.body;
|
|
109
|
+
let LamdaURL = 'https://hxpnn5weq3lm4nqouk4pjm3chy0jmqdb.lambda-url.ap-south-1.on.aws/';
|
|
110
|
+
let resultData = await LamdaServiceCall( LamdaURL, reqestData );
|
|
111
|
+
if ( resultData ) {
|
|
112
|
+
if ( resultData.status_code == '200' ) {
|
|
113
|
+
if ( reqestData.export ) {
|
|
114
|
+
if ( resultData.zoneSummaryData.length>0 ) {
|
|
115
|
+
const exportdata = [];
|
|
116
|
+
resultData.zoneSummaryData.forEach( ( element ) => {
|
|
117
|
+
exportdata.push( {
|
|
118
|
+
'Store Name': element.storeName,
|
|
119
|
+
'Store Id': element.storeId,
|
|
120
|
+
'Date': element.date,
|
|
121
|
+
'Footfall Count': element.footfallCount,
|
|
122
|
+
'Bounced Count': element.bouncedCount,
|
|
123
|
+
'Engagers Count': element.engagersCount,
|
|
124
|
+
'Concentration Rate': element.concentrationRate,
|
|
125
|
+
'AVG Dwell Time': element.avgDwellTime,
|
|
126
|
+
'Male': element.male,
|
|
127
|
+
'Female': element.female,
|
|
128
|
+
'below12': element.below12,
|
|
129
|
+
'13-19': element['13-19'],
|
|
130
|
+
'20-30': element['20-30'],
|
|
131
|
+
'31-40': element['31-40'],
|
|
132
|
+
'41-50': element['41-50'],
|
|
133
|
+
'51-60': element['51-60'],
|
|
134
|
+
'60 above': element['60 above'],
|
|
135
|
+
} );
|
|
136
|
+
} );
|
|
137
|
+
return await download( exportdata, res );
|
|
138
|
+
} else {
|
|
139
|
+
return res.sendError( 'No Content', 204 );
|
|
140
|
+
}
|
|
141
|
+
} else {
|
|
142
|
+
return res.sendSuccess( resultData );
|
|
143
|
+
}
|
|
144
|
+
} else {
|
|
145
|
+
return res.sendError( 'No Content', 204 );
|
|
146
|
+
}
|
|
147
|
+
} else {
|
|
148
|
+
return res.sendError( 'No Content', 204 );
|
|
149
|
+
}
|
|
150
|
+
} catch ( error ) {
|
|
151
|
+
logger.error( { error: error, message: req.query, function: 'zoneSummaryTableV1' } );
|
|
152
|
+
return res.sendError( { error: error }, 500 );
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
export const zoneConcentrationSummaryTableV1 = async ( req, res ) => {
|
|
157
|
+
try {
|
|
158
|
+
let reqestData = req.body;
|
|
159
|
+
let LamdaURL = 'https://ebinpkkji5wghr6rwm7jojwstu0idgiu.lambda-url.ap-south-1.on.aws/';
|
|
160
|
+
let resultData = await LamdaServiceCall( LamdaURL, reqestData );
|
|
161
|
+
if ( resultData ) {
|
|
162
|
+
if ( resultData.status_code == '200' ) {
|
|
163
|
+
return res.sendSuccess( resultData );
|
|
164
|
+
} else {
|
|
165
|
+
return res.sendError( 'No Content', 204 );
|
|
166
|
+
}
|
|
167
|
+
} else {
|
|
168
|
+
return res.sendError( 'No Content', 204 );
|
|
169
|
+
}
|
|
170
|
+
} catch ( error ) {
|
|
171
|
+
logger.error( { error: error, message: req.query, function: 'cardsFunnelV1' } );
|
|
172
|
+
return res.sendError( { error: error }, 500 );
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
export const zoneHeatmapAvailableDatesV1 = async ( req, res ) => {
|
|
177
|
+
try {
|
|
178
|
+
let reqestData = req.body;
|
|
179
|
+
reqestData.hourFormat = 12;
|
|
180
|
+
let LamdaURL = 'https://p3xcs56mkjj4sfugvsibhyto3i0gdbda.lambda-url.ap-south-1.on.aws/';
|
|
181
|
+
let resultData = await LamdaServiceCall( LamdaURL, reqestData );
|
|
182
|
+
if ( resultData ) {
|
|
183
|
+
if ( resultData.status_code == '200' ) {
|
|
184
|
+
return res.sendSuccess( resultData );
|
|
185
|
+
} else {
|
|
186
|
+
return res.sendError( 'No Content', 204 );
|
|
187
|
+
}
|
|
188
|
+
} else {
|
|
189
|
+
return res.sendError( 'No Content', 204 );
|
|
190
|
+
}
|
|
191
|
+
} catch ( error ) {
|
|
192
|
+
logger.error( { error: error, message: req.query, function: 'cardsFunnelV1' } );
|
|
193
|
+
return res.sendError( { error: error }, 500 );
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
export const zoneHeatmapDatasV1 = async ( req, res ) => {
|
|
198
|
+
try {
|
|
199
|
+
let reqestData = req.body;
|
|
200
|
+
let LamdaURL = 'https://wtcllrsyec4iwkx6sg7xi2b7se0seawx.lambda-url.ap-south-1.on.aws/';
|
|
201
|
+
let resultData = await LamdaServiceCall( LamdaURL, reqestData );
|
|
202
|
+
if ( resultData ) {
|
|
203
|
+
if ( resultData.status_code == '200' ) {
|
|
204
|
+
return res.sendSuccess( resultData );
|
|
205
|
+
} else {
|
|
206
|
+
return res.sendError( 'No Content', 204 );
|
|
207
|
+
}
|
|
208
|
+
} else {
|
|
209
|
+
return res.sendError( 'No Content', 204 );
|
|
210
|
+
}
|
|
211
|
+
} catch ( error ) {
|
|
212
|
+
logger.error( { error: error, message: req.query, function: 'cardsFunnelV1' } );
|
|
213
|
+
return res.sendError( { error: error }, 500 );
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
export async function isAllowedClient( req, res, next ) {
|
|
218
|
+
try {
|
|
219
|
+
let reqestData = req.body;
|
|
220
|
+
let getUserEmail = req.user.email;
|
|
221
|
+
let getUserType = req.user.userType;
|
|
222
|
+
let getClientId = req.user.clientId;
|
|
223
|
+
let getRole = req.user.role;
|
|
224
|
+
if ( getUserType == 'tango' ) {
|
|
225
|
+
if ( getRole == 'superadmin' ) {
|
|
226
|
+
next();
|
|
227
|
+
} else {
|
|
228
|
+
const assignedQuery = {
|
|
229
|
+
userEmail: getUserEmail,
|
|
230
|
+
assignedType: 'client',
|
|
231
|
+
assignedValue: reqestData.clientId,
|
|
232
|
+
};
|
|
233
|
+
const getAssignedType = await findOneUserAssignedStore( assignedQuery );
|
|
234
|
+
if ( getAssignedType ) {
|
|
235
|
+
next();
|
|
236
|
+
} else {
|
|
237
|
+
return res.sendError( 'Client Not Assigned', 400 );
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
} else if ( getUserType == 'client' ) {
|
|
241
|
+
if ( getClientId == reqestData.clientId ) {
|
|
242
|
+
next();
|
|
243
|
+
} else {
|
|
244
|
+
return res.sendError( 'Client Not Assigned', 400 );
|
|
245
|
+
}
|
|
246
|
+
} else {
|
|
247
|
+
return res.sendError( 'Client Not Assigned', 400 );
|
|
248
|
+
}
|
|
249
|
+
} catch ( error ) {
|
|
250
|
+
logger.error( { error: error, function: 'isAllowedClient' } );
|
|
251
|
+
return res.sendError( error, 500 );
|
|
252
|
+
}
|
|
253
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import joi from 'joi';
|
|
2
|
+
|
|
3
|
+
// Base schema
|
|
4
|
+
const baseSchema = {
|
|
5
|
+
clientId: joi.string().required(),
|
|
6
|
+
storeId: joi.array().required().empty(),
|
|
7
|
+
fromDate: joi.string().required(),
|
|
8
|
+
toDate: joi.string().required(),
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// Schema for Card Funnel
|
|
12
|
+
export const validateCardsAgeAnalysisSchema = joi.object( {
|
|
13
|
+
...baseSchema,
|
|
14
|
+
} );
|
|
15
|
+
|
|
16
|
+
export const validateCardsAgeAnalysisParams = {
|
|
17
|
+
body: validateCardsAgeAnalysisSchema,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// Schema for Card Graph (extends baseSchema with additional fields)
|
|
21
|
+
export const validateTopPerformingZonesSchema = joi.object( {
|
|
22
|
+
...baseSchema,
|
|
23
|
+
} );
|
|
24
|
+
|
|
25
|
+
export const validateTopPerformingZonesParams = {
|
|
26
|
+
body: validateTopPerformingZonesSchema,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const validateTopPerformingStoresSchema = joi.object( {
|
|
30
|
+
...baseSchema,
|
|
31
|
+
search: joi.string().optional().allow( '' ),
|
|
32
|
+
export: joi.boolean().required(),
|
|
33
|
+
} );
|
|
34
|
+
|
|
35
|
+
export const validateTopPerformingStoresParams = {
|
|
36
|
+
body: validateTopPerformingStoresSchema,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const validateZoneSummaryTableSchema = joi.object( {
|
|
40
|
+
...baseSchema,
|
|
41
|
+
search: joi.string().optional().allow( '' ),
|
|
42
|
+
sortBy: joi.number().optional().allow( '' ),
|
|
43
|
+
sort: joi.string().optional().allow( '' ),
|
|
44
|
+
limit: joi.number().required(),
|
|
45
|
+
offset: joi.number().required(),
|
|
46
|
+
export: joi.boolean().required(),
|
|
47
|
+
} );
|
|
48
|
+
|
|
49
|
+
export const validateZoneSummaryTableParams = {
|
|
50
|
+
body: validateZoneSummaryTableSchema,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const validateZoneConcentrationSummaryTableSchema = joi.object( {
|
|
54
|
+
...baseSchema,
|
|
55
|
+
search: joi.string().optional().allow( '' ),
|
|
56
|
+
sortBy: joi.number().optional().allow( '' ),
|
|
57
|
+
sort: joi.string().optional().allow( '' ),
|
|
58
|
+
} );
|
|
59
|
+
|
|
60
|
+
export const validateZoneConcentrationSummaryTableParams = {
|
|
61
|
+
body: validateZoneConcentrationSummaryTableSchema,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const validateZoneHeatmapAvailableDatesSchema = joi.object( {
|
|
65
|
+
...baseSchema,
|
|
66
|
+
zoneName: joi.string().required(),
|
|
67
|
+
dateType: joi.string().required(),
|
|
68
|
+
} );
|
|
69
|
+
|
|
70
|
+
export const validateZoneHeatmapAvailableDatesParams = {
|
|
71
|
+
body: validateZoneHeatmapAvailableDatesSchema,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export const validateZoneHeatmapDatasSchema = joi.object( {
|
|
75
|
+
...baseSchema,
|
|
76
|
+
zoneName: joi.string().required(),
|
|
77
|
+
dateType: joi.string().required(),
|
|
78
|
+
zoneDate: joi.string().required(),
|
|
79
|
+
} );
|
|
80
|
+
|
|
81
|
+
export const validateZoneHeatmapDatasParams = {
|
|
82
|
+
body: validateZoneHeatmapDatasSchema,
|
|
83
|
+
};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
|
+
import { validate, isAllowedSessionHandler, authorize } from 'tango-app-api-middleware';
|
|
3
|
+
import * as validationDtos from '../dtos/validation.dtos.js';
|
|
2
4
|
|
|
3
5
|
export const analysisZoneRouter = express.Router();
|
|
4
6
|
|
|
@@ -13,6 +15,17 @@ import {
|
|
|
13
15
|
zoneHeatmapDatas,
|
|
14
16
|
} from '../controllers/analysisZone.controllers.js';
|
|
15
17
|
|
|
18
|
+
import {
|
|
19
|
+
cardsAgeAnalysisV1,
|
|
20
|
+
topPerformingZonesV1,
|
|
21
|
+
topPerformingStoresV1,
|
|
22
|
+
zoneSummaryTableV1,
|
|
23
|
+
zoneConcentrationSummaryTableV1,
|
|
24
|
+
zoneHeatmapAvailableDatesV1,
|
|
25
|
+
zoneHeatmapDatasV1,
|
|
26
|
+
isAllowedClient,
|
|
27
|
+
} from '../controllers/analysisZoneV1.controllers.js';
|
|
28
|
+
|
|
16
29
|
analysisZoneRouter
|
|
17
30
|
.get( '/welcome', welcome )
|
|
18
31
|
.post( '/cardsAgeAnalysis', cardsAgeAnalysis )
|
|
@@ -21,6 +34,41 @@ analysisZoneRouter
|
|
|
21
34
|
.post( '/zoneSummaryTable', zoneSummaryTable )
|
|
22
35
|
.post( '/zoneConcentrationSummaryTable', zoneConcentrationSummaryTable )
|
|
23
36
|
.post( '/zoneHeatmapAvailableDates', zoneHeatmapAvailableDates )
|
|
24
|
-
.post( '/zoneHeatmapDatas', zoneHeatmapDatas )
|
|
37
|
+
.post( '/zoneHeatmapDatas', zoneHeatmapDatas )
|
|
38
|
+
.post( '/cardsAgeAnalysis_v1', isAllowedSessionHandler, isAllowedClient, authorize( {
|
|
39
|
+
userType: [ 'tango', 'client' ], access: [
|
|
40
|
+
{ featureName: 'analytics', name: 'tangoZone', permissions: [ 'isView' ] },
|
|
41
|
+
],
|
|
42
|
+
} ), validate( validationDtos.validateCardsAgeAnalysisParams ), cardsAgeAnalysisV1 )
|
|
43
|
+
.post( '/topPerformingZones_v1', isAllowedSessionHandler, isAllowedClient, authorize( {
|
|
44
|
+
userType: [ 'tango', 'client' ], access: [
|
|
45
|
+
{ featureName: 'analytics', name: 'tangoZone', permissions: [ 'isView' ] },
|
|
46
|
+
],
|
|
47
|
+
} ), validate( validationDtos.validateTopPerformingZonesParams ), topPerformingZonesV1 )
|
|
48
|
+
.post( '/topPerformingStores_v1', isAllowedSessionHandler, isAllowedClient, authorize( {
|
|
49
|
+
userType: [ 'tango', 'client' ], access: [
|
|
50
|
+
{ featureName: 'analytics', name: 'tangoZone', permissions: [ 'isView' ] },
|
|
51
|
+
],
|
|
52
|
+
} ), validate( validationDtos.validateTopPerformingStoresParams ), topPerformingStoresV1 )
|
|
53
|
+
.post( '/zoneSummaryTable_v1', isAllowedSessionHandler, isAllowedClient, authorize( {
|
|
54
|
+
userType: [ 'tango', 'client' ], access: [
|
|
55
|
+
{ featureName: 'analytics', name: 'tangoZone', permissions: [ 'isView' ] },
|
|
56
|
+
],
|
|
57
|
+
} ), validate( validationDtos.validateZoneSummaryTableParams ), zoneSummaryTableV1 )
|
|
58
|
+
.post( '/zoneConcentrationSummaryTable_v1', isAllowedSessionHandler, isAllowedClient, authorize( {
|
|
59
|
+
userType: [ 'tango', 'client' ], access: [
|
|
60
|
+
{ featureName: 'analytics', name: 'tangoZone', permissions: [ 'isView' ] },
|
|
61
|
+
],
|
|
62
|
+
} ), validate( validationDtos.validateZoneConcentrationSummaryTableParams ), zoneConcentrationSummaryTableV1 )
|
|
63
|
+
.post( '/zoneHeatmapAvailableDates_v1', isAllowedSessionHandler, isAllowedClient, authorize( {
|
|
64
|
+
userType: [ 'tango', 'client' ], access: [
|
|
65
|
+
{ featureName: 'analytics', name: 'tangoZone', permissions: [ 'isView' ] },
|
|
66
|
+
],
|
|
67
|
+
} ), validate( validationDtos.validateZoneHeatmapAvailableDatesParams ), zoneHeatmapAvailableDatesV1 )
|
|
68
|
+
.post( '/zoneHeatmapDatas_v1', isAllowedSessionHandler, isAllowedClient, authorize( {
|
|
69
|
+
userType: [ 'tango', 'client' ], access: [
|
|
70
|
+
{ featureName: 'analytics', name: 'tangoZone', permissions: [ 'isView' ] },
|
|
71
|
+
],
|
|
72
|
+
} ), validate( validationDtos.validateZoneHeatmapDatasParams ), zoneHeatmapDatasV1 );
|
|
25
73
|
|
|
26
74
|
export default analysisZoneRouter;
|