From 77aa695b210883100f0ff5017d747a2aa6148317 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Thu, 17 Jan 2019 12:50:14 -0600 Subject: [PATCH] Update schedules on line item save --- services/graphql/src/env.js | 1 + .../graphql/src/mongoose/schema/correlator.js | 4 +- services/graphql/src/mongoose/schema/image.js | 5 + .../graphql/src/mongoose/schema/lineitem.js | 97 +++++++++++-------- .../graphql/src/mongoose/schema/schedule.js | 9 +- 5 files changed, 72 insertions(+), 44 deletions(-) diff --git a/services/graphql/src/env.js b/services/graphql/src/env.js index 801bd0b..32ff568 100644 --- a/services/graphql/src/env.js +++ b/services/graphql/src/env.js @@ -19,6 +19,7 @@ module.exports = cleanEnv(process.env, { AWS_ACCESS_KEY_ID: nonemptystr({ desc: 'The AWS access key value.' }), AWS_SECRET_ACCESS_KEY: nonemptystr({ desc: 'The AWS secret access key value.' }), S3_BUCKET: nonemptystr({ desc: 'The S3 bucket for uploading images.', default: 'cdn.email-x.io' }), + CDN_HOST: nonemptystr({ desc: 'The CDN hostname for serving ad images.', default: 'cdn.email-x.io' }), MONGO_DSN: nonemptystr({ desc: 'The MongoDB DSN to connect to.' }), REDIS_DSN: nonemptystr({ desc: 'The Redis DSN to connect to.' }), INTERNAL_PORT: port({ desc: 'The internal port that express will run on.', default: 80 }), diff --git a/services/graphql/src/mongoose/schema/correlator.js b/services/graphql/src/mongoose/schema/correlator.js index e6261cd..dbb032a 100644 --- a/services/graphql/src/mongoose/schema/correlator.js +++ b/services/graphql/src/mongoose/schema/correlator.js @@ -1,12 +1,12 @@ const { Schema } = require('mongoose'); const schema = new Schema({ - correlator: String, + value: String, src: String, url: String, adId: Schema.Types.ObjectId, }); -schema.index({ correlator: 1 }); +schema.index({ value: 1 }, { unique: true }); module.exports = schema; diff --git a/services/graphql/src/mongoose/schema/image.js b/services/graphql/src/mongoose/schema/image.js index 5c97e0c..643eed3 100644 --- a/services/graphql/src/mongoose/schema/image.js +++ b/services/graphql/src/mongoose/schema/image.js @@ -1,4 +1,5 @@ const { Schema } = require('mongoose'); +const { CDN_HOST } = require('../../env'); const schema = new Schema({ filename: { @@ -36,4 +37,8 @@ const schema = new Schema({ }, }); +schema.virtual('serveSrc').get(function getServeSrc() { + return `https://${CDN_HOST}/${this.get('s3.key')}`; +}); + module.exports = schema; diff --git a/services/graphql/src/mongoose/schema/lineitem.js b/services/graphql/src/mongoose/schema/lineitem.js index d0b09a6..c7c9811 100644 --- a/services/graphql/src/mongoose/schema/lineitem.js +++ b/services/graphql/src/mongoose/schema/lineitem.js @@ -182,11 +182,6 @@ schema.method('getRequirements', async function getRequirements() { return needs.sort().join(', '); }); -schema.post('init', function setInitialStatus() { - this.$initialStatus = this.status; - this.$initialDates = this.dates; -}); - // @todo If the order name changes, this will also have to change. schema.pre('validate', async function setOrderAndAdvertiser() { if (this.isModified('orderId') || !this.orderName || !this.advertiserName || !this.advertiserId) { @@ -212,44 +207,70 @@ schema.pre('save', async function setReady() { } }); -const createSchedules = () => { +schema.post('save', async function updateSchedules() { + const lineitem = this; + const bulkOps = [ + { deleteMany: { filter: { lineitemId: lineitem._id } } }, + ]; -}; + const { targeting, priority, dates } = lineitem; + const { adunitIds, deploymentIds, publisherIds } = targeting || {}; -const handleSchedules = async (lineitem, create = false) => { - try { - await connection.model('schedule').remove({ lineitemId: lineitem.id }); - if (create) { - await createSchedules(lineitem); - } - } catch (e) { - // @todo Log to newrelic or whatever. - throw e; - } -}; + const ids = { + adunit: isArray(adunitIds) ? adunitIds : [], + deployment: isArray(deploymentIds) ? deploymentIds : [], + publisher: isArray(publisherIds) ? publisherIds : [], + }; -schema.post('save', async function updateSchedules() { - const hasStatusChanged = this.$initialStatus !== this.status; - const { $initialDates, dates } = this; + const ads = await connection.model('ad').find({ lineitemId: lineitem.id }); + const activeAds = ads.filter(ad => ad.status === 'Active'); - let haveDatesChanged = false; - if ($initialDates.type !== dates.type) { - haveDatesChanged = true; - } else if (dates.type === 'range') { - haveDatesChanged = dates.start.valueOf() !== $initialDates.start.valueOf() - || dates.end.valueOf() !== $initialDates.end.valueOf(); - } else { - const days = dates.days || []; - const initialDays = $initialDates.days || []; - haveDatesChanged = days.sort().toString() !== initialDays.sort().toString(); - } + const query = { + $or: [ + { _id: { $in: ids.adunit } }, + { deploymentId: { $in: ids.deployment } }, + { publisherId: { $in: ids.publisher } }, + ], + deleted: false, + }; + const adunits = await connection.model('adunit').find(query); - const activeStatuses = ['Running', 'Scheduled']; - if (hasStatusChanged) { - handleSchedules(this, activeStatuses.includes(this.status)); - } else if (haveDatesChanged) { - handleSchedules(this, true); - } + const endDay = day => new Date(day.valueOf() + (24 * 60 * 60 * 1000) - 1); + + const schedules = adunits.reduce((arr, adunit) => { + const elgible = activeAds + .filter(ad => ad.width === adunit.width && ad.height === adunit.height); + + if (elgible.length) { + const winners = elgible.map(ad => ({ _id: ad._id, url: ad.url, src: ad.image.serveSrc })); + if (dates.type === 'range') { + arr.push({ + lineitemId: lineitem._id, + adunitId: adunit._id, + priority, + start: dates.start, + end: dates.end, + ads: winners, + }); + } else { + dates.days.forEach((day) => { + arr.push({ + lineitemId: lineitem._id, + adunitId: adunit._id, + priority, + start: day, + end: endDay(day), + ads: winners, + }); + }); + } + } + return arr; + }, []); + schedules.forEach((schedule) => { + bulkOps.push({ insertOne: { document: schedule } }); + }); + return connection.model('schedule').bulkWrite(bulkOps); }); schema.index({ name: 1, _id: 1 }, { collation: { locale: 'en_US' } }); diff --git a/services/graphql/src/mongoose/schema/schedule.js b/services/graphql/src/mongoose/schema/schedule.js index 9107f28..17e3558 100644 --- a/services/graphql/src/mongoose/schema/schedule.js +++ b/services/graphql/src/mongoose/schema/schedule.js @@ -1,10 +1,10 @@ const { Schema } = require('mongoose'); const schema = new Schema({ - adUnitId: Schema.Types.ObjectId, + adunitId: Schema.Types.ObjectId, start: Date, end: Date, - lineItemId: Schema.Types.ObjectId, + lineitemId: Schema.Types.ObjectId, priority: Number, ads: [{ _id: Schema.Types.ObjectId, @@ -13,7 +13,8 @@ const schema = new Schema({ }], }); -schema.index({ adUnitId: 1, start: 1, end: 1 }); -schema.index({ adUnitId: 1, lineItemId: 1 }); +schema.index({ adunitId: 1, start: 1, end: 1 }); +schema.index({ lineitemId: 1 }); +schema.index({ priority: 1 }); module.exports = schema;