-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Updated notification support #131
Changes from 9 commits
e587e1e
5b92b3b
0b250b4
db970a1
28782a7
cbc9d09
fce3329
0b3b65f
1182c44
001e796
44f8728
b847404
9f96f5b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<p>Campaign "{{ campaign.name }}" was created.</p> | ||
|
||
<p>Click here to submit your creatives: <a href="{{ materialCollectUri }}">{{ materialCollectUri }}</a></p> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
<p>Campaign "{{ campaign.name }}" has ended.</p> | ||
|
||
<p>Click here to view the summary report: <a href="{{ reportSummaryUri }}">{{ reportSummaryUri }}</a></p> | ||
|
||
<p>Click here to view the creative report: <a href="{{ reportCreativeUri }}">{{ reportCreativeUri }}</a></p> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
<p>Campaign "{{ campaign.name }}" has started.</p> |
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,12 @@ const getNotifyDefaults = async (advertiserId, user) => { | |
return notify; | ||
}; | ||
|
||
const updateNotifications = async (campaignId) => { | ||
contactNotifier.scheduleCampaignCreated({ campaignId }); | ||
contactNotifier.scheduleCampaignStarted({ campaignId }); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, have a look at the |
||
contactNotifier.scheduleCampaignEnded({ campaignId }); | ||
}; | ||
|
||
module.exports = { | ||
/** | ||
* | ||
|
@@ -111,26 +117,29 @@ module.exports = { | |
payload.criteria = { start: payload.startDate }; | ||
payload.notify = await getNotifyDefaults(payload.advertiserId, auth.user); | ||
const campaign = await CampaignRepo.create(payload); | ||
contactNotifier.sendInternalCampaignCreated({ campaign }); | ||
contactNotifier.sendExternalCampaignCreated({ campaign }); | ||
await updateNotifications(campaign.id); | ||
return campaign; | ||
}, | ||
|
||
/** | ||
* | ||
*/ | ||
updateCampaign: (root, { input }, { auth }) => { | ||
updateCampaign: async (root, { input }, { auth }) => { | ||
auth.check(); | ||
const { id, payload } = input; | ||
return CampaignRepo.update(id, payload); | ||
const campaign = await CampaignRepo.update(id, payload); | ||
await updateNotifications(id); | ||
return campaign; | ||
}, | ||
|
||
assignCampaignValue: async (root, { input }) => { | ||
const { id, field, value } = input; | ||
const campaign = await Campaign.findById(id); | ||
if (!campaign) throw new Error(`Unable to assign field '${field}' to campaign: no record found for id '${id}'`); | ||
campaign.set(field, value); | ||
return campaign.save(); | ||
await campaign.save(); | ||
await updateNotifications(id); | ||
return campaign; | ||
}, | ||
|
||
/** | ||
|
@@ -139,7 +148,9 @@ module.exports = { | |
campaignCriteria: async (root, { input }, { auth }) => { | ||
auth.check(); | ||
const { campaignId, payload } = input; | ||
return CriteriaRepo.setFor(campaignId, payload); | ||
const criteria = await CriteriaRepo.setFor(campaignId, payload); | ||
await updateNotifications(campaignId); | ||
return criteria; | ||
}, | ||
|
||
campaignUrl: async (root, { input }, { auth }) => { | ||
|
@@ -148,16 +159,20 @@ module.exports = { | |
const campaign = await Campaign.findById(campaignId); | ||
if (!campaign) throw new Error(`Unable to set campaign URL: no campaign found for '${campaignId}'`); | ||
campaign.url = url; | ||
return campaign.save(); | ||
await campaign.save(); | ||
await updateNotifications(campaignId); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO yes, as any campaign field could be used within the email message itself, and changes to criteria would necessitate changes to delivery |
||
return campaign; | ||
}, | ||
|
||
/** | ||
* | ||
*/ | ||
addCampaignCreative: (root, { input }, { auth }) => { | ||
addCampaignCreative: async (root, { input }, { auth }) => { | ||
const { campaignId, payload } = input; | ||
auth.checkCampaignAccess(campaignId); | ||
return CreativeRepo.createFor(campaignId, payload); | ||
const creative = await CreativeRepo.createFor(campaignId, payload); | ||
await updateNotifications(campaignId); | ||
return creative; | ||
}, | ||
|
||
/** | ||
|
@@ -167,6 +182,7 @@ module.exports = { | |
const { campaignId, creativeId } = input; | ||
auth.checkCampaignAccess(campaignId); | ||
await CreativeRepo.removeFrom(campaignId, creativeId); | ||
await updateNotifications(campaignId); | ||
return 'ok'; | ||
}, | ||
|
||
|
@@ -176,7 +192,9 @@ module.exports = { | |
campaignCreativeStatus: async (root, { input }, { auth }) => { | ||
auth.check(); | ||
const { campaignId, creativeId, status } = input; | ||
return CreativeRepo.setStatusFor(campaignId, creativeId, status); | ||
const saved = await CreativeRepo.setStatusFor(campaignId, creativeId, status); | ||
await updateNotifications(campaignId); | ||
return saved; | ||
}, | ||
|
||
/** | ||
|
@@ -186,7 +204,13 @@ module.exports = { | |
const { campaignId, creativeId, payload } = input; | ||
auth.checkCampaignAccess(campaignId); | ||
const { title, teaser, status } = payload; | ||
return CreativeRepo.updateDetailsFor(campaignId, creativeId, { title, teaser, status }); | ||
const details = await CreativeRepo.updateDetailsFor( | ||
campaignId, | ||
creativeId, | ||
{ title, teaser, status }, | ||
); | ||
await updateNotifications(campaignId); | ||
return details; | ||
}, | ||
|
||
/** | ||
|
@@ -195,16 +219,20 @@ module.exports = { | |
campaignCreativeImage: async (root, { input }, { auth }) => { | ||
const { campaignId, creativeId, imageId } = input; | ||
auth.checkCampaignAccess(campaignId); | ||
return CreativeRepo.updateImageFor(campaignId, creativeId, imageId); | ||
const image = await CreativeRepo.updateImageFor(campaignId, creativeId, imageId); | ||
await updateNotifications(campaignId); | ||
return image; | ||
}, | ||
|
||
/** | ||
* | ||
*/ | ||
campaignContacts: (root, { input }, { auth }) => { | ||
campaignContacts: async (root, { input }, { auth }) => { | ||
auth.check(); | ||
const { id, type, contactIds } = input; | ||
return ContactRepo.setContactsFor(Campaign, id, type, contactIds); | ||
const contacts = await ContactRepo.setContactsFor(Campaign, id, type, contactIds); | ||
await updateNotifications(id); | ||
return contacts; | ||
}, | ||
}, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
const mongoose = require('../connections/mongoose/instance'); | ||
const schema = require('../schema/campaign-notification'); | ||
|
||
module.exports = mongoose.model('campaign-notification', schema); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
const { Schema } = require('mongoose'); | ||
const connection = require('../connections/mongoose/instance'); | ||
|
||
const schema = new Schema({ | ||
campaignId: { | ||
type: Schema.Types.ObjectId, | ||
required: true, | ||
validate: { | ||
async validator(v) { | ||
const doc = await connection.model('campaign').findOne({ _id: v }, { _id: 1 }); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Change to |
||
if (doc) return true; | ||
return false; | ||
}, | ||
message: 'No campaign found for ID {VALUE}', | ||
}, | ||
}, | ||
type: { | ||
type: String, | ||
enum: ['Campaign Created', 'Campaign Started', 'Campaign Ended'], | ||
required: true, | ||
}, | ||
status: { | ||
type: String, | ||
enum: ['Pending', 'Sending', 'Sent', 'Errored'], | ||
default: 'Pending', | ||
}, | ||
error: String, | ||
sendAt: { | ||
type: Date, | ||
required: true, | ||
default: () => new Date(), | ||
}, | ||
|
||
to: [String], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At least one two value is required, correct? |
||
cc: [String], | ||
bcc: [String], | ||
|
||
subject: String, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should subject, text, and html all be required? Well, maybe not text |
||
text: String, | ||
html: String, | ||
}, { timestamps: true }); | ||
|
||
|
||
module.exports = schema; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -93,6 +93,27 @@ schema.pre('save', async function setAdvertiserName() { | |
} | ||
}); | ||
|
||
schema.virtual('portalUri').get(async function getPortalUri() { | ||
const advertiser = await connection.model('advertiser').findOne({ _id: this.advertiserId }, { pushId: 1 }); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
const uri = await advertiser.get('portalUri'); | ||
return `${uri}/campaigns/${this.pushId}`; | ||
}); | ||
|
||
schema.virtual('vMaterialCollectUri').get(async function getVMCU() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we consolidate all these virtuals to a subdoc? It's getting pretty dirty at the root :) And why the |
||
const uri = await this.get('portalUri'); | ||
return `${uri}/materials`; | ||
}); | ||
|
||
schema.virtual('vReportSummaryUri').get(async function getVRSU() { | ||
const uri = await this.get('portalUri'); | ||
return `${uri}/report/summary`; | ||
}); | ||
|
||
schema.virtual('vReportCreativeUri').get(async function getVRCU() { | ||
const uri = await this.get('portalUri'); | ||
return `${uri}/report/creative-breakdown`; | ||
}); | ||
|
||
schema.plugin(notifyPlugin); | ||
schema.plugin(pushIdPlugin, { required: true }); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
updateNotifications
isn't awaiting the scheduled email calls, is that intentional?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes