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
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
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) {
|