@dhyasama/totem-models 9.51.0 → 9.53.0

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/index.js CHANGED
@@ -57,6 +57,7 @@ var bootstrap = function(mongoose, config) {
57
57
  require('./lib/Investment.js')(mongoose, config);
58
58
  require('./lib/List.js')(mongoose, config);
59
59
  require('./lib/Message.js')(mongoose, config);
60
+ require('./lib/MessageRecipient.js')(mongoose, config);
60
61
  require('./lib/News.js')(mongoose, config);
61
62
  require('./lib/Snapshot.js')(mongoose, config);
62
63
  require('./lib/Sync.js')(mongoose, config);
package/lib/Deal.js CHANGED
@@ -59,7 +59,11 @@ module.exports = function(mongoose, config) {
59
59
  description: { type: String, trim: true, required: true }
60
60
  }],
61
61
 
62
- customFields: { type: Schema.Types.Mixed }
62
+ customFields: { type: Schema.Types.Mixed },
63
+
64
+ latestInteraction: { type: Schema.ObjectId, ref: 'Interaction', required: false },
65
+
66
+ latestMessage: { type: Schema.ObjectId, ref: 'Message', required: false }
63
67
 
64
68
  });
65
69
 
@@ -210,6 +214,16 @@ module.exports = function(mongoose, config) {
210
214
  };
211
215
 
212
216
  let query = self.find(terms);
217
+
218
+ if (options.populate) {
219
+ query.populate({ path: 'documents', match: { customer: options.CUSTOMER_ID } });
220
+ query.populate({ path: 'messages', match: { customer: options.CUSTOMER_ID }, select: '-raw' });
221
+ query.populate('organization', 'name aliases description logoUrl website websiteAliases chairs contact people');
222
+ query.populate('referrer.person', 'name avatarUrl title');
223
+ query.populate('latestInteraction');
224
+ query.populate('latestMessage');
225
+ }
226
+
213
227
  query.exec(cb);
214
228
 
215
229
  };
package/lib/Financials.js CHANGED
@@ -84,6 +84,7 @@ module.exports = function(mongoose, config) {
84
84
  type: { type: String, enum: [null, 'header', 'block', 'document', 'metric', 'question']}
85
85
  }],
86
86
 
87
+ // health block
87
88
  cash: {
88
89
  amount: { type: Number, default: 0 },
89
90
  },
@@ -99,7 +100,7 @@ module.exports = function(mongoose, config) {
99
100
  period: { type: String, enum: [null, 'monthly', 'quarterly', 'yearly']},
100
101
  },
101
102
 
