bulltrackers-module 1.0.494 → 1.0.495
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.
|
@@ -29,15 +29,41 @@ async function processAlertForPI(db, logger, piCid, alertType, computationMetada
|
|
|
29
29
|
// 3. Generate alert message
|
|
30
30
|
const alertMessage = generateAlertMessage(alertType, piUsername, computationMetadata);
|
|
31
31
|
|
|
32
|
+
// Helper function to get Firebase UID from eToro CID
|
|
33
|
+
async function getFirebaseUidFromCid(etoroCid) {
|
|
34
|
+
const signedInUsersSnapshot = await db.collection('signedInUsers')
|
|
35
|
+
.where('etoroCID', '==', Number(etoroCid))
|
|
36
|
+
.limit(1)
|
|
37
|
+
.get();
|
|
38
|
+
|
|
39
|
+
if (!signedInUsersSnapshot.empty) {
|
|
40
|
+
return signedInUsersSnapshot.docs[0].id; // Firebase UID is the document ID
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
32
45
|
// 4. Create notifications for each subscribed user (using user_notifications collection)
|
|
46
|
+
// Convert eToro CIDs to Firebase UIDs first
|
|
33
47
|
const batch = db.batch();
|
|
34
48
|
const notificationRefs = [];
|
|
35
49
|
const counterUpdates = {};
|
|
50
|
+
const uidMapping = {}; // Cache for CID -> UID mappings
|
|
36
51
|
|
|
37
52
|
for (const subscription of subscriptions) {
|
|
53
|
+
// Get Firebase UID for this user's eToro CID
|
|
54
|
+
let firebaseUid = uidMapping[subscription.userCid];
|
|
55
|
+
if (!firebaseUid) {
|
|
56
|
+
firebaseUid = await getFirebaseUidFromCid(subscription.userCid);
|
|
57
|
+
if (!firebaseUid) {
|
|
58
|
+
logger.log('WARN', `[processAlertForPI] Could not find Firebase UID for user CID ${subscription.userCid}, skipping notification`);
|
|
59
|
+
continue; // Skip this user if we can't find their Firebase UID
|
|
60
|
+
}
|
|
61
|
+
uidMapping[subscription.userCid] = firebaseUid;
|
|
62
|
+
}
|
|
63
|
+
|
|
38
64
|
const notificationId = `alert_${Date.now()}_${subscription.userCid}_${piCid}_${Math.random().toString(36).substring(2, 9)}`;
|
|
39
65
|
const notificationRef = db.collection('user_notifications')
|
|
40
|
-
.doc(
|
|
66
|
+
.doc(firebaseUid) // Use Firebase UID, not eToro CID
|
|
41
67
|
.collection('notifications')
|
|
42
68
|
.doc(notificationId);
|
|
43
69
|
|
|
@@ -48,6 +74,7 @@ async function processAlertForPI(db, logger, piCid, alertType, computationMetada
|
|
|
48
74
|
message: alertMessage,
|
|
49
75
|
read: false,
|
|
50
76
|
createdAt: FieldValue.serverTimestamp(),
|
|
77
|
+
timestamp: FieldValue.serverTimestamp(), // Also include timestamp for ordering
|
|
51
78
|
metadata: {
|
|
52
79
|
piCid: Number(piCid),
|
|
53
80
|
piUsername: piUsername,
|
|
@@ -65,26 +92,26 @@ async function processAlertForPI(db, logger, piCid, alertType, computationMetada
|
|
|
65
92
|
batch.set(notificationRef, notificationData);
|
|
66
93
|
notificationRefs.push(notificationRef);
|
|
67
94
|
|
|
68
|
-
// Track counter updates
|
|
95
|
+
// Track counter updates (using Firebase UID as key)
|
|
69
96
|
const dateKey = computationDate || new Date().toISOString().split('T')[0];
|
|
70
|
-
if (!counterUpdates[
|
|
71
|
-
counterUpdates[
|
|
97
|
+
if (!counterUpdates[firebaseUid]) {
|
|
98
|
+
counterUpdates[firebaseUid] = {
|
|
72
99
|
date: dateKey,
|
|
73
100
|
unreadCount: 0,
|
|
74
101
|
totalCount: 0,
|
|
75
102
|
byType: {}
|
|
76
103
|
};
|
|
77
104
|
}
|
|
78
|
-
counterUpdates[
|
|
79
|
-
counterUpdates[
|
|
80
|
-
counterUpdates[
|
|
81
|
-
(counterUpdates[
|
|
105
|
+
counterUpdates[firebaseUid].unreadCount += 1;
|
|
106
|
+
counterUpdates[firebaseUid].totalCount += 1;
|
|
107
|
+
counterUpdates[firebaseUid].byType[alertType.id] =
|
|
108
|
+
(counterUpdates[firebaseUid].byType[alertType.id] || 0) + 1;
|
|
82
109
|
}
|
|
83
110
|
|
|
84
|
-
// 5. Update notification counters
|
|
85
|
-
for (const [
|
|
111
|
+
// 5. Update notification counters (using Firebase UIDs)
|
|
112
|
+
for (const [firebaseUid, counter] of Object.entries(counterUpdates)) {
|
|
86
113
|
const counterRef = db.collection('user_notifications')
|
|
87
|
-
.doc(
|
|
114
|
+
.doc(firebaseUid) // Use Firebase UID, not eToro CID
|
|
88
115
|
.collection('counters')
|
|
89
116
|
.doc(counter.date);
|
|
90
117
|
|
|
@@ -59,36 +59,73 @@ async function sendTestAlert(req, res, dependencies, config) {
|
|
|
59
59
|
logger.log('INFO', `[sendTestAlert] Using default alert type: ${alertType.id}`);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
//
|
|
63
|
-
|
|
62
|
+
// Helper function to get Firebase UID from eToro CID
|
|
63
|
+
async function getFirebaseUidFromCid(etoroCid) {
|
|
64
|
+
const signedInUsersSnapshot = await db.collection('signedInUsers')
|
|
65
|
+
.where('etoroCID', '==', Number(etoroCid))
|
|
66
|
+
.limit(1)
|
|
67
|
+
.get();
|
|
68
|
+
|
|
69
|
+
if (!signedInUsersSnapshot.empty) {
|
|
70
|
+
return signedInUsersSnapshot.docs[0].id; // Firebase UID is the document ID
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Determine target users (as Firebase UIDs)
|
|
76
|
+
let targetFirebaseUids = [];
|
|
64
77
|
|
|
65
78
|
if (targetUsers === 'all') {
|
|
66
|
-
// Get all users from
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
79
|
+
// Get all users from signedInUsers collection (who have etoroCID)
|
|
80
|
+
const signedInUsersSnapshot = await db.collection('signedInUsers')
|
|
81
|
+
.where('etoroCID', '!=', null)
|
|
82
|
+
.get();
|
|
83
|
+
|
|
84
|
+
targetFirebaseUids = signedInUsersSnapshot.docs.map(doc => doc.id);
|
|
85
|
+
logger.log('INFO', `[sendTestAlert] Sending to all ${targetFirebaseUids.length} users`);
|
|
70
86
|
} else if (targetUsers === 'dev') {
|
|
71
87
|
// Get all developer accounts with dev override enabled
|
|
72
88
|
const devOverridesCollection = config.devOverridesCollection || 'dev_overrides';
|
|
73
89
|
const devOverridesSnapshot = await db.collection(devOverridesCollection).get();
|
|
74
90
|
|
|
91
|
+
const devCids = [];
|
|
75
92
|
for (const doc of devOverridesSnapshot.docs) {
|
|
76
93
|
const data = doc.data();
|
|
77
94
|
if (data.enabled === true) {
|
|
78
|
-
|
|
95
|
+
devCids.push(Number(doc.id));
|
|
79
96
|
}
|
|
80
97
|
}
|
|
81
98
|
|
|
82
99
|
// Also include the requesting developer
|
|
83
|
-
if (!
|
|
84
|
-
|
|
100
|
+
if (!devCids.includes(Number(userCid))) {
|
|
101
|
+
devCids.push(Number(userCid));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Convert eToro CIDs to Firebase UIDs
|
|
105
|
+
for (const cid of devCids) {
|
|
106
|
+
const firebaseUid = await getFirebaseUidFromCid(cid);
|
|
107
|
+
if (firebaseUid) {
|
|
108
|
+
targetFirebaseUids.push(firebaseUid);
|
|
109
|
+
} else {
|
|
110
|
+
logger.log('WARN', `[sendTestAlert] Could not find Firebase UID for developer CID ${cid}`);
|
|
111
|
+
}
|
|
85
112
|
}
|
|
86
113
|
|
|
87
|
-
logger.log('INFO', `[sendTestAlert] Sending to ${
|
|
114
|
+
logger.log('INFO', `[sendTestAlert] Sending to ${targetFirebaseUids.length} developer accounts`);
|
|
88
115
|
} else if (Array.isArray(targetUsers)) {
|
|
89
|
-
// Specific user CIDs
|
|
90
|
-
|
|
91
|
-
|
|
116
|
+
// Specific user CIDs - convert to Firebase UIDs
|
|
117
|
+
const specificCids = targetUsers.map(cid => Number(cid)).filter(cid => !isNaN(cid) && cid > 0);
|
|
118
|
+
|
|
119
|
+
for (const cid of specificCids) {
|
|
120
|
+
const firebaseUid = await getFirebaseUidFromCid(cid);
|
|
121
|
+
if (firebaseUid) {
|
|
122
|
+
targetFirebaseUids.push(firebaseUid);
|
|
123
|
+
} else {
|
|
124
|
+
logger.log('WARN', `[sendTestAlert] Could not find Firebase UID for CID ${cid}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
logger.log('INFO', `[sendTestAlert] Sending to ${targetFirebaseUids.length} specific users (from ${specificCids.length} CIDs)`);
|
|
92
129
|
} else {
|
|
93
130
|
return res.status(400).json({
|
|
94
131
|
error: "Invalid targetUsers",
|
|
@@ -96,7 +133,7 @@ async function sendTestAlert(req, res, dependencies, config) {
|
|
|
96
133
|
});
|
|
97
134
|
}
|
|
98
135
|
|
|
99
|
-
if (
|
|
136
|
+
if (targetFirebaseUids.length === 0) {
|
|
100
137
|
return res.status(400).json({
|
|
101
138
|
error: "No target users",
|
|
102
139
|
message: "No users found matching the target criteria"
|
|
@@ -112,16 +149,16 @@ async function sendTestAlert(req, res, dependencies, config) {
|
|
|
112
149
|
testSentAt: new Date().toISOString()
|
|
113
150
|
});
|
|
114
151
|
|
|
115
|
-
// Create notifications for each target user
|
|
152
|
+
// Create notifications for each target user (using Firebase UIDs)
|
|
116
153
|
const batch = db.batch();
|
|
117
154
|
const notificationRefs = [];
|
|
118
155
|
const counterUpdates = {};
|
|
119
156
|
const today = new Date().toISOString().split('T')[0];
|
|
120
157
|
|
|
121
|
-
for (const
|
|
122
|
-
const notificationId = `test_alert_${Date.now()}_${
|
|
158
|
+
for (const firebaseUid of targetFirebaseUids) {
|
|
159
|
+
const notificationId = `test_alert_${Date.now()}_${firebaseUid}_${piCid}_${Math.random().toString(36).substring(2, 9)}`;
|
|
123
160
|
const notificationRef = db.collection('user_notifications')
|
|
124
|
-
.doc(
|
|
161
|
+
.doc(firebaseUid) // Use Firebase UID, not eToro CID
|
|
125
162
|
.collection('notifications')
|
|
126
163
|
.doc(notificationId);
|
|
127
164
|
|
|
@@ -132,6 +169,7 @@ async function sendTestAlert(req, res, dependencies, config) {
|
|
|
132
169
|
message: alertMessage,
|
|
133
170
|
read: false,
|
|
134
171
|
createdAt: FieldValue.serverTimestamp(),
|
|
172
|
+
timestamp: FieldValue.serverTimestamp(), // Also include timestamp for ordering
|
|
135
173
|
metadata: {
|
|
136
174
|
piCid: Number(piCid),
|
|
137
175
|
piUsername: piUsername,
|
|
@@ -150,25 +188,25 @@ async function sendTestAlert(req, res, dependencies, config) {
|
|
|
150
188
|
batch.set(notificationRef, notificationData);
|
|
151
189
|
notificationRefs.push(notificationRef);
|
|
152
190
|
|
|
153
|
-
// Track counter updates
|
|
154
|
-
if (!counterUpdates[
|
|
155
|
-
counterUpdates[
|
|
191
|
+
// Track counter updates (using Firebase UID as key)
|
|
192
|
+
if (!counterUpdates[firebaseUid]) {
|
|
193
|
+
counterUpdates[firebaseUid] = {
|
|
156
194
|
date: today,
|
|
157
195
|
unreadCount: 0,
|
|
158
196
|
totalCount: 0,
|
|
159
197
|
byType: {}
|
|
160
198
|
};
|
|
161
199
|
}
|
|
162
|
-
counterUpdates[
|
|
163
|
-
counterUpdates[
|
|
164
|
-
counterUpdates[
|
|
165
|
-
(counterUpdates[
|
|
200
|
+
counterUpdates[firebaseUid].unreadCount += 1;
|
|
201
|
+
counterUpdates[firebaseUid].totalCount += 1;
|
|
202
|
+
counterUpdates[firebaseUid].byType[alertType.id] =
|
|
203
|
+
(counterUpdates[firebaseUid].byType[alertType.id] || 0) + 1;
|
|
166
204
|
}
|
|
167
205
|
|
|
168
|
-
// Update notification counters
|
|
169
|
-
for (const [
|
|
206
|
+
// Update notification counters (using Firebase UIDs)
|
|
207
|
+
for (const [firebaseUid, counter] of Object.entries(counterUpdates)) {
|
|
170
208
|
const counterRef = db.collection('user_notifications')
|
|
171
|
-
.doc(
|
|
209
|
+
.doc(firebaseUid) // Use Firebase UID, not eToro CID
|
|
172
210
|
.collection('counters')
|
|
173
211
|
.doc(counter.date);
|
|
174
212
|
|
|
@@ -188,15 +226,15 @@ async function sendTestAlert(req, res, dependencies, config) {
|
|
|
188
226
|
|
|
189
227
|
return res.status(200).json({
|
|
190
228
|
success: true,
|
|
191
|
-
message: `Test alert sent to ${
|
|
229
|
+
message: `Test alert sent to ${targetFirebaseUids.length} users`,
|
|
192
230
|
alertType: {
|
|
193
231
|
id: alertType.id,
|
|
194
232
|
name: alertType.name,
|
|
195
233
|
computationName: alertType.computationName
|
|
196
234
|
},
|
|
197
235
|
targetUsers: {
|
|
198
|
-
count:
|
|
199
|
-
|
|
236
|
+
count: targetFirebaseUids.length,
|
|
237
|
+
firebaseUids: targetFirebaseUids
|
|
200
238
|
},
|
|
201
239
|
piCid: Number(piCid),
|
|
202
240
|
piUsername: piUsername,
|