summaryrefslogtreecommitdiff
path: root/src/node/db
diff options
context:
space:
mode:
authorStefan <mu.stefan@googlemail.com>2015-04-11 12:10:37 +0200
committerStefan <mu.stefan@googlemail.com>2015-04-11 12:10:37 +0200
commitaa0d14c7d71da3d3c4f123e1577848c026bccf0b (patch)
tree19cc760c2aa04ab57eb23e500dc442c0a901a7d1 /src/node/db
parent573a912e4f1b481fca8f3c8146972e78f76278e2 (diff)
parentcc34f4e325830f798321b8152095c4dccd6b465f (diff)
downloadetherpad-lite-aa0d14c7d71da3d3c4f123e1577848c026bccf0b.zip
Merge branch 'master' of git://github.com/ether/etherpad-lite into create_pad_special_characters
Diffstat (limited to 'src/node/db')
-rw-r--r--src/node/db/API.js274
-rw-r--r--src/node/db/AuthorManager.js1
-rw-r--r--src/node/db/Pad.js33
-rw-r--r--src/node/db/SecurityManager.js1
-rw-r--r--src/node/db/SessionManager.js10
-rw-r--r--src/node/db/SessionStore.js2
6 files changed, 295 insertions, 26 deletions
diff --git a/src/node/db/API.js b/src/node/db/API.js
index 79f5fbeb..97d5162d 100644
--- a/src/node/db/API.js
+++ b/src/node/db/API.js
@@ -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 */
/*****************/
@@ -513,6 +545,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
Example returns:
@@ -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,
diff --git a/src/node/db/AuthorManager.js b/src/node/db/AuthorManager.js
index 5ba608e9..e0f569ef 100644
--- a/src/node/db/AuthorManager.js
+++ b/src/node/db/AuthorManager.js
@@ -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;
diff --git a/src/node/db/Pad.js b/src/node/db/Pad.js
index 4670696a..53847600 100644
--- a/src/node/db/Pad.js
+++ b/src/node/db/Pad.js
@@ -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;
}
}
diff --git a/src/node/db/SecurityManager.js b/src/node/db/SecurityManager.js
index df3c3826..6fae57ff 100644
--- a/src/node/db/SecurityManager.js
+++ b/src/node/db/SecurityManager.js
@@ -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");
diff --git a/src/node/db/SessionManager.js b/src/node/db/SessionManager.js
index 71315adc..f8000e47 100644
--- a/src/node/db/SessionManager.js
+++ b/src/node/db/SessionManager.js
@@ -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();
});
diff --git a/src/node/db/SessionStore.js b/src/node/db/SessionStore.js
index 52a504f1..5c45ddb3 100644
--- a/src/node/db/SessionStore.js
+++ b/src/node/db/SessionStore.js
@@ -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");