mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-01-31 19:02:59 +01:00
prepare to async: trivial reformatting
This change is only cosmetic. Its aim is do make it easier to understand the async changes that are going to be merged later on. It was extracted from the original work from Ray Bellis. To verify that nothing has changed, you can run the following command on each file touched by this commit: npm install uglify-es diff --unified <(uglify-js --beautify bracketize <BEFORE.js>) <(uglify-js --beautify bracketize <AFTER.js>) This is a complete script that does the same automatically (works from a mercurial clone): ```bash #!/usr/bin/env bash set -eu REVISION=<THIS_REVISION> PARENT_REV=$(hg identify --rev "${REVISION}" --template '{p1rev}') FILE_LIST=$(hg status --no-status --change ${REVISION}) UGLIFYJS="node_modules/uglify-es/bin/uglifyjs" for FILE_NAME in ${FILE_LIST[@]}; do echo "Checking ${FILE_NAME}" diff --unified \ <("${UGLIFYJS}" --beautify bracketize <(hg cat --rev "${PARENT_REV}" "${FILE_NAME}")) \ <("${UGLIFYJS}" --beautify bracketize <(hg cat --rev "${REVISION}" "${FILE_NAME}")) done ```
This commit is contained in:
parent
cc23bd18a4
commit
9497ee734f
33 changed files with 2706 additions and 2943 deletions
|
@ -1,25 +1,25 @@
|
|||
/*
|
||||
This is a debug tool. It checks all revisions for data corruption
|
||||
* This is a debug tool. It checks all revisions for data corruption
|
||||
*/
|
||||
|
||||
if(process.argv.length != 2)
|
||||
{
|
||||
if (process.argv.length != 2) {
|
||||
console.error("Use: node bin/checkAllPads.js");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// initialize the variables
|
||||
var db, settings, padManager;
|
||||
var npm = require("../src/node_modules/npm");
|
||||
var async = require("../src/node_modules/async");
|
||||
var npm = require('../src/node_modules/npm');
|
||||
var async = require('../src/node_modules/async');
|
||||
|
||||
var Changeset = require("../src/static/js/Changeset");
|
||||
var Changeset = require('../src/static/js/Changeset');
|
||||
|
||||
async.series([
|
||||
// load npm
|
||||
function(callback) {
|
||||
npm.load({}, callback);
|
||||
},
|
||||
|
||||
// load modules
|
||||
function(callback) {
|
||||
settings = require('../src/node/utils/Settings');
|
||||
|
@ -28,31 +28,29 @@ async.series([
|
|||
// initialize the database
|
||||
db.init(callback);
|
||||
},
|
||||
|
||||
// load pads
|
||||
function (callback)
|
||||
{
|
||||
function (callback) {
|
||||
padManager = require('../src/node/db/PadManager');
|
||||
|
||||
padManager.listAllPads(function(err, res)
|
||||
{
|
||||
padManager.listAllPads(function(err, res) {
|
||||
padIds = res.padIDs;
|
||||
callback(err);
|
||||
});
|
||||
},
|
||||
function (callback)
|
||||
{
|
||||
async.forEach(padIds, function(padId, callback)
|
||||
{
|
||||
|
||||
function (callback) {
|
||||
async.forEach(padIds, function(padId, callback) {
|
||||
padManager.getPad(padId, function(err, pad) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
}
|
||||
|
||||
// check if the pad has a pool
|
||||
if(pad.pool === undefined )
|
||||
{
|
||||
if (pad.pool === undefined ) {
|
||||
console.error("[" + pad.id + "] Missing attribute pool");
|
||||
callback();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -60,36 +58,32 @@ async.series([
|
|||
// key revisions always save the full pad atext
|
||||
var head = pad.getHeadRevisionNumber();
|
||||
var keyRevisions = [];
|
||||
for(var i=0;i<head;i+=100)
|
||||
{
|
||||
for (var i = 0; i < head; i += 100) {
|
||||
keyRevisions.push(i);
|
||||
}
|
||||
|
||||
//run trough all key revisions
|
||||
async.forEachSeries(keyRevisions, function(keyRev, callback)
|
||||
{
|
||||
// run through all key revisions
|
||||
async.forEachSeries(keyRevisions, function(keyRev, callback) {
|
||||
// create an array of revisions we need till the next keyRevision or the End
|
||||
var revisionsNeeded = [];
|
||||
for(var i=keyRev;i<=keyRev+100 && i<=head; i++)
|
||||
{
|
||||
|
||||
for(var i = keyRev; i <= keyRev + 100 && i <= head; i++) {
|
||||
revisionsNeeded.push(i);
|
||||
}
|
||||
|
||||
// this array will hold all revision changesets
|
||||
var revisions = [];
|
||||
|
||||
//run trough all needed revisions and get them from the database
|
||||
async.forEach(revisionsNeeded, function(revNum, callback)
|
||||
{
|
||||
db.db.get("pad:"+pad.id+":revs:" + revNum, function(err, revision)
|
||||
{
|
||||
// run through all needed revisions and get them from the database
|
||||
async.forEach(revisionsNeeded, function(revNum, callback) {
|
||||
db.db.get("pad:" + pad.id + ":revs:" + revNum, function(err, revision) {
|
||||
revisions[revNum] = revision;
|
||||
callback(err);
|
||||
});
|
||||
}, function(err)
|
||||
{
|
||||
if(err)
|
||||
{
|
||||
},
|
||||
|
||||
function(err) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
@ -102,8 +96,7 @@ async.series([
|
|||
}
|
||||
|
||||
// check if there is a atext in the keyRevisions
|
||||
if(revisions[keyRev].meta === undefined || revisions[keyRev].meta.atext === undefined)
|
||||
{
|
||||
if (revisions[keyRev].meta === undefined || revisions[keyRev].meta.atext === undefined) {
|
||||
console.error("[" + pad.id + "] Missing atext in revision " + keyRev);
|
||||
callback();
|
||||
return;
|
||||
|
@ -112,16 +105,12 @@ async.series([
|
|||
var apool = pad.pool;
|
||||
var atext = revisions[keyRev].meta.atext;
|
||||
|
||||
for(var i=keyRev+1;i<=keyRev+100 && i<=head; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
for(var i = keyRev + 1; i <= keyRev + 100 && i <= head; i++) {
|
||||
try {
|
||||
// console.log("[" + pad.id + "] check revision " + i);
|
||||
var cs = revisions[i].changeset;
|
||||
atext = Changeset.applyToAText(cs, atext, apool);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
} catch(e) {
|
||||
console.error("[" + pad.id + "] Bad changeset at revision " + i + " - " + e.message);
|
||||
callback();
|
||||
return;
|
||||
|
@ -134,11 +123,11 @@ async.series([
|
|||
});
|
||||
}, callback);
|
||||
}
|
||||
], function (err)
|
||||
{
|
||||
if(err) throw err;
|
||||
else
|
||||
{
|
||||
],
|
||||
function (err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
} else {
|
||||
console.log("finished");
|
||||
process.exit(0);
|
||||
}
|
||||
|
|
|
@ -1,29 +1,30 @@
|
|||
/*
|
||||
This is a debug tool. It checks all revisions for data corruption
|
||||
* This is a debug tool. It checks all revisions for data corruption
|
||||
*/
|
||||
|
||||
if(process.argv.length != 3)
|
||||
{
|
||||
if (process.argv.length != 3) {
|
||||
console.error("Use: node bin/checkPad.js $PADID");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
//get the padID
|
||||
var padId = process.argv[2];
|
||||
|
||||
// initialize the variables
|
||||
var db, settings, padManager;
|
||||
var npm = require("../src/node_modules/npm");
|
||||
var async = require("../src/node_modules/async");
|
||||
var npm = require('../src/node_modules/npm');
|
||||
var async = require('../src/node_modules/async');
|
||||
|
||||
var Changeset = require("ep_etherpad-lite/static/js/Changeset");
|
||||
var Changeset = require('ep_etherpad-lite/static/js/Changeset');
|
||||
|
||||
async.series([
|
||||
// load npm
|
||||
function(callback) {
|
||||
npm.load({}, function(er) {
|
||||
callback(er);
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
// load modules
|
||||
function(callback) {
|
||||
settings = require('../src/node/utils/Settings');
|
||||
|
@ -32,76 +33,65 @@ async.series([
|
|||
// initialize the database
|
||||
db.init(callback);
|
||||
},
|
||||
|
||||
// get the pad
|
||||
function (callback)
|
||||
{
|
||||
function (callback) {
|
||||
padManager = require('../src/node/db/PadManager');
|
||||
|
||||
padManager.doesPadExists(padId, function(err, exists)
|
||||
{
|
||||
if(!exists)
|
||||
{
|
||||
padManager.doesPadExists(padId, function(err, exists) {
|
||||
if (!exists) {
|
||||
console.error("Pad does not exist");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
padManager.getPad(padId, function(err, _pad)
|
||||
{
|
||||
padManager.getPad(padId, function(err, _pad) {
|
||||
pad = _pad;
|
||||
callback(err);
|
||||
});
|
||||
});
|
||||
},
|
||||
function (callback)
|
||||
{
|
||||
|
||||
function (callback) {
|
||||
// create an array with key revisions
|
||||
// key revisions always save the full pad atext
|
||||
var head = pad.getHeadRevisionNumber();
|
||||
var keyRevisions = [];
|
||||
for(var i=0;i<head;i+=100)
|
||||
{
|
||||
for (var i = 0; i < head; i += 100) {
|
||||
keyRevisions.push(i);
|
||||
}
|
||||
|
||||
//run trough all key revisions
|
||||
async.forEachSeries(keyRevisions, function(keyRev, callback)
|
||||
{
|
||||
// run through all key revisions
|
||||
async.forEachSeries(keyRevisions, function(keyRev, callback) {
|
||||
// create an array of revisions we need till the next keyRevision or the End
|
||||
var revisionsNeeded = [];
|
||||
for(var i=keyRev;i<=keyRev+100 && i<=head; i++)
|
||||
{
|
||||
for(var i = keyRev; i <= keyRev + 100 && i <= head; i++) {
|
||||
revisionsNeeded.push(i);
|
||||
}
|
||||
|
||||
// this array will hold all revision changesets
|
||||
var revisions = [];
|
||||
|
||||
//run trough all needed revisions and get them from the database
|
||||
async.forEach(revisionsNeeded, function(revNum, callback)
|
||||
{
|
||||
db.db.get("pad:"+padId+":revs:" + revNum, function(err, revision)
|
||||
{
|
||||
// run through all needed revisions and get them from the database
|
||||
async.forEach(revisionsNeeded, function(revNum, callback) {
|
||||
db.db.get("pad:" + padId + ":revs:" + revNum, function(err, revision) {
|
||||
revisions[revNum] = revision;
|
||||
callback(err);
|
||||
});
|
||||
}, function(err)
|
||||
{
|
||||
if(err)
|
||||
{
|
||||
},
|
||||
function(err) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// check if the pad has a pool
|
||||
if(pad.pool === undefined )
|
||||
{
|
||||
if (pad.pool === undefined) {
|
||||
console.error("Attribute pool is missing");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// check if there is an atext in the keyRevisions
|
||||
if(revisions[keyRev] === undefined || revisions[keyRev].meta === undefined || revisions[keyRev].meta.atext === undefined)
|
||||
{
|
||||
if (revisions[keyRev] === undefined || revisions[keyRev].meta === undefined || revisions[keyRev].meta.atext === undefined) {
|
||||
console.error("No atext in key revision " + keyRev);
|
||||
callback();
|
||||
return;
|
||||
|
@ -110,16 +100,12 @@ async.series([
|
|||
var apool = pad.pool;
|
||||
var atext = revisions[keyRev].meta.atext;
|
||||
|
||||
for(var i=keyRev+1;i<=keyRev+100 && i<=head; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
for (var i = keyRev + 1; i <= keyRev + 100 && i <= head; i++) {
|
||||
try {
|
||||
// console.log("check revision " + i);
|
||||
var cs = revisions[i].changeset;
|
||||
atext = Changeset.applyToAText(cs, atext, apool);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
} catch(e) {
|
||||
console.error("Bad changeset at revision " + i + " - " + e.message);
|
||||
callback();
|
||||
return;
|
||||
|
@ -130,11 +116,11 @@ async.series([
|
|||
});
|
||||
}, callback);
|
||||
}
|
||||
], function (err)
|
||||
{
|
||||
if(err) throw err;
|
||||
else
|
||||
{
|
||||
],
|
||||
function (err) {
|
||||
if(err) {
|
||||
throw err;
|
||||
} else {
|
||||
console.log("finished");
|
||||
process.exit(0);
|
||||
}
|
||||
|
|
|
@ -1,62 +1,62 @@
|
|||
/*
|
||||
A tool for deleting pads from the CLI, because sometimes a brick is required to fix a window.
|
||||
* A tool for deleting pads from the CLI, because sometimes a brick is required
|
||||
* to fix a window.
|
||||
*/
|
||||
|
||||
if(process.argv.length != 3)
|
||||
{
|
||||
if (process.argv.length != 3) {
|
||||
console.error("Use: node deletePad.js $PADID");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// get the padID
|
||||
var padId = process.argv[2];
|
||||
|
||||
var db, padManager, pad, settings;
|
||||
var neededDBValues = ["pad:"+padId];
|
||||
|
||||
var npm = require("../src/node_modules/npm");
|
||||
var async = require("../src/node_modules/async");
|
||||
var npm = require('../src/node_modules/npm');
|
||||
var async = require('../src/node_modules/async');
|
||||
|
||||
async.series([
|
||||
// load npm
|
||||
function(callback) {
|
||||
npm.load({}, function(er) {
|
||||
if(er)
|
||||
{
|
||||
if (er) {
|
||||
console.error("Could not load NPM: " + er)
|
||||
process.exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
// load modules
|
||||
function(callback) {
|
||||
settings = require('../src/node/utils/Settings');
|
||||
db = require('../src/node/db/DB');
|
||||
callback();
|
||||
},
|
||||
|
||||
// initialize the database
|
||||
function (callback)
|
||||
{
|
||||
function (callback) {
|
||||
db.init(callback);
|
||||
},
|
||||
|
||||
// delete the pad and its links
|
||||
function (callback)
|
||||
{
|
||||
function (callback) {
|
||||
padManager = require('../src/node/db/PadManager');
|
||||
|
||||
padManager.removePad(padId, function(err){
|
||||
callback(err);
|
||||
});
|
||||
|
||||
callback();
|
||||
}
|
||||
], function (err)
|
||||
{
|
||||
if(err) throw err;
|
||||
else
|
||||
{
|
||||
],
|
||||
function (err) {
|
||||
if(err) {
|
||||
throw err;
|
||||
} else {
|
||||
console.log("Finished deleting padId: " + padId);
|
||||
process.exit();
|
||||
}
|
||||
|
|
|
@ -1,87 +1,81 @@
|
|||
/*
|
||||
This is a debug tool. It helps to extract all datas of a pad and move it from an productive environment and to a develop environment to reproduce bugs there. It outputs a dirtydb file
|
||||
* This is a debug tool. It helps to extract all datas of a pad and move it from
|
||||
* a productive environment and to a develop environment to reproduce bugs
|
||||
* there. It outputs a dirtydb file
|
||||
*/
|
||||
|
||||
if(process.argv.length != 3)
|
||||
{
|
||||
if (process.argv.length != 3) {
|
||||
console.error("Use: node extractPadData.js $PADID");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// get the padID
|
||||
var padId = process.argv[2];
|
||||
|
||||
var db, dirty, padManager, pad, settings;
|
||||
var neededDBValues = ["pad:"+padId];
|
||||
|
||||
var npm = require("../node_modules/ep_etherpad-lite/node_modules/npm");
|
||||
var async = require("../node_modules/ep_etherpad-lite/node_modules/async");
|
||||
var npm = require('../node_modules/ep_etherpad-lite/node_modules/npm');
|
||||
var async = require('../node_modules/ep_etherpad-lite/node_modules/async');
|
||||
|
||||
async.series([
|
||||
// load npm
|
||||
function(callback) {
|
||||
npm.load({}, function(er) {
|
||||
if(er)
|
||||
{
|
||||
if (er) {
|
||||
console.error("Could not load NPM: " + er)
|
||||
process.exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// load modules
|
||||
function(callback) {
|
||||
settings = require('../node_modules/ep_etherpad-lite/node/utils/Settings');
|
||||
db = require('../node_modules/ep_etherpad-lite/node/db/DB');
|
||||
dirty = require("../node_modules/ep_etherpad-lite/node_modules/ueberDB/node_modules/dirty")(padId + ".db");
|
||||
dirty = require('../node_modules/ep_etherpad-lite/node_modules/ueberDB/node_modules/dirty')(padId + ".db");
|
||||
callback();
|
||||
},
|
||||
|
||||
// initialize the database
|
||||
function (callback)
|
||||
{
|
||||
function (callback) {
|
||||
db.init(callback);
|
||||
},
|
||||
|
||||
// get the pad
|
||||
function (callback)
|
||||
{
|
||||
function (callback) {
|
||||
padManager = require('../node_modules/ep_etherpad-lite/node/db/PadManager');
|
||||
|
||||
padManager.getPad(padId, function(err, _pad)
|
||||
{
|
||||
padManager.getPad(padId, function(err, _pad) {
|
||||
pad = _pad;
|
||||
callback(err);
|
||||
});
|
||||
},
|
||||
function (callback)
|
||||
{
|
||||
|
||||
function (callback) {
|
||||
// add all authors
|
||||
var authors = pad.getAllAuthors();
|
||||
for(var i=0;i<authors.length;i++)
|
||||
{
|
||||
neededDBValues.push("globalAuthor:" + authors[i]);
|
||||
for (var i = 0; i < authors.length; i++) {
|
||||
neededDBValues.push('globalAuthor:' + authors[i]);
|
||||
}
|
||||
|
||||
// add all revisions
|
||||
var revHead = pad.head;
|
||||
for(var i=0;i<=revHead;i++)
|
||||
{
|
||||
neededDBValues.push("pad:"+padId+":revs:" + i);
|
||||
for (var i = 0; i <= revHead; i++) {
|
||||
neededDBValues.push('pad:' + padId + ':revs:' + i);
|
||||
}
|
||||
|
||||
// get all chat values
|
||||
var chatHead = pad.chatHead;
|
||||
for(var i=0;i<=chatHead;i++)
|
||||
{
|
||||
neededDBValues.push("pad:"+padId+":chat:" + i);
|
||||
for (var i = 0; i <= chatHead; i++) {
|
||||
neededDBValues.push('pad:' + padId + ':chat:' + i);
|
||||
}
|
||||
|
||||
// get and set all values
|
||||
async.forEach(neededDBValues, function(dbkey, callback)
|
||||
{
|
||||
db.db.db.wrappedDB.get(dbkey, function(err, dbvalue)
|
||||
{
|
||||
async.forEach(neededDBValues, function(dbkey, callback) {
|
||||
db.db.db.wrappedDB.get(dbkey, function(err, dbvalue) {
|
||||
if (err) { callback(err); return}
|
||||
|
||||
if (dbvalue && typeof dbvalue != 'object') {
|
||||
|
@ -92,18 +86,12 @@ async.series([
|
|||
});
|
||||
}, callback);
|
||||
}
|
||||
], function (err)
|
||||
{
|
||||
if(err) throw err;
|
||||
else
|
||||
{
|
||||
],
|
||||
function (err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
} else {
|
||||
console.log("finished");
|
||||
process.exit();
|
||||
}
|
||||
});
|
||||
|
||||
//get the pad object
|
||||
//get all revisions of this pad
|
||||
//get all authors related to this pad
|
||||
//get the readonly link related to this pad
|
||||
//get the chat entries related to this pad
|
||||
|
|
|
@ -105,9 +105,9 @@ Example returns:
|
|||
*/
|
||||
exports.getAttributePool = function(padID, callback)
|
||||
{
|
||||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
getPadSafe(padID, true, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
callback(null, {pool: pad.pool});
|
||||
});
|
||||
}
|
||||
|
@ -128,11 +128,9 @@ Example returns:
|
|||
exports.getRevisionChangeset = function(padID, rev, callback)
|
||||
{
|
||||
// check if rev is a number
|
||||
if (rev !== undefined && typeof rev !== "number")
|
||||
{
|
||||
if (rev !== undefined && typeof rev !== "number") {
|
||||
// try to parse the number
|
||||
if (isNaN(parseInt(rev)))
|
||||
{
|
||||
if (isNaN(parseInt(rev))) {
|
||||
callback(new customError("rev is not a number", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
@ -141,37 +139,31 @@ exports.getRevisionChangeset = function(padID, rev, callback)
|
|||
}
|
||||
|
||||
// ensure this is not a negative number
|
||||
if (rev !== undefined && rev < 0)
|
||||
{
|
||||
if (rev !== undefined && rev < 0) {
|
||||
callback(new customError("rev is not a negative number", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
// ensure this is not a float value
|
||||
if (rev !== undefined && !is_int(rev))
|
||||
{
|
||||
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)
|
||||
{
|
||||
getPadSafe(padID, true, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
// the client asked for a special revision
|
||||
if(rev !== undefined)
|
||||
{
|
||||
if (rev !== undefined) {
|
||||
// check if this is a valid revision
|
||||
if(rev > pad.getHeadRevisionNumber())
|
||||
{
|
||||
if (rev > pad.getHeadRevisionNumber()) {
|
||||
callback(new customError("rev is higher than the head revision of the pad", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
// get the changeset for this revision
|
||||
pad.getRevisionChangeset(rev, function(err, changeset)
|
||||
{
|
||||
pad.getRevisionChangeset(rev, function(err, changeset) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
callback(null, changeset);
|
||||
|
@ -181,8 +173,7 @@ exports.getRevisionChangeset = function(padID, rev, callback)
|
|||
}
|
||||
|
||||
// the client wants the latest changeset, lets return it to him
|
||||
pad.getRevisionChangeset(pad.getHeadRevisionNumber(), function(err, changeset)
|
||||
{
|
||||
pad.getRevisionChangeset(pad.getHeadRevisionNumber(), function(err, changeset) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
callback(null, changeset);
|
||||
|
@ -201,11 +192,9 @@ Example returns:
|
|||
exports.getText = function(padID, rev, callback)
|
||||
{
|
||||
// check if rev is a number
|
||||
if(rev !== undefined && typeof rev != "number")
|
||||
{
|
||||
if (rev !== undefined && typeof rev != "number") {
|
||||
// try to parse the number
|
||||
if(isNaN(parseInt(rev)))
|
||||
{
|
||||
if (isNaN(parseInt(rev))) {
|
||||
callback(new customError("rev is not a number", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
@ -213,38 +202,32 @@ exports.getText = function(padID, rev, callback)
|
|||
rev = parseInt(rev);
|
||||
}
|
||||
|
||||
//ensure this is not a negativ number
|
||||
if(rev !== undefined && rev < 0)
|
||||
{
|
||||
// ensure this is not a negative 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))
|
||||
{
|
||||
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)
|
||||
{
|
||||
getPadSafe(padID, true, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
// the client asked for a special revision
|
||||
if(rev !== undefined)
|
||||
{
|
||||
if (rev !== undefined) {
|
||||
// check if this is a valid revision
|
||||
if(rev > pad.getHeadRevisionNumber())
|
||||
{
|
||||
if (rev > pad.getHeadRevisionNumber()) {
|
||||
callback(new customError("rev is higher than the head revision of the pad", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
// get the text of this revision
|
||||
pad.getInternalRevisionAText(rev, function(err, atext)
|
||||
{
|
||||
pad.getInternalRevisionAText(rev, function(err, atext) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
var data = {text: atext.text};
|
||||
|
@ -273,15 +256,13 @@ Example returns:
|
|||
exports.setText = function(padID, text, callback)
|
||||
{
|
||||
// text is required
|
||||
if(typeof text != "string")
|
||||
{
|
||||
if (typeof text != "string") {
|
||||
callback(new customError("text is no string", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
// get the pad
|
||||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
getPadSafe(padID, true, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
// set the text
|
||||
|
@ -304,15 +285,13 @@ Example returns:
|
|||
exports.appendText = function(padID, text, callback)
|
||||
{
|
||||
// text is required
|
||||
if(typeof text != "string")
|
||||
{
|
||||
if (typeof text != "string") {
|
||||
callback(new customError("text is no string", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
// get the pad
|
||||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
getPadSafe(padID, true, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
pad.appendText(text);
|
||||
|
@ -322,8 +301,6 @@ exports.appendText = function(padID, text, callback)
|
|||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
getHTML(padID, [rev]) returns the html of a pad
|
||||
|
||||
|
@ -334,10 +311,8 @@ Example returns:
|
|||
*/
|
||||
exports.getHTML = function(padID, rev, callback)
|
||||
{
|
||||
if (rev !== undefined && typeof rev != "number")
|
||||
{
|
||||
if (isNaN(parseInt(rev)))
|
||||
{
|
||||
if (rev !== undefined && typeof rev != "number") {
|
||||
if (isNaN(parseInt(rev))) {
|
||||
callback(new customError("rev is not a number", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
@ -345,35 +320,29 @@ exports.getHTML = function(padID, rev, callback)
|
|||
rev = parseInt(rev);
|
||||
}
|
||||
|
||||
if(rev !== undefined && rev < 0)
|
||||
{
|
||||
if (rev !== undefined && rev < 0) {
|
||||
callback(new customError("rev is a negative number", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
if(rev !== undefined && !is_int(rev))
|
||||
{
|
||||
if (rev !== undefined && !is_int(rev)) {
|
||||
callback(new customError("rev is a float value", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
getPadSafe(padID, true, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
// the client asked for a special revision
|
||||
if(rev !== undefined)
|
||||
{
|
||||
if (rev !== undefined) {
|
||||
// check if this is a valid revision
|
||||
if(rev > pad.getHeadRevisionNumber())
|
||||
{
|
||||
if (rev > pad.getHeadRevisionNumber()) {
|
||||
callback(new customError("rev is higher than the head revision of the pad", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
// get the html of this revision
|
||||
exportHtml.getPadHTML(pad, rev, function(err, html)
|
||||
{
|
||||
exportHtml.getPadHTML(pad, rev, function(err, html) {
|
||||
if (ERR(err, callback)) return;
|
||||
html = "<!DOCTYPE HTML><html><body>" +html; // adds HTML head
|
||||
html += "</body></html>";
|
||||
|
@ -385,8 +354,7 @@ exports.getHTML = function(padID, rev, callback)
|
|||
}
|
||||
|
||||
// the client wants the latest text, lets return it to him
|
||||
exportHtml.getPadHTML(pad, undefined, function (err, html)
|
||||
{
|
||||
exportHtml.getPadHTML(pad, undefined, function(err, html) {
|
||||
if (ERR(err, callback)) return;
|
||||
html = "<!DOCTYPE HTML><html><body>" +html; // adds HTML head
|
||||
html += "</body></html>";
|
||||
|
@ -407,15 +375,13 @@ Example returns:
|
|||
exports.setHTML = function(padID, html, callback)
|
||||
{
|
||||
// html is required
|
||||
if(typeof html != "string")
|
||||
{
|
||||
if (typeof html != "string") {
|
||||
callback(new customError("html is no string", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
// get the pad
|
||||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
getPadSafe(padID, true, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
// add a new changeset with the new html to the pad
|
||||
|
@ -449,53 +415,45 @@ Example returns:
|
|||
*/
|
||||
exports.getChatHistory = function(padID, start, end, callback)
|
||||
{
|
||||
if(start && end)
|
||||
{
|
||||
if(start < 0)
|
||||
{
|
||||
if (start && end) {
|
||||
if (start < 0) {
|
||||
callback(new customError("start is below zero", "apierror"));
|
||||
return;
|
||||
}
|
||||
if(end < 0)
|
||||
{
|
||||
if (end < 0) {
|
||||
callback(new customError("end is below zero", "apierror"));
|
||||
return;
|
||||
}
|
||||
if(start > end)
|
||||
{
|
||||
if (start > end) {
|
||||
callback(new customError("start is higher than end", "apierror"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// get the pad
|
||||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
getPadSafe(padID, true, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
var chatHead = pad.chatHead;
|
||||
|
||||
// fall back to getting the whole chat-history if a parameter is missing
|
||||
if(!start || !end)
|
||||
{
|
||||
if (!start || !end) {
|
||||
start = 0;
|
||||
end = pad.chatHead;
|
||||
}
|
||||
|
||||
if(start > chatHead)
|
||||
{
|
||||
if (start > chatHead) {
|
||||
callback(new customError("start is higher than the current chatHead", "apierror"));
|
||||
return;
|
||||
}
|
||||
if(end > chatHead)
|
||||
{
|
||||
if (end > chatHead) {
|
||||
callback(new customError("end is higher than the current chatHead", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
// the the whole message-log and return it to the client
|
||||
pad.getChatMessages(start, end,
|
||||
function(err, msgs)
|
||||
{
|
||||
function(err, msgs) {
|
||||
if (ERR(err, callback)) return;
|
||||
callback(null, {messages: msgs});
|
||||
});
|
||||
|
@ -513,15 +471,13 @@ Example returns:
|
|||
exports.appendChatMessage = function(padID, text, authorID, time, callback)
|
||||
{
|
||||
// text is required
|
||||
if(typeof text != "string")
|
||||
{
|
||||
if (typeof text != "string") {
|
||||
callback(new customError("text is no string", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
// if time is not an integer value
|
||||
if(time === undefined || !is_int(time))
|
||||
{
|
||||
if (time === undefined || !is_int(time)) {
|
||||
// set time to current timestamp
|
||||
time = Date.now();
|
||||
}
|
||||
|
@ -547,8 +503,7 @@ Example returns:
|
|||
exports.getRevisionsCount = function(padID, callback)
|
||||
{
|
||||
// get the pad
|
||||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
getPadSafe(padID, true, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
callback(null, {revisions: pad.getHeadRevisionNumber()});
|
||||
|
@ -566,8 +521,7 @@ Example returns:
|
|||
exports.getSavedRevisionsCount = function(padID, callback)
|
||||
{
|
||||
// get the pad
|
||||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
getPadSafe(padID, true, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
callback(null, {savedRevisions: pad.getSavedRevisionsNumber()});
|
||||
|
@ -585,8 +539,7 @@ Example returns:
|
|||
exports.listSavedRevisions = function(padID, callback)
|
||||
{
|
||||
// get the pad
|
||||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
getPadSafe(padID, true, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
callback(null, {savedRevisions: pad.getSavedRevisionsList()});
|
||||
|
@ -604,11 +557,9 @@ Example returns:
|
|||
exports.saveRevision = function(padID, rev, callback)
|
||||
{
|
||||
// check if rev is a number
|
||||
if(rev !== undefined && typeof rev != "number")
|
||||
{
|
||||
if (rev !== undefined && typeof rev != "number") {
|
||||
// try to parse the number
|
||||
if(isNaN(parseInt(rev)))
|
||||
{
|
||||
if (isNaN(parseInt(rev))) {
|
||||
callback(new customError("rev is not a number", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
@ -616,31 +567,26 @@ exports.saveRevision = function(padID, rev, callback)
|
|||
rev = parseInt(rev);
|
||||
}
|
||||
|
||||
//ensure this is not a negativ number
|
||||
if(rev !== undefined && rev < 0)
|
||||
{
|
||||
// ensure this is not a negative 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))
|
||||
{
|
||||
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)
|
||||
{
|
||||
getPadSafe(padID, true, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
// the client asked for a special revision
|
||||
if(rev !== undefined)
|
||||
{
|
||||
if (rev !== undefined) {
|
||||
// check if this is a valid revision
|
||||
if(rev > pad.getHeadRevisionNumber())
|
||||
{
|
||||
if (rev > pad.getHeadRevisionNumber()) {
|
||||
callback(new customError("rev is higher than the head revision of the pad", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
@ -668,9 +614,9 @@ Example returns:
|
|||
exports.getLastEdited = function(padID, callback)
|
||||
{
|
||||
// get the pad
|
||||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
getPadSafe(padID, true, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
pad.getLastEdit(function(err, value) {
|
||||
if (ERR(err, callback)) return;
|
||||
callback(null, {lastEdited: value});
|
||||
|
@ -688,26 +634,22 @@ Example returns:
|
|||
*/
|
||||
exports.createPad = function(padID, text, callback)
|
||||
{
|
||||
if (padID) {
|
||||
// ensure there is no $ in the padID
|
||||
if(padID)
|
||||
{
|
||||
if(padID.indexOf("$") != -1)
|
||||
{
|
||||
if (padID.indexOf("$") != -1) {
|
||||
callback(new customError("createPad can't create group pads", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
// check for url special characters
|
||||
if(padID.match(/(\/|\?|&|#)/))
|
||||
{
|
||||
if (padID.match(/(\/|\?|&|#)/)) {
|
||||
callback(new customError("malformed padID: Remove special characters", "apierror"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// create pad
|
||||
getPadSafe(padID, false, text, function(err)
|
||||
{
|
||||
getPadSafe(padID, false, text, function(err) {
|
||||
if (ERR(err, callback)) return;
|
||||
callback();
|
||||
});
|
||||
|
@ -723,8 +665,7 @@ Example returns:
|
|||
*/
|
||||
exports.deletePad = function(padID, callback)
|
||||
{
|
||||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
getPadSafe(padID, true, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
pad.remove(callback);
|
||||
|
@ -741,11 +682,9 @@ exports.deletePad = function(padID, callback)
|
|||
exports.restoreRevision = function(padID, rev, callback)
|
||||
{
|
||||
// check if rev is a number
|
||||
if (rev !== undefined && typeof rev != "number")
|
||||
{
|
||||
if (rev !== undefined && typeof rev != "number") {
|
||||
// try to parse the number
|
||||
if (isNaN(parseInt(rev)))
|
||||
{
|
||||
if (isNaN(parseInt(rev))) {
|
||||
callback(new customError("rev is not a number", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
@ -753,51 +692,43 @@ exports.restoreRevision = function (padID, rev, callback)
|
|||
rev = parseInt(rev);
|
||||
}
|
||||
|
||||
//ensure this is not a negativ number
|
||||
if (rev !== undefined && rev < 0)
|
||||
{
|
||||
// ensure this is not a negative 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))
|
||||
{
|
||||
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)
|
||||
{
|
||||
getPadSafe(padID, true, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
|
||||
// check if this is a valid revision
|
||||
if (rev > pad.getHeadRevisionNumber())
|
||||
{
|
||||
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)
|
||||
{
|
||||
pad.getInternalRevisionAText(rev, function(err, atext) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
var oldText = pad.text();
|
||||
atext.text += "\n";
|
||||
function eachAttribRun(attribs, func)
|
||||
{
|
||||
function eachAttribRun(attribs, func) {
|
||||
var attribsIter = Changeset.opIterator(attribs);
|
||||
var textIndex = 0;
|
||||
var newTextStart = 0;
|
||||
var newTextEnd = atext.text.length;
|
||||
while (attribsIter.hasNext())
|
||||
{
|
||||
while (attribsIter.hasNext()) {
|
||||
var op = attribsIter.next();
|
||||
var nextIndex = textIndex + op.chars;
|
||||
if (!(nextIndex <= newTextStart || textIndex >= newTextEnd))
|
||||
{
|
||||
if (!(nextIndex <= newTextStart || textIndex >= newTextEnd)) {
|
||||
func(Math.max(newTextStart, textIndex), Math.min(newTextEnd, nextIndex), op.attribs);
|
||||
}
|
||||
textIndex = nextIndex;
|
||||
|
@ -808,17 +739,14 @@ exports.restoreRevision = function (padID, rev, callback)
|
|||
var builder = Changeset.builder(oldText.length);
|
||||
|
||||
// assemble each line into the builder
|
||||
eachAttribRun(atext.attribs, function (start, end, attribs)
|
||||
{
|
||||
eachAttribRun(atext.attribs, function(start, end, attribs) {
|
||||
builder.insert(atext.text.substring(start, end), attribs);
|
||||
});
|
||||
|
||||
var lastNewlinePos = oldText.lastIndexOf('\n');
|
||||
if (lastNewlinePos < 0)
|
||||
{
|
||||
if (lastNewlinePos < 0) {
|
||||
builder.remove(oldText.length - 1, 0);
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
builder.remove(lastNewlinePos, oldText.match(/\n/g).length - 1);
|
||||
builder.remove(oldText.length - lastNewlinePos - 1, 0);
|
||||
}
|
||||
|
@ -827,10 +755,9 @@ exports.restoreRevision = function (padID, rev, callback)
|
|||
|
||||
// append the changeset
|
||||
pad.appendRevision(changeset);
|
||||
//
|
||||
padMessageHandler.updatePadClients(pad, function ()
|
||||
{
|
||||
});
|
||||
|
||||
// update the clients on the pad
|
||||
padMessageHandler.updatePadClients(pad, function() {});
|
||||
callback(null, null);
|
||||
});
|
||||
|
||||
|
@ -848,8 +775,7 @@ Example returns:
|
|||
*/
|
||||
exports.copyPad = function(sourceID, destinationID, force, callback)
|
||||
{
|
||||
getPadSafe(sourceID, true, function(err, pad)
|
||||
{
|
||||
getPadSafe(sourceID, true, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
pad.copy(destinationID, force, callback);
|
||||
|
@ -867,8 +793,7 @@ Example returns:
|
|||
*/
|
||||
exports.movePad = function(sourceID, destinationID, force, callback)
|
||||
{
|
||||
getPadSafe(sourceID, true, function(err, pad)
|
||||
{
|
||||
getPadSafe(sourceID, true, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
pad.copy(destinationID, force, function(err) {
|
||||
|
@ -888,13 +813,11 @@ Example returns:
|
|||
exports.getReadOnlyID = function(padID, callback)
|
||||
{
|
||||
// we don't need the pad object, but this function does all the security stuff for us
|
||||
getPadSafe(padID, true, function(err)
|
||||
{
|
||||
getPadSafe(padID, true, function(err) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
// get the readonlyId
|
||||
readOnlyManager.getReadOnlyId(padID, function(err, readOnlyId)
|
||||
{
|
||||
readOnlyManager.getReadOnlyId(padID, function(err, readOnlyId) {
|
||||
if (ERR(err, callback)) return;
|
||||
callback(null, {readOnlyID: readOnlyId});
|
||||
});
|
||||
|
@ -912,12 +835,10 @@ Example returns:
|
|||
exports.getPadID = function(roID, callback)
|
||||
{
|
||||
// get the PadId
|
||||
readOnlyManager.getPadId(roID, function(err, retrievedPadID)
|
||||
{
|
||||
readOnlyManager.getPadId(roID, function(err, retrievedPadID) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
if(retrievedPadID == null)
|
||||
{
|
||||
if (retrievedPadID == null) {
|
||||
callback(new customError("padID does not exist", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
@ -937,15 +858,13 @@ Example returns:
|
|||
exports.setPublicStatus = function(padID, publicStatus, callback)
|
||||
{
|
||||
// ensure this is a group pad
|
||||
if(padID && padID.indexOf("$") == -1)
|
||||
{
|
||||
if (padID && padID.indexOf("$") == -1) {
|
||||
callback(new customError("You can only get/set the publicStatus of pads that belong to a group", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
// get the pad
|
||||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
getPadSafe(padID, true, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
// convert string to boolean
|
||||
|
@ -970,15 +889,13 @@ Example returns:
|
|||
exports.getPublicStatus = function(padID, callback)
|
||||
{
|
||||
// ensure this is a group pad
|
||||
if(padID && padID.indexOf("$") == -1)
|
||||
{
|
||||
if (padID && padID.indexOf("$") == -1) {
|
||||
callback(new customError("You can only get/set the publicStatus of pads that belong to a group", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
// get the pad
|
||||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
getPadSafe(padID, true, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
callback(null, {publicStatus: pad.getPublicStatus()});
|
||||
|
@ -996,15 +913,13 @@ Example returns:
|
|||
exports.setPassword = function(padID, password, callback)
|
||||
{
|
||||
// ensure this is a group pad
|
||||
if(padID && padID.indexOf("$") == -1)
|
||||
{
|
||||
if (padID && padID.indexOf("$") == -1) {
|
||||
callback(new customError("You can only get/set the password of pads that belong to a group", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
// get the pad
|
||||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
getPadSafe(padID, true, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
// set the password
|
||||
|
@ -1025,15 +940,13 @@ Example returns:
|
|||
exports.isPasswordProtected = function(padID, callback)
|
||||
{
|
||||
// ensure this is a group pad
|
||||
if(padID && padID.indexOf("$") == -1)
|
||||
{
|
||||
if (padID && padID.indexOf("$") == -1) {
|
||||
callback(new customError("You can only get/set the password of pads that belong to a group", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
// get the pad
|
||||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
getPadSafe(padID, true, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
callback(null, {isPasswordProtected: pad.isPasswordProtected()});
|
||||
|
@ -1051,8 +964,7 @@ Example returns:
|
|||
exports.listAuthorsOfPad = function(padID, callback)
|
||||
{
|
||||
// get the pad
|
||||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
getPadSafe(padID, true, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
callback(null, {authorIDs: pad.getAllAuthors()});
|
||||
|
@ -1116,9 +1028,9 @@ Example returns:
|
|||
exports.getChatHead = function(padID, callback)
|
||||
{
|
||||
// get the pad
|
||||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
getPadSafe(padID, true, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
callback(null, {chatHead: pad.chatHead});
|
||||
});
|
||||
}
|
||||
|
@ -1132,12 +1044,10 @@ Example returns:
|
|||
{"code":4,"message":"no or wrong API Key","data":null}
|
||||
*/
|
||||
exports.createDiffHTML = function(padID, startRev, endRev, callback) {
|
||||
//check if rev is a number
|
||||
if(startRev !== undefined && typeof startRev != "number")
|
||||
{
|
||||
// check if startRev is a number
|
||||
if (startRev !== undefined && typeof startRev != "number") {
|
||||
// try to parse the number
|
||||
if(isNaN(parseInt(startRev)))
|
||||
{
|
||||
if (isNaN(parseInt(startRev))) {
|
||||
callback({stop: "startRev is not a number"});
|
||||
return;
|
||||
}
|
||||
|
@ -1145,12 +1055,10 @@ exports.createDiffHTML = function(padID, startRev, endRev, callback){
|
|||
startRev = parseInt(startRev, 10);
|
||||
}
|
||||
|
||||
//check if rev is a number
|
||||
if(endRev !== undefined && typeof endRev != "number")
|
||||
{
|
||||
// check if endRev is a number
|
||||
if (endRev !== undefined && typeof endRev != "number") {
|
||||
// try to parse the number
|
||||
if(isNaN(parseInt(endRev)))
|
||||
{
|
||||
if (isNaN(parseInt(endRev))) {
|
||||
callback({stop: "endRev is not a number"});
|
||||
return;
|
||||
}
|
||||
|
@ -1159,8 +1067,7 @@ exports.createDiffHTML = function(padID, startRev, endRev, callback){
|
|||
}
|
||||
|
||||
// get the pad
|
||||
getPadSafe(padID, true, function(err, pad)
|
||||
{
|
||||
getPadSafe(padID, true, function(err, pad) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
@ -1212,44 +1119,35 @@ function is_int(value)
|
|||
// gets a pad safe
|
||||
function getPadSafe(padID, shouldExist, text, callback)
|
||||
{
|
||||
if(typeof text == "function")
|
||||
{
|
||||
if (typeof text == "function") {
|
||||
callback = text;
|
||||
text = null;
|
||||
}
|
||||
|
||||
// check if padID is a string
|
||||
if(typeof padID != "string")
|
||||
{
|
||||
if (typeof padID != "string") {
|
||||
callback(new customError("padID is not a string", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
// check if the padID maches the requirements
|
||||
if(!padManager.isValidPadId(padID))
|
||||
{
|
||||
if (!padManager.isValidPadId(padID)) {
|
||||
callback(new customError("padID did not match requirements", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
// check if the pad exists
|
||||
padManager.doesPadExists(padID, function(err, exists)
|
||||
{
|
||||
padManager.doesPadExists(padID, function(err, exists) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
// does not exist, but should
|
||||
if(exists == false && shouldExist == true)
|
||||
{
|
||||
if (exists == false && shouldExist == true) {
|
||||
callback(new customError("padID does not exist", "apierror"));
|
||||
}
|
||||
//does exists, but shouldn't
|
||||
else if(exists == true && shouldExist == false)
|
||||
{
|
||||
} else if (exists == true && shouldExist == false) {
|
||||
// does exist, but shouldn't
|
||||
callback(new customError("padID does already exist", "apierror"));
|
||||
}
|
||||
} else {
|
||||
// pad exists, let's get it
|
||||
else
|
||||
{
|
||||
padManager.getPad(padID, text, callback);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -18,14 +18,22 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
var ERR = require("async-stacktrace");
|
||||
var db = require("./DB").db;
|
||||
var customError = require("../utils/customError");
|
||||
var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString;
|
||||
|
||||
exports.getColorPalette = function() {
|
||||
return ["#ffc7c7", "#fff1c7", "#e3ffc7", "#c7ffd5", "#c7ffff", "#c7d5ff", "#e3c7ff", "#ffc7f1", "#ffa8a8", "#ffe699", "#cfff9e", "#99ffb3", "#a3ffff", "#99b3ff", "#cc99ff", "#ff99e5", "#e7b1b1", "#e9dcAf", "#cde9af", "#bfedcc", "#b1e7e7", "#c3cdee", "#d2b8ea", "#eec3e6", "#e9cece", "#e7e0ca", "#d3e5c7", "#bce1c5", "#c1e2e2", "#c1c9e2", "#cfc1e2", "#e0bdd9", "#baded3", "#a0f8eb", "#b1e7e0", "#c3c8e4", "#cec5e2", "#b1d5e7", "#cda8f0", "#f0f0a8", "#f2f2a6", "#f5a8eb", "#c5f9a9", "#ececbb", "#e7c4bc", "#daf0b2", "#b0a0fd", "#bce2e7", "#cce2bb", "#ec9afe", "#edabbd", "#aeaeea", "#c4e7b1", "#d722bb", "#f3a5e7", "#ffa8a8", "#d8c0c5", "#eaaedd", "#adc6eb", "#bedad1", "#dee9af", "#e9afc2", "#f8d2a0", "#b3b3e6"];
|
||||
return [
|
||||
"#ffc7c7", "#fff1c7", "#e3ffc7", "#c7ffd5", "#c7ffff", "#c7d5ff", "#e3c7ff", "#ffc7f1",
|
||||
"#ffa8a8", "#ffe699", "#cfff9e", "#99ffb3", "#a3ffff", "#99b3ff", "#cc99ff", "#ff99e5",
|
||||
"#e7b1b1", "#e9dcAf", "#cde9af", "#bfedcc", "#b1e7e7", "#c3cdee", "#d2b8ea", "#eec3e6",
|
||||
"#e9cece", "#e7e0ca", "#d3e5c7", "#bce1c5", "#c1e2e2", "#c1c9e2", "#cfc1e2", "#e0bdd9",
|
||||
"#baded3", "#a0f8eb", "#b1e7e0", "#c3c8e4", "#cec5e2", "#b1d5e7", "#cda8f0", "#f0f0a8",
|
||||
"#f2f2a6", "#f5a8eb", "#c5f9a9", "#ececbb", "#e7c4bc", "#daf0b2", "#b0a0fd", "#bce2e7",
|
||||
"#cce2bb", "#ec9afe", "#edabbd", "#aeaeea", "#c4e7b1", "#d722bb", "#f3a5e7", "#ffa8a8",
|
||||
"#d8c0c5", "#eaaedd", "#adc6eb", "#bedad1", "#dee9af", "#e9afc2", "#f8d2a0", "#b3b3e6"
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -34,9 +42,9 @@ exports.getColorPalette = function(){
|
|||
exports.doesAuthorExists = function(authorID, callback)
|
||||
{
|
||||
// check if the database entry of this author exists
|
||||
db.get("globalAuthor:" + authorID, function (err, author)
|
||||
{
|
||||
db.get("globalAuthor:" + authorID, function(err, author) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
callback(null, author != null);
|
||||
});
|
||||
}
|
||||
|
@ -48,9 +56,9 @@ exports.doesAuthorExists = function (authorID, callback)
|
|||
*/
|
||||
exports.getAuthor4Token = function(token, callback)
|
||||
{
|
||||
mapAuthorWithDBKey("token2author", token, function(err, author)
|
||||
{
|
||||
mapAuthorWithDBKey("token2author", token, function(err, author) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
// return only the sub value authorID
|
||||
callback(null, author ? author.authorID : author);
|
||||
});
|
||||
|
@ -64,13 +72,13 @@ exports.getAuthor4Token = function (token, callback)
|
|||
*/
|
||||
exports.createAuthorIfNotExistsFor = function(authorMapper, name, callback)
|
||||
{
|
||||
mapAuthorWithDBKey("mapper2author", authorMapper, function(err, author)
|
||||
{
|
||||
mapAuthorWithDBKey("mapper2author", authorMapper, function(err, author) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
if (name) {
|
||||
// set the name of this author
|
||||
if(name)
|
||||
exports.setAuthorName(author.authorID, name);
|
||||
}
|
||||
|
||||
// return the authorID
|
||||
callback(null, author);
|
||||
|
@ -87,15 +95,12 @@ exports.createAuthorIfNotExistsFor = function (authorMapper, name, callback)
|
|||
function mapAuthorWithDBKey (mapperkey, mapper, callback)
|
||||
{
|
||||
// try to map to an author
|
||||
db.get(mapperkey + ":" + mapper, function (err, author)
|
||||
{
|
||||
db.get(mapperkey + ":" + mapper, function(err, author) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
if (author == null) {
|
||||
// there is no author with this mapper, so create one
|
||||
if(author == null)
|
||||
{
|
||||
exports.createAuthor(null, function(err, author)
|
||||
{
|
||||
exports.createAuthor(null, function(err, author) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
// create the token2author relation
|
||||
|
@ -108,7 +113,7 @@ function mapAuthorWithDBKey (mapperkey, mapper, callback)
|
|||
return;
|
||||
}
|
||||
|
||||
//there is a author with this mapper
|
||||
// there is an author with this mapper
|
||||
// update the timestamp of this author
|
||||
db.setSub("globalAuthor:" + author, ["timestamp"], Date.now());
|
||||
|
||||
|
@ -127,7 +132,11 @@ exports.createAuthor = function(name, callback)
|
|||
var author = "a." + randomString(16);
|
||||
|
||||
// create the globalAuthors db entry
|
||||
var authorObj = {"colorId" : Math.floor(Math.random()*(exports.getColorPalette().length)), "name": name, "timestamp": Date.now()};
|
||||
var authorObj = {
|
||||
"colorId": Math.floor(Math.random() * (exports.getColorPalette().length)),
|
||||
"name": name,
|
||||
"timestamp": Date.now()
|
||||
};
|
||||
|
||||
// set the global author db entry
|
||||
db.set("globalAuthor:" + author, authorObj);
|
||||
|
@ -145,8 +154,6 @@ exports.getAuthor = function (author, callback)
|
|||
db.get("globalAuthor:" + author, callback);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the color Id of the author
|
||||
* @param {String} author The id of the author
|
||||
|
@ -200,27 +207,27 @@ exports.listPadsOfAuthor = function (authorID, callback)
|
|||
* (1) When the author is added to a pad, the author object is also updated
|
||||
* (2) When a pad is deleted, each author of that pad is also updated
|
||||
*/
|
||||
|
||||
// get the globalAuthor
|
||||
db.get("globalAuthor:" + authorID, function(err, author)
|
||||
{
|
||||
db.get("globalAuthor:" + authorID, function(err, author) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
//author does not exists
|
||||
if(author == null)
|
||||
{
|
||||
callback(new customError("authorID does not exist","apierror"))
|
||||
if (author == null) {
|
||||
// author does not exist
|
||||
callback(new customError("authorID does not exist", "apierror"));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// everything is fine, return the pad IDs
|
||||
var pads = [];
|
||||
if(author.padIDs != null)
|
||||
{
|
||||
for (var padId in author.padIDs)
|
||||
{
|
||||
|
||||
if (author.padIDs != null) {
|
||||
for (var padId in author.padIDs) {
|
||||
pads.push(padId);
|
||||
}
|
||||
}
|
||||
|
||||
callback(null, {padIDs: pads});
|
||||
});
|
||||
}
|
||||
|
@ -233,14 +240,12 @@ exports.listPadsOfAuthor = function (authorID, callback)
|
|||
exports.addPad = function(authorID, padID)
|
||||
{
|
||||
// get the entry
|
||||
db.get("globalAuthor:" + authorID, function(err, author)
|
||||
{
|
||||
db.get("globalAuthor:" + authorID, function(err, author) {
|
||||
if (ERR(err)) return;
|
||||
if (author == null) return;
|
||||
|
||||
if (author.padIDs == null) {
|
||||
// the entry doesn't exist so far, let's create it
|
||||
if(author.padIDs == null)
|
||||
{
|
||||
author.padIDs = {};
|
||||
}
|
||||
|
||||
|
@ -259,13 +264,11 @@ exports.addPad = function (authorID, padID)
|
|||
*/
|
||||
exports.removePad = function(authorID, padID)
|
||||
{
|
||||
db.get("globalAuthor:" + authorID, function (err, author)
|
||||
{
|
||||
db.get("globalAuthor:" + authorID, function(err, author) {
|
||||
if (ERR(err)) return;
|
||||
if (author == null) return;
|
||||
|
||||
if(author.padIDs != null)
|
||||
{
|
||||
if (author.padIDs != null) {
|
||||
// remove pad from author
|
||||
delete author.padIDs[padID];
|
||||
db.set("globalAuthor:" + authorID, author);
|
||||
|
|
|
@ -35,21 +35,16 @@ exports.db = null;
|
|||
* Initalizes the database with the settings provided by the settings module
|
||||
* @param {Function} callback
|
||||
*/
|
||||
exports.init = function(callback)
|
||||
{
|
||||
exports.init = function(callback) {
|
||||
// initalize the database async
|
||||
db.init(function(err)
|
||||
{
|
||||
db.init(function(err) {
|
||||
if (err) {
|
||||
// there was an error while initializing the database, output it and stop
|
||||
if(err)
|
||||
{
|
||||
console.error("ERROR: Problem while initalizing the database");
|
||||
console.error(err.stack ? err.stack : err);
|
||||
process.exit(1);
|
||||
}
|
||||
} else {
|
||||
// everything ok
|
||||
else
|
||||
{
|
||||
exports.db = db;
|
||||
callback(null);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
var ERR = require("async-stacktrace");
|
||||
var customError = require("../utils/customError");
|
||||
var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString;
|
||||
|
@ -31,9 +30,10 @@ exports.listAllGroups = function(callback) {
|
|||
db.get("groups", function (err, groups) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
// there are no groups
|
||||
if (groups == null) {
|
||||
// there are no groups
|
||||
callback(null, {groupIDs: []});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -51,16 +51,13 @@ exports.deleteGroup = function(groupID, callback)
|
|||
|
||||
async.series([
|
||||
// ensure group exists
|
||||
function (callback)
|
||||
{
|
||||
function (callback) {
|
||||
// try to get the group entry
|
||||
db.get("group:" + groupID, function (err, _group)
|
||||
{
|
||||
db.get("group:" + groupID, function (err, _group) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
if (_group == null) {
|
||||
// group does not exist
|
||||
if(_group == null)
|
||||
{
|
||||
callback(new customError("groupID does not exist", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
@ -70,33 +67,30 @@ exports.deleteGroup = function(groupID, callback)
|
|||
callback();
|
||||
});
|
||||
},
|
||||
//iterate trough all pads of this groups and delete them
|
||||
function(callback)
|
||||
{
|
||||
|
||||
// iterate through all pads of this group and delete them
|
||||
function(callback) {
|
||||
// collect all padIDs in an array, that allows us to use async.forEach
|
||||
var padIDs = [];
|
||||
for(var i in group.pads)
|
||||
{
|
||||
for(var i in group.pads) {
|
||||
padIDs.push(i);
|
||||
}
|
||||
|
||||
//loop trough all pads and delete them
|
||||
async.forEach(padIDs, function(padID, callback)
|
||||
{
|
||||
padManager.getPad(padID, function(err, pad)
|
||||
{
|
||||
// loop through all pads and delete them
|
||||
async.forEach(padIDs, function(padID, callback) {
|
||||
padManager.getPad(padID, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
pad.remove(callback);
|
||||
});
|
||||
}, callback);
|
||||
},
|
||||
//iterate trough group2sessions and delete all sessions
|
||||
|
||||
// iterate through group2sessions and delete all sessions
|
||||
function(callback)
|
||||
{
|
||||
// try to get the group entry
|
||||
db.get("group2sessions:" + groupID, function (err, group2sessions)
|
||||
{
|
||||
db.get("group2sessions:" + groupID, function (err, group2sessions) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
// skip if there is no group2sessions entry
|
||||
|
@ -104,41 +98,41 @@ exports.deleteGroup = function(groupID, callback)
|
|||
|
||||
// collect all sessions in an array, that allows us to use async.forEach
|
||||
var sessions = [];
|
||||
for(var i in group2sessions.sessionsIDs)
|
||||
{
|
||||
for (var i in group2sessions.sessionsIDs) {
|
||||
sessions.push(i);
|
||||
}
|
||||
|
||||
//loop trough all sessions and delete them
|
||||
async.forEach(sessions, function(session, callback)
|
||||
{
|
||||
// loop through all sessions and delete them
|
||||
async.forEach(sessions, function(session, callback) {
|
||||
sessionManager.deleteSession(session, callback);
|
||||
}, callback);
|
||||
});
|
||||
},
|
||||
|
||||
// remove group and group2sessions entry
|
||||
function(callback)
|
||||
{
|
||||
function(callback) {
|
||||
db.remove("group2sessions:" + groupID);
|
||||
db.remove("group:" + groupID);
|
||||
callback();
|
||||
},
|
||||
|
||||
// unlist the group
|
||||
function(callback)
|
||||
{
|
||||
function(callback) {
|
||||
exports.listAllGroups(function(err, groups) {
|
||||
if (ERR(err, callback)) return;
|
||||
groups = groups? groups.groupIDs : [];
|
||||
|
||||
// it's not listed
|
||||
if (groups.indexOf(groupID) == -1) {
|
||||
// it's not listed
|
||||
callback();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// remove from the list
|
||||
groups.splice(groups.indexOf(groupID), 1);
|
||||
|
||||
// store empty groupe list
|
||||
// store empty group list
|
||||
if (groups.length == 0) {
|
||||
db.set("groups", {});
|
||||
callback();
|
||||
|
@ -150,14 +144,15 @@ exports.deleteGroup = function(groupID, callback)
|
|||
async.forEach(groups, function(group, cb) {
|
||||
newGroups[group] = 1;
|
||||
cb();
|
||||
},function() {
|
||||
},
|
||||
function() {
|
||||
db.set("groups", newGroups);
|
||||
callback();
|
||||
});
|
||||
});
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
],
|
||||
function(err) {
|
||||
if (ERR(err, callback)) return;
|
||||
callback();
|
||||
});
|
||||
|
@ -166,8 +161,7 @@ exports.deleteGroup = function(groupID, callback)
|
|||
exports.doesGroupExist = function(groupID, callback)
|
||||
{
|
||||
// try to get the group entry
|
||||
db.get("group:" + groupID, function (err, group)
|
||||
{
|
||||
db.get("group:" + groupID, function (err, group) {
|
||||
if (ERR(err, callback)) return;
|
||||
callback(null, group != null);
|
||||
});
|
||||
|
@ -184,8 +178,8 @@ exports.createGroup = function(callback)
|
|||
// list the group
|
||||
exports.listAllGroups(function(err, groups) {
|
||||
if (ERR(err, callback)) return;
|
||||
groups = groups? groups.groupIDs : [];
|
||||
|
||||
groups = groups? groups.groupIDs : [];
|
||||
groups.push(groupID);
|
||||
|
||||
// regenerate group list
|
||||
|
@ -193,7 +187,8 @@ exports.createGroup = function(callback)
|
|||
async.forEach(groups, function(group, cb) {
|
||||
newGroups[group] = 1;
|
||||
cb();
|
||||
},function() {
|
||||
},
|
||||
function() {
|
||||
db.set("groups", newGroups);
|
||||
callback(null, {groupID: groupID});
|
||||
});
|
||||
|
@ -203,18 +198,15 @@ exports.createGroup = function(callback)
|
|||
exports.createGroupIfNotExistsFor = function(groupMapper, callback)
|
||||
{
|
||||
// ensure mapper is optional
|
||||
if(typeof groupMapper != "string")
|
||||
{
|
||||
if (typeof groupMapper != "string") {
|
||||
callback(new customError("groupMapper is no string", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
// try to get a group for this mapper
|
||||
db.get("mapper2group:"+groupMapper, function(err, groupID)
|
||||
{
|
||||
db.get("mapper2group:" + groupMapper, function(err, groupID) {
|
||||
function createGroupForMapper(cb) {
|
||||
exports.createGroup(function(err, responseObj)
|
||||
{
|
||||
exports.createGroup(function(err, responseObj) {
|
||||
if (ERR(err, cb)) return;
|
||||
|
||||
// create the mapper entry for this group
|
||||
|
@ -226,15 +218,16 @@ exports.createGroupIfNotExistsFor = function(groupMapper, callback)
|
|||
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
// there is a group for this mapper
|
||||
if (groupID) {
|
||||
// there is a group for this mapper
|
||||
exports.doesGroupExist(groupID, function(err, exists) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
if (exists) return callback(null, {groupID: groupID});
|
||||
|
||||
// hah, the returned group doesn't exist, let's create one
|
||||
createGroupForMapper(callback)
|
||||
})
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -251,15 +244,12 @@ exports.createGroupPad = function(groupID, padName, text, callback)
|
|||
|
||||
async.series([
|
||||
// ensure group exists
|
||||
function (callback)
|
||||
{
|
||||
exports.doesGroupExist(groupID, function(err, exists)
|
||||
{
|
||||
function (callback) {
|
||||
exports.doesGroupExist(groupID, function(err, exists) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
if (exists == false) {
|
||||
// group does not exist
|
||||
if(exists == false)
|
||||
{
|
||||
callback(new customError("groupID does not exist", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
@ -268,16 +258,14 @@ exports.createGroupPad = function(groupID, padName, text, callback)
|
|||
callback();
|
||||
});
|
||||
},
|
||||
//ensure pad does not exists
|
||||
function (callback)
|
||||
{
|
||||
padManager.doesPadExists(padID, function(err, exists)
|
||||
{
|
||||
|
||||
// ensure pad doesn't exist already
|
||||
function (callback) {
|
||||
padManager.doesPadExists(padID, function(err, exists) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
if (exists == true) {
|
||||
// pad exists already
|
||||
if(exists == true)
|
||||
{
|
||||
callback(new customError("padName does already exist", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
@ -286,45 +274,44 @@ exports.createGroupPad = function(groupID, padName, text, callback)
|
|||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
// create the pad
|
||||
function (callback)
|
||||
{
|
||||
padManager.getPad(padID, text, function(err)
|
||||
{
|
||||
function (callback) {
|
||||
padManager.getPad(padID, text, function(err) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
// create an entry in the group for this pad
|
||||
function (callback)
|
||||
{
|
||||
function (callback) {
|
||||
db.setSub("group:" + groupID, ["pads", padID], 1);
|
||||
callback();
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
],
|
||||
function(err) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
callback(null, {padID: padID});
|
||||
});
|
||||
}
|
||||
|
||||
exports.listPads = function(groupID, callback)
|
||||
{
|
||||
exports.doesGroupExist(groupID, function(err, exists)
|
||||
{
|
||||
exports.doesGroupExist(groupID, function(err, exists) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
//group does not exist
|
||||
if(exists == false)
|
||||
{
|
||||
// ensure the group exists
|
||||
if (exists == false) {
|
||||
callback(new customError("groupID does not exist", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
// group exists, let's get the pads
|
||||
db.getSub("group:" + groupID, ["pads"], function(err, result)
|
||||
{
|
||||
db.getSub("group:" + groupID, ["pads"], function(err, result) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
var pads = [];
|
||||
for ( var padId in result ) {
|
||||
pads.push(padId);
|
||||
|
|
|
@ -33,7 +33,6 @@ exports.cleanText = function (txt) {
|
|||
|
||||
|
||||
var Pad = function Pad(id) {
|
||||
|
||||
this.atext = Changeset.makeAText("\n");
|
||||
this.pool = new AttributePool();
|
||||
this.head = -1;
|
||||
|
@ -74,8 +73,9 @@ Pad.prototype.getPublicStatus = function getPublicStatus() {
|
|||
};
|
||||
|
||||
Pad.prototype.appendRevision = function appendRevision(aChangeset, author) {
|
||||
if(!author)
|
||||
if (!author) {
|
||||
author = '';
|
||||
}
|
||||
|
||||
var newAText = Changeset.applyToAText(aChangeset, this.atext, this.pool);
|
||||
Changeset.copyAText(newAText, this.atext);
|
||||
|
@ -89,11 +89,11 @@ Pad.prototype.appendRevision = function appendRevision(aChangeset, author) {
|
|||
newRevData.meta.timestamp = Date.now();
|
||||
|
||||
// ex. getNumForAuthor
|
||||
if(author != '')
|
||||
if (author != '') {
|
||||
this.pool.putAttrib(['author', author || '']);
|
||||
}
|
||||
|
||||
if(newRev % 100 == 0)
|
||||
{
|
||||
if (newRev % 100 == 0) {
|
||||
newRevData.meta.atext = this.atext;
|
||||
}
|
||||
|
||||
|
@ -101,8 +101,9 @@ Pad.prototype.appendRevision = function appendRevision(aChangeset, author) {
|
|||
this.saveToDatabase();
|
||||
|
||||
// set the author to pad
|
||||
if(author)
|
||||
if (author) {
|
||||
authorManager.addPad(author, this.id);
|
||||
}
|
||||
|
||||
if (this.head == 0) {
|
||||
hooks.callAll("padCreate", {'pad':this, 'author': author});
|
||||
|
@ -150,10 +151,8 @@ Pad.prototype.getRevisionDate = function getRevisionDate(revNum, callback) {
|
|||
Pad.prototype.getAllAuthors = function getAllAuthors() {
|
||||
var authors = [];
|
||||
|
||||
for(var key in this.pool.numToAttrib)
|
||||
{
|
||||
if(this.pool.numToAttrib[key][0] == "author" && this.pool.numToAttrib[key][1] != "")
|
||||
{
|
||||
for(var key in this.pool.numToAttrib) {
|
||||
if (this.pool.numToAttrib[key][0] == "author" && this.pool.numToAttrib[key][1] != "") {
|
||||
authors.push(this.pool.numToAttrib[key][1]);
|
||||
}
|
||||
}
|
||||
|
@ -171,22 +170,18 @@ Pad.prototype.getInternalRevisionAText = function getInternalRevisionAText(targe
|
|||
// find out which changesets are needed
|
||||
var neededChangesets = [];
|
||||
var curRev = keyRev;
|
||||
while (curRev < targetRev)
|
||||
{
|
||||
while (curRev < targetRev) {
|
||||
curRev++;
|
||||
neededChangesets.push(curRev);
|
||||
}
|
||||
|
||||
async.series([
|
||||
// get all needed data out of the database
|
||||
function(callback)
|
||||
{
|
||||
function(callback) {
|
||||
async.parallel([
|
||||
// get the atext of the key revision
|
||||
function (callback)
|
||||
{
|
||||
db.getSub("pad:"+_this.id+":revs:"+keyRev, ["meta", "atext"], function(err, _atext)
|
||||
{
|
||||
function (callback) {
|
||||
db.getSub("pad:" + _this.id + ":revs:" + keyRev, ["meta", "atext"], function(err, _atext) {
|
||||
if (ERR(err, callback)) return;
|
||||
try {
|
||||
atext = Changeset.cloneAText(_atext);
|
||||
|
@ -197,13 +192,11 @@ Pad.prototype.getInternalRevisionAText = function getInternalRevisionAText(targe
|
|||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
// get all needed changesets
|
||||
function (callback)
|
||||
{
|
||||
async.forEach(neededChangesets, function(item, callback)
|
||||
{
|
||||
_this.getRevisionChangeset(item, function(err, changeset)
|
||||
{
|
||||
function (callback) {
|
||||
async.forEach(neededChangesets, function(item, callback) {
|
||||
_this.getRevisionChangeset(item, function(err, changeset) {
|
||||
if (ERR(err, callback)) return;
|
||||
changesets[item] = changeset;
|
||||
callback();
|
||||
|
@ -212,14 +205,13 @@ Pad.prototype.getInternalRevisionAText = function getInternalRevisionAText(targe
|
|||
}
|
||||
], callback);
|
||||
},
|
||||
|
||||
// apply all changesets to the key changeset
|
||||
function(callback)
|
||||
{
|
||||
function(callback) {
|
||||
var apool = _this.apool();
|
||||
var curRev = keyRev;
|
||||
|
||||
while (curRev < targetRev)
|
||||
{
|
||||
while (curRev < targetRev) {
|
||||
curRev++;
|
||||
var cs = changesets[curRev];
|
||||
try {
|
||||
|
@ -231,8 +223,8 @@ Pad.prototype.getInternalRevisionAText = function getInternalRevisionAText(targe
|
|||
|
||||
callback(null);
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
],
|
||||
function(err) {
|
||||
if (ERR(err, callback)) return;
|
||||
callback(null, atext);
|
||||
});
|
||||
|
@ -252,12 +244,14 @@ Pad.prototype.getAllAuthorColors = function getAllAuthorColors(callback){
|
|||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
// colorId might be a hex color or an number out of the palette
|
||||
returnTable[author] = colorPalette[colorId] || colorId;
|
||||
|
||||
callback();
|
||||
});
|
||||
}, function(err){
|
||||
},
|
||||
function(err) {
|
||||
callback(err, returnTable);
|
||||
});
|
||||
};
|
||||
|
@ -266,14 +260,17 @@ Pad.prototype.getValidRevisionRange = function getValidRevisionRange(startRev, e
|
|||
startRev = parseInt(startRev, 10);
|
||||
var head = this.getHeadRevisionNumber();
|
||||
endRev = endRev ? parseInt(endRev, 10) : head;
|
||||
|
||||
if (isNaN(startRev) || startRev < 0 || startRev > head) {
|
||||
startRev = null;
|
||||
}
|
||||
|
||||
if (isNaN(endRev) || endRev < startRev) {
|
||||
endRev = null;
|
||||
} else if (endRev > head) {
|
||||
endRev = head;
|
||||
}
|
||||
|
||||
if (startRev !== null && endRev !== null) {
|
||||
return { startRev: startRev , endRev: endRev }
|
||||
}
|
||||
|
@ -334,35 +331,31 @@ Pad.prototype.getChatMessage = function getChatMessage(entryNum, callback) {
|
|||
|
||||
async.series([
|
||||
// get the chat entry
|
||||
function(callback)
|
||||
{
|
||||
db.get("pad:"+_this.id+":chat:"+entryNum, function(err, _entry)
|
||||
{
|
||||
function(callback) {
|
||||
db.get("pad:" + _this.id + ":chat:" + entryNum, function(err, _entry) {
|
||||
if (ERR(err, callback)) return;
|
||||
entry = _entry;
|
||||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
// add the authorName
|
||||
function(callback)
|
||||
{
|
||||
function(callback) {
|
||||
// this chat message doesn't exist, return null
|
||||
if(entry == null)
|
||||
{
|
||||
if (entry == null) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
// get the authorName
|
||||
authorManager.getAuthorName(entry.userId, function(err, authorName)
|
||||
{
|
||||
authorManager.getAuthorName(entry.userId, function(err, authorName) {
|
||||
if (ERR(err, callback)) return;
|
||||
entry.userName = authorName;
|
||||
callback();
|
||||
});
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
],
|
||||
function(err) {
|
||||
if (ERR(err, callback)) return;
|
||||
callback(null, entry);
|
||||
});
|
||||
|
@ -372,8 +365,7 @@ Pad.prototype.getChatMessages = 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++)
|
||||
{
|
||||
for (var i = start; i <= end; i++) {
|
||||
neededEntries.push({ entryNum: i, order: order });
|
||||
order++;
|
||||
}
|
||||
|
@ -382,29 +374,27 @@ Pad.prototype.getChatMessages = function getChatMessages(start, end, callback) {
|
|||
|
||||
// get all entries out of the database
|
||||
var entries = [];
|
||||
async.forEach(neededEntries, function(entryObject, callback)
|
||||
{
|
||||
_this.getChatMessage(entryObject.entryNum, function(err, entry)
|
||||
{
|
||||
async.forEach(neededEntries, function(entryObject, callback) {
|
||||
_this.getChatMessage(entryObject.entryNum, function(err, entry) {
|
||||
if (ERR(err, callback)) return;
|
||||
entries[entryObject.order] = entry;
|
||||
callback();
|
||||
});
|
||||
}, function(err)
|
||||
{
|
||||
},
|
||||
function(err) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
// sort out broken chat entries
|
||||
//it looks like in happend 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
|
||||
var cleanedEntries = [];
|
||||
for(var i=0;i<entries.length;i++)
|
||||
{
|
||||
if(entries[i]!=null)
|
||||
for (var i=0; i < entries.length; i++) {
|
||||
if (entries[i] != null) {
|
||||
cleanedEntries.push(entries[i]);
|
||||
else
|
||||
} else {
|
||||
console.warn("WARNING: Found broken chat entry in pad " + _this.id);
|
||||
}
|
||||
}
|
||||
|
||||
callback(null, cleanedEntries);
|
||||
});
|
||||
|
@ -414,20 +404,17 @@ Pad.prototype.init = function init(text, callback) {
|
|||
var _this = this;
|
||||
|
||||
// replace text with default text if text isn't set
|
||||
if(text == null)
|
||||
{
|
||||
if (text == null) {
|
||||
text = settings.defaultPadText;
|
||||
}
|
||||
|
||||
// try to load the pad
|
||||
db.get("pad:"+this.id, function(err, value)
|
||||
{
|
||||
db.get("pad:" + this.id, function(err, value) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
// if this pad exists, load it
|
||||
if(value != null)
|
||||
{
|
||||
//copy all attr. To a transfrom via fromJsonable if necassary
|
||||
if (value != null) {
|
||||
// copy all attr. To a transfrom via fromJsonable if necessary
|
||||
for (var attr in value) {
|
||||
if (jsonableList.indexOf(attr) !== -1) {
|
||||
_this[attr] = _this[attr].fromJsonable(value[attr]);
|
||||
|
@ -435,10 +422,8 @@ Pad.prototype.init = function init(text, callback) {
|
|||
_this[attr] = value[attr];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// this pad doesn't exist, so create it
|
||||
else
|
||||
{
|
||||
var firstChangeset = Changeset.makeSplice("\n", 0, 0, exports.cleanText(text));
|
||||
|
||||
_this.appendRevision(firstChangeset, '');
|
||||
|
@ -471,22 +456,18 @@ Pad.prototype.copy = function copy(destinationID, force, callback) {
|
|||
|
||||
async.series([
|
||||
// if it's a group pad, let's make sure the group exists.
|
||||
function(callback)
|
||||
{
|
||||
if (destinationID.indexOf("$") === -1)
|
||||
{
|
||||
function(callback) {
|
||||
if (destinationID.indexOf("$") === -1) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
destGroupID = destinationID.split("$")[0]
|
||||
groupManager.doesGroupExist(destGroupID, function (err, exists)
|
||||
{
|
||||
destGroupID = destinationID.split("$")[0];
|
||||
groupManager.doesGroupExist(destGroupID, function (err, exists) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
// group does not exist
|
||||
if(exists == false)
|
||||
{
|
||||
if (exists == false) {
|
||||
callback(new customError("groupID does not exist for destinationID", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
@ -495,25 +476,22 @@ Pad.prototype.copy = function copy(destinationID, force, callback) {
|
|||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
// if the pad exists, we should abort, unless forced.
|
||||
function(callback)
|
||||
{
|
||||
padManager.doesPadExists(destinationID, function (err, exists)
|
||||
{
|
||||
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))
|
||||
{
|
||||
if (!(exists == true)) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!force)
|
||||
{
|
||||
if (!force) {
|
||||
console.error("erroring out without force");
|
||||
callback(new customError("destinationID already exists", "apierror"));
|
||||
console.error("erroring out without force - after");
|
||||
|
@ -527,26 +505,24 @@ Pad.prototype.copy = function copy(destinationID, force, callback) {
|
|||
});
|
||||
});
|
||||
},
|
||||
|
||||
// copy the 'pad' entry
|
||||
function(callback)
|
||||
{
|
||||
function(callback) {
|
||||
db.get("pad:" + sourceID, function(err, pad) {
|
||||
db.set("pad:" + destinationID, pad);
|
||||
});
|
||||
|
||||
callback();
|
||||
},
|
||||
|
||||
// copy all relations
|
||||
function(callback)
|
||||
{
|
||||
function(callback) {
|
||||
async.parallel([
|
||||
// copy all chat messages
|
||||
function(callback)
|
||||
{
|
||||
function(callback) {
|
||||
var chatHead = _this.chatHead;
|
||||
|
||||
for(var i=0;i<=chatHead;i++)
|
||||
{
|
||||
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);
|
||||
|
@ -555,12 +531,11 @@ Pad.prototype.copy = function copy(destinationID, force, callback) {
|
|||
|
||||
callback();
|
||||
},
|
||||
|
||||
// copy all revisions
|
||||
function(callback)
|
||||
{
|
||||
function(callback) {
|
||||
var revHead = _this.head;
|
||||
for(var i=0;i<=revHead;i++)
|
||||
{
|
||||
for (var i=0; i <= revHead; i++) {
|
||||
db.get("pad:" + sourceID + ":revs:" + i, function (err, rev) {
|
||||
if (ERR(err, callback)) return;
|
||||
db.set("pad:" + destinationID + ":revs:" + i, rev);
|
||||
|
@ -569,12 +544,11 @@ Pad.prototype.copy = function copy(destinationID, force, callback) {
|
|||
|
||||
callback();
|
||||
},
|
||||
|
||||
// add the new pad to all authors who contributed to the old one
|
||||
function(callback)
|
||||
{
|
||||
function(callback) {
|
||||
var authorIDs = _this.getAllAuthors();
|
||||
authorIDs.forEach(function (authorID)
|
||||
{
|
||||
authorIDs.forEach(function (authorID) {
|
||||
authorManager.addPad(authorID, destinationID);
|
||||
});
|
||||
|
||||
|
@ -583,23 +557,27 @@ Pad.prototype.copy = function copy(destinationID, force, callback) {
|
|||
// parallel
|
||||
], callback);
|
||||
},
|
||||
|
||||
function(callback) {
|
||||
if (destGroupID) {
|
||||
// Group pad? Add it to the group's list
|
||||
if(destGroupID) db.setSub("group:" + destGroupID, ["pads", destinationID], 1);
|
||||
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)
|
||||
{
|
||||
],
|
||||
function(err) {
|
||||
if (ERR(err, callback)) return;
|
||||
callback(null, { padID: destinationID });
|
||||
});
|
||||
|
@ -614,14 +592,11 @@ Pad.prototype.remove = function remove(callback) {
|
|||
|
||||
async.series([
|
||||
// delete all relations
|
||||
function(callback)
|
||||
{
|
||||
function(callback) {
|
||||
async.parallel([
|
||||
// is it a group pad? -> delete the entry of this pad in the group
|
||||
function(callback)
|
||||
{
|
||||
if(padID.indexOf("$") === -1)
|
||||
{
|
||||
function(callback) {
|
||||
if (padID.indexOf("$") === -1) {
|
||||
// it isn't a group pad, nothing to do here
|
||||
callback();
|
||||
return;
|
||||
|
@ -630,8 +605,7 @@ Pad.prototype.remove = function remove(callback) {
|
|||
// it is a group pad
|
||||
var groupID = padID.substring(0, padID.indexOf("$"));
|
||||
|
||||
db.get("group:" + groupID, function (err, group)
|
||||
{
|
||||
db.get("group:" + groupID, function (err, group) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
// remove the pad entry
|
||||
|
@ -643,11 +617,10 @@ Pad.prototype.remove = function remove(callback) {
|
|||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
// remove the readonly entries
|
||||
function(callback)
|
||||
{
|
||||
readOnlyManager.getReadOnlyId(padID, function(err, readonlyID)
|
||||
{
|
||||
function(callback) {
|
||||
readOnlyManager.getReadOnlyId(padID, function(err, readonlyID) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
db.remove("pad2readonly:" + padID);
|
||||
|
@ -656,37 +629,34 @@ Pad.prototype.remove = function remove(callback) {
|
|||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
// delete all chat messages
|
||||
function(callback)
|
||||
{
|
||||
function(callback) {
|
||||
var chatHead = _this.chatHead;
|
||||
|
||||
for(var i=0;i<=chatHead;i++)
|
||||
{
|
||||
for (var i = 0; i <= chatHead; i++) {
|
||||
db.remove("pad:" + padID + ":chat:" + i);
|
||||
}
|
||||
|
||||
callback();
|
||||
},
|
||||
|
||||
// delete all revisions
|
||||
function(callback)
|
||||
{
|
||||
function(callback) {
|
||||
var revHead = _this.head;
|
||||
|
||||
for(var i=0;i<=revHead;i++)
|
||||
{
|
||||
for (var i = 0; i <= revHead; i++) {
|
||||
db.remove("pad:" + padID + ":revs:" + i);
|
||||
}
|
||||
|
||||
callback();
|
||||
},
|
||||
|
||||
// remove pad from all authors who contributed
|
||||
function(callback)
|
||||
{
|
||||
function(callback) {
|
||||
var authorIDs = _this.getAllAuthors();
|
||||
|
||||
authorIDs.forEach(function (authorID)
|
||||
{
|
||||
authorIDs.forEach(function (authorID) {
|
||||
authorManager.removePad(authorID, padID);
|
||||
});
|
||||
|
||||
|
@ -694,19 +664,20 @@ Pad.prototype.remove = function remove(callback) {
|
|||
}
|
||||
], callback);
|
||||
},
|
||||
|
||||
// delete the pad entry and delete pad from padManager
|
||||
function(callback)
|
||||
{
|
||||
function(callback) {
|
||||
padManager.removePad(padID);
|
||||
hooks.callAll("padRemove", { 'padID': padID });
|
||||
callback();
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
],
|
||||
function(err) {
|
||||
if (ERR(err, callback)) return;
|
||||
callback();
|
||||
});
|
||||
};
|
||||
|
||||
// set in db
|
||||
Pad.prototype.setPublicStatus = function setPublicStatus(publicStatus) {
|
||||
this.publicStatus = publicStatus;
|
||||
|
@ -753,19 +724,17 @@ Pad.prototype.getSavedRevisions = function getSavedRevisions() {
|
|||
|
||||
/* Crypto helper methods */
|
||||
|
||||
function hash(password, salt)
|
||||
{
|
||||
function hash(password, salt) {
|
||||
var shasum = crypto.createHash('sha512');
|
||||
shasum.update(password + salt);
|
||||
|
||||
return shasum.digest("hex") + "$" + salt;
|
||||
}
|
||||
|
||||
function generateSalt()
|
||||
{
|
||||
function generateSalt() {
|
||||
return randomString(86);
|
||||
}
|
||||
|
||||
function compare(hashStr, password)
|
||||
{
|
||||
function compare(hashStr, password) {
|
||||
return hash(password, hashStr.split("$")[1]) === hashStr;
|
||||
}
|
||||
|
|
|
@ -36,8 +36,7 @@ var db = require("./DB").db;
|
|||
*/
|
||||
var globalPads = {
|
||||
get: function(name) { return this[':'+name]; },
|
||||
set: function (name, value)
|
||||
{
|
||||
set: function(name, value) {
|
||||
this[':'+name] = value;
|
||||
},
|
||||
remove: function(name) {
|
||||
|
@ -54,24 +53,28 @@ var padList = {
|
|||
list: [],
|
||||
sorted : false,
|
||||
initiated: false,
|
||||
init: function(cb)
|
||||
{
|
||||
db.findKeys("pad:*", "*:*:*", function(err, dbData)
|
||||
{
|
||||
init: function(cb) {
|
||||
db.findKeys("pad:*", "*:*:*", function(err, dbData) {
|
||||
if (ERR(err, cb)) return;
|
||||
|
||||
if (dbData != null) {
|
||||
padList.initiated = true
|
||||
dbData.forEach(function(val) {
|
||||
padList.addPad(val.replace(/pad:/,""),false);
|
||||
});
|
||||
cb && cb()
|
||||
|
||||
cb && cb();
|
||||
}
|
||||
});
|
||||
|
||||
return this;
|
||||
},
|
||||
load: function(cb) {
|
||||
if(this.initiated) cb && cb()
|
||||
else this.init(cb)
|
||||
if (this.initiated) {
|
||||
cb && cb();
|
||||
} else {
|
||||
this.init(cb);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Returns all pads in alphabetical order as array.
|
||||
|
@ -82,28 +85,31 @@ var padList = {
|
|||
padList.list = padList.list.sort();
|
||||
padList.sorted = true;
|
||||
}
|
||||
|
||||
cb && cb(padList.list);
|
||||
})
|
||||
},
|
||||
addPad: function(name)
|
||||
{
|
||||
addPad: function(name) {
|
||||
if (!this.initiated) return;
|
||||
|
||||
if (this.list.indexOf(name) == -1) {
|
||||
this.list.push(name);
|
||||
this.sorted = false;
|
||||
}
|
||||
},
|
||||
removePad: function(name)
|
||||
{
|
||||
removePad: function(name) {
|
||||
if (!this.initiated) return;
|
||||
|
||||
var index = this.list.indexOf(name);
|
||||
|
||||
if (index > -1) {
|
||||
this.list.splice(index, 1);
|
||||
this.sorted = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
//initialises the allknowing data structure
|
||||
|
||||
// initialises the all-knowing data structure
|
||||
|
||||
/**
|
||||
* An array of padId transformations. These represent changes in pad name policy over
|
||||
|
@ -122,43 +128,41 @@ var padIdTransforms = [
|
|||
exports.getPad = function(id, text, callback)
|
||||
{
|
||||
// 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"));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// make text an optional parameter
|
||||
if(typeof text == "function")
|
||||
{
|
||||
if (typeof text == "function") {
|
||||
callback = text;
|
||||
text = null;
|
||||
}
|
||||
|
||||
// check if this is a valid text
|
||||
if(text != null)
|
||||
{
|
||||
if (text != null) {
|
||||
// check if text is a string
|
||||
if(typeof text != "string")
|
||||
{
|
||||
if (typeof text != "string") {
|
||||
callback(new customError("text is not a string", "apierror"));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// 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"));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var pad = globalPads.get(id);
|
||||
|
||||
//return pad if its already loaded
|
||||
if(pad != null)
|
||||
{
|
||||
// return pad if it's already loaded
|
||||
if (pad != null) {
|
||||
callback(null, pad);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -166,9 +170,9 @@ exports.getPad = function(id, text, callback)
|
|||
pad = new Pad(id);
|
||||
|
||||
// initalize the pad
|
||||
pad.init(text, function(err)
|
||||
{
|
||||
pad.init(text, function(err) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
globalPads.set(id, pad);
|
||||
padList.addPad(id);
|
||||
callback(null, pad);
|
||||
|
@ -185,14 +189,12 @@ exports.listAllPads = function(cb)
|
|||
// checks if a pad exists
|
||||
exports.doesPadExists = function(padId, callback)
|
||||
{
|
||||
db.get("pad:"+padId, function(err, value)
|
||||
{
|
||||
db.get("pad:" + padId, function(err, value) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
if (value != null && value.atext) {
|
||||
callback(null, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
callback(null, false);
|
||||
}
|
||||
});
|
||||
|
@ -201,29 +203,30 @@ exports.doesPadExists = function(padId, callback)
|
|||
// returns a sanitized padId, respecting legacy pad id formats
|
||||
exports.sanitizePadId = function(padId, callback) {
|
||||
var transform_index = arguments[2] || 0;
|
||||
|
||||
// we're out of possible transformations, so just return it
|
||||
if(transform_index >= padIdTransforms.length)
|
||||
{
|
||||
if (transform_index >= padIdTransforms.length) {
|
||||
callback(padId);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// check if padId exists
|
||||
exports.doesPadExists(padId, function(junk, exists)
|
||||
{
|
||||
if(exists)
|
||||
{
|
||||
exports.doesPadExists(padId, function(junk, exists) {
|
||||
if (exists) {
|
||||
callback(padId);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// get the next transformation *that's different*
|
||||
var transformedPadId = padId;
|
||||
while(transformedPadId == padId && transform_index < padIdTransforms.length)
|
||||
{
|
||||
|
||||
while(transformedPadId == padId && transform_index < padIdTransforms.length) {
|
||||
transformedPadId = padId.replace(padIdTransforms[transform_index][0], padIdTransforms[transform_index][1]);
|
||||
transform_index += 1;
|
||||
}
|
||||
|
||||
// check the next transform
|
||||
exports.sanitizePadId(transformedPadId, callback, transform_index);
|
||||
});
|
||||
|
|
|
@ -34,38 +34,35 @@ exports.getReadOnlyId = function (padId, callback)
|
|||
|
||||
async.waterfall([
|
||||
// check if there is a pad2readonly entry
|
||||
function(callback)
|
||||
{
|
||||
function(callback) {
|
||||
db.get("pad2readonly:" + padId, callback);
|
||||
},
|
||||
function(dbReadOnlyId, callback)
|
||||
{
|
||||
|
||||
function(dbReadOnlyId, callback) {
|
||||
if (dbReadOnlyId == null) {
|
||||
// there is no readOnly Entry in the database, let's create one
|
||||
if(dbReadOnlyId == null)
|
||||
{
|
||||
readOnlyId = "r." + randomString(16);
|
||||
|
||||
db.set("pad2readonly:" + padId, readOnlyId);
|
||||
db.set("readonly2pad:" + readOnlyId, padId);
|
||||
}
|
||||
} else {
|
||||
// there is a readOnly Entry in the database, let's take this one
|
||||
else
|
||||
{
|
||||
readOnlyId = dbReadOnlyId;
|
||||
}
|
||||
|
||||
callback();
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
],
|
||||
function(err) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
// return the results
|
||||
callback(null, readOnlyId);
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a the padId for a read only id
|
||||
* returns the padId for a read only id
|
||||
* @param {String} readOnlyId read only id
|
||||
*/
|
||||
exports.getPadId = function(readOnlyId, callback)
|
||||
|
@ -74,20 +71,21 @@ exports.getPadId = function(readOnlyId, callback)
|
|||
}
|
||||
|
||||
/**
|
||||
* returns a the padId and readonlyPadId in an object for any id
|
||||
* returns the padId and readonlyPadId in an object for any id
|
||||
* @param {String} padIdOrReadonlyPadId read only id or real pad id
|
||||
*/
|
||||
exports.getIds = function(id, callback) {
|
||||
if (id.indexOf("r.") == 0)
|
||||
if (id.indexOf("r.") == 0) {
|
||||
exports.getPadId(id, function (err, value) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
callback(null, {
|
||||
readOnlyPadId: id,
|
||||
padId: value, // Might be null, if this is an unknown read-only id
|
||||
readonly: true
|
||||
});
|
||||
});
|
||||
else
|
||||
} else {
|
||||
exports.getReadOnlyId(id, function (err, value) {
|
||||
callback(null, {
|
||||
readOnlyPadId: value,
|
||||
|
@ -96,3 +94,4 @@ exports.getIds = function(id, callback) {
|
|||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
var ERR = require("async-stacktrace");
|
||||
var async = require("async");
|
||||
var authorManager = require("./AuthorManager");
|
||||
|
@ -48,45 +47,43 @@ exports.checkAccess = function (padID, sessionCookie, token, password, callback)
|
|||
|
||||
// allow plugins to deny access
|
||||
var deniedByHook = hooks.callAll("onAccessCheck", {'padID': padID, 'password': password, 'token': token, 'sessionCookie': sessionCookie}).indexOf(false) > -1;
|
||||
if(deniedByHook)
|
||||
{
|
||||
if (deniedByHook) {
|
||||
callback(null, {accessStatus: "deny"});
|
||||
return;
|
||||
}
|
||||
|
||||
if (settings.requireSession) {
|
||||
// a valid session is required (api-only mode)
|
||||
if(settings.requireSession)
|
||||
{
|
||||
if (!sessionCookie) {
|
||||
// without sessionCookie, access is denied
|
||||
if(!sessionCookie)
|
||||
{
|
||||
callback(null, {accessStatus: "deny"});
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// a session is not required, so we'll check if it's a public pad
|
||||
else
|
||||
{
|
||||
if (padID.indexOf("$") == -1) {
|
||||
// it's not a group pad, means we can grant access
|
||||
if(padID.indexOf("$") == -1)
|
||||
{
|
||||
|
||||
// get author for this token
|
||||
authorManager.getAuthor4Token(token, function(err, author)
|
||||
{
|
||||
authorManager.getAuthor4Token(token, function(err, author) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
// assume user has access
|
||||
statusObject = { accessStatus: "grant", authorID: author };
|
||||
|
||||
if (settings.editOnly) {
|
||||
// user can't create pads
|
||||
if(settings.editOnly)
|
||||
{
|
||||
|
||||
// check if pad exists
|
||||
padManager.doesPadExists(padID, function(err, exists)
|
||||
{
|
||||
padManager.doesPadExists(padID, function(err, exists) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
if (!exists) {
|
||||
// pad doesn't exist - user can't have access
|
||||
if(!exists) statusObject.accessStatus = "deny";
|
||||
statusObject.accessStatus = "deny";
|
||||
}
|
||||
|
||||
// grant or deny access, with author of token
|
||||
callback(null, statusObject);
|
||||
});
|
||||
|
@ -115,38 +112,34 @@ exports.checkAccess = function (padID, sessionCookie, token, password, callback)
|
|||
|
||||
async.series([
|
||||
// get basic informations from the database
|
||||
function(callback)
|
||||
{
|
||||
function(callback) {
|
||||
async.parallel([
|
||||
//does pad exists
|
||||
function(callback)
|
||||
{
|
||||
padManager.doesPadExists(padID, function(err, exists)
|
||||
{
|
||||
// does pad exist
|
||||
function(callback) {
|
||||
padManager.doesPadExists(padID, function(err, exists) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
padExists = exists;
|
||||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
// get information about all sessions contained in this cookie
|
||||
function(callback)
|
||||
{
|
||||
if (!sessionCookie)
|
||||
{
|
||||
function(callback) {
|
||||
if (!sessionCookie) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
var sessionIDs = sessionCookie.split(',');
|
||||
async.forEach(sessionIDs, function(sessionID, callback)
|
||||
{
|
||||
sessionManager.getSessionInfo(sessionID, function(err, sessionInfo)
|
||||
{
|
||||
|
||||
async.forEach(sessionIDs, function(sessionID, callback) {
|
||||
sessionManager.getSessionInfo(sessionID, function(err, sessionInfo) {
|
||||
// skip session if it doesn't exist
|
||||
if(err && err.message == "sessionID does not exist")
|
||||
{
|
||||
if (err && err.message == "sessionID does not exist") {
|
||||
authLogger.debug("Auth failed: unknown session");
|
||||
callback();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -155,18 +148,18 @@ exports.checkAccess = function (padID, sessionCookie, token, password, callback)
|
|||
var now = Math.floor(Date.now()/1000);
|
||||
|
||||
// is it for this group?
|
||||
if(sessionInfo.groupID != groupID)
|
||||
{
|
||||
if (sessionInfo.groupID != groupID) {
|
||||
authLogger.debug("Auth failed: wrong group");
|
||||
callback();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// is validUntil still ok?
|
||||
if(sessionInfo.validUntil <= now)
|
||||
{
|
||||
if (sessionInfo.validUntil <= now) {
|
||||
authLogger.debug("Auth failed: validUntil");
|
||||
callback();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -178,31 +171,30 @@ exports.checkAccess = function (padID, sessionCookie, token, password, callback)
|
|||
});
|
||||
}, callback);
|
||||
},
|
||||
|
||||
// get author for token
|
||||
function(callback)
|
||||
{
|
||||
function(callback) {
|
||||
// get author for this token
|
||||
authorManager.getAuthor4Token(token, function(err, author)
|
||||
{
|
||||
authorManager.getAuthor4Token(token, function(err, author) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
tokenAuthor = author;
|
||||
callback();
|
||||
});
|
||||
}
|
||||
], callback);
|
||||
},
|
||||
|
||||
// get more informations of this pad, if avaiable
|
||||
function(callback)
|
||||
{
|
||||
//skip this if the pad doesn't exists
|
||||
if(padExists == false)
|
||||
{
|
||||
function(callback) {
|
||||
// skip this if the pad doesn't exist
|
||||
if (padExists == false) {
|
||||
callback();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
padManager.getPad(padID, function(err, pad)
|
||||
{
|
||||
padManager.getPad(padID, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
// is it a public pad?
|
||||
|
@ -212,108 +204,89 @@ exports.checkAccess = function (padID, sessionCookie, token, password, callback)
|
|||
isPasswordProtected = pad.isPasswordProtected();
|
||||
|
||||
// is password correct?
|
||||
if(isPasswordProtected && password && pad.isCorrectPassword(password))
|
||||
{
|
||||
if (isPasswordProtected && password && pad.isCorrectPassword(password)) {
|
||||
passwordStatus = "correct";
|
||||
}
|
||||
|
||||
callback();
|
||||
});
|
||||
},
|
||||
function(callback)
|
||||
{
|
||||
|
||||
function(callback) {
|
||||
if (validSession && padExists) {
|
||||
// - a valid session for this group is avaible AND pad exists
|
||||
if(validSession && padExists)
|
||||
{
|
||||
if (!isPasswordProtected) {
|
||||
// - the pad is not password protected
|
||||
if(!isPasswordProtected)
|
||||
{
|
||||
|
||||
// --> grant access
|
||||
statusObject = { accessStatus: "grant", authorID: sessionAuthor };
|
||||
}
|
||||
} else if (settings.sessionNoPassword) {
|
||||
// - the setting to bypass password validation is set
|
||||
else if(settings.sessionNoPassword)
|
||||
{
|
||||
|
||||
// --> grant access
|
||||
statusObject = { accessStatus: "grant", authorID: sessionAuthor };
|
||||
}
|
||||
} else if (isPasswordProtected && passwordStatus == "correct") {
|
||||
// - the pad is password protected and password is correct
|
||||
else if(isPasswordProtected && passwordStatus == "correct")
|
||||
{
|
||||
|
||||
// --> grant access
|
||||
statusObject = { accessStatus: "grant", authorID: sessionAuthor };
|
||||
}
|
||||
} else if (isPasswordProtected && passwordStatus == "wrong") {
|
||||
// - the pad is password protected but wrong password given
|
||||
else if(isPasswordProtected && passwordStatus == "wrong")
|
||||
{
|
||||
|
||||
// --> deny access, ask for new password and tell them that the password is wrong
|
||||
statusObject = { accessStatus: "wrongPassword" };
|
||||
}
|
||||
} else if (isPasswordProtected && passwordStatus == "notGiven") {
|
||||
// - the pad is password protected but no password given
|
||||
else if(isPasswordProtected && passwordStatus == "notGiven")
|
||||
{
|
||||
|
||||
// --> ask for password
|
||||
statusObject = { accessStatus: "needPassword" };
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
throw new Error("Ops, something wrong happend");
|
||||
}
|
||||
}
|
||||
//- a valid session for this group avaible but pad doesn't exists
|
||||
else if(validSession && !padExists)
|
||||
{
|
||||
} else if (validSession && !padExists) {
|
||||
// - a valid session for this group avaible but pad doesn't exist
|
||||
|
||||
// --> grant access
|
||||
statusObject = {accessStatus: "grant", authorID: sessionAuthor};
|
||||
|
||||
if (settings.editOnly) {
|
||||
// --> deny access if user isn't allowed to create the pad
|
||||
if(settings.editOnly)
|
||||
{
|
||||
authLogger.debug("Auth failed: valid session & pad does not exist");
|
||||
statusObject.accessStatus = "deny";
|
||||
}
|
||||
}
|
||||
} else if (!validSession && padExists) {
|
||||
// there is no valid session avaiable AND pad exists
|
||||
else if(!validSession && padExists)
|
||||
{
|
||||
//-- its public and not password protected
|
||||
if(isPublic && !isPasswordProtected)
|
||||
{
|
||||
|
||||
// -- it's public and not password protected
|
||||
if (isPublic && !isPasswordProtected) {
|
||||
// --> grant access, with author of token
|
||||
statusObject = {accessStatus: "grant", authorID: tokenAuthor};
|
||||
}
|
||||
//- its public and password protected and password is correct
|
||||
else if(isPublic && isPasswordProtected && passwordStatus == "correct")
|
||||
{
|
||||
} else if (isPublic && isPasswordProtected && passwordStatus == "correct") {
|
||||
// - it's public and password protected and password is correct
|
||||
|
||||
// --> grant access, with author of token
|
||||
statusObject = {accessStatus: "grant", authorID: tokenAuthor};
|
||||
}
|
||||
//- its public and the pad is password protected but wrong password given
|
||||
else if(isPublic && isPasswordProtected && passwordStatus == "wrong")
|
||||
{
|
||||
} else if (isPublic && isPasswordProtected && passwordStatus == "wrong") {
|
||||
// - it's public and the pad is password protected but wrong password given
|
||||
|
||||
// --> deny access, ask for new password and tell them that the password is wrong
|
||||
statusObject = {accessStatus: "wrongPassword"};
|
||||
}
|
||||
//- its public and the pad is password protected but no password given
|
||||
else if(isPublic && isPasswordProtected && passwordStatus == "notGiven")
|
||||
{
|
||||
} else if (isPublic && isPasswordProtected && passwordStatus == "notGiven") {
|
||||
// - it's public and the pad is password protected but no password given
|
||||
|
||||
// --> ask for password
|
||||
statusObject = {accessStatus: "needPassword"};
|
||||
}
|
||||
//- its not public
|
||||
else if(!isPublic)
|
||||
{
|
||||
} else if (!isPublic) {
|
||||
// - it's not public
|
||||
|
||||
authLogger.debug("Auth failed: invalid session & pad is not public");
|
||||
// --> deny access
|
||||
statusObject = {accessStatus: "deny"};
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
throw new Error("Ops, something wrong happend");
|
||||
}
|
||||
}
|
||||
// there is no valid session avaiable AND pad doesn't exists
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// there is no valid session avaiable AND pad doesn't exist
|
||||
authLogger.debug("Auth failed: invalid session & pad does not exist");
|
||||
// --> deny access
|
||||
statusObject = {accessStatus: "deny"};
|
||||
|
@ -321,9 +294,10 @@ exports.checkAccess = function (padID, sessionCookie, token, password, callback)
|
|||
|
||||
callback();
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
],
|
||||
function(err) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
callback(null, statusObject);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
var ERR = require("async-stacktrace");
|
||||
var customError = require("../utils/customError");
|
||||
var randomString = require("../utils/randomstring");
|
||||
|
@ -45,7 +44,7 @@ exports.createSession = function(groupID, authorID, validUntil, callback)
|
|||
var sessionID;
|
||||
|
||||
async.series([
|
||||
//check if group exists
|
||||
// check if the group exists
|
||||
function(callback)
|
||||
{
|
||||
groupMangager.doesGroupExist(groupID, function(err, exists)
|
||||
|
@ -53,36 +52,32 @@ exports.createSession = function(groupID, authorID, validUntil, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
|
||||
// group does not exist
|
||||
if(exists == false)
|
||||
{
|
||||
if (exists == false) {
|
||||
callback(new customError("groupID does not exist", "apierror"));
|
||||
}
|
||||
} else {
|
||||
// everything is fine, continue
|
||||
else
|
||||
{
|
||||
callback();
|
||||
}
|
||||
});
|
||||
},
|
||||
//check if author exists
|
||||
|
||||
// check if the author exists
|
||||
function(callback)
|
||||
{
|
||||
authorMangager.doesAuthorExists(authorID, function(err, exists)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
if (exists == false) {
|
||||
// author does not exist
|
||||
if(exists == false)
|
||||
{
|
||||
callback(new customError("authorID does not exist", "apierror"));
|
||||
}
|
||||
} else {
|
||||
// everything is fine, continue
|
||||
else
|
||||
{
|
||||
callback();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// check validUntil and create the session db entry
|
||||
function(callback)
|
||||
{
|
||||
|
@ -90,8 +85,7 @@ exports.createSession = function(groupID, authorID, validUntil, callback)
|
|||
if (typeof validUntil != "number")
|
||||
{
|
||||
// try to parse the number
|
||||
if(isNaN(parseInt(validUntil)))
|
||||
{
|
||||
if (isNaN(parseInt(validUntil))) {
|
||||
callback(new customError("validUntil is not a number", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
@ -99,23 +93,20 @@ exports.createSession = function(groupID, authorID, validUntil, callback)
|
|||
validUntil = parseInt(validUntil);
|
||||
}
|
||||
|
||||
//ensure this is not a negativ number
|
||||
if(validUntil < 0)
|
||||
{
|
||||
// ensure this is not a negative number
|
||||
if (validUntil < 0) {
|
||||
callback(new customError("validUntil is a negativ number", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
// ensure this is not a float value
|
||||
if(!is_int(validUntil))
|
||||
{
|
||||
if (!is_int(validUntil)) {
|
||||
callback(new customError("validUntil is a float value", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
// check if validUntil is in the future
|
||||
if(Math.floor(Date.now()/1000) > validUntil)
|
||||
{
|
||||
if (Math.floor(Date.now()/1000) > validUntil) {
|
||||
callback(new customError("validUntil is in the past", "apierror"));
|
||||
return;
|
||||
}
|
||||
|
@ -128,6 +119,7 @@ exports.createSession = function(groupID, authorID, validUntil, callback)
|
|||
|
||||
callback();
|
||||
},
|
||||
|
||||
// set the group2sessions entry
|
||||
function(callback)
|
||||
{
|
||||
|
@ -136,9 +128,8 @@ exports.createSession = function(groupID, authorID, validUntil, callback)
|
|||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
if (group2sessions == null || group2sessions.sessionIDs == null) {
|
||||
// the entry doesn't exist so far, let's create it
|
||||
if(group2sessions == null || group2sessions.sessionIDs == null)
|
||||
{
|
||||
group2sessions = {sessionIDs : {}};
|
||||
}
|
||||
|
||||
|
@ -151,6 +142,7 @@ exports.createSession = function(groupID, authorID, validUntil, callback)
|
|||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
// set the author2sessions entry
|
||||
function(callback)
|
||||
{
|
||||
|
@ -159,9 +151,8 @@ exports.createSession = function(groupID, authorID, validUntil, callback)
|
|||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
if (author2sessions == null || author2sessions.sessionIDs == null) {
|
||||
// the entry doesn't exist so far, let's create it
|
||||
if(author2sessions == null || author2sessions.sessionIDs == null)
|
||||
{
|
||||
author2sessions = {sessionIDs : {}};
|
||||
}
|
||||
|
||||
|
@ -190,14 +181,11 @@ exports.getSessionInfo = function(sessionID, callback)
|
|||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
//session does not exists
|
||||
if(session == null)
|
||||
{
|
||||
if (session == null) {
|
||||
// session does not exist
|
||||
callback(new customError("sessionID does not exist", "apierror"))
|
||||
}
|
||||
} else {
|
||||
// everything is fine, return the sessioninfos
|
||||
else
|
||||
{
|
||||
callback(null, session);
|
||||
}
|
||||
});
|
||||
|
@ -219,14 +207,11 @@ exports.deleteSession = function(sessionID, callback)
|
|||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
//session does not exists
|
||||
if(session == null)
|
||||
{
|
||||
if (session == null) {
|
||||
// session does not exist
|
||||
callback(new customError("sessionID does not exist", "apierror"))
|
||||
}
|
||||
//everything is fine, return the sessioninfos
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// everything is fine, use the sessioninfos
|
||||
authorID = session.authorID;
|
||||
groupID = session.groupID;
|
||||
|
||||
|
@ -234,6 +219,7 @@ exports.deleteSession = function(sessionID, callback)
|
|||
}
|
||||
});
|
||||
},
|
||||
|
||||
// get the group2sessions entry
|
||||
function(callback)
|
||||
{
|
||||
|
@ -244,6 +230,7 @@ exports.deleteSession = function(sessionID, callback)
|
|||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
// get the author2sessions entry
|
||||
function(callback)
|
||||
{
|
||||
|
@ -254,6 +241,7 @@ exports.deleteSession = function(sessionID, callback)
|
|||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
// remove the values from the database
|
||||
function(callback)
|
||||
{
|
||||
|
@ -287,14 +275,11 @@ exports.listSessionsOfGroup = function(groupID, callback)
|
|||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
if (exists == false) {
|
||||
// group does not exist
|
||||
if(exists == false)
|
||||
{
|
||||
callback(new customError("groupID does not exist", "apierror"));
|
||||
}
|
||||
} else {
|
||||
// everything is fine, continue
|
||||
else
|
||||
{
|
||||
listSessionsWithDBKey("group2sessions:" + groupID, callback);
|
||||
}
|
||||
});
|
||||
|
@ -306,20 +291,17 @@ exports.listSessionsOfAuthor = function(authorID, callback)
|
|||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
if (exists == false) {
|
||||
// group does not exist
|
||||
if(exists == false)
|
||||
{
|
||||
callback(new customError("authorID does not exist", "apierror"));
|
||||
}
|
||||
} else {
|
||||
// everything is fine, continue
|
||||
else
|
||||
{
|
||||
listSessionsWithDBKey("author2sessions:" + authorID, callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//this function is basicly the code listSessionsOfAuthor and listSessionsOfGroup has in common
|
||||
// this function is basically the code listSessionsOfAuthor and listSessionsOfGroup has in common
|
||||
function listSessionsWithDBKey (dbkey, callback)
|
||||
{
|
||||
var sessions;
|
||||
|
@ -335,6 +317,7 @@ function listSessionsWithDBKey (dbkey, callback)
|
|||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
function(callback)
|
||||
{
|
||||
// collect all sessionIDs in an arrary
|
||||
|
@ -344,17 +327,14 @@ function listSessionsWithDBKey (dbkey, callback)
|
|||
sessionIDs.push(i);
|
||||
}
|
||||
|
||||
//foreach trough the sessions and get the sessioninfos
|
||||
// iterate through the sessions and get the sessioninfos
|
||||
async.forEach(sessionIDs, function(sessionID, callback)
|
||||
{
|
||||
exports.getSessionInfo(sessionID, function(err, sessionInfo)
|
||||
{
|
||||
if (err == "apierror: sessionID does not exist")
|
||||
{
|
||||
if (err == "apierror: sessionID does not exist") {
|
||||
console.warn(`Found bad session ${sessionID} in ${dbkey}`);
|
||||
}
|
||||
else if(ERR(err, callback))
|
||||
{
|
||||
} else if(ERR(err, callback)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -373,5 +353,5 @@ function listSessionsWithDBKey (dbkey, callback)
|
|||
// checks if a number is an int
|
||||
function is_int(value)
|
||||
{
|
||||
return (parseFloat(value) == parseInt(value)) && !isNaN(value)
|
||||
return (parseFloat(value) == parseInt(value)) && !isNaN(value);
|
||||
}
|
||||
|
|
|
@ -15,9 +15,10 @@ SessionStore.prototype.__proto__ = Store.prototype;
|
|||
|
||||
SessionStore.prototype.get = function(sid, fn) {
|
||||
messageLogger.debug('GET ' + sid);
|
||||
|
||||
var self = this;
|
||||
db.get("sessionstorage:" + sid, function (err, sess)
|
||||
{
|
||||
|
||||
db.get("sessionstorage:" + sid, function(err, sess) {
|
||||
if (sess) {
|
||||
sess.cookie.expires = 'string' == typeof sess.cookie.expires ? new Date(sess.cookie.expires) : sess.cookie.expires;
|
||||
if (!sess.cookie.expires || new Date() < sess.cookie.expires) {
|
||||
|
@ -33,6 +34,7 @@ SessionStore.prototype.get = function(sid, fn){
|
|||
|
||||
SessionStore.prototype.set = function(sid, sess, fn) {
|
||||
messageLogger.debug('SET ' + sid);
|
||||
|
||||
db.set("sessionstorage:" + sid, sess);
|
||||
process.nextTick(function() {
|
||||
if (fn) fn();
|
||||
|
@ -41,6 +43,7 @@ SessionStore.prototype.set = function(sid, sess, fn){
|
|||
|
||||
SessionStore.prototype.destroy = function(sid, fn) {
|
||||
messageLogger.debug('DESTROY ' + sid);
|
||||
|
||||
db.remove("sessionstorage:" + sid);
|
||||
process.nextTick(function() {
|
||||
if (fn) fn();
|
||||
|
@ -49,7 +52,9 @@ SessionStore.prototype.destroy = function(sid, fn){
|
|||
|
||||
SessionStore.prototype.all = function(fn) {
|
||||
messageLogger.debug('ALL');
|
||||
|
||||
var sessions = [];
|
||||
|
||||
db.forEach(function(key, value) {
|
||||
if (key.substr(0,15) === "sessionstorage:") {
|
||||
sessions.push(value);
|
||||
|
@ -60,6 +65,7 @@ SessionStore.prototype.all = function(fn){
|
|||
|
||||
SessionStore.prototype.clear = function(fn) {
|
||||
messageLogger.debug('CLEAR');
|
||||
|
||||
db.forEach(function(key, value) {
|
||||
if (key.substr(0,15) === "sessionstorage:") {
|
||||
db.db.remove("session:" + key);
|
||||
|
@ -70,7 +76,9 @@ SessionStore.prototype.clear = function(fn){
|
|||
|
||||
SessionStore.prototype.length = function(fn) {
|
||||
messageLogger.debug('LENGTH');
|
||||
|
||||
var i = 0;
|
||||
|
||||
db.forEach(function(key, value) {
|
||||
if (key.substr(0,15) === "sessionstorage:") {
|
||||
i++;
|
||||
|
|
|
@ -32,13 +32,11 @@ var apiHandlerLogger = log4js.getLogger('APIHandler');
|
|||
//ensure we have an apikey
|
||||
var apikey = null;
|
||||
var apikeyFilename = absolutePaths.makeAbsolute(argv.apikey || "./APIKEY.txt");
|
||||
try
|
||||
{
|
||||
|
||||
try {
|
||||
apikey = fs.readFileSync(apikeyFilename,"utf8");
|
||||
apiHandlerLogger.info(`Api key file read from: "${apikeyFilename}"`);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
} catch(e) {
|
||||
apiHandlerLogger.info(`Api key file "${apikeyFilename}" not found. Creating with random contents.`);
|
||||
apikey = randomString(32);
|
||||
fs.writeFileSync(apikeyFilename,apikey,"utf8");
|
||||
|
@ -156,18 +154,16 @@ exports.handle = function(apiVersion, functionName, fields, req, res)
|
|||
{
|
||||
//check if this is a valid apiversion
|
||||
var isKnownApiVersion = false;
|
||||
for(var knownApiVersion in version)
|
||||
{
|
||||
if(knownApiVersion == apiVersion)
|
||||
{
|
||||
|
||||
for (var knownApiVersion in version) {
|
||||
if (knownApiVersion == apiVersion) {
|
||||
isKnownApiVersion = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// say goodbye if this is an unknown API version
|
||||
if(!isKnownApiVersion)
|
||||
{
|
||||
if (!isKnownApiVersion) {
|
||||
res.statusCode = 404;
|
||||
res.send({code: 3, message: "no such api version", data: null});
|
||||
return;
|
||||
|
@ -175,18 +171,16 @@ exports.handle = function(apiVersion, functionName, fields, req, res)
|
|||
|
||||
// check if this is a valid function name
|
||||
var isKnownFunctionname = false;
|
||||
for(var knownFunctionname in version[apiVersion])
|
||||
{
|
||||
if(knownFunctionname == functionName)
|
||||
{
|
||||
|
||||
for (var knownFunctionname in version[apiVersion]) {
|
||||
if (knownFunctionname == functionName) {
|
||||
isKnownFunctionname = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//say goodbye if this is a unknown function
|
||||
if(!isKnownFunctionname)
|
||||
{
|
||||
// say goodbye if this is an unknown function
|
||||
if (!isKnownFunctionname) {
|
||||
res.send({code: 3, message: "no such function", data: null});
|
||||
return;
|
||||
}
|
||||
|
@ -194,32 +188,24 @@ exports.handle = function(apiVersion, functionName, fields, req, res)
|
|||
// check the api key!
|
||||
fields["apikey"] = fields["apikey"] || fields["api_key"];
|
||||
|
||||
if(fields["apikey"] != apikey.trim())
|
||||
{
|
||||
if (fields["apikey"] != apikey.trim()) {
|
||||
res.statusCode = 401;
|
||||
res.send({code: 4, message: "no or wrong API Key", data: null});
|
||||
return;
|
||||
}
|
||||
|
||||
//sanitize any pad id's before continuing
|
||||
if(fields["padID"])
|
||||
{
|
||||
padManager.sanitizePadId(fields["padID"], function(padId)
|
||||
{
|
||||
// sanitize any padIDs before continuing
|
||||
if (fields["padID"]) {
|
||||
padManager.sanitizePadId(fields["padID"], function(padId) {
|
||||
fields["padID"] = padId;
|
||||
callAPI(apiVersion, functionName, fields, req, res);
|
||||
});
|
||||
}
|
||||
else if(fields["padName"])
|
||||
{
|
||||
padManager.sanitizePadId(fields["padName"], function(padId)
|
||||
{
|
||||
} else if (fields["padName"]) {
|
||||
padManager.sanitizePadId(fields["padName"], function(padId) {
|
||||
fields["padName"] = padId;
|
||||
callAPI(apiVersion, functionName, fields, req, res);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
callAPI(apiVersion, functionName, fields, req, res);
|
||||
}
|
||||
}
|
||||
|
@ -230,27 +216,25 @@ function callAPI(apiVersion, functionName, fields, req, res)
|
|||
// put the function parameters in an array
|
||||
var functionParams = version[apiVersion][functionName].map(function (field) {
|
||||
return fields[field]
|
||||
})
|
||||
});
|
||||
|
||||
// add a callback function to handle the response
|
||||
functionParams.push(function(err, data)
|
||||
{
|
||||
// no error happend, everything is fine
|
||||
if(err == null)
|
||||
{
|
||||
if(!data)
|
||||
functionParams.push(function(err, data) {
|
||||
if (err == null) {
|
||||
// no error happened, everything is fine
|
||||
|
||||
if (!data) {
|
||||
data = null;
|
||||
}
|
||||
|
||||
res.send({code: 0, message: "ok", data: data});
|
||||
}
|
||||
} else if (err.name == "apierror") {
|
||||
// parameters were wrong and the api stopped execution, pass the error
|
||||
else if(err.name == "apierror")
|
||||
{
|
||||
|
||||
res.send({code: 1, message: err.message, data: null});
|
||||
}
|
||||
//an unknown error happend
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// an unknown error happened
|
||||
|
||||
res.send({code: 2, message: "internal error", data: null});
|
||||
ERR(err);
|
||||
}
|
||||
|
|
|
@ -32,13 +32,15 @@ var TidyHtml = require('../utils/TidyHtml');
|
|||
|
||||
var convertor = null;
|
||||
|
||||
//load abiword only if its enabled
|
||||
if(settings.abiword != null)
|
||||
// load abiword only if it is enabled
|
||||
if (settings.abiword != null) {
|
||||
convertor = require("../utils/Abiword");
|
||||
}
|
||||
|
||||
// Use LibreOffice if an executable has been defined in the settings
|
||||
if(settings.soffice != null)
|
||||
if (settings.soffice != null) {
|
||||
convertor = require("../utils/LibreOffice");
|
||||
}
|
||||
|
||||
const tempDirectory = os.tmpdir();
|
||||
|
||||
|
@ -53,7 +55,9 @@ exports.doExport = function(req, res, padId, type)
|
|||
hooks.aCallFirst("exportFileName", padId,
|
||||
function(err, hookFileName){
|
||||
// if fileName is set then set it to the padId, note that fileName is returned as an array.
|
||||
if(hookFileName.length) fileName = hookFileName;
|
||||
if (hookFileName.length) {
|
||||
fileName = hookFileName;
|
||||
}
|
||||
|
||||
// tell the browser that this is a downloadable file
|
||||
res.attachment(fileName + "." + type);
|
||||
|
@ -67,48 +71,39 @@ exports.doExport = function(req, res, padId, type)
|
|||
// return;
|
||||
}
|
||||
});
|
||||
}
|
||||
else if(type == "txt")
|
||||
{
|
||||
exporttxt.getPadTXTDocument(padId, req.params.rev, function(err, txt)
|
||||
{
|
||||
} else if (type == "txt") {
|
||||
exporttxt.getPadTXTDocument(padId, req.params.rev, function(err, txt) {
|
||||
if (!err) {
|
||||
res.send(txt);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
var html;
|
||||
var randNum;
|
||||
var srcFile, destFile;
|
||||
|
||||
async.series([
|
||||
// render the html document
|
||||
function(callback)
|
||||
{
|
||||
exporthtml.getPadHTMLDocument(padId, req.params.rev, function(err, _html)
|
||||
{
|
||||
function(callback) {
|
||||
exporthtml.getPadHTMLDocument(padId, req.params.rev, function(err, _html) {
|
||||
if (ERR(err, callback)) return;
|
||||
html = _html;
|
||||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
// decide what to do with the html export
|
||||
function(callback)
|
||||
{
|
||||
function(callback) {
|
||||
// if this is a html export, we can send this from here directly
|
||||
if(type == "html")
|
||||
{
|
||||
if (type == "html") {
|
||||
// do any final changes the plugin might want to make
|
||||
hooks.aCallFirst("exportHTMLSend", html, function(err, newHTML) {
|
||||
if (newHTML.length) html = newHTML;
|
||||
res.send(html);
|
||||
callback("stop");
|
||||
});
|
||||
}
|
||||
else //write the html export to a file
|
||||
{
|
||||
} else {
|
||||
// write the html export to a file
|
||||
randNum = Math.floor(Math.random()*0xFFFFFFFF);
|
||||
srcFile = tempDirectory + "/etherpad_export_" + randNum + ".html";
|
||||
fs.writeFile(srcFile, html, callback);
|
||||
|
@ -116,8 +111,7 @@ exports.doExport = function(req, res, padId, type)
|
|||
},
|
||||
|
||||
// Tidy up the exported HTML
|
||||
function(callback)
|
||||
{
|
||||
function(callback) {
|
||||
// ensure html can be collected by the garbage collector
|
||||
html = null;
|
||||
|
||||
|
@ -125,8 +119,7 @@ exports.doExport = function(req, res, padId, type)
|
|||
},
|
||||
|
||||
// send the convert job to the convertor (abiword, libreoffice, ..)
|
||||
function(callback)
|
||||
{
|
||||
function(callback) {
|
||||
destFile = tempDirectory + "/etherpad_export_" + randNum + "." + type;
|
||||
|
||||
// Allow plugins to overwrite the convert in export process
|
||||
|
@ -141,38 +134,32 @@ exports.doExport = function(req, res, padId, type)
|
|||
});
|
||||
|
||||
},
|
||||
|
||||
// send the file
|
||||
function(callback)
|
||||
{
|
||||
function(callback) {
|
||||
res.sendFile(destFile, null, callback);
|
||||
},
|
||||
|
||||
// clean up temporary files
|
||||
function(callback)
|
||||
{
|
||||
function(callback) {
|
||||
async.parallel([
|
||||
function(callback)
|
||||
{
|
||||
function(callback) {
|
||||
fs.unlink(srcFile, callback);
|
||||
},
|
||||
function(callback)
|
||||
{
|
||||
//100ms delay to accomidate for slow windows fs
|
||||
if(os.type().indexOf("Windows") > -1)
|
||||
{
|
||||
setTimeout(function()
|
||||
{
|
||||
function(callback) {
|
||||
// 100ms delay to accommodate for slow windows fs
|
||||
if (os.type().indexOf("Windows") > -1) {
|
||||
setTimeout(function() {
|
||||
fs.unlink(destFile, callback);
|
||||
}, 100);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
fs.unlink(destFile, callback);
|
||||
}
|
||||
}
|
||||
], callback);
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
],
|
||||
function(err) {
|
||||
if (err && err != "stop") ERR(err);
|
||||
})
|
||||
}
|
||||
|
|
|
@ -37,11 +37,12 @@ var ERR = require("async-stacktrace")
|
|||
var convertor = null;
|
||||
var exportExtension = "htm";
|
||||
|
||||
//load abiword only if its enabled and if soffice is disabled
|
||||
if(settings.abiword != null && settings.soffice === null)
|
||||
// load abiword only if it is enabled and if soffice is disabled
|
||||
if (settings.abiword != null && settings.soffice === null) {
|
||||
convertor = require("../utils/Abiword");
|
||||
}
|
||||
|
||||
//load soffice only if its enabled
|
||||
// load soffice only if it is enabled
|
||||
if (settings.soffice != null) {
|
||||
convertor = require("../utils/LibreOffice");
|
||||
exportExtension = "html";
|
||||
|
@ -80,9 +81,11 @@ exports.doImport = function(req, res, padId)
|
|||
form.uploadDir = tmpDirectory;
|
||||
|
||||
form.parse(req, function(err, fields, files) {
|
||||
//the upload failed, stop at this point
|
||||
if (err || files.file === undefined) {
|
||||
if(err) console.warn("Uploading Error: " + err.stack);
|
||||
// the upload failed, stop at this point
|
||||
if (err) {
|
||||
console.warn("Uploading Error: " + err.stack);
|
||||
}
|
||||
callback("uploadFailed");
|
||||
|
||||
return;
|
||||
|
@ -119,18 +122,21 @@ exports.doImport = function(req, res, padId)
|
|||
callback("uploadFailed");
|
||||
}
|
||||
},
|
||||
|
||||
function(callback) {
|
||||
destFile = path.join(tmpDirectory, "etherpad_import_" + randNum + "." + exportExtension);
|
||||
|
||||
// Logic for allowing external Import Plugins
|
||||
hooks.aCallAll("import", { srcFile: srcFile, destFile: destFile }, function(err, result) {
|
||||
if (ERR(err, callback)) return callback();
|
||||
|
||||
if (result.length > 0) { // This feels hacky and wrong..
|
||||
importHandledByPlugin = true;
|
||||
}
|
||||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
function(callback) {
|
||||
var fileEnding = path.extname(srcFile).toLowerCase()
|
||||
var fileIsNotEtherpad = (fileEnding !== ".etherpad");
|
||||
|
@ -145,7 +151,7 @@ exports.doImport = function(req, res, padId)
|
|||
padManager.getPad(padId, function(err, _pad) {
|
||||
var headCount = _pad.head;
|
||||
if (headCount >= 10) {
|
||||
apiLogger.warn("Direct database Import attempt of a pad that already has content, we wont be doing this")
|
||||
apiLogger.warn("Direct database Import attempt of a pad that already has content, we wont be doing this");
|
||||
return callback("padHasData");
|
||||
}
|
||||
|
||||
|
@ -157,7 +163,8 @@ exports.doImport = function(req, res, padId)
|
|||
});
|
||||
});
|
||||
},
|
||||
//convert file to html
|
||||
|
||||
// convert file to html if necessary
|
||||
function(callback) {
|
||||
if (importHandledByPlugin || directDatabaseAccess) {
|
||||
callback();
|
||||
|
@ -168,7 +175,9 @@ exports.doImport = function(req, res, padId)
|
|||
var fileEnding = path.extname(srcFile).toLowerCase();
|
||||
var fileIsHTML = (fileEnding === ".html" || fileEnding === ".htm");
|
||||
var fileIsTXT = (fileEnding === ".txt");
|
||||
|
||||
if (fileIsTXT) useConvertor = false; // Don't use convertor for text files
|
||||
|
||||
// See https://github.com/ether/etherpad-lite/issues/2572
|
||||
if (fileIsHTML || (useConvertor === false)) {
|
||||
// if no convertor only rename
|
||||
|
@ -257,20 +266,23 @@ exports.doImport = function(req, res, padId)
|
|||
var fileEnding = path.extname(srcFile).toLowerCase();
|
||||
if (importHandledByPlugin || useConvertor || fileEnding == ".htm" || fileEnding == ".html") {
|
||||
importHtml.setPadHTML(pad, text, function(e){
|
||||
if(e) apiLogger.warn("Error importing, possibly caused by malformed HTML");
|
||||
if (e) {
|
||||
apiLogger.warn("Error importing, possibly caused by malformed HTML");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
pad.setText(text);
|
||||
}
|
||||
}
|
||||
|
||||
// Load the Pad into memory then brodcast updates to all clients
|
||||
// Load the Pad into memory then broadcast updates to all clients
|
||||
padManager.unloadPad(padId);
|
||||
padManager.getPad(padId, function(err, _pad) {
|
||||
var pad = _pad;
|
||||
padManager.unloadPad(padId);
|
||||
|
||||
// direct Database Access means a pad user should perform a switchToPad
|
||||
// and not attempt to recieve updated pad data..
|
||||
// and not attempt to receive updated pad data
|
||||
if (directDatabaseAccess) {
|
||||
callback();
|
||||
|
||||
|
@ -310,8 +322,7 @@ exports.doImport = function(req, res, padId)
|
|||
var status = "ok";
|
||||
|
||||
// check for known errors and replace the status
|
||||
if(err == "uploadFailed" || err == "convertFailed" || err == "padHasData")
|
||||
{
|
||||
if (err == "uploadFailed" || err == "convertFailed" || err == "padHasData") {
|
||||
status = err;
|
||||
err = null;
|
||||
}
|
||||
|
@ -331,4 +342,3 @@ exports.doImport = function(req, res, padId)
|
|||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -57,16 +57,15 @@ exports.setSocketIO = function(_socket) {
|
|||
|
||||
socket.sockets.on('connection', function(client)
|
||||
{
|
||||
|
||||
// Broken: See http://stackoverflow.com/questions/4647348/send-message-to-specific-client-with-socket-io-and-node-js
|
||||
// Fixed by having a persistant object, ideally this would actually be in the database layer
|
||||
// TODO move to database layer
|
||||
if (settings.trustProxy && client.handshake.headers['x-forwarded-for'] !== undefined) {
|
||||
remoteAddress[client.id] = client.handshake.headers['x-forwarded-for'];
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
remoteAddress[client.id] = client.handshake.address;
|
||||
}
|
||||
|
||||
var clientAuthorized = false;
|
||||
|
||||
// wrap the original send function to log the messages
|
||||
|
@ -81,28 +80,27 @@ exports.setSocketIO = function(_socket) {
|
|||
components[i].handleConnect(client);
|
||||
}
|
||||
|
||||
client.on('message', function(message)
|
||||
{
|
||||
client.on('message', function(message) {
|
||||
if (message.protocolVersion && message.protocolVersion != 2) {
|
||||
messageLogger.warn("Protocolversion header is not correct:" + stringifyWithoutPassword(message));
|
||||
return;
|
||||
}
|
||||
|
||||
//client is authorized, everything ok
|
||||
if (clientAuthorized) {
|
||||
// client is authorized, everything ok
|
||||
handleMessage(client, message);
|
||||
} else { //try to authorize the client
|
||||
} else {
|
||||
// try to authorize the client
|
||||
if (message.padId !== undefined && message.sessionID !== undefined && message.token !== undefined && message.password !== undefined) {
|
||||
var checkAccessCallback = function(err, statusObject) {
|
||||
ERR(err);
|
||||
|
||||
//access was granted, mark the client as authorized and handle the message
|
||||
if (statusObject.accessStatus == "grant") {
|
||||
// access was granted, mark the client as authorized and handle the message
|
||||
clientAuthorized = true;
|
||||
handleMessage(client, message);
|
||||
}
|
||||
//no access, send the client a message that tell him why
|
||||
else {
|
||||
} else {
|
||||
// no access, send the client a message that tells him why
|
||||
messageLogger.warn("Authentication try failed:" + stringifyWithoutPassword(message));
|
||||
client.json.send({accessStatus: statusObject.accessStatus});
|
||||
}
|
||||
|
@ -116,17 +114,16 @@ exports.setSocketIO = function(_socket) {
|
|||
// this message has everything to try an authorization
|
||||
securityManager.checkAccess (message.padId, message.sessionID, message.token, message.password, checkAccessCallback);
|
||||
}
|
||||
} else { //drop message
|
||||
} else {
|
||||
// drop message
|
||||
messageLogger.warn("Dropped message cause of bad permissions:" + stringifyWithoutPassword(message));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
client.on('disconnect', function()
|
||||
{
|
||||
client.on('disconnect', function() {
|
||||
// tell all components about this disconnect
|
||||
for(var i in components)
|
||||
{
|
||||
for (var i in components) {
|
||||
components[i].handleDisconnect(client);
|
||||
}
|
||||
});
|
||||
|
@ -136,7 +133,6 @@ exports.setSocketIO = function(_socket) {
|
|||
// try to handle the message of this client
|
||||
function handleMessage(client, message)
|
||||
{
|
||||
|
||||
if (message.component && components[message.component]) {
|
||||
// check if component is registered in the components array
|
||||
if (components[message.component]) {
|
||||
|
@ -154,13 +150,13 @@ function stringifyWithoutPassword(message)
|
|||
{
|
||||
var newMessage = {};
|
||||
|
||||
for(var i in message)
|
||||
{
|
||||
if(i == "password" && message[i] != null)
|
||||
for (var i in message) {
|
||||
if (i == "password" && message[i] != null) {
|
||||
newMessage["password"] = "xxx";
|
||||
else
|
||||
} else {
|
||||
newMessage[i] = message[i];
|
||||
}
|
||||
}
|
||||
|
||||
return JSON.stringify(newMessage);
|
||||
}
|
||||
|
|
|
@ -13,31 +13,32 @@ exports.expressCreateServer = function (hook_name, args, cb) {
|
|||
search_results: {},
|
||||
errors: [],
|
||||
};
|
||||
|
||||
res.send(eejs.require("ep_etherpad-lite/templates/admin/plugins.html", render_args));
|
||||
});
|
||||
|
||||
args.app.get('/admin/plugins/info', function(req, res) {
|
||||
var gitCommit = settings.getGitCommit();
|
||||
var epVersion = settings.getEpVersion();
|
||||
res.send( eejs.require("ep_etherpad-lite/templates/admin/plugins-info.html",
|
||||
{
|
||||
|
||||
res.send(eejs.require("ep_etherpad-lite/templates/admin/plugins-info.html", {
|
||||
gitCommit: gitCommit,
|
||||
epVersion: epVersion
|
||||
})
|
||||
);
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
exports.socketio = function(hook_name, args, cb) {
|
||||
var io = args.io.of("/pluginfw/installer");
|
||||
io.on('connection', function(socket) {
|
||||
|
||||
if (!socket.conn.request.session || !socket.conn.request.session.user || !socket.conn.request.session.user.is_admin) return;
|
||||
|
||||
socket.on("getInstalled", function(query) {
|
||||
// send currently installed plugins
|
||||
var installed = Object.keys(plugins.plugins).map(function(plugin) {
|
||||
return plugins.plugins[plugin].package
|
||||
})
|
||||
});
|
||||
|
||||
socket.emit("results:installed", {installed: installed});
|
||||
});
|
||||
|
||||
|
@ -49,22 +50,27 @@ exports.socketio = function (hook_name, args, cb) {
|
|||
socket.emit("results:updatable", {updatable: {}});
|
||||
return;
|
||||
}
|
||||
|
||||
var updatable = _(plugins.plugins).keys().filter(function(plugin) {
|
||||
if (!results[plugin]) return false;
|
||||
var latestVersion = results[plugin].version
|
||||
var currentVersion = plugins.plugins[plugin].package.version
|
||||
return semver.gt(latestVersion, currentVersion)
|
||||
|
||||
var latestVersion = results[plugin].version;
|
||||
var currentVersion = plugins.plugins[plugin].package.version;
|
||||
|
||||
return semver.gt(latestVersion, currentVersion);
|
||||
});
|
||||
|
||||
socket.emit("results:updatable", {updatable: updatable});
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
socket.on("getAvailable", function(query) {
|
||||
installer.getAvailablePlugins(/*maxCacheAge:*/ false, function(er, results) {
|
||||
if (er) {
|
||||
console.error(er)
|
||||
results = {}
|
||||
console.error(er);
|
||||
results = {};
|
||||
}
|
||||
|
||||
socket.emit("results:available", results);
|
||||
});
|
||||
});
|
||||
|
@ -72,15 +78,16 @@ exports.socketio = function (hook_name, args, cb) {
|
|||
socket.on("search", function(query) {
|
||||
installer.search(query.searchTerm, /*maxCacheAge:*/ 60 * 10, function(er, results) {
|
||||
if (er) {
|
||||
console.error(er)
|
||||
results = {}
|
||||
console.error(er);
|
||||
results = {};
|
||||
}
|
||||
|
||||
var res = Object.keys(results)
|
||||
.map(function(pluginName) {
|
||||
return results[pluginName]
|
||||
return results[pluginName];
|
||||
})
|
||||
.filter(function(plugin) {
|
||||
return !plugins.plugins[plugin.name]
|
||||
return !plugins.plugins[plugin.name];
|
||||
});
|
||||
res = sortPluginList(res, query.sortBy, query.sortDir)
|
||||
.slice(query.offset, query.offset+query.limit);
|
||||
|
@ -90,14 +97,16 @@ exports.socketio = function (hook_name, args, cb) {
|
|||
|
||||
socket.on("install", function(plugin_name) {
|
||||
installer.install(plugin_name, function(er) {
|
||||
if(er) console.warn(er)
|
||||
if (er) console.warn(er);
|
||||
|
||||
socket.emit("finished:install", {plugin: plugin_name, code: er? er.code : null, error: er? er.message : null});
|
||||
});
|
||||
});
|
||||
|
||||
socket.on("uninstall", function(plugin_name) {
|
||||
installer.uninstall(plugin_name, function(er) {
|
||||
if(er) console.warn(er)
|
||||
if (er) console.warn(er);
|
||||
|
||||
socket.emit("finished:uninstall", {plugin: plugin_name, error: er? er.message : null});
|
||||
});
|
||||
});
|
||||
|
@ -106,11 +115,15 @@ exports.socketio = function (hook_name, args, cb) {
|
|||
|
||||
function sortPluginList(plugins, property, /*ASC?*/dir) {
|
||||
return plugins.sort(function(a, b) {
|
||||
if (a[property] < b[property])
|
||||
if (a[property] < b[property]) {
|
||||
return dir? -1 : 1;
|
||||
if (a[property] > b[property])
|
||||
}
|
||||
|
||||
if (a[property] > b[property]) {
|
||||
return dir? 1 : -1;
|
||||
}
|
||||
|
||||
// a must be equal to b
|
||||
return 0;
|
||||
})
|
||||
});
|
||||
}
|
||||
|
|
|
@ -12,7 +12,10 @@ exports.gracefulShutdown = function(err) {
|
|||
}
|
||||
|
||||
// ensure there is only one graceful shutdown running
|
||||
if(exports.onShutdown) return;
|
||||
if (exports.onShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
exports.onShutdown = true;
|
||||
|
||||
console.log("graceful shutdown...");
|
||||
|
@ -42,7 +45,7 @@ exports.expressCreateServer = function (hook_name, args, cb) {
|
|||
res.status(500).send({ error: 'Sorry, something bad happened!' });
|
||||
console.error(err.stack? err.stack : err.toString());
|
||||
stats.meter('http500').mark()
|
||||
})
|
||||
});
|
||||
|
||||
/*
|
||||
* Connect graceful shutdown with sigint and uncaught exception
|
||||
|
|
|
@ -24,8 +24,7 @@ exports.expressCreateServer = function (hook_name, args, cb) {
|
|||
|
||||
hasPadAccess(req, res, function() {
|
||||
console.log('req.params.pad', req.params.pad);
|
||||
padManager.doesPadExists(req.params.pad, function(err, exists)
|
||||
{
|
||||
padManager.doesPadExists(req.params.pad, function(err, exists) {
|
||||
if (!exists) {
|
||||
return next();
|
||||
}
|
||||
|
@ -38,8 +37,7 @@ exports.expressCreateServer = function (hook_name, args, cb) {
|
|||
// handle import requests
|
||||
args.app.post('/p/:pad/import', function(req, res, next) {
|
||||
hasPadAccess(req, res, function() {
|
||||
padManager.doesPadExists(req.params.pad, function(err, exists)
|
||||
{
|
||||
padManager.doesPadExists(req.params.pad, function(err, exists) {
|
||||
if (!exists) {
|
||||
return next();
|
||||
}
|
||||
|
|
|
@ -6,17 +6,14 @@ var exporthtml = require("../../utils/ExportHtml");
|
|||
|
||||
exports.expressCreateServer = function (hook_name, args, cb) {
|
||||
// serve read only pad
|
||||
args.app.get('/ro/:id', function(req, res)
|
||||
{
|
||||
args.app.get('/ro/:id', function(req, res) {
|
||||
var html;
|
||||
var padId;
|
||||
|
||||
async.series([
|
||||
// translate the read only pad to a padId
|
||||
function(callback)
|
||||
{
|
||||
readOnlyManager.getPadId(req.params.id, function(err, _padId)
|
||||
{
|
||||
function(callback) {
|
||||
readOnlyManager.getPadId(req.params.id, function(err, _padId) {
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
padId = _padId;
|
||||
|
@ -28,28 +25,24 @@ exports.expressCreateServer = function (hook_name, args, cb) {
|
|||
});
|
||||
},
|
||||
// render the html document
|
||||
function(callback)
|
||||
{
|
||||
function(callback) {
|
||||
// return if the there is no padId
|
||||
if(padId == null)
|
||||
{
|
||||
if(padId == null) {
|
||||
callback("notfound");
|
||||
return;
|
||||
}
|
||||
|
||||
hasPadAccess(req, res, function()
|
||||
{
|
||||
hasPadAccess(req, res, function() {
|
||||
// render the html document
|
||||
exporthtml.getPadHTMLDocument(padId, null, function(err, _html)
|
||||
{
|
||||
exporthtml.getPadHTMLDocument(padId, null, function(err, _html) {
|
||||
if(ERR(err, callback)) return;
|
||||
html = _html;
|
||||
callback();
|
||||
});
|
||||
});
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
],
|
||||
function(err) {
|
||||
// throw any unexpected error
|
||||
if(err && err != "notfound")
|
||||
ERR(err);
|
||||
|
|
|
@ -2,29 +2,26 @@ var padManager = require('../../db/PadManager');
|
|||
var url = require('url');
|
||||
|
||||
exports.expressCreateServer = function (hook_name, args, cb) {
|
||||
|
||||
// redirects browser to the pad's sanitized url if needed. otherwise, renders the html
|
||||
args.app.param('pad', function (req, res, next, padId) {
|
||||
// ensure the padname is valid and the url doesn't end with a /
|
||||
if(!padManager.isValidPadId(padId) || /\/$/.test(req.url))
|
||||
{
|
||||
if (!padManager.isValidPadId(padId) || /\/$/.test(req.url)) {
|
||||
res.status(404).send('Such a padname is forbidden');
|
||||
return;
|
||||
}
|
||||
|
||||
padManager.sanitizePadId(padId, function(sanitizedPadId) {
|
||||
if (sanitizedPadId != padId) {
|
||||
// the pad id was sanitized, so we redirect to the sanitized version
|
||||
if(sanitizedPadId != padId)
|
||||
{
|
||||
var real_url = sanitizedPadId;
|
||||
real_url = encodeURIComponent(real_url);
|
||||
var query = url.parse(req.url).query;
|
||||
if ( query ) real_url += '?' + query;
|
||||
res.header('Location', real_url);
|
||||
res.status(302).send('You should be redirected to <a href="' + real_url + '">' + real_url + '</a>');
|
||||
}
|
||||
} else {
|
||||
// the pad id was fine, so just render it
|
||||
else
|
||||
{
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -5,7 +5,6 @@ var path = require("path")
|
|||
|
||||
exports.expressCreateServer = function (hook_name, args, cb) {
|
||||
args.app.get('/tests/frontend/specs_list.js', function(req, res) {
|
||||
|
||||
async.parallel({
|
||||
coreSpecs: function(callback) {
|
||||
exports.getCoreTests(callback);
|
||||
|
@ -20,10 +19,8 @@ exports.expressCreateServer = function (hook_name, args, cb) {
|
|||
console.debug("Sent browser the following test specs:", files.sort());
|
||||
res.send("var specs_list = " + JSON.stringify(files.sort()) + ";\n");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
// path.join seems to normalize by default, but we'll just be explicit
|
||||
var rootTestFolder = path.normalize(path.join(npm.root, "../tests/frontend/"));
|
||||
|
||||
|
@ -35,6 +32,7 @@ exports.expressCreateServer = function (hook_name, args, cb) {
|
|||
subPath = subPath.split("?")[0];
|
||||
|
||||
var filePath = path.normalize(path.join(rootTestFolder, subPath));
|
||||
|
||||
// make sure we jail the paths to the test folder, otherwise serve index
|
||||
if (filePath.indexOf(rootTestFolder) !== 0) {
|
||||
filePath = path.join(rootTestFolder, "index.html");
|
||||
|
@ -69,9 +67,11 @@ exports.getPluginTests = function(callback){
|
|||
var pluginSpecs = [];
|
||||
var plugins = fs.readdirSync('node_modules');
|
||||
plugins.forEach(function(plugin) {
|
||||
if(fs.existsSync("node_modules/"+plugin+"/static/tests/frontend/specs")){ // if plugins exists
|
||||
if (fs.existsSync("node_modules/" + plugin + "/static/tests/frontend/specs")) {
|
||||
// if plugins exists
|
||||
var specFiles = fs.readdirSync("node_modules/" + plugin + "/static/tests/frontend/specs/");
|
||||
async.forEach(specFiles, function(spec){ // for each specFile push it to pluginSpecs
|
||||
async.forEach(specFiles, function(spec) {
|
||||
// for each specFile push it to pluginSpecs
|
||||
pluginSpecs.push("/static/plugins/" + plugin + "/static/tests/frontend/specs/" + spec);
|
||||
},
|
||||
function(err) {
|
||||
|
@ -83,9 +83,10 @@ exports.getPluginTests = function(callback){
|
|||
}
|
||||
|
||||
exports.getCoreTests = function(callback) {
|
||||
fs.readdir('tests/frontend/specs', function(err, coreSpecs){ // get the core test specs
|
||||
// get the core test specs
|
||||
fs.readdir('tests/frontend/specs', function(err, coreSpecs) {
|
||||
if (err) { return res.send(500); }
|
||||
|
||||
callback(null, coreSpecs);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -6,11 +6,11 @@ module.exports = function (req, res, callback) {
|
|||
securityManager.checkAccess(req.params.pad, req.cookies.sessionID, req.cookies.token, req.cookies.password, function(err, accessObj) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
//there is access, continue
|
||||
if (accessObj.accessStatus == "grant") {
|
||||
// there is access, continue
|
||||
callback();
|
||||
//no access
|
||||
} else {
|
||||
// no access
|
||||
res.status(403).send("403 - Can't touch this");
|
||||
}
|
||||
});
|
||||
|
|
|
@ -46,8 +46,8 @@ NodeVersion.enforceMinNodeVersion('8.9.0');
|
|||
*/
|
||||
var stats = require('./stats');
|
||||
stats.gauge('memoryUsage', function() {
|
||||
return process.memoryUsage().rss
|
||||
})
|
||||
return process.memoryUsage().rss;
|
||||
});
|
||||
|
||||
var settings
|
||||
, db
|
||||
|
@ -59,8 +59,8 @@ async.waterfall([
|
|||
// load npm
|
||||
function(callback) {
|
||||
npm.load({}, function(er) {
|
||||
callback(er)
|
||||
})
|
||||
callback(er);
|
||||
});
|
||||
},
|
||||
|
||||
// load everything
|
||||
|
@ -74,13 +74,12 @@ async.waterfall([
|
|||
},
|
||||
|
||||
// initalize the database
|
||||
function (callback)
|
||||
{
|
||||
function (callback) {
|
||||
db.init(callback);
|
||||
},
|
||||
|
||||
function(callback) {
|
||||
plugins.update(callback)
|
||||
plugins.update(callback);
|
||||
},
|
||||
|
||||
function (callback) {
|
||||
|
@ -94,8 +93,7 @@ async.waterfall([
|
|||
},
|
||||
|
||||
// initalize the http server
|
||||
function (callback)
|
||||
{
|
||||
function (callback) {
|
||||
hooks.callAll("createServer", {});
|
||||
callback(null);
|
||||
}
|
||||
|
|
|
@ -30,40 +30,32 @@ function getPadTXT(pad, revNum, callback)
|
|||
var atext = pad.atext;
|
||||
var html;
|
||||
async.waterfall([
|
||||
|
||||
// fetch revision atext
|
||||
|
||||
|
||||
function (callback)
|
||||
{
|
||||
if (revNum != undefined)
|
||||
{
|
||||
pad.getInternalRevisionAText(revNum, function (err, revisionAtext)
|
||||
{
|
||||
function(callback) {
|
||||
if (revNum != undefined) {
|
||||
pad.getInternalRevisionAText(revNum, function(err, revisionAtext) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
atext = revisionAtext;
|
||||
callback();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
callback(null);
|
||||
}
|
||||
},
|
||||
|
||||
// convert atext to html
|
||||
|
||||
|
||||
function (callback)
|
||||
{
|
||||
html = getTXTFromAtext(pad, atext); // only this line is different to the HTML function
|
||||
function(callback) {
|
||||
// only this line is different to the HTML function
|
||||
html = getTXTFromAtext(pad, atext);
|
||||
callback(null);
|
||||
}],
|
||||
|
||||
// run final callback
|
||||
|
||||
|
||||
function (err)
|
||||
{
|
||||
function(err) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
callback(null, html);
|
||||
});
|
||||
}
|
||||
|
@ -80,17 +72,14 @@ function getTXTFromAtext(pad, atext, authorColors)
|
|||
var anumMap = {};
|
||||
var css = "";
|
||||
|
||||
props.forEach(function (propName, i)
|
||||
{
|
||||
props.forEach(function(propName, i) {
|
||||
var propTrueNum = apool.putAttrib([propName, true], true);
|
||||
if (propTrueNum >= 0)
|
||||
{
|
||||
if (propTrueNum >= 0) {
|
||||
anumMap[propTrueNum] = i;
|
||||
}
|
||||
});
|
||||
|
||||
function getLineTXT(text, attribs)
|
||||
{
|
||||
function getLineTXT(text, attribs) {
|
||||
var propVals = [false, false, false];
|
||||
var ENTER = 1;
|
||||
var STAY = 2;
|
||||
|
@ -106,94 +95,77 @@ function getTXTFromAtext(pad, atext, authorColors)
|
|||
|
||||
var idx = 0;
|
||||
|
||||
function processNextChars(numChars)
|
||||
{
|
||||
if (numChars <= 0)
|
||||
{
|
||||
function processNextChars(numChars) {
|
||||
if (numChars <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var iter = Changeset.opIterator(Changeset.subattribution(attribs, idx, idx + numChars));
|
||||
idx += numChars;
|
||||
|
||||
while (iter.hasNext())
|
||||
{
|
||||
while (iter.hasNext()) {
|
||||
var o = iter.next();
|
||||
var propChanged = false;
|
||||
Changeset.eachAttribNumber(o.attribs, function (a)
|
||||
{
|
||||
if (a in anumMap)
|
||||
{
|
||||
|
||||
Changeset.eachAttribNumber(o.attribs, function(a) {
|
||||
if (a in anumMap) {
|
||||
var i = anumMap[a]; // i = 0 => bold, etc.
|
||||
if (!propVals[i])
|
||||
{
|
||||
|
||||
if (!propVals[i]) {
|
||||
propVals[i] = ENTER;
|
||||
propChanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
propVals[i] = STAY;
|
||||
}
|
||||
}
|
||||
});
|
||||
for (var i = 0; i < propVals.length; i++)
|
||||
{
|
||||
if (propVals[i] === true)
|
||||
{
|
||||
|
||||
for (var i = 0; i < propVals.length; i++) {
|
||||
if (propVals[i] === true) {
|
||||
propVals[i] = LEAVE;
|
||||
propChanged = true;
|
||||
}
|
||||
else if (propVals[i] === STAY)
|
||||
{
|
||||
propVals[i] = true; // set it back
|
||||
} else if (propVals[i] === STAY) {
|
||||
// set it back
|
||||
propVals[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// now each member of propVal is in {false,LEAVE,ENTER,true}
|
||||
// according to what happens at start of span
|
||||
if (propChanged)
|
||||
{
|
||||
if (propChanged) {
|
||||
// leaving bold (e.g.) also leaves italics, etc.
|
||||
var left = false;
|
||||
for (var i = 0; i < propVals.length; i++)
|
||||
{
|
||||
|
||||
for (var i = 0; i < propVals.length; i++) {
|
||||
var v = propVals[i];
|
||||
if (!left)
|
||||
{
|
||||
if (v === LEAVE)
|
||||
{
|
||||
|
||||
if (!left) {
|
||||
if (v === LEAVE) {
|
||||
left = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (v === true)
|
||||
{
|
||||
propVals[i] = STAY; // tag will be closed and re-opened
|
||||
} else {
|
||||
if (v === true) {
|
||||
// tag will be closed and re-opened
|
||||
propVals[i] = STAY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var tags2close = [];
|
||||
|
||||
for (var i = propVals.length - 1; i >= 0; i--)
|
||||
{
|
||||
if (propVals[i] === LEAVE)
|
||||
{
|
||||
for (var i = propVals.length - 1; i >= 0; i--) {
|
||||
if (propVals[i] === LEAVE) {
|
||||
//emitCloseTag(i);
|
||||
tags2close.push(i);
|
||||
propVals[i] = false;
|
||||
}
|
||||
else if (propVals[i] === STAY)
|
||||
{
|
||||
} else if (propVals[i] === STAY) {
|
||||
//emitCloseTag(i);
|
||||
tags2close.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < propVals.length; i++)
|
||||
{
|
||||
if (propVals[i] === ENTER || propVals[i] === STAY)
|
||||
{
|
||||
for (var i = 0; i < propVals.length; i++) {
|
||||
if (propVals[i] === ENTER || propVals[i] === STAY) {
|
||||
propVals[i] = true;
|
||||
}
|
||||
}
|
||||
|
@ -201,9 +173,9 @@ function getTXTFromAtext(pad, atext, authorColors)
|
|||
} // end if (propChanged)
|
||||
|
||||
var chars = o.chars;
|
||||
if (o.lines)
|
||||
{
|
||||
chars--; // exclude newline at end of line, if present
|
||||
if (o.lines) {
|
||||
// exclude newline at end of line, if present
|
||||
chars--;
|
||||
}
|
||||
|
||||
var s = taker.take(chars);
|
||||
|
@ -220,19 +192,19 @@ function getTXTFromAtext(pad, atext, authorColors)
|
|||
} // end iteration over spans in line
|
||||
|
||||
var tags2close = [];
|
||||
for (var i = propVals.length - 1; i >= 0; i--)
|
||||
{
|
||||
if (propVals[i])
|
||||
{
|
||||
for (var i = propVals.length - 1; i >= 0; i--) {
|
||||
if (propVals[i]) {
|
||||
tags2close.push(i);
|
||||
propVals[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
} // end processNextChars
|
||||
|
||||
processNextChars(text.length - idx);
|
||||
return(assem.toString());
|
||||
} // end getLineHTML
|
||||
|
||||
var pieces = [css];
|
||||
|
||||
// Need to deal with constraints imposed on HTML lists; can
|
||||
|
@ -242,22 +214,25 @@ function getTXTFromAtext(pad, atext, authorColors)
|
|||
// so we want to do something reasonable there. We also
|
||||
// want to deal gracefully with blank lines.
|
||||
// => keeps track of the parents level of indentation
|
||||
for (var i = 0; i < textLines.length; i++)
|
||||
{
|
||||
for (var i = 0; i < textLines.length; i++) {
|
||||
var line = _analyzeLine(textLines[i], attribLines[i], apool);
|
||||
var lineContent = getLineTXT(line.text, line.aline);
|
||||
|
||||
if (line.listTypeName == "bullet") {
|
||||
lineContent = "* " + lineContent; // add a bullet
|
||||
}
|
||||
|
||||
if (line.listLevel > 0) {
|
||||
for (var j = line.listLevel - 1; j >= 0; j--) {
|
||||
pieces.push('\t');
|
||||
}
|
||||
|
||||
if (line.listTypeName == "number") {
|
||||
pieces.push(line.listLevel + ". ");
|
||||
// This is bad because it doesn't truly reflect what the user
|
||||
// sees because browsers do magic on nested <ol><li>s
|
||||
}
|
||||
|
||||
pieces.push(lineContent, '\n');
|
||||
} else {
|
||||
pieces.push(lineContent, '\n');
|
||||
|
@ -266,17 +241,17 @@ function getTXTFromAtext(pad, atext, authorColors)
|
|||
|
||||
return pieces.join('');
|
||||
}
|
||||
|
||||
exports.getTXTFromAtext = getTXTFromAtext;
|
||||
|
||||
exports.getPadTXTDocument = function(padId, revNum, callback)
|
||||
{
|
||||
padManager.getPad(padId, function (err, pad)
|
||||
{
|
||||
padManager.getPad(padId, function(err, pad) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
getPadTXT(pad, revNum, function (err, html)
|
||||
{
|
||||
getPadTXT(pad, revNum, function(err, html) {
|
||||
if (ERR(err, callback)) return;
|
||||
|
||||
callback(null, html);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -18,26 +18,26 @@ var log4js = require('log4js');
|
|||
var async = require("async");
|
||||
var db = require("../db/DB").db;
|
||||
|
||||
exports.setPadRaw = function(padId, records, callback){
|
||||
exports.setPadRaw = function(padId, records, callback)
|
||||
{
|
||||
records = JSON.parse(records);
|
||||
|
||||
async.eachSeries(Object.keys(records), function(key, cb) {
|
||||
var value = records[key]
|
||||
var value = records[key];
|
||||
|
||||
if (!value) {
|
||||
return setImmediate(cb);
|
||||
}
|
||||
|
||||
// Author data
|
||||
if (value.padIDs) {
|
||||
// rewrite author pad ids
|
||||
// Author data - rewrite author pad ids
|
||||
value.padIDs[padId] = 1;
|
||||
var newKey = key;
|
||||
|
||||
// Does this author already exist?
|
||||
db.get(key, function(err, author) {
|
||||
if (author) {
|
||||
// Yes, add the padID to the author..
|
||||
// Yes, add the padID to the author
|
||||
if (Object.prototype.toString.call(author) === '[object Array]') {
|
||||
author.padIDs.push(padId);
|
||||
}
|
||||
|
@ -47,28 +47,27 @@ exports.setPadRaw = function(padId, records, callback){
|
|||
value.padIDs = [padId];
|
||||
}
|
||||
});
|
||||
|
||||
// Not author data, probably pad data
|
||||
} else {
|
||||
// we can split it to look to see if its pad data
|
||||
// Not author data, probably pad data
|
||||
// we can split it to look to see if it's pad data
|
||||
var oldPadId = key.split(":");
|
||||
|
||||
// we know its pad data..
|
||||
// we know it's pad data
|
||||
if (oldPadId[0] === "pad") {
|
||||
|
||||
// so set the new pad id for the author
|
||||
oldPadId[1] = padId;
|
||||
|
||||
// and create the value
|
||||
var newKey = oldPadId.join(":"); // create the new key
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Write the value to the server
|
||||
db.set(newKey, value);
|
||||
|
||||
setImmediate(cb);
|
||||
}, function(){
|
||||
},
|
||||
function() {
|
||||
callback(null, true);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -36,19 +36,22 @@ function setPadHTML(pad, html, callback)
|
|||
// Convert a dom tree into a list of lines and attribute liens
|
||||
// using the content collector object
|
||||
var cc = contentcollector.makeContentCollector(true, null, pad.pool);
|
||||
try{ // we use a try here because if the HTML is bad it will blow up
|
||||
try {
|
||||
// we use a try here because if the HTML is bad it will blow up
|
||||
cc.collectContent(doc);
|
||||
} catch(e) {
|
||||
apiLogger.warn("HTML was not properly formed", e);
|
||||
return callback(e); // We don't process the HTML because it was bad..
|
||||
|
||||
// don't process the HTML because it was bad
|
||||
return callback(e);
|
||||
}
|
||||
|
||||
var result = cc.finish();
|
||||
|
||||
apiLogger.debug('Lines:');
|
||||
|
||||
var i;
|
||||
for (i = 0; i < result.lines.length; i += 1)
|
||||
{
|
||||
for (i = 0; i < result.lines.length; i += 1) {
|
||||
apiLogger.debug('Line ' + (i + 1) + ' text: ' + result.lines[i]);
|
||||
apiLogger.debug('Line ' + (i + 1) + ' attributes: ' + result.lineAttribs[i]);
|
||||
}
|
||||
|
@ -59,18 +62,15 @@ function setPadHTML(pad, html, callback)
|
|||
apiLogger.debug(newText);
|
||||
var newAttribs = result.lineAttribs.join('|1+1') + '|1+1';
|
||||
|
||||
function eachAttribRun(attribs, func /*(startInNewText, endInNewText, attribs)*/ )
|
||||
{
|
||||
function eachAttribRun(attribs, func /*(startInNewText, endInNewText, attribs)*/ ) {
|
||||
var attribsIter = Changeset.opIterator(attribs);
|
||||
var textIndex = 0;
|
||||
var newTextStart = 0;
|
||||
var newTextEnd = newText.length;
|
||||
while (attribsIter.hasNext())
|
||||
{
|
||||
while (attribsIter.hasNext()) {
|
||||
var op = attribsIter.next();
|
||||
var nextIndex = textIndex + op.chars;
|
||||
if (!(nextIndex <= newTextStart || textIndex >= newTextEnd))
|
||||
{
|
||||
if (!(nextIndex <= newTextStart || textIndex >= newTextEnd)) {
|
||||
func(Math.max(newTextStart, textIndex), Math.min(newTextEnd, nextIndex), op.attribs);
|
||||
}
|
||||
textIndex = nextIndex;
|
||||
|
@ -81,13 +81,13 @@ function setPadHTML(pad, html, callback)
|
|||
var builder = Changeset.builder(1);
|
||||
|
||||
// assemble each line into the builder
|
||||
eachAttribRun(newAttribs, function(start, end, attribs)
|
||||
{
|
||||
eachAttribRun(newAttribs, function(start, end, attribs) {
|
||||
builder.insert(newText.substring(start, end), attribs);
|
||||
});
|
||||
|
||||
// the changeset is ready!
|
||||
var theChangeset = builder.toString();
|
||||
|
||||
apiLogger.debug('The changeset: ' + theChangeset);
|
||||
pad.setText("\n");
|
||||
pad.appendRevision(theChangeset);
|
||||
|
|
|
@ -4,15 +4,16 @@ var exportHtml = require('./ExportHtml');
|
|||
|
||||
function PadDiff (pad, fromRev, toRev) {
|
||||
// check parameters
|
||||
if(!pad || !pad.id || !pad.atext || !pad.pool)
|
||||
{
|
||||
if (!pad || !pad.id || !pad.atext || !pad.pool) {
|
||||
throw new Error('Invalid pad');
|
||||
}
|
||||
|
||||
var range = pad.getValidRevisionRange(fromRev, toRev);
|
||||
if(!range) { throw new Error('Invalid revision range.' +
|
||||
if (!range) {
|
||||
throw new Error('Invalid revision range.' +
|
||||
' startRev: ' + fromRev +
|
||||
' endRev: ' + toRev); }
|
||||
' endRev: ' + toRev);
|
||||
}
|
||||
|
||||
this._pad = pad;
|
||||
this._fromRev = range.startRev;
|
||||
|
@ -26,12 +27,14 @@ PadDiff.prototype._isClearAuthorship = function(changeset){
|
|||
var unpacked = Changeset.unpack(changeset);
|
||||
|
||||
// check if there is nothing in the charBank
|
||||
if(unpacked.charBank !== "")
|
||||
if (unpacked.charBank !== "") {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if oldLength == newLength
|
||||
if(unpacked.oldLen !== unpacked.newLen)
|
||||
if (unpacked.oldLen !== unpacked.newLen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// lets iterator over the operators
|
||||
var iterator = Changeset.opIterator(unpacked.ops);
|
||||
|
@ -40,17 +43,20 @@ PadDiff.prototype._isClearAuthorship = function(changeset){
|
|||
var clearOperator = iterator.next();
|
||||
|
||||
// check if there is only one operator
|
||||
if(iterator.hasNext() === true)
|
||||
if (iterator.hasNext() === true) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if this operator doesn't change text
|
||||
if(clearOperator.opcode !== "=")
|
||||
if (clearOperator.opcode !== "=") {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check that this operator applys to the complete text
|
||||
// if the text ends with a new line, its exactly one character less, else it has the same length
|
||||
if(clearOperator.chars !== unpacked.oldLen-1 && clearOperator.chars !== unpacked.oldLen)
|
||||
if (clearOperator.chars !== unpacked.oldLen-1 && clearOperator.chars !== unpacked.oldLen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var attributes = [];
|
||||
Changeset.eachAttribNumber(changeset, function(attrNum) {
|
||||
|
@ -58,14 +64,16 @@ PadDiff.prototype._isClearAuthorship = function(changeset){
|
|||
});
|
||||
|
||||
// check that this changeset uses only one attribute
|
||||
if(attributes.length !== 1)
|
||||
if (attributes.length !== 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var appliedAttribute = this._pad.pool.getAttrib(attributes[0]);
|
||||
|
||||
// check if the applied attribute is an anonymous author attribute
|
||||
if(appliedAttribute[0] !== "author" || appliedAttribute[1] !== "")
|
||||
if (appliedAttribute[0] !== "author" || appliedAttribute[1] !== "") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
@ -138,13 +146,15 @@ PadDiff.prototype._getChangesetsInBulk = function(startRev, count, callback) {
|
|||
|
||||
callback();
|
||||
});
|
||||
}, function(err){
|
||||
},
|
||||
function(err) {
|
||||
callback(err, changesets, authors);
|
||||
});
|
||||
};
|
||||
|
||||
PadDiff.prototype._addAuthors = function(authors) {
|
||||
var self = this;
|
||||
|
||||
// add to array if not in the array
|
||||
authors.forEach(function(author) {
|
||||
if (self._authors.indexOf(author) == -1) {
|
||||
|
@ -250,6 +260,7 @@ PadDiff.prototype.getHtml = function(callback){
|
|||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
// get the authorColor table
|
||||
function(callback) {
|
||||
self._pad.getAllAuthorColors(function(err, _authorColors) {
|
||||
|
@ -261,13 +272,15 @@ PadDiff.prototype.getHtml = function(callback){
|
|||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
// convert the atext to html
|
||||
function(callback) {
|
||||
html = exportHtml.getHTMLFromAtext(self._pad, atext, authorColors);
|
||||
self._html = html;
|
||||
callback();
|
||||
}
|
||||
], function(err){
|
||||
],
|
||||
function(err) {
|
||||
callback(err, html);
|
||||
});
|
||||
};
|
||||
|
@ -305,12 +318,11 @@ PadDiff.prototype._extendChangesetWithAuthor = function(changeset, author, apool
|
|||
while(iterator.hasNext()) {
|
||||
var operator = iterator.next();
|
||||
|
||||
//this is a delete operator, extend it with the author
|
||||
if (operator.opcode === "-") {
|
||||
// this is a delete operator, extend it with the author
|
||||
operator.attribs = attribs;
|
||||
}
|
||||
} else if (operator.opcode === "=" && operator.attribs) {
|
||||
// this is operator changes only attributes, let's mark which author did that
|
||||
else if(operator.opcode === "=" && operator.attribs){
|
||||
operator.attribs+="*"+Changeset.numToString(authorAttrib);
|
||||
}
|
||||
|
||||
|
@ -384,10 +396,13 @@ PadDiff.prototype._createDeletionChangeset = function(cs, startAText, apool) {
|
|||
curLineNextOp.chars = 0;
|
||||
curLineOpIter = Changeset.opIterator(alines_get(curLine));
|
||||
}
|
||||
|
||||
if (!curLineNextOp.chars) {
|
||||
curLineOpIter.next(curLineNextOp);
|
||||
}
|
||||
|
||||
var charsToUse = Math.min(numChars, curLineNextOp.chars);
|
||||
|
||||
func(charsToUse, curLineNextOp.attribs, charsToUse == curLineNextOp.chars && curLineNextOp.lines > 0);
|
||||
numChars -= charsToUse;
|
||||
curLineNextOp.chars -= charsToUse;
|
||||
|
@ -421,6 +436,7 @@ PadDiff.prototype._createDeletionChangeset = function(cs, startAText, apool) {
|
|||
assem.append(firstString);
|
||||
|
||||
var lineNum = curLine + 1;
|
||||
|
||||
while (len < numChars) {
|
||||
var nextString = lines_get(lineNum);
|
||||
len += nextString.length;
|
||||
|
@ -433,6 +449,7 @@ PadDiff.prototype._createDeletionChangeset = function(cs, startAText, apool) {
|
|||
|
||||
function cachedStrFunc(func) {
|
||||
var cache = {};
|
||||
|
||||
return function (s) {
|
||||
if (!cache[s]) {
|
||||
cache[s] = func(s);
|
||||
|
@ -474,10 +491,12 @@ PadDiff.prototype._createDeletionChangeset = function(cs, startAText, apool) {
|
|||
var appliedKey = attribKeys[i];
|
||||
var appliedValue = attribValues[i];
|
||||
var oldValue = Changeset.attribsAttributeValue(attribs, appliedKey, apool);
|
||||
|
||||
if (appliedValue != oldValue) {
|
||||
backAttribs.push([appliedKey, oldValue]);
|
||||
}
|
||||
}
|
||||
|
||||
return Changeset.makeAttribsString('=', backAttribs, apool);
|
||||
});
|
||||
|
||||
|
@ -501,6 +520,7 @@ PadDiff.prototype._createDeletionChangeset = function(cs, startAText, apool) {
|
|||
|
||||
// get the text we want to procceed in this step
|
||||
var processText = textLeftToProcess.substr(0, lengthToProcess);
|
||||
|
||||
textLeftToProcess = textLeftToProcess.substr(lengthToProcess);
|
||||
|
||||
if (lineBreak) {
|
||||
|
|
|
@ -6,8 +6,10 @@ var request = require("request");
|
|||
var npmIsLoaded = false;
|
||||
var withNpm = function(npmfn) {
|
||||
if (npmIsLoaded) return npmfn();
|
||||
|
||||
npm.load({}, function(er) {
|
||||
if (er) return npmfn(er);
|
||||
|
||||
npmIsLoaded = true;
|
||||
npm.on("log", function(message) {
|
||||
console.log('npm: ',message)
|
||||
|
@ -17,26 +19,33 @@ var withNpm = function (npmfn) {
|
|||
}
|
||||
|
||||
var tasks = 0
|
||||
|
||||
function wrapTaskCb(cb) {
|
||||
tasks++
|
||||
tasks++;
|
||||
|
||||
return function() {
|
||||
cb && cb.apply(this, arguments);
|
||||
tasks--;
|
||||
if (tasks == 0) onAllTasksFinished();
|
||||
}
|
||||
}
|
||||
|
||||
function onAllTasksFinished() {
|
||||
hooks.aCallAll("restartServer", {}, function() {});
|
||||
}
|
||||
|
||||
exports.uninstall = function(plugin_name, cb) {
|
||||
cb = wrapTaskCb(cb);
|
||||
|
||||
withNpm(function(er) {
|
||||
if (er) return cb && cb(er);
|
||||
|
||||
npm.commands.uninstall([plugin_name], function(er) {
|
||||
if (er) return cb && cb(er);
|
||||
|
||||
hooks.aCallAll("pluginUninstall", {plugin_name: plugin_name}, function(er, data) {
|
||||
if (er) return cb(er);
|
||||
|
||||
plugins.update(cb);
|
||||
});
|
||||
});
|
||||
|
@ -44,13 +53,17 @@ exports.uninstall = function(plugin_name, cb) {
|
|||
};
|
||||
|
||||
exports.install = function(plugin_name, cb) {
|
||||
cb = wrapTaskCb(cb)
|
||||
cb = wrapTaskCb(cb);
|
||||
|
||||
withNpm(function(er) {
|
||||
if (er) return cb && cb(er);
|
||||
|
||||
npm.commands.install([plugin_name], function(er) {
|
||||
if (er) return cb && cb(er);
|
||||
|
||||
hooks.aCallAll("pluginInstall", {plugin_name: plugin_name}, function(er, data) {
|
||||
if (er) return cb(er);
|
||||
|
||||
plugins.update(cb);
|
||||
});
|
||||
});
|
||||
|
@ -63,18 +76,22 @@ var cacheTimestamp = 0;
|
|||
exports.getAvailablePlugins = function(maxCacheAge, cb) {
|
||||
request("https://static.etherpad.org/plugins.json", function(er, response, plugins){
|
||||
if (er) return cb && cb(er);
|
||||
|
||||
if (exports.availablePlugins && maxCacheAge && Math.round(+ new Date / 1000) - cacheTimestamp <= maxCacheAge) {
|
||||
return cb && cb(null, exports.availablePlugins)
|
||||
return cb && cb(null, exports.availablePlugins);
|
||||
}
|
||||
|
||||
try {
|
||||
plugins = JSON.parse(plugins);
|
||||
} catch (err) {
|
||||
console.error('error parsing plugins.json:', err);
|
||||
plugins = [];
|
||||
}
|
||||
|
||||
exports.availablePlugins = plugins;
|
||||
cacheTimestamp = Math.round(+ new Date / 1000);
|
||||
cb && cb(null, plugins)
|
||||
|
||||
cb && cb(null, plugins);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -82,10 +99,15 @@ exports.getAvailablePlugins = function(maxCacheAge, cb) {
|
|||
exports.search = function(searchTerm, maxCacheAge, cb) {
|
||||
exports.getAvailablePlugins(maxCacheAge, function(er, results) {
|
||||
if (er) return cb && cb(er);
|
||||
|
||||
var res = {};
|
||||
if (searchTerm)
|
||||
|
||||
if (searchTerm) {
|
||||
searchTerm = searchTerm.toLowerCase();
|
||||
for (var pluginName in results) { // for every available plugin
|
||||
}
|
||||
|
||||
for (var pluginName in results) {
|
||||
// for every available plugin
|
||||
if (pluginName.indexOf(plugins.prefix) != 0) continue; // TODO: Also search in keywords here!
|
||||
|
||||
if (searchTerm && !~results[pluginName].name.toLowerCase().indexOf(searchTerm)
|
||||
|
@ -94,10 +116,13 @@ exports.search = function(searchTerm, maxCacheAge, cb) {
|
|||
if (typeof results[pluginName].description === "undefined") {
|
||||
console.debug('plugin without Description: %s', results[pluginName].name);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
res[pluginName] = results[pluginName];
|
||||
}
|
||||
cb && cb(null, res)
|
||||
})
|
||||
|
||||
cb && cb(null, res);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -55,6 +55,7 @@ exports.formatHooks = function (hook_set_name) {
|
|||
|
||||
exports.callInit = function (cb) {
|
||||
var hooks = require("./hooks");
|
||||
|
||||
async.map(
|
||||
Object.keys(exports.plugins),
|
||||
function (plugin_name, cb) {
|
||||
|
@ -83,6 +84,7 @@ exports.update = function (cb) {
|
|||
exports.getPackages(function (er, packages) {
|
||||
var parts = [];
|
||||
var plugins = {};
|
||||
|
||||
// Load plugin metadata ep.json
|
||||
async.forEach(
|
||||
Object.keys(packages),
|
||||
|
@ -106,6 +108,7 @@ exports.getPackages = function (cb) {
|
|||
var dir = path.resolve(npm.dir, '..');
|
||||
readInstalled(dir, function (er, data) {
|
||||
if (er) cb(er, null);
|
||||
|
||||
var packages = {};
|
||||
function flatten(deps) {
|
||||
_.chain(deps).keys().each(function (name) {
|
||||
|
|
Loading…
Reference in a new issue