db/Pad.js: convert to promises/async
Also updated some small chunks of dependent code that couldn't be converted until this one had been done.pull/3559/head
parent
ebb8a64e3c
commit
6d1b6b2796
|
@ -144,12 +144,11 @@ exports.getAuthor = function(author)
|
||||||
/**
|
/**
|
||||||
* Returns the color Id of the author
|
* Returns the color Id of the author
|
||||||
* @param {String} author The id of the author
|
* @param {String} author The id of the author
|
||||||
* @param {Function} callback callback(err, colorId)
|
|
||||||
*/
|
*/
|
||||||
exports.getAuthorColorId = thenify(function(author, callback)
|
exports.getAuthorColorId = function(author)
|
||||||
{
|
{
|
||||||
db.db.getSub("globalAuthor:" + author, ["colorId"], callback);
|
return db.getSub("globalAuthor:" + author, ["colorId"]);
|
||||||
});
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the color Id of the author
|
* Sets the color Id of the author
|
||||||
|
@ -164,12 +163,11 @@ exports.setAuthorColorId = function(author, colorId)
|
||||||
/**
|
/**
|
||||||
* Returns the name of the author
|
* Returns the name of the author
|
||||||
* @param {String} author The id of the author
|
* @param {String} author The id of the author
|
||||||
* @param {Function} callback callback(err, name)
|
|
||||||
*/
|
*/
|
||||||
exports.getAuthorName = thenify(function(author, callback)
|
exports.getAuthorName = function(author)
|
||||||
{
|
{
|
||||||
db.db.getSub("globalAuthor:" + author, ["name"], callback);
|
return db.getSub("globalAuthor:" + author, ["name"]);
|
||||||
});
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the name of the author
|
* Sets the name of the author
|
||||||
|
|
|
@ -18,13 +18,11 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var ERR = require("async-stacktrace");
|
|
||||||
var customError = require("../utils/customError");
|
var customError = require("../utils/customError");
|
||||||
var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString;
|
var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString;
|
||||||
var db = require("./DB");
|
var db = require("./DB");
|
||||||
var padManager = require("./PadManager");
|
var padManager = require("./PadManager");
|
||||||
var sessionManager = require("./SessionManager");
|
var sessionManager = require("./SessionManager");
|
||||||
const thenify = require("thenify").withCallback;
|
|
||||||
|
|
||||||
exports.listAllGroups = async function()
|
exports.listAllGroups = async function()
|
||||||
{
|
{
|
||||||
|
@ -85,15 +83,13 @@ exports.deleteGroup = async function(groupID)
|
||||||
await db.set("groups", newGroups);
|
await db.set("groups", newGroups);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @TODO: this is the only function still called with a callback
|
exports.doesGroupExist = async function(groupID)
|
||||||
exports.doesGroupExist = thenify(function(groupID, callback)
|
|
||||||
{
|
{
|
||||||
// try to get the group entry
|
// try to get the group entry
|
||||||
db.db.get("group:" + groupID, function (err, group) {
|
let group = await db.get("group:" + groupID);
|
||||||
if (ERR(err, callback)) return;
|
|
||||||
callback(null, group != null);
|
return (group != null);
|
||||||
});
|
}
|
||||||
});
|
|
||||||
|
|
||||||
exports.createGroup = async function()
|
exports.createGroup = async function()
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,11 +3,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
var ERR = require("async-stacktrace");
|
|
||||||
var Changeset = require("ep_etherpad-lite/static/js/Changeset");
|
var Changeset = require("ep_etherpad-lite/static/js/Changeset");
|
||||||
var AttributePool = require("ep_etherpad-lite/static/js/AttributePool");
|
var AttributePool = require("ep_etherpad-lite/static/js/AttributePool");
|
||||||
var db = require("./DB");
|
var db = require("./DB");
|
||||||
var async = require("async");
|
|
||||||
var settings = require('../utils/Settings');
|
var settings = require('../utils/Settings');
|
||||||
var authorManager = require("./AuthorManager");
|
var authorManager = require("./AuthorManager");
|
||||||
var padManager = require("./PadManager");
|
var padManager = require("./PadManager");
|
||||||
|
@ -18,8 +16,6 @@ var readOnlyManager = require("./ReadOnlyManager");
|
||||||
var crypto = require("crypto");
|
var crypto = require("crypto");
|
||||||
var randomString = require("../utils/randomstring");
|
var randomString = require("../utils/randomstring");
|
||||||
var hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks');
|
var hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks');
|
||||||
const thenify = require("thenify").withCallback;
|
|
||||||
const nodeify = require("nodeify");
|
|
||||||
|
|
||||||
// serialization/deserialization attributes
|
// serialization/deserialization attributes
|
||||||
var attributeBlackList = ["id"];
|
var attributeBlackList = ["id"];
|
||||||
|
@ -34,7 +30,7 @@ exports.cleanText = function (txt) {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
var Pad = function Pad(id) {
|
let Pad = function Pad(id) {
|
||||||
this.atext = Changeset.makeAText("\n");
|
this.atext = Changeset.makeAText("\n");
|
||||||
this.pool = new AttributePool();
|
this.pool = new AttributePool();
|
||||||
this.head = -1;
|
this.head = -1;
|
||||||
|
@ -129,7 +125,7 @@ Pad.prototype.saveToDatabase = function saveToDatabase() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
db.db.set("pad:" + this.id, dbObject);
|
db.set("pad:" + this.id, dbObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get time of last edit (changeset application)
|
// get time of last edit (changeset application)
|
||||||
|
@ -138,17 +134,17 @@ Pad.prototype.getLastEdit = function getLastEdit() {
|
||||||
return db.getSub("pad:" + this.id + ":revs:" + revNum, ["meta", "timestamp"]);
|
return db.getSub("pad:" + this.id + ":revs:" + revNum, ["meta", "timestamp"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Pad.prototype.getRevisionChangeset = thenify(function getRevisionChangeset(revNum, callback) {
|
Pad.prototype.getRevisionChangeset = function getRevisionChangeset(revNum) {
|
||||||
db.db.getSub("pad:" + this.id + ":revs:" + revNum, ["changeset"], callback);
|
return db.getSub("pad:" + this.id + ":revs:" + revNum, ["changeset"]);
|
||||||
});
|
}
|
||||||
|
|
||||||
Pad.prototype.getRevisionAuthor = thenify(function getRevisionAuthor(revNum, callback) {
|
Pad.prototype.getRevisionAuthor = function getRevisionAuthor(revNum) {
|
||||||
db.db.getSub("pad:" + this.id + ":revs:" + revNum, ["meta", "author"], callback);
|
return db.getSub("pad:" + this.id + ":revs:" + revNum, ["meta", "author"]);
|
||||||
});
|
}
|
||||||
|
|
||||||
Pad.prototype.getRevisionDate = thenify(function getRevisionDate(revNum, callback) {
|
Pad.prototype.getRevisionDate = function getRevisionDate(revNum) {
|
||||||
db.db.getSub("pad:" + this.id + ":revs:" + revNum, ["meta", "timestamp"], callback);
|
return db.getSub("pad:" + this.id + ":revs:" + revNum, ["meta", "timestamp"]);
|
||||||
});
|
}
|
||||||
|
|
||||||
Pad.prototype.getAllAuthors = function getAllAuthors() {
|
Pad.prototype.getAllAuthors = function getAllAuthors() {
|
||||||
var authors = [];
|
var authors = [];
|
||||||
|
@ -162,101 +158,57 @@ Pad.prototype.getAllAuthors = function getAllAuthors() {
|
||||||
return authors;
|
return authors;
|
||||||
};
|
};
|
||||||
|
|
||||||
Pad.prototype.getInternalRevisionAText = thenify(function getInternalRevisionAText(targetRev, callback) {
|
Pad.prototype.getInternalRevisionAText = async function getInternalRevisionAText(targetRev) {
|
||||||
var _this = this;
|
let keyRev = this.getKeyRevisionNumber(targetRev);
|
||||||
|
|
||||||
var keyRev = this.getKeyRevisionNumber(targetRev);
|
|
||||||
var atext;
|
|
||||||
var changesets = [];
|
|
||||||
|
|
||||||
// find out which changesets are needed
|
// find out which changesets are needed
|
||||||
var neededChangesets = [];
|
let neededChangesets = [];
|
||||||
var curRev = keyRev;
|
for (let curRev = keyRev; curRev < targetRev; ) {
|
||||||
while (curRev < targetRev) {
|
neededChangesets.push(++curRev);
|
||||||
curRev++;
|
|
||||||
neededChangesets.push(curRev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async.series([
|
// get all needed data out of the database
|
||||||
// get all needed data out of the database
|
|
||||||
function(callback) {
|
|
||||||
async.parallel([
|
|
||||||
// get the atext of the key revision
|
|
||||||
function (callback) {
|
|
||||||
db.db.getSub("pad:" + _this.id + ":revs:" + keyRev, ["meta", "atext"], function(err, _atext) {
|
|
||||||
if (ERR(err, callback)) return;
|
|
||||||
try {
|
|
||||||
atext = Changeset.cloneAText(_atext);
|
|
||||||
} catch (e) {
|
|
||||||
return callback(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
callback();
|
// get the atext of the key revision
|
||||||
});
|
let _atext = await db.getSub("pad:" + this.id + ":revs:" + keyRev, ["meta", "atext"]);
|
||||||
},
|
let atext = Changeset.cloneAText(_atext);
|
||||||
|
|
||||||
// get all needed changesets
|
// get all needed changesets
|
||||||
function (callback) {
|
let changesets = [];
|
||||||
async.forEach(neededChangesets, function(item, callback) {
|
await Promise.all(neededChangesets.map(item => {
|
||||||
_this.getRevisionChangeset(item, function(err, changeset) {
|
return this.getRevisionChangeset(item).then(changeset => {
|
||||||
if (ERR(err, callback)) return;
|
changesets[item] = changeset;
|
||||||
changesets[item] = changeset;
|
});
|
||||||
callback();
|
}));
|
||||||
});
|
|
||||||
}, callback);
|
|
||||||
}
|
|
||||||
], callback);
|
|
||||||
},
|
|
||||||
|
|
||||||
// apply all changesets to the key changeset
|
// apply all changesets to the key changeset
|
||||||
function(callback) {
|
let apool = this.apool();
|
||||||
var apool = _this.apool();
|
for (let curRev = keyRev; curRev < targetRev; ) {
|
||||||
var curRev = keyRev;
|
let cs = changesets[++curRev];
|
||||||
|
atext = Changeset.applyToAText(cs, atext, apool);
|
||||||
|
}
|
||||||
|
|
||||||
while (curRev < targetRev) {
|
return atext;
|
||||||
curRev++;
|
}
|
||||||
var cs = changesets[curRev];
|
|
||||||
try {
|
|
||||||
atext = Changeset.applyToAText(cs, atext, apool);
|
|
||||||
} catch(e) {
|
|
||||||
return callback(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
callback(null);
|
Pad.prototype.getRevision = function getRevisionChangeset(revNum) {
|
||||||
}
|
return db.get("pad:" + this.id + ":revs:" + revNum);
|
||||||
],
|
}
|
||||||
function(err) {
|
|
||||||
if (ERR(err, callback)) return;
|
|
||||||
callback(null, atext);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
Pad.prototype.getRevision = thenify(function getRevisionChangeset(revNum, callback) {
|
Pad.prototype.getAllAuthorColors = async function getAllAuthorColors() {
|
||||||
db.db.get("pad:" + this.id + ":revs:" + revNum, callback);
|
let authors = this.getAllAuthors();
|
||||||
});
|
let returnTable = {};
|
||||||
|
let colorPalette = authorManager.getColorPalette();
|
||||||
Pad.prototype.getAllAuthorColors = thenify(function getAllAuthorColors(callback) {
|
|
||||||
var authors = this.getAllAuthors();
|
|
||||||
var returnTable = {};
|
|
||||||
var colorPalette = authorManager.getColorPalette();
|
|
||||||
|
|
||||||
async.forEach(authors, function(author, callback) {
|
|
||||||
authorManager.getAuthorColorId(author, function(err, colorId) {
|
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
await Promise.all(authors.map(author => {
|
||||||
|
return authorManager.getAuthorColorId(author).then(colorId => {
|
||||||
// colorId might be a hex color or an number out of the palette
|
// colorId might be a hex color or an number out of the palette
|
||||||
returnTable[author] = colorPalette[colorId] || colorId;
|
returnTable[author] = colorPalette[colorId] || colorId;
|
||||||
|
|
||||||
callback();
|
|
||||||
});
|
});
|
||||||
},
|
}));
|
||||||
function(err) {
|
|
||||||
callback(err, returnTable);
|
return returnTable;
|
||||||
});
|
}
|
||||||
});
|
|
||||||
|
|
||||||
Pad.prototype.getValidRevisionRange = function getValidRevisionRange(startRev, endRev) {
|
Pad.prototype.getValidRevisionRange = function getValidRevisionRange(startRev, endRev) {
|
||||||
startRev = parseInt(startRev, 10);
|
startRev = parseInt(startRev, 10);
|
||||||
|
@ -327,83 +279,49 @@ Pad.prototype.appendChatMessage = function appendChatMessage(text, userId, time)
|
||||||
this.saveToDatabase();
|
this.saveToDatabase();
|
||||||
};
|
};
|
||||||
|
|
||||||
Pad.prototype.getChatMessage = thenify(function getChatMessage(entryNum, callback) {
|
Pad.prototype.getChatMessage = async function getChatMessage(entryNum) {
|
||||||
var _this = this;
|
// get the chat entry
|
||||||
var entry;
|
let entry = await db.get("pad:" + this.id + ":chat:" + entryNum);
|
||||||
|
|
||||||
async.series([
|
// get the authorName if the entry exists
|
||||||
// get the chat entry
|
if (entry != null) {
|
||||||
function(callback) {
|
entry.userName = await authorManager.getAuthorName(entry.userId);
|
||||||
db.db.get("pad:" + _this.id + ":chat:" + entryNum, function(err, _entry) {
|
|
||||||
if (ERR(err, callback)) return;
|
|
||||||
entry = _entry;
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// add the authorName
|
|
||||||
function(callback) {
|
|
||||||
// this chat message doesn't exist, return null
|
|
||||||
if (entry == null) {
|
|
||||||
callback();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the authorName
|
|
||||||
authorManager.getAuthorName(entry.userId, function(err, authorName) {
|
|
||||||
if (ERR(err, callback)) return;
|
|
||||||
entry.userName = authorName;
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
],
|
|
||||||
function(err) {
|
|
||||||
if (ERR(err, callback)) return;
|
|
||||||
callback(null, entry);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
Pad.prototype.getChatMessages = thenify(function getChatMessages(start, end, callback) {
|
|
||||||
// collect the numbers of chat entries and in which order we need them
|
|
||||||
var neededEntries = [];
|
|
||||||
var order = 0;
|
|
||||||
for (var i = start; i <= end; i++) {
|
|
||||||
neededEntries.push({ entryNum: i, order: order });
|
|
||||||
order++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var _this = this;
|
return entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
Pad.prototype.getChatMessages = async function getChatMessages(start, end) {
|
||||||
|
|
||||||
|
// collect the numbers of chat entries and in which order we need them
|
||||||
|
let neededEntries = [];
|
||||||
|
for (let order = 0, entryNum = start; entryNum <= end; ++order, ++entryNum) {
|
||||||
|
neededEntries.push({ entryNum, order });
|
||||||
|
}
|
||||||
|
|
||||||
// get all entries out of the database
|
// get all entries out of the database
|
||||||
var entries = [];
|
let entries = [];
|
||||||
async.forEach(neededEntries, function(entryObject, callback) {
|
await Promise.all(neededEntries.map(entryObject => {
|
||||||
_this.getChatMessage(entryObject.entryNum, function(err, entry) {
|
return this.getChatMessage(entryObject.entryNum).then(entry => {
|
||||||
if (ERR(err, callback)) return;
|
|
||||||
entries[entryObject.order] = entry;
|
entries[entryObject.order] = entry;
|
||||||
callback();
|
|
||||||
});
|
});
|
||||||
},
|
}));
|
||||||
function(err) {
|
|
||||||
if (ERR(err, callback)) return;
|
|
||||||
|
|
||||||
// sort out broken chat entries
|
// sort out broken chat entries
|
||||||
// it looks like in happened in the past that the chat head was
|
// it looks like in happened in the past that the chat head was
|
||||||
// incremented, but the chat message wasn't added
|
// incremented, but the chat message wasn't added
|
||||||
var cleanedEntries = [];
|
let cleanedEntries = entries.filter(entry => {
|
||||||
for (var i=0; i < entries.length; i++) {
|
let pass = (entry != null);
|
||||||
if (entries[i] != null) {
|
if (!pass) {
|
||||||
cleanedEntries.push(entries[i]);
|
console.warn("WARNING: Found broken chat entry in pad " + this.id);
|
||||||
} else {
|
|
||||||
console.warn("WARNING: Found broken chat entry in pad " + _this.id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return pass;
|
||||||
callback(null, cleanedEntries);
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
Pad.prototype.init = thenify(function init(text, callback) {
|
return cleanedEntries;
|
||||||
var _this = this;
|
}
|
||||||
|
|
||||||
|
Pad.prototype.init = async function init(text) {
|
||||||
|
|
||||||
// replace text with default text if text isn't set
|
// replace text with default text if text isn't set
|
||||||
if (text == null) {
|
if (text == null) {
|
||||||
|
@ -411,35 +329,31 @@ Pad.prototype.init = thenify(function init(text, callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to load the pad
|
// try to load the pad
|
||||||
db.db.get("pad:" + this.id, function(err, value) {
|
let value = await db.get("pad:" + this.id);
|
||||||
if (ERR(err, callback)) return;
|
|
||||||
|
|
||||||
// if this pad exists, load it
|
// if this pad exists, load it
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
// copy all attr. To a transfrom via fromJsonable if necessary
|
// copy all attr. To a transfrom via fromJsonable if necassary
|
||||||
for (var attr in value) {
|
for (var attr in value) {
|
||||||
if (jsonableList.indexOf(attr) !== -1) {
|
if (jsonableList.indexOf(attr) !== -1) {
|
||||||
_this[attr] = _this[attr].fromJsonable(value[attr]);
|
this[attr] = this[attr].fromJsonable(value[attr]);
|
||||||
} else {
|
} else {
|
||||||
_this[attr] = value[attr];
|
this[attr] = value[attr];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// this pad doesn't exist, so create it
|
|
||||||
var firstChangeset = Changeset.makeSplice("\n", 0, 0, exports.cleanText(text));
|
|
||||||
|
|
||||||
_this.appendRevision(firstChangeset, '');
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// this pad doesn't exist, so create it
|
||||||
|
let firstChangeset = Changeset.makeSplice("\n", 0, 0, exports.cleanText(text));
|
||||||
|
|
||||||
hooks.callAll("padLoad", { 'pad': _this });
|
this.appendRevision(firstChangeset, '');
|
||||||
callback(null);
|
}
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
Pad.prototype.copy = thenify(function copy(destinationID, force, callback) {
|
hooks.callAll("padLoad", { 'pad': this });
|
||||||
var sourceID = this.id;
|
}
|
||||||
var _this = this;
|
|
||||||
var destGroupID;
|
Pad.prototype.copy = async function copy(destinationID, force) {
|
||||||
|
|
||||||
|
let sourceID = this.id;
|
||||||
|
|
||||||
// allow force to be a string
|
// allow force to be a string
|
||||||
if (typeof force === "string") {
|
if (typeof force === "string") {
|
||||||
|
@ -454,236 +368,134 @@ Pad.prototype.copy = thenify(function copy(destinationID, force, callback) {
|
||||||
// padMessageHandler.kickSessionsFromPad(sourceID);
|
// padMessageHandler.kickSessionsFromPad(sourceID);
|
||||||
|
|
||||||
// flush the source pad:
|
// flush the source pad:
|
||||||
_this.saveToDatabase();
|
this.saveToDatabase();
|
||||||
|
|
||||||
async.series([
|
// if it's a group pad, let's make sure the group exists.
|
||||||
// if it's a group pad, let's make sure the group exists.
|
let destGroupID;
|
||||||
function(callback) {
|
if (destinationID.indexOf("$") >= 0) {
|
||||||
if (destinationID.indexOf("$") === -1) {
|
|
||||||
callback();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
destGroupID = destinationID.split("$")[0];
|
destGroupID = destinationID.split("$")[0]
|
||||||
groupManager.doesGroupExist(destGroupID, function (err, exists) {
|
let groupExists = await groupManager.doesGroupExist(destGroupID);
|
||||||
if (ERR(err, callback)) return;
|
|
||||||
|
|
||||||
// group does not exist
|
// group does not exist
|
||||||
if (exists == false) {
|
if (!groupExists) {
|
||||||
callback(new customError("groupID does not exist for destinationID", "apierror"));
|
throw new customError("groupID does not exist for destinationID", "apierror");
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// everything is fine, continue
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// if the pad exists, we should abort, unless forced.
|
|
||||||
function(callback) {
|
|
||||||
padManager.doesPadExists(destinationID, function (err, exists) {
|
|
||||||
if (ERR(err, callback)) return;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* this is the negation of a truthy comparison. Has been left in this
|
|
||||||
* wonky state to keep the old (possibly buggy) behaviour
|
|
||||||
*/
|
|
||||||
if (!(exists == true)) {
|
|
||||||
callback();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!force) {
|
|
||||||
console.error("erroring out without force");
|
|
||||||
callback(new customError("destinationID already exists", "apierror"));
|
|
||||||
console.error("erroring out without force - after");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// exists and forcing
|
|
||||||
padManager.getPad(destinationID, function(err, pad) {
|
|
||||||
if (ERR(err, callback)) return;
|
|
||||||
pad.remove(callback);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// copy the 'pad' entry
|
|
||||||
function(callback) {
|
|
||||||
db.db.get("pad:" + sourceID, function(err, pad) {
|
|
||||||
db.set("pad:" + destinationID, pad);
|
|
||||||
});
|
|
||||||
|
|
||||||
callback();
|
|
||||||
},
|
|
||||||
|
|
||||||
// copy all relations
|
|
||||||
function(callback) {
|
|
||||||
async.parallel([
|
|
||||||
// copy all chat messages
|
|
||||||
function(callback) {
|
|
||||||
var chatHead = _this.chatHead;
|
|
||||||
|
|
||||||
for (var i=0; i <= chatHead; i++) {
|
|
||||||
db.db.get("pad:" + sourceID + ":chat:" + i, function (err, chat) {
|
|
||||||
if (ERR(err, callback)) return;
|
|
||||||
db.set("pad:" + destinationID + ":chat:" + i, chat);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
callback();
|
|
||||||
},
|
|
||||||
|
|
||||||
// copy all revisions
|
|
||||||
function(callback) {
|
|
||||||
var revHead = _this.head;
|
|
||||||
for (var i=0; i <= revHead; i++) {
|
|
||||||
db.db.get("pad:" + sourceID + ":revs:" + i, function (err, rev) {
|
|
||||||
if (ERR(err, callback)) return;
|
|
||||||
db.set("pad:" + destinationID + ":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, destinationID);
|
|
||||||
});
|
|
||||||
|
|
||||||
callback();
|
|
||||||
},
|
|
||||||
// parallel
|
|
||||||
], callback);
|
|
||||||
},
|
|
||||||
|
|
||||||
function(callback) {
|
|
||||||
if (destGroupID) {
|
|
||||||
// Group pad? Add it to the group's list
|
|
||||||
db.setSub("group:" + destGroupID, ["pads", destinationID], 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the new pad (will update the listAllPads cache)
|
|
||||||
setTimeout(function() {
|
|
||||||
padManager.getPad(destinationID, null, callback) // this runs too early.
|
|
||||||
}, 10);
|
|
||||||
},
|
|
||||||
|
|
||||||
// let the plugins know the pad was copied
|
|
||||||
function(callback) {
|
|
||||||
hooks.callAll('padCopy', { 'originalPad': _this, 'destinationID': destinationID });
|
|
||||||
callback();
|
|
||||||
}
|
}
|
||||||
// series
|
}
|
||||||
],
|
|
||||||
function(err) {
|
|
||||||
if (ERR(err, callback)) return;
|
|
||||||
callback(null, { padID: destinationID });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
Pad.prototype.remove = thenify(function remove(callback) {
|
// if the pad exists, we should abort, unless forced.
|
||||||
|
let exists = await padManager.doesPadExist(destinationID);
|
||||||
|
|
||||||
|
if (exists) {
|
||||||
|
if (!force) {
|
||||||
|
console.error("erroring out without force");
|
||||||
|
throw new customError("destinationID already exists", "apierror");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// exists and forcing
|
||||||
|
let pad = await padManager.getPad(destinationID);
|
||||||
|
await pad.remove(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy the 'pad' entry
|
||||||
|
let pad = await db.get("pad:" + sourceID);
|
||||||
|
db.set("pad:" + destinationID, pad);
|
||||||
|
|
||||||
|
// copy all relations in parallel
|
||||||
|
let promises = [];
|
||||||
|
|
||||||
|
// copy all chat messages
|
||||||
|
let chatHead = this.chatHead;
|
||||||
|
for (let i = 0; i <= chatHead; ++i) {
|
||||||
|
let p = db.get("pad:" + sourceID + ":chat:" + i).then(chat => {
|
||||||
|
return db.set("pad:" + destinationID + ":chat:" + i, chat);
|
||||||
|
});
|
||||||
|
promises.push(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy all revisions
|
||||||
|
let revHead = this.head;
|
||||||
|
for (let i = 0; i <= revHead; ++i) {
|
||||||
|
let p = db.get("pad:" + sourceID + ":revs:" + i).then(rev => {
|
||||||
|
return db.set("pad:" + destinationID + ":revs:" + i, rev);
|
||||||
|
});
|
||||||
|
promises.push(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the new pad to all authors who contributed to the old one
|
||||||
|
this.getAllAuthors().forEach(authorID => {
|
||||||
|
authorManager.addPad(authorID, destinationID);
|
||||||
|
});
|
||||||
|
|
||||||
|
// wait for the above to complete
|
||||||
|
await Promise.all(promises);
|
||||||
|
|
||||||
|
// Group pad? Add it to the group's list
|
||||||
|
if (destGroupID) {
|
||||||
|
await db.setSub("group:" + destGroupID, ["pads", destinationID], 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// delay still necessary?
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 10));
|
||||||
|
|
||||||
|
// Initialize the new pad (will update the listAllPads cache)
|
||||||
|
await padManager.getPad(destinationID, null); // this runs too early.
|
||||||
|
|
||||||
|
// let the plugins know the pad was copied
|
||||||
|
hooks.callAll('padCopy', { 'originalPad': this, 'destinationID': destinationID });
|
||||||
|
|
||||||
|
return { padID: destinationID };
|
||||||
|
}
|
||||||
|
|
||||||
|
Pad.prototype.remove = async function remove() {
|
||||||
var padID = this.id;
|
var padID = this.id;
|
||||||
var _this = this;
|
|
||||||
|
|
||||||
// kick everyone from this pad
|
// kick everyone from this pad
|
||||||
padMessageHandler.kickSessionsFromPad(padID);
|
padMessageHandler.kickSessionsFromPad(padID);
|
||||||
|
|
||||||
async.series([
|
// delete all relations
|
||||||
// delete all relations
|
|
||||||
function(callback) {
|
// is it a group pad? -> delete the entry of this pad in the group
|
||||||
async.parallel([
|
if (padID.indexOf("$") >= 0) {
|
||||||
// is it a group pad? -> delete the entry of this pad in the group
|
|
||||||
function(callback) {
|
|
||||||
if (padID.indexOf("$") === -1) {
|
|
||||||
// it isn't a group pad, nothing to do here
|
|
||||||
callback();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// it is a group pad
|
// it is a group pad
|
||||||
var groupID = padID.substring(0, padID.indexOf("$"));
|
let groupID = padID.substring(0, padID.indexOf("$"));
|
||||||
|
let group = await db.get("group:" + groupID);
|
||||||
|
|
||||||
db.db.get("group:" + groupID, function (err, group) {
|
// remove the pad entry
|
||||||
if (ERR(err, callback)) return;
|
delete group.pads[padID];
|
||||||
|
|
||||||
// remove the pad entry
|
// set the new value
|
||||||
delete group.pads[padID];
|
db.set("group:" + groupID, group);
|
||||||
|
}
|
||||||
|
|
||||||
// set the new value
|
// remove the readonly entries
|
||||||
db.set("group:" + groupID, group);
|
let readonlyID = readOnlyManager.getReadOnlyId(padID);
|
||||||
|
|
||||||
callback();
|
db.remove("pad2readonly:" + padID);
|
||||||
});
|
db.remove("readonly2pad:" + readonlyID);
|
||||||
},
|
|
||||||
|
|
||||||
// remove the readonly entries
|
// delete all chat messages
|
||||||
function(callback) {
|
for (let i = 0, n = this.chatHead; i <= n; ++i) {
|
||||||
// @TODO - temporary until surrounding code is Promisified
|
db.remove("pad:" + padID + ":chat:" + i);
|
||||||
function getReadOnlyId(padID, callback) {
|
}
|
||||||
return nodeify(readOnlyManager.getReadOnlyId(padID), callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
getReadOnlyId(padID, function(err, readonlyID) {
|
// delete all revisions
|
||||||
if (ERR(err, callback)) return;
|
for (let i = 0, n = this.head; i <= n; ++i) {
|
||||||
|
db.remove("pad:" + padID + ":revs:" + i);
|
||||||
|
}
|
||||||
|
|
||||||
db.remove("pad2readonly:" + padID);
|
// remove pad from all authors who contributed
|
||||||
db.remove("readonly2pad:" + readonlyID);
|
this.getAllAuthors().forEach(authorID => {
|
||||||
|
authorManager.removePad(authorID, padID);
|
||||||
callback();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// delete all chat messages
|
|
||||||
function(callback) {
|
|
||||||
var chatHead = _this.chatHead;
|
|
||||||
|
|
||||||
for (var i = 0; i <= chatHead; i++) {
|
|
||||||
db.remove("pad:" + padID + ":chat:" + i);
|
|
||||||
}
|
|
||||||
|
|
||||||
callback();
|
|
||||||
},
|
|
||||||
|
|
||||||
// delete all revisions
|
|
||||||
function(callback) {
|
|
||||||
var revHead = _this.head;
|
|
||||||
|
|
||||||
for (var i = 0; i <= revHead; i++) {
|
|
||||||
db.remove("pad:" + padID + ":revs:" + i);
|
|
||||||
}
|
|
||||||
|
|
||||||
callback();
|
|
||||||
},
|
|
||||||
|
|
||||||
// remove pad from all authors who contributed
|
|
||||||
function(callback) {
|
|
||||||
var authorIDs = _this.getAllAuthors();
|
|
||||||
|
|
||||||
authorIDs.forEach(function (authorID) {
|
|
||||||
authorManager.removePad(authorID, padID);
|
|
||||||
});
|
|
||||||
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
], callback);
|
|
||||||
},
|
|
||||||
|
|
||||||
// delete the pad entry and delete pad from padManager
|
|
||||||
function(callback) {
|
|
||||||
padManager.removePad(padID);
|
|
||||||
hooks.callAll("padRemove", { 'padID': padID });
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
],
|
|
||||||
function(err) {
|
|
||||||
if (ERR(err, callback)) return;
|
|
||||||
callback();
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
// delete the pad entry and delete pad from padManager
|
||||||
|
padManager.removePad(padID);
|
||||||
|
hooks.callAll("padRemove", { padID });
|
||||||
|
}
|
||||||
|
|
||||||
// set in db
|
// set in db
|
||||||
Pad.prototype.setPublicStatus = function setPublicStatus(publicStatus) {
|
Pad.prototype.setPublicStatus = function setPublicStatus(publicStatus) {
|
||||||
|
|
|
@ -18,11 +18,9 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var ERR = require("async-stacktrace");
|
|
||||||
var customError = require("../utils/customError");
|
var customError = require("../utils/customError");
|
||||||
var Pad = require("../db/Pad").Pad;
|
var Pad = require("../db/Pad").Pad;
|
||||||
var db = require("./DB").db;
|
var db = require("./DB");
|
||||||
const thenify = require("thenify").withCallback;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A cache of all loaded Pads.
|
* A cache of all loaded Pads.
|
||||||
|
@ -114,59 +112,43 @@ let padList = {
|
||||||
* @param id A String with the id of the pad
|
* @param id A String with the id of the pad
|
||||||
* @param {Function} callback
|
* @param {Function} callback
|
||||||
*/
|
*/
|
||||||
exports.getPad = thenify(function(id, text, callback)
|
exports.getPad = async function(id, text)
|
||||||
{
|
{
|
||||||
// check if this is a valid padId
|
// check if this is a valid padId
|
||||||
if (!exports.isValidPadId(id)) {
|
if (!exports.isValidPadId(id)) {
|
||||||
callback(new customError(id + " is not a valid padId", "apierror"));
|
throw new customError(id + " is not a valid padId", "apierror");
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// make text an optional parameter
|
|
||||||
if (typeof text == "function") {
|
|
||||||
callback = text;
|
|
||||||
text = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if this is a valid text
|
// check if this is a valid text
|
||||||
if (text != null) {
|
if (text != null) {
|
||||||
// check if text is a string
|
// check if text is a string
|
||||||
if (typeof text != "string") {
|
if (typeof text != "string") {
|
||||||
callback(new customError("text is not a string", "apierror"));
|
throw new customError("text is not a string", "apierror");
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if text is less than 100k chars
|
// check if text is less than 100k chars
|
||||||
if (text.length > 100000) {
|
if (text.length > 100000) {
|
||||||
callback(new customError("text must be less than 100k chars", "apierror"));
|
throw new customError("text must be less than 100k chars", "apierror");
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var pad = globalPads.get(id);
|
let pad = globalPads.get(id);
|
||||||
|
|
||||||
// return pad if it's already loaded
|
// return pad if it's already loaded
|
||||||
if (pad != null) {
|
if (pad != null) {
|
||||||
callback(null, pad);
|
return pad;
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to load pad
|
// try to load pad
|
||||||
pad = new Pad(id);
|
pad = new Pad(id);
|
||||||
|
|
||||||
// initalize the pad
|
// initalize the pad
|
||||||
pad.init(text, function(err) {
|
await pad.init(text);
|
||||||
if (ERR(err, callback)) return;
|
globalPads.set(id, pad);
|
||||||
|
padList.addPad(id);
|
||||||
|
|
||||||
globalPads.set(id, pad);
|
return pad;
|
||||||
padList.addPad(id);
|
}
|
||||||
callback(null, pad);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
exports.listAllPads = async function()
|
exports.listAllPads = async function()
|
||||||
{
|
{
|
||||||
|
@ -176,18 +158,12 @@ exports.listAllPads = async function()
|
||||||
}
|
}
|
||||||
|
|
||||||
// checks if a pad exists
|
// checks if a pad exists
|
||||||
exports.doesPadExist = thenify(function(padId, callback)
|
exports.doesPadExist = async function(padId)
|
||||||
{
|
{
|
||||||
db.get("pad:" + padId, function(err, value) {
|
let value = await db.get("pad:" + padId);
|
||||||
if (ERR(err, callback)) return;
|
|
||||||
|
|
||||||
if (value != null && value.atext) {
|
return (value != null && value.atext);
|
||||||
callback(null, true);
|
}
|
||||||
} else {
|
|
||||||
callback(null, false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// alias for backwards compatibility
|
// alias for backwards compatibility
|
||||||
exports.doesPadExists = exports.doesPadExist;
|
exports.doesPadExists = exports.doesPadExist;
|
||||||
|
|
Loading…
Reference in New Issue