Vulcan/packages/nova-newsletter/lib/server/newsletter.js

165 lines
5.3 KiB
JavaScript
Raw Normal View History

2016-06-23 11:40:35 +09:00
import Posts from "meteor/nova:posts";
2016-06-23 12:17:39 +09:00
import Comments from "meteor/nova:comments";
2016-06-23 15:00:58 +09:00
import Users from 'meteor/nova:users';
2016-06-23 15:11:56 +09:00
import Categories from "meteor/nova:categories";
2016-06-23 16:42:06 +09:00
import NovaEmail from 'meteor/nova:email';
import { SyncedCron } from 'meteor/percolatestudio:synced-cron';
import moment from 'moment';
import Newsletter from '../namespace.js';
2016-12-12 15:00:56 +09:00
import { Utils, getSetting } from 'meteor/nova:core';
// create new "newsletter" view for all posts from the past X days that haven't been scheduled yet
Posts.views.add("newsletter", function (terms) {
return {
selector: {
scheduledAt: {$exists: false}
},
options: {
sort: {baseScore: -1},
limit: terms.limit
}
};
});
/**
* @summary Return an array containing the latest n posts that can be sent in a newsletter
* @param {Number} postsCount
*/
Newsletter.getPosts = function (postsCount) {
// look for last scheduled newsletter in the database
var lastNewsletter = SyncedCron._collection.findOne({name: 'scheduleNewsletter'}, {sort: {finishedAt: -1}, limit: 1});
// if there is a last newsletter and it was sent less than 7 days ago use its date, else default to posts from the last 7 days
var lastWeek = moment().subtract(7, 'days');
var after = (lastNewsletter && moment(lastNewsletter.finishedAt).isAfter(lastWeek)) ? lastNewsletter.finishedAt : lastWeek.format("YYYY-MM-DD");
// get parameters using "newsletter" view
var params = Posts.getParameters({
view: "newsletter",
after: after,
limit: postsCount
});
2016-04-09 10:45:27 +09:00
return Posts.find(params.selector, params.options).fetch();
};
/**
* @summary Build a newsletter campaign from an array of posts
* (Called from Newsletter.scheduleNextWithMailChimp)
* @param {Array} postsArray
*/
Newsletter.build = function (postsArray) {
var postsHTML = '', subject = '';
// 1. Iterate through posts and pass each of them through a handlebars template
postsArray.forEach(function (post, index) {
// add post title to email subject (don't add a coma for the first post)
if(index > 0) subject += ', ';
subject += post.title;
// get author of the current post
var postUser = Users.findOne(post.userId);
// the naked post object as stored in the database is missing a few properties, so let's add them
var properties = _.extend(post, {
authorName: post.getAuthorName(),
2015-06-19 09:48:59 +09:00
postLink: Posts.getLink(post, true),
profileUrl: Users.getProfileUrl(postUser, true),
2015-06-19 09:48:59 +09:00
postPageLink: Posts.getPageUrl(post, true),
2015-08-14 17:39:00 +09:00
date: moment(post.postedAt).format("MMMM D YYYY"),
authorAvatarUrl: Users.avatar.getUrl(postUser),
emailShareUrl: Posts.getEmailShareUrl(post),
twitterShareUrl: Posts.getTwitterShareUrl(post),
facebookShareUrl: Posts.getFacebookShareUrl(post)
});
// if post author's avatar returns an error, remove it from properties object
2015-08-14 17:39:00 +09:00
try {
HTTP.get(post.authorAvatarUrl);
} catch (error) {
post.authorAvatarUrl = false;
}
// trim the body and remove any HTML tags
if (post.body) {
2016-12-12 11:34:28 +09:00
properties.body = Utils.trimHTML(post.htmlBody, 20);
}
// if post has comments
if (post.commentCount > 0) {
// get the two highest-scoring comments
2015-07-15 17:30:49 +10:00
properties.popularComments = Comments.find({postId: post._id}, {sort: {score: -1}, limit: 2, transform: function (comment) {
// get comment author
var user = Users.findOne(comment.userId);
// add properties to comment
2016-12-12 11:34:28 +09:00
comment.body = Utils.trimHTML(comment.htmlBody, 20);
2015-08-15 11:51:23 +09:00
comment.authorProfileUrl = Users.getProfileUrl(user, true);
2016-06-23 15:00:58 +09:00
comment.authorAvatarUrl = Users.avatar.getUrl(user);
2015-08-14 17:39:00 +09:00
try {
HTTP.get(comment.authorAvatarUrl);
} catch (error) {
comment.authorAvatarUrl = false;
}
2015-07-15 17:30:49 +10:00
return comment;
2015-07-15 17:30:49 +10:00
}}).fetch();
}
// if post has an URL, at the link domain as a property
2015-12-13 10:45:15 +09:00
if(post.url) {
2016-12-12 11:34:28 +09:00
properties.domain = Utils.getDomain(post.url);
2015-12-13 10:45:15 +09:00
}
// if post has a thumbnail, add the thumbnail URL as a property
2015-12-13 10:45:15 +09:00
if (properties.thumbnailUrl) {
2016-12-12 11:34:28 +09:00
properties.thumbnailUrl = Utils.addHttp(properties.thumbnailUrl);
2015-12-13 10:45:15 +09:00
}
// if post has categories, add them
if (post.categories) {
properties.categories = post.categories.map(categoryID => {
const category = Categories.findOne(categoryID);
2016-06-06 16:11:51 +09:00
if (category) {
return {
name: category.name,
url: Categories.getUrl(category, true)
}
}
});
}
2016-06-06 16:11:51 +09:00
// console.log(properties)
// generate post item HTML and add it to the postsHTML string
2016-06-23 16:42:06 +09:00
postsHTML += NovaEmail.getTemplate('postItem')(properties);
});
// 2. Wrap posts HTML in newsletter template
2016-06-23 16:42:06 +09:00
var newsletterHTML = NovaEmail.getTemplate('newsletter')({
2016-12-12 15:00:56 +09:00
siteName: getSetting('title', "Nova"),
date: moment().format("dddd, MMMM D YYYY"),
content: postsHTML
});
// 3. wrap newsletter HTML in email wrapper template
// (also pass date to wrapper as extra property just in case we need it)
var emailHTML = NovaEmail.buildTemplate(newsletterHTML, {
date: moment().format("dddd, MMMM D YYYY")
});
// 4. build campaign object and return it
var campaign = {
postIds: _.pluck(postsArray, '_id'),
2016-12-12 11:34:28 +09:00
subject: Utils.trimWords(subject, 15),
html: emailHTML
};
return campaign;
};