bulltrackers-module 1.0.509 → 1.0.511

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.
@@ -31,7 +31,7 @@ function getRegistryFunctions(options = {}) {
31
31
  return {
32
32
  getCollectionPath: options.collectionRegistry.getCollectionPath,
33
33
  resolvePath: options.collectionRegistry.resolvePath || resolvePath,
34
- getCollectionMetadata: options.collectionRegistry.getCollectionMetadata || options.collectionRegistry.getCollectionMetadata
34
+ getCollectionMetadata: options.collectionRegistry.getCollectionMetadata
35
35
  };
36
36
  }
37
37
 
@@ -254,6 +254,7 @@ async function readWithMigration(db, category, subcategory, params, options = {}
254
254
  if (newPath) {
255
255
  try {
256
256
  if (isCollection) {
257
+ // Collection path must have odd number of segments
257
258
  const collectionRef = db.collection(newPath);
258
259
  const snapshot = await collectionRef.get();
259
260
  if (!snapshot.empty) {
@@ -261,9 +262,21 @@ async function readWithMigration(db, category, subcategory, params, options = {}
261
262
  return { snapshot, source: 'new', path: newPath };
262
263
  }
263
264
  } else {
264
- const docRef = documentId
265
- ? db.collection(newPath).doc(documentId)
266
- : db.doc(newPath);
265
+ // Document path: if newPath has even segments, it's already a document path
266
+ // If documentId is provided, newPath should be collection path (odd segments)
267
+ let docRef;
268
+ if (documentId) {
269
+ // newPath should be collection (odd segments), add documentId
270
+ const pathSegments = newPath.split('/');
271
+ if (pathSegments.length % 2 === 0) {
272
+ // Even segments = document path, can't add documentId
273
+ throw new Error(`Path ${newPath} is a document path but documentId was provided`);
274
+ }
275
+ docRef = db.collection(newPath).doc(documentId);
276
+ } else {
277
+ // No documentId, newPath should be full document path (even segments)
278
+ docRef = db.doc(newPath);
279
+ }
267
280
  const doc = await docRef.get();
268
281
  if (doc.exists) {
269
282
  if (logger) logger.log('INFO', `[readWithMigration] Found data in new path: ${docRef.path}`);
@@ -471,6 +484,11 @@ async function writeWithMigration(db, category, subcategory, params, data, optio
471
484
  if (!documentId) {
472
485
  throw new Error('Collection writes require documentId');
473
486
  }
487
+ // Collection path must have odd number of segments
488
+ const pathSegments = newPath.split('/');
489
+ if (pathSegments.length % 2 === 0) {
490
+ throw new Error(`Path ${newPath} is a document path but isCollection=true was specified`);
491
+ }
474
492
  const newRef = db.collection(newPath).doc(documentId);
475
493
  if (merge) {
476
494
  batch.set(newRef, data, { merge: true });
@@ -478,9 +496,18 @@ async function writeWithMigration(db, category, subcategory, params, data, optio
478
496
  batch.set(newRef, data);
479
497
  }
480
498
  } else {
481
- const newRef = documentId
482
- ? db.collection(newPath).doc(documentId)
483
- : db.doc(newPath);
499
+ // Document path: if documentId provided, newPath should be collection (odd segments)
500
+ // If no documentId, newPath should be full document path (even segments)
501
+ let newRef;
502
+ if (documentId) {
503
+ const pathSegments = newPath.split('/');
504
+ if (pathSegments.length % 2 === 0) {
505
+ throw new Error(`Path ${newPath} is a document path but documentId was provided`);
506
+ }
507
+ newRef = db.collection(newPath).doc(documentId);
508
+ } else {
509
+ newRef = db.doc(newPath);
510
+ }
484
511
  if (merge) {
485
512
  batch.set(newRef, data, { merge: true });
486
513
  } else {
@@ -18,7 +18,7 @@ const { findLatestRankingsDate } = require('./data_lookup_helpers');
18
18
  async function checkIfUserIsPI(db, userCid, config, logger = null) {
19
19
  try {
20
20
  // Check dev override first (for developer accounts)
21
- const { getDevOverride } = require('../dev_helpers');
21
+ const { getDevOverride } = require('../dev/dev_helpers');
22
22
  const devOverride = await getDevOverride(db, userCid, config, logger);
23
23
 
24
24
  if (devOverride && devOverride.enabled && devOverride.pretendToBePI) {
@@ -44,8 +44,33 @@ async function requestPiAddition(req, res, dependencies, config) {
44
44
  .collection('requests')
45
45
  .doc(requestId);
46
46
 
47
+ // Write to global collection
47
48
  await requestRef.set(requestData);
48
49
 
50
+ // Also write to user-centric collection (dual-write)
51
+ const { writeWithMigration } = require('../core/path_resolution_helpers');
52
+ try {
53
+ await writeWithMigration(
54
+ db,
55
+ 'signedInUsers',
56
+ 'piAdditionRequests',
57
+ { cid: userCid },
58
+ requestData,
59
+ {
60
+ isCollection: true,
61
+ merge: false,
62
+ dataType: 'piAdditionRequests',
63
+ config,
64
+ documentId: requestId,
65
+ dualWrite: false, // Don't dual-write to legacy (new feature)
66
+ collectionRegistry: dependencies.collectionRegistry
67
+ }
68
+ );
69
+ } catch (userWriteErr) {
70
+ // Log but don't fail - global write succeeded
71
+ logger.log('WARN', `[requestPiAddition] Failed to write to user-centric collection: ${userWriteErr.message}`);
72
+ }
73
+
49
74
  logger.log('SUCCESS', `[requestPiAddition] User ${userCid} requested addition of PI ${piUsername} (CID: ${piCid || 'unknown'})`);
50
75
 
51
76
  return res.status(201).json({
@@ -36,6 +36,10 @@ async function storeSignedInUserPortfolio({ db, logger, collectionRegistry, cid,
36
36
  }, { merge: false });
37
37
 
38
38
  // 2. Store latest snapshot to user-centric collection (for fallback)
39
+ const { getCollectionPath } = collectionRegistry || {};
40
+ if (!getCollectionPath) {
41
+ throw new Error('collectionRegistry.getCollectionPath is required');
42
+ }
39
43
  const userLatestRef = db.collection(
40
44
  getCollectionPath('signedInUsers', 'portfolio', { cid })
41
45
  ).doc('latest');
@@ -76,6 +80,10 @@ async function storeSignedInUserTradeHistory({ db, logger, collectionRegistry, c
76
80
  }, { merge: false });
77
81
 
78
82
  // 2. Store latest snapshot to user-centric collection (for fallback)
83
+ const { getCollectionPath } = collectionRegistry || {};
84
+ if (!getCollectionPath) {
85
+ throw new Error('collectionRegistry.getCollectionPath is required');
86
+ }
79
87
  const userLatestRef = db.collection(
80
88
  getCollectionPath('signedInUsers', 'tradeHistory', { cid })
81
89
  ).doc('latest');
@@ -124,8 +132,12 @@ async function storeSignedInUserSocialPosts({ db, logger, collectionRegistry, ci
124
132
  }, { merge: false });
125
133
 
126
134
  // 2. Store latest posts to user-centric collection (for fallback)
135
+ const { getCollectionPath } = collectionRegistry || {};
136
+ if (!getCollectionPath) {
137
+ throw new Error('collectionRegistry.getCollectionPath is required');
138
+ }
127
139
  const userPostsRef = db.collection(
128
- getCollectionPath('signedInUsers', 'posts', { cid })
140
+ getCollectionPath('signedInUsers', 'socialPosts', { cid })
129
141
  );
130
142
 
131
143
  // Store each post individually in user-centric collection
@@ -21,7 +21,10 @@ const { shouldTryProxy, recordProxyOutcome, getFailureCount, getMaxFailures } =
21
21
  const {
22
22
  storePopularInvestorPortfolio,
23
23
  storePopularInvestorTradeHistory,
24
- storePopularInvestorSocialPosts
24
+ storePopularInvestorSocialPosts,
25
+ storeSignedInUserPortfolio,
26
+ storeSignedInUserTradeHistory,
27
+ storeSignedInUserSocialPosts
25
28
  } = require('./data_storage_helpers');
26
29
 
27
30
  async function handlePopularInvestorUpdate(taskData, config, dependencies) {
@@ -526,9 +529,10 @@ async function handleOnDemandUserUpdate(taskData, config, dependencies) {
526
529
  // Extract targetCid from metadata if present (for optimization)
527
530
  const targetCid = metadata?.targetCid || cid;
528
531
  const isNewUser = metadata?.isNewUser === true; // Flag for new user signup
532
+ const userType = metadata?.userType || data.userType || 'SIGNED_IN_USER'; // Check if this is a PI or signed-in user
529
533
 
530
534
  // [FIX] Destructure dependencies first
531
- const { logger, proxyManager, batchManager, headerManager, db } = dependencies;
535
+ const { logger, proxyManager, batchManager, headerManager, db, collectionRegistry } = dependencies;
532
536
 
533
537
  // Import notification helper once at the top
534
538
  const { notifyTaskEngineComplete } = require('../../generic-api/user-api/helpers/notification_helpers');
@@ -687,14 +691,26 @@ async function handleOnDemandUserUpdate(taskData, config, dependencies) {
687
691
  portfolioFetched = true;
688
692
 
689
693
  try {
690
- await storeSignedInUserPortfolio({
691
- db,
692
- logger,
693
- collectionRegistry,
694
- cid: String(cid),
695
- date: today,
696
- portfolioData
697
- });
694
+ // Use correct storage function based on user type
695
+ if (userType === 'POPULAR_INVESTOR') {
696
+ await storePopularInvestorPortfolio({
697
+ db,
698
+ logger,
699
+ collectionRegistry,
700
+ cid: String(cid),
701
+ date: today,
702
+ portfolioData
703
+ });
704
+ } else {
705
+ await storeSignedInUserPortfolio({
706
+ db,
707
+ logger,
708
+ collectionRegistry,
709
+ cid: String(cid),
710
+ date: today,
711
+ portfolioData
712
+ });
713
+ }
698
714
  } catch (batchErr) {
699
715
  const errorMsg = `Failed to store portfolio data: ${batchErr.message}`;
700
716
  logger.log('ERROR', `[On-Demand] ${errorMsg}`, batchErr);
@@ -765,14 +781,26 @@ async function handleOnDemandUserUpdate(taskData, config, dependencies) {
765
781
  }
766
782
 
767
783
  try {
768
- await storeSignedInUserTradeHistory({
769
- db,
770
- logger,
771
- collectionRegistry,
772
- cid: String(cid),
773
- date: today,
774
- historyData
775
- });
784
+ // Use correct storage function based on user type
785
+ if (userType === 'POPULAR_INVESTOR') {
786
+ await storePopularInvestorTradeHistory({
787
+ db,
788
+ logger,
789
+ collectionRegistry,
790
+ cid: String(cid),
791
+ date: today,
792
+ historyData
793
+ });
794
+ } else {
795
+ await storeSignedInUserTradeHistory({
796
+ db,
797
+ logger,
798
+ collectionRegistry,
799
+ cid: String(cid),
800
+ date: today,
801
+ historyData
802
+ });
803
+ }
776
804
  historyFetched = true;
777
805
  } catch (batchErr) {
778
806
  const errorMsg = `Failed to store history data: ${batchErr.message}`;
@@ -872,14 +900,26 @@ async function handleOnDemandUserUpdate(taskData, config, dependencies) {
872
900
 
873
901
  // Store posts using new structure
874
902
  if (postsToStore.length > 0) {
875
- await storeSignedInUserSocialPosts({
876
- db,
877
- logger,
878
- collectionRegistry,
879
- cid: String(cid),
880
- date: today,
881
- posts: postsToStore
882
- });
903
+ // Use correct storage function based on user type
904
+ if (userType === 'POPULAR_INVESTOR') {
905
+ await storePopularInvestorSocialPosts({
906
+ db,
907
+ logger,
908
+ collectionRegistry,
909
+ cid: String(cid),
910
+ date: today,
911
+ posts: postsToStore
912
+ });
913
+ } else {
914
+ await storeSignedInUserSocialPosts({
915
+ db,
916
+ logger,
917
+ collectionRegistry,
918
+ cid: String(cid),
919
+ date: today,
920
+ posts: postsToStore
921
+ });
922
+ }
883
923
 
884
924
  // Update date tracking document (for root data indexer)
885
925
  const { getCollectionPath } = collectionRegistry;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulltrackers-module",
3
- "version": "1.0.509",
3
+ "version": "1.0.511",
4
4
  "description": "Helper Functions for Bulltrackers.",
5
5
  "main": "index.js",
6
6
  "files": [