11const cron = require ( "node-cron" ) ;
22const UserModel = require ( "@models/User" ) ;
3+ const mongoose = require ( "mongoose" ) ;
34const PreferenceModel = require ( "@models/Preference" ) ;
45const SelectedSiteModel = require ( "@models/SelectedSite" ) ;
56const constants = require ( "@config/constants" ) ;
@@ -12,6 +13,30 @@ const stringify = require("@utils/stringify");
1213const isEmpty = require ( "is-empty" ) ;
1314const BATCH_SIZE = 100 ;
1415
16+ // Function to validate critical default values
17+ const validateDefaultValues = ( ) => {
18+ const criticalDefaults = [
19+ { key : "DEFAULT_GROUP" , value : constants . DEFAULT_GROUP } ,
20+ { key : "DEFAULT_AIRQLOUD" , value : constants . DEFAULT_AIRQLOUD } ,
21+ { key : "DEFAULT_GRID" , value : constants . DEFAULT_GRID } ,
22+ { key : "DEFAULT_NETWORK" , value : constants . DEFAULT_NETWORK } ,
23+ ] ;
24+
25+ const missingDefaults = criticalDefaults . filter (
26+ ( item ) => isEmpty ( item . value ) || item . value === undefined
27+ ) ;
28+
29+ if ( missingDefaults . length > 0 ) {
30+ const missingKeys = missingDefaults . map ( ( item ) => item . key ) . join ( ", " ) ;
31+ logger . error (
32+ `🚨 Aborting preference update: Missing critical default values: ${ missingKeys } `
33+ ) ;
34+ return false ;
35+ }
36+
37+ return true ;
38+ } ;
39+
1540// Default preference object
1641const defaultPreference = {
1742 pollutant : "pm2_5" ,
@@ -27,10 +52,22 @@ const defaultPreference = {
2752 unitValue : 14 ,
2853 unit : "day" ,
2954 } ,
30- airqloud_id : constants . DEFAULT_AIRQLOUD || "NA" ,
31- grid_id : constants . DEFAULT_GRID || "NA" ,
32- network_id : constants . DEFAULT_NETWORK || "NA" ,
33- group_id : constants . DEFAULT_GROUP || "NA" ,
55+ airqloud_id : constants . DEFAULT_AIRQLOUD ,
56+ grid_id : constants . DEFAULT_GRID ,
57+ network_id : constants . DEFAULT_NETWORK ,
58+ group_id : constants . DEFAULT_GROUP ,
59+ } ;
60+
61+ // Function to validate user's group membership
62+ const validateUserGroupMembership = ( user , defaultGroupId ) => {
63+ // Check if user has group_roles and is a member of the default group
64+ if ( ! user . group_roles || user . group_roles . length === 0 ) {
65+ return false ;
66+ }
67+
68+ return user . group_roles . some (
69+ ( role ) => role . group . toString ( ) === defaultGroupId . toString ( )
70+ ) ;
3471} ;
3572
3673// Function to get selected sites based on the specified method
@@ -62,6 +99,11 @@ const getSelectedSites = async (method = "featured") => {
6299} ;
63100
64101const updatePreferences = async ( siteSelectionMethod = "featured" ) => {
102+ // Validate default values before proceeding
103+ if ( ! validateDefaultValues ( ) ) {
104+ return ;
105+ }
106+
65107 try {
66108 const batchSize = BATCH_SIZE ;
67109 let skip = 0 ;
@@ -74,43 +116,60 @@ const updatePreferences = async (siteSelectionMethod = "featured") => {
74116 return ;
75117 }
76118
119+ // Use constants.DEFAULT_GROUP directly
120+ const defaultGroupId = mongoose . Types . ObjectId ( constants . DEFAULT_GROUP ) ;
121+
77122 while ( true ) {
123+ // Fetch users with their group_roles
78124 const users = await UserModel ( "airqo" )
79125 . find ( )
80126 . limit ( batchSize )
81127 . skip ( skip )
82- . select ( "_id" )
128+ . select ( "_id group_roles " )
83129 . lean ( ) ;
84130
85131 if ( users . length === 0 ) {
86132 break ;
87133 }
88134
89- // Fetch existing preferences for users in batch
90- const userIds = users . map ( ( user ) => user . _id ) ;
135+ // Filter users who are members of the default group
136+ const validUsers = users . filter ( ( user ) =>
137+ validateUserGroupMembership ( user , defaultGroupId )
138+ ) ;
139+
140+ // Get user IDs of valid users
141+ const validUserIds = validUsers . map ( ( user ) => user . _id ) ;
142+
143+ // Fetch existing preferences for valid users
91144 const preferences = await PreferenceModel ( "airqo" )
92- . find ( { user_id : { $in : userIds } } )
145+ . find ( {
146+ user_id : { $in : validUserIds } ,
147+ group_id : defaultGroupId ,
148+ } )
93149 . select ( "_id user_id selected_sites" )
94150 . lean ( ) ;
95151
96152 const preferencesMap = new Map ( ) ;
97-
98153 preferences . forEach ( ( pref ) => {
99154 preferencesMap . set ( pref . user_id . toString ( ) , pref ) ;
100155 } ) ;
101156
102- for ( const user of users ) {
157+ for ( const user of validUsers ) {
103158 const userIdStr = user . _id . toString ( ) ;
104159 const preference = preferencesMap . get ( userIdStr ) ;
105160
161+ // Prepare the default preference object with the specific group_id
162+ const defaultPreferenceWithGroupId = {
163+ ...defaultPreference ,
164+ user_id : user . _id ,
165+ group_id : defaultGroupId ,
166+ selected_sites : selectedSites ,
167+ } ;
168+
106169 if ( ! preference ) {
107- // No preference exists, create a new one
170+ // No preference exists for the user in the default group , create a new one
108171 await PreferenceModel ( "airqo" )
109- . create ( {
110- ...defaultPreference ,
111- user_id : user . _id ,
112- selected_sites : selectedSites ,
113- } )
172+ . create ( defaultPreferenceWithGroupId )
114173 . catch ( ( error ) => {
115174 logger . error (
116175 `🐛🐛 Failed to create preference for user ${ userIdStr } : ${ stringify (
@@ -122,14 +181,21 @@ const updatePreferences = async (siteSelectionMethod = "featured") => {
122181 // Preference exists but selected_sites is empty, update it
123182 await PreferenceModel ( "airqo" )
124183 . findOneAndUpdate (
125- { _id : preference . _id } ,
184+ {
185+ user_id : user . _id ,
186+ group_id : defaultGroupId ,
187+ } ,
126188 {
127189 $set : {
128- ...defaultPreference ,
129190 selected_sites : selectedSites ,
191+ group_id : defaultGroupId ,
130192 } ,
131193 } ,
132- { new : true }
194+ {
195+ new : true ,
196+ upsert : true ,
197+ setDefaultsOnInsert : true ,
198+ }
133199 )
134200 . catch ( ( error ) => {
135201 logger . error (
@@ -154,3 +220,5 @@ cron.schedule(schedule, () => updatePreferences("featured"), {
154220 scheduled : true ,
155221 timezone : "Africa/Nairobi" ,
156222} ) ;
223+
224+ module . exports = { updatePreferences } ;
0 commit comments