bulltrackers-module 1.0.538 → 1.0.539

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.
@@ -1,46 +1,165 @@
1
1
  /**
2
2
  * @fileoverview Social Posts Data Helpers
3
3
  * Handles user social posts endpoints
4
+ * UPDATED: Uses collection registry to read from root data collection
4
5
  */
5
6
 
7
+ const { findLatestRankingsDate } = require('../core/data_lookup_helpers');
8
+ const { getEffectiveCid, getDevOverride } = require('../dev/dev_helpers');
9
+
10
+ /**
11
+ * Find the latest available date for signed-in user social posts
12
+ * Searches backwards from today up to maxDaysBack days
13
+ * @param {Firestore} db - Firestore instance
14
+ * @param {string|number} userCid - User CID
15
+ * @param {object} collectionRegistry - Collection registry (injected at runtime)
16
+ * @param {number} maxDaysBack - Maximum days to search backwards (default: 30)
17
+ * @returns {Promise<string|null>} - Date string (YYYY-MM-DD) or null if not found
18
+ */
19
+ async function findLatestSocialDate(db, userCid, collectionRegistry, maxDaysBack = 30) {
20
+ const today = new Date();
21
+
22
+ // Get collection name from registry
23
+ let collectionName = 'SignedInUserSocialPostData'; // Default fallback
24
+ if (collectionRegistry && collectionRegistry.getCollectionPath) {
25
+ try {
26
+ // Extract collection name from registry path template
27
+ const samplePath = collectionRegistry.getCollectionPath('rootData', 'signedInUserSocial', {
28
+ date: '2025-01-01',
29
+ cid: '123'
30
+ });
31
+ collectionName = samplePath.split('/')[0]; // Extract collection name
32
+ } catch (e) {
33
+ // Use default collection name
34
+ }
35
+ }
36
+
37
+ for (let i = 0; i < maxDaysBack; i++) {
38
+ const checkDate = new Date(today);
39
+ checkDate.setDate(checkDate.getDate() - i);
40
+ const dateStr = checkDate.toISOString().split('T')[0];
41
+
42
+ try {
43
+ // Construct path: SignedInUserSocialPostData/{date}/{cid}/{cid}
44
+ const socialDocRef = db.collection(collectionName)
45
+ .doc(dateStr)
46
+ .collection(String(userCid))
47
+ .doc(String(userCid));
48
+
49
+ const socialDoc = await socialDocRef.get();
50
+
51
+ if (socialDoc.exists) {
52
+ const data = socialDoc.data();
53
+ if (data.posts && Object.keys(data.posts).length > 0) {
54
+ return dateStr; // Found social posts for this date
55
+ }
56
+ }
57
+ } catch (error) {
58
+ // Continue to next date if error
59
+ continue;
60
+ }
61
+ }
62
+
63
+ return null; // No social posts found in the last maxDaysBack days
64
+ }
65
+
6
66
  /**
7
67
  * GET /user/me/social-posts
8
- * Fetches the signed-in user's social posts
68
+ * Fetches the signed-in user's social posts from root data collection
9
69
  */
