Skip to content

Commit 1f1d50a

Browse files
authored
Merge pull request #4079 from airqo-platform/staging
move to production
2 parents 8513ca9 + 331742e commit 1f1d50a

File tree

9 files changed

+95
-27
lines changed

9 files changed

+95
-27
lines changed

k8s/analytics/values-prod.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ images:
88
celeryWorker: eu.gcr.io/airqo-250220/airqo-analytics-celery-worker
99
reportJob: eu.gcr.io/airqo-250220/airqo-analytics-report-job
1010
devicesSummaryJob: eu.gcr.io/airqo-250220/airqo-analytics-devices-summary-job
11-
tag: prod-74ce6c5b-1734102400
11+
tag: prod-8513ca91-1734151901
1212
api:
1313
name: airqo-analytics-api
1414
label: analytics-api

k8s/auth-service/values-prod.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ app:
66
replicaCount: 3
77
image:
88
repository: eu.gcr.io/airqo-250220/airqo-auth-api
9-
tag: prod-74ce6c5b-1734102400
9+
tag: prod-8513ca91-1734151901
1010
nameOverride: ''
1111
fullnameOverride: ''
1212
podAnnotations: {}

k8s/auth-service/values-stage.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ app:
66
replicaCount: 2
77
image:
88
repository: eu.gcr.io/airqo-250220/airqo-stage-auth-api
9-
tag: stage-4437d7f9-1734102322
9+
tag: stage-ff5c18e5-1734151846
1010
nameOverride: ''
1111
fullnameOverride: ''
1212
podAnnotations: {}

k8s/exceedance/values-prod-airqo.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ app:
44
configmap: env-exceedance-production
55
image:
66
repository: eu.gcr.io/airqo-250220/airqo-exceedance-job
7-
tag: prod-74ce6c5b-1734102400
7+
tag: prod-8513ca91-1734151901
88
nameOverride: ''
99
fullnameOverride: ''

k8s/exceedance/values-prod-kcca.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ app:
44
configmap: env-exceedance-production
55
image:
66
repository: eu.gcr.io/airqo-250220/kcca-exceedance-job
7-
tag: prod-74ce6c5b-1734102400
7+
tag: prod-8513ca91-1734151901
88
nameOverride: ''
99
fullnameOverride: ''

k8s/predict/values-prod.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ images:
77
predictJob: eu.gcr.io/airqo-250220/airqo-predict-job
88
trainJob: eu.gcr.io/airqo-250220/airqo-train-job
99
predictPlaces: eu.gcr.io/airqo-250220/airqo-predict-places-air-quality
10-
tag: prod-74ce6c5b-1734102400
10+
tag: prod-8513ca91-1734151901
1111
api:
1212
name: airqo-prediction-api
1313
label: prediction-api

k8s/spatial/values-prod.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ app:
66
replicaCount: 3
77
image:
88
repository: eu.gcr.io/airqo-250220/airqo-spatial-api
9-
tag: prod-74ce6c5b-1734102400
9+
tag: prod-8513ca91-1734151901
1010
nameOverride: ''
1111
fullnameOverride: ''
1212
podAnnotations: {}

k8s/website/values-prod.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ app:
66
replicaCount: 3
77
image:
88
repository: eu.gcr.io/airqo-250220/airqo-website-api
9-
tag: prod-74ce6c5b-1734102400
9+
tag: prod-8513ca91-1734151901
1010
nameOverride: ''
1111
fullnameOverride: ''
1212
podAnnotations: {}

src/auth-service/bin/jobs/preferences-update-job.js

Lines changed: 87 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const cron = require("node-cron");
22
const UserModel = require("@models/User");
3+
const mongoose = require("mongoose");
34
const PreferenceModel = require("@models/Preference");
45
const SelectedSiteModel = require("@models/SelectedSite");
56
const constants = require("@config/constants");
@@ -12,6 +13,30 @@ const stringify = require("@utils/stringify");
1213
const isEmpty = require("is-empty");
1314
const 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
1641
const 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

64101
const 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

Comments
 (0)