make it send emails
This commit is contained in:
parent
9cd41efb1d
commit
36d10a5010
4 changed files with 172 additions and 112 deletions
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
* a point to unsubscribe
|
* a point to unsubscribe
|
||||||
* stop the ui prompting if already subscribed
|
* stop the ui prompting if already subscribed
|
||||||
* send actual emails with content
|
* move settings to settings.json
|
||||||
* Clean up all code
|
* Clean up all code
|
||||||
|
* Get the modified contents from the API HTML diff
|
||||||
|
* Keep a record of when a user was last on a pad
|
||||||
|
|
2
ep.json
2
ep.json
|
@ -4,7 +4,7 @@
|
||||||
"name": "ep_email_notifications",
|
"name": "ep_email_notifications",
|
||||||
"hooks": {
|
"hooks": {
|
||||||
"padUpdate": "ep_email_notifications/update",
|
"padUpdate": "ep_email_notifications/update",
|
||||||
"handleMessage": "ep_email_notifications/update",
|
"handleMessage": "ep_email_notifications/handleMessage",
|
||||||
"eejsBlock_scripts": "ep_email_notifications/client",
|
"eejsBlock_scripts": "ep_email_notifications/client",
|
||||||
"eejsBlock_editbarMenuRight": "ep_email_notifications/client:eejsBlock_toolbarRight",
|
"eejsBlock_editbarMenuRight": "ep_email_notifications/client:eejsBlock_toolbarRight",
|
||||||
"eejsBlock_embedPopup": "ep_email_notifications/client:eejsBlock_embedPopup"
|
"eejsBlock_embedPopup": "ep_email_notifications/client:eejsBlock_embedPopup"
|
||||||
|
|
108
handleMessage.js
Normal file
108
handleMessage.js
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
var db = require('../../src/node/db/DB').db,
|
||||||
|
API = require('../../src/node/db/API.js'),
|
||||||
|
async = require('../../src/node_modules/async'),
|
||||||
|
check = require('validator').check,
|
||||||
|
settings = require('../../src/node/utils/Settings');
|
||||||
|
|
||||||
|
var pluginSettings = settings.ep_email_notifications;
|
||||||
|
|
||||||
|
// When a new message comes in from the client - FML this is ugly
|
||||||
|
exports.handleMessage = function(hook_name, context, callback){
|
||||||
|
if (context.message && context.message.data){
|
||||||
|
if (context.message.data.type == 'USERINFO_UPDATE' ) { // if it's a request to update an authors email
|
||||||
|
if (context.message.data.userInfo){
|
||||||
|
if(context.message.data.userInfo.email){ // it contains email
|
||||||
|
console.debug(context.message);
|
||||||
|
|
||||||
|
// does email Subscription already exist for this email address?
|
||||||
|
db.get("emailSubscription:"+context.message.data.padId, function(err, userIds){
|
||||||
|
|
||||||
|
var alreadyExists = false;
|
||||||
|
if(userIds){
|
||||||
|
async.forEach(Object.keys(userIds), function(user, cb){
|
||||||
|
console.debug("UserIds subscribed by email to this pad:", userIds);
|
||||||
|
if(user == context.message.data.userInfo.email){ // If we already have this email registered for this pad
|
||||||
|
|
||||||
|
// This user ID is already assigned to this padId so don't do anything except tell the user they are already subscribed somehow..
|
||||||
|
alreadyExists = true;
|
||||||
|
console.debug("email ", user, "already subscribed to ", context.message.data.padId, " so sending message to client");
|
||||||
|
|
||||||
|
context.client.json.send({ type: "COLLABROOM",
|
||||||
|
data:{
|
||||||
|
type: "emailSubscriptionSuccess",
|
||||||
|
payload: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
cb();
|
||||||
|
},
|
||||||
|
|
||||||
|
function(err){
|
||||||
|
// There should be something in here!
|
||||||
|
}); // end async for each
|
||||||
|
}
|
||||||
|
var validatesAsEmail = check(context.message.data.userInfo.email).isEmail();
|
||||||
|
if(!validatesAsEmail){ // send validation failed if it's malformed.. y'know in general fuck em!
|
||||||
|
console.warn("Dropped email subscription due to malformed email address");
|
||||||
|
context.client.json.send({ type: "COLLABROOM",
|
||||||
|
data:{
|
||||||
|
type: "emailSubscriptionSuccess",
|
||||||
|
payload: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if(alreadyExists == false && validatesAsEmail){
|
||||||
|
console.debug ("Wrote to the database and sent client a positive response ",context.message.data.userInfo.email);
|
||||||
|
|
||||||
|
exports.setAuthorEmail(
|
||||||
|
context.message.data.userInfo.userId,
|
||||||
|
context.message.data.userInfo.email, callback
|
||||||
|
);
|
||||||
|
|
||||||
|
exports.setAuthorEmailRegistered(
|
||||||
|
context.message.data.userInfo.email,
|
||||||
|
context.message.data.userInfo.userId,
|
||||||
|
context.message.data.padId
|
||||||
|
);
|
||||||
|
|
||||||
|
context.client.json.send({ type: "COLLABROOM",
|
||||||
|
data:{
|
||||||
|
type: "emailSubscriptionSuccess",
|
||||||
|
payload: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}); // close db get
|
||||||
|
|
||||||
|
callback(null); // don't run onto passing colorId or anything else to the message handler
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates the database with the email record
|
||||||
|
exports.setAuthorEmail = function (author, email, callback){
|
||||||
|
db.setSub("globalAuthor:" + author, ["email"], email, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write email and padId to the database
|
||||||
|
exports.setAuthorEmailRegistered = function(email, authorId, padId){
|
||||||
|
var timestamp = new Date().getTime();
|
||||||
|
var registered = {
|
||||||
|
authorId: authorId,
|
||||||
|
timestamp: timestamp
|
||||||
|
};
|
||||||
|
console.debug("registered", registered, " to ", padId);
|
||||||
|
|
||||||
|
// Here we have to basically hack a new value into the database, this isn't clean or polite.
|
||||||
|
db.get("emailSubscription:" + padId, function(err, value){ // get the current value
|
||||||
|
if(!value){value = {};} // if an emailSubscription doesnt exist yet for this padId don't panic
|
||||||
|
value[email] = registered; // add the registered values to the object
|
||||||
|
db.set("emailSubscription:" + padId, value); // stick it in the database
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
167
update.js
167
update.js
|
@ -1,98 +1,25 @@
|
||||||
|
// We check pads periodically for activity and notify owners when someone begins editing and when someone finishes.
|
||||||
|
|
||||||
var db = require('../../src/node/db/DB').db,
|
var db = require('../../src/node/db/DB').db,
|
||||||
API = require('../../src/node/db/API.js'),
|
API = require('../../src/node/db/API.js'),
|
||||||
async = require('../../src/node_modules/async'),
|
async = require('../../src/node_modules/async'),
|
||||||
check = require('validator').check,
|
check = require('validator').check,
|
||||||
|
email = require('emailjs'),
|
||||||
settings = require('../../src/node/utils/Settings');
|
settings = require('../../src/node/utils/Settings');
|
||||||
|
|
||||||
var pluginSettings = settings.ep_email_notifications;
|
var pluginSettings = settings.ep_email_notifications;
|
||||||
var checkInterval = 60000; // Move me to the settings file
|
var checkInterval = 3000; // How frequently to check for pad updates -- Move me to the settings file
|
||||||
var staleTime = 3600000; // Move me to settings
|
var staleTime = 3000; // How stale does a pad need to be before notifying subscribers? Move me to settings
|
||||||
var timers = {};
|
var timers = {};
|
||||||
|
var fromName = "John McLear";
|
||||||
|
var fromEmail = "john@mclear.co.uk";
|
||||||
|
var urlToPads = "http://beta.etherpad.org/p/";
|
||||||
|
|
||||||
// When a new message comes in from the client
|
var server = email.server.connect({
|
||||||
exports.handleMessage = function(hook_name, context, callback){
|
user: "username",
|
||||||
if (context.message && context.message.data){
|
password:"password",
|
||||||
if (context.message.data.type == 'USERINFO_UPDATE' ) { // if it's a request to update an authors email
|
host: "smtp.gmail.com",
|
||||||
if (context.message.data.userInfo){
|
|
||||||
if(context.message.data.userInfo.email){ // it contains email
|
|
||||||
console.debug(context.message);
|
|
||||||
|
|
||||||
// does email Subscription already exist for this email address?
|
|
||||||
db.get("emailSubscription:"+context.message.data.padId, function(err, userIds){
|
|
||||||
|
|
||||||
var alreadyExists = false;
|
|
||||||
if(userIds){
|
|
||||||
async.forEach(Object.keys(userIds), function(user, cb){
|
|
||||||
console.debug("UserIds subscribed by email to this pad:", userIds);
|
|
||||||
if(user == context.message.data.userInfo.email){ // If we already have this email registered for this pad
|
|
||||||
|
|
||||||
// This user ID is already assigned to this padId so don't do anything except tell the user they are already subscribed somehow..
|
|
||||||
alreadyExists = true;
|
|
||||||
console.debug("email ", user, "already subscribed to ", context.message.data.padId, " so sending message to client");
|
|
||||||
|
|
||||||
context.client.json.send({ type: "COLLABROOM",
|
|
||||||
data:{
|
|
||||||
type: "emailSubscriptionSuccess",
|
|
||||||
payload: false
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
cb();
|
|
||||||
},
|
|
||||||
|
|
||||||
function(err){
|
|
||||||
// There should be something in here!
|
|
||||||
}); // end async for each
|
|
||||||
}
|
|
||||||
|
|
||||||
var validatesAsEmail = check(context.message.data.userInfo.email).isEmail();
|
|
||||||
if(!validatesAsEmail){ // send validation failed if it's malformed.. y'know in general fuck em!
|
|
||||||
console.warn("Dropped email subscription due to malformed email address");
|
|
||||||
context.client.json.send({ type: "COLLABROOM",
|
|
||||||
data:{
|
|
||||||
type: "emailSubscriptionSuccess",
|
|
||||||
payload: false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if(alreadyExists == false && validatesAsEmail){
|
|
||||||
console.warn ("Wrote to the database and sent client a positive response ",context.message.data.userInfo.email);
|
|
||||||
|
|
||||||
exports.setAuthorEmail(
|
|
||||||
context.message.data.userInfo.userId,
|
|
||||||
context.message.data.userInfo.email, callback
|
|
||||||
);
|
|
||||||
|
|
||||||
exports.setAuthorEmailRegistered(
|
|
||||||
context.message.data.userInfo.email,
|
|
||||||
context.message.data.userInfo.userId,
|
|
||||||
context.message.data.padId
|
|
||||||
);
|
|
||||||
|
|
||||||
context.client.json.send({ type: "COLLABROOM",
|
|
||||||
data:{
|
|
||||||
type: "emailSubscriptionSuccess",
|
|
||||||
payload: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}); // close db get
|
|
||||||
|
|
||||||
callback(null); // don't run onto passing colorId or anything else to the message handler
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.doesPadIdEmailAssociationAlreadyExist = function (padId, email){
|
|
||||||
var found = false;
|
|
||||||
db.get("emailSubscription:"+padId, function(err, value){
|
|
||||||
return value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.padUpdate = function (hook_name, _pad) {
|
exports.padUpdate = function (hook_name, _pad) {
|
||||||
|
|
||||||
|
@ -102,6 +29,8 @@ exports.padUpdate = function (hook_name, _pad) {
|
||||||
|
|
||||||
// does an interval not exist for this pad?
|
// does an interval not exist for this pad?
|
||||||
if(!timers[padId]){
|
if(!timers[padId]){
|
||||||
|
console.warn("Someone started editing "+padId);
|
||||||
|
exports.notifyBegin(padId);
|
||||||
console.debug("Created an interval time check for "+padId);
|
console.debug("Created an interval time check for "+padId);
|
||||||
// if not then create one and write it to the timers object
|
// if not then create one and write it to the timers object
|
||||||
timers[padId] = exports.createInterval(padId, checkInterval);
|
timers[padId] = exports.createInterval(padId, checkInterval);
|
||||||
|
@ -111,6 +40,49 @@ exports.padUpdate = function (hook_name, _pad) {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.notifyBegin = function(padId){
|
||||||
|
db.get("emailSubscription:" + padId, function(err, recipients){ // get everyone we need to email
|
||||||
|
async.forEach(Object.keys(recipients), function(recipient, cb){
|
||||||
|
console.debug("Emailing "+recipient +" about a new begin update");
|
||||||
|
|
||||||
|
server.send({
|
||||||
|
text: "Your pad at "+urlToPads+"/p/"+padId +" is being edited, we're just emailing you let you know :)",
|
||||||
|
from: fromName+ "<"+fromEmail+">",
|
||||||
|
to: recipient,
|
||||||
|
subject: "Someone begin editing "+padId
|
||||||
|
}, function(err, message) { console.log(err || message); });
|
||||||
|
|
||||||
|
cb(); // finish each user
|
||||||
|
},
|
||||||
|
function(err){
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.notifyEnd = function(padId){
|
||||||
|
// get the modified contents...
|
||||||
|
|
||||||
|
|
||||||
|
db.get("emailSubscription:" + padId, function(err, recipients){ // get everyone we need to email
|
||||||
|
async.forEach(Object.keys(recipients), function(recipient, cb){
|
||||||
|
console.debug("Emailing "+recipient +" about a new begin update");
|
||||||
|
|
||||||
|
server.send({
|
||||||
|
text: "Your pad at "+urlToPads+"/p/"+padId +" has finished being edited, we're just emailing you let you know :) The changes look like this:" + changesToPad,
|
||||||
|
from: fromName+ "<"+fromEmail+">",
|
||||||
|
to: recipient,
|
||||||
|
subject: "Someone begin editing "+padId
|
||||||
|
}, function(err, message) { console.log(err || message); });
|
||||||
|
|
||||||
|
cb(); // finish each user
|
||||||
|
},
|
||||||
|
function(err){
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
exports.sendUpdates = function(padId){
|
exports.sendUpdates = function(padId){
|
||||||
|
|
||||||
// check to see if we can delete this interval
|
// check to see if we can delete this interval
|
||||||
|
@ -119,13 +91,14 @@ exports.sendUpdates = function(padId){
|
||||||
// we delete an interval if a pad hasn't been edited in X seconds.
|
// we delete an interval if a pad hasn't been edited in X seconds.
|
||||||
var currTS = new Date().getTime();
|
var currTS = new Date().getTime();
|
||||||
if(currTS - message.lastEdited > staleTime){
|
if(currTS - message.lastEdited > staleTime){
|
||||||
|
exports.notifyEnd(padId);
|
||||||
console.warn("Interval went stale so deleting it from object and timer");
|
console.warn("Interval went stale so deleting it from object and timer");
|
||||||
var interval = timers[padId];
|
var interval = timers[padId];
|
||||||
clearInterval(timers[padId]); // remove the interval timer
|
clearInterval(timers[padId]); // remove the interval timer
|
||||||
delete timers[padId]; // remove the entry from the padId
|
delete timers[padId]; // remove the entry from the padId
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
console.debug("email timeotu not stale so not deleting");
|
console.debug("email timeout not stale so not deleting");
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -186,25 +159,3 @@ exports.createInterval = function(padId){
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updates the database with the email record
|
|
||||||
exports.setAuthorEmail = function (author, email, callback){
|
|
||||||
db.setSub("globalAuthor:" + author, ["email"], email, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write email and padId to the database
|
|
||||||
exports.setAuthorEmailRegistered = function(email, authorId, padId){
|
|
||||||
var timestamp = new Date().getTime();
|
|
||||||
var registered = {
|
|
||||||
authorId: authorId,
|
|
||||||
timestamp: timestamp
|
|
||||||
};
|
|
||||||
console.debug("registered", registered, " to ", padId);
|
|
||||||
|
|
||||||
// Here we have to basically hack a new value into the database, this isn't clean or polite.
|
|
||||||
db.get("emailSubscription:" + padId, function(err, value){ // get the current value
|
|
||||||
if(!value){value = {};} // if an emailSubscription doesnt exist yet for this padId don't panic
|
|
||||||
value[email] = registered; // add the registered values to the object
|
|
||||||
db.set("emailSubscription:" + padId, value); // stick it in the database
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue