@dhyasama/totem-models 7.57.0 → 8.0.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/lib/Person.js CHANGED
@@ -2,26 +2,21 @@
2
2
 
3
3
  module.exports = function(mongoose, config) {
4
4
 
5
- var customerCompanyIds = [];
6
-
7
- var
5
+ let
8
6
 
9
7
  Schema = mongoose.Schema,
10
8
  Organization = mongoose.model('Organization'),
11
- Flag = mongoose.model('Flag'),
12
9
  Note = mongoose.model('Note'),
13
- Crypto = require('@dhyasama/ffvc-crypto'),
14
- crypto = new Crypto({'key': config.crypto.key}),
15
- domain = config.domain,
10
+ Flag = mongoose.model('Flag'),
11
+ helpers = require('../helpers'),
16
12
  utils = require('@dhyasama/ffvc-utilities'),
17
13
  async = require('async'),
18
14
  _ = require('underscore'),
19
- phoneFormatter = require('phone-formatter'),
20
15
  PhoneNumber = require( 'awesome-phonenumber'),
21
16
  validator = require('validator'),
22
17
  escapeStringRegexp = require('escape-string-regexp');
23
18
 
24
- var Person = new Schema({
19
+ let Person = new Schema({
25
20
 
26
21
  name: {
27
22
  first: { type: String, default: '', index: true },
@@ -146,7 +141,7 @@ module.exports = function(mongoose, config) {
146
141
  });
147
142
 
148
143
  Person.virtual('avatar').get(function() {
149
- return this.avatarUrl || domain + '/media/moustache.jpg';
144
+ return this.avatarUrl || '/media/moustache.jpg';
150
145
  });
151
146
 
152
147
  Person.virtual('email.primary').get(function () {
@@ -169,21 +164,42 @@ module.exports = function(mongoose, config) {
169
164
  return primary ? primary.number : '';
170
165
  });
171
166
 
172
- Person.virtual('interactions.count').get(function () {
167
+ /////////////
168
+
169
+ Person.methods.addMerged = function(id) {
170
+ if (this.merged.indexOf(id) == -1) {
171
+ this.merged = this.merged.concat([id]);
172
+ return true;
173
+ }
174
+ else {
175
+ return false;
176
+ }
177
+ };
178
+
179
+ Person.methods.deletePerson = function() {
180
+ this.deleted = true;
181
+ };
182
+
183
+ Person.methods.interactionsCount = function(requestingCustomerId) {
184
+
185
+ const self = this;
186
+
187
+ if (!requestingCustomerId) { throw new Error('requestingCustomerId is required'); }
188
+ if (!mongoose.Types.ObjectId.isValid(requestingCustomerId)) { throw new Error('requestingCustomerId is not a valid ObjectId'); }
173
189
 
174
190
  // handle missing doc data
175
- this.sources = this.sources || [];
191
+ self.sources = self.sources || [];
176
192
 
177
- var calendarCount = 0;
178
- var emailCount = 0;
193
+ let calendarCount = 0;
194
+ let emailCount = 0;
179
195
 
180
- _.each(this.sources, function(source) {
196
+ _.each(self.sources, function(source) {
181
197
 
182
198
  // Only count interactions for the current customer
183
199
  // A universal interaction count isn't useful
184
- var cid = mongoose.Types.ObjectId.isValid(source.customer) ? source.customer : source.customer._id;
200
+ let sourceCustomerId = mongoose.Types.ObjectId.isValid(source.customer) ? source.customer : source.customer._id;
185
201
 
186
- if (cid.toString() == config.CUSTOMER_ID) {
202
+ if (sourceCustomerId.toString() === requestingCustomerId.toString()) {
187
203
  source.interactions = source.interactions || {};
188
204
  calendarCount += source.interactions.calendar || 0;
189
205
  emailCount += source.interactions.email || 0;
@@ -193,43 +209,6 @@ module.exports = function(mongoose, config) {
193
209
 
194
210
  return calendarCount + emailCount;
195
211
 
196
- });
197
-
198
- Person.virtual('allNotes').get(function () {
199
-
200
- // todo - calendarEventNotes are now stored in the Interactions collection
201
- // todo - should this be deprecated? research where it's used.
202
-
203
- // combine direct person notes and notes from events this person attended
204
- // sort reverse chronologically
205
-
206
- var personNotes = this.notes || [];
207
- personNotes = _.compact(personNotes);
208
-
209
- // var eventNotes = _.pluck(this.calendarEventSummaries || [], 'notes');
210
- // eventNotes = _.flatten(eventNotes);
211
- // eventNotes = _.compact(eventNotes);
212
-
213
- var result = _.sortBy(personNotes, 'createdOn');
214
-
215
- return result.reverse();
216
-
217
- });
218
-
219
- /////////////
220
-
221
- Person.methods.addMerged = function(id) {
222
- if (this.merged.indexOf(id) == -1) {
223
- this.merged = this.merged.concat([id]);
224
- return true;
225
- }
226
- else {
227
- return false;
228
- }
229
- };
230
-
231
- Person.methods.deletePerson = function() {
232
- this.deleted = true;
233
212
  };
234
213
 
235
214
  Person.methods.relatePerson = function(id) {
@@ -286,17 +265,315 @@ module.exports = function(mongoose, config) {
286
265
 
287
266
  };
288
267
 
289
- /************* ACCESS **********************/
268
+ ////////////
269
+
270
+ Person.statics.addFlag = function(personId, creatorPersonId, text, customerId, cb) {
271
+
272
+ Flag.createForModel({
273
+ createdBy: creatorPersonId,
274
+ text: text,
275
+ customer: customerId
276
+ }, this, personId, cb);
290
277
 
291
- Person.methods.funds = function() {
292
- return getActiveFunds(this);
293
278
  };
294
279
 
295
- Person.methods.isSubscriber = function() {
296
- return this.subscriptions && this.subscriptions.length >= 1;
280
+ Person.statics.addNote = function(personId, creatorPersonId, text, isPrivate, customerId, cb) {
281
+
282
+ Note.createForModel({
283
+ createdBy: creatorPersonId,
284
+ text: text,
285
+ isPrivate: isPrivate,
286
+ customer: customerId
287
+ }, this, personId, cb);
288
+
297
289
  };
298
290
 
299
- ////////////
291
+ Person.statics.deleteNote = function(noteId, cb) {
292
+
293
+ // Delete the note itself along with any references on people
294
+
295
+ const self = this;
296
+
297
+ let removePersonNoteReferences = function removePersonNoteReferences(callback) {
298
+ self.update({}, {
299
+ $pull: { 'notes' : [noteId] }
300
+ }, callback);
301
+ };
302
+
303
+ async.series([
304
+ Note.delete.bind(Note, noteId),
305
+ removePersonNoteReferences
306
+ ], function(err, results) {
307
+ return cb(err, null);
308
+ });
309
+
310
+ };
311
+
312
+ // Retrieve any person matching an email in the emails array parameter
313
+ Person.statics.findByEmails = function (emails, cb) {
314
+
315
+ this
316
+ .find({ 'contact.email.email': { $in : emails }, 'deleted': {$ne: true}})
317
+ .select('name avatarUrl title doNotDisplay')
318
+ .sort('name.full')
319
+ .exec(cb);
320
+
321
+ };
322
+
323
+ Person.statics.findBySocial = function findBySocial(value, cb) {
324
+
325
+ // Extract stand-alone username and append it to our standardized domains
326
+
327
+ const self = this;
328
+
329
+ if (!value) { return cb(new Error('value must be provided'), null); }
330
+
331
+ let username = utils.getUsernameFromUrl(value);
332
+
333
+ if (!username) { return cb(null, []); }
334
+
335
+ self
336
+ .find({ $or:
337
+ [
338
+ { 'social.facebook': new RegExp('facebook.com/' + username + '$/?', 'i') },
339
+ { 'social.linkedin': new RegExp('linkedin.com/in/' + username + '\/?$', 'i') },
340
+ { 'social.twitter': new RegExp('twitter.com/' + username + '/?$', 'i') }
341
+ ],
342
+ 'deleted': { $ne: true }
343
+ })
344
+ .exec(cb);
345
+
346
+ };
347
+
348
+ Person.statics.getById = function (id, options, cb) {
349
+
350
+ const self = this;
351
+
352
+ if (!cb) { throw new Error('cb is required'); }
353
+ if (!id) { return cb(new Error('id is required'), null); }
354
+ if (!mongoose.Types.ObjectId.isValid(id)) { return cb(new Error('id is not a valid ObjectId'), null); }
355
+ if (!options) { return cb(new Error('options is required'), null); }
356
+ if (!options.CUSTOMER_ID) { return cb(new Error('options.CUSTOMER_ID is required'), null); }
357
+ if (!mongoose.Types.ObjectId.isValid(options.CUSTOMER_ID)) { return cb(new Error('options.CUSTOMER_ID is not a valid ObjectId'), null); }
358
+
359
+ self
360
+ .findById(id)
361
+ .select('-previous')
362
+ .populate('related')
363
+ .populate('sources.person', 'avatarUrl name title doNotDisplay')
364
+ .exec(function (err, person) {
365
+
366
+ if (err) return cb(err, null);
367
+ else if (!person) return cb(null, null);
368
+
369
+ person = helpers.cleanPerson(person, options.CUSTOMER_ID);
370
+
371
+ person.sources = _.sortBy(person.sources, function(source) {
372
+ return source.interactions.calendar + source.interactions.email;
373
+ }).reverse();
374
+
375
+ return cb(null, person);
376
+
377
+ });
378
+
379
+ };
380
+
381
+ Person.statics.getByIdNoPopulate = function (id, options, cb) {
382
+
383
+ // only for worker
384
+
385
+ const self = this;
386
+
387
+ if (!cb) { throw new Error('cb is required'); }
388
+ if (!id) { return cb(new Error('id is required'), null); }
389
+ if (!mongoose.Types.ObjectId.isValid(id)) { return cb(new Error('id is not a valid ObjectId'), null); }
390
+ if (!options) { return cb(new Error('options is required'), null); }
391
+
392
+ options = helpers.getDefaultOptions(options);
393
+
394
+ if (!options.isWorkerProcess) { return cb(null, null); }
395
+
396
+ self.findById(id).exec(cb);
397
+
398
+ };
399
+
400
+ Person.statics.getByIds = function (ids, options, cb) {
401
+
402
+ const self = this;
403
+
404
+ if (!cb) { throw new Error('cb is required'); }
405
+ if (!ids) { return cb(new Error('ids is required'), null); }
406
+ if (!options) { return cb(new Error('options is required'), null); }
407
+ if (!options.CUSTOMER_ID) { return cb(new Error('options.CUSTOMER_ID is required'), null); }
408
+ if (!mongoose.Types.ObjectId.isValid(options.CUSTOMER_ID)) { return cb(new Error('options.CUSTOMER_ID is not a valid ObjectId'), null); }
409
+
410
+ self
411
+ .find({ '_id': { $in : ids }, 'deleted': {$ne: true} })
412
+ .exec(function(err, people) {
413
+
414
+ if (err) { return cb(err, null); }
415
+ else if (!people) { return cb(null, []); }
416
+
417
+ people = _.map(people, function(person) {
418
+ return helpers.cleanPerson(person, options.CUSTOMER_ID);
419
+ });
420
+
421
+ return cb(null, people);
422
+
423
+ });
424
+ };
425
+
426
+ Person.statics.getFlags = function getFlags(personId, options, cb) {
427
+
428
+ if (!cb) { throw new Error('cb is required'); }
429
+ if (!personId) { return cb(new Error('personId is required'), null); }
430
+ if (!mongoose.Types.ObjectId.isValid(personId)) { return cb(new Error('personId is not a valid ObjectId'), null); }
431
+ if (!options) { return cb(new Error('options is required'), null); }
432
+ if (!options.CUSTOMER_ID) { return cb(new Error('options.CUSTOMER_ID is required'), null); }
433
+ if (!mongoose.Types.ObjectId.isValid(options.CUSTOMER_ID)) { return cb(new Error('options.CUSTOMER_ID is not a valid ObjectId'), null); }
434
+
435
+ const self = this;
436
+ let query = self.findById(personId);
437
+
438
+ query.select('flags');
439
+ query.populate({
440
+ path: 'flags',
441
+ match: { customer: options.CUSTOMER_ID }
442
+ });
443
+ query.deepPopulate([
444
+ 'flags.createdBy'
445
+ ], {
446
+ populate: {
447
+ 'flags.createdBy': { select: 'name avatarUrl title' }
448
+ }
449
+ });
450
+ query.sort({'createdOn':-1});
451
+
452
+ query.exec(cb);
453
+
454
+ };
455
+
456
+ Person.statics.getList = function getList(cb) {
457
+
458
+ var self = this;
459
+
460
+ self
461
+ .find({'deleted': {$ne: true}})
462
+ .select('name contact.email')
463
+ .lean()
464
+ .exec(cb);
465
+
466
+ };
467
+
468
+ Person.statics.getNotes = function getNotes(personId, options, cb) {
469
+
470
+ if (!cb) { throw new Error('cb is required'); }
471
+ if (!personId) { return cb(new Error('personId is required'), null); }
472
+ if (!mongoose.Types.ObjectId.isValid(personId)) { return cb(new Error('personId is not a valid ObjectId'), null); }
473
+ if (!options) { return cb(new Error('options is required'), null); }
474
+ if (!options.CUSTOMER_ID) { return cb(new Error('options.CUSTOMER_ID is required'), null); }
475
+ if (!mongoose.Types.ObjectId.isValid(options.CUSTOMER_ID)) { return cb(new Error('options.CUSTOMER_ID is not a valid ObjectId'), null); }
476
+
477
+ const self = this;
478
+ let query = self.findById(personId);
479
+
480
+ query.select('notes');
481
+ query.populate({
482
+ path: 'notes',
483
+ match: { customer: options.CUSTOMER_ID }
484
+ });
485
+ query.deepPopulate([
486
+ 'notes.createdBy'
487
+ ], {
488
+ populate: {
489
+ 'notes.createdBy': { select: 'name avatarUrl title' }
490
+ }
491
+ });
492
+ query.sort({'createdOn':-1});
493
+
494
+ query.exec(cb);
495
+
496
+ };
497
+
498
+ Person.statics.getSources = function (id, options, cb) {
499
+
500
+ if (!cb) { throw new Error('cb is required'); }
501
+ if (!id) { return cb(new Error('id is required'), null); }
502
+ if (!mongoose.Types.ObjectId.isValid(id)) { return cb(new Error('id is not a valid ObjectId'), null); }
503
+ if (!options) { return cb(new Error('options is required'), null); }
504
+ if (!options.CUSTOMER_ID) { return cb(new Error('options.CUSTOMER_ID is required'), null); }
505
+ if (!mongoose.Types.ObjectId.isValid(options.CUSTOMER_ID)) { return cb(new Error('options.CUSTOMER_ID is not a valid ObjectId'), null); }
506
+
507
+ const self = this;
508
+
509
+ // get the person
510
+ let query = self.findById(id);
511
+
512
+ query.populate('sources.person');
513
+
514
+ query.exec(function(err, person) {
515
+
516
+ if (err) { return cb(err, null); }
517
+ if (!person) { return cb(err, null); }
518
+
519
+ // get the customer's org
520
+ Organization.collection.findById(options.CUSTOMER_ID, function(err, customer) {
521
+
522
+ if (err) { return cb(err, null); }
523
+ if (!customer) { return cb(null, null); }
524
+
525
+ let current = [];
526
+ let past = [];
527
+ let all = [];
528
+
529
+ // look at each person at customer
530
+ // if person is a source, add to list(s)
531
+ _.each(customer.people, function(p) {
532
+
533
+ let source = _.find(person.sources, function(ps) {
534
+ if (!ps || !ps.person || !ps.person._id) { return false; }
535
+ return ps.person._id.toString() === p.person.toString();
536
+ });
537
+
538
+ if (!source) { return; }
539
+
540
+ if (p.current) { current.push(source); }
541
+ if (!p.current) { past.push(source); }
542
+
543
+ all.push(source);
544
+
545
+ });
546
+
547
+ // return categorized sources
548
+ return cb(null, {
549
+ all: all,
550
+ current: current,
551
+ past: past
552
+ });
553
+
554
+ });
555
+
556
+ });
557
+ };
558
+
559
+ Person.statics.modifyById = function(id, update, cb) {
560
+
561
+ // VERY IMPORTANT NOTE
562
+ // findByIdAndUpdate and findOneAndUpdate do not trigger pre-save hook so that code will not run here
563
+
564
+ if (!cb) throw new Error('cb is required');
565
+ if (!id) { return cb(new Error('id is required'), null); }
566
+ if (!update) { return cb(new Error('update is required'), null); }
567
+
568
+ const self = this;
569
+
570
+ // https://mongoosejs.com/docs/api.html#model_Model.findOneAndUpdate
571
+ // options runValidators defaults false which is ok since we have upsert false
572
+ // new returns the updated document
573
+
574
+ self.findByIdAndUpdate(id, update, { upsert: false, new: true }, cb);
575
+
576
+ };
300
577
 
301
578
  // search for people based on fields provided
302
579
  // Data format, everything is optional
@@ -642,491 +919,15 @@ module.exports = function(mongoose, config) {
642
919
 
643
920
  this
644
921
  .find({ 'contact.email.email': email, 'deleted': {$ne: true} })
922
+ .select('name avatarUrl')
645
923
  .exec(cb);
646
924
 
647
925
  };
648
926
 
649
- Person.statics.findDupes = function(person, options, cb) {
927
+ Person.statics.upsert = function(currentPerson, username, cb) {
650
928
 
651
- if (!cb) throw new Error('cb is required');
652
- if (!person) return cb(null, []);
653
-
654
- var emails = [];
655
- if (person.contact && person.contact.email) {
656
- // pluck emails
657
- emails = _.map(person.contact.email, function(email) {
658
- return email.email;
659
- });
660
- }
661
-
662
- var phones = [];
663
- if (person.contact && person.contact.phone) {
664
- // pluck and normalize phone numbers
665
- phones = _.map(person.contact.phone, function(phone) {
666
- return phoneFormatter.normalize(phone.number);
667
- });
668
- }
669
-
670
- // Sometimes clients pass in something like { name: 'Jason Reynolds' } rather than { name: { first: 'Jason', last: 'Reynolds' } }
671
- // Parse it out as a courtesy
672
- if (!person.name.first && !person.name.last) {
673
- var fullName = person.name;
674
- person = {
675
- name: {
676
- first: fullName.split(" ")[0],
677
- last: fullName.split(" ")[1]
678
- }
679
- };
680
- }
681
-
682
- // Require names that are at least two characters long
683
- if (person.name.first.length < 2) person.name.first = '';
684
- if (person.name.last.length < 2) person.name.last = '';
685
-
686
- this.search({
687
- emails: emails,
688
- phones: phones,
689
- name: person.name
690
- }, options, function(err, people) {
691
-
692
- if (err) return cb(err, null);
693
- if (!people) return cb(null, null);
694
-
695
- // exclude passed in person from results
696
- people = _.reject(people, function(p) {
697
- return p.id == person.id;
698
- });
699
-
700
- return cb(null, people);
701
-
702
- });
703
-
704
- };
705
-
706
- Person.statics.findBySocial = function findBySocial(value, cb) {
707
-
708
- // Extract stand-alone username and append it to our standardized domains
709
-
710
- var self = this;
711
-
712
- if (!value) { return cb(new Error('value must be provided'), null); }
713
-
714
- var username = utils.getUsernameFromUrl(value);
715
-
716
- if (!username) { return cb(null, []); }
717
-
718
- self
719
- .find({ $or:
720
- [
721
- { 'social.facebook': new RegExp('facebook.com/' + username + '$/?', 'i') },
722
- { 'social.linkedin': new RegExp('linkedin.com/in/' + username + '\/?$', 'i') },
723
- { 'social.twitter': new RegExp('twitter.com/' + username + '/?$', 'i') }
724
- ],
725
- 'deleted': { $ne: true }
726
- })
727
- .exec(cb);
728
-
729
- };
730
-
731
- Person.statics.stats = function (cb) {
732
- this.collection.stats(cb);
733
- };
734
-
735
- Person.statics.getById = function (id, cb) {
736
-
737
- this
738
- .findById(id)
739
- .select('-previous')
740
- .populate('related')
741
- .populate('sources.person', 'avatarUrl name title doNotDisplay')
742
- .exec(function (err, person) {
743
-
744
- if (err) return cb(err, null);
745
- else if (!person) return cb(null, null);
746
-
747
- person.sources = _.sortBy(person.sources, function(source) {
748
- return source.interactions.calendar + source.interactions.email;
749
- }).reverse();
750
-
751
- return cb(null, person);
752
-
753
- });
754
-
755
- };
756
-
757
- Person.statics.getByIdAsGlobal = function getByIdAsGlobal(id, options, cb) {
758
-
759
- var self = this;
760
-
761
- // Save original id so we can put it back when we're done
762
- var orginalCustomerId = config.CUSTOMER_ID;
763
-
764
- // Switch to global
765
- config.CUSTOMER_ID = "GLOBAL_PROCESS";
766
- console.log('config.CUSTOMER_ID pre query', config.CUSTOMER_ID);
767
-
768
- try {
769
-
770
- self.findById(id, function(err, result) {
771
-
772
- // Put original id back
773
- config.CUSTOMER_ID = orginalCustomerId;
774
- console.log('config.CUSTOMER_ID post query', config.CUSTOMER_ID);
775
-
776
- if (err) { return cb(err, null); }
777
-
778
- return cb(null, result);
779
-
780
- });
781
-
782
-
783
- }
784
- catch(err) {
785
-
786
- // Put original id back
787
- config.CUSTOMER_ID = orginalCustomerId;
788
- console.log('config.CUSTOMER_ID post query', config.CUSTOMER_ID);
789
-
790
- console.log('ERROR WITH PERSON.GETBYIDGLOBAL');
791
- console.log('config.CUSTOMER_ID', config.CUSTOMER_ID);
792
- console.log(err);
793
-
794
- return cb(err, null);
795
-
796
- }
797
-
798
- };
799
-
800
- Person.statics.getByIdRaw = function (id, cb) {
801
-
802
- // directly from mongo driver to avoid mongoose middlewares
803
-
804
- var self = this;
805
-
806
- self.collection.findOne({ "_id": id }, cb);
807
-
808
- };
809
-
810
- Person.statics.getByIdNoPopulate = function (id, cb) {
811
-
812
- this
813
- .findById(id)
814
- .exec(cb);
815
-
816
- };
817
-
818
- Person.statics.getByIds = function (ids, cb) {
819
- this
820
- .find({ '_id': { $in : ids }, 'deleted': {$ne: true} })
821
- .exec(cb);
822
- };
823
-
824
- Person.statics.getList = function getList(cb) {
825
-
826
- var self = this;
827
-
828
- self
829
- .find({'deleted': {$ne: true}})
830
- .select('name contact.email')
831
- .lean()
832
- .exec(cb);
833
-
834
- };
835
-
836
- Person.statics.getFlags = function getFlags(personId, cb) {
837
-
838
- var self = this;
839
- var query = self.findById(personId)
840
-
841
- query.select('flags')
842
- query.populate({
843
- path: 'flags',
844
- match: { customer: config.CUSTOMER_ID }
845
- })
846
- query.deepPopulate([
847
- 'flags.createdBy'
848
- ], {
849
- populate: {
850
- 'flags.createdBy': { select: 'name avatarUrl title' }
851
- }
852
- })
853
- query.sort({'createdOn':-1})
854
- query.exec(cb);
855
-
856
- };
857
-
858
- Person.statics.getNotes = function getNotes(personId, cb) {
859
-
860
- var self = this;
861
- var query = self.findById(personId)
862
-
863
- query.select('notes')
864
- query.populate({
865
- path: 'notes',
866
- match: { customer: config.CUSTOMER_ID }
867
- })
868
- query.deepPopulate([
869
- 'notes.createdBy'
870
- ], {
871
- populate: {
872
- 'notes.createdBy': { select: 'name avatarUrl title' }
873
- }
874
- })
875
- query.sort({'createdOn':-1})
876
- query.exec(cb);
877
-
878
- };
879
-
880
- // Retrieve any person matching an email in the emails array parameter
881
- Person.statics.findByEmails = function (emails, cb) {
882
-
883
- // sort is done post retrieval because query sort is done pre-decryption
884
-
885
- this
886
- .find({ 'contact.email.email': { $in : emails }, 'deleted': {$ne: true}})
887
- .select('name avatarUrl title doNotDisplay contact')
888
- .exec(function (err, people) {
889
- cb(err, _.sortBy(people, function(person) { return person.name.full; }));
890
- });
891
-
892
- };
893
-
894
- // Retrieve any person matching an email in the emails array parameter
895
- Person.statics.findByEmailsSkinny = function (emails, cb) {
896
- this
897
- .find({ 'contact.email.email': { $in : emails }, 'deleted': {$ne: true}})
898
- .exec(cb);
899
- };
900
-
901
- Person.statics.findBySlug = function (slug, cb) {
902
- this
903
- .find({ slug: new RegExp(slug, 'i'), 'deleted': {$ne: true} })
904
- .exec(cb);
905
- };
906
-
907
- Person.statics.findBySlugs = function (slugs, cb) {
908
- this
909
- .find({ 'slug': { $in : slugs } })
910
- .exec(cb);
911
- };
912
-
913
- Person.statics.findByUniqueInfo = function (email, cb) {
914
-
915
- // useful for not inserting dupes
916
- // could expand this to check other fields
917
- // but really should be replaced by search
918
-
919
- this.findOne({
920
- $or: [
921
- { 'contact.email': { $elemMatch: {'email': crypto.encrypt(email)} }},
922
- { 'contact.email': { $elemMatch: {'email': email} }}
923
- ]})
924
- .populate('account boards.company leadership.company chairs.first.company chairs.second.company')
925
- .exec(cb);
926
-
927
- };
928
-
929
- Person.statics.getSources = function (id, cb) {
930
- this
931
- .findById(id)
932
- .populate('sources.person')
933
- .exec(function(err, person) {
934
-
935
- if (err) return cb(err, null);
936
- if (!person) return cb(err, null);
937
-
938
- Organization.findById(config.CUSTOMER_ID, function(err, customer) {
939
-
940
- if (err) return cb(err, null);
941
- if (!customer) return cb(null, null);
942
-
943
- var current = [];
944
- var past = [];
945
- var all = [];
946
-
947
- _.each(customer.people, function(p) {
948
-
949
- var source = _.find(person.sources, function(ps) {
950
- if (!ps || !ps.person || !ps.person._id) return false;
951
- return ps.person._id.toString() == p.person.toString();
952
- });
953
-
954
- if (!source) return;
955
-
956
- if (p.current) current.push(source);
957
- if (!p.current) past.push(source);
958
- all.push(source);
959
-
960
- });
961
-
962
- return cb(null, {
963
- all: all,
964
- current: current,
965
- past: past
966
- });
967
-
968
- });
969
-
970
- });
971
- };
972
-
973
- Person.statics.listAllPeople = function (cb) {
974
-
975
- // sort is done post retrieval because query sort is done pre-decryption
976
-
977
- var query = this.find({'deleted': {$ne: true}});
978
- query.populate('account chairs.first.company chairs.second.company');
979
- query.exec(function (err, people) {
980
- cb(err, _.sortBy(people, function(person) { return person.name.full; }));
981
- });
982
-
983
- };
984
-
985
- Person.statics.listMostRecentPeople = function (cb) {
986
-
987
- // sort is done post retrieval because query sort is done pre-decryption
988
-
989
- this
990
- .find({'deleted': {$ne: true}})
991
- .sort({'_id': 1})
992
- .limit(100)
993
- .exec(function (err, people) {
994
- cb(err, _.sortBy(people, function(person) { return person.name.full; }));
995
- });
996
-
997
- };
998
-
999
- Person.statics.listPage = function (skip, cb) {
1000
-
1001
- this
1002
- .find({'deleted': {$ne: true}})
1003
- .sort({'name.first':1, 'name.last':1})
1004
- .skip(skip)
1005
- .limit(100)
1006
- .exec(cb);
1007
-
1008
- };
1009
-
1010
- Person.statics.listAllPeopleNoPop = function (cb) {
1011
-
1012
- // sort is done post retrieval because query sort is done pre-decryption
1013
-
1014
- var query = this.find({'deleted': {$ne: true}});
1015
- query.exec(function (err, people) {
1016
- cb(err, _.sortBy(people, function(person) { return person.name.full; }));
1017
- });
1018
-
1019
- };
1020
-
1021
- Person.statics.listAllFlaggedPeople = function (cb) {
1022
-
1023
- this
1024
- .find({'flagged.resolved': false, 'flagged.text': { $ne: '' }, 'deleted': {$ne: true}})
1025
- .exec(function (err, people) {
1026
- people = _.sortBy(people, function(person){
1027
- var timestamp = new Date(person.flagged.on);
1028
- timestamp = timestamp.getTime();
1029
- return timestamp;
1030
- });
1031
- people = people.reverse();
1032
-
1033
- cb(err, people);
1034
- });
1035
-
1036
- };
1037
-
1038
- Person.statics.listAllPeopleWithoutAccounts = function (cb) {
1039
-
1040
- // sort is done post retrieval because query sort is done pre-decryption
1041
-
1042
- this
1043
- .find({account: {$exists: false}, 'deleted': {$ne: true}})
1044
- .exec(function (err, people) {
1045
- cb(err, _.sortBy(people, function(person) { return person.name.full; }));
1046
- });
1047
-
1048
- };
1049
-
1050
- Person.statics.listForSubscription = function (subscriptionId, cb) {
1051
-
1052
- this
1053
- .find({ 'subscriptions.id': subscriptionId, 'deleted': {$ne: true}})
1054
- .exec(function(err, people) {
1055
- cb(err, people);
1056
- });
1057
-
1058
- };
1059
-
1060
- Person.statics.addChair = function(personId, chairPos, companyId, cb) {
1061
-
1062
- this.findById(personId).exec(function(err, person) {
1063
-
1064
- var chairObj = {
1065
- company: companyId,
1066
- start: ''
1067
- };
1068
-
1069
- switch(chairPos) {
1070
- case 'first':
1071
- person.chairs.first.push(chairObj);
1072
- break;
1073
-
1074
- case 'second':
1075
- person.chairs.second.push(chairObj);
1076
- break;
1077
- }
1078
-
1079
- person.save(cb);
1080
-
1081
- });
1082
-
1083
- };
1084
-
1085
- //same function for flag resolved and unresolved... all based on true|false resolved arg
1086
- Person.statics.flag = function(personId, resolved, text, username, cb) {
1087
-
1088
- this.findById(personId).exec(function(err, person) {
1089
-
1090
- if (!person) return cb(new Error('person not found'), null);
1091
-
1092
- person.flagged.resolved = resolved;
1093
- person.flagged.text = text;
1094
- person.flagged.by = username;
1095
- person.flagged.on = Date.now();
1096
-
1097
- person.save(cb);
1098
-
1099
- });
1100
-
1101
- };
1102
-
1103
- Person.statics.setCustomerCompanyIds = function(ids) {
1104
- customerCompanyIds = ids;
1105
- };
1106
-
1107
- Person.statics.modifyById = function(id, update, cb) {
1108
-
1109
- // VERY IMPORTANT NOTE
1110
- // findByIdAndUpdate and findOneAndUpdate do not trigger pre-save hook so that code will not run here
1111
-
1112
- if (!cb) throw new Error('cb is required');
1113
- if (!id) { return cb(new Error('id is required'), null); }
1114
- if (!update) { return cb(new Error('update is required'), null); }
1115
-
1116
- var self = this;
1117
-
1118
- // https://mongoosejs.com/docs/api.html#model_Model.findOneAndUpdate
1119
- // options runValidators defaults false which is ok since we have upsert false
1120
- // new returns the updated document
1121
-
1122
- self.findByIdAndUpdate(id, update, { upsert: false, new: true }, cb);
1123
-
1124
- };
1125
-
1126
- Person.statics.upsert = function(currentPerson, username, cb) {
1127
-
1128
- if (!currentPerson) { return cb(new Error('Current Person is required'), null); }
1129
- if (!username) { return cb(new Error('Username is required'), null); }
929
+ if (!currentPerson) { return cb(new Error('Current Person is required'), null); }
930
+ if (!username) { return cb(new Error('Username is required'), null); }
1130
931
 
1131
932
  currentPerson.entered = {
1132
933
  by: username,
@@ -1137,96 +938,8 @@ module.exports = function(mongoose, config) {
1137
938
 
1138
939
  };
1139
940
 
1140
- Person.statics.addFlag = function(personId, creatorPersonId, text, cb) {
1141
-
1142
- Flag.createForModel({
1143
- createdBy: creatorPersonId,
1144
- text: text
1145
- }, this, personId, cb);
1146
-
1147
- };
1148
-
1149
- Person.statics.addNote = function(personId, creatorPersonId, text, isPrivate, cb) {
1150
-
1151
- Note.createForModel({
1152
- createdBy: creatorPersonId,
1153
- text: text,
1154
- isPrivate: isPrivate
1155
- }, this, personId, cb);
1156
-
1157
- };
1158
-
1159
- Person.statics.deleteFlag = function(flagId, cb) {
1160
-
1161
- // Delete the flag itself along with reference on person
1162
-
1163
- var self = this;
1164
-
1165
- var removeReference = function removeReference(callback) {
1166
- self.update({}, {
1167
- $pull: { 'flags' : [flagId] }
1168
- }, callback);
1169
- };
1170
-
1171
- async.series([
1172
- Flag.delete.bind(Flag, flagId),
1173
- removeReference
1174
- ], function(err, results) {
1175
- return cb(err, null);
1176
- });
1177
-
1178
- };
1179
-
1180
- Person.statics.deleteNote = function(noteId, cb) {
1181
-
1182
- // Delete the note itself along with any references on people
1183
-
1184
- var self = this;
1185
-
1186
- var removePersonNoteReferences = function removePersonNoteReferences(callback) {
1187
- self.update({}, {
1188
- $pull: { 'notes' : [noteId] }
1189
- }, callback);
1190
- };
1191
-
1192
- // var removeEventNoteReferences = function removeEventNoteReferences(callback) {
1193
- // self.update({
1194
- // 'calendarEventSummaries.notes': noteId
1195
- // }, {
1196
- // $pull: { 'calendarEventSummaries.$.notes' : [noteId] }
1197
- // }, callback);
1198
- // };
1199
-
1200
- async.series([
1201
- Note.delete.bind(Note, noteId),
1202
- removePersonNoteReferences,
1203
- //removeEventNoteReferences
1204
- ], function(err, results) {
1205
- return cb(err, null);
1206
- });
1207
-
1208
- };
1209
-
1210
941
  ///////////////
1211
942
 
1212
- Person.post('remove', function(doc) {
1213
- // Account.person
1214
- // Investor.people
1215
- // Investor.formerPeople
1216
- // LimitedPartner.person
1217
- // Organization.people.person
1218
- // Person.merged
1219
- // Person.related
1220
- // Person.calendarEventSummaries.attendees.internal
1221
- // Person.calendarEventSummaries.attendees.external
1222
- // PortfolioCompany.chairs.first
1223
- // PortfolioCompany.chairs.second
1224
- // PortfolioCompany.boards
1225
- // PortfolioCompany.leadership.person
1226
- // PortfolioCompany.people.person
1227
- // PortfolioCompany.formerPeople
1228
- });
1229
-
1230
943
  Person.pre('save', function(next) {
1231
944
 
1232
945
  var self = this;
@@ -1327,31 +1040,10 @@ module.exports = function(mongoose, config) {
1327
1040
 
1328
1041
  });
1329
1042
 
1330
- Person.post('init', function() {
1331
-
1332
- var self = this;
1333
- var CUSTOMER_ID = config.CUSTOMER_ID;
1334
-
1335
- var protectSources = function protectSources(person) {
1336
-
1337
- if (CUSTOMER_ID == 'GLOBAL_PROCESS') return;
1338
-
1339
- person.sources = _.reject(person.sources, function(source) {
1340
- var customerId = mongoose.Types.ObjectId.isValid(source.customer) ? source.customer : source.customer._id;
1341
- return customerId.toString() != CUSTOMER_ID.toString();
1342
- });
1343
-
1344
- };
1345
-
1346
- protectSources(self);
1347
-
1348
- });
1349
-
1350
- var deepPopulate = require('mongoose-deep-populate')(mongoose);
1043
+ let deepPopulate = require('mongoose-deep-populate')(mongoose);
1351
1044
  Person.plugin(deepPopulate);
1352
1045
 
1353
1046
  Person.set('autoIndex', false);
1354
- Person.set('usePushEach', true);
1355
1047
  Person.on('index', function(err) { console.log('error building person indexes: ' + err); });
1356
1048
 
1357
1049
  Person.set('toJSON', { virtuals: true });