mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-04-22 00:16:15 -04:00
Merge pull request #2300 from cristo-rabani/patch-1
Added option to restore revisions #1791
This commit is contained in:
commit
a75f02cddf
2 changed files with 158 additions and 1 deletions
|
@ -575,6 +575,117 @@ exports.deletePad = function(padID, callback)
|
||||||
pad.remove(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");
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//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);
|
||||||
|
//
|
||||||
|
padMessage.updatePadClients(pad, function ()
|
||||||
|
{
|
||||||
|
});
|
||||||
|
callback(null, null);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
copyPad(sourceID, destinationID[, force=false]) copies a pad. If force is true,
|
copyPad(sourceID, destinationID[, force=false]) copies a pad. If force is true,
|
||||||
|
|
|
@ -345,10 +345,56 @@ var version =
|
||||||
, "getChatHistory" : ["padID", "start", "end"]
|
, "getChatHistory" : ["padID", "start", "end"]
|
||||||
, "getChatHead" : ["padID"]
|
, "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
|
// 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 the versions so it can be used by the new Swagger endpoint
|
||||||
exports.version = version;
|
exports.version = version;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue