bulltrackers-module 1.0.470 → 1.0.471
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.
|
@@ -235,16 +235,38 @@ exports.runRootDataIndexer = async (config, dependencies) => {
|
|
|
235
235
|
// Path: {verifications} (Limit 1) - Checks if collection is non-empty generally
|
|
236
236
|
const verificationsRef = db.collection(collections.verifications || 'user_verifications');
|
|
237
237
|
|
|
238
|
-
// 4.
|
|
239
|
-
//
|
|
240
|
-
//
|
|
241
|
-
// - signed_in_users_social/{
|
|
242
|
-
//
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
.
|
|
246
|
-
.
|
|
247
|
-
|
|
238
|
+
// 4. Social Data Checks - Use date tracking documents
|
|
239
|
+
// Single tracking documents at root level:
|
|
240
|
+
// - pi_social_posts/_dates -> fetchedDates.{date}
|
|
241
|
+
// - signed_in_users_social/_dates -> fetchedDates.{date}
|
|
242
|
+
// For generic social (daily_social_insights), check the collection directly
|
|
243
|
+
const [piSocialTrackingDoc, signedInSocialTrackingDoc, genericSocialSnap] = await Promise.all([
|
|
244
|
+
db.collection(PI_SOCIAL_COLL_NAME).doc('_dates').get(),
|
|
245
|
+
db.collection(SIGNED_IN_SOCIAL_COLL_NAME).doc('_dates').get(),
|
|
246
|
+
db.collectionGroup('posts')
|
|
247
|
+
.where('fetchedAt', '>=', dayStart)
|
|
248
|
+
.where('fetchedAt', '<=', dayEnd)
|
|
249
|
+
.limit(1)
|
|
250
|
+
.get()
|
|
251
|
+
]);
|
|
252
|
+
|
|
253
|
+
// Check if date exists in tracking documents
|
|
254
|
+
let foundPISocial = false;
|
|
255
|
+
let foundSignedInSocial = false;
|
|
256
|
+
|
|
257
|
+
if (piSocialTrackingDoc.exists) {
|
|
258
|
+
const data = piSocialTrackingDoc.data();
|
|
259
|
+
if (data.fetchedDates && data.fetchedDates[dateStr] === true) {
|
|
260
|
+
foundPISocial = true;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (signedInSocialTrackingDoc.exists) {
|
|
265
|
+
const data = signedInSocialTrackingDoc.data();
|
|
266
|
+
if (data.fetchedDates && data.fetchedDates[dateStr] === true) {
|
|
267
|
+
foundSignedInSocial = true;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
248
270
|
|
|
249
271
|
// --- Execute Checks ---
|
|
250
272
|
const [
|
|
@@ -256,8 +278,7 @@ exports.runRootDataIndexer = async (config, dependencies) => {
|
|
|
256
278
|
piDeepExists,
|
|
257
279
|
piHistExists,
|
|
258
280
|
signedInPortExists, signedInHistExists,
|
|
259
|
-
verificationsQuery
|
|
260
|
-
universalSocialSnap
|
|
281
|
+
verificationsQuery
|
|
261
282
|
] = await Promise.all([
|
|
262
283
|
checkAnyPartExists(normPortPartsRef),
|
|
263
284
|
checkAnyPartExists(specPortPartsRef),
|
|
@@ -271,73 +292,12 @@ exports.runRootDataIndexer = async (config, dependencies) => {
|
|
|
271
292
|
checkAnyPartExists(piHistoryPartsRef),
|
|
272
293
|
checkAnyPartExists(signedInPortPartsRef),
|
|
273
294
|
checkAnyPartExists(signedInHistPartsRef),
|
|
274
|
-
verificationsRef.limit(1).get()
|
|
275
|
-
universalSocialQuery.get()
|
|
295
|
+
verificationsRef.limit(1).get()
|
|
276
296
|
]);
|
|
277
297
|
|
|
278
|
-
//
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
logger.log('INFO', `[RootDataIndexer/${dateStr}] Checking social data availability (dayStart: ${dayStart.toISOString()}, dayEnd: ${dayEnd.toISOString()})`);
|
|
283
|
-
logger.log('INFO', `[RootDataIndexer/${dateStr}] Looking for PI social in: "${PI_SOCIAL_COLL_NAME}", Signed-in social in: "${SIGNED_IN_SOCIAL_COLL_NAME}"`);
|
|
284
|
-
|
|
285
|
-
if (!universalSocialSnap.empty) {
|
|
286
|
-
logger.log('INFO', `[RootDataIndexer/${dateStr}] Collection group query returned ${universalSocialSnap.docs.length} posts`);
|
|
287
|
-
|
|
288
|
-
// Track all paths found for debugging
|
|
289
|
-
const allPaths = [];
|
|
290
|
-
const piPaths = [];
|
|
291
|
-
const signedInPaths = [];
|
|
292
|
-
const otherPaths = [];
|
|
293
|
-
|
|
294
|
-
universalSocialSnap.docs.forEach(doc => {
|
|
295
|
-
const path = doc.ref.path;
|
|
296
|
-
const data = doc.data();
|
|
297
|
-
const fetchedAt = data.fetchedAt;
|
|
298
|
-
allPaths.push(path);
|
|
299
|
-
|
|
300
|
-
// Convert fetchedAt to string for logging
|
|
301
|
-
let fetchedAtStr = 'missing';
|
|
302
|
-
if (fetchedAt) {
|
|
303
|
-
if (fetchedAt.toDate) {
|
|
304
|
-
fetchedAtStr = fetchedAt.toDate().toISOString();
|
|
305
|
-
} else if (fetchedAt.toMillis) {
|
|
306
|
-
fetchedAtStr = new Date(fetchedAt.toMillis()).toISOString();
|
|
307
|
-
} else {
|
|
308
|
-
fetchedAtStr = String(fetchedAt);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// Use includes() to match collection name anywhere in path
|
|
313
|
-
// Path format: {collectionName}/{userId}/posts/{postId}
|
|
314
|
-
const piMatchPattern = `${PI_SOCIAL_COLL_NAME}/`;
|
|
315
|
-
const signedInMatchPattern = `${SIGNED_IN_SOCIAL_COLL_NAME}/`;
|
|
316
|
-
|
|
317
|
-
if (path.includes(piMatchPattern)) {
|
|
318
|
-
foundPISocial = true;
|
|
319
|
-
piPaths.push({ path, fetchedAt: fetchedAtStr });
|
|
320
|
-
logger.log('INFO', `[RootDataIndexer/${dateStr}] ✓ PI social: ${path} (fetchedAt: ${fetchedAtStr})`);
|
|
321
|
-
} else if (path.includes(signedInMatchPattern)) {
|
|
322
|
-
foundSignedInSocial = true;
|
|
323
|
-
signedInPaths.push({ path, fetchedAt: fetchedAtStr });
|
|
324
|
-
logger.log('INFO', `[RootDataIndexer/${dateStr}] ✓ Signed-in social: ${path} (fetchedAt: ${fetchedAtStr})`);
|
|
325
|
-
} else {
|
|
326
|
-
otherPaths.push({ path, fetchedAt: fetchedAtStr });
|
|
327
|
-
logger.log('INFO', `[RootDataIndexer/${dateStr}] ? Other social: ${path} (fetchedAt: ${fetchedAtStr})`);
|
|
328
|
-
}
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
logger.log('INFO', `[RootDataIndexer/${dateStr}] Summary - Total: ${allPaths.length}, PI: ${piPaths.length}, Signed-in: ${signedInPaths.length}, Other: ${otherPaths.length}`);
|
|
332
|
-
|
|
333
|
-
if (signedInPaths.length === 0 && !foundSignedInSocial) {
|
|
334
|
-
logger.log('WARN', `[RootDataIndexer/${dateStr}] ⚠️ No signed-in social posts found! Expected pattern: "${signedInMatchPattern}"`);
|
|
335
|
-
logger.log('WARN', `[RootDataIndexer/${dateStr}] All paths found: ${allPaths.slice(0, 10).join(', ')}${allPaths.length > 10 ? '...' : ''}`);
|
|
336
|
-
}
|
|
337
|
-
} else {
|
|
338
|
-
logger.log('WARN', `[RootDataIndexer/${dateStr}] ⚠️ Collection group query returned NO posts! (dayStart: ${dayStart.toISOString()}, dayEnd: ${dayEnd.toISOString()})`);
|
|
339
|
-
logger.log('WARN', `[RootDataIndexer/${dateStr}] This might indicate: 1) No posts with fetchedAt in this range, 2) Missing Firestore index, or 3) Query error`);
|
|
340
|
-
}
|
|
298
|
+
// Social data checks are done above using tracking documents
|
|
299
|
+
// foundPISocial and foundSignedInSocial are already set from the tracking document checks
|
|
300
|
+
logger.log('INFO', `[RootDataIndexer/${dateStr}] Social check results - PI: ${foundPISocial}, Signed-in: ${foundSignedInSocial}`);
|
|
341
301
|
|
|
342
302
|
// --- Assign to Availability ---
|
|
343
303
|
availability.details.normalPortfolio = normPortExists;
|
|
@@ -351,6 +351,30 @@ exports.handleSocialTask = async (message, context, config, dependencies) => {
|
|
|
351
351
|
offset += take;
|
|
352
352
|
}
|
|
353
353
|
|
|
354
|
+
// Write date tracking document after successful fetch
|
|
355
|
+
// Single document at root level: /signed_in_users_social/_dates and /pi_social_posts/_dates
|
|
356
|
+
// Contains a map of all dates that have been fetched
|
|
357
|
+
if (totalSaved > 0 && (type === 'SIGNED_IN_USER' || type === 'POPULAR_INVESTOR')) {
|
|
358
|
+
const today = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
|
|
359
|
+
let trackingCollectionPath;
|
|
360
|
+
|
|
361
|
+
if (type === 'SIGNED_IN_USER') {
|
|
362
|
+
trackingCollectionPath = config.signedInUserSocialCollection || 'signed_in_users_social';
|
|
363
|
+
} else {
|
|
364
|
+
trackingCollectionPath = config.piSocialCollectionName || 'pi_social_posts';
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Write to a single tracking document at the root of the collection
|
|
368
|
+
const trackingDocRef = db.collection(trackingCollectionPath).doc('_dates');
|
|
369
|
+
const trackingData = {
|
|
370
|
+
[`fetchedDates.${today}`]: true,
|
|
371
|
+
lastUpdated: FieldValue.serverTimestamp()
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
await trackingDocRef.set(trackingData, { merge: true });
|
|
375
|
+
logger.log('INFO', `[SocialTask/${taskId}] Updated date tracking for ${type}: ${today}`);
|
|
376
|
+
}
|
|
377
|
+
|
|
354
378
|
logger.log('SUCCESS', `[SocialTask/${taskId}] Process complete for ${cid}. Total stored: ${totalSaved}/${MAX_POSTS_TO_STORE}`);
|
|
355
379
|
|
|
356
380
|
} catch (error) {
|