mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-04-23 08:56:17 -04:00
Merge branch 'master' of git://github.com/ether/etherpad-lite into create_pad_special_characters
This commit is contained in:
commit
aa0d14c7d7
237 changed files with 6386 additions and 1927 deletions
|
@ -263,7 +263,7 @@ exports.getText = function(padID, rev, callback)
|
|||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
data = {text: atext.text};
|
||||
var data = {text: atext.text};
|
||||
|
||||
callback(null, data);
|
||||
})
|
||||
|
@ -368,7 +368,7 @@ exports.getHTML = function(padID, rev, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
html = "<!DOCTYPE HTML><html><body>" +html; // adds HTML head
|
||||
html += "</body></html>";
|
||||
data = {html: html};
|
||||
var data = {html: html};
|
||||
callback(null, data);
|
||||
});
|
||||
}
|
||||
|
@ -380,7 +380,7 @@ exports.getHTML = function(padID, rev, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
html = "<!DOCTYPE HTML><html><body>" +html; // adds HTML head
|
||||
html += "</body></html>";
|
||||
data = {html: html};
|
||||
var data = {html: html};
|
||||
callback(null, data);
|
||||
});
|
||||
}
|
||||
|
@ -410,11 +410,16 @@ exports.setHTML = function(padID, html, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
|
||||
// add a new changeset with the new html to the pad
|
||||
importHtml.setPadHTML(pad, cleanText(html), callback);
|
||||
|
||||
//update the clients on the pad
|
||||
padMessageHandler.updatePadClients(pad, callback);
|
||||
|
||||
importHtml.setPadHTML(pad, cleanText(html), function(e){
|
||||
if(e){
|
||||
callback(new customError("HTML is malformed","apierror"));
|
||||
return;
|
||||
}else{
|
||||
//update the clients on the pad
|
||||
padMessageHandler.updatePadClients(pad, callback);
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -427,8 +432,8 @@ getChatHistory(padId, start, end), returns a part of or the whole chat-history o
|
|||
|
||||
Example returns:
|
||||
|
||||
{"code":0,"message":"ok","data":{"messages":[{"text":"foo","userId":"a.foo","time":1359199533759,"userName":"test"},
|
||||
{"text":"bar","userId":"a.foo","time":1359199534622,"userName":"test"}]}}
|
||||
{"code":0,"message":"ok","data":{"messages":[{"text":"foo","authorID":"a.foo","time":1359199533759,"userName":"test"},
|
||||
{"text":"bar","authorID":"a.foo","time":1359199534622,"userName":"test"}]}}
|
||||
|
||||
{code: 1, message:"start is higher or equal to the current chatHead", data: null}
|
||||
|
||||
|
@ -489,6 +494,33 @@ exports.getChatHistory = function(padID, start, end, callback)
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
appendChatMessage(padID, text, authorID, time), creates a chat message for the pad id, time is a timestamp
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: null
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.appendChatMessage = function(padID, text, authorID, time, callback)
|
||||
{
|
||||
//text is required
|
||||
if(typeof text != "string")
|
||||
{
|
||||
callback(new customError("text is no string","apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
//get the pad
|
||||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
pad.appendChatMessage(text, authorID, parseInt(time));
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
/*****************/
|
||||
/**PAD FUNCTIONS */
|
||||
/*****************/
|
||||
|
@ -512,6 +544,117 @@ exports.getRevisionsCount = function(padID, callback)
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
getSavedRevisionsCount(padID) returns the number of saved revisions of this pad
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: {savedRevisions: 42}}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.getSavedRevisionsCount = function(padID, callback)
|
||||
{
|
||||
//get the pad
|
||||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
callback(null, {savedRevisions: pad.getSavedRevisionsNumber()});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
listSavedRevisions(padID) returns the list of saved revisions of this pad
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: {savedRevisions: [2, 42, 1337]}}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.listSavedRevisions = function(padID, callback)
|
||||
{
|
||||
//get the pad
|
||||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
callback(null, {savedRevisions: pad.getSavedRevisionsList()});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
saveRevision(padID) returns the list of saved revisions of this pad
|
||||
|
||||
Example returns:
|
||||
|
||||
{code: 0, message:"ok", data: null}
|
||||
{code: 1, message:"padID does not exist", data: null}
|
||||
*/
|
||||
exports.saveRevision = function(padID, rev, callback)
|
||||
{
|
||||
//check if rev is set
|
||||
if(typeof rev == "function")
|
||||
{
|
||||
callback = rev;
|
||||
rev = undefined;
|
||||
}
|
||||
|
||||
//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;
|
||||
|
||||
//the client asked for a special revision
|
||||
if(rev !== undefined)
|
||||
{
|
||||
//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;
|
||||
}
|
||||
} else {
|
||||
rev = pad.getHeadRevisionNumber();
|
||||
}
|
||||
|
||||
authorManager.createAuthor('API', function(err, author) {
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
pad.addSavedRevision(rev, author.authorID, 'Saved through API call');
|
||||
callback();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
getLastEdited(padID) returns the timestamp of the last revision of the pad
|
||||
|
||||
|
@ -584,6 +727,117 @@ 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");
|
||||
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,
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
var ERR = require("async-stacktrace");
|
||||
var db = require("./DB").db;
|
||||
var async = require("async");
|
||||
var customError = require("../utils/customError");
|
||||
var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString;
|
||||
|
||||
|
|
|
@ -54,6 +54,21 @@ Pad.prototype.getHeadRevisionNumber = function getHeadRevisionNumber() {
|
|||
return this.head;
|
||||
};
|
||||
|
||||
Pad.prototype.getSavedRevisionsNumber = function getSavedRevisionsNumber() {
|
||||
return this.savedRevisions.length;
|
||||
};
|
||||
|
||||
Pad.prototype.getSavedRevisionsList = function getSavedRevisionsList() {
|
||||
var savedRev = new Array();
|
||||
for(var rev in this.savedRevisions){
|
||||
savedRev.push(this.savedRevisions[rev].revNum);
|
||||
}
|
||||
savedRev.sort(function(a, b) {
|
||||
return a - b;
|
||||
});
|
||||
return savedRev;
|
||||
};
|
||||
|
||||
Pad.prototype.getPublicStatus = function getPublicStatus() {
|
||||
return this.publicStatus;
|
||||
};
|
||||
|
@ -135,7 +150,7 @@ Pad.prototype.getRevisionDate = function getRevisionDate(revNum, callback) {
|
|||
Pad.prototype.getAllAuthors = function getAllAuthors() {
|
||||
var authors = [];
|
||||
|
||||
for(key in this.pool.numToAttrib)
|
||||
for(var key in this.pool.numToAttrib)
|
||||
{
|
||||
if(this.pool.numToAttrib[key][0] == "author" && this.pool.numToAttrib[key][1] != "")
|
||||
{
|
||||
|
@ -461,7 +476,6 @@ Pad.prototype.copy = function copy(destinationID, force, callback) {
|
|||
// if the pad exists, we should abort, unless forced.
|
||||
function(callback)
|
||||
{
|
||||
console.log("destinationID", destinationID, force);
|
||||
padManager.doesPadExists(destinationID, function (err, exists)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
@ -470,9 +484,9 @@ Pad.prototype.copy = function copy(destinationID, force, callback) {
|
|||
{
|
||||
if (!force)
|
||||
{
|
||||
console.log("erroring out without force");
|
||||
console.error("erroring out without force");
|
||||
callback(new customError("destinationID already exists","apierror"));
|
||||
console.log("erroring out without force - after");
|
||||
console.error("erroring out without force - after");
|
||||
return;
|
||||
}
|
||||
else // exists and forcing
|
||||
|
@ -521,12 +535,9 @@ Pad.prototype.copy = function copy(destinationID, force, callback) {
|
|||
function(callback)
|
||||
{
|
||||
var revHead = _this.head;
|
||||
//console.log(revHead);
|
||||
for(var i=0;i<=revHead;i++)
|
||||
{
|
||||
db.get("pad:"+sourceID+":revs:"+i, function (err, rev) {
|
||||
//console.log("HERE");
|
||||
|
||||
if (ERR(err, callback)) return;
|
||||
db.set("pad:"+destinationID+":revs:"+i, rev);
|
||||
});
|
||||
|
@ -538,10 +549,8 @@ Pad.prototype.copy = function copy(destinationID, force, callback) {
|
|||
function(callback)
|
||||
{
|
||||
var authorIDs = _this.getAllAuthors();
|
||||
|
||||
authorIDs.forEach(function (authorID)
|
||||
{
|
||||
console.log("authors");
|
||||
authorManager.addPad(authorID, destinationID);
|
||||
});
|
||||
|
||||
|
@ -555,7 +564,9 @@ Pad.prototype.copy = function copy(destinationID, force, callback) {
|
|||
if(destGroupID) db.setSub("group:" + destGroupID, ["pads", destinationID], 1);
|
||||
|
||||
// Initialize the new pad (will update the listAllPads cache)
|
||||
padManager.getPad(destinationID, null, callback)
|
||||
setTimeout(function(){
|
||||
padManager.getPad(destinationID, null, callback) // this runs too early.
|
||||
},10);
|
||||
}
|
||||
// series
|
||||
], function(err)
|
||||
|
@ -690,7 +701,7 @@ Pad.prototype.isPasswordProtected = function isPasswordProtected() {
|
|||
Pad.prototype.addSavedRevision = function addSavedRevision(revNum, savedById, label) {
|
||||
//if this revision is already saved, return silently
|
||||
for(var i in this.savedRevisions){
|
||||
if(this.savedRevisions.revNum === revNum){
|
||||
if(this.savedRevisions[i] && this.savedRevisions[i].revNum === revNum){
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
|
||||
|
||||
var ERR = require("async-stacktrace");
|
||||
var db = require("./DB").db;
|
||||
var async = require("async");
|
||||
var authorManager = require("./AuthorManager");
|
||||
var padManager = require("./PadManager");
|
||||
|
|
|
@ -351,7 +351,15 @@ function listSessionsWithDBKey (dbkey, callback)
|
|||
{
|
||||
exports.getSessionInfo(sessionID, function(err, sessionInfo)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
if (err == "apierror: sessionID does not exist")
|
||||
{
|
||||
console.warn("Found bad session " + sessionID + " in " + dbkey + ".");
|
||||
}
|
||||
else if(ERR(err, callback))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
sessions[sessionID] = sessionInfo;
|
||||
callback();
|
||||
});
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
*/
|
||||
|
||||
var Store = require('ep_etherpad-lite/node_modules/connect/lib/middleware/session/store'),
|
||||
utils = require('ep_etherpad-lite/node_modules/connect/lib/utils'),
|
||||
Session = require('ep_etherpad-lite/node_modules/connect/lib/middleware/session/session'),
|
||||
db = require('ep_etherpad-lite/node/db/DB').db,
|
||||
log4js = require('ep_etherpad-lite/node_modules/log4js'),
|
||||
messageLogger = log4js.getLogger("SessionStore");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue