bulltrackers-module 1.0.557 → 1.0.559
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 +57 -0
- package/functions/generic-api/user-api/helpers/dev/dev_helpers.js +23 -2
- package/functions/generic-api/user-api/helpers/metrics/personalized_metrics_helpers.js +12 -1
- package/functions/generic-api/user-api/helpers/profile/user_profile_helpers.js +12 -1
- package/package.json +1 -1
|
@@ -115,6 +115,7 @@ async function processAlertForPI(db, logger, piCid, alertType, computationMetada
|
|
|
115
115
|
/**
|
|
116
116
|
* Find all users who should receive alerts for a PI and alert type
|
|
117
117
|
* Uses WatchlistMembershipData/{date} to find users, then reads watchlists from SignedInUsers/{cid}/watchlists
|
|
118
|
+
* Also checks for developer accounts with pretendSubscribedToAllAlerts flag enabled
|
|
118
119
|
*/
|
|
119
120
|
async function findSubscriptionsForPI(db, logger, piCid, alertTypeId, computationDate, dependencies = {}) {
|
|
120
121
|
const subscriptions = [];
|
|
@@ -135,6 +136,62 @@ async function findSubscriptionsForPI(db, logger, piCid, alertTypeId, computatio
|
|
|
135
136
|
return subscriptions;
|
|
136
137
|
}
|
|
137
138
|
|
|
139
|
+
// Check for developer accounts with pretendSubscribedToAllAlerts flag enabled
|
|
140
|
+
// This allows developers to test the alert system without manually configuring subscriptions
|
|
141
|
+
try {
|
|
142
|
+
const { getDevOverride, isDeveloperAccount } = require('../../generic-api/user-api/helpers/dev/dev_helpers');
|
|
143
|
+
const { getPIMasterList } = require('../../generic-api/user-api/helpers/core/user_status_helpers');
|
|
144
|
+
const config = dependencies.config || {};
|
|
145
|
+
const collectionRegistry = dependencies.collectionRegistry || null;
|
|
146
|
+
|
|
147
|
+
// Get all popular investors from master list for username lookup
|
|
148
|
+
const allInvestors = await getPIMasterList(db, collectionRegistry, logger);
|
|
149
|
+
const piUsername = allInvestors[String(piCid)]?.username || `PI-${piCid}`;
|
|
150
|
+
|
|
151
|
+
// Default alert config with all alert types enabled (for dev override)
|
|
152
|
+
const allAlertsEnabledConfig = {
|
|
153
|
+
increasedRisk: true,
|
|
154
|
+
volatilityChanges: true,
|
|
155
|
+
newSector: true,
|
|
156
|
+
increasedPositionSize: true,
|
|
157
|
+
newSocialPost: true,
|
|
158
|
+
newPositions: true
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
// Check all developer accounts
|
|
162
|
+
const devOverridesCollection = config.devOverridesCollection || 'dev_overrides';
|
|
163
|
+
const devOverridesSnapshot = await db.collection(devOverridesCollection).get();
|
|
164
|
+
|
|
165
|
+
for (const devOverrideDoc of devOverridesSnapshot.docs) {
|
|
166
|
+
const devUserCid = Number(devOverrideDoc.id);
|
|
167
|
+
|
|
168
|
+
// Verify this is actually a developer account (security check)
|
|
169
|
+
if (!isDeveloperAccount(devUserCid)) {
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const devOverrideData = devOverrideDoc.data();
|
|
174
|
+
|
|
175
|
+
// Check if this developer has the pretendSubscribedToAllAlerts flag enabled
|
|
176
|
+
if (devOverrideData.enabled === true && devOverrideData.pretendSubscribedToAllAlerts === true) {
|
|
177
|
+
// Add this developer as a subscription for this PI and alert type
|
|
178
|
+
subscriptions.push({
|
|
179
|
+
userCid: devUserCid,
|
|
180
|
+
piCid: piCid,
|
|
181
|
+
piUsername: piUsername,
|
|
182
|
+
watchlistId: 'dev-override-all-alerts',
|
|
183
|
+
watchlistName: 'Dev Override - All Alerts',
|
|
184
|
+
alertConfig: allAlertsEnabledConfig
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
logger.log('INFO', `[findSubscriptionsForPI] DEV OVERRIDE: Added developer ${devUserCid} to subscriptions for PI ${piCid}, alert type ${alertTypeId}`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
} catch (error) {
|
|
191
|
+
// Don't fail the entire function if dev override check fails
|
|
192
|
+
logger.log('WARN', `[findSubscriptionsForPI] Error checking dev overrides: ${error.message}`);
|
|
193
|
+
}
|
|
194
|
+
|
|
138
195
|
// Step 1: Load WatchlistMembershipData/{date} to find which users have this PI in their watchlist
|
|
139
196
|
const piCidStr = String(piCid);
|
|
140
197
|
let userCids = [];
|
|
@@ -41,6 +41,7 @@ async function getDevOverride(db, userCid, config, logger = null) {
|
|
|
41
41
|
fakeCopiedPIs: [],
|
|
42
42
|
pretendToBePI: false,
|
|
43
43
|
impersonateCid: null, // CID to impersonate/view as
|
|
44
|
+
pretendSubscribedToAllAlerts: false, // Pretend to be subscribed to all alert types for all PIs
|
|
44
45
|
createdAt: FieldValue.serverTimestamp(),
|
|
45
46
|
lastUpdated: FieldValue.serverTimestamp()
|
|
46
47
|
};
|
|
@@ -60,6 +61,7 @@ async function getDevOverride(db, userCid, config, logger = null) {
|
|
|
60
61
|
fakeCopiedPIs: [],
|
|
61
62
|
pretendToBePI: false,
|
|
62
63
|
impersonateCid: null,
|
|
64
|
+
pretendSubscribedToAllAlerts: false,
|
|
63
65
|
lastUpdated: null,
|
|
64
66
|
wasAutoCreated: true
|
|
65
67
|
};
|
|
@@ -73,6 +75,7 @@ async function getDevOverride(db, userCid, config, logger = null) {
|
|
|
73
75
|
fakeCopiedPIs: data.fakeCopiedPIs || [],
|
|
74
76
|
pretendToBePI: data.pretendToBePI === true,
|
|
75
77
|
impersonateCid: data.impersonateCid ? Number(data.impersonateCid) : null,
|
|
78
|
+
pretendSubscribedToAllAlerts: data.pretendSubscribedToAllAlerts === true,
|
|
76
79
|
lastUpdated: data.lastUpdated,
|
|
77
80
|
wasAutoCreated: false
|
|
78
81
|
};
|
|
@@ -157,7 +160,7 @@ async function hasUserCopiedWithDevOverride(db, userCid, piCid, config, logger)
|
|
|
157
160
|
*/
|
|
158
161
|
async function setDevOverride(req, res, dependencies, config) {
|
|
159
162
|
const { db, logger } = dependencies;
|
|
160
|
-
const { userCid, enabled, fakeCopiedPIs, pretendToBePI, impersonateCid } = req.body;
|
|
163
|
+
const { userCid, enabled, fakeCopiedPIs, pretendToBePI, impersonateCid, pretendSubscribedToAllAlerts } = req.body;
|
|
161
164
|
|
|
162
165
|
if (!userCid) {
|
|
163
166
|
return res.status(400).json({ error: "Missing userCid" });
|
|
@@ -208,6 +211,7 @@ async function setDevOverride(req, res, dependencies, config) {
|
|
|
208
211
|
fakeCopiedPIs: enabled !== undefined ? validatedPIs : (existingData.fakeCopiedPIs || []),
|
|
209
212
|
pretendToBePI: pretendToBePI !== undefined ? (pretendToBePI === true) : (existingData.pretendToBePI || false),
|
|
210
213
|
impersonateCid: impersonateCid !== undefined ? (impersonateCid ? Number(impersonateCid) : null) : (existingData.impersonateCid || null),
|
|
214
|
+
pretendSubscribedToAllAlerts: pretendSubscribedToAllAlerts !== undefined ? (pretendSubscribedToAllAlerts === true) : (existingData.pretendSubscribedToAllAlerts || false),
|
|
211
215
|
lastUpdated: FieldValue.serverTimestamp()
|
|
212
216
|
};
|
|
213
217
|
|
|
@@ -217,6 +221,7 @@ async function setDevOverride(req, res, dependencies, config) {
|
|
|
217
221
|
`enabled=${overrideData.enabled}`,
|
|
218
222
|
`pretendToBePI=${overrideData.pretendToBePI}`,
|
|
219
223
|
`impersonateCid=${overrideData.impersonateCid || 'null'}`,
|
|
224
|
+
`pretendSubscribedToAllAlerts=${overrideData.pretendSubscribedToAllAlerts}`,
|
|
220
225
|
`${validatedPIs.length} fake PIs`
|
|
221
226
|
];
|
|
222
227
|
logger.log('SUCCESS', `[setDevOverride] Updated dev override for user ${userCid}: ${logParts.join(', ')}`);
|
|
@@ -270,6 +275,7 @@ async function getDevOverrideStatus(req, res, dependencies, config) {
|
|
|
270
275
|
fakeCopiedPIs: devOverride.fakeCopiedPIs,
|
|
271
276
|
pretendToBePI: devOverride.pretendToBePI || false,
|
|
272
277
|
impersonateCid: devOverride.impersonateCid || null,
|
|
278
|
+
pretendSubscribedToAllAlerts: devOverride.pretendSubscribedToAllAlerts || false,
|
|
273
279
|
lastUpdated: devOverride.lastUpdated,
|
|
274
280
|
wasAutoCreated: devOverride.wasAutoCreated || false
|
|
275
281
|
});
|
|
@@ -284,6 +290,9 @@ async function getDevOverrideStatus(req, res, dependencies, config) {
|
|
|
284
290
|
* Get the effective CID to use for a developer account
|
|
285
291
|
* Returns impersonateCid if set, otherwise returns the actual userCid
|
|
286
292
|
* Only works for developer accounts
|
|
293
|
+
*
|
|
294
|
+
* Note: If pretendToBePI is false, impersonation will not be used for PI-related checks
|
|
295
|
+
* to prevent unintended impersonation when the user doesn't want to pretend to be a PI
|
|
287
296
|
*/
|
|
288
297
|
async function getEffectiveCid(db, userCid, config, logger = null) {
|
|
289
298
|
if (!isDeveloperAccount(userCid)) {
|
|
@@ -291,8 +300,20 @@ async function getEffectiveCid(db, userCid, config, logger = null) {
|
|
|
291
300
|
}
|
|
292
301
|
|
|
293
302
|
const devOverride = await getDevOverride(db, userCid, config, logger);
|
|
294
|
-
// Only use impersonation if dev override is enabled
|
|
303
|
+
// Only use impersonation if dev override is enabled AND impersonateCid is set
|
|
304
|
+
// BUT: If pretendToBePI is explicitly false, don't use impersonation (user doesn't want to be treated as PI)
|
|
295
305
|
if (devOverride && devOverride.enabled && devOverride.impersonateCid) {
|
|
306
|
+
// Check if user explicitly doesn't want to pretend to be a PI
|
|
307
|
+
// If pretendToBePI is false, don't use impersonation (respects user intent)
|
|
308
|
+
if (devOverride.pretendToBePI === false) {
|
|
309
|
+
if (logger && logger.log) {
|
|
310
|
+
logger.log('INFO', `[getEffectiveCid] DEV OVERRIDE: User ${userCid} has impersonateCid set but pretendToBePI=false, using actual CID ${userCid} instead`);
|
|
311
|
+
} else {
|
|
312
|
+
console.log(`[getEffectiveCid] DEV OVERRIDE: User ${userCid} has impersonateCid set but pretendToBePI=false, using actual CID ${userCid} instead`);
|
|
313
|
+
}
|
|
314
|
+
return Number(userCid);
|
|
315
|
+
}
|
|
316
|
+
|
|
296
317
|
if (logger && logger.log) {
|
|
297
318
|
logger.log('INFO', `[getEffectiveCid] DEV OVERRIDE: User ${userCid} impersonating CID ${devOverride.impersonateCid}`);
|
|
298
319
|
} else {
|
|
@@ -96,8 +96,19 @@ async function getSignedInUserPIPersonalizedMetrics(req, res, dependencies, conf
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
try {
|
|
99
|
-
const effectiveCid = await getEffectiveCid(db, userCid, config, logger);
|
|
100
99
|
const devOverride = await getDevOverride(db, userCid, config, logger);
|
|
100
|
+
|
|
101
|
+
// For PI-related checks, respect pretendToBePI flag
|
|
102
|
+
// If pretendToBePI is false, use actual userCid even if impersonateCid is set
|
|
103
|
+
let effectiveCid;
|
|
104
|
+
if (devOverride && devOverride.enabled && devOverride.pretendToBePI === false) {
|
|
105
|
+
// User explicitly doesn't want to pretend to be a PI, use actual CID
|
|
106
|
+
effectiveCid = Number(userCid);
|
|
107
|
+
} else {
|
|
108
|
+
// Use normal effective CID logic (may use impersonateCid if set)
|
|
109
|
+
effectiveCid = await getEffectiveCid(db, userCid, config, logger);
|
|
110
|
+
}
|
|
111
|
+
|
|
101
112
|
const isImpersonating = devOverride && devOverride.enabled && devOverride.impersonateCid && effectiveCid !== Number(userCid);
|
|
102
113
|
|
|
103
114
|
// Check if user is a PI
|
|
@@ -128,8 +128,19 @@ async function checkIfUserIsPopularInvestor(req, res, dependencies, config) {
|
|
|
128
128
|
|
|
129
129
|
try {
|
|
130
130
|
// Check for dev override impersonation
|
|
131
|
-
const effectiveCid = await getEffectiveCid(db, userCid, config, logger);
|
|
132
131
|
const devOverride = await getDevOverride(db, userCid, config, logger);
|
|
132
|
+
|
|
133
|
+
// For PI-related checks, respect pretendToBePI flag
|
|
134
|
+
// If pretendToBePI is false, use actual userCid even if impersonateCid is set
|
|
135
|
+
let effectiveCid;
|
|
136
|
+
if (devOverride && devOverride.enabled && devOverride.pretendToBePI === false) {
|
|
137
|
+
// User explicitly doesn't want to pretend to be a PI, use actual CID
|
|
138
|
+
effectiveCid = Number(userCid);
|
|
139
|
+
} else {
|
|
140
|
+
// Use normal effective CID logic (may use impersonateCid if set)
|
|
141
|
+
effectiveCid = await getEffectiveCid(db, userCid, config, logger);
|
|
142
|
+
}
|
|
143
|
+
|
|
133
144
|
const isImpersonating = devOverride && devOverride.enabled && devOverride.impersonateCid && effectiveCid !== Number(userCid);
|
|
134
145
|
|
|
135
146
|
// Use effective CID (impersonated or actual) to check PI status
|