tango-app-api-client 3.3.3-beta.9 → 3.4.0-beta.1
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 +4 -5
- package/src/controllers/client.controllers.js +720 -125
- package/src/docs/client.docs.js +2 -10
- package/src/hbs/approved-client.hbs +170 -170
|
@@ -142,7 +142,23 @@ export async function create( req, res ) {
|
|
|
142
142
|
'isDefaults': true,
|
|
143
143
|
};
|
|
144
144
|
|
|
145
|
-
await createclusterModel( defaultcluster );
|
|
145
|
+
const cluster = await createclusterModel( defaultcluster );
|
|
146
|
+
|
|
147
|
+
const logClusterObj = {
|
|
148
|
+
clientId: insertedClientRecord.clientId,
|
|
149
|
+
userName: req.user?.userName,
|
|
150
|
+
userId: req?.user?._id,
|
|
151
|
+
email: req.user?.email,
|
|
152
|
+
clusterId: cluster._id,
|
|
153
|
+
date: new Date(),
|
|
154
|
+
logType: 'cluster',
|
|
155
|
+
logSubType: 'clusterCreated',
|
|
156
|
+
changes: [ 'All stores' ],
|
|
157
|
+
eventType: 'create',
|
|
158
|
+
showTo: [ 'client', 'tango' ],
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
await insertOpenSearchData( openSearch.activityLog, logClusterObj );
|
|
146
162
|
|
|
147
163
|
|
|
148
164
|
const defaultGroup = {
|
|
@@ -284,6 +300,7 @@ export async function create( req, res ) {
|
|
|
284
300
|
const logObj = {
|
|
285
301
|
clientId: insertedClientRecord.clientId,
|
|
286
302
|
userName: req.user?.userName,
|
|
303
|
+
userId: req?.user?._id,
|
|
287
304
|
email: req.user?.email,
|
|
288
305
|
date: new Date(),
|
|
289
306
|
logType: 'brandDetails',
|
|
@@ -691,7 +708,7 @@ export async function updateBrandInfo( req, res ) {
|
|
|
691
708
|
ContentType: req.files.logo.mimetype,
|
|
692
709
|
body: req.files.logo.data,
|
|
693
710
|
};
|
|
694
|
-
updateKeys.push( 'Logo' );
|
|
711
|
+
updateKeys.push( 'Brand Logo' );
|
|
695
712
|
await fileUpload( uploadDataParams );
|
|
696
713
|
}
|
|
697
714
|
|
|
@@ -701,32 +718,93 @@ export async function updateBrandInfo( req, res ) {
|
|
|
701
718
|
} );
|
|
702
719
|
}
|
|
703
720
|
|
|
704
|
-
|
|
721
|
+
// Get updated client information before the update operation (fetch selected fields only)
|
|
722
|
+
const getPreCientInfo = await findOneClient(
|
|
723
|
+
{ clientId: req.params.id }, // Filter by clientId
|
|
724
|
+
{
|
|
725
|
+
'_id': 0,
|
|
726
|
+
'profileDetails.registeredCompanyName': 1,
|
|
727
|
+
'profileDetails.industry': 1,
|
|
728
|
+
'profileDetails.clientType': 1,
|
|
729
|
+
'profileDetails.registeredAddress': 1,
|
|
730
|
+
'profileDetails.headQuarters': 1,
|
|
731
|
+
'profileDetails.website': 1,
|
|
732
|
+
'status': 1,
|
|
733
|
+
'averageTransactionValue': 1,
|
|
734
|
+
},
|
|
735
|
+
);
|
|
736
|
+
|
|
705
737
|
|
|
738
|
+
const updateAck = await brandInfoUpdate( {
|
|
739
|
+
clientId: req.params?.id, registeredCompanyName: req.body?.registeredCompanyName, industry: req.body?.industry,
|
|
740
|
+
clientType: req.body?.clientType, registeredAddress: req.body?.registeredAddress, headQuarters: req.body?.headQuarters,
|
|
741
|
+
website: req.body?.website, status: req.body?.status, logo: req.files?.logo ? `brandLogo.${req.files.logo.name.split( '.' )[1]}` : undefined, averageTransactionValue: req.body?.averageTransactionValue,
|
|
742
|
+
} );
|
|
706
743
|
|
|
744
|
+
// Get updated client information after the update operation (fetch selected fields only)
|
|
745
|
+
const getPosCientInfo = await findOneClient(
|
|
746
|
+
{ clientId: req.params.id }, // Filter by clientId
|
|
747
|
+
{
|
|
748
|
+
'_id': 0,
|
|
749
|
+
'profileDetails.registeredCompanyName': 1,
|
|
750
|
+
'profileDetails.industry': 1,
|
|
751
|
+
'profileDetails.clientType': 1,
|
|
752
|
+
'profileDetails.registeredAddress': 1,
|
|
753
|
+
'profileDetails.headQuarters': 1,
|
|
754
|
+
'profileDetails.website': 1,
|
|
755
|
+
'status': 1,
|
|
756
|
+
'averageTransactionValue': 1,
|
|
757
|
+
},
|
|
758
|
+
);
|
|
759
|
+
// Map and rename keys from previous client info for UI display and logging
|
|
760
|
+
const oldData = {
|
|
761
|
+
RegisteredCompanyName: getPreCientInfo?.profileDetails?.registeredCompanyName,
|
|
762
|
+
IndustryType: getPreCientInfo?.profileDetails?.industry,
|
|
763
|
+
FirmType: getPreCientInfo?.profileDetails?.clientType,
|
|
764
|
+
RegisteredAddress: getPreCientInfo?.profileDetails?.registeredAddress,
|
|
765
|
+
HeadQuarters: getPreCientInfo?.profileDetails?.headQuarters,
|
|
766
|
+
CompanyWebsite: getPreCientInfo?.profileDetails?.website,
|
|
767
|
+
ProcessingStatus: getPreCientInfo?.status,
|
|
768
|
+
AverageTransactionValue: getPreCientInfo?.averageTransactionValue,
|
|
769
|
+
};
|
|
770
|
+
|
|
771
|
+
// Map and rename keys from current client info for UI display and logging
|
|
772
|
+
const newData ={
|
|
773
|
+
RegisteredCompanyName: getPosCientInfo?.profileDetails?.registeredCompanyName,
|
|
774
|
+
IndustryType: getPosCientInfo?.profileDetails?.industry,
|
|
775
|
+
FirmType: getPosCientInfo?.profileDetails?.clientType,
|
|
776
|
+
RegisteredAddress: getPosCientInfo?.profileDetails?.registeredAddress,
|
|
777
|
+
HeadQuarters: getPosCientInfo?.profileDetails?.headQuarters,
|
|
778
|
+
CompanyWebsite: getPosCientInfo?.profileDetails?.website,
|
|
779
|
+
ProcessingStatus: getPosCientInfo?.status,
|
|
780
|
+
AverageTransactionValue: getPosCientInfo?.averageTransactionValue,
|
|
781
|
+
|
|
782
|
+
};
|
|
783
|
+
|
|
784
|
+
// Prepare activity log object with all relevant details for OpenSearch logging
|
|
707
785
|
const logObj = {
|
|
708
|
-
clientId: req.params?.id,
|
|
709
|
-
userName: user?.userName,
|
|
710
|
-
email: user?.email,
|
|
711
|
-
date: new Date(),
|
|
712
|
-
logType: 'brandDetails',
|
|
713
|
-
logSubType: 'brandInfo',
|
|
714
|
-
changes: updateKeys,
|
|
715
|
-
eventType: 'update',
|
|
716
|
-
showTo: [ 'client', 'tango' ],
|
|
786
|
+
clientId: req.params?.id, // ID of the client whose data was updated
|
|
787
|
+
userName: req?.user?.userName, // Name of the user performing the update
|
|
788
|
+
email: req?.user?.email, // Email of the user performing the update
|
|
789
|
+
date: new Date(), // Timestamp of the update event
|
|
790
|
+
logType: 'brandDetails', // Type of log (e.g., related to brand details)
|
|
791
|
+
logSubType: 'brandInfo', // Subtype for more specific categorization
|
|
792
|
+
changes: updateKeys, // List of fields that were updated.these will shown in the UI as part of activity log
|
|
793
|
+
eventType: 'update', // Type of event (update operation)
|
|
794
|
+
showTo: [ 'client', 'tango' ], // Visibility of the log (who can see this log)
|
|
795
|
+
previous: getPreCientInfo, // Previous (old) client information before update based on DB keys (for internal reference and comparison).
|
|
796
|
+
current: getPosCientInfo, // Current (new) client information after update based on DB keys (for internal reference and comparison).
|
|
797
|
+
oldData: oldData, // Previous (old) client information before update (used for showing detailed changes in the UI).
|
|
798
|
+
newData: newData, // Current (new) client information after update (used for showing detailed changes in the UI).
|
|
717
799
|
};
|
|
800
|
+
logger.info( { logObj: logObj, updateKeys: updateKeys, length: updateKeys?.length } );
|
|
718
801
|
|
|
802
|
+
// Insert activity log into OpenSearch if there are fields that were updated
|
|
719
803
|
if ( updateKeys.length ) {
|
|
720
|
-
await insertOpenSearchData( openSearch.activityLog, logObj );
|
|
804
|
+
await insertOpenSearchData( openSearch.activityLog, logObj ); // Insert activity log
|
|
721
805
|
}
|
|
722
806
|
|
|
723
807
|
|
|
724
|
-
const updateAck = await brandInfoUpdate( {
|
|
725
|
-
clientId: req.params?.id, registeredCompanyName: req.body?.registeredCompanyName, industry: req.body?.industry,
|
|
726
|
-
clientType: req.body?.clientType, registeredAddress: req.body?.registeredAddress, headQuarters: req.body?.headQuarters,
|
|
727
|
-
website: req.body?.website, status: req.body?.status, logo: req.files?.logo ? `brandLogo.${req.files.logo.name.split( '.' )[1]}` : undefined, averageTransactionValue: req.body?.averageTransactionValue,
|
|
728
|
-
} );
|
|
729
|
-
|
|
730
808
|
if ( req.body?.status === 'active' ) {
|
|
731
809
|
await updateManyStore( { clientId: req.params?.id }, { status: 'active' } );
|
|
732
810
|
await updateManyUser( { clientId: req.params?.id }, { isActive: true } );
|
|
@@ -743,7 +821,6 @@ export async function updateBrandInfo( req, res ) {
|
|
|
743
821
|
|
|
744
822
|
if ( req.body?.status === 'deactive' ) {
|
|
745
823
|
await updateManyStore( { clientId: req.params?.id }, { status: 'deactive' } );
|
|
746
|
-
// await updateManyCamera( { clientId: req.params?.id }, { isUp: false, isActivated: false } );
|
|
747
824
|
await updateManyUser( { clientId: req.params?.id }, { isActive: false } );
|
|
748
825
|
}
|
|
749
826
|
|
|
@@ -769,7 +846,7 @@ export async function updateBrandInfo( req, res ) {
|
|
|
769
846
|
await postApi( `${url.oldapidomain}/oldBrandUpdate/${data?._id}`, { clientStatus: data.clientStatus } );
|
|
770
847
|
|
|
771
848
|
if ( updateAck ) {
|
|
772
|
-
res.sendSuccess( { result: 'Updated Successfully' } );
|
|
849
|
+
return res.sendSuccess( { result: 'Updated Successfully' } );
|
|
773
850
|
}
|
|
774
851
|
} catch ( error ) {
|
|
775
852
|
logger.error( { error: error, message: req.params, function: 'updateBrandInfo' } );
|
|
@@ -878,7 +955,25 @@ export async function updateSignatoryDetails( req, res ) {
|
|
|
878
955
|
export async function updateTicketConfiguration( req, res ) {
|
|
879
956
|
try {
|
|
880
957
|
const openSearch = JSON.parse( process.env.OPENSEARCH );
|
|
881
|
-
|
|
958
|
+
const fields ={
|
|
959
|
+
'ticketConfigs.downTimeType': 1,
|
|
960
|
+
'ticketConfigs.installationReAssign': 1,
|
|
961
|
+
'ticketConfigs.infraDownTime': 1,
|
|
962
|
+
'ticketConfigs.MinFilesCount': 1,
|
|
963
|
+
'ticketConfigs.rcaTicketAssign': 1,
|
|
964
|
+
'ticketConfigs.refreshAlert': 1,
|
|
965
|
+
'ticketConfigs.statusCheckAlert': 1,
|
|
966
|
+
'ticketConfigs.accuracyPercentage': 1,
|
|
967
|
+
'ticketConfigs.reTrain': 1,
|
|
968
|
+
};
|
|
969
|
+
|
|
970
|
+
// Get updated client ticket configuration before the update operation (fetch selected fields only)
|
|
971
|
+
let findClient = await findOneClient(
|
|
972
|
+
{ clientId: req.params?.id }, // Filter by clientId
|
|
973
|
+
fields,
|
|
974
|
+
);
|
|
975
|
+
|
|
976
|
+
// update the requested values in Mongo DB
|
|
882
977
|
const updateAck = await ticketConfigurationUpdate( {
|
|
883
978
|
clientId: req.params?.id, MinFilesCount: req.body?.MinFilesCount, accuracyPercentage: req.body?.accuracyPercentage, downTimeType: req.body?.downTimeType,
|
|
884
979
|
infraDownTime: req.body?.infraDownTime, installationReAssign: req.body?.installationReAssign, isRcaTicketAssign: req.body?.isRcaTicketAssign,
|
|
@@ -886,40 +981,75 @@ export async function updateTicketConfiguration( req, res ) {
|
|
|
886
981
|
refreshAlert: req.body?.refreshAlert, sendToAdmin: req.body?.sendToAdmin, sendToUser: req.body?.sendToUser, statusCheckAlert: req.body?.statusCheckAlert,
|
|
887
982
|
} );
|
|
888
983
|
|
|
889
|
-
let updateKeys = [];
|
|
984
|
+
let updateKeys = []; // List of updated field names in readable format
|
|
985
|
+
|
|
986
|
+
// Check if request body has any fields to update
|
|
890
987
|
if ( Object.keys( req.body ).length > 0 ) {
|
|
891
988
|
Object.keys( req.body ).forEach( ( element ) => {
|
|
892
|
-
updateKeys.push( camelCaseToWords( element ) );
|
|
989
|
+
updateKeys.push( camelCaseToWords( element ) ); // Convert camelCase field name to readable format and add to updateKeys
|
|
893
990
|
} );
|
|
894
991
|
}
|
|
895
992
|
|
|
896
|
-
const user = await getUserNameEmailById( req.userId );
|
|
897
|
-
let updatedClient = await findOneClient({clientId:req.params?.id})
|
|
898
993
|
|
|
994
|
+
// Get updated client ticket configuration after the update operation (fetch selected fields only)
|
|
995
|
+
let updatedClient = await findOneClient( { clientId: req.params?.id }, fields );
|
|
996
|
+
|
|
997
|
+
// Map and rename keys from previous client info for UI display and logging
|
|
998
|
+
const oldData = {
|
|
999
|
+
InfraDowntimeType: findClient?.ticketConfigs?.downTimeType,
|
|
1000
|
+
AutoReAssignInstallation: findClient?.ticketConfigs?.installationReAssign,
|
|
1001
|
+
InfraDowntime: findClient?.ticketConfigs?.infraDownTime,
|
|
1002
|
+
InfraFiles: findClient?.ticketConfigs?.MinFilesCount,
|
|
1003
|
+
RcaTicket: findClient?.ticketConfigs?.rcaTicketAssign,
|
|
1004
|
+
RefreshTicketAlert: findClient?.ticketConfigs?.refreshAlert,
|
|
1005
|
+
StatusCheckAlert: findClient?.ticketConfigs?.statusCheckAlert,
|
|
1006
|
+
DataMismatchAccuracyPercentage: findClient?.ticketConfigs?.accuracyPercentage,
|
|
1007
|
+
DataMismatchReTraining: findClient?.ticketConfigs?.reTrain,
|
|
1008
|
+
};
|
|
1009
|
+
|
|
1010
|
+
// Map and rename keys from current client info for UI display and logging
|
|
1011
|
+
const newData ={
|
|
1012
|
+
InfraDowntimeType: updatedClient?.ticketConfigs?.downTimeType,
|
|
1013
|
+
AutoReAssignInstallation: updatedClient?.ticketConfigs?.installationReAssign,
|
|
1014
|
+
InfraDowntime: updatedClient?.ticketConfigs?.infraDownTime,
|
|
1015
|
+
InfraFiles: updatedClient?.ticketConfigs?.MinFilesCount,
|
|
1016
|
+
RcaTicket: updatedClient?.ticketConfigs?.rcaTicketAssign,
|
|
1017
|
+
RefreshTicketAlert: updatedClient?.ticketConfigs?.refreshAlert,
|
|
1018
|
+
StatusCheckAlert: updatedClient?.ticketConfigs?.statusCheckAlert,
|
|
1019
|
+
DataMismatchAccuracyPercentage: updatedClient?.ticketConfigs?.accuracyPercentage,
|
|
1020
|
+
DataMismatchReTraining: updatedClient?.ticketConfigs?.reTrain,
|
|
1021
|
+
|
|
1022
|
+
};
|
|
1023
|
+
|
|
1024
|
+
// Prepare activity log object with all relevant details for OpenSearch logging
|
|
899
1025
|
const logObj = {
|
|
900
|
-
clientId: req.params?.id,
|
|
901
|
-
userName: user
|
|
902
|
-
email: user
|
|
903
|
-
date: new Date(),
|
|
904
|
-
logType: 'configuration',
|
|
905
|
-
logSubType: 'ticketConfig',
|
|
906
|
-
changes: updateKeys,
|
|
907
|
-
eventType: 'update',
|
|
908
|
-
showTo: [ 'tango' ],
|
|
909
|
-
current:updatedClient.ticketConfigs,
|
|
910
|
-
previous:findClient.ticketConfigs
|
|
1026
|
+
clientId: req.params?.id, // ID of the client whose data was updated
|
|
1027
|
+
userName: req?.user?.userName, // Name of the user performing the update
|
|
1028
|
+
email: req?.user?.email, // Email of the user performing the update
|
|
1029
|
+
date: new Date(), // Timestamp of the update event
|
|
1030
|
+
logType: 'configuration', // Type of log (e.g., related to brand details)
|
|
1031
|
+
logSubType: 'ticketConfig', // Subtype for more specific categorization
|
|
1032
|
+
changes: updateKeys, // List of fields that were updated.these will shown in the UI as part of activity log
|
|
1033
|
+
eventType: 'update', // Type of event (update operation)
|
|
1034
|
+
showTo: [ 'tango' ], // Visibility of the log (who can see this log)
|
|
1035
|
+
current: updatedClient.ticketConfigs, // Previous (old) client information before update based on DB keys (for internal reference and comparison).
|
|
1036
|
+
previous: findClient.ticketConfigs, // Current (new) client information after update based on DB keys (for internal reference and comparison).
|
|
1037
|
+
oldData: oldData, // Previous (old) client information before update (used for showing detailed changes in the UI).
|
|
1038
|
+
newData: newData, // Current (new) client information after update (used for showing detailed changes in the UI).
|
|
911
1039
|
};
|
|
912
1040
|
|
|
1041
|
+
// Insert activity log into OpenSearch if there are fields that were updated
|
|
913
1042
|
if ( updateKeys.length ) {
|
|
914
|
-
await insertOpenSearchData( openSearch.activityLog, logObj );
|
|
1043
|
+
await insertOpenSearchData( openSearch.activityLog, logObj ); // Insert activity log
|
|
915
1044
|
}
|
|
916
1045
|
|
|
917
1046
|
if ( updateAck ) {
|
|
918
1047
|
res.sendSuccess( { result: 'Updated Successfully' } );
|
|
919
1048
|
}
|
|
920
1049
|
} catch ( error ) {
|
|
1050
|
+
const err = error.message || 'Internal Server Error';
|
|
921
1051
|
logger.error( { error: error, message: req.params, function: 'updateTicketConfiguration' } );
|
|
922
|
-
return res.sendError(
|
|
1052
|
+
return res.sendError( err, 500 );
|
|
923
1053
|
}
|
|
924
1054
|
}
|
|
925
1055
|
|
|
@@ -927,6 +1057,9 @@ export async function updateFeatureConfiguration( req, res ) {
|
|
|
927
1057
|
try {
|
|
928
1058
|
const openSearch = JSON.parse( process.env.OPENSEARCH );
|
|
929
1059
|
const url = JSON.parse( process.env.URL );
|
|
1060
|
+
|
|
1061
|
+
// Get updated client Feature configuration before the update operation (fetch selected fields only)
|
|
1062
|
+
const previousData = await findOneClient( { clientId: req.params?.id }, { featureConfigs: 1 } );
|
|
930
1063
|
const inputData = req.body;
|
|
931
1064
|
if ( inputData?.bouncedLimitValue ) {
|
|
932
1065
|
inputData.missedOpportunityFromValue = inputData?.bouncedLimitValue;
|
|
@@ -937,11 +1070,15 @@ export async function updateFeatureConfiguration( req, res ) {
|
|
|
937
1070
|
}
|
|
938
1071
|
const updateAck = await featureConfigurationUpdate( { clientId: req.params?.id }, inputData );
|
|
939
1072
|
|
|
940
|
-
|
|
1073
|
+
// Get updated client Feature configuration after the update operation (fetch selected fields only)
|
|
1074
|
+
const postData = await findOneClient( { clientId: req.params?.id }, { featureConfigs: 1 } );
|
|
1075
|
+
let updateKeys = []; // List of updated field names in readable format
|
|
941
1076
|
|
|
1077
|
+
// Check if request body has any fields to update
|
|
942
1078
|
if ( Object.keys( inputData ).length > 0 ) {
|
|
943
1079
|
Object.keys( inputData ).forEach( ( element ) => {
|
|
944
|
-
|
|
1080
|
+
element === 'billableCalculation'? 'potentialCalculation': element; // Replace 'billableCalculation' with 'potentialCalculation' if present
|
|
1081
|
+
updateKeys.push( camelCaseToWords( element ) ); // Convert camelCase field name to readable format and add to updateKeys
|
|
945
1082
|
} );
|
|
946
1083
|
}
|
|
947
1084
|
|
|
@@ -990,21 +1127,105 @@ export async function updateFeatureConfiguration( req, res ) {
|
|
|
990
1127
|
}
|
|
991
1128
|
|
|
992
1129
|
await postApi( `${url.oldapidomain}/oldBrandUpdate/${data?._id}`, { brandConfigs: data.brandConfigs } );
|
|
1130
|
+
const keysArray = [
|
|
1131
|
+
'isExcludedArea', 'isPasserByData', 'isNormalized', 'isbillingDisabled',
|
|
1132
|
+
'isCameraDisabled', 'isFootfallDirectory', 'isNOB', 'isNewTraffic',
|
|
1133
|
+
'isTrax', 'isNewZone', 'isNewReports', 'isNewDashboard', 'streamBy',
|
|
1134
|
+
];
|
|
1135
|
+
// Map and rename keys from previous client info for UI display and logging
|
|
1136
|
+
const oldData = {
|
|
1137
|
+
StoreOpenTime: previousData?.featureConfigs?.open,
|
|
1138
|
+
StoreCloseTime: previousData?.featureConfigs?.close,
|
|
1139
|
+
ConversionCalculations: previousData?.featureConfigs?.conversionCalculation,
|
|
1140
|
+
MissedOpportunityCalculation: previousData?.featureConfigs?.missedOpportunityCalculation,
|
|
1141
|
+
PotentialCalculations: previousData?.featureConfigs?.billableCalculation,
|
|
1142
|
+
ConversionCondition: previousData?.featureConfigs?.conversion.condition,
|
|
1143
|
+
ConversionValue: previousData?.featureConfigs?.conversion.value,
|
|
1144
|
+
MissedOpportunityFromCondition: previousData?.featureConfigs?.missedOpportunityFrom?.condition,
|
|
1145
|
+
MissedOpportunityToCondition: previousData?.featureConfigs?.missedOpportunityTo?.condition,
|
|
1146
|
+
MissedOpportunityFromValue: previousData?.featureConfigs?.missedOpportunityFrom?.value,
|
|
1147
|
+
MissedOpportunityToValue: previousData?.featureConfigs?.missedOpportunityTo?.value,
|
|
1148
|
+
BouncedLimitCondition: previousData?.featureConfigs?.bouncedLimit?.condition,
|
|
1149
|
+
BouncedLimitValue: previousData?.featureConfigs?.bouncedLimit?.value,
|
|
1150
|
+
InfraAlertValue: previousData?.featureConfigs?.infraAlert?.value,
|
|
1151
|
+
InfraAlertCondition: previousData?.featureConfigs?.infraAlert?.condition,
|
|
1152
|
+
ConversionCalculations: previousData?.featureConfigs?.conversionCalculation,
|
|
1153
|
+
ExcludedArea: previousData?.featureConfigs?.isExcludedArea ==true ? 'Enable': 'Disable',
|
|
1154
|
+
PasserBydata: previousData?.featureConfigs?.isPasserByData ==true ? 'Enable': 'Disable',
|
|
1155
|
+
NormalizedDataDuringDowntime: previousData?.featureConfigs?.isNormalized ==true ? 'Enable': 'Disable',
|
|
1156
|
+
Billing: previousData?.featureConfigs?.isbillingDisabled ==true ? 'Enable': 'Disable',
|
|
1157
|
+
CameraBlurring: previousData?.featureConfigs?.isCameraDisabled ==true ? 'Enable': 'Disable',
|
|
1158
|
+
FootfallDirectory: previousData?.featureConfigs?.isFootfallDirectory ==true ? 'Enable': 'Disable',
|
|
1159
|
+
NOBStatus: previousData?.featureConfigs?.isNOB ==true ? 'Enable': 'Disable',
|
|
1160
|
+
EnableAnalyze: previousData?.featureConfigs?.isNewDashboard ==true ? 'Enable': 'Disable',
|
|
1161
|
+
Traffic: previousData?.featureConfigs?.isNewTraffic==true ? 'Enable': 'Disable',
|
|
1162
|
+
Zone: previousData?.featureConfigs?.isNewZone ==true ? 'Enable': 'Disable',
|
|
1163
|
+
Zonev2: previousData?.featureConfigs?.isNewZoneV2 ==true ? 'Enable': 'Disable',
|
|
1164
|
+
Reports: previousData?.featureConfigs?.isNewReports ==true ? 'Enable': 'Disable',
|
|
1165
|
+
Trax: previousData?.featureConfigs?.isTrax ==true ? 'Enable': 'Disable',
|
|
1166
|
+
StreamType: previousData?.featureConfigs?.streamBy =='Edge' ? 'Edge App': 'RTSP',
|
|
1167
|
+
FootfallDirectoryOnlyAudit: previousData?.featureConfigs?.isFootfallDirectoryAudit ==true ? 'Enable': 'Disable',
|
|
1168
|
+
FootfallDirectoryOnlyFew: previousData?.featureConfigs?.isFootfallDirectoryLimit ==true ? 'Enable': 'Disable',
|
|
1169
|
+
|
|
1170
|
+
};
|
|
993
1171
|
|
|
1172
|
+
// Map and rename keys from current client info for UI display and logging
|
|
1173
|
+
const newData ={
|
|
1174
|
+
StoreOpenTime: postData?.featureConfigs?.open,
|
|
1175
|
+
StoreCloseTime: postData?.featureConfigs?.close,
|
|
1176
|
+
ConversionCalculations: postData?.featureConfigs?.conversionCalculation,
|
|
1177
|
+
MissedOpportunityCalculation: postData?.featureConfigs?.missedOpportunityCalculation,
|
|
1178
|
+
PotentialCalculations: postData?.featureConfigs?.billableCalculation,
|
|
1179
|
+
ConversionCondition: postData?.featureConfigs?.conversion.condition,
|
|
1180
|
+
ConversionValue: postData?.featureConfigs?.conversion.value,
|
|
1181
|
+
MissedOpportunityFromCondition: postData?.featureConfigs?.missedOpportunityFrom?.condition,
|
|
1182
|
+
MissedOpportunityToCondition: postData?.featureConfigs?.missedOpportunityTo?.condition,
|
|
1183
|
+
MissedOpportunityFromValue: postData?.featureConfigs?.missedOpportunityFrom?.value,
|
|
1184
|
+
MissedOpportunityToValue: postData?.featureConfigs?.missedOpportunityTo?.value,
|
|
1185
|
+
BouncedLimitCondition: postData?.featureConfigs?.bouncedLimit?.condition,
|
|
1186
|
+
BouncedLimitValue: postData?.featureConfigs?.bouncedLimit?.value,
|
|
1187
|
+
InfraAlertValue: postData?.featureConfigs?.infraAlert?.value,
|
|
1188
|
+
InfraAlertCondition: postData?.featureConfigs?.infraAlert?.condition,
|
|
1189
|
+
ConversionCalculations: postData?.featureConfigs?.conversionCalculation,
|
|
1190
|
+
ExcludedArea: postData?.featureConfigs?.isExcludedArea ==true ? 'Enable': 'Disable',
|
|
1191
|
+
PasserBydata: postData?.featureConfigs?.isPasserByData ==true ? 'Enable': 'Disable',
|
|
1192
|
+
NormalizedDataDuringDowntime: postData?.featureConfigs?.isNormalized ==true ? 'Enable': 'Disable',
|
|
1193
|
+
Billing: postData?.featureConfigs?.isbillingDisabled ==true ? 'Enable': 'Disable',
|
|
1194
|
+
CameraBlurring: postData?.featureConfigs?.isCameraDisabled ==true ? 'Enable': 'Disable',
|
|
1195
|
+
FootfallDirectory: postData?.featureConfigs?.isFootfallDirectory ==true ? 'Enable': 'Disable',
|
|
1196
|
+
NOBStatus: postData?.featureConfigs?.isNOB ==true ? 'Enable': 'Disable',
|
|
1197
|
+
EnableAnalyze: postData?.featureConfigs?.isNewDashboard ==true ? 'Enable': 'Disable',
|
|
1198
|
+
Traffic: postData?.featureConfigs?.isNewTraffic==true ? 'Enable': 'Disable',
|
|
1199
|
+
Zone: postData?.featureConfigs?.isNewZone ==true ? 'Enable': 'Disable',
|
|
1200
|
+
Zonev2: postData?.featureConfigs?.isNewZoneV2 ==true ? 'Enable': 'Disable',
|
|
1201
|
+
Reports: postData?.featureConfigs?.isNewReports ==true ? 'Enable': 'Disable',
|
|
1202
|
+
Trax: postData?.featureConfigs?.isTrax ==true ? 'Enable': 'Disable',
|
|
1203
|
+
StreamType: postData?.featureConfigs?.streamBy =='Edge' ? 'Edge App': 'RTSP',
|
|
1204
|
+
FootfallDirectoryOnlyAudit: postData?.featureConfigs?.isFootfallDirectoryAudit ==true ? 'Enable': 'Disable',
|
|
1205
|
+
FootfallDirectoryOnlyFew: postData?.featureConfigs?.isFootfallDirectoryLimit ==true ? 'Enable': 'Disable',
|
|
994
1206
|
|
|
1207
|
+
};
|
|
1208
|
+
|
|
1209
|
+
// Prepare activity log object with all relevant details for OpenSearch logging
|
|
995
1210
|
const logObj = {
|
|
996
|
-
clientId: req.params?.id,
|
|
997
|
-
userName: user?.userName,
|
|
998
|
-
email: user?.email,
|
|
999
|
-
date: new Date(),
|
|
1000
|
-
logType: 'configuration',
|
|
1001
|
-
logSubType: 'featureConfig',
|
|
1002
|
-
changes: updateKeys,
|
|
1003
|
-
eventType: 'update',
|
|
1004
|
-
showTo: [ 'client', 'tango' ],
|
|
1211
|
+
clientId: req.params?.id, // ID of the client whose data was updated
|
|
1212
|
+
userName: user?.userName, // Name of the user performing the update
|
|
1213
|
+
email: user?.email, // Email of the user performing the update
|
|
1214
|
+
date: new Date(), // Timestamp of the update event
|
|
1215
|
+
logType: 'configuration', // Type of log (e.g., related to brand details)
|
|
1216
|
+
logSubType: Object.keys( inputData ).some( ( key ) => keysArray.includes( key ) ) ? 'dashboardConfig' : 'featureConfig', // Subtype for more specific categorization
|
|
1217
|
+
changes: updateKeys, // List of fields that were updated.these will shown in the UI as part of activity log
|
|
1218
|
+
eventType: 'update', // Type of event (update operation)
|
|
1219
|
+
showTo: [ 'client', 'tango' ], // Visibility of the log (who can see this log)
|
|
1220
|
+
previous: previousData.featureConfigs, // Previous (old) client information before update based on DB keys (for internal reference and comparison).
|
|
1221
|
+
current: postData.featureConfigs, // Current (new) client information after update based on DB keys (for internal reference and comparison).
|
|
1222
|
+
oldData: oldData, // Previous (old) client information before update (used for showing detailed changes in the UI).
|
|
1223
|
+
newData: newData, // Current (new) client information after update (used for showing detailed changes in the UI).
|
|
1005
1224
|
};
|
|
1225
|
+
|
|
1226
|
+
// Insert activity log into OpenSearch if there are fields that were updated
|
|
1006
1227
|
if ( updateKeys.length ) {
|
|
1007
|
-
await insertOpenSearchData( openSearch.activityLog, logObj );
|
|
1228
|
+
await insertOpenSearchData( openSearch.activityLog, logObj ); // Insert activity log
|
|
1008
1229
|
}
|
|
1009
1230
|
|
|
1010
1231
|
if ( updateAck ) {
|
|
@@ -1020,6 +1241,18 @@ export async function updateFeatureConfiguration( req, res ) {
|
|
|
1020
1241
|
export async function domainDetailsConfiguration( req, res ) {
|
|
1021
1242
|
try {
|
|
1022
1243
|
const openSearch = JSON.parse( process.env.OPENSEARCH );
|
|
1244
|
+
|
|
1245
|
+
// Get updated client domain configuration before the update operation (fetch selected fields only)
|
|
1246
|
+
const getPreData = await findOneClient(
|
|
1247
|
+
{ clientId: req.params?.id }, // filter by clientId
|
|
1248
|
+
{
|
|
1249
|
+
domainName: '$domainConfig.ssoLogin.domainName',
|
|
1250
|
+
isEnable: '$domainConfig.ssoLogin.isEnable',
|
|
1251
|
+
ipWhitelist: '$domainConfig.ipWhitelisting.enableWhitelisting',
|
|
1252
|
+
WhitelistedIps: '$domainConfig.ipWhitelisting.allowedIps',
|
|
1253
|
+
TwoFactorAuthentication: '$domainConfig.enableOtp',
|
|
1254
|
+
},
|
|
1255
|
+
);
|
|
1023
1256
|
const updateAck = await domainDetailsConfigurationUpdate( {
|
|
1024
1257
|
clientId: req.params?.id, domainName: req.body?.domainName, isEnable: req.body?.isEnable,
|
|
1025
1258
|
enableWhitelisting: req.body?.enableWhitelisting, allowedIps: req.body?.allowedIps, enableOtp: req.body?.enableOtp,
|
|
@@ -1027,30 +1260,66 @@ export async function domainDetailsConfiguration( req, res ) {
|
|
|
1027
1260
|
|
|
1028
1261
|
let updateKeys = [];
|
|
1029
1262
|
|
|
1030
|
-
|
|
1263
|
+
// Check if request body has any fields to update
|
|
1031
1264
|
if ( Object.keys( req.body ).length > 0 ) {
|
|
1032
1265
|
Object.keys( req.body ).forEach( ( element ) => {
|
|
1033
1266
|
updateKeys.push( camelCaseToWords( element ) );
|
|
1034
1267
|
} );
|
|
1035
1268
|
}
|
|
1036
1269
|
|
|
1037
|
-
|
|
1270
|
+
// Get updated client domain configuration after the update operation (fetch selected fields only)
|
|
1271
|
+
const getPostData = await findOneClient(
|
|
1272
|
+
{ clientId: req.params?.id }, // Filter by clientId
|
|
1273
|
+
{
|
|
1274
|
+
domainName: '$domainConfig.ssoLogin.domainName',
|
|
1275
|
+
isEnable: '$domainConfig.ssoLogin.isEnable',
|
|
1276
|
+
ipWhitelist: '$domainConfig.ipWhitelisting.enableWhitelisting',
|
|
1277
|
+
WhitelistedIps: '$domainConfig.ipWhitelisting.allowedIps',
|
|
1278
|
+
TwoFactorAuthentication: '$domainConfig.enableOtp',
|
|
1279
|
+
},
|
|
1280
|
+
);
|
|
1281
|
+
|
|
1038
1282
|
|
|
1283
|
+
// Map and rename keys from previous client info for UI display and logging
|
|
1284
|
+
const oldData = {
|
|
1285
|
+
DomainName: getPreData?.domainConfig?.ssoLogin?.domainName,
|
|
1286
|
+
IsEnable: getPreData?.domainConfig?.ssoLogin?.isEnable ==true ? 'Enable': 'Disable',
|
|
1287
|
+
IPWhitelist: getPreData?.domainConfig?.ipWhitelisting?.enableWhitelisting ==true ? 'Enable': 'Disable',
|
|
1288
|
+
WhitelistedIps: ( getPreData?.domainConfig?.ipWhitelisting?.allowedIps ).join( ', ' ),
|
|
1289
|
+
TwoFactorAuthentication: getPreData?.domainConfig?.enableOtp ==true ? 'Enable': 'Disable',
|
|
1290
|
+
|
|
1291
|
+
};
|
|
1039
1292
|
|
|
1293
|
+
// Map and rename keys from current client info for UI display and logging
|
|
1294
|
+
const newData ={
|
|
1295
|
+
DomainName: getPostData?.domainConfig?.ssoLogin?.domainName,
|
|
1296
|
+
IsEnable: getPostData?.domainConfig?.ssoLogin?.isEnable ==true ? 'Enable': 'Disable',
|
|
1297
|
+
IPWhitelist: getPostData?.domainConfig?.ipWhitelisting?.enableWhitelisting ==true ? 'Enable': 'Disable',
|
|
1298
|
+
WhitelistedIps: ( getPostData?.domainConfig?.ipWhitelisting?.allowedIps ).join( ', ' ),
|
|
1299
|
+
TwoFactorAuthentication: getPostData?.domainConfig?.enableOtp ==true ? 'Enable': 'Disable',
|
|
1300
|
+
};
|
|
1301
|
+
|
|
1302
|
+
|
|
1303
|
+
// Prepare activity log object with all relevant details for OpenSearch logging
|
|
1040
1304
|
const logObj = {
|
|
1041
|
-
clientId: req.params?.id,
|
|
1042
|
-
userName: user?.userName,
|
|
1043
|
-
email: user?.email,
|
|
1044
|
-
date: new Date(),
|
|
1045
|
-
logType: 'configuration',
|
|
1046
|
-
logSubType: 'domainDetails',
|
|
1047
|
-
changes: updateKeys,
|
|
1048
|
-
eventType: 'update',
|
|
1049
|
-
showTo: [ 'client', 'tango' ],
|
|
1305
|
+
clientId: req.params?.id, // ID of the client whose data was updated
|
|
1306
|
+
userName: req?.user?.userName, // Name of the user performing the update
|
|
1307
|
+
email: req?.user?.email, // Email of the user performing the update
|
|
1308
|
+
date: new Date(), // Timestamp of the update event
|
|
1309
|
+
logType: 'configuration', // Type of log (e.g., related to brand details)
|
|
1310
|
+
logSubType: 'domainDetails', // Subtype for more specific categorization
|
|
1311
|
+
changes: updateKeys, // List of fields that were updated.these will shown in the UI as part of activity log
|
|
1312
|
+
eventType: 'update', // Type of event (update operation)
|
|
1313
|
+
showTo: [ 'client', 'tango' ], // Visibility of the log (who can see this log)
|
|
1314
|
+
previous: getPreData, // Previous (old) client information before update based on DB keys (for internal reference and comparison).
|
|
1315
|
+
current: getPostData, // Current (new) client information after update based on DB keys (for internal reference and comparison).
|
|
1316
|
+
oldData: oldData, // Previous (old) client information before update (used for showing detailed changes in the UI).
|
|
1317
|
+
newData: newData, // Current (new) client information after update (used for showing detailed changes in the UI).
|
|
1050
1318
|
};
|
|
1051
1319
|
|
|
1320
|
+
// Insert activity log into OpenSearch if there are fields that were updated
|
|
1052
1321
|
if ( updateKeys.length ) {
|
|
1053
|
-
await insertOpenSearchData( openSearch.activityLog, logObj );
|
|
1322
|
+
await insertOpenSearchData( openSearch.activityLog, logObj ); // Insert activity log
|
|
1054
1323
|
}
|
|
1055
1324
|
|
|
1056
1325
|
if ( updateAck ) {
|
|
@@ -1152,7 +1421,6 @@ export async function updateDocuments( req, res ) {
|
|
|
1152
1421
|
|
|
1153
1422
|
const user = await getUserNameEmailById( req.userId );
|
|
1154
1423
|
|
|
1155
|
-
|
|
1156
1424
|
const logObj = {
|
|
1157
1425
|
clientId: req.params?.id,
|
|
1158
1426
|
userName: user?.userName,
|
|
@@ -1214,14 +1482,29 @@ export async function auditConfiguration( req, res ) {
|
|
|
1214
1482
|
auditConfigs: 1, _id: 0,
|
|
1215
1483
|
};
|
|
1216
1484
|
const previousClient = await findOneClient( query, fields );
|
|
1485
|
+
previousClient.auditConfigs.ratio = previousClient?.auditConfigs?.ratio? ( previousClient.auditConfigs.ratio )*100 : null;
|
|
1217
1486
|
const record = {
|
|
1218
1487
|
'auditConfigs.count': inputData.count,
|
|
1219
1488
|
'auditConfigs.audit': inputData.audit,
|
|
1220
1489
|
'auditConfigs.ratio': Number( normalizeNumber( inputData.ratio, 0, 100 ) ),
|
|
1221
1490
|
};
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1491
|
+
await updateOneClient( query, record );
|
|
1492
|
+
|
|
1493
|
+
|
|
1494
|
+
// Map and rename keys from previous client info for UI display and logging
|
|
1495
|
+
const oldData = {
|
|
1496
|
+
AuditStatus: inputData?.audit ==true ? 'Enable': 'Disable',
|
|
1497
|
+
MappingPercentage: inputData?.ratio,
|
|
1498
|
+
AuditCount: inputData?.count,
|
|
1499
|
+
|
|
1500
|
+
};
|
|
1501
|
+
|
|
1502
|
+
// Map and rename keys from current client info for UI display and logging
|
|
1503
|
+
const newData ={
|
|
1504
|
+
AuditStatus: previousClient.auditConfigs?.audit ==true ? 'Enable': 'Disable',
|
|
1505
|
+
MappingPercentage: previousClient.auditConfigs?.ratio,
|
|
1506
|
+
AuditCount: previousClient.auditConfigs?.count,
|
|
1507
|
+
};
|
|
1225
1508
|
const logObj = {
|
|
1226
1509
|
clientId: req.params?.id,
|
|
1227
1510
|
userName: req.user?.userName,
|
|
@@ -1232,13 +1515,15 @@ export async function auditConfiguration( req, res ) {
|
|
|
1232
1515
|
eventType: 'update',
|
|
1233
1516
|
showTo: [ 'tango' ],
|
|
1234
1517
|
changes: [ `Audit config for client id ${req.params?.id}` ],
|
|
1235
|
-
previous: previousClient,
|
|
1518
|
+
previous: previousClient.auditConfigs,
|
|
1236
1519
|
current: {
|
|
1237
1520
|
clientId: req.params?.id,
|
|
1238
1521
|
count: inputData.count,
|
|
1239
1522
|
audit: inputData.audit,
|
|
1240
|
-
ratio:
|
|
1523
|
+
ratio: inputData.ratio,
|
|
1241
1524
|
},
|
|
1525
|
+
oldData: oldData,
|
|
1526
|
+
newData: newData,
|
|
1242
1527
|
};
|
|
1243
1528
|
|
|
1244
1529
|
await insertOpenSearchData( openSearch.activityLog, logObj );
|
|
@@ -1281,17 +1566,6 @@ export async function clientList( req, res ) {
|
|
|
1281
1566
|
$match: {
|
|
1282
1567
|
userEmail: { $eq: req?.user?.email },
|
|
1283
1568
|
userType: 'tango',
|
|
1284
|
-
// $expr: {
|
|
1285
|
-
// $cond: {
|
|
1286
|
-
// if: {
|
|
1287
|
-
// $and: [
|
|
1288
|
-
// { $eq: [ '$tangoUserType', 'csm' ] },
|
|
1289
|
-
// ],
|
|
1290
|
-
// },
|
|
1291
|
-
// then: { $eq: [ '$isClientApproved', true ] },
|
|
1292
|
-
// else: true,
|
|
1293
|
-
// },
|
|
1294
|
-
// },
|
|
1295
1569
|
|
|
1296
1570
|
},
|
|
1297
1571
|
}, {
|
|
@@ -1607,17 +1881,6 @@ export async function clientListV1( req, res ) {
|
|
|
1607
1881
|
$match: {
|
|
1608
1882
|
userEmail: { $eq: req?.user?.email },
|
|
1609
1883
|
userType: 'tango',
|
|
1610
|
-
// $expr: {
|
|
1611
|
-
// $cond: {
|
|
1612
|
-
// if: {
|
|
1613
|
-
// $and: [
|
|
1614
|
-
// { $eq: [ '$tangoUserType', 'csm' ] },
|
|
1615
|
-
// ],
|
|
1616
|
-
// },
|
|
1617
|
-
// then: { $eq: [ '$isClientApproved', true ] },
|
|
1618
|
-
// else: true,
|
|
1619
|
-
// },
|
|
1620
|
-
// },
|
|
1621
1884
|
|
|
1622
1885
|
},
|
|
1623
1886
|
},
|
|
@@ -2013,9 +2276,37 @@ export async function detailedClientCount( req, res ) {
|
|
|
2013
2276
|
}
|
|
2014
2277
|
}
|
|
2015
2278
|
|
|
2016
|
-
export async function
|
|
2279
|
+
export async function getActivityLogs1( req, res ) {
|
|
2017
2280
|
try {
|
|
2281
|
+
const inputData = req.body;
|
|
2018
2282
|
const openSearch = JSON.parse( process.env.OPENSEARCH );
|
|
2283
|
+
const clientQuery =[
|
|
2284
|
+
{
|
|
2285
|
+
$match: {
|
|
2286
|
+
$and: [
|
|
2287
|
+
{
|
|
2288
|
+
clientId: { $in: inputData },
|
|
2289
|
+
},
|
|
2290
|
+
],
|
|
2291
|
+
},
|
|
2292
|
+
},
|
|
2293
|
+
{
|
|
2294
|
+
$group: {
|
|
2295
|
+
_id: null,
|
|
2296
|
+
clientName: { $push: '$clientName' },
|
|
2297
|
+
},
|
|
2298
|
+
},
|
|
2299
|
+
{
|
|
2300
|
+
$project: {
|
|
2301
|
+
_id: 0,
|
|
2302
|
+
clientName: 1,
|
|
2303
|
+
},
|
|
2304
|
+
},
|
|
2305
|
+
];
|
|
2306
|
+
const getClientName = await aggregateClient( clientQuery );
|
|
2307
|
+
if ( getClientName?.length == 0 || getClientName[0]?.clientName?.length ===0 ) {
|
|
2308
|
+
return res.sendError( 'No Data Found', 204 );
|
|
2309
|
+
}
|
|
2019
2310
|
const query = {
|
|
2020
2311
|
'_source': [
|
|
2021
2312
|
'userId', 'userName', 'email', 'date', 'logType', 'logSubType',
|
|
@@ -2023,13 +2314,27 @@ export async function getActivityLogs( req, res ) {
|
|
|
2023
2314
|
],
|
|
2024
2315
|
'query': {
|
|
2025
2316
|
'bool': {
|
|
2026
|
-
'must': [
|
|
2317
|
+
// 'must': [
|
|
2318
|
+
// {
|
|
2319
|
+
// 'terms': {
|
|
2320
|
+
// 'clientId.keyword': [ req.body.clientId ],
|
|
2321
|
+
// },
|
|
2322
|
+
// },
|
|
2323
|
+
// ],
|
|
2324
|
+
|
|
2325
|
+
'should': [
|
|
2326
|
+
{
|
|
2327
|
+
'terms': {
|
|
2328
|
+
'clientId.keyword': [ inputData.clientId ],
|
|
2329
|
+
},
|
|
2330
|
+
},
|
|
2027
2331
|
{
|
|
2028
2332
|
'terms': {
|
|
2029
|
-
'
|
|
2333
|
+
'clientName.keyword': [ getClientName[0].clientName ], // Add clientName condition
|
|
2030
2334
|
},
|
|
2031
2335
|
},
|
|
2032
2336
|
],
|
|
2337
|
+
'minimum_should_match': 1, // Ensures at least one condition must match
|
|
2033
2338
|
},
|
|
2034
2339
|
},
|
|
2035
2340
|
'from': ( req.body.offset - 1 ) * req.body.limit,
|
|
@@ -2076,30 +2381,22 @@ export async function getActivityLogs( req, res ) {
|
|
|
2076
2381
|
|
|
2077
2382
|
const hits = logs?.body?.hits?.hits;
|
|
2078
2383
|
const totalDocuments = logs?.body?.hits?.total?.value;
|
|
2384
|
+
|
|
2079
2385
|
let temp = [];
|
|
2080
2386
|
if ( totalDocuments ) {
|
|
2081
2387
|
hits.map( ( hit, i ) => {
|
|
2082
|
-
|
|
2388
|
+
let respo ={};
|
|
2389
|
+
hit._source.logSubType = hit._source.logSubType === 'documentUpload'? 'documentsUpload': hit._source.logSubType === 'domainDetails'? 'securityFeatures': hit?._source?.logSubType;
|
|
2083
2390
|
if ( ( ( hit?._source?.eventType ).match( /update/ ) || ( hit?._source?.eventType ).match( /edit/ ) )&& hit?._source?.previous ) {
|
|
2084
|
-
const previous =
|
|
2085
|
-
const current=
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
const diff = Object.entries( current )
|
|
2094
|
-
.reduce( ( acc, [ key, value ] ) => {
|
|
2095
|
-
if ( value !== previous[key] & typeof previous[key] === 'string' ) {
|
|
2096
|
-
acc[key] = { previous: previous[key], current: value };
|
|
2097
|
-
}
|
|
2098
|
-
|
|
2099
|
-
return acc;
|
|
2100
|
-
}, {} );
|
|
2101
|
-
logger.info( { diff: diff } );
|
|
2102
|
-
temp[i].updatedValue = diff;
|
|
2391
|
+
const previous = hit?._source?.previous;
|
|
2392
|
+
const current=hit?._source?.current;
|
|
2393
|
+
const logType =hit?._source?.logType;
|
|
2394
|
+
|
|
2395
|
+
const logSubType =hit?._source?.logSubType;
|
|
2396
|
+
respo = findDifferences1( previous, current, logType, logSubType );
|
|
2397
|
+
hit._source.updatedValue = respo;
|
|
2398
|
+
temp.push( hit?._source );
|
|
2399
|
+
hit._source.changes =logSubType === 'ticketConfig'? Object.keys( respo ).map( ( item ) => item ) : hit._source.changes;
|
|
2103
2400
|
} else {
|
|
2104
2401
|
temp.push( hit?._source );
|
|
2105
2402
|
}
|
|
@@ -2114,25 +2411,292 @@ export async function getActivityLogs( req, res ) {
|
|
|
2114
2411
|
return res.sendError( 'Internal Server Error', 500 );
|
|
2115
2412
|
}
|
|
2116
2413
|
}
|
|
2117
|
-
function removeIndexedKeysAndFlatten( obj ) {
|
|
2118
|
-
const result = {};
|
|
2119
2414
|
|
|
2120
|
-
for ( const [ key, value ] of Object.entries( obj ) ) {
|
|
2121
|
-
// Skip numeric keys and preserve arrays intact
|
|
2122
|
-
if ( /^\d+$/.test( key ) ) continue;
|
|
2123
2415
|
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2416
|
+
function findDifferences1( previous, current, logType, logSubType, path = '' ) {
|
|
2417
|
+
const dbKeys = JSON.parse( process.env.DB_KEYS );
|
|
2418
|
+
const ignoredKeys = new Set( [
|
|
2419
|
+
'_id', 'updatedAt', 'createdAt', 'password', 'clientId',
|
|
2420
|
+
'storeId', 'refreshToken', 'employeeId', 'fcmToken', 'permission', 'updateFeatureConfig',
|
|
2421
|
+
] );
|
|
2422
|
+
const documents = dbKeys.DOCUMENTS;
|
|
2423
|
+
// Get correct key mapping based on logType
|
|
2424
|
+
const keyMapping = logType == 'stores' ?documents.stores: logType == 'users' ?documents.users :logSubType=='reportConfig'?documents.reports: logType=='brandInfo'?documents.client:documents.client;
|
|
2425
|
+
|
|
2426
|
+
|
|
2427
|
+
let differences = {};
|
|
2428
|
+
|
|
2429
|
+
for ( const key in current ) {
|
|
2430
|
+
if ( !Object.prototype.hasOwnProperty.call( current, key ) || ignoredKeys.has( key ) ) continue;
|
|
2431
|
+
|
|
2432
|
+
const prevValue = previous[key];
|
|
2433
|
+
const currValue = current[key];
|
|
2434
|
+
|
|
2435
|
+
if ( typeof prevValue === 'object' && typeof currValue === 'object' && prevValue !== null && currValue !== null ) {
|
|
2436
|
+
if ( logSubType!== 'userUpdated' ) {
|
|
2437
|
+
if ( key == 'spocDetails' ) {
|
|
2438
|
+
if ( _.isEqual( prevValue, currValue ) ) {
|
|
2439
|
+
continue;
|
|
2440
|
+
} else {
|
|
2441
|
+
let result = compareArrayObjects( prevValue, currValue );
|
|
2442
|
+
differences = { ...differences, ...result };
|
|
2443
|
+
}
|
|
2444
|
+
} else if ( Array.isArray( prevValue ) && prevValue.every( ( item ) => typeof item === 'string' ) ||Array.isArray( currValue ) && currValue.every( ( item ) => typeof item === 'string' ) ) {
|
|
2445
|
+
JSON.stringify( prevValue ) !== JSON.stringify( currValue )?
|
|
2446
|
+
differences[`${path}${key}`] = { previous: prevValue.length> 0 ? prevValue.join( ',' ): null, current: currValue.length > 0? currValue.join( ',' ): null } : null;
|
|
2447
|
+
|
|
2448
|
+
// differences[`${path}${key}`] = { previous: removed.length> 0 ? prevValue.join( ',' ): prevValue.join( ', ' ) :, current: added.length > 0? addedUsers.join( ', ' ) : currValue.join( ',' ) } : null;
|
|
2449
|
+
} else {
|
|
2450
|
+
const nestedDiffs = findDifferences1( prevValue, currValue, logType, logSubType, `${path}${key}.` );
|
|
2451
|
+
Object.assign( differences, nestedDiffs );
|
|
2452
|
+
}
|
|
2453
|
+
} else {
|
|
2454
|
+
const nestedDiffs = findDifferences1( prevValue, currValue, logType, logSubType, `${path}${key}.` );
|
|
2455
|
+
Object.assign( differences, nestedDiffs );
|
|
2456
|
+
}
|
|
2457
|
+
} else if ( prevValue !== currValue ) {
|
|
2458
|
+
if (
|
|
2459
|
+
( prevValue === '' && currValue === '' ) ||
|
|
2460
|
+
( Array.isArray( prevValue ) && Array.isArray( currValue ) && prevValue.length === 0 && currValue.length === 0 )
|
|
2461
|
+
) {
|
|
2462
|
+
continue;
|
|
2463
|
+
}
|
|
2464
|
+
differences[`${path}${key}`] = { previous: prevValue, current: currValue };
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
2467
|
+
|
|
2468
|
+
// **Transform & Filter Differences**
|
|
2469
|
+
let updatedDifferences = {};
|
|
2470
|
+
Object.keys( differences ).forEach( ( key ) => {
|
|
2471
|
+
let newKey = key.replace( /spocDetails\.\d+\./, 'spocDetails.' ).replace( /WhitelistedIps\.\d+/, 'Whitelisted Ips' );
|
|
2472
|
+
let diff = differences[key];
|
|
2473
|
+
if ( newKey.toLowerCase().includes( 'isactive' ) ) {
|
|
2474
|
+
diff = {
|
|
2475
|
+
previous: diff.previous ? 'Active' : 'Deactive',
|
|
2476
|
+
current: diff.current ? 'Active' : 'Deactive',
|
|
2477
|
+
};
|
|
2478
|
+
}
|
|
2479
|
+
|
|
2480
|
+
const userFriendlyKey = getUserFriendlyKey( newKey, keyMapping );
|
|
2481
|
+
if ( userFriendlyKey ) {
|
|
2482
|
+
newKey = userFriendlyKey;
|
|
2483
|
+
}
|
|
2484
|
+
const binaryKeys = [ 'Two Factor Authentication', 'Mat Enabled', 'Audit Status', 'Infra Email Alert', 'Ip Whitelist', 'Excluded Area', 'Passer-by data', 'Normalized data during downtime', 'Billing', 'Camera Blurring', 'Footfall Directory', 'Footfall Directory Audit', 'Footfall Directory Limit', 'NOB Status', 'Traffic', 'Trax', 'Zone V1', 'Zone V2', 'Reports', 'Analyze' ];
|
|
2485
|
+
if ( binaryKeys.includes( newKey ) ) {
|
|
2486
|
+
diff.previous = ( diff.previous == true || diff.previous == 'Enabled' ) ? 'Enabled' : 'Disabled';
|
|
2487
|
+
diff.current = ( diff.current == true || diff.current == 'Enabled' ) ? 'Enabled' : 'Disabled';
|
|
2488
|
+
}
|
|
2489
|
+
if ( newKey === 'Server Type' ) {
|
|
2490
|
+
diff.previous = ( diff.previous == true || diff.previous == 'Server' ) ? 'Server' : 'Serverless';
|
|
2491
|
+
diff.current = ( diff.current == true || diff.current == 'Server' ) ? 'Server' : 'Serverless';
|
|
2492
|
+
}
|
|
2493
|
+
|
|
2494
|
+
if ( newKey === 'Stream Type' ) {
|
|
2495
|
+
diff.previous = ( diff.previous == 'Edge' || diff.previous == 'Edge App' ) ? 'Edge App' : 'RTSP';
|
|
2496
|
+
diff.current = ( diff.current == 'Edge' || diff.current == 'Edge App' ) ? 'Edge App' : 'RTSP';
|
|
2497
|
+
}
|
|
2498
|
+
|
|
2499
|
+
// **Transform Roles Permission Keys**
|
|
2500
|
+
const rolesPermissionMatch = newKey.match( /rolespermission\.(\d+)\.modules\.(\d+)\.(isAdd|isEdit)/ );
|
|
2501
|
+
if ( rolesPermissionMatch ) {
|
|
2502
|
+
const [ , roleIndex, moduleIndex, action ] = rolesPermissionMatch;
|
|
2503
|
+
const role = previous.rolespermission?.[roleIndex];
|
|
2504
|
+
const module = role?.modules?.[moduleIndex];
|
|
2505
|
+
|
|
2506
|
+
if ( module ) {
|
|
2507
|
+
newKey = `User's ${module.name} Module ${action === 'isAdd' ? 'Add' : 'Edit'}`;
|
|
2508
|
+
diff.previous = diff.previous ? 'Enabled' : 'Disabled';
|
|
2509
|
+
diff.current = diff.current ? 'Enabled' : 'Disabled';
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
|
|
2513
|
+
if ( !newKey || ( diff.previous === '' && !diff.current ) ) return;
|
|
2514
|
+
|
|
2515
|
+
if (
|
|
2516
|
+
( diff.previous === '' || diff.previous === null || ( Array.isArray( diff.previous ) && diff.previous.length === 0 ) ) &&
|
|
2517
|
+
diff.current === undefined
|
|
2518
|
+
) {
|
|
2519
|
+
return;
|
|
2520
|
+
}
|
|
2521
|
+
if (
|
|
2522
|
+
( diff.current === '' || diff.current === null || ( Array.isArray( diff.current ) && diff.current.length === 0 ) ) &&
|
|
2523
|
+
diff.previous === undefined
|
|
2524
|
+
) {
|
|
2525
|
+
return;
|
|
2526
|
+
}
|
|
2527
|
+
|
|
2528
|
+
updatedDifferences[newKey] = diff;
|
|
2529
|
+
} );
|
|
2530
|
+
|
|
2531
|
+
return updatedDifferences;
|
|
2532
|
+
}
|
|
2533
|
+
|
|
2534
|
+
|
|
2535
|
+
function getUserFriendlyKey( keyPath, mapping ) {
|
|
2536
|
+
const keys = keyPath.split( '.' ); // Split the key path (e.g., storeProfile.pincode → ['storeProfile', 'pincode'])
|
|
2537
|
+
let value = mapping;
|
|
2538
|
+
|
|
2539
|
+
for ( const key of keys ) {
|
|
2540
|
+
if ( value && typeof value === 'object' && key in value ) {
|
|
2541
|
+
value = value[key]; // Traverse down the object
|
|
2542
|
+
} else {
|
|
2543
|
+
return null; // Return original if not found
|
|
2544
|
+
}
|
|
2545
|
+
}
|
|
2546
|
+
|
|
2547
|
+
return typeof value === 'string' ? value : keyPath; // Return mapped value or original key
|
|
2548
|
+
}
|
|
2549
|
+
|
|
2550
|
+
export async function getActivityLogs( req, res ) {
|
|
2551
|
+
try {
|
|
2552
|
+
const inputData = req.body;
|
|
2553
|
+
const openSearch = JSON.parse( process.env.OPENSEARCH );
|
|
2554
|
+
const clientQuery =[
|
|
2555
|
+
{
|
|
2556
|
+
$match: {
|
|
2557
|
+
$and: [
|
|
2558
|
+
{
|
|
2559
|
+
clientId: { $eq: inputData.clientId },
|
|
2560
|
+
},
|
|
2561
|
+
],
|
|
2562
|
+
},
|
|
2563
|
+
},
|
|
2564
|
+
{
|
|
2565
|
+
$group: {
|
|
2566
|
+
_id: null,
|
|
2567
|
+
clientName: { $push: '$clientName' },
|
|
2568
|
+
},
|
|
2569
|
+
},
|
|
2570
|
+
{
|
|
2571
|
+
$project: {
|
|
2572
|
+
_id: 0,
|
|
2573
|
+
clientName: 1,
|
|
2574
|
+
},
|
|
2575
|
+
},
|
|
2576
|
+
];
|
|
2577
|
+
const getClientName = await aggregateClient( clientQuery );
|
|
2578
|
+
if ( getClientName?.length == 0 || getClientName[0]?.clientName?.length ===0 ) {
|
|
2579
|
+
return res.sendError( 'No Data Found', 204 );
|
|
2580
|
+
}
|
|
2581
|
+
const query = {
|
|
2582
|
+
'_source': [
|
|
2583
|
+
'userId', 'userName', 'email', 'date', 'logType', 'logSubType',
|
|
2584
|
+
'changes', 'eventType', 'previous', 'current', 'oldData', 'newData',
|
|
2585
|
+
],
|
|
2586
|
+
'query': {
|
|
2587
|
+
'bool': {
|
|
2588
|
+
'must': [
|
|
2589
|
+
{
|
|
2590
|
+
'terms': {
|
|
2591
|
+
'clientId.keyword': [ inputData.clientId ],
|
|
2592
|
+
},
|
|
2593
|
+
},
|
|
2594
|
+
|
|
2595
|
+
],
|
|
2596
|
+
'should': [
|
|
2597
|
+
{
|
|
2598
|
+
'terms': {
|
|
2599
|
+
'clientName.keyword': getClientName[0].clientName, // Add clientName condition
|
|
2600
|
+
},
|
|
2601
|
+
},
|
|
2602
|
+
],
|
|
2603
|
+
},
|
|
2604
|
+
},
|
|
2605
|
+
'from': ( req.body.offset - 1 ) * req.body.limit,
|
|
2606
|
+
'size': req.body.limit,
|
|
2607
|
+
'sort': [
|
|
2608
|
+
{
|
|
2609
|
+
'date': {
|
|
2610
|
+
'order': 'desc',
|
|
2611
|
+
},
|
|
2612
|
+
},
|
|
2613
|
+
],
|
|
2614
|
+
};
|
|
2615
|
+
|
|
2616
|
+
if ( req.body?.logTypeFilters?.length ) {
|
|
2617
|
+
query.query.bool.must.push(
|
|
2618
|
+
{
|
|
2619
|
+
'terms': {
|
|
2620
|
+
'logType.keyword': req.body.logTypeFilters,
|
|
2621
|
+
},
|
|
2622
|
+
},
|
|
2623
|
+
);
|
|
2624
|
+
}
|
|
2625
|
+
|
|
2626
|
+
if ( req.body?.startDate || req.body?.endDate ) {
|
|
2627
|
+
query.query.bool.must.push( {
|
|
2628
|
+
'range': {
|
|
2629
|
+
'date': {
|
|
2630
|
+
'gte': req.body?.startDate ? req.body.startDate : '',
|
|
2631
|
+
'lte': req.body?.endDate ? req.body.endDate : '',
|
|
2632
|
+
},
|
|
2633
|
+
},
|
|
2634
|
+
} );
|
|
2635
|
+
}
|
|
2636
|
+
|
|
2637
|
+
query.query.bool.must.push(
|
|
2638
|
+
{
|
|
2639
|
+
'terms': {
|
|
2640
|
+
'showTo.keyword': [ req.user.userType ],
|
|
2641
|
+
},
|
|
2642
|
+
},
|
|
2643
|
+
);
|
|
2644
|
+
|
|
2645
|
+
const logs = await getOpenSearchData( openSearch.activityLog, query );
|
|
2646
|
+
|
|
2647
|
+
const hits = logs?.body?.hits?.hits;
|
|
2648
|
+
const totalDocuments = logs?.body?.hits?.total?.value;
|
|
2649
|
+
|
|
2650
|
+
let temp = [];
|
|
2651
|
+
if ( totalDocuments ) {
|
|
2652
|
+
hits.map( ( hit, i ) => {
|
|
2653
|
+
let respo ={};
|
|
2654
|
+
hit._source.logSubType = hit._source.logSubType === 'documentUpload'? 'documentsUpload': hit._source.logSubType === 'domainDetails'? 'securityFeatures': hit?._source?.logSubType;
|
|
2655
|
+
if ( ( ( hit?._source?.eventType ).match( /update/ ) || ( hit?._source?.eventType ).match( /edit/ ) )&& hit?._source?.previous ) {
|
|
2656
|
+
const previous = hit?._source?.oldData;
|
|
2657
|
+
const current=hit?._source?.newData;
|
|
2658
|
+
respo = findDifferences( previous, current );
|
|
2659
|
+
hit._source.updatedValue = respo;
|
|
2660
|
+
temp.push( hit?._source );
|
|
2661
|
+
// hit._source.changes =logSubType === 'ticketConfig'? Object.keys( respo ).map( ( item ) => item ) : hit._source.changes;
|
|
2662
|
+
} else {
|
|
2663
|
+
temp.push( hit?._source );
|
|
2664
|
+
}
|
|
2665
|
+
},
|
|
2666
|
+
);
|
|
2667
|
+
res.sendSuccess( { data: temp, count: totalDocuments } );
|
|
2128
2668
|
} else {
|
|
2129
|
-
|
|
2669
|
+
res.sendError( 'No data found', 204 );
|
|
2130
2670
|
}
|
|
2671
|
+
} catch ( error ) {
|
|
2672
|
+
logger.error( { error: error, message: req.body, function: 'getActivityLogs' } );
|
|
2673
|
+
return res.sendError( 'Internal Server Error', 500 );
|
|
2131
2674
|
}
|
|
2675
|
+
}
|
|
2676
|
+
|
|
2677
|
+
function findDifferences( oldData, newData ) {
|
|
2678
|
+
const allKeys = new Set( [ ...Object.keys( oldData ), ...Object.keys( newData ) ] );
|
|
2679
|
+
const diff = {};
|
|
2680
|
+
|
|
2681
|
+
allKeys.forEach( ( key ) => {
|
|
2682
|
+
const previous = key in oldData ? oldData[key] : null;
|
|
2683
|
+
const current = key in newData ? newData[key] : null;
|
|
2684
|
+
|
|
2685
|
+
// Only include fields that are added or updated (where previous !== current)
|
|
2686
|
+
if ( previous !== current ) {
|
|
2687
|
+
diff[splitCamelCase( key )] = {
|
|
2688
|
+
previous,
|
|
2689
|
+
current,
|
|
2690
|
+
};
|
|
2691
|
+
}
|
|
2692
|
+
} );
|
|
2132
2693
|
|
|
2133
|
-
return
|
|
2694
|
+
return diff;
|
|
2134
2695
|
}
|
|
2135
2696
|
|
|
2697
|
+
function splitCamelCase( text ) {
|
|
2698
|
+
return text.replace( /([a-z])([A-Z])/g, '$1 $2' );
|
|
2699
|
+
}
|
|
2136
2700
|
|
|
2137
2701
|
async function postApi( url, data ) {
|
|
2138
2702
|
const requestOptions = {
|
|
@@ -2201,3 +2765,34 @@ export async function clientCsmAssignAction( req, res ) {
|
|
|
2201
2765
|
return res.sendError( 'Internal Server Error', 500 );
|
|
2202
2766
|
}
|
|
2203
2767
|
}
|
|
2768
|
+
|
|
2769
|
+
function compareArrayObjects( prevArray, currArray ) {
|
|
2770
|
+
let changes = {};
|
|
2771
|
+
// logger.info( { prevArray: prevArray, currArray: currArray } );
|
|
2772
|
+
// Find the longest array length to avoid index mismatch
|
|
2773
|
+
let maxLength = Math.max( prevArray.length, currArray.length );
|
|
2774
|
+
|
|
2775
|
+
for ( let i = 0; i < maxLength; i++ ) {
|
|
2776
|
+
let prevObj = prevArray[i] || {}; // Default to empty object if missing
|
|
2777
|
+
let currObj = currArray[i] || {};
|
|
2778
|
+
let diff = {};
|
|
2779
|
+
|
|
2780
|
+
Object.keys( { ...prevObj, ...currObj } ).forEach( ( key ) => {
|
|
2781
|
+
if ( prevObj[key] !== currObj[key] && key !== '_id' ) {
|
|
2782
|
+
const key1 = key == 'contact'? 'Contact Number': key == 'email'? 'Email ID':key == 'name'?'Name': key == 'designation'?'Designation':key;
|
|
2783
|
+
const name = i ==0? 'Primary Spoc': `Alternate Spoc ${i+1}`;
|
|
2784
|
+
diff[`${name} ${key1}`] = {
|
|
2785
|
+
previous: prevObj[key] || 'null',
|
|
2786
|
+
current: currObj[key] || 'null',
|
|
2787
|
+
};
|
|
2788
|
+
}
|
|
2789
|
+
} );
|
|
2790
|
+
|
|
2791
|
+
if ( Object.keys( diff ).length > 0 ) {
|
|
2792
|
+
// changes.push( { index: i, changes: diff } );
|
|
2793
|
+
changes = { ...changes, ...diff };
|
|
2794
|
+
}
|
|
2795
|
+
}
|
|
2796
|
+
|
|
2797
|
+
return changes;
|
|
2798
|
+
}
|