bulltrackers-module 1.0.563 → 1.0.564
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.
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
* Handles user portfolio data endpoints with migration support
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
const { findLatestPortfolioDate } = require('../core/data_lookup_helpers');
|
|
6
|
+
const { findLatestPortfolioDate, findLatestComputationDate } = require('../core/data_lookup_helpers');
|
|
7
7
|
const { checkIfUserIsPI } = require('../core/user_status_helpers');
|
|
8
8
|
const { getEffectiveCid, getDevOverride } = require('../dev/dev_helpers');
|
|
9
|
+
const { checkPiInComputationDate } = require('./computation_helpers');
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* GET /user/me/portfolio
|
|
@@ -119,7 +120,9 @@ async function getUserPortfolio(req, res, dependencies, config) {
|
|
|
119
120
|
|
|
120
121
|
/**
|
|
121
122
|
* GET /user/me/data-status
|
|
122
|
-
* Checks if signed-in user's
|
|
123
|
+
* Checks if signed-in user's profile page computation is available.
|
|
124
|
+
* The profile page uses SignedInUserProfileMetrics computation, not raw portfolio/history data.
|
|
125
|
+
* If computation exists, the profile page can be rendered. If not, user should sync.
|
|
123
126
|
*/
|
|
124
127
|
async function getUserDataStatus(req, res, dependencies, config) {
|
|
125
128
|
const { db, logger } = dependencies;
|
|
@@ -130,146 +133,80 @@ async function getUserDataStatus(req, res, dependencies, config) {
|
|
|
130
133
|
}
|
|
131
134
|
|
|
132
135
|
try {
|
|
133
|
-
const { signedInUsersCollection, signedInHistoryCollection } = config;
|
|
134
|
-
const CANARY_BLOCK_ID = '19M';
|
|
135
|
-
|
|
136
136
|
const today = new Date().toISOString().split('T')[0];
|
|
137
137
|
|
|
138
|
-
logger.log('INFO', `[getUserDataStatus] Checking
|
|
139
|
-
|
|
140
|
-
// Try to find latest available date for portfolio (with fallback)
|
|
141
|
-
const portfolioDate = await findLatestPortfolioDate(db, signedInUsersCollection, userCid, 30);
|
|
142
|
-
const portfolioExists = !!portfolioDate;
|
|
143
|
-
const isPortfolioFallback = portfolioDate && portfolioDate !== today;
|
|
138
|
+
logger.log('INFO', `[getUserDataStatus] Checking computation for CID: ${userCid}, Date: ${today}`);
|
|
144
139
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Check history data with fallback
|
|
150
|
-
// Check new root data path first: SignedInUsers/{cid}/tradeHistory/latest
|
|
151
|
-
let historyExists = false;
|
|
152
|
-
let historyDate = null;
|
|
153
|
-
let isHistoryFallback = false;
|
|
140
|
+
// Check for dev override impersonation
|
|
141
|
+
const effectiveCid = await getEffectiveCid(db, userCid, config, logger);
|
|
154
142
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
143
|
+
// Primary check: Does SignedInUserProfileMetrics computation exist for this user?
|
|
144
|
+
// This is what the profile page actually uses to render
|
|
145
|
+
const insightsCollection = config.unifiedInsightsCollection || 'unified_insights';
|
|
146
|
+
const resultsSub = config.resultsSubcollection || 'results';
|
|
147
|
+
const compsSub = config.computationsSubcollection || 'computations';
|
|
148
|
+
const category = 'popular-investor';
|
|
149
|
+
const computationName = 'SignedInUserProfileMetrics';
|
|
150
|
+
|
|
151
|
+
// Find latest computation date
|
|
152
|
+
const latestComputationDate = await findLatestComputationDate(
|
|
153
|
+
db,
|
|
154
|
+
insightsCollection,
|
|
155
|
+
resultsSub,
|
|
156
|
+
compsSub,
|
|
157
|
+
category,
|
|
158
|
+
computationName,
|
|
159
|
+
effectiveCid,
|
|
160
|
+
30
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
let computationAvailable = false;
|
|
164
|
+
let computationDate = null;
|
|
165
|
+
let isComputationFallback = false;
|
|
166
|
+
|
|
167
|
+
if (latestComputationDate) {
|
|
168
|
+
// Check if this specific user exists in the computation
|
|
169
|
+
const { found } = await checkPiInComputationDate(
|
|
170
|
+
db,
|
|
171
|
+
insightsCollection,
|
|
172
|
+
resultsSub,
|
|
173
|
+
compsSub,
|
|
174
|
+
category,
|
|
175
|
+
computationName,
|
|
176
|
+
latestComputationDate,
|
|
177
|
+
String(effectiveCid),
|
|
178
|
+
logger
|
|
179
|
+
);
|
|
160
180
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
historyExists = true;
|
|
166
|
-
historyDate = data.date;
|
|
167
|
-
isHistoryFallback = data.date !== today;
|
|
168
|
-
logger.log('INFO', `[getUserDataStatus] Found history data in latest snapshot: ${historyDate}`);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
} catch (error) {
|
|
172
|
-
// Continue to other checks if this fails
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// If not found in latest snapshot, check new root data path: SignedInUserTradeHistoryData/{date}/{cid}/{cid}
|
|
176
|
-
if (!historyExists) {
|
|
177
|
-
for (let i = 0; i <= 30; i++) {
|
|
178
|
-
const checkDate = new Date();
|
|
179
|
-
checkDate.setDate(checkDate.getDate() - i);
|
|
180
|
-
const dateStr = checkDate.toISOString().split('T')[0];
|
|
181
|
+
if (found) {
|
|
182
|
+
computationAvailable = true;
|
|
183
|
+
computationDate = latestComputationDate;
|
|
184
|
+
isComputationFallback = latestComputationDate !== today;
|
|
181
185
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
.doc(String(userCid));
|
|
187
|
-
|
|
188
|
-
const rootHistoryDoc = await rootHistoryRef.get();
|
|
189
|
-
if (rootHistoryDoc.exists) {
|
|
190
|
-
historyExists = true;
|
|
191
|
-
historyDate = dateStr;
|
|
192
|
-
isHistoryFallback = dateStr !== today;
|
|
193
|
-
logger.log('INFO', `[getUserDataStatus] Found history data in root data collection: ${historyDate}`);
|
|
194
|
-
break;
|
|
195
|
-
}
|
|
196
|
-
} catch (error) {
|
|
197
|
-
continue;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// If still not found, check legacy path for backward compatibility
|
|
203
|
-
if (!historyExists) {
|
|
204
|
-
const historyCollection = signedInHistoryCollection || 'signed_in_user_history';
|
|
205
|
-
|
|
206
|
-
// Check today first
|
|
207
|
-
const todayHistoryRef = db.collection(historyCollection)
|
|
208
|
-
.doc(CANARY_BLOCK_ID)
|
|
209
|
-
.collection('snapshots')
|
|
210
|
-
.doc(today)
|
|
211
|
-
.collection('parts');
|
|
212
|
-
|
|
213
|
-
const todayHistorySnapshot = await todayHistoryRef.get();
|
|
214
|
-
|
|
215
|
-
if (!todayHistorySnapshot.empty) {
|
|
216
|
-
for (const partDoc of todayHistorySnapshot.docs) {
|
|
217
|
-
const partData = partDoc.data();
|
|
218
|
-
if (partData && partData[String(userCid)]) {
|
|
219
|
-
historyExists = true;
|
|
220
|
-
historyDate = today;
|
|
221
|
-
break;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// If not found today, search backwards
|
|
227
|
-
if (!historyExists) {
|
|
228
|
-
for (let i = 1; i <= 30; i++) {
|
|
229
|
-
const checkDate = new Date();
|
|
230
|
-
checkDate.setDate(checkDate.getDate() - i);
|
|
231
|
-
const dateStr = checkDate.toISOString().split('T')[0];
|
|
232
|
-
|
|
233
|
-
try {
|
|
234
|
-
const historyPartsRef = db.collection(historyCollection)
|
|
235
|
-
.doc(CANARY_BLOCK_ID)
|
|
236
|
-
.collection('snapshots')
|
|
237
|
-
.doc(dateStr)
|
|
238
|
-
.collection('parts');
|
|
239
|
-
|
|
240
|
-
const historyPartsSnapshot = await historyPartsRef.get();
|
|
241
|
-
|
|
242
|
-
if (!historyPartsSnapshot.empty) {
|
|
243
|
-
for (const partDoc of historyPartsSnapshot.docs) {
|
|
244
|
-
const partData = partDoc.data();
|
|
245
|
-
if (partData && partData[String(userCid)]) {
|
|
246
|
-
historyExists = true;
|
|
247
|
-
historyDate = dateStr;
|
|
248
|
-
isHistoryFallback = true;
|
|
249
|
-
logger.log('INFO', `[getUserDataStatus] Found history data in legacy fallback date ${dateStr}`);
|
|
250
|
-
break;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (historyExists) break;
|
|
256
|
-
} catch (error) {
|
|
257
|
-
continue;
|
|
258
|
-
}
|
|
186
|
+
if (isComputationFallback) {
|
|
187
|
+
logger.log('INFO', `[getUserDataStatus] Using fallback computation date ${computationDate} for user ${userCid} (today: ${today})`);
|
|
188
|
+
} else {
|
|
189
|
+
logger.log('INFO', `[getUserDataStatus] Found computation for user ${userCid} on today's date`);
|
|
259
190
|
}
|
|
191
|
+
} else {
|
|
192
|
+
logger.log('INFO', `[getUserDataStatus] Computation exists for date ${latestComputationDate} but user ${userCid} not found in it`);
|
|
260
193
|
}
|
|
194
|
+
} else {
|
|
195
|
+
logger.log('INFO', `[getUserDataStatus] No computation found for user ${userCid} in last 30 days`);
|
|
261
196
|
}
|
|
262
197
|
|
|
198
|
+
// For backward compatibility, keep portfolioAvailable and historyAvailable
|
|
199
|
+
// but they should match computationAvailable (computation is the source of truth)
|
|
263
200
|
const result = {
|
|
264
|
-
portfolioAvailable:
|
|
265
|
-
historyAvailable:
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
isHistoryFallback: isHistoryFallback,
|
|
201
|
+
portfolioAvailable: computationAvailable, // Profile page uses computation, not raw portfolio
|
|
202
|
+
historyAvailable: computationAvailable, // Profile page uses computation, not raw history
|
|
203
|
+
computationAvailable: computationAvailable, // Explicit computation check
|
|
204
|
+
date: computationDate || today,
|
|
205
|
+
computationDate: computationDate,
|
|
206
|
+
isComputationFallback: isComputationFallback,
|
|
271
207
|
requestedDate: today,
|
|
272
|
-
userCid: String(userCid)
|
|
208
|
+
userCid: String(userCid),
|
|
209
|
+
effectiveCid: String(effectiveCid)
|
|
273
210
|
};
|
|
274
211
|
|
|
275
212
|
logger.log('INFO', `[getUserDataStatus] Result for CID ${userCid}:`, result);
|