@dhyasama/totem-merge 6.0.1

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.
@@ -0,0 +1,408 @@
1
+ "use strict";
2
+
3
+ let async = require('async');
4
+ let _ = require('underscore');
5
+ let helpers = require('./helpers');
6
+ let mongoose = require('mongoose');
7
+ let ObjectId = mongoose.Types.ObjectId;
8
+ let logger;
9
+
10
+ var merge = function merge(context, target, source, mergedBy, customerId, cb) {
11
+
12
+ logger = context.logger;
13
+
14
+ logger.writeToInfoLog('Merge organizations...');
15
+
16
+ // validate parameters
17
+ if (!context) return cb(new Error('context is required'), null);
18
+ if (!target) return cb(new Error('target is required'), null);
19
+ if (!source) return cb(new Error('source is required'), null);
20
+ if (!mergedBy) return cb(new Error('mergedBy is required'), null);
21
+ if (!cb) throw new Error('cb is required');
22
+
23
+ var saveOrganization = function(org, username, callback) {
24
+
25
+ logger.writeToInfoLog('Save target organization...');
26
+ logger.writeToInfoLog(' ID: ' + org._id.toString());
27
+ logger.writeToInfoLog(' LinkedIn: ' + org.social.linkedin);
28
+ logger.writeToInfoLog(' Twitter: ' + org.social.twitter);
29
+ logger.writeToInfoLog(' Domains: ' + org.websites);
30
+
31
+ context.Organization.upsert(org, username, callback);
32
+
33
+ };
34
+
35
+ if (context.flagOnly) {
36
+
37
+ var url = 'https://admin.ffvc.com/orgs/' + source.id;
38
+ var text = 'This org should be merged with ' + url;
39
+
40
+ context.Organization.addFlag(target._id, target._id, text, customerId, function(err, result) {
41
+ if (err) return cb(err, null);
42
+ return cb(null, result);
43
+ });
44
+
45
+ }
46
+ else {
47
+
48
+ // mergedBy can be either an account or a username
49
+ var username = mergedBy.username ? mergedBy.username : mergedBy;
50
+ logger.writeToInfoLog('Username: ' + username);
51
+
52
+ async.series([
53
+
54
+ verifyOkToMerge.bind(null, target, source),
55
+
56
+ // Create a snapshot of the target
57
+ helpers.createSnapshot.bind(null, context, 'Organization', target, username),
58
+
59
+ // Create a snapshot of the source
60
+ helpers.createSnapshot.bind(null, context, 'Organization', source, username),
61
+
62
+ // Merge the source into the target
63
+ mergeSourceIntoTarget.bind(null, target, source),
64
+
65
+ // Delete the source
66
+ // Do this prior to saving merged target in order to avoid unique key issues
67
+ helpers.removeEntity.bind(null, context, source),
68
+
69
+ // Save the updated target
70
+ saveOrganization.bind(null, target, username),
71
+
72
+ // Change source references to target
73
+ updateReferences.bind(null, context, target, source, mergedBy, customerId)
74
+
75
+ ], function(err, results) {
76
+
77
+ if (err) { return cb(err, null); }
78
+
79
+ // result from saveOrganization
80
+ var updatedTarget = results[5];
81
+
82
+ // result from updateOrganizations within updateReferences
83
+ var updatedReferencesOrgs = results[6][4];
84
+
85
+ // Check if target had reference(s) updated
86
+ var targetMatch = _.find(updatedReferencesOrgs, function(o) {
87
+ return o.id.toString() === target.id.toString();
88
+ });
89
+
90
+ // Return up to date target
91
+ if (targetMatch) { return cb(null, targetMatch); }
92
+ else { return cb(null, updatedTarget); }
93
+
94
+ });
95
+
96
+ }
97
+
98
+ };
99
+
100
+ var mergeSourceIntoTarget = function mergeEntities(target, source, cb) {
101
+
102
+ logger.writeToInfoLog('Merge source into target...');
103
+
104
+ var doNotMergeKeys = [
105
+ 'merged',
106
+ 'deleted',
107
+ 'entered',
108
+ '__v'
109
+ ];
110
+
111
+ helpers.mergeObjects(target, source, doNotMergeKeys);
112
+
113
+ // keep a list of copied orgs
114
+ target.merge(source.id);
115
+
116
+ // add copied org name as an alias if it's different from source name
117
+ if (target.name.toLowerCase() != source.name.toLowerCase()) {
118
+ target.aliases = target.aliases.concat([source.name]);
119
+ target.aliases = _.uniq(target.aliases);
120
+ }
121
+
122
+ // Add source website as alias for target
123
+ target.websiteAliases = target.websiteAliases.concat(source.website);
124
+ target.websiteAliases = _.uniq(target.websiteAliases);
125
+
126
+ // mark as entered by system
127
+ target.entered = {
128
+ by: 'ff-merge',
129
+ on: new Date()
130
+ };
131
+
132
+ return cb(null, target);
133
+
134
+ };
135
+
136
+ var verifyOkToMerge = function verifyOkToMerge(target, source, cb) {
137
+
138
+ logger.writeToInfoLog('Verify ok to merge...');
139
+
140
+ // Cannot merge if target is a customer
141
+ if (target && target.customer && target.customer.totemUrl) { return cb(true, null); }
142
+
143
+ // Cannot merge if source is a customer
144
+ else if (source && source.customer && source.customer.totemUrl) { return cb(true, null); }
145
+
146
+ // Ok to merge
147
+ else { return cb(null, null); }
148
+
149
+ };
150
+
151
+ var updateReferences = function updateReferences(context, target, source, mergedBy, customerId, cb) {
152
+
153
+ logger.writeToInfoLog('Update references...');
154
+
155
+ // validate parameters
156
+ if (!context) return cb(new Error('context is required'), null);
157
+ if (!target) return cb(new Error('target is required'), null);
158
+ if (!source) return cb(new Error('source is required'), null);
159
+ if (!cb) throw new Error('cb is required');
160
+
161
+ var oldOrgId = ObjectId(source.id);
162
+ var newOrgId = ObjectId(target.id);
163
+
164
+ logger.writeToInfoLog(' Target: ' + newOrgId.toString());
165
+ logger.writeToInfoLog(' Source: ' + oldOrgId.toString());
166
+
167
+ // mergedBy can be either an account or a username
168
+ var username = mergedBy.username ? mergedBy.username : mergedBy;
169
+
170
+ // Do not update cap tables, financials or rounds as these are complicated
171
+ // and get cleaned and updated on each pull anyway
172
+
173
+ async.parallel([
174
+ updateDeals.bind(context, newOrgId, oldOrgId, mergedBy, customerId),
175
+ updateLists.bind(context, newOrgId, oldOrgId, username),
176
+ updateMessages.bind(context, newOrgId, oldOrgId, username),
177
+ updateNews.bind(context, newOrgId, oldOrgId, username),
178
+ updateOrganizations.bind(context, newOrgId, oldOrgId, username)
179
+ ], cb)
180
+
181
+ };
182
+
183
+ var updateDeals = function updateDeals(newOrgId, oldOrgId, user, customerId, cb) {
184
+
185
+ logger.writeToInfoLog(' Updating deals...');
186
+
187
+ var self = this;
188
+
189
+ // Get all deals for this org
190
+ self.Deal.collection.find({ 'organization': oldOrgId }).toArray(function(err, items) {
191
+
192
+ if (err) return cb(err, null);
193
+ else if (!items || items.length === 0) return cb(null, []);
194
+
195
+ var tasks = [];
196
+ var updated = [];
197
+
198
+ _.each(items, function(item) {
199
+ tasks.push({
200
+ id: item._id,
201
+ update: { $set: { organization: newOrgId } }
202
+ });
203
+ });
204
+
205
+ logger.writeToInfoLog(' Found ' + tasks.length + ' deal references to update');
206
+
207
+ var queue = async.queue(function(task, callback) {
208
+ self.Deal.modifyById(task.id, task.update, { CUSTOMER_ID: customerId }, function(err, result) {
209
+ if (err) { return callback(err, null); }
210
+ else if (result) { updated.push(result); }
211
+ return callback(null, result);
212
+ });
213
+ }, 8);
214
+
215
+ queue.drain = function() { return cb(null, updated); };
216
+
217
+ queue.push(tasks);
218
+
219
+ });
220
+
221
+ };
222
+
223
+ var updateLists = function updateLists(newOrgId, oldOrgId, user, cb) {
224
+
225
+ logger.writeToInfoLog(' Updating lists...');
226
+
227
+ var self = this;
228
+
229
+ self.List.collection.find({ 'organizations': oldOrgId }).toArray(function(err, items) {
230
+
231
+ if (err) return cb(err, null);
232
+ else if (!items || items.length === 0) return cb(null, []);
233
+
234
+ var tasks = [];
235
+ var updated = [];
236
+
237
+ _.each(items, function(item) {
238
+
239
+ var orgs = _.map(item.organizations, function(o) {
240
+ if (o.toString() === oldOrgId.toString()) { o = newOrgId; }
241
+ return o;
242
+ });
243
+
244
+ tasks.push({
245
+ id: item._id,
246
+ update: { $set: { organizations: orgs } }
247
+ });
248
+
249
+ });
250
+
251
+ logger.writeToInfoLog(' Found ' + tasks.length + ' list references to update');
252
+
253
+ var queue = async.queue(function(task, callback) {
254
+ self.List.modifyById(task.id, task.update, function(err, result) {
255
+ if (err) { return callback(err, null); }
256
+ else if (result) { updated.push(result); }
257
+ return callback(null, result);
258
+ });
259
+ }, 8);
260
+
261
+ queue.drain = function() { return cb(null, updated); };
262
+
263
+ queue.push(tasks);
264
+
265
+ });
266
+
267
+ };
268
+
269
+ var updateMessages = function updateMessages(newOrgId, oldOrgId, user, cb) {
270
+
271
+ logger.writeToInfoLog(' Updating messages...');
272
+
273
+ var self = this;
274
+
275
+ self.Message.collection.find({ 'organization': oldOrgId }).toArray(function(err, items) {
276
+
277
+ if (err) return cb(err, null);
278
+ else if (!items || items.length === 0) return cb(null, []);
279
+
280
+ var tasks = [];
281
+ var updated = [];
282
+
283
+ _.each(items, function(item) {
284
+ tasks.push({
285
+ id: item._id,
286
+ update: { $set: { organization: newOrgId } }
287
+ });
288
+ });
289
+
290
+ logger.writeToInfoLog(' Found ' + tasks.length + ' message references to update');
291
+
292
+ var queue = async.queue(function(task, callback) {
293
+ self.Message.modifyById(task.id, task.update, function(err, result) {
294
+ if (err) { return callback(err, null); }
295
+ else if (result) { updated.push(result); }
296
+ return callback(null, result);
297
+ });
298
+ }, 8);
299
+
300
+ queue.drain = function() { return cb(null, updated); };
301
+
302
+ queue.push(tasks);
303
+
304
+ });
305
+
306
+ };
307
+
308
+ var updateNews = function updateNews(newOrgId, oldOrgId, user, cb) {
309
+
310
+ logger.writeToInfoLog(' Updating news...');
311
+
312
+ var self = this;
313
+
314
+ self.News.collection.find({ 'org': oldOrgId }).toArray(function(err, items) {
315
+
316
+ if (err) return cb(err, null);
317
+ else if (!items || items.length === 0) return cb(null, []);
318
+
319
+ var tasks = [];
320
+ var updated = [];
321
+
322
+ _.each(items, function(item) {
323
+ tasks.push({
324
+ id: item._id,
325
+ update: { $set: { org: newOrgId } }
326
+ });
327
+ });
328
+
329
+ logger.writeToInfoLog(' Found ' + tasks.length + ' news references to update');
330
+
331
+ var queue = async.queue(function(task, callback) {
332
+ self.News.modifyById(task.id, task.update, function(err, result) {
333
+ if (err) { return callback(err, null); }
334
+ else if (result) { updated.push(result); }
335
+ return callback(null, result);
336
+ });
337
+ }, 8);
338
+
339
+ queue.drain = function() { return cb(null, updated); };
340
+
341
+ queue.push(tasks);
342
+
343
+ });
344
+
345
+ };
346
+
347
+ var updateOrganizations = function updateOrganizations(newOrgId, oldOrgId, user, cb) {
348
+
349
+ logger.writeToInfoLog(' Updating orgs...');
350
+
351
+ var self = this;
352
+
353
+ self.Organization.collection.find({ $or: [{ 'merged': oldOrgId }, { 'operating.acquired.public.by': oldOrgId }, { 'operating.acquired.private.by': oldOrgId }, { 'related': oldOrgId }] }).toArray(function(err, items) {
354
+
355
+ if (err) return cb(err, null);
356
+ else if (!items || items.length === 0) return cb(null, []);
357
+
358
+ var tasks = [];
359
+ var updated = [];
360
+
361
+ _.each(items, function(item) {
362
+
363
+ var setObj = {};
364
+
365
+ setObj.merged = _.map(item.merged, function(o) {
366
+ if (o.toString() === oldOrgId) { o = newOrgId; }
367
+ return o;
368
+ });
369
+
370
+ setObj.related = _.map(item.related, function(o) {
371
+ if (o.toString() === oldOrgId) { o = newOrgId; }
372
+ return o;
373
+ });
374
+
375
+ var publicBy = item["operating.acquired.public.by"];
376
+ var privateBy = item["operating.acquired.private.by"];
377
+
378
+ if (publicBy && publicBy.toString() === oldOrgId) { setObj["operating.acquired.public.by"] = newOrgId; }
379
+ if (privateBy && privateBy.toString() === oldOrgId) { setObj["operating.acquired.private.by"] = newOrgId; }
380
+
381
+ tasks.push({
382
+ id: item._id,
383
+ update: {
384
+ $set: setObj
385
+ }
386
+ });
387
+
388
+ });
389
+
390
+ logger.writeToInfoLog(' Found ' + tasks.length + ' org references to update');
391
+
392
+ var queue = async.queue(function(task, callback) {
393
+ self.Organization.modifyById(task.id, task.update, function(err, result) {
394
+ if (err) { return callback(err, null); }
395
+ else if (result) { updated.push(result); }
396
+ return callback(null, result);
397
+ });
398
+ }, 8);
399
+
400
+ queue.drain = function() { return cb(null, updated); };
401
+
402
+ queue.push(tasks);
403
+
404
+ });
405
+
406
+ };
407
+
408
+ module.exports.merge = merge;