@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 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
- // name of the campaign, e.g., "2022 Annual Audit"
10
- campaign: { type: String, trim: true, required: true },
9
+ // campaign this communication is part of
10
+ campaign: { type: Schema.ObjectId, ref: 'LimitedPartnerCampaign', required: true },
11
11
 
12
- // customer sending this communication
13
- customer: { type: Schema.ObjectId, ref: 'Organization', required: true },
12
+ // the lp it's for
13
+ limitedPartner: { type: Schema.ObjectId, ref: 'LimitedPartner', required: true },
14
14
 
15
- // date and time to send
16
- sendOn: { type: Date, required: true },
15
+ // email of recipient from the lp
16
+ email: { type: String, trim: true, required: true },
17
17
 
18
- // email content
19
- email: {
18
+ // attach document to email (only option currently supported)
19
+ attachToEmail: { type: Boolean, required: true, default: true },
20
20
 
21
- // email subject
22
- subject: { type: String, trim: true, required: true },
21
+ // job was added to queue to send email
22
+ sentToQueue: { type: Boolean, required: true, default: false },
23
23
 
24
- // email body
25
- body: { type: String, trim: true, required: true },
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
- // whether the task has been sent to the queue
30
- sentToQueue: { type: Boolean, default: false },
30
+ // email tracking via postmark
31
+ emailStatus: { type: String, enum: [null, 'Sent', 'Bounced', 'Delivered', 'Opened', 'Clicked'], required: false },
31
32
 
32
- limitedPartners: [{
33
+ // the documents included in this communication
34
+ documents: [{
33
35
 
34
- // the lp it's for
35
- limitedPartner: { type: Schema.ObjectId, ref: 'LimitedPartner', required: true },
36
+ fileName: { type: String, trim: true, required: true },
36
37
 
37
- // attach documents to email (only option currently supported)
38
- attachToEmail: { type: Boolean, required: true, default: true },
38
+ // file type
39
+ contentType: { type: String, trim: true, required: true },
39
40
 
40
- // the documents included in this communication
41
- documents: [{
41
+ // file size
42
+ contentLength: { type: String, trim: true, required: true },
42
43
 
43
- fileName: { type: String, trim: true, required: true },
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
- // file type
46
- contentType: { type: String, trim: true, required: true },
50
+ }]
47
51
 
48
- // file size
49
- contentLength: { type: String, trim: true, required: true },
52
+ });
50
53
 
51
- // where to find in s3
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
- // So we can put these on lp pages
71
- LimitedPartnerCommunication.statics.getForLimitedPartner = function getForLimitedPartner(lpid, options, cb) {
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 (!lpid) { return cb(new Error('lpid is required'), null); }
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
- 'limitedPartners.limitedPartner': lpid,
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
- // Get all communications that haven't been sent but are scheduled to go
92
- // Scheduled worker jobs will use this and add them to the queue to send
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
- sentToQueue: false,
102
- sendOn: { $lte: now }
103
+ limitedPartner: lpid,
104
+ customer: options.CUSTOMER_ID
103
105
  });
104
106
 
105
107
  query.exec(cb);
106
108
 
107
109
  };
108
110
 
109
- // For the "Historical" page
110
- LimitedPartnerCommunication.statics.getSentForCustomer = function getSentForCustomer(customerId, options, cb) {
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
- customer: customerId,
120
- sentOn: { $ne: null }
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
- // For the "Scheduled" page
128
- LimitedPartnerCommunication.statics.getUnsentForCustomer = function getUnsentForCustomer(customerId, options, cb) {
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 (!customerId) { return cb(new Error('customerId is required'), null); }
134
- if (!mongoose.Types.ObjectId.isValid(customerId)) { return cb(new Error('customerId is not a valid ObjectId'), null); }
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
- let query = self.find({
137
- customer: customerId,
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.delete = function(id, options, cb) {
148
+ LimitedPartnerCommunication.statics.removeById = function removeById(id, options, cb) {
146
149
 
147
- let self = this;
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
- let query = self.findOne({
159
- '_id': id,
160
- 'customer': options.CUSTOMER_ID
156
+ const query = self.findByIdAndRemove({
157
+ id: id
161
158
  });
162
159
 
163
- query.exec(function(err, doc) {
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
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dhyasama/totem-models",
3
- "version": "9.64.1",
3
+ "version": "9.66.0",
4
4
  "author": "Jason Reynolds",
5
5
  "license": "UNLICENSED",
6
6
  "description": "Models for Totem platform",