10
70
  async function getUserSocialPosts(req, res, dependencies, config) {
11
- const { db, logger } = dependencies;
12
- const { userCid } = req.query;
71
+ const { db, logger, collectionRegistry } = dependencies;
72
+ const { userCid, date } = req.query;
13
73
 
14
74
  if (!userCid) {
15
75
  return res.status(400).json({ error: "Missing userCid" });
16
76
  }
17
77
 
18
78
  try {
19
- const { signedInSocialCollection } = config;
20
- const socialCollection = signedInSocialCollection || 'signed_in_users_social';
21
-
22
- // Fetch posts from signed_in_users_social/{cid}/posts
23
- const postsRef = db.collection(socialCollection)
24
- .doc(String(userCid))
25
- .collection('posts');
26
-
27
- const postsSnapshot = await postsRef
28
- .orderBy('createdAt', 'desc')
29
- .limit(50) // Limit to 50 most recent posts
30
- .get();
31
-
32
- const posts = [];
33
- postsSnapshot.forEach(doc => {
34
- posts.push({
35
- id: doc.id,
36
- ...doc.data()
79
+ // Check for dev override impersonation
80
+ const effectiveCid = await getEffectiveCid(db, userCid, config, logger);
81
+ const devOverride = await getDevOverride(db, userCid, config, logger);
82
+ const isImpersonating = devOverride && devOverride.enabled && devOverride.impersonateCid && effectiveCid !== Number(userCid);
83
+
84
+ const today = new Date().toISOString().split('T')[0];
85
+
86
+ // Determine which date to use
87
+ let dataDate = date || today;
88
+ let isFallback = false;
89
+
90
+ // If no specific date requested, find latest available date
91
+ if (!date) {
92
+ dataDate = await findLatestSocialDate(db, effectiveCid, collectionRegistry, 30);
93
+ if (!dataDate) {
94
+ return res.status(404).json({
95
+ error: "Social posts not found for this user (checked last 30 days)",
96
+ effectiveCid: effectiveCid,
97
+ isImpersonating: isImpersonating || false
98
+ });
99
+ }
100
+ isFallback = dataDate !== today;
101
+ if (isFallback) {
102
+ logger.log('INFO', `[getUserSocialPosts] Using fallback date ${dataDate} for effective CID ${effectiveCid} (today: ${today})`);
103
+ }
104
+ }
105
+
106
+ // Get collection name from registry
107
+ let collectionName = 'SignedInUserSocialPostData'; // Default fallback
108
+ if (collectionRegistry && collectionRegistry.getCollectionPath) {
109
+ try {
110
+ // Extract collection name from registry path template
111
+ const samplePath = collectionRegistry.getCollectionPath('rootData', 'signedInUserSocial', {
112
+ date: '2025-01-01',
113
+ cid: '123'
114
+ });
115
+ collectionName = samplePath.split('/')[0]; // Extract collection name
116
+ } catch (e) {
117
+ logger.log('WARN', `[getUserSocialPosts] Failed to get collection name from registry, using default: ${e.message}`);
118
+ }
119
+ }
120
+
121
+ // Construct path: SignedInUserSocialPostData/{date}/{cid}/{cid}
122
+ const socialDocRef = db.collection(collectionName)
123
+ .doc(dataDate)
124
+ .collection(String(effectiveCid))
125
+ .doc(String(effectiveCid));
126
+
127
+ const socialDoc = await socialDocRef.get();
128
+
129
+ if (!socialDoc.exists) {
130
+ return res.status(404).json({
131
+ error: "Social posts not found",
132
+ date: dataDate,
133
+ effectiveCid: effectiveCid,
134
+ isImpersonating: isImpersonating || false
37
135
  });
38
- });
136
+ }
137
+
138
+ const socialData = socialDoc.data();
139
+ const postsMap = socialData.posts || {};
140
+
141
+ // Convert posts map to array and sort by createdAt (descending)
142
+ const posts = Object.entries(postsMap)
143
+ .map(([postId, postData]) => ({
144
+ id: postId,
145
+ ...postData
146
+ }))
147
+ .sort((a, b) => {
148
+ const dateA = a.createdAt ? new Date(a.createdAt).getTime() : 0;
149
+ const dateB = b.createdAt ? new Date(b.createdAt).getTime() : 0;
150
+ return dateB - dateA; // Descending order
151
+ })
152
+ .slice(0, 50); // Limit to 50 most recent posts
39
153
 
40
154
  return res.status(200).json({
41
155
  posts,
42
156
  count: posts.length,
43
- userCid: String(userCid)
157
+ date: dataDate,
158
+ isFallback: isFallback,
159
+ requestedDate: date || today,
160
+ userCid: String(userCid),
161
+ effectiveCid: effectiveCid,
162
+ isImpersonating: isImpersonating || false
44
163
  });
45
164
 
46
165
  } catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulltrackers-module",
3
- "version": "1.0.538",
3
+ "version": "1.0.539",
4
4
  "description": "Helper Functions for Bulltrackers.",
5
5
  "main": "index.js",
6
6
  "files": [