2013-04-03 03:16:18 +00:00
var db = require ( 'ep_etherpad-lite/node/db/DB' ) . db ,
fs = require ( "fs" ) ,
async = require ( '../../src/node_modules/async' ) ,
settings = require ( '../../src/node/utils/Settings' ) ;
2013-04-02 03:14:01 +00:00
// Remove cache for this procedure
db [ 'dbSettings' ] . cache = 0 ;
exports . registerRoute = function ( hook _name , args , callback ) {
// Catching (un)subscribe addresses
2015-05-03 11:48:15 +00:00
args . app . get ( /\/p/ * /(un){0,1}subscribe=\/(.*)/ , function ( req , res ) {
2013-04-02 03:14:01 +00:00
var fullURL = req . protocol + "://" + req . get ( 'host' ) + req . url ;
var path = req . url . split ( "/" ) ;
var padId = path [ 2 ] ;
var param = path [ 3 ] . split ( "=" ) ;
var action = param [ 0 ] ;
var actionId = param [ 1 ] ;
var padURL = req . protocol + "://" + req . get ( 'host' ) + "/p/" + padId ;
2013-04-02 22:30:11 +00:00
async . waterfall (
2013-04-02 03:14:01 +00:00
[
function ( cb ) {
// Is the (un)subscription valid (exists & not older than 24h)
db . get ( "emailSubscription:" + padId , function ( err , userIds ) {
var foundInDb = false ;
var timeDiffGood = false ;
var email = "your email" ;
2013-04-02 22:30:11 +00:00
var resultDb = {
"foundInDb" : foundInDb ,
"timeDiffGood" : timeDiffGood ,
"email" : email
}
2013-04-02 03:14:01 +00:00
2013-04-02 22:30:11 +00:00
if ( userIds && userIds [ 'pending' ] ) {
2013-04-02 03:14:01 +00:00
async . forEach ( Object . keys ( userIds [ 'pending' ] ) , function ( user ) {
var userInfo = userIds [ 'pending' ] [ user ] ;
// If we have Id int the Db, then we are good ot really unsubscribe the user
if ( userInfo [ action + 'Id' ] == actionId ) {
console . debug ( "emailSubscription:" , user , "found in DB:" , userInfo ) ;
foundInDb = true ;
email = user ;
// Checking if the demand is not older than 24h
var timeDiff = new Date ( ) . getTime ( ) - userInfo . timestamp ;
timeDiffGood = timeDiff < 1000 * 60 * 60 * 24 ;
if ( action == 'subscribe' && timeDiffGood == true ) {
// Subscription process
setAuthorEmail (
userInfo ,
user
) ;
setAuthorEmailRegistered (
userIds ,
userInfo ,
user ,
padId
) ;
} else if ( action == 'unsubscribe' && timeDiffGood == true ) {
// Unsubscription process
unsetAuthorEmail (
userInfo ,
user
) ;
unsetAuthorEmailRegistered (
userIds ,
user ,
padId
) ;
}
2013-04-02 22:30:11 +00:00
resultDb = {
"foundInDb" : foundInDb ,
"timeDiffGood" : timeDiffGood ,
"email" : user
}
2013-04-02 03:14:01 +00:00
}
} ,
function ( err , msg ) {
2013-04-02 22:30:11 +00:00
if ( err != null ) {
console . error ( "Error in async.forEach" , err , " -> " , msg ) ;
}
2013-04-02 03:14:01 +00:00
} ) ; // end async for each
}
2013-04-02 22:30:11 +00:00
cb ( null , resultDb ) ;
2013-04-02 03:14:01 +00:00
} ) ;
} ,
2013-04-02 22:30:11 +00:00
function ( resultDb , cb ) {
2013-04-02 03:14:01 +00:00
// Create and send the output message
sendContent ( res , args , action , padId , padURL , resultDb ) ;
2013-04-02 22:30:11 +00:00
cb ( null , resultDb ) ;
2013-04-02 03:14:01 +00:00
} ,
2013-04-02 22:30:11 +00:00
function ( resultDb , cb ) {
2013-04-02 03:14:01 +00:00
// Take a moment to clean all obsolete pending data
cleanPendingData ( padId ) ;
2013-04-02 22:30:11 +00:00
cb ( null , resultDb ) ;
2013-04-02 03:14:01 +00:00
}
] ,
function ( err , results ) {
2013-04-02 22:30:11 +00:00
if ( err != null ) {
console . error ( "Callback async.series: Err -> " , err , " / results -> " , results ) ;
}
2013-04-02 03:14:01 +00:00
}
) ;
} ) ;
callback ( ) ; // Am I even called?
}
/ * *
* Database manipulation
* /
// Updates the database with the email record
setAuthorEmail = function ( userInfo , email ) {
db . setSub ( "globalAuthor:" + userInfo . authorId , [ "email" ] , email ) ;
}
// Write email and padId to the database
setAuthorEmailRegistered = function ( userIds , userInfo , email , padId ) {
console . debug ( "setAuthorEmailRegistered: Initial userIds:" , userIds ) ;
var timestamp = new Date ( ) . getTime ( ) ;
var registered = {
authorId : userInfo . authorId ,
onStart : userInfo . onStart ,
onEnd : userInfo . onEnd ,
timestamp : timestamp
} ;
// add the registered values to the object
userIds [ email ] = registered ;
// remove the pending data
delete userIds [ 'pending' ] [ email ] ;
// Write the modified datas back in the Db
console . warn ( "written to database" ) ;
db . set ( "emailSubscription:" + padId , userIds ) ; // stick it in the database
console . debug ( "setAuthorEmailRegistered: Modified userIds:" , userIds ) ;
}
// Updates the database by removing the email record for that AuthorId
unsetAuthorEmail = function ( userInfo , email ) {
db . get ( "globalAuthor:" + userInfo . authorId , function ( err , value ) { // get the current value
if ( value [ 'email' ] == email ) {
// Remove the email option from the datas
delete value [ 'email' ] ;
// Write the modified datas back in the Db
db . set ( "globalAuthor:" + userInfo . authorId , value ) ;
}
} ) ;
}
// Remove email, options and padId from the database
unsetAuthorEmailRegistered = function ( userIds , email , padId ) {
console . debug ( "unsetAuthorEmailRegistered: initial userIds:" , userIds ) ;
// remove the registered options from the object
delete userIds [ email ] ;
// remove the pending data
delete userIds [ 'pending' ] [ email ] ;
// Write the modified datas back in the Db
console . warn ( "written to database" ) ;
db . set ( "emailSubscription:" + padId , userIds ) ;
console . debug ( "unsetAuthorEmailRegistered: modified userIds:" , userIds ) ;
}
/ * *
* We take a moment to remove too old pending ( un ) subscription
* /
cleanPendingData = function ( padId ) {
var modifiedData , areDataModified = false ;
db . get ( "emailSubscription:" + padId , function ( err , userIds ) { // get the current value
console . debug ( "cleanPendingData: Initial userIds:" , userIds ) ;
modifiedData = userIds ;
if ( userIds && userIds [ 'pending' ] ) {
async . forEach ( Object . keys ( userIds [ 'pending' ] ) , function ( user ) {
var timeDiff = new Date ( ) . getTime ( ) - userIds [ 'pending' ] [ user ] . timestamp ;
var timeDiffGood = timeDiff < 1000 * 60 * 60 * 24 ;
if ( timeDiffGood == false ) {
delete modifiedData [ 'pending' ] [ user ] ;
areDataModified = true ;
}
} ) ;
}
if ( areDataModified == true ) {
// Write the modified datas back in the Db
db . set ( "emailSubscription:" + padId , modifiedData ) ;
}
console . debug ( "cleanPendingData: Modified userIds:" , modifiedData , " / areDataModified:" , areDataModified ) ;
} ) ;
}
/ * *
* Create html output with the status of the process
* /
function sendContent ( res , args , action , padId , padURL , resultDb ) {
console . debug ( "starting sendContent: args ->" , action , " / " , padId , " / " , padURL , " / " , resultDb ) ;
if ( action == 'subscribe' ) {
var actionMsg = "Subscribing '" + resultDb . email + "' to pad " + padId ;
} else {
var actionMsg = "Unsubscribing '" + resultDb . email + "' from pad " + padId ;
}
var msgCause , resultMsg , classResult ;
if ( resultDb . foundInDb == true && resultDb . timeDiffGood == true ) {
// Pending data were found un Db and updated -> good
resultMsg = "Success" ;
2013-04-03 03:16:18 +00:00
classResult = "validationGood" ;
if ( action == 'subscribe' ) {
msgCause = "You will receive email when someone changes this pad." ;
} else {
msgCause = "You won't receive anymore email when someone changes this pad." ;
}
2013-04-02 03:14:01 +00:00
} else if ( resultDb . foundInDb == true ) {
// Pending data were found but older than a day -> fail
resultMsg = "Too late!" ;
2013-04-03 03:16:18 +00:00
classResult = "validationBad" ;
msgCause = "You have max 24h to click the link in your confirmation email." ;
2013-04-02 03:14:01 +00:00
} else {
// Pending data weren't found in Db -> fail
2013-04-03 03:16:18 +00:00
resultMsg = "Fail" ;
classResult = "validationBad" ;
2013-04-02 03:14:01 +00:00
msgCause = "We couldn't find any pending " + ( action == 'subscribe' ? 'subscription' : 'unsubscription' ) + "<br />in our system with this Id.<br />Maybe you wait more than 24h before validating" ;
}
2013-04-03 03:16:18 +00:00
args . content = fs . readFileSync ( _ _dirname + "/templates/response.ejs" , 'utf-8' ) ;
args . content = args . content
. replace ( /\<%action%\>/ , actionMsg )
. replace ( /\<%classResult%\>/ , classResult )
. replace ( /\<%result%\>/ , resultMsg )
. replace ( /\<%explanation%\>/ , msgCause )
. replace ( /\<%padUrl%\>/g , padURL ) ;
2013-04-02 03:14:01 +00:00
2013-04-03 03:16:18 +00:00
res . contentType ( "text/html; charset=utf-8" ) ;
res . send ( args . content ) ; // Send it to the requester*/
2013-04-02 03:14:01 +00:00
}