From 53c1df824838d164468b6a95113cbc3e1db57dfe Mon Sep 17 00:00:00 2001
From: etherpad
Date: Tue, 26 Mar 2013 20:44:34 +0100
Subject: [PATCH 01/22] Unsubscription & choose to receive a mail onStart /
onEnd
- The subscription panel is placed in the "mysettings" menu (not anymmore a popup)
- A Unsubscribe button were added. It removes the email if found
- The 2 options to receive a mail when someone is starting to edit and finished to edit can be chosen for each user (at least one of the two is compulsory)
- First time you go on the email notification panel in the mysettings menu, a call is made to get the email and options already subscribed for this userId
* If found, the form is pre-filled with the datas
* If not, the form is set with defaults values
It's just informative. Users can still subscribe another mail for this userId.
- Removed the integration of this plugin in the "Share this pad" menu. First becaue, imo, it's not the place, and second, because it meant 2 forms with the same id.
---
client.js | 14 ++
ep.json | 7 +-
handleMessage.js | 198 ++++++++++++++-----
static/css/email_notifications.css | 10 +
static/js/ep_email.js | 210 +++++++++++++++------
templates/email_notifications_settings.ejs | 20 ++
update.js | 9 +-
7 files changed, 359 insertions(+), 109 deletions(-)
create mode 100644 static/css/email_notifications.css
create mode 100644 templates/email_notifications_settings.ejs
diff --git a/client.js b/client.js
index 4f465ba..86da61c 100644
--- a/client.js
+++ b/client.js
@@ -1,11 +1,25 @@
var eejs = require("ep_etherpad-lite/node/eejs");
+var settings = require('ep_etherpad-lite/node/utils/Settings');
+var checked_state = '';
exports.eejsBlock_scripts = function (hook_name, args, cb) {
args.content = args.content + eejs.require("ep_email_notifications/templates/scripts.html", {}, module);
return cb();
};
+/*
exports.eejsBlock_embedPopup = function (hook_name, args, cb) {
args.content = args.content + eejs.require("ep_email_notifications/templates/embedFrame.html", {}, module);
return cb();
};
+*/
+
+exports.eejsBlock_mySettings = function (hook_name, args, cb) {
+ args.content = args.content + eejs.require('ep_email_notifications/templates/email_notifications_settings.ejs', {checked : checked_state});
+ return cb();
+};
+
+exports.eejsBlock_styles = function (hook_name, args, cb) {
+ args.content = args.content + '';
+};
+
diff --git a/ep.json b/ep.json
index b9471cf..9202804 100644
--- a/ep.json
+++ b/ep.json
@@ -6,11 +6,14 @@
"padUpdate": "ep_email_notifications/update",
"handleMessage": "ep_email_notifications/handleMessage",
"eejsBlock_scripts": "ep_email_notifications/client",
- "eejsBlock_embedPopup": "ep_email_notifications/client:eejsBlock_embedPopup"
+ "eejsBlock_mySettings": "ep_email_notifications/client:eejsBlock_mySettings",
+ "eejsBlock_styles": "ep_email_notifications/client:eejsBlock_styles"
},
"client_hooks": {
"postAceInit":"ep_email_notifications/static/js/ep_email:postAceInit",
- "handleClientMessage_emailSubscriptionSuccess":"ep_email_notifications/static/js/ep_email"
+ "handleClientMessage_emailSubscriptionSuccess":"ep_email_notifications/static/js/ep_email",
+ "handleClientMessage_emailUnsubscriptionSuccess":"ep_email_notifications/static/js/ep_email",
+ "handleClientMessage_emailNotificationGetUserInfo":"ep_email_notifications/static/js/ep_email"
}
}
]
diff --git a/handleMessage.js b/handleMessage.js
index e48d044..4aa2d97 100644
--- a/handleMessage.js
+++ b/handleMessage.js
@@ -13,24 +13,135 @@ exports.handleMessage = function(hook_name, context, callback){
if (context.message.data.userInfo){
if(context.message.data.userInfo.email){ // it contains email
console.debug(context.message);
+ console.info("ep_mail: " + context.message.data.userInfo.email + " / " + context.message.data.userInfo.email_option);
+ console.info(context.message.data.userInfo);
// does email Subscription already exist for this email address?
db.get("emailSubscription:"+context.message.data.padId, function(err, userIds){
var alreadyExists = false;
+ console.info(userIds);
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
-
+ console.info("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");
+ }
+ cb();
+ },
+ function(err){
+ // There should be something in here!
+ }); // end async for each
+ }
+
+ if(context.message.data.userInfo.email_option == 'subscribe' && alreadyExists == true){
+ // SUbscription
+ console.info("email ", context.message.data.userInfo.email, "already subscribed to ", context.message.data.padId, " so sending message to client");
+
+ context.client.json.send({ type: "COLLABROOM",
+ data:{
+ type: "emailSubscriptionSuccess",
+ payload: false
+ }
+ });
+ } else if(context.message.data.userInfo.email_option == 'subscribe' && alreadyExists == false){
+ // SUbscription
+ 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
+ }
+ });
+ } else {
+ console.info ("Subscription: 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,
+ callback
+ );
+
+ exports.setAuthorEmailRegistered(
+ context.message.data.userInfo,
+ context.message.data.userInfo.userId,
+ context.message.data.padId
+ );
+
+ context.client.json.send({ type: "COLLABROOM",
+ data:{
+ type: "emailSubscriptionSuccess",
+ payload: true
+ }
+ });
+ }
+ } else if(context.message.data.userInfo.email_option == 'unsubscribe' && alreadyExists == true) {
+ // Unsubscription
+ console.info ("Unsubscription: Remove from the database and sent client a positive response ",context.message.data.userInfo.email);
+
+ exports.unsetAuthorEmail(
+ context.message.data.userInfo.userId,
+ context.message.data.userInfo,
+ callback
+ );
+
+ exports.unsetAuthorEmailRegistered(
+ context.message.data.userInfo,
+ context.message.data.userInfo.userId,
+ context.message.data.padId
+ );
+
+ context.client.json.send({ type: "COLLABROOM",
+ data:{
+ type: "emailUnsubscriptionSuccess",
+ payload: true
+ }
+ });
+ } else if(context.message.data.userInfo.email_option == 'unsubscribe' && alreadyExists == false) {
+ // Unsubscription
+ console.info ("Unsubscription: Send client a negative response ",context.message.data.userInfo.email);
+
+ context.client.json.send({ type: "COLLABROOM",
+ data:{
+ type: "emailUnsubscriptionSuccess",
+ payload: false
+ }
+ });
+ }
+ }); // close db get
+
+ callback([null]); // don't run onto passing colorId or anything else to the message handler
+
+ }
+ }
+ } else if (context.message.data.type == 'USERINFO_GET' ) { // A request to find datas for a username
+ if (context.message.data.userInfo){
+ if(context.message.data.userInfo.userId){ // it contains the userId
+ console.debug(context.message);
+
+ var userIdFound = false;
+ // does email Subscription already exist for this name and padID?
+ db.get("emailSubscription:"+context.message.data.padId, function(err, userIds){
+ if(userIds){
+ async.forEach(Object.keys(userIds), function(user, cb){
+ if(userIds[user].authorId == context.message.data.userInfo.userId){ // if we find the same Id in the Db as the one used by the user
+ console.info("Options for this pad ", userIds[user].authorId, " found in the Db");
+ userIdFound = true;
+
+ // We send back the options set for this user
context.client.json.send({ type: "COLLABROOM",
data:{
- type: "emailSubscriptionSuccess",
- payload: false
+ type: "emailNotificationGetUserInfo",
+ payload: {
+ email: user,
+ onStart: userIds[user].onStart && typeof userIds[user].onStart === 'boolean'?userIds[user].onStart:true,
+ onEnd: userIds[user].onEnd && typeof userIds[user].onEnd === 'boolean'?userIds[user].onEnd:false,
+ success:true
+ }
}
});
}
@@ -41,41 +152,19 @@ exports.handleMessage = function(hook_name, context, callback){
// 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
+ });
+ if (!userIdFound) {
+ // We send back the options set for this user
+ context.client.json.send({ type: "COLLABROOM",
+ data:{
+ type: "emailNotificationGetUserInfo",
+ payload: {
+ success:false
+ }
+ }
+ });
+ }
}
}
}
@@ -84,25 +173,46 @@ exports.handleMessage = function(hook_name, context, callback){
}
// Updates the database with the email record
-exports.setAuthorEmail = function (author, email, callback){
- db.setSub("globalAuthor:" + author, ["email"], email, callback);
+exports.setAuthorEmail = function (author, datas, callback){
+ db.setSub("globalAuthor:" + author, ["email"], datas.email, callback);
}
// Write email and padId to the database
-exports.setAuthorEmailRegistered = function(email, authorId, padId){
+exports.setAuthorEmailRegistered = function(datas, authorId, padId){
var timestamp = new Date().getTime();
var registered = {
authorId: authorId,
+ onStart: datas.email_onStart,
+ onEnd: datas.email_onEnd,
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
+ value[datas.email] = registered; // add the registered values to the object
console.warn("written to database");
db.set("emailSubscription:" + padId, value); // stick it in the database
});
}
+// Updates the database by removing the email record for that AuthorId
+exports.unsetAuthorEmail = function (author, datas, callback){
+ db.get("globalAuthor:" + author, function(err, value){ // get the current value
+ delete value['email'];
+ db.set("globalAuthor:" + author, value);
+ });
+}
+
+// Remove email and padId from the database
+exports.unsetAuthorEmailRegistered = function(datas, authorId, padId){
+ console.debug("unregistered", datas.email, " 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
+ delete value[datas.email]; // remove the registered values to the object
+ console.warn("written to database");
+ db.set("emailSubscription:" + padId, value); // stick it in the database
+ });
+
+}
diff --git a/static/css/email_notifications.css b/static/css/email_notifications.css
new file mode 100644
index 0000000..f8e3264
--- /dev/null
+++ b/static/css/email_notifications.css
@@ -0,0 +1,10 @@
+.ep_email_settings {
+ display: none;
+ padding-left: 1.5em;
+ padding: .2em;
+}
+
+.ep_email_input {
+ padding:.2em;
+ width:177px;
+}
diff --git a/static/js/ep_email.js b/static/js/ep_email.js
index 9f70476..709b3a4 100644
--- a/static/js/ep_email.js
+++ b/static/js/ep_email.js
@@ -1,19 +1,44 @@
var cookie = require('ep_etherpad-lite/static/js/pad_cookie').padcookie;
+var firstRun = true;
if(typeof exports == 'undefined'){
var exports = this['mymodule'] = {};
}
exports.postAceInit = function(hook, context){
- // after 10 seconds if we dont already have an email for this author then prompt them
- setTimeout(function(){init()},10000);
+ // Uncheck the checkbox
+ $('#options-emailNotifications').attr('checked', false);
+ setDefaultOptions();
+
+ /* on click */
+ $('#options-emailNotifications').on('click', function() {
+ if (firstRun) {
+ getDatasForUserId();
+ firstRun = false;
+ } else {
+ $('.ep_email_settings').slideToggle();
+ }
+ });
+
+ // Prepare subscription before submit form
+ $('#ep_email_subscribe').on('click', function() {
+ $('#ep_email_option').val('subscribe');
+ checkAndSend();
+ });
+
+ // Prepare unsubscription before submit form
+ $('#ep_email_unsubscribe').on('click', function() {
+ $('#ep_email_option').val('unsubscribe');
+ checkAndSend();
+ });
// subscribe by email can be active..
$('.ep_email_form').submit(function(){
sendEmailToServer();
+ $('.ep_email_settings').slideToggle();
+ $('#options-emailNotifications').attr('checked', false);
return false;
});
-
}
exports.handleClientMessage_emailSubscriptionSuccess = function(hook, context){ // was subscribing to the email a big win or fail?
@@ -24,21 +49,108 @@ exports.handleClientMessage_emailSubscriptionSuccess = function(hook, context){
}
}
-function init(){
- var popUpIsAlreadyVisible = $('.ep_email_form').is(":visible");
- if(!popUpIsAlreadyVisible){ // if the popup isn't already visible
- if(clientHasAlreadyRegistered()){ // if the client has already registered for emails on this pad.
- // showAlreadyRegistered(); // client has already registered, let em know..
- }else{
- var cookieVal = pad.getPadId() + "email";
- if(cookie.getPref(cookieVal) !== "true"){ // if this user hasn't already subscribed
- askClientToEnterEmail(); // ask the client to register TODO uncomment me for a pop up
- }
- }
+exports.handleClientMessage_emailUnsubscriptionSuccess = function(hook, context){ // was subscribing to the email a big win or fail?
+ if(context.payload == false){
+ showWasNotRegistered();
+ }else{
+ showUnregistrationSuccess();
}
}
-function showRegistrationSuccess(){ // show a successful registration message
+exports.handleClientMessage_emailNotificationGetUserInfo = function (hook, context) { // return the existing options for this userId
+ var datas = context.payload;
+ if(datas.success == true){ // If datas were found, set the options with them
+ if (datas.email) $('#ep_email').val(datas.email);
+ if (datas.onStart && typeof datas.onStart === 'boolean') $('#ep_email_onStart').attr('checked', datas.onStart);
+ if (datas.onEnd && typeof datas.onEnd === 'boolean') $('#ep_email_onEnd').attr('checked', datas.onEnd);
+ } else { // No datas were found, set the options to default values
+ setDefaultOptions();
+ }
+
+ $('.ep_email_settings').slideToggle();
+}
+
+/**
+ * Set the options in the frame to a default value
+ */
+function setDefaultOptions() {
+ $('#ep_email_onStart').attr('checked', true);
+ $('#ep_email_onEnd').attr('checked', false);
+}
+
+/**
+ * Control options before submitting the form
+ */
+function checkAndSend() {
+ var email = getEmail();
+ if (email && $('#ep_email_option').val() == 'subscribe' && !$('#ep_email_onStart').is(':checked') && !$('#ep_email_onEnd').is(':checked')) {
+ $.gritter.add({
+ // (string | mandatory) the heading of the notification
+ title: "Email subscription error",
+ // (string | mandatory) the text inside the notification
+ text: "You need to check at least one of the two options from 'Send a mail when someone..'"
+ });
+ } else if (email) {
+ $('.ep_email_form').submit();
+ }
+ return false;
+}
+
+/**
+ * Return the email from the user
+ */
+function getEmail() {
+ var email = $('#ep_email').val();
+ if(!email){ // if we're not using the top value use the notification value
+ email = $('#ep_email_notification').val();
+ }
+ return email;
+}
+
+/**
+ * Ask the server to register the email
+ */
+function sendEmailToServer(){
+ var email = getEmail();
+ var userId = pad.getUserId();
+ var message = {};
+ message.type = 'USERINFO_UPDATE';
+ message.userInfo = {};
+ message.padId = pad.getPadId();
+ message.userInfo.email = email;
+ message.userInfo.email_option = $('#ep_email_option').val();
+ message.userInfo.email_onStart = $('#ep_email_onStart').is(':checked');
+ message.userInfo.email_onEnd = $('#ep_email_onEnd').is(':checked');
+ message.userInfo.userId = userId;
+ if(email){
+ pad.collabClient.sendMessage(message);
+ cookie.setPref(message.padId+"email", "true");
+ }
+}
+
+/**
+ * Thanks to the userId, we can get back from the Db the options set for this user
+ * and fill the fields with them
+ */
+function getDatasForUserId() {
+ var userId = pad.getUserId();
+ var message = {};
+ message.type = 'USERINFO_GET';
+ message.padId = pad.getPadId();
+ message.userInfo = {};
+ message.userInfo.userId = userId;
+
+ pad.collabClient.sendMessage(message);
+}
+
+/*************************************
+Manage return msgs from server
+*************************************/
+
+/**
+ * Show a successful registration message
+ */
+function showRegistrationSuccess(){
$.gritter.add({
// (string | mandatory) the heading of the notification
title: "Email subscribed",
@@ -47,7 +159,10 @@ function showRegistrationSuccess(){ // show a successful registration message
});
}
-function showAlreadyRegistered(){ // the client already registered for emails on this pad so notify the UI
+/**
+ * The client already registered for emails on this pad so notify the UI
+ */
+function showAlreadyRegistered(){
$.gritter.add({
// (string | mandatory) the heading of the notification
title: "Email subscription",
@@ -59,54 +174,29 @@ function showAlreadyRegistered(){ // the client already registered for emails on
}
-function clientHasAlreadyRegistered(){ // Has the client already registered for emails on this?
- // Given a specific AuthorID do we have an email address in the database?
- // Given that email address is it registered to this pad?
- // need to pass the server a message to check
- var userId = pad.getUserId();
- var message = {};
- message.type = 'USERINFO_AUTHOR_EMAIL_IS_REGISTERED_TO_PAD';
- message.userInfo = {};
- message.userInfo.userId = userId;
- pad.collabClient.sendMessage(message);
-}
-
-function askClientToEnterEmail(){
+/**
+ * Show a successful unregistration message
+ */
+function showUnregistrationSuccess(){
$.gritter.add({
// (string | mandatory) the heading of the notification
- title: "Enter your email to receive an email when someone modifies this pad",
+ title: "Email unsubscribed",
// (string | mandatory) the text inside the notification
- text: "",
- // (bool | optional) if you want it to fade out on its own or just sit there
- sticky: true,
- // (int | optional) the time you want it to be alive for before fading out
- time: '2000',
- // the function to bind to the form
- after_open: function(e){
- $('.ep_email_form').submit(function(){
- $(e).hide();
- sendEmailToServer();
- return false;
- });
- }
+ text: "You won't receive anymore email when someone changes this pad."
});
}
-function sendEmailToServer(){
- var email = $('#ep_email').val();
- if(!email){ // if we're not using the top value use the notification value
- email = $('#ep_email_notification').val();
- }
- var userId = pad.getUserId();
- var message = {};
- message.type = 'USERINFO_UPDATE';
- message.userInfo = {};
- message.padId = pad.getPadId();
- message.userInfo.email = email;
- message.userInfo.userId = userId;
- if(email){
- pad.collabClient.sendMessage(message);
- cookie.setPref(message.padId+"email", "true");
- }
-}
+/**
+ * The client wasn't registered for emails
+ */
+function showWasNotRegistered(){
+ $.gritter.add({
+ // (string | mandatory) the heading of the notification
+ title: "Email unsubscription",
+ // (string | mandatory) the text inside the notification
+ text: "This email address is not registered for this pad",
+ // (bool | optional) if you want it to fade out on its own or just sit there
+ sticky: false
+ });
+}
diff --git a/templates/email_notifications_settings.ejs b/templates/email_notifications_settings.ejs
new file mode 100644
index 0000000..b935e7a
--- /dev/null
+++ b/templates/email_notifications_settings.ejs
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/update.js b/update.js
index 49d1905..a6653fa 100644
--- a/update.js
+++ b/update.js
@@ -45,10 +45,11 @@ exports.notifyBegin = function(padId){
async.forEach(Object.keys(recipients), function(recipient, cb){
// Is this recipient already on the pad?
exports.isUserEditingPad(padId, recipients[recipient].authorId, function(err,userIsOnPad){ // is the user already on the pad?
- if(!userIsOnPad){
+ 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({
- text: "Your pad at "+urlToPads+padId +" is being edited, we're just emailing you let you know :)\n\n -- This plugin is in alpha state, can you help fund it's development? https://github.com/johnmclear/ep_email_notifications",
+ text: "Your pad at "+urlToPads+padId +" is being edited, we're just emailing you let you know :)",
from: fromName+ "<"+fromEmail+">",
to: recipient,
subject: "Someone started editing "+padId
@@ -76,7 +77,9 @@ exports.notifyEnd = function(padId){
async.forEach(Object.keys(recipients), function(recipient, cb){
// Is this recipient already on the pad?
exports.isUserEditingPad(padId, recipients[recipient].authorId, function(err,userIsOnPad){ // is the user already on the$
- if(!userIsOnPad){
+ var onEnd = typeof(recipients[recipient].onEnd) == "undefined" || recipients[recipient].onEnd?true:false; // In case onEnd wasn't defined we set it to true
+
+ if(!userIsOnPad && onEnd){
console.debug("Emailing "+recipient +" about a pad finished being updated");
server.send({
text: "Your pad at "+urlToPads+padId +" has finished being edited, we're just emailing you let you know :) \n\n The changes look like this: \n" + changesToPad,
From 907ecb9a7b6b926923fa97e2788b6619e26ce18c Mon Sep 17 00:00:00 2001
From: quenenni
Date: Tue, 26 Mar 2013 21:40:02 +0100
Subject: [PATCH 02/22] Small corrections
- put back msgs to the debug level instead of info
- remove a call to ep_etherpad-lite/node/utils/Settings as it was for a function that doesn't exist anymore
- remove checked_state var for the form as I manage myself the default check for the options.
---
client.js | 4 +---
handleMessage.js | 15 ++++++---------
2 files changed, 7 insertions(+), 12 deletions(-)
diff --git a/client.js b/client.js
index 86da61c..4a9a1e5 100644
--- a/client.js
+++ b/client.js
@@ -1,6 +1,4 @@
var eejs = require("ep_etherpad-lite/node/eejs");
-var settings = require('ep_etherpad-lite/node/utils/Settings');
-var checked_state = '';
exports.eejsBlock_scripts = function (hook_name, args, cb) {
args.content = args.content + eejs.require("ep_email_notifications/templates/scripts.html", {}, module);
@@ -15,7 +13,7 @@ exports.eejsBlock_embedPopup = function (hook_name, args, cb) {
*/
exports.eejsBlock_mySettings = function (hook_name, args, cb) {
- args.content = args.content + eejs.require('ep_email_notifications/templates/email_notifications_settings.ejs', {checked : checked_state});
+ args.content = args.content + eejs.require('ep_email_notifications/templates/email_notifications_settings.ejs');
return cb();
};
diff --git a/handleMessage.js b/handleMessage.js
index 4aa2d97..00064b4 100644
--- a/handleMessage.js
+++ b/handleMessage.js
@@ -13,17 +13,14 @@ exports.handleMessage = function(hook_name, context, callback){
if (context.message.data.userInfo){
if(context.message.data.userInfo.email){ // it contains email
console.debug(context.message);
- console.info("ep_mail: " + context.message.data.userInfo.email + " / " + context.message.data.userInfo.email_option);
- console.info(context.message.data.userInfo);
// does email Subscription already exist for this email address?
db.get("emailSubscription:"+context.message.data.padId, function(err, userIds){
var alreadyExists = false;
- console.info(userIds);
if(userIds){
async.forEach(Object.keys(userIds), function(user, cb){
- console.info("UserIds subscribed by email to this pad:", userIds);
+ 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;
@@ -38,7 +35,7 @@ exports.handleMessage = function(hook_name, context, callback){
if(context.message.data.userInfo.email_option == 'subscribe' && alreadyExists == true){
// SUbscription
- console.info("email ", context.message.data.userInfo.email, "already subscribed to ", context.message.data.padId, " so sending message to client");
+ console.debug("email ", context.message.data.userInfo.email, "already subscribed to ", context.message.data.padId, " so sending message to client");
context.client.json.send({ type: "COLLABROOM",
data:{
@@ -58,7 +55,7 @@ exports.handleMessage = function(hook_name, context, callback){
}
});
} else {
- console.info ("Subscription: Wrote to the database and sent client a positive response ",context.message.data.userInfo.email);
+ console.debug ("Subscription: Wrote to the database and sent client a positive response ",context.message.data.userInfo.email);
exports.setAuthorEmail(
context.message.data.userInfo.userId,
@@ -81,7 +78,7 @@ exports.handleMessage = function(hook_name, context, callback){
}
} else if(context.message.data.userInfo.email_option == 'unsubscribe' && alreadyExists == true) {
// Unsubscription
- console.info ("Unsubscription: Remove from the database and sent client a positive response ",context.message.data.userInfo.email);
+ console.debug ("Unsubscription: Remove from the database and sent client a positive response ",context.message.data.userInfo.email);
exports.unsetAuthorEmail(
context.message.data.userInfo.userId,
@@ -103,7 +100,7 @@ exports.handleMessage = function(hook_name, context, callback){
});
} else if(context.message.data.userInfo.email_option == 'unsubscribe' && alreadyExists == false) {
// Unsubscription
- console.info ("Unsubscription: Send client a negative response ",context.message.data.userInfo.email);
+ console.debug ("Unsubscription: Send client a negative response ",context.message.data.userInfo.email);
context.client.json.send({ type: "COLLABROOM",
data:{
@@ -129,7 +126,7 @@ exports.handleMessage = function(hook_name, context, callback){
if(userIds){
async.forEach(Object.keys(userIds), function(user, cb){
if(userIds[user].authorId == context.message.data.userInfo.userId){ // if we find the same Id in the Db as the one used by the user
- console.info("Options for this pad ", userIds[user].authorId, " found in the Db");
+ console.debug("Options for this pad ", userIds[user].authorId, " found in the Db");
userIdFound = true;
// We send back the options set for this user
From 7d3d2a2920b04c0064909c985c9b7dfc738a07ee Mon Sep 17 00:00:00 2001
From: quenenni
Date: Wed, 27 Mar 2013 02:19:27 +0100
Subject: [PATCH 03/22] Changed tabs to spaces & removed trailing spaces
---
client.js | 8 ---
ep.json | 4 +-
handleMessage.js | 63 ++++++++++++----------
static/css/email_notifications.css | 10 ++--
static/js/ep_email.js | 8 +--
templates/email_notifications_settings.ejs | 28 +++++-----
update.js | 6 +--
7 files changed, 64 insertions(+), 63 deletions(-)
diff --git a/client.js b/client.js
index 4a9a1e5..ef960a8 100644
--- a/client.js
+++ b/client.js
@@ -5,13 +5,6 @@ exports.eejsBlock_scripts = function (hook_name, args, cb) {
return cb();
};
-/*
-exports.eejsBlock_embedPopup = function (hook_name, args, cb) {
- args.content = args.content + eejs.require("ep_email_notifications/templates/embedFrame.html", {}, module);
- return cb();
-};
-*/
-
exports.eejsBlock_mySettings = function (hook_name, args, cb) {
args.content = args.content + eejs.require('ep_email_notifications/templates/email_notifications_settings.ejs');
return cb();
@@ -20,4 +13,3 @@ exports.eejsBlock_mySettings = function (hook_name, args, cb) {
exports.eejsBlock_styles = function (hook_name, args, cb) {
args.content = args.content + '';
};
-
diff --git a/ep.json b/ep.json
index 9202804..f77ce2a 100644
--- a/ep.json
+++ b/ep.json
@@ -6,8 +6,8 @@
"padUpdate": "ep_email_notifications/update",
"handleMessage": "ep_email_notifications/handleMessage",
"eejsBlock_scripts": "ep_email_notifications/client",
- "eejsBlock_mySettings": "ep_email_notifications/client:eejsBlock_mySettings",
- "eejsBlock_styles": "ep_email_notifications/client:eejsBlock_styles"
+ "eejsBlock_mySettings": "ep_email_notifications/client:eejsBlock_mySettings",
+ "eejsBlock_styles": "ep_email_notifications/client:eejsBlock_styles"
},
"client_hooks": {
"postAceInit":"ep_email_notifications/static/js/ep_email:postAceInit",
diff --git a/handleMessage.js b/handleMessage.js
index 00064b4..6b724f5 100644
--- a/handleMessage.js
+++ b/handleMessage.js
@@ -33,20 +33,21 @@ exports.handleMessage = function(hook_name, context, callback){
}); // end async for each
}
- if(context.message.data.userInfo.email_option == 'subscribe' && alreadyExists == true){
- // SUbscription
- console.debug("email ", context.message.data.userInfo.email, "already subscribed to ", context.message.data.padId, " so sending message to client");
+ if(context.message.data.userInfo.email_option == 'subscribe' && alreadyExists == true){
+ // SUbscription
+ console.debug("email ", context.message.data.userInfo.email, "already subscribed to ", context.message.data.padId, " so sending message to client");
- context.client.json.send({ type: "COLLABROOM",
+ context.client.json.send({ type: "COLLABROOM",
data:{
type: "emailSubscriptionSuccess",
payload: false
}
});
} else if(context.message.data.userInfo.email_option == 'subscribe' && alreadyExists == false){
- // SUbscription
+ // SUbscription
var validatesAsEmail = check(context.message.data.userInfo.email).isEmail();
- if(!validatesAsEmail){ // send validation failed if it's malformed.. y'know in general fuck em!
+ if(!validatesAsEmail){
+ // Subscription -> failed coz mail malformed.. y'know in general fuck em!
console.warn("Dropped email subscription due to malformed email address");
context.client.json.send({ type: "COLLABROOM",
data:{
@@ -55,12 +56,13 @@ exports.handleMessage = function(hook_name, context, callback){
}
});
} else {
+ // Subscription -> Go for it
console.debug ("Subscription: 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,
- callback
+ callback
);
exports.setAuthorEmailRegistered(
@@ -75,15 +77,15 @@ exports.handleMessage = function(hook_name, context, callback){
payload: true
}
});
- }
+ }
} else if(context.message.data.userInfo.email_option == 'unsubscribe' && alreadyExists == true) {
- // Unsubscription
+ // Unsubscription -> Go for it
console.debug ("Unsubscription: Remove from the database and sent client a positive response ",context.message.data.userInfo.email);
- exports.unsetAuthorEmail(
+ exports.unsetAuthorEmail(
context.message.data.userInfo.userId,
context.message.data.userInfo,
- callback
+ callback
);
exports.unsetAuthorEmailRegistered(
@@ -98,17 +100,17 @@ exports.handleMessage = function(hook_name, context, callback){
payload: true
}
});
- } else if(context.message.data.userInfo.email_option == 'unsubscribe' && alreadyExists == false) {
- // Unsubscription
- console.debug ("Unsubscription: Send client a negative response ",context.message.data.userInfo.email);
+ } else if(context.message.data.userInfo.email_option == 'unsubscribe' && alreadyExists == false) {
+ // Unsubscription -> Send failed as email not found
+ console.debug ("Unsubscription: Send client a negative response ",context.message.data.userInfo.email);
- context.client.json.send({ type: "COLLABROOM",
+ context.client.json.send({ type: "COLLABROOM",
data:{
type: "emailUnsubscriptionSuccess",
payload: false
}
});
- }
+ }
}); // close db get
callback([null]); // don't run onto passing colorId or anything else to the message handler
@@ -121,7 +123,7 @@ exports.handleMessage = function(hook_name, context, callback){
console.debug(context.message);
var userIdFound = false;
- // does email Subscription already exist for this name and padID?
+ // does email Subscription already exist for this UserId?
db.get("emailSubscription:"+context.message.data.padId, function(err, userIds){
if(userIds){
async.forEach(Object.keys(userIds), function(user, cb){
@@ -129,7 +131,7 @@ exports.handleMessage = function(hook_name, context, callback){
console.debug("Options for this pad ", userIds[user].authorId, " found in the Db");
userIdFound = true;
- // We send back the options set for this user
+ // We send back the options associated to this userId
context.client.json.send({ type: "COLLABROOM",
data:{
type: "emailNotificationGetUserInfo",
@@ -152,13 +154,13 @@ exports.handleMessage = function(hook_name, context, callback){
});
if (!userIdFound) {
- // We send back the options set for this user
+ // No options set for this userId
context.client.json.send({ type: "COLLABROOM",
data:{
type: "emailNotificationGetUserInfo",
payload: {
success:false
- }
+ }
}
});
}
@@ -197,19 +199,26 @@ exports.setAuthorEmailRegistered = function(datas, authorId, padId){
// Updates the database by removing the email record for that AuthorId
exports.unsetAuthorEmail = function (author, datas, callback){
db.get("globalAuthor:" + author, function(err, value){ // get the current value
+
+ // Remove the email option from the datas
delete value['email'];
+
+ // Write the modified datas back in the Db
db.set("globalAuthor:" + author, value);
});
}
-// Remove email and padId from the database
+// Remove email, options and padId from the database
exports.unsetAuthorEmailRegistered = function(datas, authorId, padId){
console.debug("unregistered", datas.email, " 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
- delete value[datas.email]; // remove the registered values to the object
- console.warn("written to database");
- db.set("emailSubscription:" + padId, value); // stick it in the database
- });
+ db.get("emailSubscription:" + padId, function(err, value){ // get the current value
+
+ // remove the registered options from the object
+ delete value[datas.email];
+
+ // Write the modified datas back in the Db
+ console.warn("written to database");
+ db.set("emailSubscription:" + padId, value);
+ });
}
diff --git a/static/css/email_notifications.css b/static/css/email_notifications.css
index f8e3264..71c61d7 100644
--- a/static/css/email_notifications.css
+++ b/static/css/email_notifications.css
@@ -1,10 +1,10 @@
.ep_email_settings {
- display: none;
- padding-left: 1.5em;
- padding: .2em;
+ display: none;
+ padding-left: 1.5em;
+ padding: .2em;
}
.ep_email_input {
- padding:.2em;
- width:177px;
+ padding:.2em;
+ width:177px;
}
diff --git a/static/js/ep_email.js b/static/js/ep_email.js
index 709b3a4..d93dde1 100644
--- a/static/js/ep_email.js
+++ b/static/js/ep_email.js
@@ -22,14 +22,14 @@ exports.postAceInit = function(hook, context){
// Prepare subscription before submit form
$('#ep_email_subscribe').on('click', function() {
- $('#ep_email_option').val('subscribe');
- checkAndSend();
+ $('#ep_email_option').val('subscribe');
+ checkAndSend();
});
// Prepare unsubscription before submit form
$('#ep_email_unsubscribe').on('click', function() {
- $('#ep_email_option').val('unsubscribe');
- checkAndSend();
+ $('#ep_email_option').val('unsubscribe');
+ checkAndSend();
});
// subscribe by email can be active..
diff --git a/templates/email_notifications_settings.ejs b/templates/email_notifications_settings.ejs
index b935e7a..482d934 100644
--- a/templates/email_notifications_settings.ejs
+++ b/templates/email_notifications_settings.ejs
@@ -2,19 +2,19 @@
-
-
-
-
+
+
+
+
diff --git a/update.js b/update.js
index a6653fa..6b29cf7 100644
--- a/update.js
+++ b/update.js
@@ -45,8 +45,8 @@ exports.notifyBegin = function(padId){
async.forEach(Object.keys(recipients), function(recipient, cb){
// 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){
+ 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({
text: "Your pad at "+urlToPads+padId +" is being edited, we're just emailing you let you know :)",
@@ -77,7 +77,7 @@ exports.notifyEnd = function(padId){
async.forEach(Object.keys(recipients), function(recipient, cb){
// 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 true
+ var onEnd = typeof(recipients[recipient].onEnd) == "undefined" || recipients[recipient].onEnd?true:false; // In case onEnd wasn't defined we set it to false
if(!userIsOnPad && onEnd){
console.debug("Emailing "+recipient +" about a pad finished being updated");
From 330cc427b8e27ee61b0a071c39469a0c98086f6e Mon Sep 17 00:00:00 2001
From: quenenni
Date: Sat, 30 Mar 2013 01:34:19 +0100
Subject: [PATCH 04/22] Added global option + malformed email + cleaning
- Added 'panelDisplayLocation' option to choose where to show the subscription form
- Manage malformed email (it crashed EPL)
- Brought back popup form to subscribe (with the new options + unsubscription)
- Popup form is a copy of the form in mysettings menu, so no more 2 html codes in 2 different places
- On unsubscription, only remove the email from "globalAuthor" row if the email is the same.
- Put all css styles in css file
- Some cleaning
---
README.md | 5 +-
client.js | 6 +
ep.json | 3 +-
handleMessage.js | 350 ++++++++++++++-------
package.json | 9 +-
static/css/email_notifications.css | 28 +-
static/js/ep_email.js | 230 +++++++++-----
templates/button.html | 0
templates/email_notifications_settings.ejs | 37 +--
templates/embedFrame.html | 3 -
10 files changed, 464 insertions(+), 207 deletions(-)
delete mode 100644 templates/button.html
delete mode 100644 templates/embedFrame.html
diff --git a/README.md b/README.md
index d632502..f9e7202 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,10 @@ NOTE: You will NOT receive an email if you(the author that registered their emai
```
"ep_email_notifications" : {
+ panelDisplayLocation: { // Where you want to have the subscription panel
+ mysettings: true, // In the "mysettings" menu
+ popup: true // A popup that pop in the bottom right corner of the pad after 10 seconds
+ },
checkFrequency: 6000, // checkFrequency = How frequently(milliseconds) to check for pad updates -- Move me to the settings file
staleTime: 30000, // staleTime = How stale(milliseconds) does a pad need to be before notifying subscribers? Move me to settings
fromName: "Etherpad SETTINGS FILE!",
@@ -27,5 +31,4 @@ NOTE: You will NOT receive an email if you(the author that registered their emai
# FUTURE VERSIONS TODO
* v2 - Get the modified contents from the API HTML diff and append that to the Email and make the email from the server HTML not plain text
-* v2 - a point to unsubscribe and validate/verify email https://github.com/alfredwesterveld/node-email-verification
* v2 - Keep a record of when a user was last on a pad
diff --git a/client.js b/client.js
index ef960a8..73a98d9 100644
--- a/client.js
+++ b/client.js
@@ -1,4 +1,5 @@
var eejs = require("ep_etherpad-lite/node/eejs");
+var settings = require('../../src/node/utils/Settings');
exports.eejsBlock_scripts = function (hook_name, args, cb) {
args.content = args.content + eejs.require("ep_email_notifications/templates/scripts.html", {}, module);
@@ -13,3 +14,8 @@ exports.eejsBlock_mySettings = function (hook_name, args, cb) {
exports.eejsBlock_styles = function (hook_name, args, cb) {
args.content = args.content + '';
};
+
+exports.clientVars = function(hook, context, callback) {
+ // return the setting to the clientVars, sending the value
+ return callback({ "panelDisplayLocation": settings.ep_email_notifications.panelDisplayLocation });
+};
diff --git a/ep.json b/ep.json
index f77ce2a..2f7fe5a 100644
--- a/ep.json
+++ b/ep.json
@@ -7,7 +7,8 @@
"handleMessage": "ep_email_notifications/handleMessage",
"eejsBlock_scripts": "ep_email_notifications/client",
"eejsBlock_mySettings": "ep_email_notifications/client:eejsBlock_mySettings",
- "eejsBlock_styles": "ep_email_notifications/client:eejsBlock_styles"
+ "eejsBlock_styles": "ep_email_notifications/client:eejsBlock_styles",
+ "clientVars": "ep_email_notifications/client:clientVars"
},
"client_hooks": {
"postAceInit":"ep_email_notifications/static/js/ep_email:postAceInit",
diff --git a/handleMessage.js b/handleMessage.js
index 6b724f5..4334168 100644
--- a/handleMessage.js
+++ b/handleMessage.js
@@ -1,7 +1,6 @@
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;
@@ -14,16 +13,37 @@ exports.handleMessage = function(hook_name, context, callback){
if(context.message.data.userInfo.email){ // it contains email
console.debug(context.message);
- // does email Subscription already exist for this email address?
+ // does email (Un)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;
+
+ if(context.message.data.userInfo.email_option == 'subscribe') {
+ // Subscription process
+ exports.subscriptionEmail(
+ context,
+ context.message.data.userInfo.email,
+ alreadyExists,
+ context.message.data.userInfo,
+ context.message.data.padId,
+ callback
+ );
+ } else if (context.message.data.userInfo.email_option == 'unsubscribe') {
+ // Unsubscription process
+ exports.unsubscriptionEmail(
+ context,
+ alreadyExists,
+ context.message.data.userInfo,
+ context.message.data.padId
+ );
+ }
}
cb();
},
@@ -33,116 +53,58 @@ exports.handleMessage = function(hook_name, context, callback){
}); // end async for each
}
- if(context.message.data.userInfo.email_option == 'subscribe' && alreadyExists == true){
- // SUbscription
- console.debug("email ", context.message.data.userInfo.email, "already subscribed to ", context.message.data.padId, " so sending message to client");
-
- context.client.json.send({ type: "COLLABROOM",
- data:{
- type: "emailSubscriptionSuccess",
- payload: false
- }
- });
- } else if(context.message.data.userInfo.email_option == 'subscribe' && alreadyExists == false){
- // SUbscription
- var validatesAsEmail = check(context.message.data.userInfo.email).isEmail();
- if(!validatesAsEmail){
- // Subscription -> failed coz mail 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
- }
- });
- } else {
- // Subscription -> Go for it
- console.debug ("Subscription: Wrote to the database and sent client a positive response ",context.message.data.userInfo.email);
-
- exports.setAuthorEmail(
- context.message.data.userInfo.userId,
+ // In case we didn't find it in the Db
+ if (alreadyExists == false) {
+ if(context.message.data.userInfo.email_option == 'subscribe') {
+ // Subscription process
+ exports.subscriptionEmail(
+ context,
+ context.message.data.userInfo.email,
+ alreadyExists,
context.message.data.userInfo,
+ context.message.data.padId,
callback
);
-
- exports.setAuthorEmailRegistered(
+ } else if (context.message.data.userInfo.email_option == 'unsubscribe') {
+ // Unsubscription process
+ exports.unsubscriptionEmail(
+ context,
+ alreadyExists,
context.message.data.userInfo,
- context.message.data.userInfo.userId,
context.message.data.padId
);
-
- context.client.json.send({ type: "COLLABROOM",
- data:{
- type: "emailSubscriptionSuccess",
- payload: true
- }
- });
}
- } else if(context.message.data.userInfo.email_option == 'unsubscribe' && alreadyExists == true) {
- // Unsubscription -> Go for it
- console.debug ("Unsubscription: Remove from the database and sent client a positive response ",context.message.data.userInfo.email);
-
- exports.unsetAuthorEmail(
- context.message.data.userInfo.userId,
- context.message.data.userInfo,
- callback
- );
-
- exports.unsetAuthorEmailRegistered(
- context.message.data.userInfo,
- context.message.data.userInfo.userId,
- context.message.data.padId
- );
-
- context.client.json.send({ type: "COLLABROOM",
- data:{
- type: "emailUnsubscriptionSuccess",
- payload: true
- }
- });
- } else if(context.message.data.userInfo.email_option == 'unsubscribe' && alreadyExists == false) {
- // Unsubscription -> Send failed as email not found
- console.debug ("Unsubscription: Send client a negative response ",context.message.data.userInfo.email);
-
- context.client.json.send({ type: "COLLABROOM",
- data:{
- type: "emailUnsubscriptionSuccess",
- payload: false
- }
- });
}
+
}); // close db get
callback([null]); // don't run onto passing colorId or anything else to the message handler
}
}
- } else if (context.message.data.type == 'USERINFO_GET' ) { // A request to find datas for a username
+
+ } else if (context.message.data.type == 'USERINFO_GET' ) { // A request to find datas for a userId
if (context.message.data.userInfo){
if(context.message.data.userInfo.userId){ // it contains the userId
console.debug(context.message);
- var userIdFound = false;
// does email Subscription already exist for this UserId?
db.get("emailSubscription:"+context.message.data.padId, function(err, userIds){
+ var userIdFound = false;
+
if(userIds){
async.forEach(Object.keys(userIds), function(user, cb){
if(userIds[user].authorId == context.message.data.userInfo.userId){ // if we find the same Id in the Db as the one used by the user
console.debug("Options for this pad ", userIds[user].authorId, " found in the Db");
userIdFound = true;
- // We send back the options associated to this userId
- context.client.json.send({ type: "COLLABROOM",
- data:{
- type: "emailNotificationGetUserInfo",
- payload: {
- email: user,
- onStart: userIds[user].onStart && typeof userIds[user].onStart === 'boolean'?userIds[user].onStart:true,
- onEnd: userIds[user].onEnd && typeof userIds[user].onEnd === 'boolean'?userIds[user].onEnd:false,
- success:true
- }
- }
- });
+ // Request user subscription info process
+ exports.sendUserInfo (
+ context,
+ userIdFound,
+ user,
+ userIds[user]
+ );
}
cb();
},
@@ -151,19 +113,19 @@ exports.handleMessage = function(hook_name, context, callback){
// There should be something in here!
}); // end async for each
}
+
+ if (userIdFound == false) {
+ // Request user subscription info process
+ exports.sendUserInfo (
+ context,
+ userIdFound,
+ "",
+ ""
+ );
+ }
});
- if (!userIdFound) {
- // No options set for this userId
- context.client.json.send({ type: "COLLABROOM",
- data:{
- type: "emailNotificationGetUserInfo",
- payload: {
- success:false
- }
- }
- });
- }
+ callback([null]);
}
}
}
@@ -171,25 +133,189 @@ exports.handleMessage = function(hook_name, context, callback){
callback();
}
+/**
+ * Subscription process
+ */
+exports.subscriptionEmail = function (context, email, emailFound, userInfo, padId, callback) {
+ var validatesAsEmail = exports.checkEmailValidation(email);
+
+ if(emailFound == false && validatesAsEmail){
+ // Subscription -> Go for it
+ console.debug ("Subscription: Wrote to the database and sent client a positive response ",context.message.data.userInfo.email);
+
+ exports.setAuthorEmail(
+ userInfo.userId,
+ userInfo,
+ callback
+ );
+
+ exports.setAuthorEmailRegistered(
+ userInfo,
+ userInfo.userId,
+ padId
+ );
+
+ context.client.json.send({ type: "COLLABROOM",
+ data:{
+ type: "emailSubscriptionSuccess",
+ payload: {
+ formName: userInfo.formName,
+ success: true
+ }
+ }
+ });
+ } else if (!validatesAsEmail) {
+ // Subscription -> failed coz mail 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: {
+ type: "malformedEmail",
+ formName: userInfo.formName,
+ success: false
+ }
+ }
+ });
+ } else {
+ // Subscription -> failed coz email already subscribed for this pad
+ console.debug("email ", context.message.data.userInfo.email, "already subscribed to ", context.message.data.padId, " so sending message to client");
+
+ context.client.json.send({ type: "COLLABROOM",
+ data:{
+ type: "emailSubscriptionSuccess",
+ payload: {
+ type: "alreadyRegistered",
+ formName: userInfo.formName,
+ success: false
+ }
+ }
+ });
+ }
+}
+
+/**
+ * UnsUbscription process
+ */
+exports.unsubscriptionEmail = function (context, emailFound, userInfo, padId) {
+ if(emailFound == true) {
+ // Unsubscription -> Go for it
+ console.debug ("Unsubscription: Remove from the database and sent client a positive response ",context.message.data.userInfo.email);
+
+ exports.unsetAuthorEmail(
+ userInfo.userId,
+ userInfo
+ );
+
+ exports.unsetAuthorEmailRegistered(
+ userInfo,
+ userInfo.userId,
+ padId
+ );
+
+ context.client.json.send({ type: "COLLABROOM",
+ data:{
+ type: "emailUnsubscriptionSuccess",
+ payload: {
+ formName: userInfo.formName,
+ success: true
+ }
+ }
+ });
+ } else {
+ // Unsubscription -> Send failed as email not found
+ console.debug ("Unsubscription: Send client a negative response ",context.message.data.userInfo.email);
+
+ context.client.json.send({ type: "COLLABROOM",
+ data:{
+ type: "emailUnsubscriptionSuccess",
+ payload: {
+ formName: userInfo.formName,
+ success: false
+ }
+ }
+ });
+ }
+}
+
+/**
+ * Request user subscription info process
+ */
+exports.sendUserInfo = function (context, emailFound, email, userInfo) {
+ var defaultOnStartOption = true;
+ var defaultOnEndOption = false;
+
+ if (typeof userInfo.onStart == 'boolean' && typeof userInfo.onEnd == 'boolean') {
+ var onStart = userInfo.onStart;
+ var onEnd = userInfo.onEnd;
+ } else { // In case these options are not yet defined for this userId
+ var onStart = defaultOnStartOption;
+ var onEnd = defaultOnEndOption;
+ }
+
+ if (emailFound == true) {
+ // We send back the options associated to this userId
+ context.client.json.send({ type: "COLLABROOM",
+ data:{
+ type: "emailNotificationGetUserInfo",
+ payload: {
+ email: email,
+ onStart: onStart,
+ onEnd: onEnd,
+ formName: context.message.data.userInfo.formName,
+ success:true
+ }
+ }
+ });
+ } else {
+ // No options set for this userId
+ context.client.json.send({ type: "COLLABROOM",
+ data:{
+ type: "emailNotificationGetUserInfo",
+ payload: {
+ formName: context.message.data.userInfo.formName,
+ success:false
+ }
+ }
+ });
+ }
+}
+
+/**
+ * Function to check if an email is valid
+ */
+exports.checkEmailValidation = function (email) {
+ var Validator = require('validator').Validator;
+ var validator = new Validator();
+ validator.error = function() {
+ return false;
+ };
+ return validator.check(email).isEmail();
+}
+
+/**
+ * Database manipulation
+ */
+
// Updates the database with the email record
-exports.setAuthorEmail = function (author, datas, callback){
- db.setSub("globalAuthor:" + author, ["email"], datas.email, callback);
+exports.setAuthorEmail = function (author, userInfo, callback){
+ db.setSub("globalAuthor:" + author, ["email"], userInfo.email, callback);
}
// Write email and padId to the database
-exports.setAuthorEmailRegistered = function(datas, authorId, padId){
+exports.setAuthorEmailRegistered = function(userInfo, authorId, padId){
var timestamp = new Date().getTime();
var registered = {
authorId: authorId,
- onStart: datas.email_onStart,
- onEnd: datas.email_onEnd,
+ onStart: userInfo.email_onStart,
+ onEnd: userInfo.email_onEnd,
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[datas.email] = registered; // add the registered values to the object
+ value[userInfo.email] = registered; // add the registered values to the object
console.warn("written to database");
db.set("emailSubscription:" + padId, value); // stick it in the database
});
@@ -197,25 +323,27 @@ exports.setAuthorEmailRegistered = function(datas, authorId, padId){
}
// Updates the database by removing the email record for that AuthorId
-exports.unsetAuthorEmail = function (author, datas, callback){
+exports.unsetAuthorEmail = function (author, userInfo){
db.get("globalAuthor:" + author, function(err, value){ // get the current value
- // Remove the email option from the datas
- delete value['email'];
+ if (value['email'] == userInfo.email) {
+ // Remove the email option from the datas
+ delete value['email'];
- // Write the modified datas back in the Db
- db.set("globalAuthor:" + author, value);
+ // Write the modified datas back in the Db
+ db.set("globalAuthor:" + author, value);
+ }
});
}
// Remove email, options and padId from the database
-exports.unsetAuthorEmailRegistered = function(datas, authorId, padId){
- console.debug("unregistered", datas.email, " to ", padId);
+exports.unsetAuthorEmailRegistered = function(userInfo, authorId, padId){
+ console.debug("unregistered", userInfo.email, " to ", padId);
db.get("emailSubscription:" + padId, function(err, value){ // get the current value
// remove the registered options from the object
- delete value[datas.email];
+ delete value[userInfo.email];
// Write the modified datas back in the Db
console.warn("written to database");
diff --git a/package.json b/package.json
index b744782..b394d1a 100644
--- a/package.json
+++ b/package.json
@@ -15,5 +15,12 @@
},
"engines": {
"node": ">= 0.4.1"
- }
+ },
+ "readme": "# Description\nThis plugin allows users to subscribe to pads and receive email updates when a pad is being modified. You can modify the frequency. This plugin is very much in alpha stage and has a lot of things TODO (See TODO).\n\n# Installation\nMake sure an SMTP gateway is installed IE postfix\nConfigure SPF and RDNS records to ensure proper mail flow <-- Search online\nCopy/Edit the below to your settings.json\nConnect to a pad, Click on the Share/Embed link and enter in your email address.\nOpen that pad in ANOTHER BROWSER then begin modifying, you should receive an email when the pad has begun editing and once the pad has gone stale (when everyone stops editing it and a time period passes).\nNOTE: You will NOT receive an email if you(the author that registered their email) are currently on or editing that pad!\n\n```\n \"ep_email_notifications\" : {\n checkFrequency: 6000, // checkFrequency = How frequently(milliseconds) to check for pad updates -- Move me to the settings file\n staleTime: 30000, // staleTime = How stale(milliseconds) does a pad need to be before notifying subscribers? Move me to settings\n fromName: \"Etherpad SETTINGS FILE!\",\n fromEmail: \"pad@etherpad.org\",\n urlToPads: \"http://beta.etherpad.org/p/\", // urlToPads = The URL to your pads note the trailing /\n emailServer: { // See https://github.com/eleith/emailjs for settings\n host: \"127.0.0.1\"\n }\n }\n```\n\n# TODO\n* Clean up all code\n\n# FUTURE VERSIONS TODO\n* v2 - Get the modified contents from the API HTML diff and append that to the Email and make the email from the server HTML not plain text\n* v2 - a point to unsubscribe and validate/verify email https://github.com/alfredwesterveld/node-email-verification\n* v2 - Keep a record of when a user was last on a pad\n",
+ "readmeFilename": "README.md",
+ "_id": "ep_email_notifications@0.0.6",
+ "dist": {
+ "shasum": "1f32eee4c8d5f3903c549b5a7985afc0053ed451"
+ },
+ "_from": "ep_email_notifications"
}
diff --git a/static/css/email_notifications.css b/static/css/email_notifications.css
index 71c61d7..2801045 100644
--- a/static/css/email_notifications.css
+++ b/static/css/email_notifications.css
@@ -1,10 +1,34 @@
.ep_email_settings {
display: none;
- padding-left: 1.5em;
- padding: .2em;
+ padding: 0.2em 0.2em 0.2em 0.5em;
+}
+
+.ep_email_buttons {
+ padding:5px;
+}
+
+.ep_email_checkbox {
+ margin-left:0.3em;
}
.ep_email_input {
padding:.2em;
width:177px;
}
+
+#ep_email_form_popup > p {
+ font-size:x-small;
+}
+
+#ep_email_form_popup .ep_email_buttons {
+ margin-top: .5em;
+}
+
+#ep_email_form_popup .ep_email_checkbox {
+ margin-top: .2em;
+}
+
+#ep_email_form_popup .ep_email_input {
+ margin: .3em 0;
+ width:95%;
+}
diff --git a/static/js/ep_email.js b/static/js/ep_email.js
index d93dde1..97c5f68 100644
--- a/static/js/ep_email.js
+++ b/static/js/ep_email.js
@@ -1,89 +1,181 @@
var cookie = require('ep_etherpad-lite/static/js/pad_cookie').padcookie;
-var firstRun = true;
+var optionsAlreadyRecovered = false;
if(typeof exports == 'undefined'){
var exports = this['mymodule'] = {};
}
exports.postAceInit = function(hook, context){
- // Uncheck the checkbox
- $('#options-emailNotifications').attr('checked', false);
- setDefaultOptions();
+ // If plugin settings set panel form in mysettings menu
+ if (clientVars.panelDisplayLocation.mysettings == true) {
+ // Uncheck the checkbox incase of reminiscence
+ $('#options-emailNotifications').prop('checked', false);
- /* on click */
- $('#options-emailNotifications').on('click', function() {
- if (firstRun) {
- getDatasForUserId();
- firstRun = false;
- } else {
- $('.ep_email_settings').slideToggle();
- }
- });
+ $('#options-emailNotifications').on('click', function() {
+ if (!optionsAlreadyRecovered) {
+ getDataForUserId('ep_email_form_mysettings');
+ optionsAlreadyRecovered = true;
+ } else {
+ $('.ep_email_settings').slideToggle();
+ }
+ });
- // Prepare subscription before submit form
- $('#ep_email_subscribe').on('click', function() {
- $('#ep_email_option').val('subscribe');
- checkAndSend();
- });
+ // Prepare subscription before submit form
+ $('[name=ep_email_subscribe]').on('click', function(e) {
+ $('[name=ep_email_option]').val('subscribe');
+ checkAndSend(e);
+ });
- // Prepare unsubscription before submit form
- $('#ep_email_unsubscribe').on('click', function() {
- $('#ep_email_option').val('unsubscribe');
- checkAndSend();
- });
+ // Prepare unsubscription before submit form
+ $('[name=ep_email_unsubscribe]').on('click', function(e) {
+ $('[name=ep_email_option]').val('unsubscribe');
+ checkAndSend(e);
+ });
- // subscribe by email can be active..
- $('.ep_email_form').submit(function(){
- sendEmailToServer();
- $('.ep_email_settings').slideToggle();
- $('#options-emailNotifications').attr('checked', false);
- return false;
- });
+ // subscribe by email can be active..
+ $('#ep_email_form_mysettings').submit(function(){
+ sendEmailToServer('ep_email_form_mysettings');
+ return false;
+ });
+ } else {
+ // Hide the notification menu in mysettings
+ $('#options-emailNotifications').parent().hide();
+ }
+
+ // If settings set popup panel form to true, show it
+ if (clientVars.panelDisplayLocation.popup == true) {
+ // after 10 seconds if we dont already have an email for this author then prompt them
+ setTimeout(function(){initPopupForm()},10000);
+ }
}
exports.handleClientMessage_emailSubscriptionSuccess = function(hook, context){ // was subscribing to the email a big win or fail?
- if(context.payload == false){
- showAlreadyRegistered();
- }else{
+ if(context.payload.success == false) {
+ showAlreadyRegistered(context.payload.type);
+ $('#' + context.payload.formName + ' [name=ep_email]').select();
+ } else {
showRegistrationSuccess();
+
+ if (clientVars.panelDisplayLocation.mysettings == true && $('.ep_email_settings').is(":visible")) {
+ $('.ep_email_settings').slideToggle();
+ $('#options-emailNotifications').prop('checked', false);
+ }
+
+ if (clientVars.panelDisplayLocation.popup == true && $('#ep_email_form_popup').is(":visible")) {
+ $('#ep_email_form_popup').parent().parent().parent().hide();
+ }
}
}
exports.handleClientMessage_emailUnsubscriptionSuccess = function(hook, context){ // was subscribing to the email a big win or fail?
- if(context.payload == false){
+ if(context.payload.success == false) {
showWasNotRegistered();
- }else{
+ $('#' + context.payload.formName + ' [name=ep_email]').select();
+ } else {
showUnregistrationSuccess();
+
+ if (clientVars.panelDisplayLocation.mysettings == true && $('.ep_email_settings').is(":visible")) {
+ $('.ep_email_settings').slideToggle();
+ $('#options-emailNotifications').prop('checked', false);
+ }
+
+ if (clientVars.panelDisplayLocation.popup == true && $('#ep_email_form_popup').is(":visible")) {
+ $('#ep_email_form_popup').parent().parent().parent().hide();
+ }
}
}
exports.handleClientMessage_emailNotificationGetUserInfo = function (hook, context) { // return the existing options for this userId
- var datas = context.payload;
- if(datas.success == true){ // If datas were found, set the options with them
- if (datas.email) $('#ep_email').val(datas.email);
- if (datas.onStart && typeof datas.onStart === 'boolean') $('#ep_email_onStart').attr('checked', datas.onStart);
- if (datas.onEnd && typeof datas.onEnd === 'boolean') $('#ep_email_onEnd').attr('checked', datas.onEnd);
- } else { // No datas were found, set the options to default values
- setDefaultOptions();
+ var result = context.payload;
+ if(result.success == true){ // If data found, set the options with them
+ $('[name=ep_email]').val(result.email);
+ $('[name=ep_email_onStart]').prop('checked', result.onStart);
+ $('[name=ep_email_onEnd]').prop('checked', result.onEnd);
+ } else { // No data found, set the options to default values
+ $('[name=ep_email_onStart]').prop('checked', true);
+ $('[name=ep_email_onEnd]').prop('checked', false);
}
- $('.ep_email_settings').slideToggle();
+ if (result.formName == 'ep_email_form_mysettings') {
+ $('.ep_email_settings').slideToggle();
+ }
}
/**
- * Set the options in the frame to a default value
+ * Initialize the popup panel form for subscription
*/
-function setDefaultOptions() {
- $('#ep_email_onStart').attr('checked', true);
- $('#ep_email_onEnd').attr('checked', false);
+function initPopupForm(){
+ var popUpIsAlreadyVisible = $('#ep_email_form_popup').is(":visible");
+ if(!popUpIsAlreadyVisible){ // if the popup isn't already visible
+ var cookieVal = pad.getPadId() + "email";
+ if(cookie.getPref(cookieVal) !== "true"){ // if this user hasn't already subscribed
+ askClientToEnterEmail(); // ask the client to register TODO uncomment me for a pop up
+ }
+ }
+}
+
+function clientHasAlreadyRegistered(){ // Has the client already registered for emails on this?
+ // Given a specific AuthorID do we have an email address in the database?
+ // Given that email address is it registered to this pad?
+ // need to pass the server a message to check
+ var userId = pad.getUserId();
+ var message = {};
+ message.type = 'USERINFO_AUTHOR_EMAIL_IS_REGISTERED_TO_PAD';
+ message.userInfo = {};
+ message.userInfo.userId = userId;
+ pad.collabClient.sendMessage(message);
+}
+
+function askClientToEnterEmail(){
+ var formContent = $('.ep_email_settings')
+ .html()
+ .replace('ep_email_form_mysettings', 'ep_email_form_popup');
+
+ $.gritter.add({
+ // (string | mandatory) the heading of the notification
+ title: "Email subscription",
+ // (string | mandatory) the text inside the notification
+ text: "
(Receive an email when someone modifies this pad)
" + formContent,
+ // (bool | optional) if you want it to fade out on its own or just sit there
+ sticky: true,
+ // (int | optional) the time you want it to be alive for before fading out
+ time: 2000,
+ // the function to bind to the form
+ after_open: function(e){
+ $('#ep_email_form_popup').submit(function(){
+ sendEmailToServer('ep_email_form_popup');
+ return false;
+ });
+
+ // Prepare subscription before submit form
+ $('#ep_email_form_popup [name=ep_email_subscribe]').on('click', function(e) {
+ $('#ep_email_form_popup [name=ep_email_option]').val('subscribe');
+ checkAndSend(e);
+ });
+
+ // Prepare unsubscription before submit form
+ $('#ep_email_form_popup [name=ep_email_unsubscribe]').on('click', function(e) {
+ $('#ep_email_form_popup [name=ep_email_option]').val('unsubscribe');
+ checkAndSend(e);
+ });
+
+ getDataForUserId('ep_email_form_popup');
+ optionsAlreadyRecovered = true;
+ }
+ });
}
/**
* Control options before submitting the form
*/
-function checkAndSend() {
- var email = getEmail();
- if (email && $('#ep_email_option').val() == 'subscribe' && !$('#ep_email_onStart').is(':checked') && !$('#ep_email_onEnd').is(':checked')) {
+function checkAndSend(e) {
+ var formName = $(e.currentTarget.parentNode).attr('id');
+
+ var email = $('#' + formName + ' [name=ep_email]').val();
+
+ if (email && $('#' + formName + ' [name=ep_email_option]').val() == 'subscribe'
+ && !$('#' + formName + ' [name=ep_email_onStart]').is(':checked')
+ && !$('#' + formName + ' [name=ep_email_onEnd]').is(':checked')) {
$.gritter.add({
// (string | mandatory) the heading of the notification
title: "Email subscription error",
@@ -91,36 +183,26 @@ function checkAndSend() {
text: "You need to check at least one of the two options from 'Send a mail when someone..'"
});
} else if (email) {
- $('.ep_email_form').submit();
+ $('#' + formName).submit();
}
return false;
}
-/**
- * Return the email from the user
- */
-function getEmail() {
- var email = $('#ep_email').val();
- if(!email){ // if we're not using the top value use the notification value
- email = $('#ep_email_notification').val();
- }
- return email;
-}
-
/**
* Ask the server to register the email
*/
-function sendEmailToServer(){
- var email = getEmail();
+function sendEmailToServer(formName){
+ var email = $('#' + formName + ' [name=ep_email]').val();
var userId = pad.getUserId();
var message = {};
message.type = 'USERINFO_UPDATE';
message.userInfo = {};
message.padId = pad.getPadId();
message.userInfo.email = email;
- message.userInfo.email_option = $('#ep_email_option').val();
- message.userInfo.email_onStart = $('#ep_email_onStart').is(':checked');
- message.userInfo.email_onEnd = $('#ep_email_onEnd').is(':checked');
+ message.userInfo.email_option = $('#' + formName + ' [name=ep_email_option]').val();
+ message.userInfo.email_onStart = $('#' + formName + ' [name=ep_email_onStart]').is(':checked');
+ message.userInfo.email_onEnd = $('#' + formName + ' [name=ep_email_onEnd]').is(':checked');
+ message.userInfo.formName = formName;
message.userInfo.userId = userId;
if(email){
pad.collabClient.sendMessage(message);
@@ -132,13 +214,14 @@ function sendEmailToServer(){
* Thanks to the userId, we can get back from the Db the options set for this user
* and fill the fields with them
*/
-function getDatasForUserId() {
+function getDataForUserId(formName) {
var userId = pad.getUserId();
var message = {};
message.type = 'USERINFO_GET';
message.padId = pad.getPadId();
message.userInfo = {};
message.userInfo.userId = userId;
+ message.userInfo.formName = formName;
pad.collabClient.sendMessage(message);
}
@@ -162,12 +245,19 @@ function showRegistrationSuccess(){
/**
* The client already registered for emails on this pad so notify the UI
*/
-function showAlreadyRegistered(){
+function showAlreadyRegistered(type){
+ if (type == "malformedEmail") {
+ var msg = "The email address is malformed";
+ } else if (type == "alreadyRegistered") {
+ var msg = "You are already registered for emails for this pad";
+ } else {
+ var msg = "Unknown error";
+ }
$.gritter.add({
// (string | mandatory) the heading of the notification
title: "Email subscription",
// (string | mandatory) the text inside the notification
- text: "You are already registered for emails for this pad",
+ text: msg,
// (bool | optional) if you want it to fade out on its own or just sit there
sticky: false
});
diff --git a/templates/button.html b/templates/button.html
deleted file mode 100644
index e69de29..0000000
diff --git a/templates/email_notifications_settings.ejs b/templates/email_notifications_settings.ejs
index 482d934..18533a9 100644
--- a/templates/email_notifications_settings.ejs
+++ b/templates/email_notifications_settings.ejs
@@ -1,20 +1,21 @@
-
From 45259b1207a005e8c6877f98c58fbdc8a0d50a7f Mon Sep 17 00:00:00 2001
From: quenenni
Date: Sat, 30 Mar 2013 01:51:31 +0100
Subject: [PATCH 05/22] Removed trailing space
---
handleMessage.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/handleMessage.js b/handleMessage.js
index 4334168..34b6c71 100644
--- a/handleMessage.js
+++ b/handleMessage.js
@@ -119,7 +119,7 @@ exports.handleMessage = function(hook_name, context, callback){
exports.sendUserInfo (
context,
userIdFound,
- "",
+ "",
""
);
}
From ad58d186fd54d04d372f6d624df9350b0cbfbaab Mon Sep 17 00:00:00 2001
From: quenenni
Date: Sat, 30 Mar 2013 15:56:10 +0100
Subject: [PATCH 06/22] Fixed when new settings not in settings.json
---
static/js/ep_email.js | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/static/js/ep_email.js b/static/js/ep_email.js
index 97c5f68..56cc5df 100644
--- a/static/js/ep_email.js
+++ b/static/js/ep_email.js
@@ -6,6 +6,23 @@ if(typeof exports == 'undefined'){
}
exports.postAceInit = function(hook, context){
+ // Test if settings are good before continuing
+ if (typeof clientVars.panelDisplayLocation != "object") {
+ $.gritter.add({
+ // (string | mandatory) the heading of the notification
+ title: "Email subscription error",
+ // (string | mandatory) the text inside the notification
+ text: "Some settings for the 'email_Notifications' plugin are missing. Please contact your administrator.",
+ // (int | optional) the time you want it to be alive for before fading out
+ time: 10000,
+ });
+
+ // Hide the notification menu in mysettings
+ $('#options-emailNotifications').parent().hide();
+
+ return false;
+ }
+
// If plugin settings set panel form in mysettings menu
if (clientVars.panelDisplayLocation.mysettings == true) {
// Uncheck the checkbox incase of reminiscence
From 2efae97d4a42d1102cd4ffdf728e83a9df4076bd Mon Sep 17 00:00:00 2001
From: quenenni
Date: Tue, 2 Apr 2013 05:14:01 +0200
Subject: [PATCH 07/22] Added email confirmation for (un)subscription
---
ep.json | 3 +-
handleMessage.js | 106 ++++++++++------
index.js | 287 ++++++++++++++++++++++++++++++++++++++++++
static/js/ep_email.js | 12 +-
4 files changed, 365 insertions(+), 43 deletions(-)
create mode 100644 index.js
diff --git a/ep.json b/ep.json
index 2f7fe5a..8f69f6c 100644
--- a/ep.json
+++ b/ep.json
@@ -8,7 +8,8 @@
"eejsBlock_scripts": "ep_email_notifications/client",
"eejsBlock_mySettings": "ep_email_notifications/client:eejsBlock_mySettings",
"eejsBlock_styles": "ep_email_notifications/client:eejsBlock_styles",
- "clientVars": "ep_email_notifications/client:clientVars"
+ "clientVars": "ep_email_notifications/client:clientVars",
+ "expressCreateServer" : "ep_email_notifications/index:registerRoute"
},
"client_hooks": {
"postAceInit":"ep_email_notifications/static/js/ep_email:postAceInit",
diff --git a/handleMessage.js b/handleMessage.js
index 34b6c71..0bfd1e7 100644
--- a/handleMessage.js
+++ b/handleMessage.js
@@ -1,9 +1,18 @@
var db = require('../../src/node/db/DB').db,
API = require('../../src/node/db/API.js'),
async = require('../../src/node_modules/async'),
+ email = require('emailjs'),
+randomString = require('../../src/static/js/pad_utils').randomString;
settings = require('../../src/node/utils/Settings');
var pluginSettings = settings.ep_email_notifications;
+var fromName = pluginSettings.fromName || "Etherpad";
+var fromEmail = pluginSettings.fromEmail || "pad@etherpad.org";
+var urlToPads = pluginSettings.urlToPads || "http://beta.etherpad.org/p/";
+var emailServer = pluginSettings.emailServer || {host:"127.0.0.1"};
+
+// Connect to the email server -- This might not be the ideal place to connect but it stops us having lots of connections
+var server = email.server.connect(emailServer);
// When a new message comes in from the client - FML this is ugly
exports.handleMessage = function(hook_name, context, callback){
@@ -138,20 +147,16 @@ exports.handleMessage = function(hook_name, context, callback){
*/
exports.subscriptionEmail = function (context, email, emailFound, userInfo, padId, callback) {
var validatesAsEmail = exports.checkEmailValidation(email);
+ var subscribeId = randomString(25);
if(emailFound == false && validatesAsEmail){
// Subscription -> Go for it
console.debug ("Subscription: Wrote to the database and sent client a positive response ",context.message.data.userInfo.email);
- exports.setAuthorEmail(
- userInfo.userId,
- userInfo,
- callback
- );
-
exports.setAuthorEmailRegistered(
userInfo,
userInfo.userId,
+ subscribeId,
padId
);
@@ -164,6 +169,20 @@ exports.subscriptionEmail = function (context, email, emailFound, userInfo, padI
}
}
});
+
+ // Send mail to user with the link for validation
+ server.send(
+ {
+ text: "Please click on this link in order to validate your subscription to the pad " + padId + "\n" + urlToPads+padId + "/subscribe=" + subscribeId,
+ from: fromName+ "<"+fromEmail+">",
+ to: userInfo.email,
+ subject: "Email subscription confirmation for pad "+padId
+ },
+ function(err, message) {
+ console.log(err || message);
+ }
+ );
+
} else if (!validatesAsEmail) {
// Subscription -> failed coz mail malformed.. y'know in general fuck em!
console.warn("Dropped email subscription due to malformed email address");
@@ -198,18 +217,16 @@ exports.subscriptionEmail = function (context, email, emailFound, userInfo, padI
* UnsUbscription process
*/
exports.unsubscriptionEmail = function (context, emailFound, userInfo, padId) {
+ var unsubscribeId = randomString(25);
+
if(emailFound == true) {
// Unsubscription -> Go for it
console.debug ("Unsubscription: Remove from the database and sent client a positive response ",context.message.data.userInfo.email);
- exports.unsetAuthorEmail(
- userInfo.userId,
- userInfo
- );
-
exports.unsetAuthorEmailRegistered(
userInfo,
userInfo.userId,
+ unsubscribeId,
padId
);
@@ -222,6 +239,19 @@ exports.unsubscriptionEmail = function (context, emailFound, userInfo, padId) {
}
}
});
+
+ // Send mail to user with the link for validation
+ server.send(
+ {
+ text: "Please click on this link in order to validate your unsubscription to the pad " + padId + "\n" + urlToPads+padId + "/unsubscribe=" + unsubscribeId,
+ from: fromName+ "<"+fromEmail+">",
+ to: userInfo.email,
+ subject: "Email unsubscription confirmation for pad "+padId
+ },
+ function(err, message) {
+ console.log(err || message);
+ }
+ );
} else {
// Unsubscription -> Send failed as email not found
console.debug ("Unsubscription: Send client a negative response ",context.message.data.userInfo.email);
@@ -297,53 +327,53 @@ exports.checkEmailValidation = function (email) {
* Database manipulation
*/
-// Updates the database with the email record
-exports.setAuthorEmail = function (author, userInfo, callback){
- db.setSub("globalAuthor:" + author, ["email"], userInfo.email, callback);
-}
-
-// Write email and padId to the database
-exports.setAuthorEmailRegistered = function(userInfo, authorId, padId){
+// Write email, options, authorId and pendingId to the database
+exports.setAuthorEmailRegistered = function(userInfo, authorId, subscribeId, padId){
var timestamp = new Date().getTime();
var registered = {
authorId: authorId,
onStart: userInfo.email_onStart,
onEnd: userInfo.email_onEnd,
+ subscribeId: subscribeId,
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[userInfo.email] = registered; // add the registered values to the object
+ if(!value){
+ // if an emailSubscription doesnt exist yet for this padId don't panic
+ value = {"pending":{}};
+ } else if (!value['pending']) {
+ // if the pending section doesn't exist yet for this padId, we create it
+ value['pending'] = {};
+ }
+
+ // add the registered values to the pending section of the object
+ value['pending'][userInfo.email] = registered;
+
console.warn("written to database");
db.set("emailSubscription:" + padId, value); // stick it in the database
});
}
-// Updates the database by removing the email record for that AuthorId
-exports.unsetAuthorEmail = function (author, userInfo){
- db.get("globalAuthor:" + author, function(err, value){ // get the current value
-
- if (value['email'] == userInfo.email) {
- // Remove the email option from the datas
- delete value['email'];
-
- // Write the modified datas back in the Db
- db.set("globalAuthor:" + author, value);
- }
- });
-}
-
-// Remove email, options and padId from the database
-exports.unsetAuthorEmailRegistered = function(userInfo, authorId, padId){
+// Write email, authorId and pendingId to the database
+exports.unsetAuthorEmailRegistered = function(userInfo, authorId, unsubscribeId, padId){
+ var timestamp = new Date().getTime();
+ var registered = {
+ authorId: authorId,
+ unsubscribeId: unsubscribeId,
+ timestamp: timestamp
+ };
console.debug("unregistered", userInfo.email, " to ", padId);
db.get("emailSubscription:" + padId, function(err, value){ // get the current value
+ // if the pending section doesn't exist yet for this padId, we create it (this shouldn't happen)
+ if (!value['pending']) {value['pending'] = {};}
- // remove the registered options from the object
- delete value[userInfo.email];
+ // add the registered values to the pending section of the object
+ value['pending'][userInfo.email] = registered;
// Write the modified datas back in the Db
console.warn("written to database");
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..a7e22ed
--- /dev/null
+++ b/index.js
@@ -0,0 +1,287 @@
+var db = require('ep_etherpad-lite/node/db/DB').db,
+ async = require('../../src/node_modules/async'),
+ settings = require('../../src/node/utils/Settings');
+
+// Remove cache for this procedure
+db['dbSettings'].cache = 0;
+
+exports.registerRoute = function (hook_name, args, callback) {
+ // Catching (un)subscribe addresses
+ args.app.get('/p/*/(un){0,1}subscribe=*', function(req, res) {
+ 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;
+ var resultDb = {};
+
+ async.series(
+ [
+ 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";
+
+ if(userIds && userIds['pending']){
+ 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
+ );
+ }
+ }
+ },
+
+ function(err, msg){
+ // There should be something in here!
+ console.error("Error in emailSubscription async in first function", err, " -> ", msg);
+ }); // end async for each
+ }
+
+ resultDb = {
+ "foundInDb": foundInDb,
+ "timeDiffGood": timeDiffGood,
+ "email": email
+ }
+
+ cb(null, 1);
+ });
+ },
+
+ function(cb) {
+ // Create and send the output message
+ sendContent(res, args, action, padId, padURL, resultDb);
+
+ cb(null, 2);
+ },
+
+ function(cb) {
+ // Take a moment to clean all obsolete pending data
+ cleanPendingData(padId);
+
+ cb(null, 3);
+ }
+ ],
+ function(err, results){
+ console.error("Callback async.series: Err -> ", err, " / results -> ", results);
+ }
+ );
+ });
+
+ 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";
+ classResult = "good";
+ } else if (resultDb.foundInDb == true) {
+ // Pending data were found but older than a day -> fail
+ msgCause = "You have max 24h to click the link in your confirmation email.";
+ resultMsg = "Too late!";
+ resultMsg += '
\n';
+ resultMsg += msgCause;
+ resultMsg += '
\n';
+ classResult = "bad";
+ } else {
+ // Pending data weren't found in Db -> fail
+ msgCause = "We couldn't find any pending " + (action == 'subscribe'?'subscription':'unsubscription') + " in our system with this Id. Maybe you wait more than 24h before validating";
+ resultMsg = "Fail\n";
+ resultMsg += '
You won't receive anymore email when someone changes this pad.
";
+ }
+ args.content += '
\n';
+ args.content += 'Go to the pad: ' + padURL + '';
+ args.content += '
\n';
+ args.content += '\n';
+ args.content += '\n';
+ res.send(args.content); // Send it to the requester
+}
diff --git a/static/js/ep_email.js b/static/js/ep_email.js
index 56cc5df..eb916fd 100644
--- a/static/js/ep_email.js
+++ b/static/js/ep_email.js
@@ -253,9 +253,11 @@ Manage return msgs from server
function showRegistrationSuccess(){
$.gritter.add({
// (string | mandatory) the heading of the notification
- title: "Email subscribed",
+ title: "Email subscription",
// (string | mandatory) the text inside the notification
- text: "You will receive email when someone changes this pad. If this is the first time you have requested emails you may need to confirm your email address"
+ text: "An email was sent to your address. Click on the link in order to validate your subscription.",
+ // (int | optional) the time you want it to be alive for before fading out
+ time: 10000
});
}
@@ -287,9 +289,11 @@ function showAlreadyRegistered(type){
function showUnregistrationSuccess(){
$.gritter.add({
// (string | mandatory) the heading of the notification
- title: "Email unsubscribed",
+ title: "Email unsubscription",
// (string | mandatory) the text inside the notification
- text: "You won't receive anymore email when someone changes this pad."
+ text: "An email was sent to your address. Click on the link in order to validate your unsubscription.",
+ // (int | optional) the time you want it to be alive for before fading out
+ time: 10000
});
}
From 335a0b065f63df9eba8509cb227675c50400f2f1 Mon Sep 17 00:00:00 2001
From: quenenni
Date: Tue, 2 Apr 2013 05:36:20 +0200
Subject: [PATCH 08/22] A small correction to avoid a error generated in
certain cases
---
index.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/index.js b/index.js
index a7e22ed..052b79d 100644
--- a/index.js
+++ b/index.js
@@ -27,7 +27,7 @@ exports.registerRoute = function (hook_name, args, callback) {
var timeDiffGood = false;
var email = "your email";
- if(userIds && userIds['pending']){
+ if(userIds && userIds['pending'] && userIds['pending'].length > 0){
async.forEach(Object.keys(userIds['pending']), function(user){
var userInfo = userIds['pending'][user];
From 787b9157be4a7c3df7e61be31cd551da0c7288a6 Mon Sep 17 00:00:00 2001
From: quenenni
Date: Wed, 3 Apr 2013 00:30:11 +0200
Subject: [PATCH 09/22] Better management of the (un)subscription process
---
index.js | 45 ++++++++++++++++++++++++---------------------
1 file changed, 24 insertions(+), 21 deletions(-)
diff --git a/index.js b/index.js
index 052b79d..d062b77 100644
--- a/index.js
+++ b/index.js
@@ -15,19 +15,22 @@ exports.registerRoute = function (hook_name, args, callback) {
var action = param[0];
var actionId = param[1];
var padURL = req.protocol + "://" + req.get('host') + "/p/" +padId;
- var resultDb = {};
- async.series(
+ async.waterfall(
[
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";
+ var resultDb = {
+ "foundInDb": foundInDb,
+ "timeDiffGood": timeDiffGood,
+ "email": email
+ }
- if(userIds && userIds['pending'] && userIds['pending'].length > 0){
+ if(userIds && userIds['pending']){
async.forEach(Object.keys(userIds['pending']), function(user){
var userInfo = userIds['pending'][user];
@@ -68,41 +71,41 @@ exports.registerRoute = function (hook_name, args, callback) {
padId
);
}
+
+ resultDb = {
+ "foundInDb": foundInDb,
+ "timeDiffGood": timeDiffGood,
+ "email": user
+ }
}
},
function(err, msg){
- // There should be something in here!
- console.error("Error in emailSubscription async in first function", err, " -> ", msg);
+ if (err != null) {
+ console.error("Error in async.forEach", err, " -> ", msg);
+ }
}); // end async for each
}
-
- resultDb = {
- "foundInDb": foundInDb,
- "timeDiffGood": timeDiffGood,
- "email": email
- }
-
- cb(null, 1);
+ cb(null, resultDb);
});
},
- function(cb) {
+ function(resultDb, cb) {
// Create and send the output message
sendContent(res, args, action, padId, padURL, resultDb);
-
- cb(null, 2);
+ cb(null, resultDb);
},
- function(cb) {
+ function(resultDb, cb) {
// Take a moment to clean all obsolete pending data
cleanPendingData(padId);
-
- cb(null, 3);
+ cb(null, resultDb);
}
],
function(err, results){
- console.error("Callback async.series: Err -> ", err, " / results -> ", results);
+ if (err != null) {
+ console.error("Callback async.series: Err -> ", err, " / results -> ", results);
+ }
}
);
});
From a98c59fed570e21a5dd3f8036cf4cb2dfd999b47 Mon Sep 17 00:00:00 2001
From: quenenni
Date: Wed, 3 Apr 2013 00:41:11 +0200
Subject: [PATCH 10/22] Not take into account the 'pending' section when
finding users to send a mail to
---
update.js | 70 ++++++++++++++++++++++++++++++-------------------------
1 file changed, 38 insertions(+), 32 deletions(-)
diff --git a/update.js b/update.js
index 6b29cf7..f47072b 100644
--- a/update.js
+++ b/update.js
@@ -43,22 +43,25 @@ exports.notifyBegin = function(padId){
db.get("emailSubscription:" + padId, function(err, recipients){ // get everyone we need to email
if(recipients){
async.forEach(Object.keys(recipients), function(recipient, cb){
- // 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({
- text: "Your pad at "+urlToPads+padId +" is being edited, we're just emailing you let you know :)",
- 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");
- }
- });
+ //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({
+ text: "Your pad at "+urlToPads+padId +" is being edited, we're just emailing you let you know :)",
+ 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");
+ }
+ });
+ }
cb(); // finish each user
},
function(err){
@@ -75,23 +78,26 @@ exports.notifyEnd = function(padId){
db.get("emailSubscription:" + padId, function(err, recipients){ // get everyone we need to email
if(recipients){
async.forEach(Object.keys(recipients), function(recipient, cb){
- // 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
+ //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
- if(!userIsOnPad && onEnd){
- console.debug("Emailing "+recipient +" about a pad finished being updated");
- server.send({
- text: "Your pad at "+urlToPads+padId +" has finished being edited, we're just emailing you let you know :) \n\n The changes look like this: \n" + changesToPad,
- 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");
- }
- });
+ if(!userIsOnPad && onEnd){
+ console.debug("Emailing "+recipient +" about a pad finished being updated");
+ server.send({
+ text: "Your pad at "+urlToPads+padId +" has finished being edited, we're just emailing you let you know :) \n\n The changes look like this: \n" + changesToPad,
+ 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");
+ }
+ });
+ }
cb(); // finish each user
},
function(err){
From c84222d0850ee05299921f95bc5e8385bb546aaa Mon Sep 17 00:00:00 2001
From: quenenni
Date: Wed, 3 Apr 2013 01:57:32 +0200
Subject: [PATCH 11/22] i18n of the plugin (english & french for now)
---
README.md | 8 +++++
static/js/ep_email.js | 40 +++++++++++-----------
templates/email_notifications_settings.ejs | 12 +++----
3 files changed, 34 insertions(+), 26 deletions(-)
diff --git a/README.md b/README.md
index f9e7202..4d4bf2d 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,9 @@
# Description
This plugin allows users to subscribe to pads and receive email updates when a pad is being modified. You can modify the frequency. This plugin is very much in alpha stage and has a lot of things TODO (See TODO).
+# Source code
+On Github : https://github.com/JohnMcLear/ep_email_notifications
+
# Installation
Make sure an SMTP gateway is installed IE postfix
Configure SPF and RDNS records to ensure proper mail flow <-- Search online
@@ -26,6 +29,11 @@ NOTE: You will NOT receive an email if you(the author that registered their emai
}
```
+# Translation
+This plugin has for now an english and french translation.
+In case you would like to have it in another language, you can easily translate the few sentences and then contact us on irc (#etherpad-lite-dev on irc.freenode.net) or create a Pull-Request on the GitHub repository.
+You can find the sentences to translate in the ep_email_notifications/locales/ directory.
+
# TODO
* Clean up all code
diff --git a/static/js/ep_email.js b/static/js/ep_email.js
index eb916fd..8a52ae6 100644
--- a/static/js/ep_email.js
+++ b/static/js/ep_email.js
@@ -10,9 +10,9 @@ exports.postAceInit = function(hook, context){
if (typeof clientVars.panelDisplayLocation != "object") {
$.gritter.add({
// (string | mandatory) the heading of the notification
- title: "Email subscription error",
+ title: window._('ep_email_notifications.titleGritterError'),
// (string | mandatory) the text inside the notification
- text: "Some settings for the 'email_Notifications' plugin are missing. Please contact your administrator.",
+ text: window._('ep_email_notifications.msgParamsMissing'),
// (int | optional) the time you want it to be alive for before fading out
time: 10000,
});
@@ -150,9 +150,9 @@ function askClientToEnterEmail(){
$.gritter.add({
// (string | mandatory) the heading of the notification
- title: "Email subscription",
+ title: window._('ep_email_notifications.titleGritterSubscr'),
// (string | mandatory) the text inside the notification
- text: "
" + formContent,
// (bool | optional) if you want it to fade out on its own or just sit there
sticky: true,
// (int | optional) the time you want it to be alive for before fading out
@@ -195,9 +195,9 @@ function checkAndSend(e) {
&& !$('#' + formName + ' [name=ep_email_onEnd]').is(':checked')) {
$.gritter.add({
// (string | mandatory) the heading of the notification
- title: "Email subscription error",
+ title: window._('ep_email_notifications.titleGritterError'),
// (string | mandatory) the text inside the notification
- text: "You need to check at least one of the two options from 'Send a mail when someone..'"
+ text: window._('ep_email_notifications.msgOptionsNotChecked')
});
} else if (email) {
$('#' + formName).submit();
@@ -253,9 +253,9 @@ Manage return msgs from server
function showRegistrationSuccess(){
$.gritter.add({
// (string | mandatory) the heading of the notification
- title: "Email subscription",
+ title: window._('ep_email_notifications.titleGritterSubscr'),
// (string | mandatory) the text inside the notification
- text: "An email was sent to your address. Click on the link in order to validate your subscription.",
+ text: window._('ep_email_notifications.msgSubscrSuccess'),
// (int | optional) the time you want it to be alive for before fading out
time: 10000
});
@@ -266,19 +266,19 @@ function showRegistrationSuccess(){
*/
function showAlreadyRegistered(type){
if (type == "malformedEmail") {
- var msg = "The email address is malformed";
+ var msg = window._('ep_email_notifications.msgEmailMalformed');
} else if (type == "alreadyRegistered") {
- var msg = "You are already registered for emails for this pad";
+ var msg = window._('ep_email_notifications.msgAlreadySubscr');
} else {
- var msg = "Unknown error";
+ var msg = window._('ep_email_notifications.msgUnknownErr');
}
$.gritter.add({
// (string | mandatory) the heading of the notification
- title: "Email subscription",
+ title: window._('ep_email_notifications.titleGritterSubscr'),
// (string | mandatory) the text inside the notification
text: msg,
- // (bool | optional) if you want it to fade out on its own or just sit there
- sticky: false
+ // (int | optional) the time you want it to be alive for before fading out
+ time: 7000
});
}
@@ -289,9 +289,9 @@ function showAlreadyRegistered(type){
function showUnregistrationSuccess(){
$.gritter.add({
// (string | mandatory) the heading of the notification
- title: "Email unsubscription",
+ title: window._('ep_email_notifications.titleGritterUnsubscr'),
// (string | mandatory) the text inside the notification
- text: "An email was sent to your address. Click on the link in order to validate your unsubscription.",
+ text: window._('ep_email_notifications.msgUnsubscrSuccess'),
// (int | optional) the time you want it to be alive for before fading out
time: 10000
});
@@ -303,11 +303,11 @@ function showUnregistrationSuccess(){
function showWasNotRegistered(){
$.gritter.add({
// (string | mandatory) the heading of the notification
- title: "Email unsubscription",
+ title: window._('ep_email_notifications.titleGritterUnsubscr'),
// (string | mandatory) the text inside the notification
- text: "This email address is not registered for this pad",
- // (bool | optional) if you want it to fade out on its own or just sit there
- sticky: false
+ text: window._('ep_email_notifications.msgUnsubscrNotExisting'),
+ // (int | optional) the time you want it to be alive for before fading out
+ time: 7000
});
}
diff --git a/templates/email_notifications_settings.ejs b/templates/email_notifications_settings.ejs
index 18533a9..a26aef1 100644
--- a/templates/email_notifications_settings.ejs
+++ b/templates/email_notifications_settings.ejs
@@ -1,21 +1,21 @@
-
+
From 18a3964a84e9b279a92108f54b7b5de8db6ae27d Mon Sep 17 00:00:00 2001
From: quenenni
Date: Wed, 3 Apr 2013 05:16:18 +0200
Subject: [PATCH 12/22] forgot to commit i18n files + validation output page
with template and external css
---
index.js | 82 +++++++++---------------------
locales/en.json | 19 +++++++
locales/fr.json | 19 +++++++
static/css/email_notifications.css | 30 +++++++++++
templates/response.ejs | 22 ++++++++
5 files changed, 113 insertions(+), 59 deletions(-)
create mode 100644 locales/en.json
create mode 100644 locales/fr.json
create mode 100644 templates/response.ejs
diff --git a/index.js b/index.js
index d062b77..6bc0c60 100644
--- a/index.js
+++ b/index.js
@@ -1,6 +1,7 @@
-var db = require('ep_etherpad-lite/node/db/DB').db,
- async = require('../../src/node_modules/async'),
- settings = require('../../src/node/utils/Settings');
+ 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');
// Remove cache for this procedure
db['dbSettings'].cache = 0;
@@ -222,69 +223,32 @@ function sendContent(res, args, action, padId, padURL, resultDb) {
if (resultDb.foundInDb == true && resultDb.timeDiffGood == true) {
// Pending data were found un Db and updated -> good
resultMsg = "Success";
- classResult = "good";
+ 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.";
+ }
} else if (resultDb.foundInDb == true) {
// Pending data were found but older than a day -> fail
- msgCause = "You have max 24h to click the link in your confirmation email.";
resultMsg = "Too late!";
- resultMsg += '
\n';
- resultMsg += msgCause;
- resultMsg += '
\n';
- classResult = "bad";
+ classResult = "validationBad";
+ msgCause = "You have max 24h to click the link in your confirmation email.";
} else {
// Pending data weren't found in Db -> fail
+ resultMsg = "Fail";
+ classResult = "validationBad";
msgCause = "We couldn't find any pending " + (action == 'subscribe'?'subscription':'unsubscription') + " in our system with this Id. Maybe you wait more than 24h before validating";
- resultMsg = "Fail\n";
- resultMsg += '
You won't receive anymore email when someone changes this pad.
";
- }
- args.content += '
\n';
- args.content += 'Go to the pad: ' + padURL + '';
- args.content += '
\n';
- args.content += '\n';
- args.content += '\n';
- res.send(args.content); // Send it to the requester
+ res.send(args.content); // Send it to the requester*/
}
diff --git a/locales/en.json b/locales/en.json
new file mode 100644
index 0000000..b036aa0
--- /dev/null
+++ b/locales/en.json
@@ -0,0 +1,19 @@
+{ "ep_email_notifications.titleGritterError": "Email subscription error"
+, "ep_email_notifications.titleGritterSubscr": "Email subscription"
+, "ep_email_notifications.titleGritterUnsubscr": "Email unsubscription"
+, "ep_email_notifications.headerGritterSubscr": "(Receive an email when someone modifies this pad)"
+, "ep_email_notifications.msgOptionsNotChecked": "You need to check at least one of the two options from 'Send a mail when someone..'"
+, "ep_email_notifications.msgParamsMissing": "Some settings for the 'email_Notifications' plugin are missing. Please contact your administrator."
+, "ep_email_notifications.msgEmailMalformed": "The email address is malformed"
+, "ep_email_notifications.msgAlreadySubscr": "You are already registered for emails for this pad"
+, "ep_email_notifications.msgUnsubscrNotExisting": "This email address is not registered for this pad"
+, "ep_email_notifications.msgUnknownErr": "Unknown error"
+, "ep_email_notifications.msgSubscrSuccess": "An email was sent to your address. Click on the link in order to validate your subscription."
+, "ep_email_notifications.msgUnsubscrSuccess": "An email was sent to your address. Click on the link in order to validate your unsubscription"
+, "ep_email_notifications.menuLabel": "Email Notifications"
+, "ep_email_notifications.formOptionsTitle": "Send a mail when someone.."
+, "ep_email_notifications.formOptionOnStart": "starts editing the pad"
+, "ep_email_notifications.formOptionOnEnd": "finish editing the pad"
+, "ep_email_notifications.formBtnSubscr": "subscribe"
+, "ep_email_notifications.formBtnUnsubscr": "unsubscribe"
+}
diff --git a/locales/fr.json b/locales/fr.json
new file mode 100644
index 0000000..4fb12c1
--- /dev/null
+++ b/locales/fr.json
@@ -0,0 +1,19 @@
+{ "ep_email_notifications.titleGritterError": "Notification par email - Erreur"
+, "ep_email_notifications.titleGritterSubscr": "Notification par email"
+, "ep_email_notifications.titleGritterUnsubscr": "Désinscription d'email"
+, "ep_email_notifications.headerGritterSubscr": "(Être prévenu lorsque quelqu'un modifie ce pad)"
+, "ep_email_notifications.msgOptionsNotChecked": "Il faut cocher au moins une des 2 options pour l'inscription de l'email..'"
+, "ep_email_notifications.msgParamsMissing": "Les paramètres de configurations du plugin 'email_Notifications' sont manquantes. Veuillez contacter votre administrateur."
+, "ep_email_notifications.msgEmailMalformed": "L'adresse email n'est pas valide"
+, "ep_email_notifications.msgAlreadySubscr": "Vous avez déjà enregistré cette adresse email pour ce pad"
+, "ep_email_notifications.msgUnsubscrNotExisting": "Cette adresse email n'est pas enregistrée pour ce pad"
+, "ep_email_notifications.msgUnknownErr": "Etteur inconnue"
+, "ep_email_notifications.msgSubscrSuccess": "Un email a été envoyé à votre adresse. Cliquez sur le lien afin de valider votre inscription."
+, "ep_email_notifications.msgUnsubscrSuccess": "Un email a été envoyé à votre adresse. Cliquez sur le lien afin de valider votre désinscription."
+, "ep_email_notifications.menuLabel": "Notification par email"
+, "ep_email_notifications.formOptionsTitle": "Envoyer un email quand qqu'un.."
+, "ep_email_notifications.formOptionOnStart": "commence l'édition du pad"
+, "ep_email_notifications.formOptionOnEnd": "a fini d'éditer le pad"
+, "ep_email_notifications.formBtnSubscr": "inscription"
+, "ep_email_notifications.formBtnUnsubscr": "désinscription"
+}
diff --git a/static/css/email_notifications.css b/static/css/email_notifications.css
index 2801045..44d2da7 100644
--- a/static/css/email_notifications.css
+++ b/static/css/email_notifications.css
@@ -32,3 +32,33 @@
margin: .3em 0;
width:95%;
}
+/* (un)subscription validation page */
+.validationTitle {
+ margin: 0 auto;
+ width: 600px;
+ text-align: center;
+}
+.validationEmailSubscription {
+ width: 600px;
+ margin: 0 auto;
+ text-align: center;
+ font-size: bigger;
+ font-weight: bold;
+ font-color: green;
+}
+.validationEmailSubscription > div {
+ border: solid 2px #333;
+ padding: .3em;
+ margin: .5em 0;
+}
+.validationEmailSubscription > div > div {
+ margin:0;
+ padding:.2em;
+ font-weight:normal;
+}
+.validationGood {
+ background-color: green;
+}
+.validationBad {
+ background-color: red;
+}
diff --git a/templates/response.ejs b/templates/response.ejs
new file mode 100644
index 0000000..5cd004b
--- /dev/null
+++ b/templates/response.ejs
@@ -0,0 +1,22 @@
+
+
+
+ Email Notifications Subscription
+
+
+
+
+
+
From 66f1f7f2c32a1a4855d0810ec057e0e90be857b3 Mon Sep 17 00:00:00 2001
From: quenenni
Date: Wed, 3 Apr 2013 05:40:12 +0200
Subject: [PATCH 13/22] Tweaks: i18n in unicode format + nicer color for msg
---
README.md | 1 +
locales/fr.json | 28 ++++++++++++++--------------
static/css/email_notifications.css | 4 ++--
3 files changed, 17 insertions(+), 16 deletions(-)
diff --git a/README.md b/README.md
index 4d4bf2d..f51b9e6 100644
--- a/README.md
+++ b/README.md
@@ -33,6 +33,7 @@ NOTE: You will NOT receive an email if you(the author that registered their emai
This plugin has for now an english and french translation.
In case you would like to have it in another language, you can easily translate the few sentences and then contact us on irc (#etherpad-lite-dev on irc.freenode.net) or create a Pull-Request on the GitHub repository.
You can find the sentences to translate in the ep_email_notifications/locales/ directory.
+Specials chars written in unicode (See https://fr.wikipedia.org/wiki/Table_des_caract%C3%A8res_Unicode_%280000-0FFF%29)
# TODO
* Clean up all code
diff --git a/locales/fr.json b/locales/fr.json
index 4fb12c1..a301ed5 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -1,19 +1,19 @@
{ "ep_email_notifications.titleGritterError": "Notification par email - Erreur"
, "ep_email_notifications.titleGritterSubscr": "Notification par email"
-, "ep_email_notifications.titleGritterUnsubscr": "Désinscription d'email"
-, "ep_email_notifications.headerGritterSubscr": "(Être prévenu lorsque quelqu'un modifie ce pad)"
-, "ep_email_notifications.msgOptionsNotChecked": "Il faut cocher au moins une des 2 options pour l'inscription de l'email..'"
-, "ep_email_notifications.msgParamsMissing": "Les paramètres de configurations du plugin 'email_Notifications' sont manquantes. Veuillez contacter votre administrateur."
-, "ep_email_notifications.msgEmailMalformed": "L'adresse email n'est pas valide"
-, "ep_email_notifications.msgAlreadySubscr": "Vous avez déjà enregistré cette adresse email pour ce pad"
-, "ep_email_notifications.msgUnsubscrNotExisting": "Cette adresse email n'est pas enregistrée pour ce pad"
-, "ep_email_notifications.msgUnknownErr": "Etteur inconnue"
-, "ep_email_notifications.msgSubscrSuccess": "Un email a été envoyé à votre adresse. Cliquez sur le lien afin de valider votre inscription."
-, "ep_email_notifications.msgUnsubscrSuccess": "Un email a été envoyé à votre adresse. Cliquez sur le lien afin de valider votre désinscription."
+, "ep_email_notifications.titleGritterUnsubscr": "D\u00e9sinscription d\u2019email"
+, "ep_email_notifications.headerGritterSubscr": "(\u00catre pr\u00e9venu lorsque quelqu\u2019un modifie ce pad)"
+, "ep_email_notifications.msgOptionsNotChecked": "Il faut cocher au moins une des 2 options pour l\u2019inscription de l\u2019email..\u2019"
+, "ep_email_notifications.msgParamsMissing": "Les param\u00e8tres de configurations du plugin \u2019email_Notifications\u2019 sont manquants. Veuillez contacter votre administrateur."
+, "ep_email_notifications.msgEmailMalformed": "L\u2019adresse email n\u2019est pas valide"
+, "ep_email_notifications.msgAlreadySubscr": "Vous avez d\u00e9j\u00e0 enregistr\u00e9 cette adresse email pour ce pad"
+, "ep_email_notifications.msgUnsubscrNotExisting": "Cette adresse email n\u2019est pas enregistr\u00e9e pour ce pad"
+, "ep_email_notifications.msgUnknownErr": "Erreur inconnue"
+, "ep_email_notifications.msgSubscrSuccess": "Un email a \u00e9t\u00e9 envoy\u00e9 \u00e0 votre adresse. Cliquez sur le lien afin de valider votre inscription."
+, "ep_email_notifications.msgUnsubscrSuccess": "Un email a \u00e9t\u00e9 envoy\u00e9 \u00e0 votre adresse. Cliquez sur le lien afin de valider votre d\u00e9sinscription."
, "ep_email_notifications.menuLabel": "Notification par email"
-, "ep_email_notifications.formOptionsTitle": "Envoyer un email quand qqu'un.."
-, "ep_email_notifications.formOptionOnStart": "commence l'édition du pad"
-, "ep_email_notifications.formOptionOnEnd": "a fini d'éditer le pad"
+, "ep_email_notifications.formOptionsTitle": "Envoyer un email quand qqu\u2019un.."
+, "ep_email_notifications.formOptionOnStart": "commence l\u2019\u00e9dition du pad"
+, "ep_email_notifications.formOptionOnEnd": "a fini d\u2019\u00e9diter le pad"
, "ep_email_notifications.formBtnSubscr": "inscription"
-, "ep_email_notifications.formBtnUnsubscr": "désinscription"
+, "ep_email_notifications.formBtnUnsubscr": "d\u00e9sinscription"
}
diff --git a/static/css/email_notifications.css b/static/css/email_notifications.css
index 44d2da7..739e45b 100644
--- a/static/css/email_notifications.css
+++ b/static/css/email_notifications.css
@@ -57,8 +57,8 @@
font-weight:normal;
}
.validationGood {
- background-color: green;
+ background-color: #CCFF66;
}
.validationBad {
- background-color: red;
+ background-color: #FF3300;
}
From 75578aa676a48b6e196d9c32c8d0bebe26014916 Mon Sep 17 00:00:00 2001
From: quenenni
Date: Thu, 4 Apr 2013 14:57:54 +0200
Subject: [PATCH 14/22] Added test to var coming from settings.json file to
avoid errors
---
handleMessage.js | 8 ++++----
update.js | 12 ++++++------
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/handleMessage.js b/handleMessage.js
index 0bfd1e7..e1b0f5c 100644
--- a/handleMessage.js
+++ b/handleMessage.js
@@ -6,10 +6,10 @@ randomString = require('../../src/static/js/pad_utils').randomString;
settings = require('../../src/node/utils/Settings');
var pluginSettings = settings.ep_email_notifications;
-var fromName = pluginSettings.fromName || "Etherpad";
-var fromEmail = pluginSettings.fromEmail || "pad@etherpad.org";
-var urlToPads = pluginSettings.urlToPads || "http://beta.etherpad.org/p/";
-var emailServer = pluginSettings.emailServer || {host:"127.0.0.1"};
+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"};
// Connect to the email server -- This might not be the ideal place to connect but it stops us having lots of connections
var server = email.server.connect(emailServer);
diff --git a/update.js b/update.js
index f47072b..0874624 100644
--- a/update.js
+++ b/update.js
@@ -8,12 +8,12 @@ settings = require('../../src/node/utils/Settings');
// Settings -- EDIT THESE IN settings.json not here..
var pluginSettings = settings.ep_email_notifications;
-var checkFrequency = pluginSettings.checkFrequency || 60000; // 10 seconds
-var staleTime = pluginSettings.staleTime || 300000; // 5 minutes
-var fromName = pluginSettings.fromName || "Etherpad";
-var fromEmail = pluginSettings.fromEmail || "pad@etherpad.org";
-var urlToPads = pluginSettings.urlToPads || "http://beta.etherpad.org/p/";
-var emailServer = pluginSettings.emailServer || {host:"127.0.0.1"};
+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"};
// A timer object we maintain to control how we send emails
var timers = {};
From de660e89d2a5aec4792823265c1e99c075a88ac2 Mon Sep 17 00:00:00 2001
From: quenenni
Date: Thu, 4 Apr 2013 17:57:37 +0200
Subject: [PATCH 15/22] if no settings for the pligin -> msg sent to the user
---
client.js | 4 +++-
locales/en.json | 2 +-
static/js/ep_email.js | 4 ++--
update.js | 3 +++
4 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/client.js b/client.js
index 73a98d9..1b360be 100644
--- a/client.js
+++ b/client.js
@@ -16,6 +16,8 @@ exports.eejsBlock_styles = function (hook_name, args, cb) {
};
exports.clientVars = function(hook, context, callback) {
+ var pluginSettings = settings.ep_email_notifications;
+ var panelDisplayLocation = (pluginSettings && pluginSettings.panelDisplayLocation)?pluginSettings.panelDisplayLocation:"undefiend";
// return the setting to the clientVars, sending the value
- return callback({ "panelDisplayLocation": settings.ep_email_notifications.panelDisplayLocation });
+ return callback({ "panelDisplayLocation": panelDisplayLocation });
};
diff --git a/locales/en.json b/locales/en.json
index b036aa0..2884b90 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -3,7 +3,7 @@
, "ep_email_notifications.titleGritterUnsubscr": "Email unsubscription"
, "ep_email_notifications.headerGritterSubscr": "(Receive an email when someone modifies this pad)"
, "ep_email_notifications.msgOptionsNotChecked": "You need to check at least one of the two options from 'Send a mail when someone..'"
-, "ep_email_notifications.msgParamsMissing": "Some settings for the 'email_Notifications' plugin are missing. Please contact your administrator."
+, "ep_email_notifications.msgParamsMissing": "Settings for the 'email_Notifications' plugin are missing. Please contact your administrator."
, "ep_email_notifications.msgEmailMalformed": "The email address is malformed"
, "ep_email_notifications.msgAlreadySubscr": "You are already registered for emails for this pad"
, "ep_email_notifications.msgUnsubscrNotExisting": "This email address is not registered for this pad"
diff --git a/static/js/ep_email.js b/static/js/ep_email.js
index 8a52ae6..8f59212 100644
--- a/static/js/ep_email.js
+++ b/static/js/ep_email.js
@@ -13,8 +13,8 @@ exports.postAceInit = function(hook, context){
title: window._('ep_email_notifications.titleGritterError'),
// (string | mandatory) the text inside the notification
text: window._('ep_email_notifications.msgParamsMissing'),
- // (int | optional) the time you want it to be alive for before fading out
- time: 10000,
+ // (bool | optional) if you want it to fade out on its own or just sit there
+ sticky: true
});
// Hide the notification menu in mysettings
diff --git a/update.js b/update.js
index 0874624..1f0e6d9 100644
--- a/update.js
+++ b/update.js
@@ -8,6 +8,7 @@ settings = require('../../src/node/utils/Settings');
// Settings -- EDIT THESE IN settings.json not here..
var pluginSettings = settings.ep_email_notifications;
+var areParamsOk = (pluginSettings)?true:false;
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";
@@ -22,6 +23,8 @@ var timers = {};
var server = email.server.connect(emailServer);
exports.padUpdate = function (hook_name, _pad) {
+ if (areParamsOk == false) return false;
+
var pad = _pad.pad;
var padId = pad.id;
exports.sendUpdates(padId);
From 941ede5dafbe7948e469e8b5026da43961169d9f Mon Sep 17 00:00:00 2001
From: quenenni
Date: Thu, 4 Apr 2013 18:06:07 +0200
Subject: [PATCH 16/22] wIll I be invited by the king of my country now?
---
package.json | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/package.json b/package.json
index b394d1a..10c90e2 100644
--- a/package.json
+++ b/package.json
@@ -1,13 +1,17 @@
{
"name": "ep_email_notifications",
"description": "Subscribe to a pad and receive an email when someone edits your pad",
- "version": "0.0.6",
+ "version": "0.0.7",
"author": {
"name": "johnyma22",
"email": "john@mclear.co.uk",
"url": "John McLear"
},
- "contributors": [],
+ "contributors": [{
+ "name": "quenenni",
+ "email": "quenenni@bruxxel.org",
+ "url": "https://github.com/quenenni"
+ }],
"dependencies": {
"emailjs": ">= 0.2.7",
"buffertools": ">= 1.0.8",
@@ -18,7 +22,7 @@
},
"readme": "# Description\nThis plugin allows users to subscribe to pads and receive email updates when a pad is being modified. You can modify the frequency. This plugin is very much in alpha stage and has a lot of things TODO (See TODO).\n\n# Installation\nMake sure an SMTP gateway is installed IE postfix\nConfigure SPF and RDNS records to ensure proper mail flow <-- Search online\nCopy/Edit the below to your settings.json\nConnect to a pad, Click on the Share/Embed link and enter in your email address.\nOpen that pad in ANOTHER BROWSER then begin modifying, you should receive an email when the pad has begun editing and once the pad has gone stale (when everyone stops editing it and a time period passes).\nNOTE: You will NOT receive an email if you(the author that registered their email) are currently on or editing that pad!\n\n```\n \"ep_email_notifications\" : {\n checkFrequency: 6000, // checkFrequency = How frequently(milliseconds) to check for pad updates -- Move me to the settings file\n staleTime: 30000, // staleTime = How stale(milliseconds) does a pad need to be before notifying subscribers? Move me to settings\n fromName: \"Etherpad SETTINGS FILE!\",\n fromEmail: \"pad@etherpad.org\",\n urlToPads: \"http://beta.etherpad.org/p/\", // urlToPads = The URL to your pads note the trailing /\n emailServer: { // See https://github.com/eleith/emailjs for settings\n host: \"127.0.0.1\"\n }\n }\n```\n\n# TODO\n* Clean up all code\n\n# FUTURE VERSIONS TODO\n* v2 - Get the modified contents from the API HTML diff and append that to the Email and make the email from the server HTML not plain text\n* v2 - a point to unsubscribe and validate/verify email https://github.com/alfredwesterveld/node-email-verification\n* v2 - Keep a record of when a user was last on a pad\n",
"readmeFilename": "README.md",
- "_id": "ep_email_notifications@0.0.6",
+ "_id": "ep_email_notifications@0.0.7",
"dist": {
"shasum": "1f32eee4c8d5f3903c549b5a7985afc0053ed451"
},
From 0bccbc5ce1223ee562191acd388e96c45a652d95 Mon Sep 17 00:00:00 2001
From: quenenni
Date: Thu, 4 Apr 2013 20:39:43 +0200
Subject: [PATCH 17/22] handling missing setting values
- default value given to panelDisplyLocation if missing instead of showing an error msg
- sending an error msg when user tries to use the plugin if settings are missing
- send a warn msg in the console on server start and when using the plugin if settings are missing
---
ep.json | 3 ++-
handleMessage.js | 13 ++++++++++++-
static/js/ep_email.js | 44 +++++++++++++++++++++++++++++--------------
3 files changed, 44 insertions(+), 16 deletions(-)
diff --git a/ep.json b/ep.json
index 8f69f6c..13e3687 100644
--- a/ep.json
+++ b/ep.json
@@ -15,7 +15,8 @@
"postAceInit":"ep_email_notifications/static/js/ep_email:postAceInit",
"handleClientMessage_emailSubscriptionSuccess":"ep_email_notifications/static/js/ep_email",
"handleClientMessage_emailUnsubscriptionSuccess":"ep_email_notifications/static/js/ep_email",
- "handleClientMessage_emailNotificationGetUserInfo":"ep_email_notifications/static/js/ep_email"
+ "handleClientMessage_emailNotificationGetUserInfo":"ep_email_notifications/static/js/ep_email",
+ "handleClientMessage_emailNotificationMissingParams":"ep_email_notifications/static/js/ep_email"
}
}
]
diff --git a/handleMessage.js b/handleMessage.js
index e1b0f5c..ebbf5ef 100644
--- a/handleMessage.js
+++ b/handleMessage.js
@@ -6,11 +6,14 @@ randomString = require('../../src/static/js/pad_utils').randomString;
settings = require('../../src/node/utils/Settings');
var pluginSettings = settings.ep_email_notifications;
+var areParamsOk = (pluginSettings)?true:false;
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"};
+if (areParamsOk == false) console.warn("Settings for ep_email_notifications plugin are missing in settings.json file");
+
// Connect to the email server -- This might not be the ideal place to connect but it stops us having lots of connections
var server = email.server.connect(emailServer);
@@ -18,7 +21,15 @@ var server = email.server.connect(emailServer);
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 (areParamsOk == false) {
+ context.client.json.send({ type: "COLLABROOM",
+ data:{
+ type: "emailNotificationMissingParams",
+ payload: true
+ }
+ });
+ console.warn("Settings for ep_email_notifications plugin are missing in settings.json file");
+ } else if (context.message.data.userInfo){
if(context.message.data.userInfo.email){ // it contains email
console.debug(context.message);
diff --git a/static/js/ep_email.js b/static/js/ep_email.js
index 8f59212..efd02e0 100644
--- a/static/js/ep_email.js
+++ b/static/js/ep_email.js
@@ -6,21 +6,12 @@ if(typeof exports == 'undefined'){
}
exports.postAceInit = function(hook, context){
- // Test if settings are good before continuing
+ // If panelDisplayLocation setting is missing, set default value
if (typeof clientVars.panelDisplayLocation != "object") {
- $.gritter.add({
- // (string | mandatory) the heading of the notification
- title: window._('ep_email_notifications.titleGritterError'),
- // (string | mandatory) the text inside the notification
- text: window._('ep_email_notifications.msgParamsMissing'),
- // (bool | optional) if you want it to fade out on its own or just sit there
- sticky: true
- });
-
- // Hide the notification menu in mysettings
- $('#options-emailNotifications').parent().hide();
-
- return false;
+ clientVars.panelDisplayLocation = {
+ mysettings: true, // In the "mysettings" menu
+ popup: true
+ }
}
// If plugin settings set panel form in mysettings menu
@@ -118,6 +109,31 @@ exports.handleClientMessage_emailNotificationGetUserInfo = function (hook, conte
}
}
+exports.handleClientMessage_emailNotificationMissingParams = function (hook, context) { // Settings are missing in settings.json file
+ if (context.payload == true) {
+ $.gritter.add({
+ // (string | mandatory) the heading of the notification
+ title: window._('ep_email_notifications.titleGritterError'),
+ // (string | mandatory) the text inside the notification
+ text: window._('ep_email_notifications.msgParamsMissing'),
+ // (bool | optional) if you want it to fade out on its own or just sit there
+ sticky: true
+ });
+
+ // Hide the notification menu in mysettings
+ if (clientVars.panelDisplayLocation.mysettings == true && $('.ep_email_settings').is(":visible")) {
+ $('.ep_email_settings').slideToggle();
+ $('#options-emailNotifications').prop('checked', false);
+ $('#options-emailNotifications').parent().hide();
+ }
+
+ // Hide the popup if it is visible
+ if (clientVars.panelDisplayLocation.popup == true && $('#ep_email_form_popup').is(":visible")) {
+ $('#ep_email_form_popup').parent().parent().parent().hide();
+ }
+ }
+}
+
/**
* Initialize the popup panel form for subscription
*/
From fddc835f826dbb78221ba202ec436b22a0679b38 Mon Sep 17 00:00:00 2001
From: quenenni
Date: Thu, 4 Apr 2013 20:56:19 +0200
Subject: [PATCH 18/22] Cookie management
---
static/js/ep_email.js | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/static/js/ep_email.js b/static/js/ep_email.js
index efd02e0..5c8c609 100644
--- a/static/js/ep_email.js
+++ b/static/js/ep_email.js
@@ -64,6 +64,9 @@ exports.handleClientMessage_emailSubscriptionSuccess = function(hook, context){
} else {
showRegistrationSuccess();
+ // Add cookie to say an email is registered for this pad
+ cookie.setPref(pad.getPadId() + "email", "true");
+
if (clientVars.panelDisplayLocation.mysettings == true && $('.ep_email_settings').is(":visible")) {
$('.ep_email_settings').slideToggle();
$('#options-emailNotifications').prop('checked', false);
@@ -82,6 +85,9 @@ exports.handleClientMessage_emailUnsubscriptionSuccess = function(hook, context)
} else {
showUnregistrationSuccess();
+ // Set cookie to say no email is registered for this pad
+ cookie.setPref(pad.getPadId() + "email", "false");
+
if (clientVars.panelDisplayLocation.mysettings == true && $('.ep_email_settings').is(":visible")) {
$('.ep_email_settings').slideToggle();
$('#options-emailNotifications').prop('checked', false);
@@ -239,7 +245,6 @@ function sendEmailToServer(formName){
message.userInfo.userId = userId;
if(email){
pad.collabClient.sendMessage(message);
- cookie.setPref(message.padId+"email", "true");
}
}
From 5c258325c26f8830c9a7d3e634156832e9dc0b88 Mon Sep 17 00:00:00 2001
From: quenenni
Date: Thu, 4 Apr 2013 21:03:54 +0200
Subject: [PATCH 19/22] css correction
---
static/css/email_notifications.css | 2 +-
static/js/ep_email.js | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/static/css/email_notifications.css b/static/css/email_notifications.css
index 739e45b..a5e5ee0 100644
--- a/static/css/email_notifications.css
+++ b/static/css/email_notifications.css
@@ -16,7 +16,7 @@
width:177px;
}
-#ep_email_form_popup > p {
+.ep_email_form_popup_header {
font-size:x-small;
}
diff --git a/static/js/ep_email.js b/static/js/ep_email.js
index 5c8c609..4be591a 100644
--- a/static/js/ep_email.js
+++ b/static/js/ep_email.js
@@ -174,7 +174,7 @@ function askClientToEnterEmail(){
// (string | mandatory) the heading of the notification
title: window._('ep_email_notifications.titleGritterSubscr'),
// (string | mandatory) the text inside the notification
- text: "
" + formContent,
// (bool | optional) if you want it to fade out on its own or just sit there
sticky: true,
// (int | optional) the time you want it to be alive for before fading out
From a8d22c3cf88c98342a821bf7f7edaf72783f39c5 Mon Sep 17 00:00:00 2001
From: quenenni
Date: Thu, 4 Apr 2013 21:09:57 +0200
Subject: [PATCH 20/22] testing for i18n problems
---
handleMessage.js | 3 +++
static/js/ep_email.js | 6 ++++--
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/handleMessage.js b/handleMessage.js
index ebbf5ef..e10e2cf 100644
--- a/handleMessage.js
+++ b/handleMessage.js
@@ -29,6 +29,9 @@ exports.handleMessage = function(hook_name, context, callback){
}
});
console.warn("Settings for ep_email_notifications plugin are missing in settings.json file");
+
+ callback([null]); // don't run onto passing colorId or anything else to the message handler
+
} else if (context.message.data.userInfo){
if(context.message.data.userInfo.email){ // it contains email
console.debug(context.message);
diff --git a/static/js/ep_email.js b/static/js/ep_email.js
index 4be591a..801af4d 100644
--- a/static/js/ep_email.js
+++ b/static/js/ep_email.js
@@ -117,11 +117,13 @@ exports.handleClientMessage_emailNotificationGetUserInfo = function (hook, conte
exports.handleClientMessage_emailNotificationMissingParams = function (hook, context) { // Settings are missing in settings.json file
if (context.payload == true) {
+ var title = window._('ep_email_notifications.titleGritterError');
+ var msg = window._('ep_email_notifications.msgParamsMissing');
$.gritter.add({
// (string | mandatory) the heading of the notification
- title: window._('ep_email_notifications.titleGritterError'),
+ title: title,
// (string | mandatory) the text inside the notification
- text: window._('ep_email_notifications.msgParamsMissing'),
+ text: msg,
// (bool | optional) if you want it to fade out on its own or just sit there
sticky: true
});
From f7e79f48467bcb78feed778c5c4b68828fbb92ab Mon Sep 17 00:00:00 2001
From: quenenni
Date: Thu, 4 Apr 2013 23:07:13 +0200
Subject: [PATCH 21/22] Back before all the tests
---
static/js/ep_email.js | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/static/js/ep_email.js b/static/js/ep_email.js
index 801af4d..4be591a 100644
--- a/static/js/ep_email.js
+++ b/static/js/ep_email.js
@@ -117,13 +117,11 @@ exports.handleClientMessage_emailNotificationGetUserInfo = function (hook, conte
exports.handleClientMessage_emailNotificationMissingParams = function (hook, context) { // Settings are missing in settings.json file
if (context.payload == true) {
- var title = window._('ep_email_notifications.titleGritterError');
- var msg = window._('ep_email_notifications.msgParamsMissing');
$.gritter.add({
// (string | mandatory) the heading of the notification
- title: title,
+ title: window._('ep_email_notifications.titleGritterError'),
// (string | mandatory) the text inside the notification
- text: msg,
+ text: window._('ep_email_notifications.msgParamsMissing'),
// (bool | optional) if you want it to fade out on its own or just sit there
sticky: true
});
From 7135f1d47ab8ca5524f061faabcda75dfeac7e3e Mon Sep 17 00:00:00 2001
From: quenenni
Date: Thu, 4 Apr 2013 23:24:24 +0200
Subject: [PATCH 22/22] some cleaning
---
README.md | 2 +-
handleMessage.js | 3 +--
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index f51b9e6..84703d7 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
# Description
-This plugin allows users to subscribe to pads and receive email updates when a pad is being modified. You can modify the frequency. This plugin is very much in alpha stage and has a lot of things TODO (See TODO).
+This plugin allows users to subscribe to pads and receive email updates when a pad is being modified. You can modify the frequency. This plugin is still in early stage and has things TODO (See TODO).
# Source code
On Github : https://github.com/JohnMcLear/ep_email_notifications
diff --git a/handleMessage.js b/handleMessage.js
index e10e2cf..358c5e7 100644
--- a/handleMessage.js
+++ b/handleMessage.js
@@ -366,7 +366,7 @@ exports.setAuthorEmailRegistered = function(userInfo, authorId, subscribeId, pad
// add the registered values to the pending section of the object
value['pending'][userInfo.email] = registered;
- console.warn("written to database");
+ // Write the modified datas back in the Db
db.set("emailSubscription:" + padId, value); // stick it in the database
});
@@ -390,7 +390,6 @@ exports.unsetAuthorEmailRegistered = function(userInfo, authorId, unsubscribeId,
value['pending'][userInfo.email] = registered;
// Write the modified datas back in the Db
- console.warn("written to database");
db.set("emailSubscription:" + padId, value);
});
}