@dhyasama/totem-models 9.64.1 → 9.66.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 +1 -0
- package/lib/LimitedPartnerCampaign.js +151 -0
- package/lib/LimitedPartnerCommunication.js +75 -87
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -56,6 +56,7 @@ var bootstrap = function(mongoose, config) {
|
|
|
56
56
|
require('./lib/Interaction.js')(mongoose, config);
|
|
57
57
|
require('./lib/Investment.js')(mongoose, config);
|
|
58
58
|
require('./lib/List.js')(mongoose, config);
|
|
59
|
+
require('./lib/LimitedPartnerCampaign.js')(mongoose, config);
|
|
59
60
|
require('./lib/LimitedPartnerContactGroup.js')(mongoose, config);
|
|
60
61
|
require('./lib/LimitedPartnerCommunication.js')(mongoose, config);
|
|
61
62
|
require('./lib/Message.js')(mongoose, config);
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('underscore');
|
|
4
|
+
|
|
5
|
+
module.exports = function(mongoose, config) {
|
|
6
|
+
|
|
7
|
+
const Schema = mongoose.Schema;
|
|
8
|
+
|
|
9
|
+
const LimitedPartnerCampaign = new Schema({
|
|
10
|
+
|
|
11
|
+
// name of the campaign, e.g., "2022 Annual Audit"
|
|
12
|
+
name: { type: String, trim: true, required: true },
|
|
13
|
+
|
|
14
|
+
// customer sending this communication
|
|
15
|
+
customer: { type: Schema.ObjectId, ref: 'Organization', required: true },
|
|
16
|
+
|
|
17
|
+
// date and time to send
|
|
18
|
+
sendOn: { type: Date, required: true },
|
|
19
|
+
|
|
20
|
+
// email subject
|
|
21
|
+
subject: { type: String, trim: true, required: true },
|
|
22
|
+
|
|
23
|
+
// email body
|
|
24
|
+
body: { type: String, trim: true, required: true },
|
|
25
|
+
|
|
26
|
+
// job was added to queue to send emails
|
|
27
|
+
sentToQueue: { type: Boolean, required: true, default: false },
|
|
28
|
+
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
LimitedPartnerCampaign.statics.getById = function getById(campaignId, customerId, options, cb) {
|
|
32
|
+
|
|
33
|
+
const self = this;
|
|
34
|
+
|
|
35
|
+
if (!cb) { throw new Error('cb is required'); }
|
|
36
|
+
if (!campaignId) { return cb(new Error('campaignId is required'), null); }
|
|
37
|
+
if (!mongoose.Types.ObjectId.isValid(campaignId)) { return cb(new Error('campaignId is not a valid ObjectId'), null); }
|
|
38
|
+
if (!customerId) { return cb(new Error('customerId is required'), null); }
|
|
39
|
+
if (!mongoose.Types.ObjectId.isValid(customerId)) { return cb(new Error('customerId is not a valid ObjectId'), null); }
|
|
40
|
+
|
|
41
|
+
const query = self.findOne({
|
|
42
|
+
id: campaignId,
|
|
43
|
+
customer: customerId
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
query.exec(cb);
|
|
47
|
+
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Scheduled but not sent and now isn't the time
|
|
51
|
+
LimitedPartnerCampaign.statics.getFuture = function getFuture(customerId, options, cb) {
|
|
52
|
+
|
|
53
|
+
const self = this;
|
|
54
|
+
const now = new Date();
|
|
55
|
+
|
|
56
|
+
if (!cb) { throw new Error('cb is required'); }
|
|
57
|
+
if (!customerId) { return cb(new Error('customerId is required'), null); }
|
|
58
|
+
if (!mongoose.Types.ObjectId.isValid(customerId)) { return cb(new Error('customerId is not a valid ObjectId'), null); }
|
|
59
|
+
|
|
60
|
+
const query = self.find({
|
|
61
|
+
customer: customerId,
|
|
62
|
+
sentToQueue: false,
|
|
63
|
+
sendOn: { $gte: now }
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
query.exec(cb);
|
|
67
|
+
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// Scheduled and not yet sent but now is the time
|
|
71
|
+
// Note this doesn't use customer id because it's for the worker and we want all customers.
|
|
72
|
+
LimitedPartnerCampaign.statics.getOutbound = function getOutbound(options, cb) {
|
|
73
|
+
|
|
74
|
+
const self = this;
|
|
75
|
+
const now = new Date();
|
|
76
|
+
|
|
77
|
+
if (!cb) { throw new Error('cb is required'); }
|
|
78
|
+
|
|
79
|
+
let query = self.find({
|
|
80
|
+
sentToQueue: false,
|
|
81
|
+
sendOn: { $lte: now }
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
query.exec(cb);
|
|
85
|
+
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Already sent
|
|
89
|
+
LimitedPartnerCampaign.statics.getPrevious = function getPrevious(customerId, options, cb) {
|
|
90
|
+
|
|
91
|
+
const self = this;
|
|
92
|
+
|
|
93
|
+
if (!cb) { throw new Error('cb is required'); }
|
|
94
|
+
if (!customerId) { return cb(new Error('customerId is required'), null); }
|
|
95
|
+
if (!mongoose.Types.ObjectId.isValid(customerId)) { return cb(new Error('customerId is not a valid ObjectId'), null); }
|
|
96
|
+
|
|
97
|
+
// No need to check send on. If sentToQueue then safe to assume sendOn is in the past.
|
|
98
|
+
|
|
99
|
+
const query = self.find({
|
|
100
|
+
customer: customerId,
|
|
101
|
+
sentToQueue: true
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
query.exec(cb);
|
|
105
|
+
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
LimitedPartnerCampaign.statics.remove = function remove(campaignId, customerId, options, cb) {
|
|
109
|
+
|
|
110
|
+
const self = this;
|
|
111
|
+
|
|
112
|
+
if (!cb) { throw new Error('cb is required'); }
|
|
113
|
+
if (!campaignId) { return cb(new Error('campaignId is required'), null); }
|
|
114
|
+
if (!mongoose.Types.ObjectId.isValid(campaignId)) { return cb(new Error('campaignId is not a valid ObjectId'), null); }
|
|
115
|
+
if (!customerId) { return cb(new Error('customerId is required'), null); }
|
|
116
|
+
if (!mongoose.Types.ObjectId.isValid(customerId)) { return cb(new Error('customerId is not a valid ObjectId'), null); }
|
|
117
|
+
|
|
118
|
+
const query = self.findOneAndRemove({
|
|
119
|
+
id: campaignId,
|
|
120
|
+
customer: customerId
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
query.exec(cb);
|
|
124
|
+
|
|
125
|
+
// remove associated limited partner communications at the business logic layer
|
|
126
|
+
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
LimitedPartnerCampaign.statics.upsert = function upsert(doc, options, cb) {
|
|
130
|
+
|
|
131
|
+
if (!doc) { return cb(new Error('doc is required'), null); }
|
|
132
|
+
|
|
133
|
+
doc.save(cb);
|
|
134
|
+
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
///////////////////////////////////////////////////////////////////////////////////////
|
|
139
|
+
// CONFIG
|
|
140
|
+
///////////////////////////////////////////////////////////////////////////////////////
|
|
141
|
+
|
|
142
|
+
LimitedPartnerCampaign.set('usePushEach', true);
|
|
143
|
+
LimitedPartnerCampaign.set('toJSON', { virtuals: true });
|
|
144
|
+
LimitedPartnerCampaign.set('autoIndex', false);
|
|
145
|
+
LimitedPartnerCampaign.set('usePushEach', true);
|
|
146
|
+
|
|
147
|
+
LimitedPartnerCampaign.on('index', function(err) { console.log('error building LimitedPartnerCampaign indexes: ' + err); });
|
|
148
|
+
|
|
149
|
+
mongoose.model('LimitedPartnerCampaign', LimitedPartnerCampaign);
|
|
150
|
+
|
|
151
|
+
};
|
|
@@ -6,81 +6,80 @@ module.exports = function(mongoose, config) {
|
|
|
6
6
|
|
|
7
7
|
const LimitedPartnerCommunication = new Schema({
|
|
8
8
|
|
|
9
|
-
//
|
|
10
|
-
campaign: { type:
|
|
9
|
+
// campaign this communication is part of
|
|
10
|
+
campaign: { type: Schema.ObjectId, ref: 'LimitedPartnerCampaign', required: true },
|
|
11
11
|
|
|
12
|
-
//
|
|
13
|
-
|
|
12
|
+
// the lp it's for
|
|
13
|
+
limitedPartner: { type: Schema.ObjectId, ref: 'LimitedPartner', required: true },
|
|
14
14
|
|
|
15
|
-
//
|
|
16
|
-
|
|
15
|
+
// email of recipient from the lp
|
|
16
|
+
email: { type: String, trim: true, required: true },
|
|
17
17
|
|
|
18
|
-
// email
|
|
19
|
-
|
|
18
|
+
// attach document to email (only option currently supported)
|
|
19
|
+
attachToEmail: { type: Boolean, required: true, default: true },
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
// job was added to queue to send email
|
|
22
|
+
sentToQueue: { type: Boolean, required: true, default: false },
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
// when email was sent
|
|
25
|
+
sentOn: { type: Date, required: false },
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
// postmark reference
|
|
28
|
+
postmarkMessageId: { type: String, trim: true, required: false },
|
|
28
29
|
|
|
29
|
-
//
|
|
30
|
-
|
|
30
|
+
// email tracking via postmark
|
|
31
|
+
emailStatus: { type: String, enum: [null, 'Sent', 'Bounced', 'Delivered', 'Opened', 'Clicked'], required: false },
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
// the documents included in this communication
|
|
34
|
+
documents: [{
|
|
33
35
|
|
|
34
|
-
|
|
35
|
-
limitedPartner: { type: Schema.ObjectId, ref: 'LimitedPartner', required: true },
|
|
36
|
+
fileName: { type: String, trim: true, required: true },
|
|
36
37
|
|
|
37
|
-
//
|
|
38
|
-
|
|
38
|
+
// file type
|
|
39
|
+
contentType: { type: String, trim: true, required: true },
|
|
39
40
|
|
|
40
|
-
//
|
|
41
|
-
|
|
41
|
+
// file size
|
|
42
|
+
contentLength: { type: String, trim: true, required: true },
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
// where to find in s3
|
|
45
|
+
s3: {
|
|
46
|
+
bucket: { type: String, required: true, trim: true },
|
|
47
|
+
key: { type: String, required: true, trim: true }
|
|
48
|
+
}
|
|
44
49
|
|
|
45
|
-
|
|
46
|
-
contentType: { type: String, trim: true, required: true },
|
|
50
|
+
}]
|
|
47
51
|
|
|
48
|
-
|
|
49
|
-
contentLength: { type: String, trim: true, required: true },
|
|
52
|
+
});
|
|
50
53
|
|
|
51
|
-
|
|
52
|
-
s3: {
|
|
53
|
-
bucket: { type: String, required: true, trim: true },
|
|
54
|
-
key: { type: String, required: true, trim: true }
|
|
55
|
-
}
|
|
54
|
+
LimitedPartnerCommunication.statics.getByCampaign = function getByCampaign(campaignId, options, cb) {
|
|
56
55
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
notifications: [{
|
|
60
|
-
sendTo: { type: String, trim: true },
|
|
61
|
-
sentOn: { type: Date, required: false },
|
|
62
|
-
postmarkMessageId: { type: String, trim: true },
|
|
63
|
-
status: { type: String, enum: [null, 'Sent', 'Bounced', 'Delivered', 'Opened', 'Clicked']}
|
|
64
|
-
}],
|
|
56
|
+
const self = this;
|
|
65
57
|
|
|
66
|
-
}
|
|
58
|
+
if (!cb) { throw new Error('cb is required'); }
|
|
59
|
+
if (!campaignId) { return cb(new Error('campaignId is required'), null); }
|
|
60
|
+
if (!mongoose.Types.ObjectId.isValid(campaignId)) { return cb(new Error('campaignId is not a valid ObjectId'), null); }
|
|
67
61
|
|
|
68
|
-
|
|
62
|
+
let query = self.find({
|
|
63
|
+
campaign: campaignId
|
|
64
|
+
});
|
|
69
65
|
|
|
70
|
-
|
|
71
|
-
|
|
66
|
+
query.exec(cb);
|
|
67
|
+
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// So we can put these on person pages
|
|
71
|
+
LimitedPartnerCommunication.statics.getByEmail = function getByEmail(email, options, cb) {
|
|
72
72
|
|
|
73
73
|
const self = this;
|
|
74
74
|
|
|
75
75
|
if (!cb) { throw new Error('cb is required'); }
|
|
76
|
-
if (!
|
|
77
|
-
if (!mongoose.Types.ObjectId.isValid(lpid)) { return cb(new Error('lpid is not a valid ObjectId'), null); }
|
|
76
|
+
if (!email) { return cb(new Error('email is required'), null); }
|
|
78
77
|
if (!options) { return cb(new Error('options is required'), null); }
|
|
79
78
|
if (!options.CUSTOMER_ID) { return cb(new Error('options.CUSTOMER_ID is required'), null); }
|
|
80
79
|
if (!mongoose.Types.ObjectId.isValid(options.CUSTOMER_ID)) { return cb(new Error('options.CUSTOMER_ID is not a valid ObjectId'), null); }
|
|
81
80
|
|
|
82
81
|
let query = self.find({
|
|
83
|
-
|
|
82
|
+
email: email,
|
|
84
83
|
customer: options.CUSTOMER_ID
|
|
85
84
|
});
|
|
86
85
|
|
|
@@ -88,88 +87,77 @@ module.exports = function(mongoose, config) {
|
|
|
88
87
|
|
|
89
88
|
};
|
|
90
89
|
|
|
91
|
-
//
|
|
92
|
-
|
|
93
|
-
LimitedPartnerCommunication.statics.getReadyToSend = function getReadyToSend(options, cb) {
|
|
90
|
+
// So we can put these on lp pages
|
|
91
|
+
LimitedPartnerCommunication.statics.getForLimitedPartner = function getForLimitedPartner(lpid, options, cb) {
|
|
94
92
|
|
|
95
93
|
const self = this;
|
|
96
|
-
const now = new Date();
|
|
97
94
|
|
|
98
95
|
if (!cb) { throw new Error('cb is required'); }
|
|
96
|
+
if (!lpid) { return cb(new Error('lpid is required'), null); }
|
|
97
|
+
if (!mongoose.Types.ObjectId.isValid(lpid)) { return cb(new Error('lpid is not a valid ObjectId'), null); }
|
|
98
|
+
if (!options) { return cb(new Error('options is required'), null); }
|
|
99
|
+
if (!options.CUSTOMER_ID) { return cb(new Error('options.CUSTOMER_ID is required'), null); }
|
|
100
|
+
if (!mongoose.Types.ObjectId.isValid(options.CUSTOMER_ID)) { return cb(new Error('options.CUSTOMER_ID is not a valid ObjectId'), null); }
|
|
99
101
|
|
|
100
102
|
let query = self.find({
|
|
101
|
-
|
|
102
|
-
|
|
103
|
+
limitedPartner: lpid,
|
|
104
|
+
customer: options.CUSTOMER_ID
|
|
103
105
|
});
|
|
104
106
|
|
|
105
107
|
query.exec(cb);
|
|
106
108
|
|
|
107
109
|
};
|
|
108
110
|
|
|
109
|
-
//
|
|
110
|
-
|
|
111
|
+
// Get all communications that haven't been sent but are scheduled to go
|
|
112
|
+
// Scheduled worker jobs will use this and add them to the queue to send
|
|
113
|
+
LimitedPartnerCommunication.statics.getReadyToSend = function getReadyToSend(options, cb) {
|
|
111
114
|
|
|
112
115
|
const self = this;
|
|
116
|
+
const now = new Date();
|
|
113
117
|
|
|
114
118
|
if (!cb) { throw new Error('cb is required'); }
|
|
115
|
-
if (!customerId) { return cb(new Error('customerId is required'), null); }
|
|
116
|
-
if (!mongoose.Types.ObjectId.isValid(customerId)) { return cb(new Error('customerId is not a valid ObjectId'), null); }
|
|
117
119
|
|
|
118
120
|
let query = self.find({
|
|
119
|
-
|
|
120
|
-
|
|
121
|
+
sentToQueue: false,
|
|
122
|
+
sendOn: { $lte: now }
|
|
121
123
|
});
|
|
122
124
|
|
|
125
|
+
query.populate('campaign');
|
|
126
|
+
|
|
123
127
|
query.exec(cb);
|
|
124
128
|
|
|
125
129
|
};
|
|
126
130
|
|
|
127
|
-
//
|
|
128
|
-
LimitedPartnerCommunication.statics.
|
|
131
|
+
// Remove all the docs associated with a campaign
|
|
132
|
+
LimitedPartnerCommunication.statics.removeByCampaign = function removeByCampaign(campaignId, options, cb) {
|
|
129
133
|
|
|
130
134
|
const self = this;
|
|
131
135
|
|
|
132
136
|
if (!cb) { throw new Error('cb is required'); }
|
|
133
|
-
if (!
|
|
134
|
-
if (!mongoose.Types.ObjectId.isValid(
|
|
137
|
+
if (!campaignId) { return cb(new Error('campaignId is required'), null); }
|
|
138
|
+
if (!mongoose.Types.ObjectId.isValid(campaignId)) { return cb(new Error('campaignId is not a valid ObjectId'), null); }
|
|
135
139
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
sentOn: null
|
|
140
|
+
const query = self.deleteMany({
|
|
141
|
+
campaign: campaignId
|
|
139
142
|
});
|
|
140
143
|
|
|
141
144
|
query.exec(cb);
|
|
142
145
|
|
|
143
146
|
};
|
|
144
147
|
|
|
145
|
-
LimitedPartnerCommunication.statics.
|
|
148
|
+
LimitedPartnerCommunication.statics.removeById = function removeById(id, options, cb) {
|
|
146
149
|
|
|
147
|
-
|
|
150
|
+
const self = this;
|
|
148
151
|
|
|
149
152
|
if (!cb) { throw new Error('cb is required'); }
|
|
150
153
|
if (!id) { return cb(new Error('id is required'), null); }
|
|
151
154
|
if (!mongoose.Types.ObjectId.isValid(id)) { return cb(new Error('id is not a valid ObjectId'), null); }
|
|
152
|
-
if (!options) { return cb(new Error('options is required'), null); }
|
|
153
|
-
if (!options.CUSTOMER_ID) { return cb(new Error('options.CUSTOMER_ID is required'), null); }
|
|
154
|
-
if (!mongoose.Types.ObjectId.isValid(options.CUSTOMER_ID)) { return cb(new Error('options.CUSTOMER_ID is not a valid ObjectId'), null); }
|
|
155
|
-
|
|
156
|
-
// Not strictly necessary but provides verification that the document being deleted belongs to the customer doing the deleting
|
|
157
155
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
'customer': options.CUSTOMER_ID
|
|
156
|
+
const query = self.findByIdAndRemove({
|
|
157
|
+
id: id
|
|
161
158
|
});
|
|
162
159
|
|
|
163
|
-
query.exec(
|
|
164
|
-
|
|
165
|
-
if (err) return cb(err, null);
|
|
166
|
-
else if (!doc) return cb(null, null);
|
|
167
|
-
|
|
168
|
-
// No population so no need to scrub
|
|
169
|
-
|
|
170
|
-
doc.remove(cb);
|
|
171
|
-
|
|
172
|
-
});
|
|
160
|
+
query.exec(cb);
|
|
173
161
|
|
|
174
162
|
};
|
|
175
163
|
|
|
@@ -195,4 +183,4 @@ module.exports = function(mongoose, config) {
|
|
|
195
183
|
|
|
196
184
|
mongoose.model('LimitedPartnerCommunication', LimitedPartnerCommunication);
|
|
197
185
|
|
|
198
|
-
};
|
|
186
|
+
};
|