bulltrackers-module 1.0.629 → 1.0.631
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.
- package/functions/alert-system/helpers/alert_helpers.js +69 -77
- package/functions/alert-system/index.js +19 -29
- package/functions/api-v2/helpers/notification_helpers.js +187 -0
- package/functions/computation-system/helpers/computation_worker.js +1 -1
- package/functions/task-engine/helpers/popular_investor_helpers.js +11 -7
- package/index.js +0 -5
- package/package.json +1 -2
- package/functions/old-generic-api/admin-api/index.js +0 -895
- package/functions/old-generic-api/helpers/api_helpers.js +0 -457
- package/functions/old-generic-api/index.js +0 -204
- package/functions/old-generic-api/user-api/helpers/alerts/alert_helpers.js +0 -355
- package/functions/old-generic-api/user-api/helpers/alerts/subscription_helpers.js +0 -327
- package/functions/old-generic-api/user-api/helpers/alerts/test_alert_helpers.js +0 -212
- package/functions/old-generic-api/user-api/helpers/collection_helpers.js +0 -193
- package/functions/old-generic-api/user-api/helpers/core/compression_helpers.js +0 -68
- package/functions/old-generic-api/user-api/helpers/core/data_lookup_helpers.js +0 -256
- package/functions/old-generic-api/user-api/helpers/core/path_resolution_helpers.js +0 -640
- package/functions/old-generic-api/user-api/helpers/core/user_status_helpers.js +0 -195
- package/functions/old-generic-api/user-api/helpers/data/computation_helpers.js +0 -503
- package/functions/old-generic-api/user-api/helpers/data/instrument_helpers.js +0 -55
- package/functions/old-generic-api/user-api/helpers/data/portfolio_helpers.js +0 -245
- package/functions/old-generic-api/user-api/helpers/data/social_helpers.js +0 -174
- package/functions/old-generic-api/user-api/helpers/data_helpers.js +0 -87
- package/functions/old-generic-api/user-api/helpers/dev/dev_helpers.js +0 -336
- package/functions/old-generic-api/user-api/helpers/fetch/on_demand_fetch_helpers.js +0 -615
- package/functions/old-generic-api/user-api/helpers/metrics/personalized_metrics_helpers.js +0 -231
- package/functions/old-generic-api/user-api/helpers/notifications/notification_helpers.js +0 -641
- package/functions/old-generic-api/user-api/helpers/profile/pi_profile_helpers.js +0 -182
- package/functions/old-generic-api/user-api/helpers/profile/profile_view_helpers.js +0 -137
- package/functions/old-generic-api/user-api/helpers/profile/user_profile_helpers.js +0 -190
- package/functions/old-generic-api/user-api/helpers/recommendations/recommendation_helpers.js +0 -66
- package/functions/old-generic-api/user-api/helpers/reviews/review_helpers.js +0 -550
- package/functions/old-generic-api/user-api/helpers/rootdata/rootdata_aggregation_helpers.js +0 -378
- package/functions/old-generic-api/user-api/helpers/search/pi_request_helpers.js +0 -295
- package/functions/old-generic-api/user-api/helpers/search/pi_search_helpers.js +0 -162
- package/functions/old-generic-api/user-api/helpers/sync/user_sync_helpers.js +0 -677
- package/functions/old-generic-api/user-api/helpers/verification/verification_helpers.js +0 -323
- package/functions/old-generic-api/user-api/helpers/watchlist/watchlist_analytics_helpers.js +0 -96
- package/functions/old-generic-api/user-api/helpers/watchlist/watchlist_data_helpers.js +0 -141
- package/functions/old-generic-api/user-api/helpers/watchlist/watchlist_generation_helpers.js +0 -310
- package/functions/old-generic-api/user-api/helpers/watchlist/watchlist_management_helpers.js +0 -829
- package/functions/old-generic-api/user-api/index.js +0 -109
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Personalized Metrics Helpers
|
|
3
|
-
* Handles personalized metrics for signed-in users who are also PIs
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const { findLatestComputationDate } = require('../core/data_lookup_helpers');
|
|
7
|
-
const { tryDecompress } = require('../core/compression_helpers');
|
|
8
|
-
const { checkIfUserIsPI } = require('../core/user_status_helpers');
|
|
9
|
-
const { getEffectiveCid, getDevOverride } = require('../dev/dev_helpers');
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* GET /user/me/pi-personalized-metrics
|
|
13
|
-
* Fetches personalized metrics for a signed-in user who is also a Popular Investor
|
|
14
|
-
* Reads from pages subcollection: /unified_insights/YYYY-MM-DD/results/popular-investor/computations/SignedInUserPIPersonalizedMetrics/pages/{cid}
|
|
15
|
-
*/
|
|
16
|
-
async function getSignedInUserPIPersonalizedMetrics(req, res, dependencies, config) {
|
|
17
|
-
const { db, logger } = dependencies;
|
|
18
|
-
const { userCid } = req.query;
|
|
19
|
-
|
|
20
|
-
if (!userCid) {
|
|
21
|
-
return res.status(400).json({ error: "Missing userCid" });
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
try {
|
|
25
|
-
const devOverride = await getDevOverride(db, userCid, config, logger);
|
|
26
|
-
|
|
27
|
-
// Also read raw Firestore data to check pretendToBePI value directly (in case of normalization issues)
|
|
28
|
-
let rawPretendToBePI = null;
|
|
29
|
-
if (devOverride && devOverride.enabled) {
|
|
30
|
-
try {
|
|
31
|
-
const devOverridesCollection = config.devOverridesCollection || 'dev_overrides';
|
|
32
|
-
const overrideDoc = await db.collection(devOverridesCollection).doc(String(userCid)).get();
|
|
33
|
-
if (overrideDoc.exists) {
|
|
34
|
-
const rawData = overrideDoc.data();
|
|
35
|
-
rawPretendToBePI = rawData.pretendToBePI; // Get raw value (could be false, true, undefined, etc.)
|
|
36
|
-
}
|
|
37
|
-
} catch (err) {
|
|
38
|
-
logger.log('WARN', `[getSignedInUserPIPersonalizedMetrics] Error reading raw dev override: ${err.message}`);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// For PI-related checks, respect pretendToBePI flag
|
|
43
|
-
// If pretendToBePI is false (either normalized or raw), use actual userCid even if impersonateCid is set
|
|
44
|
-
let effectiveCid;
|
|
45
|
-
let shouldCheckPI = true;
|
|
46
|
-
|
|
47
|
-
// Check if user explicitly doesn't want to pretend to be a PI
|
|
48
|
-
// Check both normalized value and raw value to be safe
|
|
49
|
-
const pretendToBePIValue = rawPretendToBePI !== undefined ? rawPretendToBePI : (devOverride ? devOverride.pretendToBePI : false);
|
|
50
|
-
const explicitlyNotPretending = pretendToBePIValue === false;
|
|
51
|
-
|
|
52
|
-
if (devOverride && devOverride.enabled && explicitlyNotPretending) {
|
|
53
|
-
// User explicitly doesn't want to pretend to be a PI
|
|
54
|
-
// Use actual CID and don't check PI status (user doesn't want to be treated as PI)
|
|
55
|
-
effectiveCid = Number(userCid);
|
|
56
|
-
shouldCheckPI = false; // Skip PI check since user doesn't want to pretend to be PI
|
|
57
|
-
|
|
58
|
-
logger.log('INFO', `[getSignedInUserPIPersonalizedMetrics] DEV OVERRIDE: User ${userCid} has pretendToBePI=false (raw: ${rawPretendToBePI}, normalized: ${devOverride.pretendToBePI}), skipping PI check and returning 404`);
|
|
59
|
-
} else {
|
|
60
|
-
// Use normal effective CID logic (may use impersonateCid if set)
|
|
61
|
-
effectiveCid = await getEffectiveCid(db, userCid, config, logger);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Calculate isImpersonating based on whether we're actually using impersonation
|
|
65
|
-
// If pretendToBePI is false, we're not impersonating for PI purposes
|
|
66
|
-
// Only consider it impersonating if pretendToBePI is not explicitly false AND effectiveCid differs from userCid
|
|
67
|
-
const isImpersonating = shouldCheckPI &&
|
|
68
|
-
devOverride && devOverride.enabled && devOverride.impersonateCid &&
|
|
69
|
-
!explicitlyNotPretending && effectiveCid !== Number(userCid);
|
|
70
|
-
|
|
71
|
-
// If user explicitly doesn't want to pretend to be a PI, return 404 immediately
|
|
72
|
-
if (!shouldCheckPI) {
|
|
73
|
-
return res.status(404).json({
|
|
74
|
-
error: "Not a Popular Investor",
|
|
75
|
-
message: "This endpoint is only available for users who are Popular Investors",
|
|
76
|
-
effectiveCid: effectiveCid,
|
|
77
|
-
isImpersonating: false, // Not impersonating if pretendToBePI is false
|
|
78
|
-
actualCid: Number(userCid)
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Check if user is a PI
|
|
83
|
-
const rankEntry = await checkIfUserIsPI(db, effectiveCid, config, logger);
|
|
84
|
-
if (!rankEntry) {
|
|
85
|
-
return res.status(404).json({
|
|
86
|
-
error: "Not a Popular Investor",
|
|
87
|
-
message: "This endpoint is only available for users who are Popular Investors",
|
|
88
|
-
effectiveCid: effectiveCid,
|
|
89
|
-
isImpersonating: isImpersonating || false,
|
|
90
|
-
actualCid: Number(userCid)
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const insightsCollection = config.unifiedInsightsCollection || 'unified_insights';
|
|
95
|
-
const resultsSub = config.resultsSubcollection || 'results';
|
|
96
|
-
const compsSub = config.computationsSubcollection || 'computations';
|
|
97
|
-
const category = 'popular-investor';
|
|
98
|
-
const computationName = 'SignedInUserPIPersonalizedMetrics';
|
|
99
|
-
const today = new Date().toISOString().split('T')[0];
|
|
100
|
-
const cidStr = String(effectiveCid);
|
|
101
|
-
const maxDaysBack = 30;
|
|
102
|
-
|
|
103
|
-
logger.log('INFO', `[getSignedInUserPIPersonalizedMetrics] Starting search for PI CID: ${effectiveCid}`);
|
|
104
|
-
|
|
105
|
-
// Find latest available computation date
|
|
106
|
-
const latestDate = await findLatestComputationDate(
|
|
107
|
-
db,
|
|
108
|
-
insightsCollection,
|
|
109
|
-
resultsSub,
|
|
110
|
-
compsSub,
|
|
111
|
-
category,
|
|
112
|
-
computationName,
|
|
113
|
-
null,
|
|
114
|
-
30
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
logger.log('INFO', `[getSignedInUserPIPersonalizedMetrics] Latest computation date found: ${latestDate || 'NONE'}`);
|
|
118
|
-
|
|
119
|
-
if (!latestDate) {
|
|
120
|
-
logger.log('WARN', `[getSignedInUserPIPersonalizedMetrics] No computation document found for ${computationName} in last 30 days`);
|
|
121
|
-
return res.status(200).json({
|
|
122
|
-
status: 'not_found',
|
|
123
|
-
message: 'No computation data available. Please sync your account to generate personalized metrics.',
|
|
124
|
-
data: null,
|
|
125
|
-
dataDate: null,
|
|
126
|
-
requestedDate: today,
|
|
127
|
-
fallbackWindowExhausted: true,
|
|
128
|
-
effectiveCid: effectiveCid,
|
|
129
|
-
isImpersonating: isImpersonating || false,
|
|
130
|
-
actualCid: Number(userCid)
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Try to find the user's page starting from the latest date, then going back up to 30 days
|
|
135
|
-
let foundDate = null;
|
|
136
|
-
let metricsData = null;
|
|
137
|
-
let checkedDates = [];
|
|
138
|
-
|
|
139
|
-
const latestDateObj = new Date(latestDate + 'T00:00:00Z');
|
|
140
|
-
|
|
141
|
-
for (let daysBack = 0; daysBack <= maxDaysBack; daysBack++) {
|
|
142
|
-
const checkDate = new Date(latestDateObj);
|
|
143
|
-
checkDate.setUTCDate(latestDateObj.getUTCDate() - daysBack);
|
|
144
|
-
const dateStr = checkDate.toISOString().split('T')[0];
|
|
145
|
-
checkedDates.push(dateStr);
|
|
146
|
-
|
|
147
|
-
logger.log('INFO', `[getSignedInUserPIPersonalizedMetrics] Checking date ${dateStr} for CID ${effectiveCid} (${daysBack} days back from latest)`);
|
|
148
|
-
|
|
149
|
-
// Read from pages subcollection: /unified_insights/YYYY-MM-DD/results/popular-investor/computations/SignedInUserPIPersonalizedMetrics/pages/{cid}
|
|
150
|
-
const pageRef = db.collection(insightsCollection)
|
|
151
|
-
.doc(dateStr)
|
|
152
|
-
.collection(resultsSub)
|
|
153
|
-
.doc(category)
|
|
154
|
-
.collection(compsSub)
|
|
155
|
-
.doc(computationName)
|
|
156
|
-
.collection('pages')
|
|
157
|
-
.doc(cidStr);
|
|
158
|
-
|
|
159
|
-
const pageDoc = await pageRef.get();
|
|
160
|
-
|
|
161
|
-
if (pageDoc.exists) {
|
|
162
|
-
const rawData = pageDoc.data();
|
|
163
|
-
let data = tryDecompress(rawData);
|
|
164
|
-
|
|
165
|
-
// Handle string decompression result
|
|
166
|
-
if (typeof data === 'string') {
|
|
167
|
-
try {
|
|
168
|
-
data = JSON.parse(data);
|
|
169
|
-
} catch (e) {
|
|
170
|
-
logger.log('WARN', `[getSignedInUserPIPersonalizedMetrics] Failed to parse decompressed string for CID ${effectiveCid} on date ${dateStr}:`, e.message);
|
|
171
|
-
continue;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (data && typeof data === 'object') {
|
|
176
|
-
foundDate = dateStr;
|
|
177
|
-
metricsData = data;
|
|
178
|
-
logger.log('SUCCESS', `[getSignedInUserPIPersonalizedMetrics] Found personalized metrics for CID ${effectiveCid} in date ${dateStr} (${daysBack} days back from latest)`);
|
|
179
|
-
break;
|
|
180
|
-
} else {
|
|
181
|
-
logger.log('WARN', `[getSignedInUserPIPersonalizedMetrics] Page data is not an object for CID ${effectiveCid} on date ${dateStr}`);
|
|
182
|
-
}
|
|
183
|
-
} else {
|
|
184
|
-
logger.log('INFO', `[getSignedInUserPIPersonalizedMetrics] Page document not found for CID ${effectiveCid} in date ${dateStr}`);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// If not found in any checked date, return response indicating sync is needed
|
|
189
|
-
if (!foundDate || !metricsData) {
|
|
190
|
-
logger.log('WARN', `[getSignedInUserPIPersonalizedMetrics] CID ${effectiveCid} not found in any checked dates: ${checkedDates.join(', ')}`);
|
|
191
|
-
|
|
192
|
-
return res.status(200).json({
|
|
193
|
-
status: 'not_found',
|
|
194
|
-
message: 'No personalized metrics found for this user. Please sync your account to generate personalized metrics.',
|
|
195
|
-
data: null,
|
|
196
|
-
dataDate: null,
|
|
197
|
-
requestedDate: today,
|
|
198
|
-
latestComputationDate: latestDate,
|
|
199
|
-
checkedDates: checkedDates,
|
|
200
|
-
fallbackWindowExhausted: true,
|
|
201
|
-
effectiveCid: effectiveCid,
|
|
202
|
-
isImpersonating: isImpersonating || false,
|
|
203
|
-
actualCid: Number(userCid)
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
logger.log('SUCCESS', `[getSignedInUserPIPersonalizedMetrics] Returning personalized metrics for CID ${effectiveCid} from date ${foundDate} (requested: ${today}, latest available: ${latestDate})`);
|
|
208
|
-
|
|
209
|
-
return res.status(200).json({
|
|
210
|
-
status: 'success',
|
|
211
|
-
userCid: String(effectiveCid),
|
|
212
|
-
data: metricsData,
|
|
213
|
-
dataDate: foundDate,
|
|
214
|
-
requestedDate: today,
|
|
215
|
-
latestComputationDate: latestDate,
|
|
216
|
-
isFallback: foundDate !== latestDate || foundDate !== today,
|
|
217
|
-
daysBackFromLatest: checkedDates.indexOf(foundDate),
|
|
218
|
-
isImpersonating: isImpersonating || false,
|
|
219
|
-
actualCid: Number(userCid),
|
|
220
|
-
pretendToBePI: devOverride && devOverride.enabled ? (devOverride.pretendToBePI || false) : false
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
} catch (error) {
|
|
224
|
-
logger.log('ERROR', `[getSignedInUserPIPersonalizedMetrics] Error fetching personalized metrics for ${userCid}:`, error);
|
|
225
|
-
return res.status(500).json({ error: error.message });
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
module.exports = {
|
|
230
|
-
getSignedInUserPIPersonalizedMetrics
|
|
231
|
-
};
|