1
1
const cron = require ( "node-cron" ) ;
2
2
const UserModel = require ( "@models/User" ) ;
3
+ const mongoose = require ( "mongoose" ) ;
3
4
const PreferenceModel = require ( "@models/Preference" ) ;
4
5
const SelectedSiteModel = require ( "@models/SelectedSite" ) ;
5
6
const constants = require ( "@config/constants" ) ;
@@ -12,6 +13,30 @@ const stringify = require("@utils/stringify");
12
13
const isEmpty = require ( "is-empty" ) ;
13
14
const BATCH_SIZE = 100 ;
14
15
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
+
15
40
// Default preference object
16
41
const defaultPreference = {
17
42
pollutant : "pm2_5" ,
@@ -27,10 +52,22 @@ const defaultPreference = {
27
52
unitValue : 14 ,
28
53
unit : "day" ,
29
54
} ,
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
+ ) ;
34
71
} ;
35
72
36
73
// Function to get selected sites based on the specified method
@@ -62,6 +99,11 @@ const getSelectedSites = async (method = "featured") => {
62
99
} ;
63
100
64
101
const updatePreferences = async ( siteSelectionMethod = "featured" ) => {
102
+ // Validate default values before proceeding
103
+ if ( ! validateDefaultValues ( ) ) {
104
+ return ;
105
+ }
106
+
65
107
try {
66
108
const batchSize = BATCH_SIZE ;
67
109
let skip = 0 ;
@@ -74,43 +116,60 @@ const updatePreferences = async (siteSelectionMethod = "featured") => {
74
116
return ;
75
117
}
76
118
119
+ // Use constants.DEFAULT_GROUP directly
120
+ const defaultGroupId = mongoose . Types . ObjectId ( constants . DEFAULT_GROUP ) ;
121
+
77
122
while ( true ) {
123
+ // Fetch users with their group_roles
78
124
const users = await UserModel ( "airqo" )
79
125
. find ( )
80
126
. limit ( batchSize )
81
127
. skip ( skip )
82
- . select ( "_id" )
128
+ . select ( "_id group_roles " )
83
129
. lean ( ) ;
84
130
85
131
if ( users . length === 0 ) {
86
132
break ;
87
133
}
88
134
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
91
144
const preferences = await PreferenceModel ( "airqo" )
92
- . find ( { user_id : { $in : userIds } } )
145
+ . find ( {
146
+ user_id : { $in : validUserIds } ,
147
+ group_id : defaultGroupId ,
148
+ } )
93
149
. select ( "_id user_id selected_sites" )
94
150
. lean ( ) ;
95
151
96
152
const preferencesMap = new Map ( ) ;
97
-
98
153
preferences . forEach ( ( pref ) => {
99
154
preferencesMap . set ( pref . user_id . toString ( ) , pref ) ;
100
155
} ) ;
101
156
102
- for ( const user of users ) {
157
+ for ( const user of validUsers ) {
103
158
const userIdStr = user . _id . toString ( ) ;
104
159
const preference = preferencesMap . get ( userIdStr ) ;
105
160
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
+
106
169
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
108
171
await PreferenceModel ( "airqo" )
109
- . create ( {
110
- ...defaultPreference ,
111
- user_id : user . _id ,
112
- selected_sites : selectedSites ,
113
- } )
172
+ . create ( defaultPreferenceWithGroupId )
114
173
. catch ( ( error ) => {
115
174
logger . error (
116
175
`🐛🐛 Failed to create preference for user ${ userIdStr } : ${ stringify (
@@ -122,14 +181,21 @@ const updatePreferences = async (siteSelectionMethod = "featured") => {
122
181
// Preference exists but selected_sites is empty, update it
123
182
await PreferenceModel ( "airqo" )
124
183
. findOneAndUpdate (
125
- { _id : preference . _id } ,
184
+ {
185
+ user_id : user . _id ,
186
+ group_id : defaultGroupId ,
187
+ } ,
126
188
{
127
189
$set : {
128
- ...defaultPreference ,
129
190
selected_sites : selectedSites ,
191
+ group_id : defaultGroupId ,
130
192
} ,
131
193
} ,
132
- { new : true }
194
+ {
195
+ new : true ,
196
+ upsert : true ,
197
+ setDefaultsOnInsert : true ,
198
+ }
133
199
)
134
200
. catch ( ( error ) => {
135
201
logger . error (
@@ -154,3 +220,5 @@ cron.schedule(schedule, () => updatePreferences("featured"), {
154
220
scheduled : true ,
155
221
timezone : "Africa/Nairobi" ,
156
222
} ) ;
223
+
224
+ module . exports = { updatePreferences } ;
0 commit comments