102
- // income statement
103
+ // income statement block
103
104
  revenue: {
104
105
  amount: { type: Number, default: 0 },
105
106
  projected: { type: Number, default: 0 },
@@ -121,7 +122,7 @@ module.exports = function(mongoose, config) {
121
122
  breakdown: { type: Schema.Types.Mixed }
122
123
  },
123
124
 
124
- // balance sheet
125
+ // balance sheet block
125
126
  assets: {
126
127
  amount: { type: Number, default: 0 },
127
128
  breakdown: { type: Schema.Types.Mixed }
@@ -135,7 +136,7 @@ module.exports = function(mongoose, config) {
135
136
  breakdown: { type: Schema.Types.Mixed }
136
137
  },
137
138
 
138
- // cash flow
139
+ // cash flow block
139
140
  operatingActivities: {
140
141
  amount: { type: Number, default: 0 },
141
142
  breakdown: { type: Schema.Types.Mixed }
package/lib/Message.js CHANGED
@@ -30,21 +30,8 @@ module.exports = function(mongoose, config) {
30
30
  },
31
31
  notes: [ { type: Schema.ObjectId, ref: 'Note' } ],
32
32
  documents: [ { type: Schema.ObjectId, ref: 'Document' } ],
33
- raw: { type: Schema.Types.Mixed, required: true }
34
-
35
- });
36
-
37
- ///////////////////////////////////////
38
-
39
- Message.virtual('messageDate').get(function () {
40
-
41
- // A little helper to get the message date since
42
- // the original message date isn't always contained
43
- // in the email. In its absence, use created on.
44
-
45
- const self = this;
46
-
47
- return self.originalMessageDate || self.createdOn;
33
+ raw: { type: Schema.Types.Mixed, required: true },
34
+ messageDate: { type: Date, required: true },
48
35
 
49
36
  });
50
37
 
@@ -242,28 +229,23 @@ module.exports = function(mongoose, config) {
242
229
 
243
230
  const self = this;
244
231
 
232
+ // Must match customer
245
233
  let query = self.find({ customer: options.CUSTOMER_ID });
246
234
 
235
+ // Match either the org or a list of people
247
236
  query.where({ $or: [{organization: orgId}, {'recipients.external': { $in : personIds }}] });
248
237
 
249
- query.exec(function (err, messages) {
238
+ // Optionally limit search space to message newer than some timestamp
239
+ if (options.timestamp) query.where({'messageDate': { $gte: options.timestamp }});
250
240
 
251
- if (err) {
252
- return cb(err, null);
253
- }
254
- else if (!messages) {
255
- return cb(null, null);
256
- }
257
-
258
- messages = _.sortBy(messages, function(message) {
259
- return message.originalMessageDate || message.createdOn;
260
- });
261
-
262
- var message = _.last(messages);
241
+ // Don't need the full raw message
242
+ query.select({ 'raw': -1 });
263
243
 
264
- return cb(null, message);
244
+ // Only need one
245
+ query.sort({ 'messageDate': -1 });
246
+ query.limit(1);
265
247
 
266
- });
248
+ query.exec(cb);
267
249
 
268
250
  };
269
251
 
@@ -409,9 +391,15 @@ module.exports = function(mongoose, config) {
409
391
 
410
392
  const timestamp = new Date();
411
393
 
394
+ // Use now if created on is empty
412
395
  message.createdOn = message.createdOn || timestamp;
396
+
397
+ // Updated on is always now
413
398
  message.updatedOn = timestamp;
414
399
 
400
+ // The original message date isn't always contained in the email. In its absence, use created on.
401
+ message.messageDate = message.messageDate || message.originalMessageDate || message.createdOn;
402
+
415
403
  message.save(cb);
416
404
 
417
405
  };
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+
3
+ module.exports = function(mongoose, config) {
4
+
5
+ let Schema = mongoose.Schema;
6
+
7
+ let MessageRecipient = new Schema({
8
+
9
+ message: { type: Schema.ObjectId, ref: 'Message', required: true },
10
+ customer: { type: Schema.ObjectId, ref: 'Organization', required: true },
11
+ organization: { type: Schema.ObjectId, ref: 'Organization', required: true },
12
+ recipient: { type: Schema.ObjectId, ref: 'Person', required: true },
13
+ messageDate: { type: Date, required: true },
14
+
15
+ });
16
+
17
+ ///////////////////////////////////////
18
+
19
+ MessageRecipient.statics.getMostRecent = function getMostRecent(orgId, customerId, personId, options, cb) {
20
+
21
+ if (!cb) { throw new Error('cb is required'); }
22
+ if (!orgId) { return cb(new Error('orgId is required'), null); }
23
+ if (!mongoose.Types.ObjectId.isValid(orgId)) { return cb(new Error('orgId is not a valid ObjectId'), null); }
24
+ if (!customerId) { return cb(new Error('customerId is required'), null); }
25
+ if (!mongoose.Types.ObjectId.isValid(customerId)) { return cb(new Error('customerId is not a valid ObjectId'), null); }
26
+ if (!personId) { return cb(new Error('personId is required'), null); }
27
+ if (!mongoose.Types.ObjectId.isValid(personId)) { return cb(new Error('personId is not a valid ObjectId'), null); }
28
+
29
+ const self = this;
30
+
31
+ options = options || {};
32
+
33
+ let query = self.find({
34
+ customer: options.CUSTOMER_ID,
35
+ organization: orgId,
36
+ recipient: personId
37
+ });
38
+
39
+ // Optionally limit search space to message newer than some timestamp
40
+ if (options.timestamp) query.where({'messageDate': { $gte: options.timestamp }});
41
+
42
+ // Only need one
43
+ query.sort({ 'messageDate': -1 });
44
+ query.limit(1);
45
+
46
+ query.exec(cb);
47
+
48
+ };
49
+
50
+ MessageRecipient.statics.getMostRecentBatch = function getMostRecentBatch(orgId, customerId, personIds, options, cb) {
51
+
52
+ if (!cb) { throw new Error('cb is required'); }
53
+ if (!orgId) { return cb(new Error('orgId is required'), null); }
54
+ if (!mongoose.Types.ObjectId.isValid(orgId)) { return cb(new Error('orgId is not a valid ObjectId'), null); }
55
+ if (!customerId) { return cb(new Error('customerId is required'), null); }
56
+ if (!mongoose.Types.ObjectId.isValid(customerId)) { return cb(new Error('customerId is not a valid ObjectId'), null); }
57
+ if (!personIds) { return cb(new Error('personIds is required'), null); }
58
+ if (!Array.isArray(personIds)) { return cb(new Error('personIds must be an array'), null); }
59
+
60
+ const self = this;
61
+
62
+ options = options || {};
63
+
64
+ let query = self.find({
65
+ customer: options.CUSTOMER_ID,
66
+ organization: orgId
67
+ });
68
+
69
+ query.where({ 'recipient': { $in : personIds }});
70
+
71
+ // Optionally limit search space to message newer than some timestamp
72
+ if (options.timestamp) query.where({'messageDate': { $gte: options.timestamp }});
73
+
74
+ // Only need one
75
+ query.sort({ 'messageDate': -1 });
76
+ query.limit(1);
77
+
78
+ query.exec(cb);
79
+
80
+ };
81
+
82
+ MessageRecipient.statics.upsert = function(message, cb) {
83
+ message.save(cb);
84
+ };
85
+
86
+ ///////////////////////////////////////
87
+
88
+ mongoose.model('MessageRecipient', MessageRecipient);
89
+
90
+ };
package/lib/Round.js CHANGED
@@ -29,14 +29,6 @@ module.exports = function(mongoose, config) {
29
29
 
30
30
  roundName: { type: String, trim: true, required: true },
31
31
 
32
- // People that participated in this round
33
- // This is a public list of people that invested
34
- // Use the addPerson method and removePerson static
35
- people: [{
36
- person: { type: Schema.ObjectId, ref: 'Person', index: true },
37
- _id: false
38
- }],
39
-
40
32
  // Investment vehicles that participated in this round
41
33
  // Currently only funds. May expand to SPVs.
42
34
  // Recall that a fund belongs to an organization
@@ -146,15 +138,11 @@ module.exports = function(mongoose, config) {
146
138
  // Fuck shit up so it gets taken care of
147
139
 
148
140
  var vehicles = _.compact(_.flatten(_.pluck(rounds, 'vehicles')));
149
- var people = _.compact(_.flatten(_.pluck(rounds, 'people')));
150
141
  var badData = null;
151
142
 
152
143
  badData = _.find(rounds, function(item) { return !item.organization; });
153
144
  if (badData) return new Error(fnName + ' has one or more orgs that is not populated which means there is bad data');
154
145
 
155
- badData = _.find(people, function(p) { return !p.person; });
156
- if (badData) return new Error(fnName + ' has one or more people that is not populated which means there is bad data');
157
-
158
146
  badData = _.find(vehicles, function(item) { return !item.fund; });
159
147
  if (badData) return new Error(fnName + ' has one or more funds that is not populated which means there is bad data');
160
148
 
@@ -244,34 +232,6 @@ module.exports = function(mongoose, config) {
244
232
 
245
233
  };
246
234
 
247
- Round.methods.addPerson = function addPerson(person) {
248
-
249
- // Add a reference to a person that participated in this round
250
-
251
- var self = this;
252
-
253
- if (!person) throw new Error('Must supply person to add');
254
-
255
- // Do our best to accept an object or an objectid
256
- if (!mongoose.Types.ObjectId.isValid(person)) {
257
- person = person._id;
258
- if (!mongoose.Types.ObjectId.isValid(person)) throw new Error('Need a valid objectid!');
259
- }
260
-
261
- // Check if person is already added
262
- var match = _.find(self.people, function(existingPerson) {
263
- var p = existingPerson.person || existingPerson;
264
- var id = mongoose.Types.ObjectId.isValid(p) ? p : p._id;
265
- return id.toString() === person.toString();
266
- });
267
-
268
- // If not, add it
269
- if (!match) self.people.push({
270
- person: person
271
- });
272
-
273
- };
274
-
275
235
  Round.methods.addVehicle = function addVehicle(fund) {
276
236
 
277
237
  // Add a vehicle, which is a fund
@@ -338,7 +298,6 @@ module.exports = function(mongoose, config) {
338
298
  });
339
299
 
340
300
  query.populate('organization', 'name logoUrl website websiteAliases');
341
- query.populate('people.person', 'name avatarUrl title');
342
301
  query.populate('vehicles.fund', 'name shortName');
343
302
 
344
303
  if (options.isWorkerProcess) {
@@ -399,7 +358,6 @@ module.exports = function(mongoose, config) {
399
358
  });
400
359
 
401
360
  query.populate('organization', 'name logoUrl website websiteAliases');
402
- query.populate('people.person', 'name avatarUrl');
403
361
  query.populate('vehicles.fund');
404
362
 
405
363
  if (options.isWorkerProcess) {
@@ -646,40 +604,6 @@ module.exports = function(mongoose, config) {
646
604
 
647
605
  };
648
606
 
649
- Round.statics.getPortfolioByPerson = function getPortfolioByPerson(personId, options, cb) {
650
-
651
- // Returns a list of orgs that have rounds participated in by the given person id
652
-
653
- if (!cb) { throw new Error('cb is required'); }
654
- if (!personId) { throw new Error('personId is required'); }
655
- if (!mongoose.Types.ObjectId.isValid(personId)) { return cb(new Error('personId is not a valid ObjectId'), null); }
656
-
657
- const self = this;
658
-
659
- let query = self.find({ 'people.person': personId });
660
-
661
- query.select('organization');
662
- query.populate('organization', 'name logoUrl description website websiteAliases');
663
-
664
- query.exec(function(err, rounds) {
665
-
666
- if (err) return cb(err, null);
667
- if (!rounds || rounds.length === 0) return cb(null, []);
668
-
669
- let error = checkForUnpopulatedData(rounds, 'Round.getPortfolioByPerson');
670
- if (error) return cb(error, null);
671
-
672
- // Return a list of orgs, not a list of rounds
673
- let portfolio = _.pluck(rounds, 'organization');
674
- portfolio = _.uniq(portfolio, function(org) { return org.name; });
675
- portfolio = _.sortBy(portfolio, 'name');
676
-
677
- return cb(null, portfolio);
678
-
679
- });
680
-
681
- };
682
-
683
607
  Round.statics.removeInvestment = function(investmentId, cb) {
684
608
 
685
609
  // Do not call this directly. It will leave an orphaned investment document.
@@ -714,20 +638,6 @@ module.exports = function(mongoose, config) {
714
638
 
715
639
  };
716
640
 
717
- Round.statics.removePerson = function(roundId, personId, cb) {
718
-
719
- const self = this;
720
-
721
- self
722
- .findOneAndUpdate(
723
- { '_id': roundId },
724
- { $pull : { 'people': { 'person': personId } } },
725
- { multi : false }
726
- )
727
- .exec(cb);
728
-
729
- };
730
-
731
641
  Round.statics.removeVehicle = function(roundId, fundId, cb) {
732
642
 
733
643
  const self = this;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dhyasama/totem-models",
3
- "version": "9.51.0",
3
+ "version": "9.53.0",
4
4
  "author": "Jason Reynolds",
5
5
  "license": "UNLICENSED",
6
6
  "description": "Models for Totem platform",
@@ -16,6 +16,7 @@
16
16
  },
17
17
  "dependencies": {
18
18
  "@dhyasama/totem-utilities": "^3.0.0",
19
+ "algoliasearch": "^4.13.0",
19
20
  "async": "^2.6.3",
20
21
  "awesome-phonenumber": "^1.0.14",
21
22
  "bluebird": "^3.7.2",