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 | ||||
| * stop the ui prompting if already subscribed | ||||
| * send actual emails with content | ||||
| * move settings to settings.json | ||||
| * 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", | ||||
|       "hooks": { | ||||
|         "padUpdate": "ep_email_notifications/update", | ||||
|         "handleMessage": "ep_email_notifications/update", | ||||
|         "handleMessage": "ep_email_notifications/handleMessage", | ||||
|         "eejsBlock_scripts": "ep_email_notifications/client", | ||||
|         "eejsBlock_editbarMenuRight": "ep_email_notifications/client:eejsBlock_toolbarRight", | ||||
|         "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
 | ||||
|   }); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										169
									
								
								update.js
									
										
									
									
									
								
							
							
						
						
									
										169
									
								
								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, | ||||
|      API = require('../../src/node/db/API.js'), | ||||
|    async = require('../../src/node_modules/async'), | ||||
|    check = require('validator').check, | ||||
|    email = require('emailjs'), | ||||
| settings = require('../../src/node/utils/Settings'); | ||||
| 
 | ||||
| var pluginSettings = settings.ep_email_notifications; | ||||
| var checkInterval = 60000; // Move me to the settings file
 | ||||
| var staleTime = 3600000; // Move me to settings
 | ||||
| var checkInterval = 3000; // How frequently to check for pad updates -- Move me to the settings file
 | ||||
| var staleTime = 3000; // How stale does a pad need to be before notifying subscribers?  Move me to settings
 | ||||
| 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
 | ||||
| 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.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; | ||||
|   }); | ||||
| } | ||||
| var server  = email.server.connect({ | ||||
|    user:    "username",  | ||||
|    password:"password",  | ||||
|    host:    "smtp.gmail.com",  | ||||
| }); | ||||
| 
 | ||||
| exports.padUpdate = function (hook_name, _pad) { | ||||
| 
 | ||||
|  | @ -102,6 +29,8 @@ exports.padUpdate = function (hook_name, _pad) { | |||
| 
 | ||||
|   // does an interval not exist for this pad?
 | ||||
|   if(!timers[padId]){ | ||||
|     console.warn("Someone started editing "+padId); | ||||
|     exports.notifyBegin(padId); | ||||
|     console.debug("Created an interval time check for "+padId); | ||||
|     // if not then create one and write it to the timers object
 | ||||
|     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){ | ||||
| 
 | ||||
|   // 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.
 | ||||
|     var currTS = new Date().getTime(); | ||||
|     if(currTS - message.lastEdited > staleTime){ | ||||
|       exports.notifyEnd(padId); | ||||
|       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{ | ||||
|       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…
	
	Add table
		
		Reference in a new issue
	
	 John McLear
						John McLear