@dhyasama/totem-models 1.0.1 → 1.6.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 +18 -6
- package/lib/Account.js +13 -50
- package/lib/CapTable.js +397 -0
- package/lib/Fund.js +56 -12
- package/lib/Investment.js +143 -0
- package/lib/LimitedPartner.js +0 -10
- package/lib/News.js +4 -0
- package/lib/Organization.js +570 -391
- package/lib/Person.js +47 -62
- package/lib/Round.js +805 -0
- package/package.json +4 -3
- package/test/CapTable.js +359 -0
- package/test/Investment.js +180 -0
- package/test/Organization.js +99 -2
- package/test/Person.js +0 -48
- package/test/Round.js +684 -0
package/lib/Organization.js
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
module.exports = function(mongoose, config) {
|
|
4
4
|
|
|
5
|
-
var LPS_ENABLED = config.LPS_ENABLED || false;
|
|
6
|
-
|
|
7
5
|
var
|
|
8
6
|
|
|
9
7
|
_ = require('underscore'),
|
|
@@ -12,6 +10,8 @@ module.exports = function(mongoose, config) {
|
|
|
12
10
|
Schema = mongoose.Schema,
|
|
13
11
|
Note = mongoose.model('Note'),
|
|
14
12
|
|
|
13
|
+
customerPortfolio = [],
|
|
14
|
+
|
|
15
15
|
Organization = new Schema({
|
|
16
16
|
|
|
17
17
|
name: { type: String, required: true, index: true },
|
|
@@ -64,6 +64,7 @@ module.exports = function(mongoose, config) {
|
|
|
64
64
|
title: { type: String, default: null, trim: true },
|
|
65
65
|
current: { type: Boolean, default: false, index: true },
|
|
66
66
|
leader: { type: Boolean, default: false, index: true },
|
|
67
|
+
public: { type: Boolean, default: true },
|
|
67
68
|
board: { type: String, enum: ['chairman', 'director', 'observer', 'none'], default: 'none', index: true }
|
|
68
69
|
}],
|
|
69
70
|
|
|
@@ -114,10 +115,6 @@ module.exports = function(mongoose, config) {
|
|
|
114
115
|
url: { type: String, unique: true, sparse: true, trim: true }
|
|
115
116
|
},
|
|
116
117
|
|
|
117
|
-
eshares: {
|
|
118
|
-
companyid: { type: String, unique: true, sparse: true, trim: true }
|
|
119
|
-
},
|
|
120
|
-
|
|
121
118
|
related: [{ type: Schema.ObjectId, ref: 'Organization' }],
|
|
122
119
|
|
|
123
120
|
// customer specific (customer id is stored on note)
|
|
@@ -172,171 +169,238 @@ module.exports = function(mongoose, config) {
|
|
|
172
169
|
// Funds belonging to this organization (which is typically, but not necessarily, what we'd call an investor)
|
|
173
170
|
// An example of a non-"investor" with funds would be Slack with it's Slack Fund
|
|
174
171
|
// Another way to put it, these are funds from which this organization makes investments
|
|
175
|
-
funds: [{ type: Schema.ObjectId, ref: 'Fund' }]
|
|
172
|
+
funds: [{ type: Schema.ObjectId, ref: 'Fund' }]
|
|
176
173
|
|
|
177
|
-
|
|
178
|
-
capTable: [{
|
|
174
|
+
});
|
|
179
175
|
|
|
180
|
-
customer: { type: Schema.ObjectId, ref: 'Organization', required: true },
|
|
181
|
-
shares: { type: Number, default: 0 },
|
|
182
|
-
fullyDiluted: { type: Number, default: 0 },
|
|
183
|
-
asOfDate: { type: Date },
|
|
184
176
|
|
|
185
|
-
// todo - ??? - clarify how to handle this
|
|
186
|
-
optionsAndWarrants: {
|
|
187
|
-
unissued: { type: Number },
|
|
188
|
-
issuedToUnspecified: { type: Number }
|
|
189
|
-
}
|
|
190
177
|
|
|
191
|
-
|
|
178
|
+
///////////////////////////////////////////////////////////////////////////////////////
|
|
179
|
+
// HELPERS
|
|
180
|
+
///////////////////////////////////////////////////////////////////////////////////////
|
|
192
181
|
|
|
193
|
-
|
|
194
|
-
rounds: [{
|
|
182
|
+
var getSources = function getSources(people) {
|
|
195
183
|
|
|
196
|
-
|
|
184
|
+
var result = _.compact(_.pluck(people, 'person'));
|
|
185
|
+
if (result.length == 0) return [];
|
|
197
186
|
|
|
198
|
-
|
|
199
|
-
|
|
187
|
+
result = _.compact(_.pluck(result, 'sources'));
|
|
188
|
+
if (result.length == 0) return [];
|
|
200
189
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
amountRaised: { type: Number, default: 0 },
|
|
204
|
-
closingDate: { type: Date, default: null },
|
|
190
|
+
result = _.flatten(result);
|
|
191
|
+
result = _.compact(result);
|
|
205
192
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
// This is a public list of funds/orgs that invested
|
|
209
|
-
funds: [{
|
|
193
|
+
if (result.length == 0) return [];
|
|
194
|
+
if (mongoose.Types.ObjectId.isValid(result[0].person)) return []; // not populated
|
|
210
195
|
|
|
211
|
-
|
|
196
|
+
result = _.uniq(result, function(item) { return item.person._id.toString(); });
|
|
197
|
+
result = _.sortBy(result, 'interactions.count');
|
|
198
|
+
result.reverse();
|
|
199
|
+
result = _.sortBy(result, 'name.full');
|
|
212
200
|
|
|
213
|
-
|
|
214
|
-
partner: { type: Schema.ObjectId, ref: 'Person', required: false },
|
|
201
|
+
return result;
|
|
215
202
|
|
|
216
|
-
|
|
217
|
-
// include because it makes filtering investments data, which is private, much easier
|
|
218
|
-
customer: { type: Schema.ObjectId, ref: 'Organization', required: false },
|
|
203
|
+
};
|
|
219
204
|
|
|
220
|
-
// Investments in this round from this fund
|
|
221
|
-
// this is all private data
|
|
222
|
-
investments: [{
|
|
223
205
|
|
|
224
|
-
amount: { type: Number, default: 0 },
|
|
225
|
-
date: { type: Date, default: null },
|
|
226
|
-
lead: { type: Boolean, default: false },
|
|
227
|
-
participatingPreferred: { type: Boolean, default: false },
|
|
228
|
-
pricePerShare: { type: Number, default: 0 },
|
|
229
|
-
fairMarketValue: { type: Number, default: 0 },
|
|
230
|
-
notes: { type: String, trim: true, default: null },
|
|
231
206
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
closingDate: { type: Date, default: null },
|
|
207
|
+
///////////////////////////////////////////////////////////////////////////////////////
|
|
208
|
+
// VIRTUALS
|
|
209
|
+
// Properties that are not persisted to the database
|
|
210
|
+
///////////////////////////////////////////////////////////////////////////////////////
|
|
237
211
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
notes: { type: String, trim: true, default: null }
|
|
245
|
-
}]
|
|
212
|
+
Organization.virtual('address.primary').get(function () {
|
|
213
|
+
var primary = _.find(this.contact.address, function(address) {
|
|
214
|
+
return address.primary;
|
|
215
|
+
});
|
|
216
|
+
return primary ? primary.address : null;
|
|
217
|
+
});
|
|
246
218
|
|
|
247
|
-
|
|
219
|
+
Organization.virtual('board.all').get(function () {
|
|
248
220
|
|
|
249
|
-
|
|
221
|
+
var self = this;
|
|
222
|
+
var members = [];
|
|
250
223
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
}]
|
|
224
|
+
_.each(self.people, function(p) {
|
|
225
|
+
var boardRole = p.board;
|
|
226
|
+
if (boardRole && boardRole != 'none') members.push(p.person);
|
|
227
|
+
});
|
|
256
228
|
|
|
257
|
-
|
|
229
|
+
members = _.sortBy(members, function(member) {
|
|
230
|
+
if (!member || !member.name) return null;
|
|
231
|
+
return member.name.last + member.name.first;
|
|
232
|
+
});
|
|
258
233
|
|
|
234
|
+
return members;
|
|
235
|
+
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
Organization.virtual('board.current').get(function () {
|
|
239
|
+
|
|
240
|
+
var self = this;
|
|
241
|
+
var members = [];
|
|
242
|
+
|
|
243
|
+
_.each(self.people, function(p) {
|
|
244
|
+
var boardRole = p.board;
|
|
245
|
+
if (p.current && boardRole && boardRole != 'none') members.push(p.person);
|
|
259
246
|
});
|
|
260
247
|
|
|
261
|
-
|
|
248
|
+
members = _.sortBy(members, function(member) {
|
|
249
|
+
if (!member || !member.name) return null;
|
|
250
|
+
return member.name.last + member.name.first;
|
|
251
|
+
});
|
|
262
252
|
|
|
263
|
-
|
|
253
|
+
return members;
|
|
254
|
+
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
Organization.virtual('board.past').get(function () {
|
|
264
258
|
|
|
265
259
|
var self = this;
|
|
260
|
+
var members = [];
|
|
266
261
|
|
|
267
|
-
|
|
262
|
+
_.each(self.people, function(p) {
|
|
263
|
+
var boardRole = p.board;
|
|
264
|
+
if (!p.current && boardRole && boardRole != 'none') members.push(p.person);
|
|
265
|
+
});
|
|
268
266
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
267
|
+
members = _.sortBy(members, function(member) {
|
|
268
|
+
if (!member || !member.name) return null;
|
|
269
|
+
return member.name.last + member.name.first;
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
return members;
|
|
273
273
|
|
|
274
274
|
});
|
|
275
275
|
|
|
276
|
-
Organization.virtual('
|
|
277
|
-
|
|
278
|
-
|
|
276
|
+
Organization.virtual('employees.all').get(function () {
|
|
277
|
+
|
|
278
|
+
var self = this;
|
|
279
|
+
var result = [];
|
|
280
|
+
|
|
281
|
+
_.each(self.people, function(p) {
|
|
282
|
+
if (!p.leader && (!p.board || p.board == 'none')) result.push(p);
|
|
279
283
|
});
|
|
280
|
-
|
|
284
|
+
|
|
285
|
+
result = _.sortBy(result, function(item) {
|
|
286
|
+
if (!item.person || !item.person.name) return null;
|
|
287
|
+
return item.person.name.last + item.person.name.first;
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
return result;
|
|
291
|
+
|
|
281
292
|
});
|
|
282
293
|
|
|
283
|
-
Organization.virtual('
|
|
294
|
+
Organization.virtual('employees.current').get(function () {
|
|
295
|
+
|
|
296
|
+
var self = this;
|
|
297
|
+
var result = [];
|
|
298
|
+
|
|
299
|
+
_.each(self.people, function(p) {
|
|
300
|
+
if (p.current && !p.leader && (!p.board || p.board == 'none')) result.push(p);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
result = _.sortBy(result, function(item) {
|
|
304
|
+
if (!item.person || !item.person.name) return null;
|
|
305
|
+
return item.person.name.last + item.person.name.first;
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
return result;
|
|
309
|
+
|
|
310
|
+
});
|
|
284
311
|
|
|
285
|
-
|
|
286
|
-
// Sort by interactions descending, full name ascending
|
|
312
|
+
Organization.virtual('employees.past').get(function () {
|
|
287
313
|
|
|
288
314
|
var self = this;
|
|
315
|
+
var result = [];
|
|
289
316
|
|
|
290
|
-
|
|
291
|
-
|
|
317
|
+
_.each(self.people, function(p) {
|
|
318
|
+
if (!p.current && !p.leader && (!p.board || p.board == 'none')) result.push(p);
|
|
319
|
+
});
|
|
292
320
|
|
|
293
|
-
result = _.
|
|
294
|
-
|
|
321
|
+
result = _.sortBy(result, function(item) {
|
|
322
|
+
if (!item.person || !item.person.name) return null;
|
|
323
|
+
return item.person.name.last + item.person.name.first;
|
|
324
|
+
});
|
|
295
325
|
|
|
296
|
-
|
|
297
|
-
result = _.compact(result);
|
|
326
|
+
return result;
|
|
298
327
|
|
|
299
|
-
|
|
300
|
-
if (mongoose.Types.ObjectId.isValid(result[0].person)) return []; // not populated
|
|
328
|
+
});
|
|
301
329
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
result =
|
|
330
|
+
Organization.virtual('leaders.all').get(function () {
|
|
331
|
+
|
|
332
|
+
var self = this;
|
|
333
|
+
var result = [];
|
|
334
|
+
|
|
335
|
+
_.each(self.people, function(p) {
|
|
336
|
+
if (p.leader) result.push(p);
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
result = _.sortBy(result, function(item) {
|
|
340
|
+
if (!item.person || !item.person.name) return null;
|
|
341
|
+
return item.person.name.last + item.person.name.first;
|
|
342
|
+
});
|
|
306
343
|
|
|
307
344
|
return result;
|
|
308
345
|
|
|
309
346
|
});
|
|
310
347
|
|
|
311
|
-
|
|
348
|
+
Organization.virtual('leaders.current').get(function () {
|
|
312
349
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
this.merged.push(id);
|
|
316
|
-
return true;
|
|
317
|
-
}
|
|
318
|
-
else {
|
|
319
|
-
return false;
|
|
320
|
-
}
|
|
321
|
-
};
|
|
350
|
+
var self = this;
|
|
351
|
+
var result = [];
|
|
322
352
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
};
|
|
353
|
+
_.each(self.people, function(p) {
|
|
354
|
+
if (p.leader && p.current) result.push(p);
|
|
355
|
+
});
|
|
327
356
|
|
|
328
|
-
|
|
357
|
+
result = _.sortBy(result, function(item) {
|
|
358
|
+
if (!item.person || !item.person.name) return null;
|
|
359
|
+
return item.person.name.last + item.person.name.first;
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
return result;
|
|
363
|
+
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
Organization.virtual('leaders.past').get(function () {
|
|
329
367
|
|
|
330
368
|
var self = this;
|
|
369
|
+
var result = [];
|
|
331
370
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
return orgId.toString() == id.toString();
|
|
371
|
+
_.each(self.people, function(p) {
|
|
372
|
+
if (p.leader && !p.current) result.push(p);
|
|
335
373
|
});
|
|
336
374
|
|
|
337
|
-
|
|
375
|
+
result = _.sortBy(result, function(item) {
|
|
376
|
+
if (!item.person || !item.person.name) return null;
|
|
377
|
+
return item.person.name.last + item.person.name.first;
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
return result;
|
|
381
|
+
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
Organization.virtual('status').get(function () {
|
|
385
|
+
|
|
386
|
+
var self = this;
|
|
387
|
+
|
|
388
|
+
// infer from data
|
|
389
|
+
|
|
390
|
+
if (self.closedOn) return 'Dead';
|
|
391
|
+
else if (self.ipo && self.ipo.year) return 'IPO';
|
|
392
|
+
else if (self.acquisition && self.acquisition.year) return 'Acquired';
|
|
393
|
+
else return 'Active';
|
|
394
|
+
|
|
395
|
+
});
|
|
396
|
+
|
|
338
397
|
|
|
339
|
-
|
|
398
|
+
|
|
399
|
+
///////////////////////////////////////////////////////////////////////////////////////
|
|
400
|
+
// METHODS
|
|
401
|
+
// Methods operate on a single document that has already been returned
|
|
402
|
+
// Note that running a method on a document does not save it
|
|
403
|
+
///////////////////////////////////////////////////////////////////////////////////////
|
|
340
404
|
|
|
341
405
|
Organization.methods.addPerson = function(personToAdd) {
|
|
342
406
|
|
|
@@ -358,165 +422,149 @@ module.exports = function(mongoose, config) {
|
|
|
358
422
|
|
|
359
423
|
};
|
|
360
424
|
|
|
361
|
-
Organization.methods.
|
|
362
|
-
|
|
363
|
-
this.
|
|
364
|
-
var id = utils.isValidObjectId(existingPerson.person) ? existingPerson.person : existingPerson.person._id;
|
|
365
|
-
return id.toString() == personIdToRemove.toString();
|
|
366
|
-
});
|
|
367
|
-
|
|
425
|
+
Organization.methods.deleteOrg = function() {
|
|
426
|
+
// Soft delete
|
|
427
|
+
this.deleted = true;
|
|
368
428
|
};
|
|
369
429
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
// fuzzy: searches within strings, e.g., searching for "venture" will match "ff Venture Capital"
|
|
380
|
-
// non-fuzzy does a full-string match, e.g., "ffvc" will match "ffvc" but "ff" will not
|
|
381
|
-
// both fuzzy and non are case-insensitive
|
|
382
|
-
// queryFirstWord: tokenizes first word and searches for it
|
|
383
|
-
// removeRelatedFromTopLevel: related people are removed from top-level results
|
|
384
|
-
Organization.statics.search = function search(data, options, cb) {
|
|
430
|
+
Organization.methods.merge = function(id) {
|
|
431
|
+
if (this.merged.indexOf(id) == -1) {
|
|
432
|
+
this.merged.push(id);
|
|
433
|
+
return true;
|
|
434
|
+
}
|
|
435
|
+
else {
|
|
436
|
+
return false;
|
|
437
|
+
}
|
|
438
|
+
};
|
|
385
439
|
|
|
386
|
-
|
|
387
|
-
if (!cb) throw new Error('cb is required');
|
|
388
|
-
if (!data || (!data.name && !data.domain)) return cb(null, []);
|
|
440
|
+
Organization.methods.relateOrg = function(id) {
|
|
389
441
|
|
|
390
|
-
var
|
|
391
|
-
fuzzy: true,
|
|
392
|
-
queryFirstWord: false,
|
|
393
|
-
removeRelatedFromTopLevel: true
|
|
394
|
-
};
|
|
442
|
+
var self = this;
|
|
395
443
|
|
|
396
|
-
|
|
397
|
-
|
|
444
|
+
var match = _.find(self.related, function(org) {
|
|
445
|
+
var orgId = utils.isValidObjectId(org) ? org : org.id;
|
|
446
|
+
return orgId.toString() == id.toString();
|
|
447
|
+
});
|
|
398
448
|
|
|
399
|
-
|
|
400
|
-
if (!options.admin && !options.investor) return cb(null, []);
|
|
449
|
+
if (!match) { self.related.push(id); }
|
|
401
450
|
|
|
402
|
-
|
|
403
|
-
data.domain = data.domain || '';
|
|
451
|
+
};
|
|
404
452
|
|
|
405
|
-
|
|
453
|
+
Organization.methods.removePerson = function(personIdToRemove) {
|
|
406
454
|
|
|
407
|
-
|
|
408
|
-
|
|
455
|
+
this.people = _.reject(this.people, function(existingPerson) {
|
|
456
|
+
var id = utils.isValidObjectId(existingPerson.person) ? existingPerson.person : existingPerson.person._id;
|
|
457
|
+
return id.toString() == personIdToRemove.toString();
|
|
458
|
+
});
|
|
409
459
|
|
|
410
|
-
|
|
460
|
+
};
|
|
411
461
|
|
|
412
|
-
var result = [];
|
|
413
462
|
|
|
414
|
-
_.each(items, function(item) {
|
|
415
|
-
if (item.related && item.related.length >= 1) {
|
|
416
|
-
var ids = _.pluck(item.related, 'id');
|
|
417
|
-
result = result.concat(ids);
|
|
418
|
-
}
|
|
419
|
-
});
|
|
420
463
|
|
|
421
|
-
|
|
464
|
+
//////////////////////////////////////////////////////
|
|
465
|
+
// STATICS
|
|
466
|
+
// Statics query the entire collection
|
|
467
|
+
//////////////////////////////////////////////////////
|
|
422
468
|
|
|
423
|
-
|
|
469
|
+
Organization.statics.addNote = function(organizationId, creatorPersonId, text, cb) {
|
|
424
470
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
471
|
+
Note.createForModel({
|
|
472
|
+
createdBy: creatorPersonId,
|
|
473
|
+
text: text
|
|
474
|
+
}, this, organizationId, cb);
|
|
429
475
|
|
|
430
|
-
|
|
476
|
+
};
|
|
431
477
|
|
|
432
|
-
|
|
478
|
+
Organization.statics.deleteNote = function(noteId, cb) {
|
|
433
479
|
|
|
434
|
-
//
|
|
435
|
-
// but effective technique as the first word is commonly the most important
|
|
436
|
-
var tokenizeName = function tokenizeName(name, query) {
|
|
480
|
+
// Delete the note itself along with any references
|
|
437
481
|
|
|
438
|
-
|
|
439
|
-
if (!query) throw new Error('query is required');
|
|
482
|
+
var self = this;
|
|
440
483
|
|
|
441
|
-
|
|
484
|
+
var removeReferences = function removeReferences(callback) {
|
|
485
|
+
self.update({}, {
|
|
486
|
+
$pull: { 'notes' : [noteId] }
|
|
487
|
+
}, callback);
|
|
488
|
+
};
|
|
442
489
|
|
|
443
|
-
|
|
444
|
-
|
|
490
|
+
async.series([
|
|
491
|
+
Note.delete.bind(Note, noteId),
|
|
492
|
+
removeReferences
|
|
493
|
+
], function(err, results) {
|
|
494
|
+
return cb(err, null);
|
|
495
|
+
});
|
|
445
496
|
|
|
446
|
-
|
|
447
|
-
if (parts.length >= 2) {
|
|
448
|
-
query['$or'].push({ 'name': new RegExp(parts[0], 'i') });
|
|
449
|
-
}
|
|
497
|
+
};
|
|
450
498
|
|
|
451
|
-
|
|
499
|
+
Organization.statics.findByDomains = function findByDomains(domains, cb) {
|
|
500
|
+
var query = this.find({ $or: [ {'website': { $in : domains }}, {'websiteAliases': { $in : domains }} ], 'deleted': {$ne: true} });
|
|
501
|
+
query.exec(cb);
|
|
502
|
+
};
|
|
452
503
|
|
|
453
|
-
|
|
504
|
+
Organization.statics.findByFunds = function findByFunds(fundids, cb) {
|
|
505
|
+
var self = this;
|
|
506
|
+
self
|
|
507
|
+
.find({ 'funds': { $in : fundids }, 'deleted': {$ne: true} })
|
|
508
|
+
.select('name logoUrl')
|
|
509
|
+
.exec(cb);
|
|
510
|
+
};
|
|
454
511
|
|
|
455
|
-
|
|
456
|
-
var query = {};
|
|
457
|
-
query['$or'] = []; // these will be added dynamically from data parameter
|
|
458
|
-
query['$and'] = []; // these will be added dynamically from data parameter
|
|
459
|
-
query['deleted'] = { $ne: true }; // always include this
|
|
512
|
+
Organization.statics.findByIds = function findByIds(ids, cb) {
|
|
460
513
|
|
|
461
|
-
|
|
462
|
-
if (data.name) {
|
|
514
|
+
var self = this;
|
|
463
515
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
516
|
+
self
|
|
517
|
+
.find({ '_id': { $in : ids }})
|
|
518
|
+
.populate('people.person', 'name avatarUrl title calendarEventSummaries sources')
|
|
519
|
+
.populate('related', 'name logoUrl')
|
|
520
|
+
.populate('notes')
|
|
521
|
+
.populate('chairs.first', 'name avatarUrl title')
|
|
522
|
+
.populate('chairs.second', 'name avatarUrl title')
|
|
523
|
+
.populate('funds', 'name hexColorCode')
|
|
524
|
+
.deepPopulate([
|
|
525
|
+
'people.person.sources.person',
|
|
526
|
+
'people.person.calendarEventSummaries.attendees.internal',
|
|
527
|
+
'people.person.calendarEventSummaries.attendees.external',
|
|
528
|
+
'people.person.calendarEventSummaries.notes.createdBy',
|
|
529
|
+
'notes.createdBy'
|
|
530
|
+
], {
|
|
531
|
+
populate: {
|
|
532
|
+
'people.person.sources.person': { select: 'name avatarUrl title' },
|
|
533
|
+
'people.person.calendarEventSummaries.attendees.internal': { select: 'name avatarUrl title' },
|
|
534
|
+
'people.person.calendarEventSummaries.attendees.external': { select: 'name avatarUrl title' },
|
|
535
|
+
'people.person.calendarEventSummaries.notes.createdBy': { select: 'name avatarUrl title' },
|
|
536
|
+
'notes.createdBy': { select: 'name avatarUrl title' }
|
|
475
537
|
}
|
|
538
|
+
})
|
|
539
|
+
.exec(cb);
|
|
476
540
|
|
|
477
|
-
|
|
478
|
-
query['$or'].push({ 'aliases': aliasRegExp });
|
|
479
|
-
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
// conditionally include domain
|
|
483
|
-
if (data.domain) {
|
|
484
|
-
var domainRegExp = options.fuzzy ? new RegExp(data.domain, 'i') : new RegExp('^' + data.domain + '$', 'i');
|
|
485
|
-
query['$or'].push({ 'website': domainRegExp });
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
// remove if unused
|
|
489
|
-
if (query['$or'].length == 0) delete query['$or'];
|
|
490
|
-
if (query['$and'].length == 0) delete query['$and'];
|
|
491
|
-
|
|
492
|
-
return query;
|
|
493
|
-
|
|
494
|
-
};
|
|
495
|
-
|
|
496
|
-
var query = buildQuery(data, options);
|
|
497
|
-
|
|
498
|
-
this
|
|
499
|
-
.find(query)
|
|
500
|
-
.populate('merged')
|
|
501
|
-
.select('logoUrl name description related')
|
|
502
|
-
.exec(function(err, orgs) {
|
|
541
|
+
};
|
|
503
542
|
|
|
504
|
-
|
|
505
|
-
else if (!orgs) return cb(null, null);
|
|
506
|
-
else {
|
|
543
|
+
Organization.statics.findByPerson = function findByPerson(personId, cb) {
|
|
507
544
|
|
|
508
|
-
|
|
509
|
-
if (options.removeRelatedFromTopLevel) orgs = removeRelatedFromTopLevel(orgs);
|
|
545
|
+
// Given a person id, get all organizations with that person
|
|
510
546
|
|
|
511
|
-
|
|
512
|
-
orgs = _.sortBy(orgs, function(orgs) { return orgs.name; });
|
|
547
|
+
var self = this;
|
|
513
548
|
|
|
514
|
-
|
|
549
|
+
self
|
|
550
|
+
.find({ $or:
|
|
551
|
+
[
|
|
552
|
+
{ 'people.person': personId },
|
|
553
|
+
{ 'chairs.first': personId },
|
|
554
|
+
{ 'chairs.second': personId }
|
|
555
|
+
],
|
|
556
|
+
'deleted': { $ne: true }
|
|
557
|
+
})
|
|
558
|
+
.exec(cb);
|
|
515
559
|
|
|
516
|
-
|
|
560
|
+
};
|
|
517
561
|
|
|
518
|
-
|
|
562
|
+
Organization.statics.findBySlug = function findBySlug(slug, cb) {
|
|
563
|
+
this.findOne({ slug: slug, 'deleted': {$ne: true} }).exec(cb);
|
|
564
|
+
};
|
|
519
565
|
|
|
566
|
+
Organization.statics.findBySlugs = function findBySlugs(slugs, cb) {
|
|
567
|
+
this.find({ 'slug': { $in : slugs }, 'deleted': {$ne: true} }).exec(cb);
|
|
520
568
|
};
|
|
521
569
|
|
|
522
570
|
Organization.statics.findDupes = function findDupes(org, options, cb) {
|
|
@@ -543,43 +591,60 @@ module.exports = function(mongoose, config) {
|
|
|
543
591
|
|
|
544
592
|
};
|
|
545
593
|
|
|
546
|
-
Organization.statics.
|
|
547
|
-
this.collection.stats(cb);
|
|
548
|
-
};
|
|
594
|
+
Organization.statics.flag = function(orgId, resolved, text, username, cb) {
|
|
549
595
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
596
|
+
this.findById(orgId).exec(function(err, org) {
|
|
597
|
+
|
|
598
|
+
org.flagged.resolved = resolved;
|
|
599
|
+
org.flagged.text = text;
|
|
600
|
+
org.flagged.by = username;
|
|
601
|
+
org.flagged.on = Date.now();
|
|
602
|
+
|
|
603
|
+
org.save(cb);
|
|
604
|
+
|
|
605
|
+
});
|
|
554
606
|
|
|
555
|
-
Organization.statics.findBySlug = function findBySlug(slug, cb) {
|
|
556
|
-
this.findOne({ slug: slug, 'deleted': {$ne: true} }).exec(cb);
|
|
557
607
|
};
|
|
558
608
|
|
|
559
|
-
Organization.statics.
|
|
560
|
-
|
|
609
|
+
Organization.statics.getBoardsOfPerson = function getBoardsOfPerson(personId, cb) {
|
|
610
|
+
|
|
611
|
+
var self = this;
|
|
612
|
+
|
|
613
|
+
self
|
|
614
|
+
.find({
|
|
615
|
+
'deleted': { $ne: true },
|
|
616
|
+
'people': {
|
|
617
|
+
$elemMatch: {
|
|
618
|
+
'person': personId,
|
|
619
|
+
'board': { $in: ['chairman', 'director', 'observer'] }
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
})
|
|
623
|
+
.select('name avatarUrl')
|
|
624
|
+
.exec(cb);
|
|
625
|
+
|
|
561
626
|
};
|
|
562
627
|
|
|
563
|
-
Organization.statics.
|
|
564
|
-
var
|
|
565
|
-
|
|
628
|
+
Organization.statics.getByFund = function getByFund(id, cb) {
|
|
629
|
+
var self = this;
|
|
630
|
+
self
|
|
631
|
+
.findOne({ 'funds': id, 'deleted': {$ne: true} })
|
|
632
|
+
.select('name logoUrl')
|
|
633
|
+
.exec(cb);
|
|
566
634
|
};
|
|
567
635
|
|
|
568
|
-
Organization.statics.
|
|
636
|
+
Organization.statics.getById = function getById(id, cb) {
|
|
569
637
|
|
|
570
638
|
var self = this;
|
|
571
639
|
|
|
572
640
|
self
|
|
573
|
-
.
|
|
641
|
+
.findById(id)
|
|
574
642
|
.populate('people.person', 'name avatarUrl title calendarEventSummaries sources')
|
|
575
643
|
.populate('related', 'name logoUrl')
|
|
576
644
|
.populate('notes')
|
|
577
645
|
.populate('chairs.first', 'name avatarUrl title')
|
|
578
646
|
.populate('chairs.second', 'name avatarUrl title')
|
|
579
|
-
.populate('funds', 'name hexColorCode')
|
|
580
|
-
.populate('rounds.funds.fund', 'name hexColorCode')
|
|
581
|
-
.populate('rounds.funds.partner', 'name avatarUrl title')
|
|
582
|
-
.populate('rounds.people.person', 'name avatarUrl title')
|
|
647
|
+
.populate('funds', 'name hexColorCode closeDate')
|
|
583
648
|
.deepPopulate([
|
|
584
649
|
'people.person.sources.person',
|
|
585
650
|
'people.person.calendarEventSummaries.attendees.internal',
|
|
@@ -599,51 +664,94 @@ module.exports = function(mongoose, config) {
|
|
|
599
664
|
|
|
600
665
|
};
|
|
601
666
|
|
|
602
|
-
Organization.statics.
|
|
667
|
+
Organization.statics.getChairsOfPerson = function getChairsOfPerson(personId, cb) {
|
|
668
|
+
|
|
669
|
+
var self = this;
|
|
670
|
+
|
|
671
|
+
self
|
|
672
|
+
.find({ $or:
|
|
673
|
+
[
|
|
674
|
+
{ 'chairs.first': personId },
|
|
675
|
+
{ 'chairs.second': personId }
|
|
676
|
+
],
|
|
677
|
+
'deleted': { $ne: true }
|
|
678
|
+
})
|
|
679
|
+
.exec(cb);
|
|
680
|
+
|
|
681
|
+
};
|
|
682
|
+
|
|
683
|
+
Organization.statics.getSources = function(id, cb) {
|
|
603
684
|
|
|
604
685
|
var self = this;
|
|
605
686
|
|
|
606
687
|
self
|
|
607
688
|
.findById(id)
|
|
608
689
|
.populate('people.person', 'name avatarUrl title calendarEventSummaries sources')
|
|
609
|
-
.populate('related', 'name logoUrl')
|
|
610
|
-
.populate('notes')
|
|
611
|
-
.populate('chairs.first', 'name avatarUrl title')
|
|
612
|
-
.populate('chairs.second', 'name avatarUrl title')
|
|
613
|
-
.populate('funds', 'name hexColorCode')
|
|
614
|
-
.populate('rounds.funds.fund', 'name hexColorCode')
|
|
615
|
-
.populate('rounds.funds.partner', 'name avatarUrl title')
|
|
616
|
-
.populate('rounds.people.person', 'name avatarUrl title')
|
|
617
690
|
.deepPopulate([
|
|
618
|
-
'people.person.sources.person'
|
|
619
|
-
'people.person.calendarEventSummaries.attendees.internal',
|
|
620
|
-
'people.person.calendarEventSummaries.attendees.external',
|
|
621
|
-
'people.person.calendarEventSummaries.notes.createdBy',
|
|
622
|
-
'notes.createdBy'
|
|
691
|
+
'people.person.sources.person'
|
|
623
692
|
], {
|
|
624
693
|
populate: {
|
|
625
|
-
'people.person.sources.person': { select: 'name avatarUrl title' }
|
|
626
|
-
'people.person.calendarEventSummaries.attendees.internal': { select: 'name avatarUrl title' },
|
|
627
|
-
'people.person.calendarEventSummaries.attendees.external': { select: 'name avatarUrl title' },
|
|
628
|
-
'people.person.calendarEventSummaries.notes.createdBy': { select: 'name avatarUrl title' },
|
|
629
|
-
'notes.createdBy': { select: 'name avatarUrl title' }
|
|
694
|
+
'people.person.sources.person': { select: 'name avatarUrl title' }
|
|
630
695
|
}
|
|
631
696
|
})
|
|
632
|
-
.exec(
|
|
697
|
+
.exec(function(err, org) {
|
|
698
|
+
|
|
699
|
+
if (err) return cb(err, null);
|
|
700
|
+
if (!org) return cb(null, null);
|
|
701
|
+
|
|
702
|
+
self.findById(config.CUSTOMER_ID, function(err, customer) {
|
|
703
|
+
|
|
704
|
+
if (err) return cb(err, null);
|
|
705
|
+
if (!customer) return cb(null, null);
|
|
706
|
+
|
|
707
|
+
var current = [];
|
|
708
|
+
var past = [];
|
|
709
|
+
var all = [];
|
|
710
|
+
var orgSources = getSources(org.people);
|
|
711
|
+
|
|
712
|
+
_.each(customer.people, function(p) {
|
|
713
|
+
|
|
714
|
+
var source = _.find(orgSources, function(os) {
|
|
715
|
+
return os.person._id.toString() == p.person.toString();
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
if (!source) return;
|
|
719
|
+
|
|
720
|
+
if (p.current) current.push(source);
|
|
721
|
+
if (!p.current) past.push(source);
|
|
722
|
+
all.push(source);
|
|
723
|
+
|
|
724
|
+
});
|
|
725
|
+
|
|
726
|
+
return cb(null, {
|
|
727
|
+
all: all,
|
|
728
|
+
current: current,
|
|
729
|
+
past: past
|
|
730
|
+
});
|
|
731
|
+
|
|
732
|
+
});
|
|
733
|
+
|
|
734
|
+
});
|
|
633
735
|
|
|
634
736
|
};
|
|
635
737
|
|
|
636
|
-
Organization.statics.
|
|
738
|
+
Organization.statics.listAllFlagged = function (cb) {
|
|
637
739
|
|
|
638
|
-
|
|
740
|
+
var query = this.find({'flagged.resolved': false, 'flagged.text': { $ne: '' }, 'deleted': {$ne: true}});
|
|
741
|
+
query.exec(function (err, orgs) {
|
|
639
742
|
|
|
640
|
-
|
|
743
|
+
if (err) return cb(err, null);
|
|
641
744
|
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
745
|
+
orgs = _.sortBy(orgs, function(org){
|
|
746
|
+
var timestamp = new Date(org.flagged.on);
|
|
747
|
+
timestamp = timestamp.getTime();
|
|
748
|
+
return timestamp;
|
|
749
|
+
});
|
|
750
|
+
orgs = orgs.reverse();
|
|
751
|
+
|
|
752
|
+
return cb(null, orgs);
|
|
753
|
+
|
|
754
|
+
});
|
|
647
755
|
|
|
648
756
|
};
|
|
649
757
|
|
|
@@ -658,93 +766,195 @@ module.exports = function(mongoose, config) {
|
|
|
658
766
|
|
|
659
767
|
};
|
|
660
768
|
|
|
661
|
-
Organization.statics.
|
|
769
|
+
Organization.statics.removeById = function(id, cb) {
|
|
662
770
|
|
|
663
|
-
|
|
664
|
-
|
|
771
|
+
if (!id) { return cb(new Error('id is required'), null); }
|
|
772
|
+
if (!cb) { throw new Error('cb is required'); }
|
|
665
773
|
|
|
666
|
-
|
|
774
|
+
this.remove({_id: id}, cb);
|
|
775
|
+
|
|
776
|
+
};
|
|
667
777
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
778
|
+
Organization.statics.search = function search(data, options, cb) {
|
|
779
|
+
|
|
780
|
+
// search for orgs based on fields provided
|
|
781
|
+
// data format, each field is optional
|
|
782
|
+
// {
|
|
783
|
+
// domain: ''
|
|
784
|
+
// name: ''
|
|
785
|
+
// }
|
|
786
|
+
// options:
|
|
787
|
+
// fuzzy: searches within strings, e.g., searching for "venture" will match "ff Venture Capital"
|
|
788
|
+
// non-fuzzy does a full-string match, e.g., "ffvc" will match "ffvc" but "ff" will not
|
|
789
|
+
// both fuzzy and non are case-insensitive
|
|
790
|
+
// queryFirstWord: tokenizes first word and searches for it
|
|
791
|
+
// removeRelatedFromTopLevel: related people are removed from top-level results
|
|
792
|
+
|
|
793
|
+
// validate input
|
|
794
|
+
if (!cb) throw new Error('cb is required');
|
|
795
|
+
if (!data || (!data.name && !data.domain)) return cb(null, []);
|
|
796
|
+
|
|
797
|
+
var defaultOptions = {
|
|
798
|
+
fuzzy: true,
|
|
799
|
+
queryFirstWord: false,
|
|
800
|
+
removeRelatedFromTopLevel: true
|
|
801
|
+
};
|
|
802
|
+
|
|
803
|
+
// combine provided and default options
|
|
804
|
+
options = utils.setDefaults(options, defaultOptions);
|
|
805
|
+
|
|
806
|
+
// need to be admin or provide investor id
|
|
807
|
+
if (!options.admin && !options.investor) return cb(null, []);
|
|
808
|
+
|
|
809
|
+
data.name = data.name || '';
|
|
810
|
+
data.domain = data.domain || '';
|
|
811
|
+
|
|
812
|
+
var removeRelatedFromTopLevel = function(items) {
|
|
813
|
+
|
|
814
|
+
// All entities are searched initially, including entities that are listed as related to other entities
|
|
815
|
+
// Remove related entities from top-level results so they only come up as related
|
|
816
|
+
|
|
817
|
+
var getRelatedIds = function getRelatedIds(items) {
|
|
818
|
+
|
|
819
|
+
var result = [];
|
|
820
|
+
|
|
821
|
+
_.each(items, function(item) {
|
|
822
|
+
if (item.related && item.related.length >= 1) {
|
|
823
|
+
var ids = _.pluck(item.related, 'id');
|
|
824
|
+
result = result.concat(ids);
|
|
825
|
+
}
|
|
672
826
|
});
|
|
673
|
-
orgs = orgs.reverse();
|
|
674
827
|
|
|
675
|
-
return
|
|
828
|
+
return _.uniq(result);
|
|
829
|
+
|
|
830
|
+
};
|
|
676
831
|
|
|
832
|
+
var relatedIds = getRelatedIds(items);
|
|
833
|
+
items = _.reject(items, function(item) {
|
|
834
|
+
return relatedIds.indexOf(item.id) >= 0;
|
|
677
835
|
});
|
|
678
836
|
|
|
679
|
-
|
|
837
|
+
return items;
|
|
680
838
|
|
|
681
|
-
|
|
839
|
+
};
|
|
682
840
|
|
|
683
|
-
|
|
684
|
-
|
|
841
|
+
// use first word in org name to look for fuzzy matches which is a simple
|
|
842
|
+
// but effective technique as the first word is commonly the most important
|
|
843
|
+
var tokenizeName = function tokenizeName(name, query) {
|
|
685
844
|
|
|
686
|
-
|
|
687
|
-
|
|
845
|
+
if (!name) throw new Error('name is required');
|
|
846
|
+
if (!query) throw new Error('query is required');
|
|
688
847
|
|
|
689
|
-
|
|
848
|
+
var parts = [];
|
|
690
849
|
|
|
691
|
-
|
|
850
|
+
try { parts = name.toString().split(' '); }
|
|
851
|
+
catch (err) { throw err; }
|
|
692
852
|
|
|
693
|
-
|
|
853
|
+
// fuzzy search first word if more than one word in phrase
|
|
854
|
+
if (parts.length >= 2) {
|
|
855
|
+
query['$or'].push({ 'name': new RegExp(parts[0], 'i') });
|
|
856
|
+
}
|
|
694
857
|
|
|
695
|
-
|
|
696
|
-
if (!cb) { throw new Error('cb is required'); }
|
|
858
|
+
};
|
|
697
859
|
|
|
698
|
-
|
|
860
|
+
var buildQuery = function buildQuery(data, options) {
|
|
699
861
|
|
|
700
|
-
|
|
862
|
+
// prepare query
|
|
863
|
+
var query = {};
|
|
864
|
+
query['$or'] = []; // these will be added dynamically from data parameter
|
|
865
|
+
query['$and'] = []; // these will be added dynamically from data parameter
|
|
866
|
+
query['deleted'] = { $ne: true }; // always include this
|
|
701
867
|
|
|
702
|
-
|
|
868
|
+
// conditionally include name
|
|
869
|
+
if (data.name) {
|
|
703
870
|
|
|
704
|
-
|
|
871
|
+
// an exact match is always a good thing
|
|
872
|
+
query['$or'].push({ 'name': new RegExp('^' + data.name + '$', 'i') });
|
|
705
873
|
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
874
|
+
if (options.fuzzy) {
|
|
875
|
+
// fuzzy search full phrase
|
|
876
|
+
query['$or'].push({'name': new RegExp(data.name, 'i')});
|
|
877
|
+
}
|
|
710
878
|
|
|
711
|
-
|
|
879
|
+
if (options.queryFirstWord) {
|
|
880
|
+
// fuzzy search first word
|
|
881
|
+
tokenizeName(data.name, query);
|
|
882
|
+
}
|
|
712
883
|
|
|
713
|
-
|
|
884
|
+
var aliasRegExp = options.fuzzy ? new RegExp(data.name, 'i') : new RegExp('^' + data.name + '$', 'i');
|
|
885
|
+
query['$or'].push({ 'aliases': aliasRegExp });
|
|
714
886
|
|
|
715
|
-
|
|
887
|
+
}
|
|
716
888
|
|
|
717
|
-
|
|
889
|
+
// conditionally include domain
|
|
890
|
+
if (data.domain) {
|
|
891
|
+
var domainRegExp = options.fuzzy ? new RegExp(data.domain, 'i') : new RegExp('^' + data.domain + '$', 'i');
|
|
892
|
+
query['$or'].push({ 'website': domainRegExp });
|
|
893
|
+
}
|
|
718
894
|
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
}, this, organizationId, cb);
|
|
895
|
+
// remove if unused
|
|
896
|
+
if (query['$or'].length == 0) delete query['$or'];
|
|
897
|
+
if (query['$and'].length == 0) delete query['$and'];
|
|
723
898
|
|
|
724
|
-
|
|
899
|
+
return query;
|
|
725
900
|
|
|
726
|
-
|
|
901
|
+
};
|
|
727
902
|
|
|
728
|
-
|
|
903
|
+
var query = buildQuery(data, options);
|
|
904
|
+
|
|
905
|
+
this
|
|
906
|
+
.find(query)
|
|
907
|
+
.populate('merged')
|
|
908
|
+
.select('logoUrl name description related')
|
|
909
|
+
.exec(function(err, orgs) {
|
|
910
|
+
|
|
911
|
+
if (err) return cb(err, null);
|
|
912
|
+
else if (!orgs) return cb(null, null);
|
|
913
|
+
else {
|
|
914
|
+
|
|
915
|
+
// remove related from top level
|
|
916
|
+
if (options.removeRelatedFromTopLevel) orgs = removeRelatedFromTopLevel(orgs);
|
|
917
|
+
|
|
918
|
+
// sort by name
|
|
919
|
+
orgs = _.sortBy(orgs, function(orgs) { return orgs.name; });
|
|
920
|
+
|
|
921
|
+
return cb(null, orgs);
|
|
922
|
+
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
});
|
|
729
926
|
|
|
927
|
+
};
|
|
928
|
+
|
|
929
|
+
Organization.statics.setCustomerPortfolio = function setCustomerPortfolio(portfolio) {
|
|
730
930
|
var self = this;
|
|
931
|
+
self.customerPortfolio = portfolio;
|
|
932
|
+
return self.customerPortfolio;
|
|
933
|
+
};
|
|
731
934
|
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
}, callback);
|
|
736
|
-
};
|
|
935
|
+
Organization.statics.stats = function stats(cb) {
|
|
936
|
+
this.collection.stats(cb);
|
|
937
|
+
};
|
|
737
938
|
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
939
|
+
Organization.statics.upsert = function(org, username, cb) {
|
|
940
|
+
|
|
941
|
+
if (!org) { return cb(new Error('Organization is required'), null); }
|
|
942
|
+
if (!username) { return cb(new Error('Username is required'), null); }
|
|
943
|
+
|
|
944
|
+
org.entered.by = username;
|
|
945
|
+
org.entered.on = new Date();
|
|
946
|
+
|
|
947
|
+
org.save(cb);
|
|
744
948
|
|
|
745
949
|
};
|
|
746
950
|
|
|
747
|
-
|
|
951
|
+
|
|
952
|
+
|
|
953
|
+
///////////////////////////////////////////////////////////////////////////////////////
|
|
954
|
+
// HOOKS
|
|
955
|
+
// Pre-save: fired on every document before it is saved
|
|
956
|
+
// Post-init: fired on every document when it's returned from a query
|
|
957
|
+
///////////////////////////////////////////////////////////////////////////////////////
|
|
748
958
|
|
|
749
959
|
Organization.pre('save', function(next) {
|
|
750
960
|
|
|
@@ -764,75 +974,44 @@ module.exports = function(mongoose, config) {
|
|
|
764
974
|
|
|
765
975
|
});
|
|
766
976
|
|
|
767
|
-
Organization.post('init', function() {
|
|
977
|
+
Organization.post('init', function(doc, next) {
|
|
768
978
|
|
|
769
979
|
// Protect private data
|
|
770
980
|
// Merge public and private data
|
|
771
981
|
|
|
772
|
-
var self = this;
|
|
773
982
|
var CUSTOMER_ID = config.CUSTOMER_ID;
|
|
774
983
|
|
|
775
|
-
if (CUSTOMER_ID == 'GLOBAL_PROCESS') return;
|
|
984
|
+
if (CUSTOMER_ID == 'GLOBAL_PROCESS') return next();
|
|
776
985
|
|
|
777
|
-
|
|
986
|
+
// remove customer details if not viewing self
|
|
987
|
+
if (doc._id.toString() != CUSTOMER_ID) doc.customer = {};
|
|
778
988
|
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
self.docs = _.reject(self.docs, function(item) { return item.customer != CUSTOMER_ID; });
|
|
784
|
-
self.iLevel = _.reject(self.iLevel, function(item) { return item.customer != CUSTOMER_ID; });
|
|
785
|
-
self.chairs = _.reject(self.chairs, function(item) { return item.customer != CUSTOMER_ID; });
|
|
786
|
-
self.capTable = _.reject(self.capTable, function(item) { return item.customer != CUSTOMER_ID; });
|
|
787
|
-
|
|
788
|
-
// investment data
|
|
789
|
-
_.each(self.rounds, function(round) {
|
|
790
|
-
_.each(round.funds, function(fund) {
|
|
791
|
-
if (fund.customer != CUSTOMER_ID) fund.investments = [];
|
|
792
|
-
});
|
|
793
|
-
});
|
|
794
|
-
|
|
795
|
-
};
|
|
989
|
+
doc.filters = _.reject(doc.filters, function(item) { return item.customer != CUSTOMER_ID; });
|
|
990
|
+
doc.docs = _.reject(doc.docs, function(item) { return item.customer != CUSTOMER_ID; });
|
|
991
|
+
doc.iLevel = _.reject(doc.iLevel, function(item) { return item.customer != CUSTOMER_ID; });
|
|
992
|
+
doc.chairs = _.reject(doc.chairs, function(item) { return item.customer != CUSTOMER_ID; });
|
|
796
993
|
|
|
797
|
-
|
|
994
|
+
// people
|
|
995
|
+
_.each(doc.people, function(person) {
|
|
798
996
|
|
|
799
|
-
//
|
|
800
|
-
|
|
997
|
+
// always include if explicitly public
|
|
998
|
+
if (person.public) return;
|
|
801
999
|
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
// closingDate
|
|
806
|
-
// this data will be overwritten if private data belonging to the current customer is present
|
|
1000
|
+
// if not public, keep it in if org is in the current customer's portfolio. otherwise remove it.
|
|
1001
|
+
// todo
|
|
1002
|
+
console.log(customerPortfolio);
|
|
807
1003
|
|
|
808
|
-
|
|
809
|
-
_.each(round.funds, function(fund) {
|
|
810
|
-
|
|
811
|
-
if (fund.customer != CUSTOMER_ID) return;
|
|
812
|
-
if (!fund.investments || fund.investments.length == 0) return;
|
|
813
|
-
|
|
814
|
-
// there can be multiple investments in a single round from the same fund
|
|
815
|
-
// use the most recent
|
|
816
|
-
var mostRecentInvestment = _.max(fund.investments, function(investment) { return investment.date; });
|
|
817
|
-
|
|
818
|
-
// this fund belongs to the current customer
|
|
819
|
-
// if we have private data, use it rather than the public data
|
|
820
|
-
if (mostRecentInvestment) {
|
|
821
|
-
if (mostRecentInvestment.preMoneyValuation) round.preMoneyValuation = mostRecentInvestment.preMoneyValuation;
|
|
822
|
-
if (mostRecentInvestment.amountRaised) round.amountRaised = mostRecentInvestment.amountRaised;
|
|
823
|
-
if (mostRecentInvestment.closingDate) round.closingDate = mostRecentInvestment.closingDate;
|
|
824
|
-
}
|
|
1004
|
+
});
|
|
825
1005
|
|
|
826
|
-
|
|
1006
|
+
return next();
|
|
827
1007
|
|
|
828
|
-
|
|
1008
|
+
});
|
|
829
1009
|
|
|
830
|
-
};
|
|
831
1010
|
|
|
832
|
-
protectCustomerData();
|
|
833
|
-
mergePublicAndPrivateData();
|
|
834
1011
|
|
|
835
|
-
|
|
1012
|
+
///////////////////////////////////////////////////////////////////////////////////////
|
|
1013
|
+
// CONFIG
|
|
1014
|
+
///////////////////////////////////////////////////////////////////////////////////////
|
|
836
1015
|
|
|
837
1016
|
Organization.set('toJSON', { virtuals: true });
|
|
838
1017
|
Organization.set('autoIndex', true);
|
|
@@ -843,6 +1022,6 @@ module.exports = function(mongoose, config) {
|
|
|
843
1022
|
var deepPopulate = require('mongoose-deep-populate')(mongoose);
|
|
844
1023
|
Organization.plugin(deepPopulate);
|
|
845
1024
|
|
|
846
|
-
mongoose.model('Organization', Organization, '
|
|
1025
|
+
mongoose.model('Organization', Organization, 'organization_new');
|
|
847
1026
|
|
|
848
1027
|
};
|