From 29d8bb7716213dbb1e0fa2bcb53a20469cab02e0 Mon Sep 17 00:00:00 2001 From: s1341 Date: Sun, 17 Nov 2013 16:46:43 +0000 Subject: [PATCH 1/3] add pad copy/move API functions --- src/node/db/API.js | 42 +++++++++++- src/node/db/Pad.js | 114 +++++++++++++++++++++++++++++++++ src/node/handler/APIHandler.js | 2 + 3 files changed, 156 insertions(+), 2 deletions(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index 5bb83f029..39b37959c 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -440,8 +440,8 @@ exports.getChatHistory = function(padID, start, end, callback) // fall back to getting the whole chat-history if a parameter is missing if(!start || !end) { - start = 0; - end = pad.chatHead; + start = 0; + end = pad.chatHead; } if(start >= chatHead && chatHead > 0) @@ -552,6 +552,44 @@ exports.deletePad = function(padID, callback) }); } +/** +copyPad(padID, newID) copies a pad + +Example returns: + +{code: 0, message:"ok", data: null} +{code: 1, message:"padID does not exist", data: null} +*/ +exports.copyPad = function(padID, newID, callback) +{ + getPadSafe(padID, true, function(err, pad) + { + if(ERR(err, callback)) return; + + pad.copy(newID, callback); + }); +} + +/** +movePad(padID, newID) moves a pad + +Example returns: + +{code: 0, message:"ok", data: null} +{code: 1, message:"padID does not exist", data: null} +*/ +exports.movePad = function(padID, newID, callback) +{ + getPadSafe(padID, true, function(err, pad) + { + if(ERR(err, callback)) return; + + pad.copy(newID, function(err) { + if(ERR(err, callback)) return; + pad.remove(callback); + }); + }); +} /** getReadOnlyLink(padID) returns the read only link of a pad diff --git a/src/node/db/Pad.js b/src/node/db/Pad.js index 4701e82a3..7c2f63aa4 100644 --- a/src/node/db/Pad.js +++ b/src/node/db/Pad.js @@ -13,6 +13,8 @@ var settings = require('../utils/Settings'); var authorManager = require("./AuthorManager"); var padManager = require("./PadManager"); var padMessageHandler = require("../handler/PadMessageHandler"); +var groupManager = require("./GroupManager"); +var customError = require("../utils/customError"); var readOnlyManager = require("./ReadOnlyManager"); var crypto = require("crypto"); var randomString = require("../utils/randomstring"); @@ -404,6 +406,118 @@ Pad.prototype.init = function init(text, callback) { }); }; +Pad.prototype.copy = function copy(newID, callback) { + var padID = this.id; + var _this = this; + + //kick everyone from this pad + // TODO: this presents a message on the client saying that the pad was 'deleted'. Fix this? + padMessageHandler.kickSessionsFromPad(padID); + + // flush the source pad: + _this.saveToDatabase(); + + async.series([ + // if it's a group pad, let's make sure the group exists. + function(callback) + { + if (newID.indexOf("$") != -1) + { + groupManager.doesGroupExist(newID.split("$")[0], function (err, exists) + { + if(ERR(err, callback)) return; + + //group does not exist + if(exists == false) + { + callback(new customError("groupID does not exist","apierror")); + } + //everything is fine, continue + else + { + callback(); + } + }); + } + callback(); + }, + // if the pad exists, we should abort. + function(callback) + { + padManager.doesPadExists(newID, function (err, exists) + { + if(ERR(err, callback)) return; + + if(exists == true) + { + callback(new customError("new padID already exists","apierror")); + } + //everything is fine, continue + else + { + db.get("pad:"+padID, function(err, pad) { + db.set("pad:"+newID, pad); + callback(); + }); + } + }); + }, + //delete all relations + function(callback) + { + async.parallel([ + //copy all chat messages + function(callback) + { + var chatHead = _this.chatHead; + + for(var i=0;i<=chatHead;i++) + { + db.get("pad:"+padID+":chat:"+i, function (err, chat) { + db.set("pad:"+newID+":chat:"+i, chat); + }); + } + + callback(); + }, + //copy all revisions + function(callback) + { + var revHead = _this.head; + + for(var i=0;i<=revHead;i++) + { + db.get("pad:"+padID+":revs:"+i, function (err, rev) { + if (ERR(err, callback)) return; + db.set("pad:"+newID+":revs:"+i, rev); + }); + } + + callback(); + }, + //add the new pad to all authors who contributed to the old one + function(callback) + { + var authorIDs = _this.getAllAuthors(); + + authorIDs.forEach(function (authorID) + { + authorManager.addPad(authorID, newID); + }); + + callback(); + }, + // parallel + ], callback); + }, + // series + ], function(err) + { + if(ERR(err, callback)) return; + callback(null, {padID: newID}); + }); +}; + Pad.prototype.remove = function remove(callback) { var padID = this.id; var _this = this; diff --git a/src/node/handler/APIHandler.js b/src/node/handler/APIHandler.js index cba13f9b7..7df0864da 100644 --- a/src/node/handler/APIHandler.js +++ b/src/node/handler/APIHandler.js @@ -240,6 +240,8 @@ var version = , "getRevisionChangeset" : ["padID", "rev"] , "getLastEdited" : ["padID"] , "deletePad" : ["padID"] + , "copyPad" : ["padID", "newID"] + , "movePad" : ["padID", "newID"] , "getReadOnlyID" : ["padID"] , "setPublicStatus" : ["padID", "publicStatus"] , "getPublicStatus" : ["padID"] From 93fcab046181b8224649dbc4b0184c2c29f94e5b Mon Sep 17 00:00:00 2001 From: s1341 Date: Sun, 17 Nov 2013 21:01:02 +0200 Subject: [PATCH 2/3] change parameter names --- src/node/db/API.js | 8 ++++---- src/node/db/Pad.js | 28 ++++++++++++++-------------- src/node/handler/APIHandler.js | 4 ++-- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index 39b37959c..e18add8ed 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -553,20 +553,20 @@ exports.deletePad = function(padID, callback) } /** -copyPad(padID, newID) copies a pad +copyPad(sourceID, destinationID) copies a pad Example returns: {code: 0, message:"ok", data: null} {code: 1, message:"padID does not exist", data: null} */ -exports.copyPad = function(padID, newID, callback) +exports.copyPad = function(sourceID, destinationID, callback) { - getPadSafe(padID, true, function(err, pad) + getPadSafe(sourceID, true, function(err, pad) { if(ERR(err, callback)) return; - pad.copy(newID, callback); + pad.copy(destinationID, callback); }); } diff --git a/src/node/db/Pad.js b/src/node/db/Pad.js index 7c2f63aa4..fc16c2ee5 100644 --- a/src/node/db/Pad.js +++ b/src/node/db/Pad.js @@ -406,13 +406,13 @@ Pad.prototype.init = function init(text, callback) { }); }; -Pad.prototype.copy = function copy(newID, callback) { - var padID = this.id; +Pad.prototype.copy = function copy(destinationID, callback) { + var sourceID = this.id; var _this = this; //kick everyone from this pad // TODO: this presents a message on the client saying that the pad was 'deleted'. Fix this? - padMessageHandler.kickSessionsFromPad(padID); + padMessageHandler.kickSessionsFromPad(sourceID); // flush the source pad: _this.saveToDatabase(); @@ -421,9 +421,9 @@ Pad.prototype.copy = function copy(newID, callback) { // if it's a group pad, let's make sure the group exists. function(callback) { - if (newID.indexOf("$") != -1) + if (destinationID.indexOf("$") != -1) { - groupManager.doesGroupExist(newID.split("$")[0], function (err, exists) + groupManager.doesGroupExist(destinationID.split("$")[0], function (err, exists) { if(ERR(err, callback)) return; @@ -444,7 +444,7 @@ Pad.prototype.copy = function copy(newID, callback) { // if the pad exists, we should abort. function(callback) { - padManager.doesPadExists(newID, function (err, exists) + padManager.doesPadExists(destinationID, function (err, exists) { if(ERR(err, callback)) return; @@ -455,8 +455,8 @@ Pad.prototype.copy = function copy(newID, callback) { //everything is fine, continue else { - db.get("pad:"+padID, function(err, pad) { - db.set("pad:"+newID, pad); + db.get("pad:"+sourceID, function(err, pad) { + db.set("pad:"+destinationID, pad); callback(); }); } @@ -473,8 +473,8 @@ Pad.prototype.copy = function copy(newID, callback) { for(var i=0;i<=chatHead;i++) { - db.get("pad:"+padID+":chat:"+i, function (err, chat) { - db.set("pad:"+newID+":chat:"+i, chat); + db.get("pad:"+sourceID+":chat:"+i, function (err, chat) { + db.set("pad:"+destinationID+":chat:"+i, chat); }); } @@ -487,9 +487,9 @@ Pad.prototype.copy = function copy(newID, callback) { for(var i=0;i<=revHead;i++) { - db.get("pad:"+padID+":revs:"+i, function (err, rev) { + db.get("pad:"+sourceID+":revs:"+i, function (err, rev) { if (ERR(err, callback)) return; - db.set("pad:"+newID+":revs:"+i, rev); + db.set("pad:"+destinationID+":revs:"+i, rev); }); } @@ -502,7 +502,7 @@ Pad.prototype.copy = function copy(newID, callback) { authorIDs.forEach(function (authorID) { - authorManager.addPad(authorID, newID); + authorManager.addPad(authorID, destinationID); }); callback(); @@ -514,7 +514,7 @@ Pad.prototype.copy = function copy(newID, callback) { ], function(err) { if(ERR(err, callback)) return; - callback(null, {padID: newID}); + callback(null, {padID: destinationID}); }); }; diff --git a/src/node/handler/APIHandler.js b/src/node/handler/APIHandler.js index 7df0864da..72561ea8a 100644 --- a/src/node/handler/APIHandler.js +++ b/src/node/handler/APIHandler.js @@ -240,8 +240,8 @@ var version = , "getRevisionChangeset" : ["padID", "rev"] , "getLastEdited" : ["padID"] , "deletePad" : ["padID"] - , "copyPad" : ["padID", "newID"] - , "movePad" : ["padID", "newID"] + , "copyPad" : ["sourceID", "destinationID"] + , "movePad" : ["sourceID", "destinationID"] , "getReadOnlyID" : ["padID"] , "setPublicStatus" : ["padID", "publicStatus"] , "getPublicStatus" : ["padID"] From 52a99eb9e52f096d3fbcdf377112720424dce1d3 Mon Sep 17 00:00:00 2001 From: s1341 Date: Mon, 18 Nov 2013 08:25:46 +0200 Subject: [PATCH 3/3] fix bugs, add force option to overwrite destination --- src/node/db/API.js | 20 +++++++----- src/node/db/Pad.js | 60 ++++++++++++++++++++++++++-------- src/node/handler/APIHandler.js | 4 +-- 3 files changed, 60 insertions(+), 24 deletions(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index e18add8ed..e48c14015 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -553,38 +553,40 @@ exports.deletePad = function(padID, callback) } /** -copyPad(sourceID, destinationID) copies a pad +copyPad(sourceID, destinationID[, force=false]) copies a pad. If force is true, + the destination will be overwritten if it exists. Example returns: -{code: 0, message:"ok", data: null} +{code: 0, message:"ok", data: {padID: destinationID}} {code: 1, message:"padID does not exist", data: null} */ -exports.copyPad = function(sourceID, destinationID, callback) +exports.copyPad = function(sourceID, destinationID, force, callback) { getPadSafe(sourceID, true, function(err, pad) { if(ERR(err, callback)) return; - pad.copy(destinationID, callback); + pad.copy(destinationID, force, callback); }); } /** -movePad(padID, newID) moves a pad +movePad(sourceID, destinationID[, force=false]) moves a pad. If force is true, + the destination will be overwritten if it exists. Example returns: -{code: 0, message:"ok", data: null} +{code: 0, message:"ok", data: {padID: destinationID}} {code: 1, message:"padID does not exist", data: null} */ -exports.movePad = function(padID, newID, callback) +exports.movePad = function(sourceID, destinationID, force, callback) { - getPadSafe(padID, true, function(err, pad) + getPadSafe(sourceID, true, function(err, pad) { if(ERR(err, callback)) return; - pad.copy(newID, function(err) { + pad.copy(destinationID, force, function(err) { if(ERR(err, callback)) return; pad.remove(callback); }); diff --git a/src/node/db/Pad.js b/src/node/db/Pad.js index fc16c2ee5..b6dee897f 100644 --- a/src/node/db/Pad.js +++ b/src/node/db/Pad.js @@ -406,10 +406,20 @@ Pad.prototype.init = function init(text, callback) { }); }; -Pad.prototype.copy = function copy(destinationID, callback) { +Pad.prototype.copy = function copy(destinationID, force, callback) { var sourceID = this.id; var _this = this; + // make force optional + if (typeof force == "function") { + callback = force; + force = false; + } + else if (force == undefined || force.toLowerCase() != "true") { + force = false; + } + else force = true; + //kick everyone from this pad // TODO: this presents a message on the client saying that the pad was 'deleted'. Fix this? padMessageHandler.kickSessionsFromPad(sourceID); @@ -430,7 +440,8 @@ Pad.prototype.copy = function copy(destinationID, callback) { //group does not exist if(exists == false) { - callback(new customError("groupID does not exist","apierror")); + callback(new customError("groupID does not exist for destinationID","apierror")); + return; } //everything is fine, continue else @@ -439,30 +450,49 @@ Pad.prototype.copy = function copy(destinationID, callback) { } }); } - callback(); + else + callback(); }, - // if the pad exists, we should abort. + // 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; if(exists == true) { - callback(new customError("new padID already exists","apierror")); + if (!force) + { + console.log("erroring out without force"); + callback(new customError("destinationID already exists","apierror")); + console.log("erroring out without force - after"); + return; + } + else // exists and forcing + { + padManager.getPad(destinationID, function(err, pad) { + if (ERR(err, callback)) return; + pad.remove(callback); + }); + } } - //everything is fine, continue - else + else { - db.get("pad:"+sourceID, function(err, pad) { - db.set("pad:"+destinationID, pad); - callback(); - }); + callback(); } }); }, - //delete all relations + // copy the 'pad' entry + function(callback) + { + db.get("pad:"+sourceID, function(err, pad) { + db.set("pad:"+destinationID, pad); + }); + callback(); + }, + //copy all relations function(callback) { async.parallel([ @@ -474,6 +504,7 @@ Pad.prototype.copy = function copy(destinationID, callback) { for(var i=0;i<=chatHead;i++) { db.get("pad:"+sourceID+":chat:"+i, function (err, chat) { + if (ERR(err, callback)) return; db.set("pad:"+destinationID+":chat:"+i, chat); }); } @@ -484,10 +515,12 @@ Pad.prototype.copy = function copy(destinationID, 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); }); @@ -502,6 +535,7 @@ Pad.prototype.copy = function copy(destinationID, callback) { authorIDs.forEach(function (authorID) { + console.log("authors"); authorManager.addPad(authorID, destinationID); }); diff --git a/src/node/handler/APIHandler.js b/src/node/handler/APIHandler.js index 72561ea8a..f2746b067 100644 --- a/src/node/handler/APIHandler.js +++ b/src/node/handler/APIHandler.js @@ -240,8 +240,8 @@ var version = , "getRevisionChangeset" : ["padID", "rev"] , "getLastEdited" : ["padID"] , "deletePad" : ["padID"] - , "copyPad" : ["sourceID", "destinationID"] - , "movePad" : ["sourceID", "destinationID"] + , "copyPad" : ["sourceID", "destinationID", "force"] + , "movePad" : ["sourceID", "destinationID", "force"] , "getReadOnlyID" : ["padID"] , "setPublicStatus" : ["padID", "publicStatus"] , "getPublicStatus" : ["padID"]