2013-01-31 15:49:45 +00:00
// Main job is to check pads periodically for activity and notify owners when someone begins editing and when someone finishes.
2013-01-30 18:09:04 +00:00
var db = require ( '../../src/node/db/DB' ) . db ,
2013-01-29 23:15:53 +00:00
API = require ( '../../src/node/db/API.js' ) ,
async = require ( '../../src/node_modules/async' ) ,
2013-01-31 01:16:34 +00:00
check = require ( 'validator' ) . check ,
2013-01-31 01:57:12 +00:00
email = require ( 'emailjs' ) ,
2017-08-30 16:40:46 +00:00
settings = require ( '../../src/node/utils/Settings' ) ,
util = require ( 'util' ) ;
2013-01-29 23:15:53 +00:00
2013-01-31 15:49:45 +00:00
// Settings -- EDIT THESE IN settings.json not here..
2013-01-29 23:15:53 +00:00
var pluginSettings = settings . ep _email _notifications ;
2013-04-04 15:57:37 +00:00
var areParamsOk = ( pluginSettings ) ? true : false ;
2013-04-04 12:57:54 +00:00
var checkFrequency = ( pluginSettings && pluginSettings . checkFrequency ) ? pluginSettings . checkFrequency : 60000 ; // 10 seconds
var staleTime = ( pluginSettings && pluginSettings . staleTime ) ? pluginSettings . staleTime : 300000 ; // 5 minutes
var fromName = ( pluginSettings && pluginSettings . fromName ) ? pluginSettings . fromName : "Etherpad" ;
var fromEmail = ( pluginSettings && pluginSettings . fromEmail ) ? pluginSettings . fromEmail : "pad@etherpad.org" ;
var urlToPads = ( pluginSettings && pluginSettings . urlToPads ) ? pluginSettings . urlToPads : "http://beta.etherpad.org/p/" ;
var emailServer = ( pluginSettings && pluginSettings . emailServer ) ? pluginSettings . emailServer : { host : "127.0.0.1" } ;
2013-01-31 15:49:45 +00:00
// A timer object we maintain to control how we send emails
2013-01-29 23:15:53 +00:00
var timers = { } ;
2013-01-31 22:14:24 +00:00
// Connect to the email server -- This might not be the ideal place to connect but it stops us having lots of connections
2013-01-31 21:30:48 +00:00
var server = email . server . connect ( emailServer ) ;
2013-01-30 18:09:04 +00:00
2017-08-30 16:40:46 +00:00
var emailFooter = "\nYou can unsubscribe from these emails in the pad's Settings window.\n" ;
2013-01-29 17:35:40 +00:00
exports . padUpdate = function ( hook _name , _pad ) {
2013-04-04 15:57:37 +00:00
if ( areParamsOk == false ) return false ;
2013-01-29 23:15:53 +00:00
var pad = _pad . pad ;
var padId = pad . id ;
exports . sendUpdates ( padId ) ;
// does an interval not exist for this pad?
if ( ! timers [ padId ] ) {
2013-01-31 22:14:24 +00:00
console . debug ( "Someone started editing " + padId ) ;
2013-01-31 01:57:12 +00:00
exports . notifyBegin ( padId ) ;
2013-01-29 23:15:53 +00:00
console . debug ( "Created an interval time check for " + padId ) ;
// if not then create one and write it to the timers object
2013-01-31 15:49:45 +00:00
timers [ padId ] = exports . createInterval ( padId , checkFrequency ) ;
2013-01-29 23:15:53 +00:00
} else { // an interval already exists so don't create
}
} ;
2017-08-30 16:40:46 +00:00
padUrl = function ( padId , fmt ) {
fmt = fmt || "%s" ;
return util . format ( fmt , urlToPads + padId ) ;
}
2013-01-31 01:57:12 +00:00
exports . notifyBegin = function ( padId ) {
2013-02-07 15:04:12 +00:00
console . warn ( "Getting pad email stuff for " + padId ) ;
2013-01-31 01:57:12 +00:00
db . get ( "emailSubscription:" + padId , function ( err , recipients ) { // get everyone we need to email
2013-01-31 15:49:45 +00:00
if ( recipients ) {
async . forEach ( Object . keys ( recipients ) , function ( recipient , cb ) {
2013-04-02 22:41:11 +00:00
//avoid the 'pending' section
if ( recipient != 'pending' ) {
// Is this recipient already on the pad?
exports . isUserEditingPad ( padId , recipients [ recipient ] . authorId , function ( err , userIsOnPad ) { // is the user already on the pad?
var onStart = typeof ( recipients [ recipient ] . onStart ) == "undefined" || recipients [ recipient ] . onStart ? true : false ; // In case onStart wasn't defined we set it to true
if ( ! userIsOnPad && onStart ) {
console . debug ( "Emailing " + recipient + " about a new begin update" ) ;
server . send ( {
2017-08-30 16:40:46 +00:00
text : "This pad is now being edited:\n" + padUrl ( padId , " <%s>\n" ) + emailFooter ,
2013-04-02 22:41:11 +00:00
from : fromName + "<" + fromEmail + ">" ,
to : recipient ,
subject : "Someone started editing " + padId
} , function ( err , message ) { console . log ( err || message ) ; } ) ;
}
else {
console . debug ( "Didn't send an email because user is already on the pad" ) ;
}
} ) ;
}
2013-01-31 15:49:45 +00:00
cb ( ) ; // finish each user
} ,
function ( err ) {
2013-01-31 22:14:24 +00:00
// do some error handling..
2013-01-31 15:49:45 +00:00
} ) ;
}
2013-01-31 01:57:12 +00:00
} ) ;
}
exports . notifyEnd = function ( padId ) {
2017-08-30 16:40:46 +00:00
// TODO: get the modified contents to include in the email
2013-01-31 01:57:12 +00:00
db . get ( "emailSubscription:" + padId , function ( err , recipients ) { // get everyone we need to email
2013-01-31 21:26:22 +00:00
if ( recipients ) {
async . forEach ( Object . keys ( recipients ) , function ( recipient , cb ) {
2013-04-02 22:41:11 +00:00
//avoid the 'pending' section
if ( recipient != 'pending' ) {
// Is this recipient already on the pad?
exports . isUserEditingPad ( padId , recipients [ recipient ] . authorId , function ( err , userIsOnPad ) { // is the user already on the$
var onEnd = typeof ( recipients [ recipient ] . onEnd ) == "undefined" || recipients [ recipient ] . onEnd ? true : false ; // In case onEnd wasn't defined we set it to false
2013-03-26 19:44:34 +00:00
2013-04-02 22:41:11 +00:00
if ( ! userIsOnPad && onEnd ) {
console . debug ( "Emailing " + recipient + " about a pad finished being updated" ) ;
server . send ( {
2017-08-30 16:40:46 +00:00
text : "This pad is done being edited:\n" + padUrl ( padId , " <%s>\n" ) + emailFooter ,
2013-04-02 22:41:11 +00:00
from : fromName + "<" + fromEmail + ">" ,
to : recipient ,
subject : "Someone finished editing " + padId
} , function ( err , message ) { console . log ( err || message ) ; } ) ;
}
else {
console . debug ( "Didn't send an email because user is already on the pad" ) ;
}
} ) ;
}
2013-01-31 21:26:22 +00:00
cb ( ) ; // finish each user
} ,
function ( err ) {
2013-01-31 22:14:24 +00:00
// do some error handling..
2013-01-31 21:26:22 +00:00
} ) ;
}
2013-01-31 01:57:12 +00:00
} ) ;
}
2013-01-29 23:15:53 +00:00
exports . sendUpdates = function ( padId ) {
// check to see if we can delete this interval
API . getLastEdited ( padId , function ( callback , message ) {
// we delete an interval if a pad hasn't been edited in X seconds.
var currTS = new Date ( ) . getTime ( ) ;
if ( currTS - message . lastEdited > staleTime ) {
2013-01-31 01:57:12 +00:00
exports . notifyEnd ( padId ) ;
2013-01-29 23:15:53 +00:00
console . warn ( "Interval went stale so deleting it from object and timer" ) ;
var interval = timers [ padId ] ;
clearInterval ( timers [ padId ] ) ; // remove the interval timer
delete timers [ padId ] ; // remove the entry from the padId
} else {
2013-01-31 01:57:12 +00:00
console . debug ( "email timeout not stale so not deleting" ) ;
2013-01-29 23:15:53 +00:00
}
} ) ;
2013-01-29 17:35:40 +00:00
// The status of the users relationship with the pad -- IE if it's subscribed to this pad / if it's already on the pad
2013-01-29 23:15:53 +00:00
// This comes frmo the database
2013-01-31 22:14:24 +00:00
var userStatus = { } ; // I'm not even sure we use this value.. I put it here when drunk or something
2013-01-29 23:15:53 +00:00
}
2013-01-29 17:35:40 +00:00
2013-01-29 23:15:53 +00:00
// Is the user editing the pad?
exports . isUserEditingPad = function ( padId , user , cb ) {
2013-02-07 15:04:12 +00:00
console . warn ( "padId is" , padId ) ;
/ *
2013-01-29 23:15:53 +00:00
API . padUsers ( padId , function ( callback , padUsers ) { // get the current users editing the pad
2013-01-29 17:35:40 +00:00
var userIsEditing = false ;
2013-01-31 22:14:24 +00:00
console . debug ( "Current Pad Users:" + padUsers ) ;
2013-01-29 23:15:53 +00:00
// for each user on the pad right now
async . forEach ( padUsers . padUsers ,
2013-01-29 17:35:40 +00:00
function ( userOnPad , callback ) {
2013-01-31 22:14:24 +00:00
if ( userOnPad . id == user ) {
console . debug ( "User is on the pad so don't send any notification" ) ;
2013-01-29 17:35:40 +00:00
userIsEditing = true ; // If the user is editing the pad then return true
2013-01-29 23:15:53 +00:00
} else {
userIsEditing = false ; // If the user isnt on this pad then that'd be okay to contact em
2013-01-29 17:35:40 +00:00
}
2013-01-29 23:15:53 +00:00
callback ( userIsEditing ) ;
2013-01-29 17:35:40 +00:00
} ,
function ( err ) {
2013-01-29 23:15:53 +00:00
cb ( null , userIsEditing ) ;
} ) ;
} ) ;
2013-02-07 15:04:12 +00:00
* /
cb ( null , false ) ;
2013-01-29 17:35:40 +00:00
} ;
2013-01-31 15:49:45 +00:00
// Creates an interval process to check to send Updates based on checkFrequency and it returns an ID
2013-01-29 23:15:53 +00:00
exports . createInterval = function ( padId ) {
return setInterval ( function ( ) {
2013-01-31 15:49:45 +00:00
exports . sendUpdates ( padId ) , checkFrequency
2013-01-29 23:15:53 +00:00
} ) ;
}