From d246a191c6cc9a6e2d84451058e2252f7c552095 Mon Sep 17 00:00:00 2001 From: Cristo Date: Sat, 8 Nov 2014 01:12:40 +0100 Subject: [PATCH 1/8] Added option to restore revisions #1791 --- src/node/db/API.js | 98 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/src/node/db/API.js b/src/node/db/API.js index 4a912368..2aadc483 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -576,6 +576,104 @@ exports.deletePad = function(padID, callback) }); } +exports.restoreRevision = function(padID, rev, callback) +{ + var Changeset = require("ep_etherpad-lite/static/js/Changeset"); + + //check if rev is a number + if(rev !== undefined && typeof rev != "number") + { + //try to parse the number + if(!isNaN(parseInt(rev))) + { + rev = parseInt(rev); + } + else + { + callback(new customError("rev is not a number", "apierror")); + return; + } + } + + //ensure this is not a negativ number + if(rev !== undefined && rev < 0) + { + callback(new customError("rev is a negativ number","apierror")); + return; + } + + //ensure this is not a float value + if(rev !== undefined && !is_int(rev)) + { + callback(new customError("rev is a float value","apierror")); + return; + } + + //get the pad + getPadSafe(padID, true, function(err, pad) + { + if(ERR(err, callback)) return; + + + //check if this is a valid revision + if(rev > pad.getHeadRevisionNumber()) + { + callback(new customError("rev is higher than the head revision of the pad","apierror")); + return; + } + + pad.getInternalRevisionAText(rev, function(err, atext) + { + if(ERR(err, callback)) return; + + var oldText = pad.text(); + atext.text += "\n"; + function eachAttribRun(attribs, func) + { + var attribsIter = Changeset.opIterator(attribs); + var textIndex = 0; + var newTextStart = 0; + var newTextEnd = atext.text.length; + while (attribsIter.hasNext()) + { + var op = attribsIter.next(); + var nextIndex = textIndex + op.chars; + if (!(nextIndex <= newTextStart || textIndex >= newTextEnd)) + { + func(Math.max(newTextStart, textIndex), Math.min(newTextEnd, nextIndex), op.attribs); + } + textIndex = nextIndex; + } + } + + // create a new changeset with a helper builder object + var builder = Changeset.builder(oldText.length); + + // assemble each line into the builder + eachAttribRun(atext.attribs, function(start, end, attribs) + { + builder.insert(atext.text.substring(start, end), attribs); + }); + + var lastNewlinePos = oldText.lastIndexOf('\n'); + if (lastNewlinePos < 0) { + builder.remove(oldText.length-1,0); + } else { + builder.remove(lastNewlinePos, oldText.match(/\n/g).length-1); + builder.remove(oldText.length - lastNewlinePos-1,0); + } + + var changeset = builder.toString(); + + //append the changeset + pad.appendRevision(changeset); + // + callback(null, changeset); + }); + + }); +}; + /** copyPad(sourceID, destinationID[, force=false]) copies a pad. If force is true, the destination will be overwritten if it exists. From c33c6e085ec533056cb5bf75dc76350e9cdf03ba Mon Sep 17 00:00:00 2001 From: Cristo Date: Sat, 8 Nov 2014 01:39:27 +0100 Subject: [PATCH 2/8] comment addded --- src/node/db/API.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index 2aadc483..8ad6e2eb 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -575,7 +575,14 @@ exports.deletePad = function(padID, callback) pad.remove(callback); }); } +/** + restoreRevision(padID, [rev]) Restores revision from past as new changeset + Example returns: + + {code:0, message:"ok", data:null} + {code: 1, message:"padID does not exist", data: null} + */ exports.restoreRevision = function(padID, rev, callback) { var Changeset = require("ep_etherpad-lite/static/js/Changeset"); @@ -668,7 +675,7 @@ exports.restoreRevision = function(padID, rev, callback) //append the changeset pad.appendRevision(changeset); // - callback(null, changeset); + callback(null, null); }); }); From 46bc328896877630169c4cea60431be981859352 Mon Sep 17 00:00:00 2001 From: Cristo Date: Sat, 8 Nov 2014 01:41:23 +0100 Subject: [PATCH 3/8] new api ver --- src/node/handler/APIHandler.js | 48 +++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/src/node/handler/APIHandler.js b/src/node/handler/APIHandler.js index 273a58a6..76af4aa1 100644 --- a/src/node/handler/APIHandler.js +++ b/src/node/handler/APIHandler.js @@ -345,10 +345,56 @@ var version = , "getChatHistory" : ["padID", "start", "end"] , "getChatHead" : ["padID"] } + , "1.2.11": + { "createGroup" : [] + , "createGroupIfNotExistsFor" : ["groupMapper"] + , "deleteGroup" : ["groupID"] + , "listPads" : ["groupID"] + , "listAllPads" : [] + , "createDiffHTML" : ["padID", "startRev", "endRev"] + , "createPad" : ["padID", "text"] + , "createGroupPad" : ["groupID", "padName", "text"] + , "createAuthor" : ["name"] + , "createAuthorIfNotExistsFor": ["authorMapper" , "name"] + , "listPadsOfAuthor" : ["authorID"] + , "createSession" : ["groupID", "authorID", "validUntil"] + , "deleteSession" : ["sessionID"] + , "getSessionInfo" : ["sessionID"] + , "listSessionsOfGroup" : ["groupID"] + , "listSessionsOfAuthor" : ["authorID"] + , "getText" : ["padID", "rev"] + , "setText" : ["padID", "text"] + , "getHTML" : ["padID", "rev"] + , "setHTML" : ["padID", "html"] + , "getAttributePool" : ["padID"] + , "getRevisionsCount" : ["padID"] + , "getRevisionChangeset" : ["padID", "rev"] + , "getLastEdited" : ["padID"] + , "deletePad" : ["padID"] + , "copyPad" : ["sourceID", "destinationID", "force"] + , "movePad" : ["sourceID", "destinationID", "force"] + , "getReadOnlyID" : ["padID"] + , "getPadID" : ["roID"] + , "setPublicStatus" : ["padID", "publicStatus"] + , "getPublicStatus" : ["padID"] + , "setPassword" : ["padID", "password"] + , "isPasswordProtected" : ["padID"] + , "listAuthorsOfPad" : ["padID"] + , "padUsersCount" : ["padID"] + , "getAuthorName" : ["authorID"] + , "padUsers" : ["padID"] + , "sendClientsMessage" : ["padID", "msg"] + , "listAllGroups" : [] + , "checkToken" : [] + , "getChatHistory" : ["padID"] + , "getChatHistory" : ["padID", "start", "end"] + , "getChatHead" : ["padID"] + , "restoreRevision" : ["padID", "rev"] + } }; // set the latest available API version here -exports.latestApiVersion = '1.2.10'; +exports.latestApiVersion = '1.2.11'; // exports the versions so it can be used by the new Swagger endpoint exports.version = version; From 9d39c9591adab5b6638e16ee54e7f87a9147e015 Mon Sep 17 00:00:00 2001 From: Cristo Date: Wed, 12 Nov 2014 19:46:50 +0100 Subject: [PATCH 4/8] update pad clients --- src/node/db/API.js | 170 +++++++++++++++++++++++---------------------- 1 file changed, 88 insertions(+), 82 deletions(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index 8ad6e2eb..b3d46ea1 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -583,102 +583,108 @@ exports.deletePad = function(padID, callback) {code:0, message:"ok", data:null} {code: 1, message:"padID does not exist", data: null} */ -exports.restoreRevision = function(padID, rev, callback) +exports.restoreRevision = function (padID, rev, callback) { - var Changeset = require("ep_etherpad-lite/static/js/Changeset"); - - //check if rev is a number - if(rev !== undefined && typeof rev != "number") - { - //try to parse the number - if(!isNaN(parseInt(rev))) - { - rev = parseInt(rev); - } - else - { - callback(new customError("rev is not a number", "apierror")); - return; - } - } + var Changeset = require("ep_etherpad-lite/static/js/Changeset"); + var padMessage = require("ep_etherpad-lite/node/handler/PadMessageHandler.js"); - //ensure this is not a negativ number - if(rev !== undefined && rev < 0) - { - callback(new customError("rev is a negativ number","apierror")); - return; - } + //check if rev is a number + if (rev !== undefined && typeof rev != "number") + { + //try to parse the number + if (!isNaN(parseInt(rev))) + { + rev = parseInt(rev); + } + else + { + callback(new customError("rev is not a number", "apierror")); + return; + } + } - //ensure this is not a float value - if(rev !== undefined && !is_int(rev)) - { - callback(new customError("rev is a float value","apierror")); - return; - } + //ensure this is not a negativ number + if (rev !== undefined && rev < 0) + { + callback(new customError("rev is a negativ number", "apierror")); + return; + } - //get the pad - getPadSafe(padID, true, function(err, pad) - { - if(ERR(err, callback)) return; + //ensure this is not a float value + if (rev !== undefined && !is_int(rev)) + { + callback(new customError("rev is a float value", "apierror")); + return; + } + + //get the pad + getPadSafe(padID, true, function (err, pad) + { + if (ERR(err, callback)) return; - //check if this is a valid revision - if(rev > pad.getHeadRevisionNumber()) - { - callback(new customError("rev is higher than the head revision of the pad","apierror")); - return; - } + //check if this is a valid revision + if (rev > pad.getHeadRevisionNumber()) + { + callback(new customError("rev is higher than the head revision of the pad", "apierror")); + return; + } - pad.getInternalRevisionAText(rev, function(err, atext) - { - if(ERR(err, callback)) return; + pad.getInternalRevisionAText(rev, function (err, atext) + { + if (ERR(err, callback)) return; - var oldText = pad.text(); - atext.text += "\n"; - function eachAttribRun(attribs, func) - { - var attribsIter = Changeset.opIterator(attribs); - var textIndex = 0; - var newTextStart = 0; - var newTextEnd = atext.text.length; - while (attribsIter.hasNext()) - { - var op = attribsIter.next(); - var nextIndex = textIndex + op.chars; - if (!(nextIndex <= newTextStart || textIndex >= newTextEnd)) - { - func(Math.max(newTextStart, textIndex), Math.min(newTextEnd, nextIndex), op.attribs); - } - textIndex = nextIndex; - } - } + var oldText = pad.text(); + atext.text += "\n"; + function eachAttribRun(attribs, func) + { + var attribsIter = Changeset.opIterator(attribs); + var textIndex = 0; + var newTextStart = 0; + var newTextEnd = atext.text.length; + while (attribsIter.hasNext()) + { + var op = attribsIter.next(); + var nextIndex = textIndex + op.chars; + if (!(nextIndex <= newTextStart || textIndex >= newTextEnd)) + { + func(Math.max(newTextStart, textIndex), Math.min(newTextEnd, nextIndex), op.attribs); + } + textIndex = nextIndex; + } + } - // create a new changeset with a helper builder object - var builder = Changeset.builder(oldText.length); + // create a new changeset with a helper builder object + var builder = Changeset.builder(oldText.length); - // assemble each line into the builder - eachAttribRun(atext.attribs, function(start, end, attribs) - { - builder.insert(atext.text.substring(start, end), attribs); - }); + // assemble each line into the builder + eachAttribRun(atext.attribs, function (start, end, attribs) + { + builder.insert(atext.text.substring(start, end), attribs); + }); - var lastNewlinePos = oldText.lastIndexOf('\n'); - if (lastNewlinePos < 0) { - builder.remove(oldText.length-1,0); - } else { - builder.remove(lastNewlinePos, oldText.match(/\n/g).length-1); - builder.remove(oldText.length - lastNewlinePos-1,0); - } + var lastNewlinePos = oldText.lastIndexOf('\n'); + if (lastNewlinePos < 0) + { + builder.remove(oldText.length - 1, 0); + } else + { + builder.remove(lastNewlinePos, oldText.match(/\n/g).length - 1); + builder.remove(oldText.length - lastNewlinePos - 1, 0); + } - var changeset = builder.toString(); + var changeset = builder.toString(); - //append the changeset - pad.appendRevision(changeset); - // - callback(null, null); - }); + //append the changeset + pad.appendRevision(changeset); + // + padMessage.updatePadClients(pad, function () + { + }); + callback(null, null); + }); - }); + }); }; /** From 24ac082cae6ad8842d3028a14ec9ecb8bbd47b9a Mon Sep 17 00:00:00 2001 From: Cristo Date: Wed, 12 Nov 2014 19:49:08 +0100 Subject: [PATCH 5/8] Update API.js --- src/node/db/API.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index b3d46ea1..d933f99e 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -587,7 +587,6 @@ exports.restoreRevision = function (padID, rev, callback) { var Changeset = require("ep_etherpad-lite/static/js/Changeset"); var padMessage = require("ep_etherpad-lite/node/handler/PadMessageHandler.js"); - //check if rev is a number if (rev !== undefined && typeof rev != "number") { From f59238fe58ac1d1a28896642a86f8483a0d524a3 Mon Sep 17 00:00:00 2001 From: Cristo Date: Wed, 12 Nov 2014 19:50:43 +0100 Subject: [PATCH 6/8] Update API.js --- src/node/db/API.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index d933f99e..2ba99f6a 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -587,6 +587,7 @@ exports.restoreRevision = function (padID, rev, callback) { var Changeset = require("ep_etherpad-lite/static/js/Changeset"); var padMessage = require("ep_etherpad-lite/node/handler/PadMessageHandler.js"); + //check if rev is a number if (rev !== undefined && typeof rev != "number") { @@ -682,7 +683,6 @@ exports.restoreRevision = function (padID, rev, callback) }); callback(null, null); }); - }); }; From f7dd756642623ade815f417de7b7b2eb880e488c Mon Sep 17 00:00:00 2001 From: Cristo Date: Wed, 12 Nov 2014 19:53:56 +0100 Subject: [PATCH 7/8] Update API.js --- src/node/db/API.js | 173 +++++++++++++++++++++++---------------------- 1 file changed, 87 insertions(+), 86 deletions(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index 2ba99f6a..07d3703c 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -585,105 +585,106 @@ exports.deletePad = function(padID, callback) */ exports.restoreRevision = function (padID, rev, callback) { - var Changeset = require("ep_etherpad-lite/static/js/Changeset"); - var padMessage = require("ep_etherpad-lite/node/handler/PadMessageHandler.js"); + var Changeset = require("ep_etherpad-lite/static/js/Changeset"); + var padMessage = require("ep_etherpad-lite/node/handler/PadMessageHandler.js"); - //check if rev is a number - if (rev !== undefined && typeof rev != "number") - { - //try to parse the number - if (!isNaN(parseInt(rev))) - { - rev = parseInt(rev); - } - else - { - callback(new customError("rev is not a number", "apierror")); - return; - } - } + //check if rev is a number + if (rev !== undefined && typeof rev != "number") + { + //try to parse the number + if (!isNaN(parseInt(rev))) + { + rev = parseInt(rev); + } + else + { + callback(new customError("rev is not a number", "apierror")); + return; + } + } - //ensure this is not a negativ number - if (rev !== undefined && rev < 0) - { - callback(new customError("rev is a negativ number", "apierror")); - return; - } + //ensure this is not a negativ number + if (rev !== undefined && rev < 0) + { + callback(new customError("rev is a negativ number", "apierror")); + return; + } - //ensure this is not a float value - if (rev !== undefined && !is_int(rev)) - { - callback(new customError("rev is a float value", "apierror")); - return; - } + //ensure this is not a float value + if (rev !== undefined && !is_int(rev)) + { + callback(new customError("rev is a float value", "apierror")); + return; + } - //get the pad - getPadSafe(padID, true, function (err, pad) - { - if (ERR(err, callback)) return; + //get the pad + getPadSafe(padID, true, function (err, pad) + { + if (ERR(err, callback)) return; - //check if this is a valid revision - if (rev > pad.getHeadRevisionNumber()) - { - callback(new customError("rev is higher than the head revision of the pad", "apierror")); - return; - } + //check if this is a valid revision + if (rev > pad.getHeadRevisionNumber()) + { + callback(new customError("rev is higher than the head revision of the pad", "apierror")); + return; + } - pad.getInternalRevisionAText(rev, function (err, atext) - { - if (ERR(err, callback)) return; + pad.getInternalRevisionAText(rev, function (err, atext) + { + if (ERR(err, callback)) return; - var oldText = pad.text(); - atext.text += "\n"; - function eachAttribRun(attribs, func) - { - var attribsIter = Changeset.opIterator(attribs); - var textIndex = 0; - var newTextStart = 0; - var newTextEnd = atext.text.length; - while (attribsIter.hasNext()) - { - var op = attribsIter.next(); - var nextIndex = textIndex + op.chars; - if (!(nextIndex <= newTextStart || textIndex >= newTextEnd)) - { - func(Math.max(newTextStart, textIndex), Math.min(newTextEnd, nextIndex), op.attribs); - } - textIndex = nextIndex; - } - } + var oldText = pad.text(); + atext.text += "\n"; + function eachAttribRun(attribs, func) + { + var attribsIter = Changeset.opIterator(attribs); + var textIndex = 0; + var newTextStart = 0; + var newTextEnd = atext.text.length; + while (attribsIter.hasNext()) + { + var op = attribsIter.next(); + var nextIndex = textIndex + op.chars; + if (!(nextIndex <= newTextStart || textIndex >= newTextEnd)) + { + func(Math.max(newTextStart, textIndex), Math.min(newTextEnd, nextIndex), op.attribs); + } + textIndex = nextIndex; + } + } - // create a new changeset with a helper builder object - var builder = Changeset.builder(oldText.length); + // create a new changeset with a helper builder object + var builder = Changeset.builder(oldText.length); - // assemble each line into the builder - eachAttribRun(atext.attribs, function (start, end, attribs) - { - builder.insert(atext.text.substring(start, end), attribs); - }); + // assemble each line into the builder + eachAttribRun(atext.attribs, function (start, end, attribs) + { + builder.insert(atext.text.substring(start, end), attribs); + }); - var lastNewlinePos = oldText.lastIndexOf('\n'); - if (lastNewlinePos < 0) - { - builder.remove(oldText.length - 1, 0); - } else - { - builder.remove(lastNewlinePos, oldText.match(/\n/g).length - 1); - builder.remove(oldText.length - lastNewlinePos - 1, 0); - } + var lastNewlinePos = oldText.lastIndexOf('\n'); + if (lastNewlinePos < 0) + { + builder.remove(oldText.length - 1, 0); + } else + { + builder.remove(lastNewlinePos, oldText.match(/\n/g).length - 1); + builder.remove(oldText.length - lastNewlinePos - 1, 0); + } - var changeset = builder.toString(); + var changeset = builder.toString(); - //append the changeset - pad.appendRevision(changeset); - // - padMessage.updatePadClients(pad, function () - { - }); - callback(null, null); - }); - }); + //append the changeset + pad.appendRevision(changeset); + // + padMessage.updatePadClients(pad, function () + { + }); + callback(null, null); + }); + + }); }; /** From 0253156dbb2e26a1a894a414c61ff8e521b3fece Mon Sep 17 00:00:00 2001 From: Cristo Date: Wed, 12 Nov 2014 19:55:37 +0100 Subject: [PATCH 8/8] Update APIHandler.js --- src/node/handler/APIHandler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/handler/APIHandler.js b/src/node/handler/APIHandler.js index 76af4aa1..9adc2418 100644 --- a/src/node/handler/APIHandler.js +++ b/src/node/handler/APIHandler.js @@ -345,7 +345,7 @@ var version = , "getChatHistory" : ["padID", "start", "end"] , "getChatHead" : ["padID"] } - , "1.2.11": +, "1.2.11": { "createGroup" : [] , "createGroupIfNotExistsFor" : ["groupMapper"] , "deleteGroup" : ["groupID"]