mirror of
https://github.com/vale981/Vulcan
synced 2025-03-06 10:01:40 -05:00
refactoring email templates
This commit is contained in:
parent
6cc5bedb4d
commit
78f440e8cd
16 changed files with 193 additions and 134 deletions
|
@ -6,7 +6,7 @@ Template[getTemplate('notification_item')].helpers({
|
|||
return this.properties;
|
||||
},
|
||||
notificationHTML: function(){
|
||||
return getNotificationContents(this).html;
|
||||
return buildSiteNotification(this);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -29,70 +29,26 @@ Notifications.allow({
|
|||
, remove: canEditById
|
||||
});
|
||||
|
||||
getNotificationContents = function(notification, context){
|
||||
// the same notifications can be displayed in multiple contexts: on-site in the sidebar, sent by email, etc.
|
||||
buildSiteNotification = function(notification){
|
||||
var event = notification.event,
|
||||
p = notification.properties,
|
||||
context = typeof context === 'undefined' ? 'sidebar' : context,
|
||||
userToNotify = Meteor.users.findOne(notification.userId);
|
||||
userToNotify = Meteor.users.findOne(notification.userId),
|
||||
html
|
||||
|
||||
switch(event){
|
||||
case 'newReply':
|
||||
var n = {
|
||||
subject: 'Someone replied to your comment on "'+p.postTitle+'"',
|
||||
text: p.commentAuthorName+' has replied to your comment on "'+p.postTitle+'": '+getPostCommentUrl(p.postId, p.commentId),
|
||||
html: '<p><a href="'+getProfileUrlById(p.commentAuthorId)+'">'+p.commentAuthorName+'</a> has replied to your comment on "<a href="'+getPostCommentUrl(p.postId, p.commentId)+'" class="action-link">'+p.postTitle+'</a>"</p>'
|
||||
};
|
||||
if(context == 'email')
|
||||
n.html += '<p>'+p.commentExcerpt+'</p><a href="'+getPostCommentUrl(p.postId, p.commentId)+'" class="action-link">Read more</a>';
|
||||
html = '<p><a href="'+getProfileUrlById(p.commentAuthorId)+'">'+p.commentAuthorName+'</a> has replied to your comment on "<a href="'+getPostCommentUrl(p.postId, p.commentId)+'" class="action-link">'+p.postTitle+'</a>"</p>';
|
||||
break;
|
||||
|
||||
case 'newComment':
|
||||
var n = {
|
||||
subject: 'A new comment on your post "'+p.postTitle+'"',
|
||||
text: 'You have a new comment by '+p.commentAuthorName+' on your post "'+p.postTitle+'": '+getPostCommentUrl(p.postId, p.commentId),
|
||||
html: '<p><a href="'+getProfileUrlById(p.commentAuthorId)+'">'+p.commentAuthorName+'</a> left a new comment on your post "<a href="'+getPostCommentUrl(p.postId, p.commentId)+'" class="action-link">'+p.postTitle+'</a>"</p>'
|
||||
};
|
||||
if(context == 'email')
|
||||
n.html += '<p>'+p.commentExcerpt+'</p><a href="'+getPostCommentUrl(p.postId, p.commentId)+'" class="action-link">Read more</a>';
|
||||
break;
|
||||
|
||||
case 'newPost':
|
||||
var n = {
|
||||
subject: p.postAuthorName+' has created a new post: "'+p.postTitle+'"',
|
||||
text: p.postAuthorName+' has created a new post: "'+p.postTitle+'" '+getPostUrl(p.postId),
|
||||
html: '<a href="'+getProfileUrlById(p.postAuthorId)+'">'+p.postAuthorName+'</a> has created a new post: "<a href="'+getPostUrl(p.postId)+'" class="action-link">'+p.postTitle+'</a>".'
|
||||
};
|
||||
break;
|
||||
|
||||
case 'accountApproved':
|
||||
var n = {
|
||||
subject: 'Your account has been approved.',
|
||||
text: 'Welcome to '+getSetting('title')+'! Your account has just been approved.',
|
||||
html: 'Welcome to '+getSetting('title')+'!<br/> Your account has just been approved. <a href="'+Meteor.absoluteUrl()+'">Start posting.</a>'
|
||||
};
|
||||
break;
|
||||
|
||||
case 'newUser':
|
||||
var n = {
|
||||
subject: 'New user: '+p.username,
|
||||
text: 'A new user account has been created: '+p.profileUrl,
|
||||
html: 'A new user account has been created: <a href="'+p.profileUrl+'">'+p.username+'</a>'
|
||||
};
|
||||
break;
|
||||
html = '<p><a href="'+getProfileUrlById(p.commentAuthorId)+'">'+p.commentAuthorName+'</a> left a new comment on your post "<a href="'+getPostCommentUrl(p.postId, p.commentId)+'" class="action-link">'+p.postTitle+'</a>"</p>';
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
// if context is email, append unsubscribe link to all outgoing notifications
|
||||
if(context == 'email'){
|
||||
n.to = getEmail(userToNotify);
|
||||
n.text = n.text + '\n\n Unsubscribe from all notifications: '+getUnsubscribeLink(userToNotify);
|
||||
n.html = n.html + '<br/><br/><a href="'+getUnsubscribeLink(userToNotify)+'">Unsubscribe from all notifications</a>';
|
||||
}
|
||||
|
||||
return n;
|
||||
return html;
|
||||
};
|
||||
|
||||
Meteor.methods({
|
||||
|
|
|
@ -223,19 +223,18 @@ Meteor.methods({
|
|||
|
||||
Meteor.call('upvotePost', post, postAuthor);
|
||||
|
||||
if(getSetting('emailNotifications', false)){
|
||||
if(!!getSetting('emailNotifications', false)){
|
||||
// notify users of new posts
|
||||
var notification = {
|
||||
event: 'newPost',
|
||||
properties: {
|
||||
postAuthorName : getDisplayName(postAuthor),
|
||||
postAuthorId : post.userId,
|
||||
postTitle : title,
|
||||
postId : post._id
|
||||
}
|
||||
emailProperties = {
|
||||
postAuthorName : getDisplayName(postAuthor),
|
||||
postAuthorId : post.userId,
|
||||
postTitle : title,
|
||||
postId : post._id,
|
||||
profileUrl: getProfileUrlById(post.userId),
|
||||
postUrl: getPostUrl(post._id)
|
||||
};
|
||||
// call a server method because we do not have access to users' info on the client
|
||||
Meteor.call('newPostNotify', notification, function(error, result){
|
||||
Meteor.call('newPostNotify', emailProperties, function(error, result){
|
||||
//run asynchronously
|
||||
});
|
||||
}
|
||||
|
@ -290,5 +289,20 @@ Meteor.methods({
|
|||
|
||||
Meteor.users.update({_id: post.userId}, {$inc: {postCount: -1}});
|
||||
Posts.remove(postId);
|
||||
},
|
||||
newPostNotify : function(p){
|
||||
// only run on server since we need to get a list of all users
|
||||
if(Meteor.isServer){
|
||||
var currentUser = Meteor.users.findOne(this.userId);
|
||||
console.log('newPostNotify');
|
||||
var subject = p.postAuthorName+' has created a new post: '+p.postTitle;
|
||||
var html = Handlebars.templates[getTemplate('emailNewPost')](p)
|
||||
// send a notification to every user according to their notifications settings
|
||||
Meteor.users.find({'profile.notifications.posts': 1}).forEach(function(user) {
|
||||
// don't send users notifications for their own posts
|
||||
if(user._id !== currentUser._id && getUserSetting('notifications.posts', false, user))
|
||||
sendEmail(getEmail(user), subject, html);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -704,6 +704,35 @@ Router.map(function() {
|
|||
}
|
||||
});
|
||||
|
||||
// Notification email online
|
||||
|
||||
this.route('notification', {
|
||||
where: 'server',
|
||||
path: '/email/notification/:id?',
|
||||
action: function() {
|
||||
var notification = Notifications.findOne(this.params.id);
|
||||
var notificationContents = buildEmailNotification(notification);
|
||||
var html = buildEmailTemplate(notificationContents.html);
|
||||
this.response.write(html);
|
||||
this.response.end();
|
||||
}
|
||||
});
|
||||
|
||||
this.route('newUser', {
|
||||
where: 'server',
|
||||
path: '/email/new-user/:id?',
|
||||
action: function() {
|
||||
var user = Meteor.users.findOne(this.params.id);
|
||||
var emailProperties = {
|
||||
profileUrl: getProfileUrl(user),
|
||||
username: getUserName(user)
|
||||
}
|
||||
html = Handlebars.templates[getTemplate('emailNewUser')](emailProperties);
|
||||
this.response.write(buildEmailTemplate(html));
|
||||
this.response.end();
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// adding common subscriptions that's need to be loaded on all the routes
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
{
|
||||
"juice": "0.4.0"
|
||||
"juice": "0.4.0",
|
||||
"html-to-text": "0.1.0"
|
||||
}
|
|
@ -5,7 +5,7 @@ Meteor.startup(function () {
|
|||
|
||||
this.route('campaign', {
|
||||
where: 'server',
|
||||
path: '/campaign/:id?',
|
||||
path: '/email/campaign/:id?',
|
||||
action: function() {
|
||||
var campaignId = parseInt(this.params.id);
|
||||
var htmlContent = buildCampaign(2);
|
||||
|
|
|
@ -1,32 +1,7 @@
|
|||
sendEmail = function(to, subject, text, html){
|
||||
|
||||
// TODO: limit who can send emails
|
||||
// TODO: fix this error: Error: getaddrinfo ENOTFOUND
|
||||
|
||||
var from = getSetting('defaultEmail', 'noreply@example.com');
|
||||
var siteName = getSetting('title');
|
||||
var subject = '['+siteName+'] '+subject;
|
||||
|
||||
console.log('sending email…');
|
||||
console.log(from);
|
||||
console.log(to);
|
||||
console.log(subject);
|
||||
console.log(text);
|
||||
console.log(html);
|
||||
|
||||
Email.send({
|
||||
from: from,
|
||||
to: to,
|
||||
subject: subject,
|
||||
text: text,
|
||||
html: html
|
||||
});
|
||||
};
|
||||
|
||||
buildEmailTemplate = function (htmlContent) {
|
||||
var juice = Meteor.require('juice');
|
||||
|
||||
var emailHTML = Handlebars.templates[getTemplate('emailMain')]({
|
||||
var emailHTML = Handlebars.templates[getTemplate('emailWrapper')]({
|
||||
headerColor: getSetting('headerColor'),
|
||||
buttonColor: getSetting('buttonColor'),
|
||||
logo: '',
|
||||
|
@ -46,5 +21,40 @@ buildEmailTemplate = function (htmlContent) {
|
|||
});
|
||||
}).result;
|
||||
|
||||
return inlinedHTML;
|
||||
}
|
||||
var doctype = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">'
|
||||
|
||||
return doctype+inlinedHTML;
|
||||
}
|
||||
|
||||
sendEmail = function(to, subject, html, text){
|
||||
|
||||
// TODO: limit who can send emails
|
||||
// TODO: fix this error: Error: getaddrinfo ENOTFOUND
|
||||
|
||||
var from = getSetting('defaultEmail', 'noreply@example.com');
|
||||
var siteName = getSetting('title');
|
||||
var subject = '['+siteName+'] '+subject;
|
||||
|
||||
if (typeof text == 'undefined'){
|
||||
// Auto-generate text version if it doesn't exist. Has bugs, but should be good enough.
|
||||
var htmlToText = Meteor.require('html-to-text');
|
||||
var text = htmlToText.fromString(html, {
|
||||
wordwrap: 130
|
||||
});
|
||||
}
|
||||
|
||||
console.log('sending email…');
|
||||
console.log(from);
|
||||
console.log(to);
|
||||
console.log(subject);
|
||||
console.log(text);
|
||||
console.log(html);
|
||||
|
||||
Email.send({
|
||||
from: from,
|
||||
to: to,
|
||||
subject: subject,
|
||||
text: text,
|
||||
html: html
|
||||
});
|
||||
};
|
|
@ -24,13 +24,13 @@ Meteor.methods({
|
|||
}});
|
||||
console.log(a);
|
||||
|
||||
createNotification({
|
||||
event: 'accountApproved',
|
||||
properties: {},
|
||||
userToNotify: invitedUser,
|
||||
userDoingAction: currentUser,
|
||||
sendEmail: true
|
||||
});
|
||||
var emailProperties = {
|
||||
siteTitle: getSettings('siteTitle'),
|
||||
siteUrl: getSiteUrl()
|
||||
}
|
||||
sendEmail(getEmail(invitedUser), 'You\'ve been invited',
|
||||
Handlebars.templates[getTemplate('emailAccountApproved')](emailProperties)
|
||||
)
|
||||
|
||||
}else{
|
||||
throw new Meteor.Error(701, "You can't invite this user, sorry.");
|
||||
|
|
|
@ -26,11 +26,54 @@ createNotification = function(options) {
|
|||
// the notificationsFrequency is set to 1, or if it's undefined (legacy compatibility)
|
||||
if(sendEmail){
|
||||
// get specific notification content for "email" context
|
||||
var contents = getNotificationContents(notification, 'email');
|
||||
var contents = buildEmailNotification(notification);
|
||||
sendNotification(contents);
|
||||
}
|
||||
};
|
||||
|
||||
buildEmailNotification = function (notification) {
|
||||
var event = notification.event,
|
||||
p = notification.properties,
|
||||
userToNotify = Meteor.users.findOne(notification.userId),
|
||||
n = {}
|
||||
|
||||
n.to = getEmail(userToNotify);
|
||||
|
||||
p.profileUrl = getProfileUrlById(p.commentAuthorId);
|
||||
p.postCommentUrl = getPostCommentUrl(p.postId, p.commentId);
|
||||
p.unsubscribeLink = getUnsubscribeLink(userToNotify);
|
||||
|
||||
switch(event){
|
||||
case 'newReply':
|
||||
n.subject = 'Someone replied to your comment on "'+p.postTitle+'"';
|
||||
n.template = 'emailNewReply';
|
||||
n.text = p.commentAuthorName+' has replied to your comment on "'+p.postTitle+'": '+getPostCommentUrl(p.postId, p.commentId);
|
||||
break;
|
||||
|
||||
case 'newComment':
|
||||
n.subject = 'A new comment on your post "'+p.postTitle+'"';
|
||||
n.template = 'emailNewComment';
|
||||
n.text = 'You have a new comment by '+p.commentAuthorName+' on your post "'+p.postTitle+'": '+getPostCommentUrl(p.postId, p.commentId);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
n.html = Handlebars.templates[getTemplate(n.template)](p);
|
||||
// append unsubscribe link to all outgoing notifications
|
||||
n.text = n.text + '\n\n Unsubscribe from all notifications: '+getUnsubscribeLink(userToNotify);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
sendNotification = function (notification) {
|
||||
// console.log('send notification:')
|
||||
// console.log(notification)
|
||||
var html = buildEmailTemplate(notification.html)
|
||||
sendEmail(notification.to, notification.subject, html, notification.text);
|
||||
};
|
||||
|
||||
Meteor.methods({
|
||||
unsubscribeUser : function(hash){
|
||||
// TO-DO: currently, if you have somebody's email you can unsubscribe them
|
||||
|
@ -48,24 +91,6 @@ Meteor.methods({
|
|||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
newPostNotify : function(properties){
|
||||
var currentUser = Meteor.users.findOne(this.userId);
|
||||
console.log('newPostNotify');
|
||||
// send a notification to every user according to their notifications settings
|
||||
Meteor.users.find({'profile.notifications.posts': 1}).forEach(function(user) {
|
||||
// don't send users notifications for their own posts
|
||||
if(user._id !== currentUser._id && getUserSetting('notifications.posts', false, user)){
|
||||
properties.userId = user._id;
|
||||
var notification = getNotificationContents(properties, 'email');
|
||||
sendNotification(notification, user);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
sendNotification = function (notification) {
|
||||
// console.log('send notification:')
|
||||
// console.log(notification)
|
||||
sendEmail(notification.to, notification.subject, notification.text, notification.html);
|
||||
};
|
||||
|
|
3
server/templates/emailAccountApproved.handlebars
Normal file
3
server/templates/emailAccountApproved.handlebars
Normal file
|
@ -0,0 +1,3 @@
|
|||
<span class="heading">Welcome to {{siteTitle}}</span><br><br>
|
||||
|
||||
Your account has just been approved. <a href="{{siteUrl}}">Start posting!</a><br><br>
|
7
server/templates/emailNewComment.handlebars
Normal file
7
server/templates/emailNewComment.handlebars
Normal file
|
@ -0,0 +1,7 @@
|
|||
<span class="heading"><a href="{{profileUrl}}">{{commentAuthorName}}</a>
|
||||
left a new comment on your post
|
||||
"<a href="{{postCommentUrl}}" class="action-link">{{postTitle}}</a>"</span><br/><br/>
|
||||
|
||||
{{{commentExcerpt}}} <a href="{{postCommentUrl}}" class="action-link">Read more…</a><br/><br/>
|
||||
|
||||
<a href="{{unsubscribeLink}}">Unsubscribe from all notifications</a><br/><br/>
|
5
server/templates/emailNewPost.handlebars
Normal file
5
server/templates/emailNewPost.handlebars
Normal file
|
@ -0,0 +1,5 @@
|
|||
<span class="heading">
|
||||
<a href="{{profileUrl}}">{{postAuthorName}}</a>
|
||||
has created a new post:
|
||||
"<a href="{{postUrl}}" class="action-link">{{postTitle}}}</a>
|
||||
</span><br><br>
|
7
server/templates/emailNewReply.handlebars
Normal file
7
server/templates/emailNewReply.handlebars
Normal file
|
@ -0,0 +1,7 @@
|
|||
<span class="heading"><a href="{{profileUrl}}">{{commentAuthorName}}</a>
|
||||
has replied to your comment on
|
||||
"<a href="{{postCommentUrl}}" class="action-link">{{postTitle}}</a>"</span><br/><br/>
|
||||
|
||||
{{{commentExcerpt}}} <a href="{{postCommentUrl}}" class="action-link">Read more…</a><br/><br/>
|
||||
|
||||
<a href="{{unsubscribeLink}}">Unsubscribe from all notifications</a><br/><br/>
|
1
server/templates/emailNewUser.handlebars
Normal file
1
server/templates/emailNewUser.handlebars
Normal file
|
@ -0,0 +1 @@
|
|||
A new user account has been created: <a href="{{profileUrl}}">{{username}}</a><br><br>
|
|
@ -1,5 +1,3 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
|
@ -36,7 +34,12 @@
|
|||
padding-left: 12px !important;
|
||||
padding-right: 12px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
a{
|
||||
color: {{buttonColor}};
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
}
|
||||
.container{
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
@ -58,19 +61,19 @@
|
|||
font-family: Helvetica, sans-serif;
|
||||
color: #555;
|
||||
}
|
||||
h3{
|
||||
color: {{buttonColor}};
|
||||
.heading{
|
||||
font-weight: bold;
|
||||
font-size: 18px;
|
||||
line-height: 1.5;
|
||||
margin: 0;
|
||||
}
|
||||
.footer-container{
|
||||
background: #ccc;
|
||||
background: #ddd;
|
||||
font-family: Helvetica, sans-serif;
|
||||
padding: 30px;
|
||||
color: #777;
|
||||
border-radius: 0px 0px 3px 3px;
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
|
@ -47,15 +47,13 @@ Accounts.onCreateUser(function(options, user){
|
|||
var admins = Meteor.users.find({isAdmin: true});
|
||||
admins.forEach(function(admin){
|
||||
if(getUserSetting('notifications.users', false, admin)){
|
||||
var notification = getNotificationContents({
|
||||
event: 'newUser',
|
||||
properties: {
|
||||
username: getUserName(user),
|
||||
profileUrl: getProfileUrl(user)
|
||||
},
|
||||
userId: admin._id
|
||||
}, 'email');
|
||||
sendNotification(notification, admin);
|
||||
var emailProperties = {
|
||||
profileUrl: getProfileUrl(user),
|
||||
username: getUserName(user)
|
||||
}
|
||||
sendEmail(getEmail(admin), 'New user account: '+getUserName(user),
|
||||
Handlebars.templates[getTemplate('emailNewUser')](emailProperties)
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue