mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-01-19 14:13:34 +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,109 +1,102 @@
|
||||||
/*
|
/*
|
||||||
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");
|
console.error("Use: node bin/checkAllPads.js");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//initialize the variables
|
// initialize the variables
|
||||||
var db, settings, padManager;
|
var db, settings, padManager;
|
||||||
var npm = require("../src/node_modules/npm");
|
var npm = require('../src/node_modules/npm');
|
||||||
var async = require("../src/node_modules/async");
|
var async = require('../src/node_modules/async');
|
||||||
|
|
||||||
var Changeset = require("../src/static/js/Changeset");
|
var Changeset = require('../src/static/js/Changeset');
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
//load npm
|
// load npm
|
||||||
function(callback) {
|
function(callback) {
|
||||||
npm.load({}, callback);
|
npm.load({}, callback);
|
||||||
},
|
},
|
||||||
//load modules
|
|
||||||
|
// load modules
|
||||||
function(callback) {
|
function(callback) {
|
||||||
settings = require('../src/node/utils/Settings');
|
settings = require('../src/node/utils/Settings');
|
||||||
db = require('../src/node/db/DB');
|
db = require('../src/node/db/DB');
|
||||||
|
|
||||||
//initialize the database
|
// initialize the database
|
||||||
db.init(callback);
|
db.init(callback);
|
||||||
},
|
},
|
||||||
//load pads
|
|
||||||
function (callback)
|
// load pads
|
||||||
{
|
function (callback) {
|
||||||
padManager = require('../src/node/db/PadManager');
|
padManager = require('../src/node/db/PadManager');
|
||||||
|
|
||||||
padManager.listAllPads(function(err, res)
|
padManager.listAllPads(function(err, res) {
|
||||||
{
|
|
||||||
padIds = res.padIDs;
|
padIds = res.padIDs;
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function (callback)
|
|
||||||
{
|
function (callback) {
|
||||||
async.forEach(padIds, function(padId, callback)
|
async.forEach(padIds, function(padId, callback) {
|
||||||
{
|
|
||||||
padManager.getPad(padId, function(err, pad) {
|
padManager.getPad(padId, function(err, pad) {
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if the pad has a pool
|
// check if the pad has a pool
|
||||||
if(pad.pool === undefined )
|
if (pad.pool === undefined ) {
|
||||||
{
|
|
||||||
console.error("[" + pad.id + "] Missing attribute pool");
|
console.error("[" + pad.id + "] Missing attribute pool");
|
||||||
callback();
|
callback();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//create an array with key kevisions
|
// create an array with key kevisions
|
||||||
//key revisions always save the full pad atext
|
// key revisions always save the full pad atext
|
||||||
var head = pad.getHeadRevisionNumber();
|
var head = pad.getHeadRevisionNumber();
|
||||||
var keyRevisions = [];
|
var keyRevisions = [];
|
||||||
for(var i=0;i<head;i+=100)
|
for (var i = 0; i < head; i += 100) {
|
||||||
{
|
|
||||||
keyRevisions.push(i);
|
keyRevisions.push(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
//run trough all key revisions
|
// run through all key revisions
|
||||||
async.forEachSeries(keyRevisions, function(keyRev, callback)
|
async.forEachSeries(keyRevisions, function(keyRev, callback) {
|
||||||
{
|
// create an array of revisions we need till the next keyRevision or the End
|
||||||
//create an array of revisions we need till the next keyRevision or the End
|
|
||||||
var revisionsNeeded = [];
|
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);
|
revisionsNeeded.push(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
//this array will hold all revision changesets
|
// this array will hold all revision changesets
|
||||||
var revisions = [];
|
var revisions = [];
|
||||||
|
|
||||||
//run trough all needed revisions and get them from the database
|
// run through all needed revisions and get them from the database
|
||||||
async.forEach(revisionsNeeded, function(revNum, callback)
|
async.forEach(revisionsNeeded, function(revNum, callback) {
|
||||||
{
|
db.db.get("pad:" + pad.id + ":revs:" + revNum, function(err, revision) {
|
||||||
db.db.get("pad:"+pad.id+":revs:" + revNum, function(err, revision)
|
|
||||||
{
|
|
||||||
revisions[revNum] = revision;
|
revisions[revNum] = revision;
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
}, function(err)
|
},
|
||||||
{
|
|
||||||
if(err)
|
function(err) {
|
||||||
{
|
if (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if the revision exists
|
// check if the revision exists
|
||||||
if (revisions[keyRev] == null) {
|
if (revisions[keyRev] == null) {
|
||||||
console.error("[" + pad.id + "] Missing revision " + keyRev);
|
console.error("[" + pad.id + "] Missing revision " + keyRev);
|
||||||
callback();
|
callback();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if there is a atext in the keyRevisions
|
// 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);
|
console.error("[" + pad.id + "] Missing atext in revision " + keyRev);
|
||||||
callback();
|
callback();
|
||||||
return;
|
return;
|
||||||
|
@ -112,16 +105,12 @@ async.series([
|
||||||
var apool = pad.pool;
|
var apool = pad.pool;
|
||||||
var atext = revisions[keyRev].meta.atext;
|
var atext = revisions[keyRev].meta.atext;
|
||||||
|
|
||||||
for(var i=keyRev+1;i<=keyRev+100 && i<=head; i++)
|
for(var i = keyRev + 1; i <= keyRev + 100 && i <= head; i++) {
|
||||||
{
|
try {
|
||||||
try
|
// console.log("[" + pad.id + "] check revision " + i);
|
||||||
{
|
|
||||||
//console.log("[" + pad.id + "] check revision " + i);
|
|
||||||
var cs = revisions[i].changeset;
|
var cs = revisions[i].changeset;
|
||||||
atext = Changeset.applyToAText(cs, atext, apool);
|
atext = Changeset.applyToAText(cs, atext, apool);
|
||||||
}
|
} catch(e) {
|
||||||
catch(e)
|
|
||||||
{
|
|
||||||
console.error("[" + pad.id + "] Bad changeset at revision " + i + " - " + e.message);
|
console.error("[" + pad.id + "] Bad changeset at revision " + i + " - " + e.message);
|
||||||
callback();
|
callback();
|
||||||
return;
|
return;
|
||||||
|
@ -134,11 +123,11 @@ async.series([
|
||||||
});
|
});
|
||||||
}, callback);
|
}, callback);
|
||||||
}
|
}
|
||||||
], function (err)
|
],
|
||||||
{
|
function (err) {
|
||||||
if(err) throw err;
|
if (err) {
|
||||||
else
|
throw err;
|
||||||
{
|
} else {
|
||||||
console.log("finished");
|
console.log("finished");
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
110
bin/checkPad.js
110
bin/checkPad.js
|
@ -1,107 +1,97 @@
|
||||||
/*
|
/*
|
||||||
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");
|
console.error("Use: node bin/checkPad.js $PADID");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//get the padID
|
//get the padID
|
||||||
var padId = process.argv[2];
|
var padId = process.argv[2];
|
||||||
|
|
||||||
//initialize the variables
|
// initialize the variables
|
||||||
var db, settings, padManager;
|
var db, settings, padManager;
|
||||||
var npm = require("../src/node_modules/npm");
|
var npm = require('../src/node_modules/npm');
|
||||||
var async = require("../src/node_modules/async");
|
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([
|
async.series([
|
||||||
//load npm
|
// load npm
|
||||||
function(callback) {
|
function(callback) {
|
||||||
npm.load({}, function(er) {
|
npm.load({}, function(er) {
|
||||||
callback(er);
|
callback(er);
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
//load modules
|
|
||||||
|
// load modules
|
||||||
function(callback) {
|
function(callback) {
|
||||||
settings = require('../src/node/utils/Settings');
|
settings = require('../src/node/utils/Settings');
|
||||||
db = require('../src/node/db/DB');
|
db = require('../src/node/db/DB');
|
||||||
|
|
||||||
//initialize the database
|
// initialize the database
|
||||||
db.init(callback);
|
db.init(callback);
|
||||||
},
|
},
|
||||||
//get the pad
|
|
||||||
function (callback)
|
// get the pad
|
||||||
{
|
function (callback) {
|
||||||
padManager = require('../src/node/db/PadManager');
|
padManager = require('../src/node/db/PadManager');
|
||||||
|
|
||||||
padManager.doesPadExists(padId, function(err, exists)
|
padManager.doesPadExists(padId, function(err, exists) {
|
||||||
{
|
if (!exists) {
|
||||||
if(!exists)
|
|
||||||
{
|
|
||||||
console.error("Pad does not exist");
|
console.error("Pad does not exist");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
padManager.getPad(padId, function(err, _pad)
|
padManager.getPad(padId, function(err, _pad) {
|
||||||
{
|
|
||||||
pad = _pad;
|
pad = _pad;
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function (callback)
|
|
||||||
{
|
function (callback) {
|
||||||
//create an array with key revisions
|
// create an array with key revisions
|
||||||
//key revisions always save the full pad atext
|
// key revisions always save the full pad atext
|
||||||
var head = pad.getHeadRevisionNumber();
|
var head = pad.getHeadRevisionNumber();
|
||||||
var keyRevisions = [];
|
var keyRevisions = [];
|
||||||
for(var i=0;i<head;i+=100)
|
for (var i = 0; i < head; i += 100) {
|
||||||
{
|
|
||||||
keyRevisions.push(i);
|
keyRevisions.push(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
//run trough all key revisions
|
// run through all key revisions
|
||||||
async.forEachSeries(keyRevisions, function(keyRev, callback)
|
async.forEachSeries(keyRevisions, function(keyRev, callback) {
|
||||||
{
|
// create an array of revisions we need till the next keyRevision or the End
|
||||||
//create an array of revisions we need till the next keyRevision or the End
|
|
||||||
var revisionsNeeded = [];
|
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);
|
revisionsNeeded.push(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
//this array will hold all revision changesets
|
// this array will hold all revision changesets
|
||||||
var revisions = [];
|
var revisions = [];
|
||||||
|
|
||||||
//run trough all needed revisions and get them from the database
|
// run through all needed revisions and get them from the database
|
||||||
async.forEach(revisionsNeeded, function(revNum, callback)
|
async.forEach(revisionsNeeded, function(revNum, callback) {
|
||||||
{
|
db.db.get("pad:" + padId + ":revs:" + revNum, function(err, revision) {
|
||||||
db.db.get("pad:"+padId+":revs:" + revNum, function(err, revision)
|
|
||||||
{
|
|
||||||
revisions[revNum] = revision;
|
revisions[revNum] = revision;
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
}, function(err)
|
},
|
||||||
{
|
function(err) {
|
||||||
if(err)
|
if (err) {
|
||||||
{
|
|
||||||
callback(err);
|
callback(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if the pad has a pool
|
// check if the pad has a pool
|
||||||
if(pad.pool === undefined )
|
if (pad.pool === undefined) {
|
||||||
{
|
|
||||||
console.error("Attribute pool is missing");
|
console.error("Attribute pool is missing");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if there is an atext in the keyRevisions
|
// 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);
|
console.error("No atext in key revision " + keyRev);
|
||||||
callback();
|
callback();
|
||||||
return;
|
return;
|
||||||
|
@ -110,16 +100,12 @@ async.series([
|
||||||
var apool = pad.pool;
|
var apool = pad.pool;
|
||||||
var atext = revisions[keyRev].meta.atext;
|
var atext = revisions[keyRev].meta.atext;
|
||||||
|
|
||||||
for(var i=keyRev+1;i<=keyRev+100 && i<=head; i++)
|
for (var i = keyRev + 1; i <= keyRev + 100 && i <= head; i++) {
|
||||||
{
|
try {
|
||||||
try
|
// console.log("check revision " + i);
|
||||||
{
|
|
||||||
//console.log("check revision " + i);
|
|
||||||
var cs = revisions[i].changeset;
|
var cs = revisions[i].changeset;
|
||||||
atext = Changeset.applyToAText(cs, atext, apool);
|
atext = Changeset.applyToAText(cs, atext, apool);
|
||||||
}
|
} catch(e) {
|
||||||
catch(e)
|
|
||||||
{
|
|
||||||
console.error("Bad changeset at revision " + i + " - " + e.message);
|
console.error("Bad changeset at revision " + i + " - " + e.message);
|
||||||
callback();
|
callback();
|
||||||
return;
|
return;
|
||||||
|
@ -130,11 +116,11 @@ async.series([
|
||||||
});
|
});
|
||||||
}, callback);
|
}, callback);
|
||||||
}
|
}
|
||||||
], function (err)
|
],
|
||||||
{
|
function (err) {
|
||||||
if(err) throw err;
|
if(err) {
|
||||||
else
|
throw err;
|
||||||
{
|
} else {
|
||||||
console.log("finished");
|
console.log("finished");
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,63 +1,63 @@
|
||||||
/*
|
/*
|
||||||
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");
|
console.error("Use: node deletePad.js $PADID");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
//get the padID
|
|
||||||
|
// get the padID
|
||||||
var padId = process.argv[2];
|
var padId = process.argv[2];
|
||||||
|
|
||||||
var db, padManager, pad, settings;
|
var db, padManager, pad, settings;
|
||||||
var neededDBValues = ["pad:"+padId];
|
var neededDBValues = ["pad:"+padId];
|
||||||
|
|
||||||
var npm = require("../src/node_modules/npm");
|
var npm = require('../src/node_modules/npm');
|
||||||
var async = require("../src/node_modules/async");
|
var async = require('../src/node_modules/async');
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
// load npm
|
// load npm
|
||||||
function(callback) {
|
function(callback) {
|
||||||
npm.load({}, function(er) {
|
npm.load({}, function(er) {
|
||||||
if(er)
|
if (er) {
|
||||||
{
|
|
||||||
console.error("Could not load NPM: " + er)
|
console.error("Could not load NPM: " + er)
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// load modules
|
// load modules
|
||||||
function(callback) {
|
function(callback) {
|
||||||
settings = require('../src/node/utils/Settings');
|
settings = require('../src/node/utils/Settings');
|
||||||
db = require('../src/node/db/DB');
|
db = require('../src/node/db/DB');
|
||||||
callback();
|
callback();
|
||||||
},
|
},
|
||||||
|
|
||||||
// initialize the database
|
// initialize the database
|
||||||
function (callback)
|
function (callback) {
|
||||||
{
|
|
||||||
db.init(callback);
|
db.init(callback);
|
||||||
},
|
},
|
||||||
|
|
||||||
// delete the pad and its links
|
// delete the pad and its links
|
||||||
function (callback)
|
function (callback) {
|
||||||
{
|
|
||||||
padManager = require('../src/node/db/PadManager');
|
padManager = require('../src/node/db/PadManager');
|
||||||
|
|
||||||
padManager.removePad(padId, function(err){
|
padManager.removePad(padId, function(err){
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
], function (err)
|
],
|
||||||
{
|
function (err) {
|
||||||
if(err) throw err;
|
if(err) {
|
||||||
else
|
throw err;
|
||||||
{
|
} else {
|
||||||
console.log("Finished deleting padId: "+padId);
|
console.log("Finished deleting padId: " + padId);
|
||||||
process.exit();
|
process.exit();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,109 +1,97 @@
|
||||||
/*
|
/*
|
||||||
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");
|
console.error("Use: node extractPadData.js $PADID");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
//get the padID
|
|
||||||
|
// get the padID
|
||||||
var padId = process.argv[2];
|
var padId = process.argv[2];
|
||||||
|
|
||||||
var db, dirty, padManager, pad, settings;
|
var db, dirty, padManager, pad, settings;
|
||||||
var neededDBValues = ["pad:"+padId];
|
var neededDBValues = ["pad:"+padId];
|
||||||
|
|
||||||
var npm = require("../node_modules/ep_etherpad-lite/node_modules/npm");
|
var npm = require('../node_modules/ep_etherpad-lite/node_modules/npm');
|
||||||
var async = require("../node_modules/ep_etherpad-lite/node_modules/async");
|
var async = require('../node_modules/ep_etherpad-lite/node_modules/async');
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
// load npm
|
// load npm
|
||||||
function(callback) {
|
function(callback) {
|
||||||
npm.load({}, function(er) {
|
npm.load({}, function(er) {
|
||||||
if(er)
|
if (er) {
|
||||||
{
|
|
||||||
console.error("Could not load NPM: " + er)
|
console.error("Could not load NPM: " + er)
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
// load modules
|
// load modules
|
||||||
function(callback) {
|
function(callback) {
|
||||||
settings = require('../node_modules/ep_etherpad-lite/node/utils/Settings');
|
settings = require('../node_modules/ep_etherpad-lite/node/utils/Settings');
|
||||||
db = require('../node_modules/ep_etherpad-lite/node/db/DB');
|
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();
|
callback();
|
||||||
},
|
},
|
||||||
//initialize the database
|
|
||||||
function (callback)
|
// initialize the database
|
||||||
{
|
function (callback) {
|
||||||
db.init(callback);
|
db.init(callback);
|
||||||
},
|
},
|
||||||
//get the pad
|
|
||||||
function (callback)
|
// get the pad
|
||||||
{
|
function (callback) {
|
||||||
padManager = require('../node_modules/ep_etherpad-lite/node/db/PadManager');
|
padManager = require('../node_modules/ep_etherpad-lite/node/db/PadManager');
|
||||||
|
|
||||||
padManager.getPad(padId, function(err, _pad)
|
padManager.getPad(padId, function(err, _pad) {
|
||||||
{
|
|
||||||
pad = _pad;
|
pad = _pad;
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function (callback)
|
|
||||||
{
|
function (callback) {
|
||||||
//add all authors
|
// add all authors
|
||||||
var authors = pad.getAllAuthors();
|
var authors = pad.getAllAuthors();
|
||||||
for(var i=0;i<authors.length;i++)
|
for (var i = 0; i < authors.length; i++) {
|
||||||
{
|
neededDBValues.push('globalAuthor:' + authors[i]);
|
||||||
neededDBValues.push("globalAuthor:" + authors[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//add all revisions
|
// add all revisions
|
||||||
var revHead = pad.head;
|
var revHead = pad.head;
|
||||||
for(var i=0;i<=revHead;i++)
|
for (var i = 0; i <= revHead; i++) {
|
||||||
{
|
neededDBValues.push('pad:' + padId + ':revs:' + i);
|
||||||
neededDBValues.push("pad:"+padId+":revs:" + i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//get all chat values
|
// get all chat values
|
||||||
var chatHead = pad.chatHead;
|
var chatHead = pad.chatHead;
|
||||||
for(var i=0;i<=chatHead;i++)
|
for (var i = 0; i <= chatHead; i++) {
|
||||||
{
|
neededDBValues.push('pad:' + padId + ':chat:' + i);
|
||||||
neededDBValues.push("pad:"+padId+":chat:" + i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//get and set all values
|
// get and set all values
|
||||||
async.forEach(neededDBValues, function(dbkey, callback)
|
async.forEach(neededDBValues, function(dbkey, callback) {
|
||||||
{
|
db.db.db.wrappedDB.get(dbkey, function(err, dbvalue) {
|
||||||
db.db.db.wrappedDB.get(dbkey, function(err, dbvalue)
|
if (err) { callback(err); return}
|
||||||
{
|
|
||||||
if(err) { callback(err); return}
|
|
||||||
|
|
||||||
if(dbvalue && typeof dbvalue != 'object'){
|
if (dbvalue && typeof dbvalue != 'object') {
|
||||||
dbvalue=JSON.parse(dbvalue); // if it's not json then parse it as json
|
dbvalue = JSON.parse(dbvalue); // if it's not json then parse it as json
|
||||||
}
|
}
|
||||||
|
|
||||||
dirty.set(dbkey, dbvalue, callback);
|
dirty.set(dbkey, dbvalue, callback);
|
||||||
});
|
});
|
||||||
}, callback);
|
}, callback);
|
||||||
}
|
}
|
||||||
], function (err)
|
],
|
||||||
{
|
function (err) {
|
||||||
if(err) throw err;
|
if (err) {
|
||||||
else
|
throw err;
|
||||||
{
|
} else {
|
||||||
console.log("finished");
|
console.log("finished");
|
||||||
process.exit();
|
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
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -18,25 +18,33 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
var ERR = require("async-stacktrace");
|
var ERR = require("async-stacktrace");
|
||||||
var db = require("./DB").db;
|
var db = require("./DB").db;
|
||||||
var customError = require("../utils/customError");
|
var customError = require("../utils/customError");
|
||||||
var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString;
|
var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString;
|
||||||
|
|
||||||
exports.getColorPalette = function(){
|
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"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the author exists
|
* Checks if the author exists
|
||||||
*/
|
*/
|
||||||
exports.doesAuthorExists = function (authorID, callback)
|
exports.doesAuthorExists = function(authorID, callback)
|
||||||
{
|
{
|
||||||
//check if the database entry of this author exists
|
// 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;
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
callback(null, author != null);
|
callback(null, author != null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -46,12 +54,12 @@ exports.doesAuthorExists = function (authorID, callback)
|
||||||
* @param {String} token The token
|
* @param {String} token The token
|
||||||
* @param {Function} callback callback (err, author)
|
* @param {Function} callback callback (err, author)
|
||||||
*/
|
*/
|
||||||
exports.getAuthor4Token = function (token, callback)
|
exports.getAuthor4Token = function(token, callback)
|
||||||
{
|
{
|
||||||
mapAuthorWithDBKey("token2author", token, function(err, author)
|
mapAuthorWithDBKey("token2author", token, function(err, author) {
|
||||||
{
|
if (ERR(err, callback)) return;
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
//return only the sub value authorID
|
// return only the sub value authorID
|
||||||
callback(null, author ? author.authorID : author);
|
callback(null, author ? author.authorID : author);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -62,17 +70,17 @@ exports.getAuthor4Token = function (token, callback)
|
||||||
* @param {String} name The name of the author (optional)
|
* @param {String} name The name of the author (optional)
|
||||||
* @param {Function} callback callback (err, author)
|
* @param {Function} callback callback (err, author)
|
||||||
*/
|
*/
|
||||||
exports.createAuthorIfNotExistsFor = function (authorMapper, name, 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(ERR(err, callback)) return;
|
|
||||||
|
|
||||||
//set the name of this author
|
if (name) {
|
||||||
if(name)
|
// set the name of this author
|
||||||
exports.setAuthorName(author.authorID, name);
|
exports.setAuthorName(author.authorID, name);
|
||||||
|
}
|
||||||
|
|
||||||
//return the authorID
|
// return the authorID
|
||||||
callback(null, author);
|
callback(null, author);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -86,33 +94,30 @@ exports.createAuthorIfNotExistsFor = function (authorMapper, name, callback)
|
||||||
*/
|
*/
|
||||||
function mapAuthorWithDBKey (mapperkey, mapper, callback)
|
function mapAuthorWithDBKey (mapperkey, mapper, callback)
|
||||||
{
|
{
|
||||||
//try to map to an author
|
// 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(ERR(err, callback)) return;
|
|
||||||
|
|
||||||
//there is no author with this mapper, so create one
|
if (author == null) {
|
||||||
if(author == null)
|
// there is no author with this mapper, so create one
|
||||||
{
|
exports.createAuthor(null, function(err, author) {
|
||||||
exports.createAuthor(null, function(err, author)
|
if (ERR(err, callback)) return;
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
|
|
||||||
//create the token2author relation
|
// create the token2author relation
|
||||||
db.set(mapperkey + ":" + mapper, author.authorID);
|
db.set(mapperkey + ":" + mapper, author.authorID);
|
||||||
|
|
||||||
//return the author
|
// return the author
|
||||||
callback(null, author);
|
callback(null, author);
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//there is a author with this mapper
|
// there is an author with this mapper
|
||||||
//update the timestamp of this author
|
// update the timestamp of this author
|
||||||
db.setSub("globalAuthor:" + author, ["timestamp"], Date.now());
|
db.setSub("globalAuthor:" + author, ["timestamp"], Date.now());
|
||||||
|
|
||||||
//return the author
|
// return the author
|
||||||
callback(null, {authorID: author});
|
callback(null, {authorID: author});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -123,13 +128,17 @@ function mapAuthorWithDBKey (mapperkey, mapper, callback)
|
||||||
*/
|
*/
|
||||||
exports.createAuthor = function(name, callback)
|
exports.createAuthor = function(name, callback)
|
||||||
{
|
{
|
||||||
//create the new author name
|
// create the new author name
|
||||||
var author = "a." + randomString(16);
|
var author = "a." + randomString(16);
|
||||||
|
|
||||||
//create the globalAuthors db entry
|
// 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
|
// set the global author db entry
|
||||||
db.set("globalAuthor:" + author, authorObj);
|
db.set("globalAuthor:" + author, authorObj);
|
||||||
|
|
||||||
callback(null, {authorID: author});
|
callback(null, {authorID: author});
|
||||||
|
@ -140,19 +149,17 @@ exports.createAuthor = function(name, callback)
|
||||||
* @param {String} author The id of the author
|
* @param {String} author The id of the author
|
||||||
* @param {Function} callback callback(err, authorObj)
|
* @param {Function} callback callback(err, authorObj)
|
||||||
*/
|
*/
|
||||||
exports.getAuthor = function (author, callback)
|
exports.getAuthor = function(author, callback)
|
||||||
{
|
{
|
||||||
db.get("globalAuthor:" + author, callback);
|
db.get("globalAuthor:" + author, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the color Id of the author
|
* Returns the color Id of the author
|
||||||
* @param {String} author The id of the author
|
* @param {String} author The id of the author
|
||||||
* @param {Function} callback callback(err, colorId)
|
* @param {Function} callback callback(err, colorId)
|
||||||
*/
|
*/
|
||||||
exports.getAuthorColorId = function (author, callback)
|
exports.getAuthorColorId = function(author, callback)
|
||||||
{
|
{
|
||||||
db.getSub("globalAuthor:" + author, ["colorId"], callback);
|
db.getSub("globalAuthor:" + author, ["colorId"], callback);
|
||||||
}
|
}
|
||||||
|
@ -163,7 +170,7 @@ exports.getAuthorColorId = function (author, callback)
|
||||||
* @param {String} colorId The color id of the author
|
* @param {String} colorId The color id of the author
|
||||||
* @param {Function} callback (optional)
|
* @param {Function} callback (optional)
|
||||||
*/
|
*/
|
||||||
exports.setAuthorColorId = function (author, colorId, callback)
|
exports.setAuthorColorId = function(author, colorId, callback)
|
||||||
{
|
{
|
||||||
db.setSub("globalAuthor:" + author, ["colorId"], colorId, callback);
|
db.setSub("globalAuthor:" + author, ["colorId"], colorId, callback);
|
||||||
}
|
}
|
||||||
|
@ -173,7 +180,7 @@ exports.setAuthorColorId = function (author, colorId, callback)
|
||||||
* @param {String} author The id of the author
|
* @param {String} author The id of the author
|
||||||
* @param {Function} callback callback(err, name)
|
* @param {Function} callback callback(err, name)
|
||||||
*/
|
*/
|
||||||
exports.getAuthorName = function (author, callback)
|
exports.getAuthorName = function(author, callback)
|
||||||
{
|
{
|
||||||
db.getSub("globalAuthor:" + author, ["name"], callback);
|
db.getSub("globalAuthor:" + author, ["name"], callback);
|
||||||
}
|
}
|
||||||
|
@ -184,7 +191,7 @@ exports.getAuthorName = function (author, callback)
|
||||||
* @param {String} name The name of the author
|
* @param {String} name The name of the author
|
||||||
* @param {Function} callback (optional)
|
* @param {Function} callback (optional)
|
||||||
*/
|
*/
|
||||||
exports.setAuthorName = function (author, name, callback)
|
exports.setAuthorName = function(author, name, callback)
|
||||||
{
|
{
|
||||||
db.setSub("globalAuthor:" + author, ["name"], name, callback);
|
db.setSub("globalAuthor:" + author, ["name"], name, callback);
|
||||||
}
|
}
|
||||||
|
@ -194,33 +201,33 @@ exports.setAuthorName = function (author, name, callback)
|
||||||
* @param {String} author The id of the author
|
* @param {String} author The id of the author
|
||||||
* @param {Function} callback (optional)
|
* @param {Function} callback (optional)
|
||||||
*/
|
*/
|
||||||
exports.listPadsOfAuthor = function (authorID, callback)
|
exports.listPadsOfAuthor = function(authorID, callback)
|
||||||
{
|
{
|
||||||
/* There are two other places where this array is manipulated:
|
/* There are two other places where this array is manipulated:
|
||||||
* (1) When the author is added to a pad, the author object is also updated
|
* (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
|
* (2) When a pad is deleted, each author of that pad is also updated
|
||||||
*/
|
*/
|
||||||
//get the globalAuthor
|
|
||||||
db.get("globalAuthor:" + authorID, function(err, author)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
|
|
||||||
//author does not exists
|
// get the globalAuthor
|
||||||
if(author == null)
|
db.get("globalAuthor:" + authorID, function(err, author) {
|
||||||
{
|
if (ERR(err, callback)) return;
|
||||||
callback(new customError("authorID does not exist","apierror"))
|
|
||||||
|
if (author == null) {
|
||||||
|
// author does not exist
|
||||||
|
callback(new customError("authorID does not exist", "apierror"));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//everything is fine, return the pad IDs
|
// everything is fine, return the pad IDs
|
||||||
var pads = [];
|
var pads = [];
|
||||||
if(author.padIDs != null)
|
|
||||||
{
|
if (author.padIDs != null) {
|
||||||
for (var padId in author.padIDs)
|
for (var padId in author.padIDs) {
|
||||||
{
|
|
||||||
pads.push(padId);
|
pads.push(padId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(null, {padIDs: pads});
|
callback(null, {padIDs: pads});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -230,24 +237,22 @@ exports.listPadsOfAuthor = function (authorID, callback)
|
||||||
* @param {String} author The id of the author
|
* @param {String} author The id of the author
|
||||||
* @param {String} padID The id of the pad the author contributes to
|
* @param {String} padID The id of the pad the author contributes to
|
||||||
*/
|
*/
|
||||||
exports.addPad = function (authorID, padID)
|
exports.addPad = function(authorID, padID)
|
||||||
{
|
{
|
||||||
//get the entry
|
// get the entry
|
||||||
db.get("globalAuthor:" + authorID, function(err, author)
|
db.get("globalAuthor:" + authorID, function(err, author) {
|
||||||
{
|
if (ERR(err)) return;
|
||||||
if(ERR(err)) return;
|
if (author == null) return;
|
||||||
if(author == null) return;
|
|
||||||
|
|
||||||
//the entry doesn't exist so far, let's create it
|
if (author.padIDs == null) {
|
||||||
if(author.padIDs == null)
|
// the entry doesn't exist so far, let's create it
|
||||||
{
|
|
||||||
author.padIDs = {};
|
author.padIDs = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
//add the entry for this pad
|
// add the entry for this pad
|
||||||
author.padIDs[padID] = 1;// anything, because value is not used
|
author.padIDs[padID] = 1; // anything, because value is not used
|
||||||
|
|
||||||
//save the new element back
|
// save the new element back
|
||||||
db.set("globalAuthor:" + authorID, author);
|
db.set("globalAuthor:" + authorID, author);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -257,16 +262,14 @@ exports.addPad = function (authorID, padID)
|
||||||
* @param {String} author The id of the author
|
* @param {String} author The id of the author
|
||||||
* @param {String} padID The id of the pad the author contributes to
|
* @param {String} padID The id of the pad the author contributes to
|
||||||
*/
|
*/
|
||||||
exports.removePad = 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(ERR(err)) return;
|
if (author == null) return;
|
||||||
if(author == null) return;
|
|
||||||
|
|
||||||
if(author.padIDs != null)
|
if (author.padIDs != null) {
|
||||||
{
|
// remove pad from author
|
||||||
//remove pad from author
|
|
||||||
delete author.padIDs[padID];
|
delete author.padIDs[padID];
|
||||||
db.set("globalAuthor:" + authorID, author);
|
db.set("globalAuthor:" + authorID, author);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ var ueberDB = require("ueberdb2");
|
||||||
var settings = require("../utils/Settings");
|
var settings = require("../utils/Settings");
|
||||||
var log4js = require('log4js');
|
var log4js = require('log4js');
|
||||||
|
|
||||||
//set database settings
|
// set database settings
|
||||||
var db = new ueberDB.database(settings.dbType, settings.dbSettings, null, log4js.getLogger("ueberDB"));
|
var db = new ueberDB.database(settings.dbType, settings.dbSettings, null, log4js.getLogger("ueberDB"));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,21 +35,16 @@ exports.db = null;
|
||||||
* Initalizes the database with the settings provided by the settings module
|
* Initalizes the database with the settings provided by the settings module
|
||||||
* @param {Function} callback
|
* @param {Function} callback
|
||||||
*/
|
*/
|
||||||
exports.init = function(callback)
|
exports.init = function(callback) {
|
||||||
{
|
// initalize the database async
|
||||||
//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
|
||||||
//there was an error while initializing the database, output it and stop
|
|
||||||
if(err)
|
|
||||||
{
|
|
||||||
console.error("ERROR: Problem while initalizing the database");
|
console.error("ERROR: Problem while initalizing the database");
|
||||||
console.error(err.stack ? err.stack : err);
|
console.error(err.stack ? err.stack : err);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
} else {
|
||||||
//everything ok
|
// everything ok
|
||||||
else
|
|
||||||
{
|
|
||||||
exports.db = db;
|
exports.db = db;
|
||||||
callback(null);
|
callback(null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
var ERR = require("async-stacktrace");
|
var ERR = require("async-stacktrace");
|
||||||
var customError = require("../utils/customError");
|
var customError = require("../utils/customError");
|
||||||
var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString;
|
var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString;
|
||||||
|
@ -29,16 +28,17 @@ var sessionManager = require("./SessionManager");
|
||||||
|
|
||||||
exports.listAllGroups = function(callback) {
|
exports.listAllGroups = function(callback) {
|
||||||
db.get("groups", function (err, groups) {
|
db.get("groups", function (err, groups) {
|
||||||
if(ERR(err, callback)) return;
|
if (ERR(err, callback)) return;
|
||||||
|
|
||||||
|
if (groups == null) {
|
||||||
// there are no groups
|
// there are no groups
|
||||||
if(groups == null) {
|
|
||||||
callback(null, {groupIDs: []});
|
callback(null, {groupIDs: []});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var groupIDs = [];
|
var groupIDs = [];
|
||||||
for ( var groupID in groups ) {
|
for (var groupID in groups) {
|
||||||
groupIDs.push(groupID);
|
groupIDs.push(groupID);
|
||||||
}
|
}
|
||||||
callback(null, {groupIDs: groupIDs});
|
callback(null, {groupIDs: groupIDs});
|
||||||
|
@ -50,96 +50,90 @@ exports.deleteGroup = function(groupID, callback)
|
||||||
var group;
|
var group;
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
//ensure group exists
|
// ensure group exists
|
||||||
function (callback)
|
function (callback) {
|
||||||
{
|
// try to get the group entry
|
||||||
//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(ERR(err, callback)) return;
|
|
||||||
|
|
||||||
//group does not exist
|
if (_group == null) {
|
||||||
if(_group == null)
|
// group does not exist
|
||||||
{
|
callback(new customError("groupID does not exist", "apierror"));
|
||||||
callback(new customError("groupID does not exist","apierror"));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//group exists, everything is fine
|
// group exists, everything is fine
|
||||||
group = _group;
|
group = _group;
|
||||||
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
|
// collect all padIDs in an array, that allows us to use async.forEach
|
||||||
var padIDs = [];
|
var padIDs = [];
|
||||||
for(var i in group.pads)
|
for(var i in group.pads) {
|
||||||
{
|
|
||||||
padIDs.push(i);
|
padIDs.push(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
//loop trough all pads and delete them
|
// loop through all pads and delete them
|
||||||
async.forEach(padIDs, function(padID, callback)
|
async.forEach(padIDs, function(padID, callback) {
|
||||||
{
|
padManager.getPad(padID, function(err, pad) {
|
||||||
padManager.getPad(padID, function(err, pad)
|
if (ERR(err, callback)) return;
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
|
|
||||||
pad.remove(callback);
|
pad.remove(callback);
|
||||||
});
|
});
|
||||||
}, callback);
|
}, callback);
|
||||||
},
|
},
|
||||||
//iterate trough group2sessions and delete all sessions
|
|
||||||
|
// iterate through group2sessions and delete all sessions
|
||||||
function(callback)
|
function(callback)
|
||||||
{
|
{
|
||||||
//try to get the group entry
|
// 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;
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
|
|
||||||
//skip if there is no group2sessions entry
|
// skip if there is no group2sessions entry
|
||||||
if(group2sessions == null) {callback(); return}
|
if (group2sessions == null) { callback(); return }
|
||||||
|
|
||||||
//collect all sessions in an array, that allows us to use async.forEach
|
// collect all sessions in an array, that allows us to use async.forEach
|
||||||
var sessions = [];
|
var sessions = [];
|
||||||
for(var i in group2sessions.sessionsIDs)
|
for (var i in group2sessions.sessionsIDs) {
|
||||||
{
|
|
||||||
sessions.push(i);
|
sessions.push(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
//loop trough all sessions and delete them
|
// loop through all sessions and delete them
|
||||||
async.forEach(sessions, function(session, callback)
|
async.forEach(sessions, function(session, callback) {
|
||||||
{
|
|
||||||
sessionManager.deleteSession(session, callback);
|
sessionManager.deleteSession(session, callback);
|
||||||
}, callback);
|
}, callback);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//remove group and group2sessions entry
|
|
||||||
function(callback)
|
// remove group and group2sessions entry
|
||||||
{
|
function(callback) {
|
||||||
db.remove("group2sessions:" + groupID);
|
db.remove("group2sessions:" + groupID);
|
||||||
db.remove("group:" + groupID);
|
db.remove("group:" + groupID);
|
||||||
callback();
|
callback();
|
||||||
},
|
},
|
||||||
//unlist the group
|
|
||||||
function(callback)
|
// unlist the group
|
||||||
{
|
function(callback) {
|
||||||
exports.listAllGroups(function(err, groups) {
|
exports.listAllGroups(function(err, groups) {
|
||||||
if(ERR(err, callback)) return;
|
if (ERR(err, callback)) return;
|
||||||
groups = groups? groups.groupIDs : [];
|
groups = groups? groups.groupIDs : [];
|
||||||
|
|
||||||
|
if (groups.indexOf(groupID) == -1) {
|
||||||
// it's not listed
|
// it's not listed
|
||||||
if(groups.indexOf(groupID) == -1) {
|
|
||||||
callback();
|
callback();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove from the list
|
||||||
groups.splice(groups.indexOf(groupID), 1);
|
groups.splice(groups.indexOf(groupID), 1);
|
||||||
|
|
||||||
// store empty groupe list
|
// store empty group list
|
||||||
if(groups.length == 0) {
|
if (groups.length == 0) {
|
||||||
db.set("groups", {});
|
db.set("groups", {});
|
||||||
callback();
|
callback();
|
||||||
return;
|
return;
|
||||||
|
@ -150,42 +144,42 @@ exports.deleteGroup = function(groupID, callback)
|
||||||
async.forEach(groups, function(group, cb) {
|
async.forEach(groups, function(group, cb) {
|
||||||
newGroups[group] = 1;
|
newGroups[group] = 1;
|
||||||
cb();
|
cb();
|
||||||
},function() {
|
},
|
||||||
|
function() {
|
||||||
db.set("groups", newGroups);
|
db.set("groups", newGroups);
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
], function(err)
|
],
|
||||||
{
|
function(err) {
|
||||||
if(ERR(err, callback)) return;
|
if (ERR(err, callback)) return;
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.doesGroupExist = function(groupID, callback)
|
exports.doesGroupExist = function(groupID, callback)
|
||||||
{
|
{
|
||||||
//try to get the group entry
|
// 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(ERR(err, callback)) return;
|
|
||||||
callback(null, group != null);
|
callback(null, group != null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.createGroup = function(callback)
|
exports.createGroup = function(callback)
|
||||||
{
|
{
|
||||||
//search for non existing groupID
|
// search for non existing groupID
|
||||||
var groupID = "g." + randomString(16);
|
var groupID = "g." + randomString(16);
|
||||||
|
|
||||||
//create the group
|
// create the group
|
||||||
db.set("group:" + groupID, {pads: {}});
|
db.set("group:" + groupID, {pads: {}});
|
||||||
|
|
||||||
//list the group
|
// list the group
|
||||||
exports.listAllGroups(function(err, groups) {
|
exports.listAllGroups(function(err, groups) {
|
||||||
if(ERR(err, callback)) return;
|
if (ERR(err, callback)) return;
|
||||||
groups = groups? groups.groupIDs : [];
|
|
||||||
|
|
||||||
|
groups = groups? groups.groupIDs : [];
|
||||||
groups.push(groupID);
|
groups.push(groupID);
|
||||||
|
|
||||||
// regenerate group list
|
// regenerate group list
|
||||||
|
@ -193,7 +187,8 @@ exports.createGroup = function(callback)
|
||||||
async.forEach(groups, function(group, cb) {
|
async.forEach(groups, function(group, cb) {
|
||||||
newGroups[group] = 1;
|
newGroups[group] = 1;
|
||||||
cb();
|
cb();
|
||||||
},function() {
|
},
|
||||||
|
function() {
|
||||||
db.set("groups", newGroups);
|
db.set("groups", newGroups);
|
||||||
callback(null, {groupID: groupID});
|
callback(null, {groupID: groupID});
|
||||||
});
|
});
|
||||||
|
@ -202,129 +197,121 @@ exports.createGroup = function(callback)
|
||||||
|
|
||||||
exports.createGroupIfNotExistsFor = function(groupMapper, callback)
|
exports.createGroupIfNotExistsFor = function(groupMapper, callback)
|
||||||
{
|
{
|
||||||
//ensure mapper is optional
|
// ensure mapper is optional
|
||||||
if(typeof groupMapper != "string")
|
if (typeof groupMapper != "string") {
|
||||||
{
|
callback(new customError("groupMapper is no string", "apierror"));
|
||||||
callback(new customError("groupMapper is no string","apierror"));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//try to get a group for this mapper
|
// 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) {
|
function createGroupForMapper(cb) {
|
||||||
exports.createGroup(function(err, responseObj)
|
exports.createGroup(function(err, responseObj) {
|
||||||
{
|
if (ERR(err, cb)) return;
|
||||||
if(ERR(err, cb)) return;
|
|
||||||
|
|
||||||
//create the mapper entry for this group
|
// create the mapper entry for this group
|
||||||
db.set("mapper2group:"+groupMapper, responseObj.groupID);
|
db.set("mapper2group:" + groupMapper, responseObj.groupID);
|
||||||
|
|
||||||
cb(null, responseObj);
|
cb(null, responseObj);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ERR(err, callback)) return;
|
if (ERR(err, callback)) return;
|
||||||
|
|
||||||
|
if (groupID) {
|
||||||
// there is a group for this mapper
|
// there is a group for this mapper
|
||||||
if(groupID) {
|
|
||||||
exports.doesGroupExist(groupID, function(err, exists) {
|
exports.doesGroupExist(groupID, function(err, exists) {
|
||||||
if(ERR(err, callback)) return;
|
if (ERR(err, callback)) return;
|
||||||
if(exists) return callback(null, {groupID: groupID});
|
|
||||||
|
if (exists) return callback(null, {groupID: groupID});
|
||||||
|
|
||||||
// hah, the returned group doesn't exist, let's create one
|
// hah, the returned group doesn't exist, let's create one
|
||||||
createGroupForMapper(callback)
|
createGroupForMapper(callback)
|
||||||
})
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//there is no group for this mapper, let's create a group
|
// there is no group for this mapper, let's create a group
|
||||||
createGroupForMapper(callback)
|
createGroupForMapper(callback)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.createGroupPad = function(groupID, padName, text, callback)
|
exports.createGroupPad = function(groupID, padName, text, callback)
|
||||||
{
|
{
|
||||||
//create the padID
|
// create the padID
|
||||||
var padID = groupID + "$" + padName;
|
var padID = groupID + "$" + padName;
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
//ensure group exists
|
// ensure group exists
|
||||||
function (callback)
|
function (callback) {
|
||||||
{
|
exports.doesGroupExist(groupID, function(err, exists) {
|
||||||
exports.doesGroupExist(groupID, function(err, exists)
|
if (ERR(err, callback)) return;
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
|
|
||||||
//group does not exist
|
if (exists == false) {
|
||||||
if(exists == false)
|
// group does not exist
|
||||||
{
|
callback(new customError("groupID does not exist", "apierror"));
|
||||||
callback(new customError("groupID does not exist","apierror"));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//group exists, everything is fine
|
// group exists, everything is fine
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//ensure pad does not exists
|
|
||||||
function (callback)
|
|
||||||
{
|
|
||||||
padManager.doesPadExists(padID, function(err, exists)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
|
|
||||||
//pad exists already
|
// ensure pad doesn't exist already
|
||||||
if(exists == true)
|
function (callback) {
|
||||||
{
|
padManager.doesPadExists(padID, function(err, exists) {
|
||||||
callback(new customError("padName does already exist","apierror"));
|
if (ERR(err, callback)) return;
|
||||||
|
|
||||||
|
if (exists == true) {
|
||||||
|
// pad exists already
|
||||||
|
callback(new customError("padName does already exist", "apierror"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//pad does not exist, everything is fine
|
// pad does not exist, everything is fine
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//create the pad
|
|
||||||
function (callback)
|
// create the pad
|
||||||
{
|
function (callback) {
|
||||||
padManager.getPad(padID, text, function(err)
|
padManager.getPad(padID, text, function(err) {
|
||||||
{
|
if (ERR(err, callback)) return;
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//create an entry in the group for this pad
|
|
||||||
function (callback)
|
// create an entry in the group for this pad
|
||||||
{
|
function (callback) {
|
||||||
db.setSub("group:" + groupID, ["pads", padID], 1);
|
db.setSub("group:" + groupID, ["pads", padID], 1);
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
], function(err)
|
],
|
||||||
{
|
function(err) {
|
||||||
if(ERR(err, callback)) return;
|
if (ERR(err, callback)) return;
|
||||||
|
|
||||||
callback(null, {padID: padID});
|
callback(null, {padID: padID});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.listPads = function(groupID, callback)
|
exports.listPads = function(groupID, callback)
|
||||||
{
|
{
|
||||||
exports.doesGroupExist(groupID, function(err, exists)
|
exports.doesGroupExist(groupID, function(err, exists) {
|
||||||
{
|
if (ERR(err, callback)) return;
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
|
|
||||||
//group does not exist
|
// ensure the group exists
|
||||||
if(exists == false)
|
if (exists == false) {
|
||||||
{
|
callback(new customError("groupID does not exist", "apierror"));
|
||||||
callback(new customError("groupID does not exist","apierror"));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//group exists, let's get the pads
|
// 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;
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
var pads = [];
|
var pads = [];
|
||||||
for ( var padId in result ) {
|
for ( var padId in result ) {
|
||||||
pads.push(padId);
|
pads.push(padId);
|
||||||
|
|
|
@ -19,7 +19,7 @@ var crypto = require("crypto");
|
||||||
var randomString = require("../utils/randomstring");
|
var randomString = require("../utils/randomstring");
|
||||||
var hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks');
|
var hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks');
|
||||||
|
|
||||||
//serialization/deserialization attributes
|
// serialization/deserialization attributes
|
||||||
var attributeBlackList = ["id"];
|
var attributeBlackList = ["id"];
|
||||||
var jsonableList = ["pool"];
|
var jsonableList = ["pool"];
|
||||||
|
|
||||||
|
@ -33,7 +33,6 @@ exports.cleanText = function (txt) {
|
||||||
|
|
||||||
|
|
||||||
var Pad = function Pad(id) {
|
var Pad = function Pad(id) {
|
||||||
|
|
||||||
this.atext = Changeset.makeAText("\n");
|
this.atext = Changeset.makeAText("\n");
|
||||||
this.pool = new AttributePool();
|
this.pool = new AttributePool();
|
||||||
this.head = -1;
|
this.head = -1;
|
||||||
|
@ -60,7 +59,7 @@ Pad.prototype.getSavedRevisionsNumber = function getSavedRevisionsNumber() {
|
||||||
|
|
||||||
Pad.prototype.getSavedRevisionsList = function getSavedRevisionsList() {
|
Pad.prototype.getSavedRevisionsList = function getSavedRevisionsList() {
|
||||||
var savedRev = new Array();
|
var savedRev = new Array();
|
||||||
for(var rev in this.savedRevisions){
|
for (var rev in this.savedRevisions) {
|
||||||
savedRev.push(this.savedRevisions[rev].revNum);
|
savedRev.push(this.savedRevisions[rev].revNum);
|
||||||
}
|
}
|
||||||
savedRev.sort(function(a, b) {
|
savedRev.sort(function(a, b) {
|
||||||
|
@ -74,8 +73,9 @@ Pad.prototype.getPublicStatus = function getPublicStatus() {
|
||||||
};
|
};
|
||||||
|
|
||||||
Pad.prototype.appendRevision = function appendRevision(aChangeset, author) {
|
Pad.prototype.appendRevision = function appendRevision(aChangeset, author) {
|
||||||
if(!author)
|
if (!author) {
|
||||||
author = '';
|
author = '';
|
||||||
|
}
|
||||||
|
|
||||||
var newAText = Changeset.applyToAText(aChangeset, this.atext, this.pool);
|
var newAText = Changeset.applyToAText(aChangeset, this.atext, this.pool);
|
||||||
Changeset.copyAText(newAText, this.atext);
|
Changeset.copyAText(newAText, this.atext);
|
||||||
|
@ -88,21 +88,22 @@ Pad.prototype.appendRevision = function appendRevision(aChangeset, author) {
|
||||||
newRevData.meta.author = author;
|
newRevData.meta.author = author;
|
||||||
newRevData.meta.timestamp = Date.now();
|
newRevData.meta.timestamp = Date.now();
|
||||||
|
|
||||||
//ex. getNumForAuthor
|
// ex. getNumForAuthor
|
||||||
if(author != '')
|
if (author != '') {
|
||||||
this.pool.putAttrib(['author', author || '']);
|
this.pool.putAttrib(['author', author || '']);
|
||||||
|
}
|
||||||
|
|
||||||
if(newRev % 100 == 0)
|
if (newRev % 100 == 0) {
|
||||||
{
|
|
||||||
newRevData.meta.atext = this.atext;
|
newRevData.meta.atext = this.atext;
|
||||||
}
|
}
|
||||||
|
|
||||||
db.set("pad:"+this.id+":revs:"+newRev, newRevData);
|
db.set("pad:" + this.id + ":revs:" + newRev, newRevData);
|
||||||
this.saveToDatabase();
|
this.saveToDatabase();
|
||||||
|
|
||||||
// set the author to pad
|
// set the author to pad
|
||||||
if(author)
|
if (author) {
|
||||||
authorManager.addPad(author, this.id);
|
authorManager.addPad(author, this.id);
|
||||||
|
}
|
||||||
|
|
||||||
if (this.head == 0) {
|
if (this.head == 0) {
|
||||||
hooks.callAll("padCreate", {'pad':this, 'author': author});
|
hooks.callAll("padCreate", {'pad':this, 'author': author});
|
||||||
|
@ -111,49 +112,47 @@ Pad.prototype.appendRevision = function appendRevision(aChangeset, author) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//save all attributes to the database
|
// save all attributes to the database
|
||||||
Pad.prototype.saveToDatabase = function saveToDatabase(){
|
Pad.prototype.saveToDatabase = function saveToDatabase() {
|
||||||
var dbObject = {};
|
var dbObject = {};
|
||||||
|
|
||||||
for(var attr in this){
|
for (var attr in this) {
|
||||||
if(typeof this[attr] === "function") continue;
|
if (typeof this[attr] === "function") continue;
|
||||||
if(attributeBlackList.indexOf(attr) !== -1) continue;
|
if (attributeBlackList.indexOf(attr) !== -1) continue;
|
||||||
|
|
||||||
dbObject[attr] = this[attr];
|
dbObject[attr] = this[attr];
|
||||||
|
|
||||||
if(jsonableList.indexOf(attr) !== -1){
|
if (jsonableList.indexOf(attr) !== -1) {
|
||||||
dbObject[attr] = dbObject[attr].toJsonable();
|
dbObject[attr] = dbObject[attr].toJsonable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
db.set("pad:"+this.id, dbObject);
|
db.set("pad:" + this.id, dbObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get time of last edit (changeset application)
|
// get time of last edit (changeset application)
|
||||||
Pad.prototype.getLastEdit = function getLastEdit(callback){
|
Pad.prototype.getLastEdit = function getLastEdit(callback) {
|
||||||
var revNum = this.getHeadRevisionNumber();
|
var revNum = this.getHeadRevisionNumber();
|
||||||
db.getSub("pad:"+this.id+":revs:"+revNum, ["meta", "timestamp"], callback);
|
db.getSub("pad:" + this.id + ":revs:" + revNum, ["meta", "timestamp"], callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
Pad.prototype.getRevisionChangeset = function getRevisionChangeset(revNum, callback) {
|
Pad.prototype.getRevisionChangeset = function getRevisionChangeset(revNum, callback) {
|
||||||
db.getSub("pad:"+this.id+":revs:"+revNum, ["changeset"], callback);
|
db.getSub("pad:" + this.id + ":revs:" + revNum, ["changeset"], callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
Pad.prototype.getRevisionAuthor = function getRevisionAuthor(revNum, callback) {
|
Pad.prototype.getRevisionAuthor = function getRevisionAuthor(revNum, callback) {
|
||||||
db.getSub("pad:"+this.id+":revs:"+revNum, ["meta", "author"], callback);
|
db.getSub("pad:" + this.id + ":revs:" + revNum, ["meta", "author"], callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
Pad.prototype.getRevisionDate = function getRevisionDate(revNum, callback) {
|
Pad.prototype.getRevisionDate = function getRevisionDate(revNum, callback) {
|
||||||
db.getSub("pad:"+this.id+":revs:"+revNum, ["meta", "timestamp"], callback);
|
db.getSub("pad:" + this.id + ":revs:" + revNum, ["meta", "timestamp"], callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
Pad.prototype.getAllAuthors = function getAllAuthors() {
|
Pad.prototype.getAllAuthors = function getAllAuthors() {
|
||||||
var authors = [];
|
var authors = [];
|
||||||
|
|
||||||
for(var key in this.pool.numToAttrib)
|
for(var key in this.pool.numToAttrib) {
|
||||||
{
|
if (this.pool.numToAttrib[key][0] == "author" && this.pool.numToAttrib[key][1] != "") {
|
||||||
if(this.pool.numToAttrib[key][0] == "author" && this.pool.numToAttrib[key][1] != "")
|
|
||||||
{
|
|
||||||
authors.push(this.pool.numToAttrib[key][1]);
|
authors.push(this.pool.numToAttrib[key][1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,26 +167,22 @@ Pad.prototype.getInternalRevisionAText = function getInternalRevisionAText(targe
|
||||||
var atext;
|
var atext;
|
||||||
var changesets = [];
|
var changesets = [];
|
||||||
|
|
||||||
//find out which changesets are needed
|
// find out which changesets are needed
|
||||||
var neededChangesets = [];
|
var neededChangesets = [];
|
||||||
var curRev = keyRev;
|
var curRev = keyRev;
|
||||||
while (curRev < targetRev)
|
while (curRev < targetRev) {
|
||||||
{
|
|
||||||
curRev++;
|
curRev++;
|
||||||
neededChangesets.push(curRev);
|
neededChangesets.push(curRev);
|
||||||
}
|
}
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
//get all needed data out of the database
|
// get all needed data out of the database
|
||||||
function(callback)
|
function(callback) {
|
||||||
{
|
|
||||||
async.parallel([
|
async.parallel([
|
||||||
//get the atext of the key revision
|
// get the atext of the key revision
|
||||||
function (callback)
|
function (callback) {
|
||||||
{
|
db.getSub("pad:" + _this.id + ":revs:" + keyRev, ["meta", "atext"], function(err, _atext) {
|
||||||
db.getSub("pad:"+_this.id+":revs:"+keyRev, ["meta", "atext"], function(err, _atext)
|
if (ERR(err, callback)) return;
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
try {
|
try {
|
||||||
atext = Changeset.cloneAText(_atext);
|
atext = Changeset.cloneAText(_atext);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -197,14 +192,12 @@ Pad.prototype.getInternalRevisionAText = function getInternalRevisionAText(targe
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//get all needed changesets
|
|
||||||
function (callback)
|
// get all needed changesets
|
||||||
{
|
function (callback) {
|
||||||
async.forEach(neededChangesets, function(item, callback)
|
async.forEach(neededChangesets, function(item, callback) {
|
||||||
{
|
_this.getRevisionChangeset(item, function(err, changeset) {
|
||||||
_this.getRevisionChangeset(item, function(err, changeset)
|
if (ERR(err, callback)) return;
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
changesets[item] = changeset;
|
changesets[item] = changeset;
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
|
@ -212,52 +205,53 @@ Pad.prototype.getInternalRevisionAText = function getInternalRevisionAText(targe
|
||||||
}
|
}
|
||||||
], callback);
|
], callback);
|
||||||
},
|
},
|
||||||
//apply all changesets to the key changeset
|
|
||||||
function(callback)
|
// apply all changesets to the key changeset
|
||||||
{
|
function(callback) {
|
||||||
var apool = _this.apool();
|
var apool = _this.apool();
|
||||||
var curRev = keyRev;
|
var curRev = keyRev;
|
||||||
|
|
||||||
while (curRev < targetRev)
|
while (curRev < targetRev) {
|
||||||
{
|
|
||||||
curRev++;
|
curRev++;
|
||||||
var cs = changesets[curRev];
|
var cs = changesets[curRev];
|
||||||
try{
|
try {
|
||||||
atext = Changeset.applyToAText(cs, atext, apool);
|
atext = Changeset.applyToAText(cs, atext, apool);
|
||||||
}catch(e) {
|
} catch(e) {
|
||||||
return callback(e)
|
return callback(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(null);
|
callback(null);
|
||||||
}
|
}
|
||||||
], function(err)
|
],
|
||||||
{
|
function(err) {
|
||||||
if(ERR(err, callback)) return;
|
if (ERR(err, callback)) return;
|
||||||
callback(null, atext);
|
callback(null, atext);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Pad.prototype.getRevision = function getRevisionChangeset(revNum, callback) {
|
Pad.prototype.getRevision = function getRevisionChangeset(revNum, callback) {
|
||||||
db.get("pad:"+this.id+":revs:"+revNum, callback);
|
db.get("pad:" + this.id + ":revs:" + revNum, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
Pad.prototype.getAllAuthorColors = function getAllAuthorColors(callback){
|
Pad.prototype.getAllAuthorColors = function getAllAuthorColors(callback) {
|
||||||
var authors = this.getAllAuthors();
|
var authors = this.getAllAuthors();
|
||||||
var returnTable = {};
|
var returnTable = {};
|
||||||
var colorPalette = authorManager.getColorPalette();
|
var colorPalette = authorManager.getColorPalette();
|
||||||
|
|
||||||
async.forEach(authors, function(author, callback){
|
async.forEach(authors, function(author, callback) {
|
||||||
authorManager.getAuthorColorId(author, function(err, colorId){
|
authorManager.getAuthorColorId(author, function(err, colorId) {
|
||||||
if(err){
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
//colorId might be a hex color or an number out of the palette
|
|
||||||
returnTable[author]=colorPalette[colorId] || colorId;
|
// colorId might be a hex color or an number out of the palette
|
||||||
|
returnTable[author] = colorPalette[colorId] || colorId;
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
}, function(err){
|
},
|
||||||
|
function(err) {
|
||||||
callback(err, returnTable);
|
callback(err, returnTable);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -266,15 +260,18 @@ Pad.prototype.getValidRevisionRange = function getValidRevisionRange(startRev, e
|
||||||
startRev = parseInt(startRev, 10);
|
startRev = parseInt(startRev, 10);
|
||||||
var head = this.getHeadRevisionNumber();
|
var head = this.getHeadRevisionNumber();
|
||||||
endRev = endRev ? parseInt(endRev, 10) : head;
|
endRev = endRev ? parseInt(endRev, 10) : head;
|
||||||
if(isNaN(startRev) || startRev < 0 || startRev > head) {
|
|
||||||
|
if (isNaN(startRev) || startRev < 0 || startRev > head) {
|
||||||
startRev = null;
|
startRev = null;
|
||||||
}
|
}
|
||||||
if(isNaN(endRev) || endRev < startRev) {
|
|
||||||
|
if (isNaN(endRev) || endRev < startRev) {
|
||||||
endRev = null;
|
endRev = null;
|
||||||
} else if(endRev > head) {
|
} else if (endRev > head) {
|
||||||
endRev = head;
|
endRev = head;
|
||||||
}
|
}
|
||||||
if(startRev !== null && endRev !== null) {
|
|
||||||
|
if (startRev !== null && endRev !== null) {
|
||||||
return { startRev: startRev , endRev: endRev }
|
return { startRev: startRev , endRev: endRev }
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -289,12 +286,12 @@ Pad.prototype.text = function text() {
|
||||||
};
|
};
|
||||||
|
|
||||||
Pad.prototype.setText = function setText(newText) {
|
Pad.prototype.setText = function setText(newText) {
|
||||||
//clean the new text
|
// clean the new text
|
||||||
newText = exports.cleanText(newText);
|
newText = exports.cleanText(newText);
|
||||||
|
|
||||||
var oldText = this.text();
|
var oldText = this.text();
|
||||||
|
|
||||||
//create the changeset
|
// create the changeset
|
||||||
// We want to ensure the pad still ends with a \n, but otherwise keep
|
// We want to ensure the pad still ends with a \n, but otherwise keep
|
||||||
// getText() and setText() consistent.
|
// getText() and setText() consistent.
|
||||||
var changeset;
|
var changeset;
|
||||||
|
@ -304,27 +301,27 @@ Pad.prototype.setText = function setText(newText) {
|
||||||
changeset = Changeset.makeSplice(oldText, 0, oldText.length-1, newText);
|
changeset = Changeset.makeSplice(oldText, 0, oldText.length-1, newText);
|
||||||
}
|
}
|
||||||
|
|
||||||
//append the changeset
|
// append the changeset
|
||||||
this.appendRevision(changeset);
|
this.appendRevision(changeset);
|
||||||
};
|
};
|
||||||
|
|
||||||
Pad.prototype.appendText = function appendText(newText) {
|
Pad.prototype.appendText = function appendText(newText) {
|
||||||
//clean the new text
|
// clean the new text
|
||||||
newText = exports.cleanText(newText);
|
newText = exports.cleanText(newText);
|
||||||
|
|
||||||
var oldText = this.text();
|
var oldText = this.text();
|
||||||
|
|
||||||
//create the changeset
|
// create the changeset
|
||||||
var changeset = Changeset.makeSplice(oldText, oldText.length, 0, newText);
|
var changeset = Changeset.makeSplice(oldText, oldText.length, 0, newText);
|
||||||
|
|
||||||
//append the changeset
|
// append the changeset
|
||||||
this.appendRevision(changeset);
|
this.appendRevision(changeset);
|
||||||
};
|
};
|
||||||
|
|
||||||
Pad.prototype.appendChatMessage = function appendChatMessage(text, userId, time) {
|
Pad.prototype.appendChatMessage = function appendChatMessage(text, userId, time) {
|
||||||
this.chatHead++;
|
this.chatHead++;
|
||||||
//save the chat entry in the database
|
// save the chat entry in the database
|
||||||
db.set("pad:"+this.id+":chat:"+this.chatHead, {"text": text, "userId": userId, "time": time});
|
db.set("pad:" + this.id + ":chat:" + this.chatHead, { "text": text, "userId": userId, "time": time });
|
||||||
this.saveToDatabase();
|
this.saveToDatabase();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -333,78 +330,71 @@ Pad.prototype.getChatMessage = function getChatMessage(entryNum, callback) {
|
||||||
var entry;
|
var entry;
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
//get the chat entry
|
// get the chat entry
|
||||||
function(callback)
|
function(callback) {
|
||||||
{
|
db.get("pad:" + _this.id + ":chat:" + entryNum, function(err, _entry) {
|
||||||
db.get("pad:"+_this.id+":chat:"+entryNum, function(err, _entry)
|
if (ERR(err, callback)) return;
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
entry = _entry;
|
entry = _entry;
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//add the authorName
|
|
||||||
function(callback)
|
// add the authorName
|
||||||
{
|
function(callback) {
|
||||||
//this chat message doesn't exist, return null
|
// this chat message doesn't exist, return null
|
||||||
if(entry == null)
|
if (entry == null) {
|
||||||
{
|
|
||||||
callback();
|
callback();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//get the authorName
|
// get the authorName
|
||||||
authorManager.getAuthorName(entry.userId, function(err, authorName)
|
authorManager.getAuthorName(entry.userId, function(err, authorName) {
|
||||||
{
|
if (ERR(err, callback)) return;
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
entry.userName = authorName;
|
entry.userName = authorName;
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
], function(err)
|
],
|
||||||
{
|
function(err) {
|
||||||
if(ERR(err, callback)) return;
|
if (ERR(err, callback)) return;
|
||||||
callback(null, entry);
|
callback(null, entry);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Pad.prototype.getChatMessages = function getChatMessages(start, end, callback) {
|
Pad.prototype.getChatMessages = function getChatMessages(start, end, callback) {
|
||||||
//collect the numbers of chat entries and in which order we need them
|
// collect the numbers of chat entries and in which order we need them
|
||||||
var neededEntries = [];
|
var neededEntries = [];
|
||||||
var order = 0;
|
var order = 0;
|
||||||
for(var i=start;i<=end; i++)
|
for (var i = start; i <= end; i++) {
|
||||||
{
|
neededEntries.push({ entryNum: i, order: order });
|
||||||
neededEntries.push({entryNum:i, order: order});
|
|
||||||
order++;
|
order++;
|
||||||
}
|
}
|
||||||
|
|
||||||
var _this = this;
|
var _this = this;
|
||||||
|
|
||||||
//get all entries out of the database
|
// get all entries out of the database
|
||||||
var entries = [];
|
var entries = [];
|
||||||
async.forEach(neededEntries, function(entryObject, callback)
|
async.forEach(neededEntries, function(entryObject, callback) {
|
||||||
{
|
_this.getChatMessage(entryObject.entryNum, function(err, entry) {
|
||||||
_this.getChatMessage(entryObject.entryNum, function(err, entry)
|
if (ERR(err, callback)) return;
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
entries[entryObject.order] = entry;
|
entries[entryObject.order] = entry;
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
}, function(err)
|
},
|
||||||
{
|
function(err) {
|
||||||
if(ERR(err, callback)) return;
|
if (ERR(err, callback)) return;
|
||||||
|
|
||||||
//sort out broken chat entries
|
// 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
|
// incremented, but the chat message wasn't added
|
||||||
var cleanedEntries = [];
|
var cleanedEntries = [];
|
||||||
for(var i=0;i<entries.length;i++)
|
for (var i=0; i < entries.length; i++) {
|
||||||
{
|
if (entries[i] != null) {
|
||||||
if(entries[i]!=null)
|
|
||||||
cleanedEntries.push(entries[i]);
|
cleanedEntries.push(entries[i]);
|
||||||
else
|
} else {
|
||||||
console.warn("WARNING: Found broken chat entry in pad " + _this.id);
|
console.warn("WARNING: Found broken chat entry in pad " + _this.id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
callback(null, cleanedEntries);
|
callback(null, cleanedEntries);
|
||||||
});
|
});
|
||||||
|
@ -413,38 +403,33 @@ Pad.prototype.getChatMessages = function getChatMessages(start, end, callback) {
|
||||||
Pad.prototype.init = function init(text, callback) {
|
Pad.prototype.init = function init(text, callback) {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
|
|
||||||
//replace text with default text if text isn't set
|
// replace text with default text if text isn't set
|
||||||
if(text == null)
|
if (text == null) {
|
||||||
{
|
|
||||||
text = settings.defaultPadText;
|
text = settings.defaultPadText;
|
||||||
}
|
}
|
||||||
|
|
||||||
//try to load the pad
|
// 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(ERR(err, callback)) return;
|
|
||||||
|
|
||||||
//if this pad exists, load it
|
// if this pad exists, load it
|
||||||
if(value != null)
|
if (value != null) {
|
||||||
{
|
// copy all attr. To a transfrom via fromJsonable if necessary
|
||||||
//copy all attr. To a transfrom via fromJsonable if necassary
|
for (var attr in value) {
|
||||||
for(var attr in value){
|
if (jsonableList.indexOf(attr) !== -1) {
|
||||||
if(jsonableList.indexOf(attr) !== -1){
|
|
||||||
_this[attr] = _this[attr].fromJsonable(value[attr]);
|
_this[attr] = _this[attr].fromJsonable(value[attr]);
|
||||||
} else {
|
} else {
|
||||||
_this[attr] = value[attr];
|
_this[attr] = value[attr];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
//this pad doesn't exist, so create it
|
// this pad doesn't exist, so create it
|
||||||
else
|
|
||||||
{
|
|
||||||
var firstChangeset = Changeset.makeSplice("\n", 0, 0, exports.cleanText(text));
|
var firstChangeset = Changeset.makeSplice("\n", 0, 0, exports.cleanText(text));
|
||||||
|
|
||||||
_this.appendRevision(firstChangeset, '');
|
_this.appendRevision(firstChangeset, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
hooks.callAll("padLoad", {'pad':_this});
|
hooks.callAll("padLoad", { 'pad': _this });
|
||||||
callback(null);
|
callback(null);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -471,51 +456,44 @@ Pad.prototype.copy = function copy(destinationID, force, callback) {
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
// if it's a group pad, let's make sure the group exists.
|
// if it's a group pad, let's make sure the group exists.
|
||||||
function(callback)
|
function(callback) {
|
||||||
{
|
if (destinationID.indexOf("$") === -1) {
|
||||||
if (destinationID.indexOf("$") === -1)
|
|
||||||
{
|
|
||||||
callback();
|
callback();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
destGroupID = destinationID.split("$")[0]
|
destGroupID = destinationID.split("$")[0];
|
||||||
groupManager.doesGroupExist(destGroupID, function (err, exists)
|
groupManager.doesGroupExist(destGroupID, function (err, exists) {
|
||||||
{
|
if (ERR(err, callback)) return;
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
|
|
||||||
//group does not exist
|
// group does not exist
|
||||||
if(exists == false)
|
if (exists == false) {
|
||||||
{
|
callback(new customError("groupID does not exist for destinationID", "apierror"));
|
||||||
callback(new customError("groupID does not exist for destinationID","apierror"));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//everything is fine, continue
|
// everything is fine, continue
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// if the pad exists, we should abort, unless forced.
|
// if the pad exists, we should abort, unless forced.
|
||||||
function(callback)
|
function(callback) {
|
||||||
{
|
padManager.doesPadExists(destinationID, function (err, exists) {
|
||||||
padManager.doesPadExists(destinationID, function (err, exists)
|
if (ERR(err, callback)) return;
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* this is the negation of a truthy comparison. Has been left in this
|
* this is the negation of a truthy comparison. Has been left in this
|
||||||
* wonky state to keep the old (possibly buggy) behaviour
|
* wonky state to keep the old (possibly buggy) behaviour
|
||||||
*/
|
*/
|
||||||
if (!(exists == true))
|
if (!(exists == true)) {
|
||||||
{
|
|
||||||
callback();
|
callback();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!force)
|
if (!force) {
|
||||||
{
|
|
||||||
console.error("erroring out without force");
|
console.error("erroring out without force");
|
||||||
callback(new customError("destinationID already exists","apierror"));
|
callback(new customError("destinationID already exists", "apierror"));
|
||||||
console.error("erroring out without force - after");
|
console.error("erroring out without force - after");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -527,54 +505,50 @@ Pad.prototype.copy = function copy(destinationID, force, callback) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// copy the 'pad' entry
|
// copy the 'pad' entry
|
||||||
function(callback)
|
function(callback) {
|
||||||
{
|
db.get("pad:" + sourceID, function(err, pad) {
|
||||||
db.get("pad:"+sourceID, function(err, pad) {
|
db.set("pad:" + destinationID, pad);
|
||||||
db.set("pad:"+destinationID, pad);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
},
|
},
|
||||||
//copy all relations
|
|
||||||
function(callback)
|
// copy all relations
|
||||||
{
|
function(callback) {
|
||||||
async.parallel([
|
async.parallel([
|
||||||
//copy all chat messages
|
// copy all chat messages
|
||||||
function(callback)
|
function(callback) {
|
||||||
{
|
|
||||||
var chatHead = _this.chatHead;
|
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) {
|
||||||
db.get("pad:"+sourceID+":chat:"+i, function (err, chat) {
|
|
||||||
if (ERR(err, callback)) return;
|
if (ERR(err, callback)) return;
|
||||||
db.set("pad:"+destinationID+":chat:"+i, chat);
|
db.set("pad:" + destinationID + ":chat:" + i, chat);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
},
|
},
|
||||||
//copy all revisions
|
|
||||||
function(callback)
|
// copy all revisions
|
||||||
{
|
function(callback) {
|
||||||
var revHead = _this.head;
|
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) {
|
||||||
db.get("pad:"+sourceID+":revs:"+i, function (err, rev) {
|
|
||||||
if (ERR(err, callback)) return;
|
if (ERR(err, callback)) return;
|
||||||
db.set("pad:"+destinationID+":revs:"+i, rev);
|
db.set("pad:" + destinationID + ":revs:" + i, rev);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
},
|
},
|
||||||
//add the new pad to all authors who contributed to the old one
|
|
||||||
function(callback)
|
// add the new pad to all authors who contributed to the old one
|
||||||
{
|
function(callback) {
|
||||||
var authorIDs = _this.getAllAuthors();
|
var authorIDs = _this.getAllAuthors();
|
||||||
authorIDs.forEach(function (authorID)
|
authorIDs.forEach(function (authorID) {
|
||||||
{
|
|
||||||
authorManager.addPad(authorID, destinationID);
|
authorManager.addPad(authorID, destinationID);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -583,25 +557,29 @@ Pad.prototype.copy = function copy(destinationID, force, callback) {
|
||||||
// parallel
|
// parallel
|
||||||
], callback);
|
], callback);
|
||||||
},
|
},
|
||||||
|
|
||||||
function(callback) {
|
function(callback) {
|
||||||
|
if (destGroupID) {
|
||||||
// Group pad? Add it to the group's list
|
// 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)
|
// Initialize the new pad (will update the listAllPads cache)
|
||||||
setTimeout(function(){
|
setTimeout(function() {
|
||||||
padManager.getPad(destinationID, null, callback) // this runs too early.
|
padManager.getPad(destinationID, null, callback) // this runs too early.
|
||||||
},10);
|
}, 10);
|
||||||
},
|
},
|
||||||
|
|
||||||
// let the plugins know the pad was copied
|
// let the plugins know the pad was copied
|
||||||
function(callback) {
|
function(callback) {
|
||||||
hooks.callAll('padCopy', { 'originalPad': _this, 'destinationID': destinationID });
|
hooks.callAll('padCopy', { 'originalPad': _this, 'destinationID': destinationID });
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
// series
|
// series
|
||||||
], function(err)
|
],
|
||||||
{
|
function(err) {
|
||||||
if(ERR(err, callback)) return;
|
if (ERR(err, callback)) return;
|
||||||
callback(null, {padID: destinationID});
|
callback(null, { padID: destinationID });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -609,46 +587,41 @@ Pad.prototype.remove = function remove(callback) {
|
||||||
var padID = this.id;
|
var padID = this.id;
|
||||||
var _this = this;
|
var _this = this;
|
||||||
|
|
||||||
//kick everyone from this pad
|
// kick everyone from this pad
|
||||||
padMessageHandler.kickSessionsFromPad(padID);
|
padMessageHandler.kickSessionsFromPad(padID);
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
//delete all relations
|
// delete all relations
|
||||||
function(callback)
|
function(callback) {
|
||||||
{
|
|
||||||
async.parallel([
|
async.parallel([
|
||||||
//is it a group pad? -> delete the entry of this pad in the group
|
// is it a group pad? -> delete the entry of this pad in the group
|
||||||
function(callback)
|
function(callback) {
|
||||||
{
|
if (padID.indexOf("$") === -1) {
|
||||||
if(padID.indexOf("$") === -1)
|
|
||||||
{
|
|
||||||
// it isn't a group pad, nothing to do here
|
// it isn't a group pad, nothing to do here
|
||||||
callback();
|
callback();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// it is a group pad
|
// it is a group pad
|
||||||
var groupID = padID.substring(0,padID.indexOf("$"));
|
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;
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
|
|
||||||
//remove the pad entry
|
// remove the pad entry
|
||||||
delete group.pads[padID];
|
delete group.pads[padID];
|
||||||
|
|
||||||
//set the new value
|
// set the new value
|
||||||
db.set("group:" + groupID, group);
|
db.set("group:" + groupID, group);
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//remove the readonly entries
|
|
||||||
function(callback)
|
// remove the readonly entries
|
||||||
{
|
function(callback) {
|
||||||
readOnlyManager.getReadOnlyId(padID, function(err, readonlyID)
|
readOnlyManager.getReadOnlyId(padID, function(err, readonlyID) {
|
||||||
{
|
if (ERR(err, callback)) return;
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
|
|
||||||
db.remove("pad2readonly:" + padID);
|
db.remove("pad2readonly:" + padID);
|
||||||
db.remove("readonly2pad:" + readonlyID);
|
db.remove("readonly2pad:" + readonlyID);
|
||||||
|
@ -656,37 +629,34 @@ Pad.prototype.remove = function remove(callback) {
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//delete all chat messages
|
|
||||||
function(callback)
|
// delete all chat messages
|
||||||
{
|
function(callback) {
|
||||||
var chatHead = _this.chatHead;
|
var chatHead = _this.chatHead;
|
||||||
|
|
||||||
for(var i=0;i<=chatHead;i++)
|
for (var i = 0; i <= chatHead; i++) {
|
||||||
{
|
db.remove("pad:" + padID + ":chat:" + i);
|
||||||
db.remove("pad:"+padID+":chat:"+i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
},
|
},
|
||||||
//delete all revisions
|
|
||||||
function(callback)
|
// delete all revisions
|
||||||
{
|
function(callback) {
|
||||||
var revHead = _this.head;
|
var revHead = _this.head;
|
||||||
|
|
||||||
for(var i=0;i<=revHead;i++)
|
for (var i = 0; i <= revHead; i++) {
|
||||||
{
|
db.remove("pad:" + padID + ":revs:" + i);
|
||||||
db.remove("pad:"+padID+":revs:"+i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
},
|
},
|
||||||
//remove pad from all authors who contributed
|
|
||||||
function(callback)
|
// remove pad from all authors who contributed
|
||||||
{
|
function(callback) {
|
||||||
var authorIDs = _this.getAllAuthors();
|
var authorIDs = _this.getAllAuthors();
|
||||||
|
|
||||||
authorIDs.forEach(function (authorID)
|
authorIDs.forEach(function (authorID) {
|
||||||
{
|
|
||||||
authorManager.removePad(authorID, padID);
|
authorManager.removePad(authorID, padID);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -694,20 +664,21 @@ Pad.prototype.remove = function remove(callback) {
|
||||||
}
|
}
|
||||||
], callback);
|
], callback);
|
||||||
},
|
},
|
||||||
//delete the pad entry and delete pad from padManager
|
|
||||||
function(callback)
|
// delete the pad entry and delete pad from padManager
|
||||||
{
|
function(callback) {
|
||||||
padManager.removePad(padID);
|
padManager.removePad(padID);
|
||||||
hooks.callAll("padRemove", {'padID':padID});
|
hooks.callAll("padRemove", { 'padID': padID });
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
], function(err)
|
],
|
||||||
{
|
function(err) {
|
||||||
if(ERR(err, callback)) return;
|
if (ERR(err, callback)) return;
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
//set in db
|
|
||||||
|
// set in db
|
||||||
Pad.prototype.setPublicStatus = function setPublicStatus(publicStatus) {
|
Pad.prototype.setPublicStatus = function setPublicStatus(publicStatus) {
|
||||||
this.publicStatus = publicStatus;
|
this.publicStatus = publicStatus;
|
||||||
this.saveToDatabase();
|
this.saveToDatabase();
|
||||||
|
@ -727,14 +698,14 @@ Pad.prototype.isPasswordProtected = function isPasswordProtected() {
|
||||||
};
|
};
|
||||||
|
|
||||||
Pad.prototype.addSavedRevision = function addSavedRevision(revNum, savedById, label) {
|
Pad.prototype.addSavedRevision = function addSavedRevision(revNum, savedById, label) {
|
||||||
//if this revision is already saved, return silently
|
// if this revision is already saved, return silently
|
||||||
for(var i in this.savedRevisions){
|
for (var i in this.savedRevisions) {
|
||||||
if(this.savedRevisions[i] && this.savedRevisions[i].revNum === revNum){
|
if (this.savedRevisions[i] && this.savedRevisions[i].revNum === revNum) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//build the saved revision object
|
// build the saved revision object
|
||||||
var savedRevision = {};
|
var savedRevision = {};
|
||||||
savedRevision.revNum = revNum;
|
savedRevision.revNum = revNum;
|
||||||
savedRevision.savedById = savedById;
|
savedRevision.savedById = savedById;
|
||||||
|
@ -742,7 +713,7 @@ Pad.prototype.addSavedRevision = function addSavedRevision(revNum, savedById, la
|
||||||
savedRevision.timestamp = Date.now();
|
savedRevision.timestamp = Date.now();
|
||||||
savedRevision.id = randomString(10);
|
savedRevision.id = randomString(10);
|
||||||
|
|
||||||
//save this new saved revision
|
// save this new saved revision
|
||||||
this.savedRevisions.push(savedRevision);
|
this.savedRevisions.push(savedRevision);
|
||||||
this.saveToDatabase();
|
this.saveToDatabase();
|
||||||
};
|
};
|
||||||
|
@ -753,19 +724,17 @@ Pad.prototype.getSavedRevisions = function getSavedRevisions() {
|
||||||
|
|
||||||
/* Crypto helper methods */
|
/* Crypto helper methods */
|
||||||
|
|
||||||
function hash(password, salt)
|
function hash(password, salt) {
|
||||||
{
|
|
||||||
var shasum = crypto.createHash('sha512');
|
var shasum = crypto.createHash('sha512');
|
||||||
shasum.update(password + salt);
|
shasum.update(password + salt);
|
||||||
|
|
||||||
return shasum.digest("hex") + "$" + salt;
|
return shasum.digest("hex") + "$" + salt;
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateSalt()
|
function generateSalt() {
|
||||||
{
|
|
||||||
return randomString(86);
|
return randomString(86);
|
||||||
}
|
}
|
||||||
|
|
||||||
function compare(hashStr, password)
|
function compare(hashStr, password) {
|
||||||
{
|
|
||||||
return hash(password, hashStr.split("$")[1]) === hashStr;
|
return hash(password, hashStr.split("$")[1]) === hashStr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,12 +35,11 @@ var db = require("./DB").db;
|
||||||
* that's defined somewhere more sensible.
|
* that's defined somewhere more sensible.
|
||||||
*/
|
*/
|
||||||
var globalPads = {
|
var globalPads = {
|
||||||
get: function (name) { return this[':'+name]; },
|
get: function(name) { return this[':'+name]; },
|
||||||
set: function (name, value)
|
set: function(name, value) {
|
||||||
{
|
|
||||||
this[':'+name] = value;
|
this[':'+name] = value;
|
||||||
},
|
},
|
||||||
remove: function (name) {
|
remove: function(name) {
|
||||||
delete this[':'+name];
|
delete this[':'+name];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -54,56 +53,63 @@ var padList = {
|
||||||
list: [],
|
list: [],
|
||||||
sorted : false,
|
sorted : false,
|
||||||
initiated: false,
|
initiated: false,
|
||||||
init: function(cb)
|
init: function(cb) {
|
||||||
{
|
db.findKeys("pad:*", "*:*:*", function(err, dbData) {
|
||||||
db.findKeys("pad:*", "*:*:*", function(err, dbData)
|
if (ERR(err, cb)) return;
|
||||||
{
|
|
||||||
if(ERR(err, cb)) return;
|
if (dbData != null) {
|
||||||
if(dbData != null){
|
|
||||||
padList.initiated = true
|
padList.initiated = true
|
||||||
dbData.forEach(function(val){
|
dbData.forEach(function(val) {
|
||||||
padList.addPad(val.replace(/pad:/,""),false);
|
padList.addPad(val.replace(/pad:/,""),false);
|
||||||
});
|
});
|
||||||
cb && cb()
|
|
||||||
|
cb && cb();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
load: function(cb) {
|
load: function(cb) {
|
||||||
if(this.initiated) cb && cb()
|
if (this.initiated) {
|
||||||
else this.init(cb)
|
cb && cb();
|
||||||
|
} else {
|
||||||
|
this.init(cb);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Returns all pads in alphabetical order as array.
|
* Returns all pads in alphabetical order as array.
|
||||||
*/
|
*/
|
||||||
getPads: function(cb){
|
getPads: function(cb) {
|
||||||
this.load(function() {
|
this.load(function() {
|
||||||
if(!padList.sorted){
|
if (!padList.sorted) {
|
||||||
padList.list = padList.list.sort();
|
padList.list = padList.list.sort();
|
||||||
padList.sorted = true;
|
padList.sorted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
cb && cb(padList.list);
|
cb && cb(padList.list);
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
addPad: function(name)
|
addPad: function(name) {
|
||||||
{
|
if (!this.initiated) return;
|
||||||
if(!this.initiated) return;
|
|
||||||
if(this.list.indexOf(name) == -1){
|
if (this.list.indexOf(name) == -1) {
|
||||||
this.list.push(name);
|
this.list.push(name);
|
||||||
this.sorted=false;
|
this.sorted = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
removePad: function(name)
|
removePad: function(name) {
|
||||||
{
|
if (!this.initiated) return;
|
||||||
if(!this.initiated) return;
|
|
||||||
var index = this.list.indexOf(name);
|
var index = this.list.indexOf(name);
|
||||||
if(index>-1){
|
|
||||||
this.list.splice(index,1);
|
if (index > -1) {
|
||||||
this.sorted=false;
|
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
|
* An array of padId transformations. These represent changes in pad name policy over
|
||||||
|
@ -121,54 +127,52 @@ var padIdTransforms = [
|
||||||
*/
|
*/
|
||||||
exports.getPad = function(id, text, callback)
|
exports.getPad = function(id, text, callback)
|
||||||
{
|
{
|
||||||
//check if this is a valid padId
|
// check if this is a valid padId
|
||||||
if(!exports.isValidPadId(id))
|
if (!exports.isValidPadId(id)) {
|
||||||
{
|
callback(new customError(id + " is not a valid padId", "apierror"));
|
||||||
callback(new customError(id + " is not a valid padId","apierror"));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//make text an optional parameter
|
// make text an optional parameter
|
||||||
if(typeof text == "function")
|
if (typeof text == "function") {
|
||||||
{
|
|
||||||
callback = text;
|
callback = text;
|
||||||
text = null;
|
text = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if this is a valid text
|
// check if this is a valid text
|
||||||
if(text != null)
|
if (text != null) {
|
||||||
{
|
// check if text is a string
|
||||||
//check if text is a string
|
if (typeof text != "string") {
|
||||||
if(typeof text != "string")
|
callback(new customError("text is not a string", "apierror"));
|
||||||
{
|
|
||||||
callback(new customError("text is not a string","apierror"));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if text is less than 100k chars
|
// check if text is less than 100k chars
|
||||||
if(text.length > 100000)
|
if (text.length > 100000) {
|
||||||
{
|
callback(new customError("text must be less than 100k chars", "apierror"));
|
||||||
callback(new customError("text must be less than 100k chars","apierror"));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var pad = globalPads.get(id);
|
var pad = globalPads.get(id);
|
||||||
|
|
||||||
//return pad if its already loaded
|
// return pad if it's already loaded
|
||||||
if(pad != null)
|
if (pad != null) {
|
||||||
{
|
|
||||||
callback(null, pad);
|
callback(null, pad);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//try to load pad
|
// try to load pad
|
||||||
pad = new Pad(id);
|
pad = new Pad(id);
|
||||||
|
|
||||||
//initalize the pad
|
// initalize the pad
|
||||||
pad.init(text, function(err)
|
pad.init(text, function(err) {
|
||||||
{
|
if (ERR(err, callback)) return;
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
globalPads.set(id, pad);
|
globalPads.set(id, pad);
|
||||||
padList.addPad(id);
|
padList.addPad(id);
|
||||||
callback(null, pad);
|
callback(null, pad);
|
||||||
|
@ -182,49 +186,48 @@ exports.listAllPads = function(cb)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//checks if a pad exists
|
// checks if a pad exists
|
||||||
exports.doesPadExists = function(padId, callback)
|
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(ERR(err, callback)) return;
|
|
||||||
if(value != null && value.atext){
|
if (value != null && value.atext) {
|
||||||
callback(null, true);
|
callback(null, true);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
callback(null, false);
|
callback(null, false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//returns a sanitized padId, respecting legacy pad id formats
|
// returns a sanitized padId, respecting legacy pad id formats
|
||||||
exports.sanitizePadId = function(padId, callback) {
|
exports.sanitizePadId = function(padId, callback) {
|
||||||
var transform_index = arguments[2] || 0;
|
var transform_index = arguments[2] || 0;
|
||||||
//we're out of possible transformations, so just return it
|
|
||||||
if(transform_index >= padIdTransforms.length)
|
// we're out of possible transformations, so just return it
|
||||||
{
|
if (transform_index >= padIdTransforms.length) {
|
||||||
callback(padId);
|
callback(padId);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if padId exists
|
// check if padId exists
|
||||||
exports.doesPadExists(padId, function(junk, exists)
|
exports.doesPadExists(padId, function(junk, exists) {
|
||||||
{
|
if (exists) {
|
||||||
if(exists)
|
|
||||||
{
|
|
||||||
callback(padId);
|
callback(padId);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//get the next transformation *that's different*
|
// get the next transformation *that's different*
|
||||||
var transformedPadId = padId;
|
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]);
|
transformedPadId = padId.replace(padIdTransforms[transform_index][0], padIdTransforms[transform_index][1]);
|
||||||
transform_index += 1;
|
transform_index += 1;
|
||||||
}
|
}
|
||||||
//check the next transform
|
|
||||||
|
// check the next transform
|
||||||
exports.sanitizePadId(transformedPadId, callback, transform_index);
|
exports.sanitizePadId(transformedPadId, callback, transform_index);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -237,13 +240,13 @@ exports.isValidPadId = function(padId)
|
||||||
/**
|
/**
|
||||||
* Removes the pad from database and unloads it.
|
* Removes the pad from database and unloads it.
|
||||||
*/
|
*/
|
||||||
exports.removePad = function(padId){
|
exports.removePad = function(padId) {
|
||||||
db.remove("pad:"+padId);
|
db.remove("pad:" + padId);
|
||||||
exports.unloadPad(padId);
|
exports.unloadPad(padId);
|
||||||
padList.removePad(padId);
|
padList.removePad(padId);
|
||||||
}
|
}
|
||||||
|
|
||||||
//removes a pad from the cache
|
// removes a pad from the cache
|
||||||
exports.unloadPad = function(padId)
|
exports.unloadPad = function(padId)
|
||||||
{
|
{
|
||||||
globalPads.remove(padId);
|
globalPads.remove(padId);
|
||||||
|
|
|
@ -33,39 +33,36 @@ exports.getReadOnlyId = function (padId, callback)
|
||||||
var readOnlyId;
|
var readOnlyId;
|
||||||
|
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
//check if there is a pad2readonly entry
|
// check if there is a pad2readonly entry
|
||||||
function(callback)
|
function(callback) {
|
||||||
{
|
|
||||||
db.get("pad2readonly:" + padId, callback);
|
db.get("pad2readonly:" + padId, callback);
|
||||||
},
|
},
|
||||||
function(dbReadOnlyId, callback)
|
|
||||||
{
|
function(dbReadOnlyId, callback) {
|
||||||
//there is no readOnly Entry in the database, let's create one
|
if (dbReadOnlyId == null) {
|
||||||
if(dbReadOnlyId == null)
|
// there is no readOnly Entry in the database, let's create one
|
||||||
{
|
|
||||||
readOnlyId = "r." + randomString(16);
|
readOnlyId = "r." + randomString(16);
|
||||||
|
|
||||||
db.set("pad2readonly:" + padId, readOnlyId);
|
db.set("pad2readonly:" + padId, readOnlyId);
|
||||||
db.set("readonly2pad:" + readOnlyId, padId);
|
db.set("readonly2pad:" + readOnlyId, padId);
|
||||||
}
|
} else {
|
||||||
//there is a readOnly Entry in the database, let's take this one
|
// there is a readOnly Entry in the database, let's take this one
|
||||||
else
|
|
||||||
{
|
|
||||||
readOnlyId = dbReadOnlyId;
|
readOnlyId = dbReadOnlyId;
|
||||||
}
|
}
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
], function(err)
|
],
|
||||||
{
|
function(err) {
|
||||||
if(ERR(err, callback)) return;
|
if (ERR(err, callback)) return;
|
||||||
//return the results
|
|
||||||
|
// return the results
|
||||||
callback(null, readOnlyId);
|
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
|
* @param {String} readOnlyId read only id
|
||||||
*/
|
*/
|
||||||
exports.getPadId = function(readOnlyId, callback)
|
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
|
* @param {String} padIdOrReadonlyPadId read only id or real pad id
|
||||||
*/
|
*/
|
||||||
exports.getIds = function(id, callback) {
|
exports.getIds = function(id, callback) {
|
||||||
if (id.indexOf("r.") == 0)
|
if (id.indexOf("r.") == 0) {
|
||||||
exports.getPadId(id, function (err, value) {
|
exports.getPadId(id, function (err, value) {
|
||||||
if(ERR(err, callback)) return;
|
if (ERR(err, callback)) return;
|
||||||
|
|
||||||
callback(null, {
|
callback(null, {
|
||||||
readOnlyPadId: id,
|
readOnlyPadId: id,
|
||||||
padId: value, // Might be null, if this is an unknown read-only id
|
padId: value, // Might be null, if this is an unknown read-only id
|
||||||
readonly: true
|
readonly: true
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
else
|
} else {
|
||||||
exports.getReadOnlyId(id, function (err, value) {
|
exports.getReadOnlyId(id, function (err, value) {
|
||||||
callback(null, {
|
callback(null, {
|
||||||
readOnlyPadId: value,
|
readOnlyPadId: value,
|
||||||
|
@ -95,4 +93,5 @@ exports.getIds = function(id, callback) {
|
||||||
readonly: false
|
readonly: false
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
var ERR = require("async-stacktrace");
|
var ERR = require("async-stacktrace");
|
||||||
var async = require("async");
|
var async = require("async");
|
||||||
var authorManager = require("./AuthorManager");
|
var authorManager = require("./AuthorManager");
|
||||||
|
@ -37,56 +36,54 @@ var authLogger = log4js.getLogger("auth");
|
||||||
* @param password the password the user has given to access this pad, can be null
|
* @param password the password the user has given to access this pad, can be null
|
||||||
* @param callback will be called with (err, {accessStatus: grant|deny|wrongPassword|needPassword, authorID: a.xxxxxx})
|
* @param callback will be called with (err, {accessStatus: grant|deny|wrongPassword|needPassword, authorID: a.xxxxxx})
|
||||||
*/
|
*/
|
||||||
exports.checkAccess = function (padID, sessionCookie, token, password, callback)
|
exports.checkAccess = function(padID, sessionCookie, token, password, callback)
|
||||||
{
|
{
|
||||||
var statusObject;
|
var statusObject;
|
||||||
|
|
||||||
if(!padID) {
|
if (!padID) {
|
||||||
callback(null, {accessStatus: "deny"});
|
callback(null, {accessStatus: "deny"});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow plugins to deny access
|
// allow plugins to deny access
|
||||||
var deniedByHook = hooks.callAll("onAccessCheck", {'padID': padID, 'password': password, 'token': token, 'sessionCookie': sessionCookie}).indexOf(false) > -1;
|
var deniedByHook = hooks.callAll("onAccessCheck", {'padID': padID, 'password': password, 'token': token, 'sessionCookie': sessionCookie}).indexOf(false) > -1;
|
||||||
if(deniedByHook)
|
if (deniedByHook) {
|
||||||
{
|
|
||||||
callback(null, {accessStatus: "deny"});
|
callback(null, {accessStatus: "deny"});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (settings.requireSession) {
|
||||||
// a valid session is required (api-only mode)
|
// a valid session is required (api-only mode)
|
||||||
if(settings.requireSession)
|
if (!sessionCookie) {
|
||||||
{
|
|
||||||
// without sessionCookie, access is denied
|
// without sessionCookie, access is denied
|
||||||
if(!sessionCookie)
|
|
||||||
{
|
|
||||||
callback(null, {accessStatus: "deny"});
|
callback(null, {accessStatus: "deny"});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
// a session is not required, so we'll check if it's a public pad
|
// 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
|
// it's not a group pad, means we can grant access
|
||||||
if(padID.indexOf("$") == -1)
|
|
||||||
{
|
// get author for this token
|
||||||
//get author for this token
|
authorManager.getAuthor4Token(token, function(err, author) {
|
||||||
authorManager.getAuthor4Token(token, function(err, author)
|
if (ERR(err, callback)) return;
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
|
|
||||||
// assume user has access
|
// assume user has access
|
||||||
statusObject = {accessStatus: "grant", authorID: author};
|
statusObject = { accessStatus: "grant", authorID: author };
|
||||||
// user can't create pads
|
|
||||||
if(settings.editOnly)
|
|
||||||
{
|
|
||||||
// check if pad exists
|
|
||||||
padManager.doesPadExists(padID, function(err, exists)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
|
|
||||||
|
if (settings.editOnly) {
|
||||||
|
// user can't create pads
|
||||||
|
|
||||||
|
// check if pad exists
|
||||||
|
padManager.doesPadExists(padID, function(err, exists) {
|
||||||
|
if (ERR(err, callback)) return;
|
||||||
|
|
||||||
|
if (!exists) {
|
||||||
// pad doesn't exist - user can't have access
|
// 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
|
// grant or deny access, with author of token
|
||||||
callback(null, statusObject);
|
callback(null, statusObject);
|
||||||
});
|
});
|
||||||
|
@ -99,7 +96,7 @@ exports.checkAccess = function (padID, sessionCookie, token, password, callback)
|
||||||
callback(null, statusObject);
|
callback(null, statusObject);
|
||||||
});
|
});
|
||||||
|
|
||||||
//don't continue
|
// don't continue
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,59 +111,55 @@ exports.checkAccess = function (padID, sessionCookie, token, password, callback)
|
||||||
var passwordStatus = password == null ? "notGiven" : "wrong"; // notGiven, correct, wrong
|
var passwordStatus = password == null ? "notGiven" : "wrong"; // notGiven, correct, wrong
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
//get basic informations from the database
|
// get basic informations from the database
|
||||||
function(callback)
|
function(callback) {
|
||||||
{
|
|
||||||
async.parallel([
|
async.parallel([
|
||||||
//does pad exists
|
// does pad exist
|
||||||
function(callback)
|
function(callback) {
|
||||||
{
|
padManager.doesPadExists(padID, function(err, exists) {
|
||||||
padManager.doesPadExists(padID, function(err, exists)
|
if (ERR(err, callback)) return;
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
padExists = exists;
|
padExists = exists;
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//get information about all sessions contained in this cookie
|
|
||||||
function(callback)
|
// get information about all sessions contained in this cookie
|
||||||
{
|
function(callback) {
|
||||||
if (!sessionCookie)
|
if (!sessionCookie) {
|
||||||
{
|
|
||||||
callback();
|
callback();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var sessionIDs = sessionCookie.split(',');
|
var sessionIDs = sessionCookie.split(',');
|
||||||
async.forEach(sessionIDs, function(sessionID, callback)
|
|
||||||
{
|
async.forEach(sessionIDs, function(sessionID, callback) {
|
||||||
sessionManager.getSessionInfo(sessionID, function(err, sessionInfo)
|
sessionManager.getSessionInfo(sessionID, function(err, sessionInfo) {
|
||||||
{
|
// skip session if it doesn't exist
|
||||||
//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");
|
authLogger.debug("Auth failed: unknown session");
|
||||||
callback();
|
callback();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ERR(err, callback)) return;
|
if (ERR(err, callback)) return;
|
||||||
|
|
||||||
var now = Math.floor(Date.now()/1000);
|
var now = Math.floor(Date.now()/1000);
|
||||||
|
|
||||||
//is it for this group?
|
// is it for this group?
|
||||||
if(sessionInfo.groupID != groupID)
|
if (sessionInfo.groupID != groupID) {
|
||||||
{
|
|
||||||
authLogger.debug("Auth failed: wrong group");
|
authLogger.debug("Auth failed: wrong group");
|
||||||
callback();
|
callback();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//is validUntil still ok?
|
// is validUntil still ok?
|
||||||
if(sessionInfo.validUntil <= now)
|
if (sessionInfo.validUntil <= now) {
|
||||||
{
|
|
||||||
authLogger.debug("Auth failed: validUntil");
|
authLogger.debug("Auth failed: validUntil");
|
||||||
callback();
|
callback();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,152 +171,133 @@ exports.checkAccess = function (padID, sessionCookie, token, password, callback)
|
||||||
});
|
});
|
||||||
}, callback);
|
}, callback);
|
||||||
},
|
},
|
||||||
//get author for token
|
|
||||||
function(callback)
|
// get author for token
|
||||||
{
|
function(callback) {
|
||||||
//get author for this token
|
// get author for this token
|
||||||
authorManager.getAuthor4Token(token, function(err, author)
|
authorManager.getAuthor4Token(token, function(err, author) {
|
||||||
{
|
if (ERR(err, callback)) return;
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
tokenAuthor = author;
|
tokenAuthor = author;
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
], callback);
|
], callback);
|
||||||
},
|
},
|
||||||
//get more informations of this pad, if avaiable
|
|
||||||
function(callback)
|
// get more informations of this pad, if avaiable
|
||||||
{
|
function(callback) {
|
||||||
//skip this if the pad doesn't exists
|
// skip this if the pad doesn't exist
|
||||||
if(padExists == false)
|
if (padExists == false) {
|
||||||
{
|
|
||||||
callback();
|
callback();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
padManager.getPad(padID, function(err, pad)
|
padManager.getPad(padID, function(err, pad) {
|
||||||
{
|
if (ERR(err, callback)) return;
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
|
|
||||||
//is it a public pad?
|
// is it a public pad?
|
||||||
isPublic = pad.getPublicStatus();
|
isPublic = pad.getPublicStatus();
|
||||||
|
|
||||||
//is it password protected?
|
// is it password protected?
|
||||||
isPasswordProtected = pad.isPasswordProtected();
|
isPasswordProtected = pad.isPasswordProtected();
|
||||||
|
|
||||||
//is password correct?
|
// is password correct?
|
||||||
if(isPasswordProtected && password && pad.isCorrectPassword(password))
|
if (isPasswordProtected && password && pad.isCorrectPassword(password)) {
|
||||||
{
|
|
||||||
passwordStatus = "correct";
|
passwordStatus = "correct";
|
||||||
}
|
}
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function(callback)
|
|
||||||
{
|
function(callback) {
|
||||||
//- a valid session for this group is avaible AND pad exists
|
if (validSession && padExists) {
|
||||||
if(validSession && padExists)
|
// - a valid session for this group is avaible AND pad exists
|
||||||
{
|
if (!isPasswordProtected) {
|
||||||
//- the pad is not password protected
|
// - the pad is not password protected
|
||||||
if(!isPasswordProtected)
|
|
||||||
{
|
// --> grant access
|
||||||
//--> grant access
|
statusObject = { accessStatus: "grant", authorID: sessionAuthor };
|
||||||
statusObject = {accessStatus: "grant", authorID: sessionAuthor};
|
} else if (settings.sessionNoPassword) {
|
||||||
}
|
// - the setting to bypass password validation is set
|
||||||
//- the setting to bypass password validation is set
|
|
||||||
else if(settings.sessionNoPassword)
|
// --> grant access
|
||||||
{
|
statusObject = { accessStatus: "grant", authorID: sessionAuthor };
|
||||||
//--> grant access
|
} else if (isPasswordProtected && passwordStatus == "correct") {
|
||||||
statusObject = {accessStatus: "grant", authorID: sessionAuthor};
|
// - the pad is password protected and password is correct
|
||||||
}
|
|
||||||
//- the pad is password protected and password is correct
|
// --> grant access
|
||||||
else if(isPasswordProtected && passwordStatus == "correct")
|
statusObject = { accessStatus: "grant", authorID: sessionAuthor };
|
||||||
{
|
} else if (isPasswordProtected && passwordStatus == "wrong") {
|
||||||
//--> grant access
|
// - the pad is password protected but wrong password given
|
||||||
statusObject = {accessStatus: "grant", authorID: sessionAuthor};
|
|
||||||
}
|
// --> deny access, ask for new password and tell them that the password is wrong
|
||||||
//- the pad is password protected but wrong password given
|
statusObject = { accessStatus: "wrongPassword" };
|
||||||
else if(isPasswordProtected && passwordStatus == "wrong")
|
} else if (isPasswordProtected && passwordStatus == "notGiven") {
|
||||||
{
|
// - the pad is password protected but no password given
|
||||||
//--> deny access, ask for new password and tell them that the password is wrong
|
|
||||||
statusObject = {accessStatus: "wrongPassword"};
|
// --> ask for password
|
||||||
}
|
statusObject = { accessStatus: "needPassword" };
|
||||||
//- the pad is password protected but no password given
|
} else {
|
||||||
else if(isPasswordProtected && passwordStatus == "notGiven")
|
|
||||||
{
|
|
||||||
//--> ask for password
|
|
||||||
statusObject = {accessStatus: "needPassword"};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new Error("Ops, something wrong happend");
|
throw new Error("Ops, something wrong happend");
|
||||||
}
|
}
|
||||||
}
|
} else if (validSession && !padExists) {
|
||||||
//- a valid session for this group avaible but pad doesn't exists
|
// - a valid session for this group avaible but pad doesn't exist
|
||||||
else if(validSession && !padExists)
|
|
||||||
{
|
// --> grant access
|
||||||
//--> grant access
|
|
||||||
statusObject = {accessStatus: "grant", authorID: sessionAuthor};
|
statusObject = {accessStatus: "grant", authorID: sessionAuthor};
|
||||||
//--> deny access if user isn't allowed to create the pad
|
|
||||||
if(settings.editOnly)
|
if (settings.editOnly) {
|
||||||
{
|
// --> deny access if user isn't allowed to create the pad
|
||||||
authLogger.debug("Auth failed: valid session & pad does not exist");
|
authLogger.debug("Auth failed: valid session & pad does not exist");
|
||||||
statusObject.accessStatus = "deny";
|
statusObject.accessStatus = "deny";
|
||||||
}
|
}
|
||||||
}
|
} else if (!validSession && padExists) {
|
||||||
// there is no valid session avaiable AND pad exists
|
// there is no valid session avaiable AND pad exists
|
||||||
else if(!validSession && padExists)
|
|
||||||
{
|
// -- it's public and not password protected
|
||||||
//-- its public and not password protected
|
if (isPublic && !isPasswordProtected) {
|
||||||
if(isPublic && !isPasswordProtected)
|
// --> grant access, with author of token
|
||||||
{
|
|
||||||
//--> grant access, with author of token
|
|
||||||
statusObject = {accessStatus: "grant", authorID: tokenAuthor};
|
statusObject = {accessStatus: "grant", authorID: tokenAuthor};
|
||||||
}
|
} else if (isPublic && isPasswordProtected && passwordStatus == "correct") {
|
||||||
//- its public and password protected and password is correct
|
// - it's public and password protected and password is correct
|
||||||
else if(isPublic && isPasswordProtected && passwordStatus == "correct")
|
|
||||||
{
|
// --> grant access, with author of token
|
||||||
//--> grant access, with author of token
|
|
||||||
statusObject = {accessStatus: "grant", authorID: tokenAuthor};
|
statusObject = {accessStatus: "grant", authorID: tokenAuthor};
|
||||||
}
|
} else if (isPublic && isPasswordProtected && passwordStatus == "wrong") {
|
||||||
//- its public and the pad is password protected but wrong password given
|
// - it's public and the pad is password protected but wrong password given
|
||||||
else if(isPublic && isPasswordProtected && passwordStatus == "wrong")
|
|
||||||
{
|
// --> deny access, ask for new password and tell them that the password is wrong
|
||||||
//--> deny access, ask for new password and tell them that the password is wrong
|
|
||||||
statusObject = {accessStatus: "wrongPassword"};
|
statusObject = {accessStatus: "wrongPassword"};
|
||||||
}
|
} else if (isPublic && isPasswordProtected && passwordStatus == "notGiven") {
|
||||||
//- its public and the pad is password protected but no password given
|
// - it's public and the pad is password protected but no password given
|
||||||
else if(isPublic && isPasswordProtected && passwordStatus == "notGiven")
|
|
||||||
{
|
// --> ask for password
|
||||||
//--> ask for password
|
|
||||||
statusObject = {accessStatus: "needPassword"};
|
statusObject = {accessStatus: "needPassword"};
|
||||||
}
|
} else if (!isPublic) {
|
||||||
//- its not public
|
// - it's not public
|
||||||
else if(!isPublic)
|
|
||||||
{
|
|
||||||
authLogger.debug("Auth failed: invalid session & pad is not public");
|
authLogger.debug("Auth failed: invalid session & pad is not public");
|
||||||
//--> deny access
|
// --> deny access
|
||||||
statusObject = {accessStatus: "deny"};
|
statusObject = {accessStatus: "deny"};
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new Error("Ops, something wrong happend");
|
throw new Error("Ops, something wrong happend");
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
// there is no valid session avaiable AND pad doesn't exists
|
// there is no valid session avaiable AND pad doesn't exist
|
||||||
else
|
|
||||||
{
|
|
||||||
authLogger.debug("Auth failed: invalid session & pad does not exist");
|
authLogger.debug("Auth failed: invalid session & pad does not exist");
|
||||||
//--> deny access
|
// --> deny access
|
||||||
statusObject = {accessStatus: "deny"};
|
statusObject = {accessStatus: "deny"};
|
||||||
}
|
}
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
], function(err)
|
],
|
||||||
{
|
function(err) {
|
||||||
if(ERR(err, callback)) return;
|
if (ERR(err, callback)) return;
|
||||||
|
|
||||||
callback(null, statusObject);
|
callback(null, statusObject);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
var ERR = require("async-stacktrace");
|
var ERR = require("async-stacktrace");
|
||||||
var customError = require("../utils/customError");
|
var customError = require("../utils/customError");
|
||||||
var randomString = require("../utils/randomstring");
|
var randomString = require("../utils/randomstring");
|
||||||
|
@ -45,127 +44,119 @@ exports.createSession = function(groupID, authorID, validUntil, callback)
|
||||||
var sessionID;
|
var sessionID;
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
//check if group exists
|
// check if the group exists
|
||||||
function(callback)
|
function(callback)
|
||||||
{
|
{
|
||||||
groupMangager.doesGroupExist(groupID, function(err, exists)
|
groupMangager.doesGroupExist(groupID, function(err, exists)
|
||||||
{
|
{
|
||||||
if(ERR(err, callback)) return;
|
if(ERR(err, callback)) return;
|
||||||
|
|
||||||
//group does not exist
|
// group does not exist
|
||||||
if(exists == false)
|
if (exists == false) {
|
||||||
{
|
callback(new customError("groupID does not exist", "apierror"));
|
||||||
callback(new customError("groupID does not exist","apierror"));
|
} else {
|
||||||
}
|
// everything is fine, continue
|
||||||
//everything is fine, continue
|
|
||||||
else
|
|
||||||
{
|
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//check if author exists
|
|
||||||
|
// check if the author exists
|
||||||
function(callback)
|
function(callback)
|
||||||
{
|
{
|
||||||
authorMangager.doesAuthorExists(authorID, function(err, exists)
|
authorMangager.doesAuthorExists(authorID, function(err, exists)
|
||||||
{
|
{
|
||||||
if(ERR(err, callback)) return;
|
if(ERR(err, callback)) return;
|
||||||
|
|
||||||
//author does not exist
|
if (exists == false) {
|
||||||
if(exists == false)
|
// author does not exist
|
||||||
{
|
callback(new customError("authorID does not exist", "apierror"));
|
||||||
callback(new customError("authorID does not exist","apierror"));
|
} else {
|
||||||
}
|
// everything is fine, continue
|
||||||
//everything is fine, continue
|
|
||||||
else
|
|
||||||
{
|
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//check validUntil and create the session db entry
|
|
||||||
|
// check validUntil and create the session db entry
|
||||||
function(callback)
|
function(callback)
|
||||||
{
|
{
|
||||||
//check if rev is a number
|
// check if rev is a number
|
||||||
if(typeof validUntil != "number")
|
if (typeof validUntil != "number")
|
||||||
{
|
{
|
||||||
//try to parse the number
|
// try to parse the number
|
||||||
if(isNaN(parseInt(validUntil)))
|
if (isNaN(parseInt(validUntil))) {
|
||||||
{
|
callback(new customError("validUntil is not a number", "apierror"));
|
||||||
callback(new customError("validUntil is not a number","apierror"));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
validUntil = parseInt(validUntil);
|
validUntil = parseInt(validUntil);
|
||||||
}
|
}
|
||||||
|
|
||||||
//ensure this is not a negativ number
|
// ensure this is not a negative number
|
||||||
if(validUntil < 0)
|
if (validUntil < 0) {
|
||||||
{
|
callback(new customError("validUntil is a negativ number", "apierror"));
|
||||||
callback(new customError("validUntil is a negativ number","apierror"));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//ensure this is not a float value
|
// ensure this is not a float value
|
||||||
if(!is_int(validUntil))
|
if (!is_int(validUntil)) {
|
||||||
{
|
callback(new customError("validUntil is a float value", "apierror"));
|
||||||
callback(new customError("validUntil is a float value","apierror"));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if validUntil is in the future
|
// 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"));
|
||||||
callback(new customError("validUntil is in the past","apierror"));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//generate sessionID
|
// generate sessionID
|
||||||
sessionID = "s." + randomString(16);
|
sessionID = "s." + randomString(16);
|
||||||
|
|
||||||
//set the session into the database
|
// set the session into the database
|
||||||
db.set("session:" + sessionID, {"groupID": groupID, "authorID": authorID, "validUntil": validUntil});
|
db.set("session:" + sessionID, {"groupID": groupID, "authorID": authorID, "validUntil": validUntil});
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
},
|
},
|
||||||
//set the group2sessions entry
|
|
||||||
|
// set the group2sessions entry
|
||||||
function(callback)
|
function(callback)
|
||||||
{
|
{
|
||||||
//get the entry
|
// get the entry
|
||||||
db.get("group2sessions:" + groupID, function(err, group2sessions)
|
db.get("group2sessions:" + groupID, function(err, group2sessions)
|
||||||
{
|
{
|
||||||
if(ERR(err, callback)) return;
|
if(ERR(err, callback)) return;
|
||||||
|
|
||||||
//the entry doesn't exist so far, let's create it
|
if (group2sessions == null || group2sessions.sessionIDs == null) {
|
||||||
if(group2sessions == null || group2sessions.sessionIDs == null)
|
// the entry doesn't exist so far, let's create it
|
||||||
{
|
|
||||||
group2sessions = {sessionIDs : {}};
|
group2sessions = {sessionIDs : {}};
|
||||||
}
|
}
|
||||||
|
|
||||||
//add the entry for this session
|
// add the entry for this session
|
||||||
group2sessions.sessionIDs[sessionID] = 1;
|
group2sessions.sessionIDs[sessionID] = 1;
|
||||||
|
|
||||||
//save the new element back
|
// save the new element back
|
||||||
db.set("group2sessions:" + groupID, group2sessions);
|
db.set("group2sessions:" + groupID, group2sessions);
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//set the author2sessions entry
|
|
||||||
|
// set the author2sessions entry
|
||||||
function(callback)
|
function(callback)
|
||||||
{
|
{
|
||||||
//get the entry
|
// get the entry
|
||||||
db.get("author2sessions:" + authorID, function(err, author2sessions)
|
db.get("author2sessions:" + authorID, function(err, author2sessions)
|
||||||
{
|
{
|
||||||
if(ERR(err, callback)) return;
|
if(ERR(err, callback)) return;
|
||||||
|
|
||||||
//the entry doesn't exist so far, let's create it
|
if (author2sessions == null || author2sessions.sessionIDs == null) {
|
||||||
if(author2sessions == null || author2sessions.sessionIDs == null)
|
// the entry doesn't exist so far, let's create it
|
||||||
{
|
|
||||||
author2sessions = {sessionIDs : {}};
|
author2sessions = {sessionIDs : {}};
|
||||||
}
|
}
|
||||||
|
|
||||||
//add the entry for this session
|
// add the entry for this session
|
||||||
author2sessions.sessionIDs[sessionID] = 1;
|
author2sessions.sessionIDs[sessionID] = 1;
|
||||||
|
|
||||||
//save the new element back
|
//save the new element back
|
||||||
|
@ -178,26 +169,23 @@ exports.createSession = function(groupID, authorID, validUntil, callback)
|
||||||
{
|
{
|
||||||
if(ERR(err, callback)) return;
|
if(ERR(err, callback)) return;
|
||||||
|
|
||||||
//return error and sessionID
|
// return error and sessionID
|
||||||
callback(null, {sessionID: sessionID});
|
callback(null, {sessionID: sessionID});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.getSessionInfo = function(sessionID, callback)
|
exports.getSessionInfo = function(sessionID, callback)
|
||||||
{
|
{
|
||||||
//check if the database entry of this session exists
|
// check if the database entry of this session exists
|
||||||
db.get("session:" + sessionID, function (err, session)
|
db.get("session:" + sessionID, function (err, session)
|
||||||
{
|
{
|
||||||
if(ERR(err, callback)) return;
|
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"))
|
||||||
callback(new customError("sessionID does not exist","apierror"))
|
} else {
|
||||||
}
|
// everything is fine, return the sessioninfos
|
||||||
//everything is fine, return the sessioninfos
|
|
||||||
else
|
|
||||||
{
|
|
||||||
callback(null, session);
|
callback(null, session);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -214,19 +202,16 @@ exports.deleteSession = function(sessionID, callback)
|
||||||
async.series([
|
async.series([
|
||||||
function(callback)
|
function(callback)
|
||||||
{
|
{
|
||||||
//get the session entry
|
// get the session entry
|
||||||
db.get("session:" + sessionID, function (err, session)
|
db.get("session:" + sessionID, function (err, session)
|
||||||
{
|
{
|
||||||
if(ERR(err, callback)) return;
|
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"))
|
||||||
callback(new customError("sessionID does not exist","apierror"))
|
} else {
|
||||||
}
|
// everything is fine, use the sessioninfos
|
||||||
//everything is fine, return the sessioninfos
|
|
||||||
else
|
|
||||||
{
|
|
||||||
authorID = session.authorID;
|
authorID = session.authorID;
|
||||||
groupID = session.groupID;
|
groupID = session.groupID;
|
||||||
|
|
||||||
|
@ -234,7 +219,8 @@ exports.deleteSession = function(sessionID, callback)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//get the group2sessions entry
|
|
||||||
|
// get the group2sessions entry
|
||||||
function(callback)
|
function(callback)
|
||||||
{
|
{
|
||||||
db.get("group2sessions:" + groupID, function (err, _group2sessions)
|
db.get("group2sessions:" + groupID, function (err, _group2sessions)
|
||||||
|
@ -244,7 +230,8 @@ exports.deleteSession = function(sessionID, callback)
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//get the author2sessions entry
|
|
||||||
|
// get the author2sessions entry
|
||||||
function(callback)
|
function(callback)
|
||||||
{
|
{
|
||||||
db.get("author2sessions:" + authorID, function (err, _author2sessions)
|
db.get("author2sessions:" + authorID, function (err, _author2sessions)
|
||||||
|
@ -254,19 +241,20 @@ exports.deleteSession = function(sessionID, callback)
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//remove the values from the database
|
|
||||||
|
// remove the values from the database
|
||||||
function(callback)
|
function(callback)
|
||||||
{
|
{
|
||||||
//remove the session
|
//remove the session
|
||||||
db.remove("session:" + sessionID);
|
db.remove("session:" + sessionID);
|
||||||
|
|
||||||
//remove session from group2sessions
|
// remove session from group2sessions
|
||||||
if(group2sessions != null) { // Maybe the group was already deleted
|
if(group2sessions != null) { // Maybe the group was already deleted
|
||||||
delete group2sessions.sessionIDs[sessionID];
|
delete group2sessions.sessionIDs[sessionID];
|
||||||
db.set("group2sessions:" + groupID, group2sessions);
|
db.set("group2sessions:" + groupID, group2sessions);
|
||||||
}
|
}
|
||||||
|
|
||||||
//remove session from author2sessions
|
// remove session from author2sessions
|
||||||
if(author2sessions != null) { // Maybe the author was already deleted
|
if(author2sessions != null) { // Maybe the author was already deleted
|
||||||
delete author2sessions.sessionIDs[sessionID];
|
delete author2sessions.sessionIDs[sessionID];
|
||||||
db.set("author2sessions:" + authorID, author2sessions);
|
db.set("author2sessions:" + authorID, author2sessions);
|
||||||
|
@ -287,14 +275,11 @@ exports.listSessionsOfGroup = function(groupID, callback)
|
||||||
{
|
{
|
||||||
if(ERR(err, callback)) return;
|
if(ERR(err, callback)) return;
|
||||||
|
|
||||||
//group does not exist
|
if (exists == false) {
|
||||||
if(exists == false)
|
// group does not exist
|
||||||
{
|
callback(new customError("groupID does not exist", "apierror"));
|
||||||
callback(new customError("groupID does not exist","apierror"));
|
} else {
|
||||||
}
|
// everything is fine, continue
|
||||||
//everything is fine, continue
|
|
||||||
else
|
|
||||||
{
|
|
||||||
listSessionsWithDBKey("group2sessions:" + groupID, callback);
|
listSessionsWithDBKey("group2sessions:" + groupID, callback);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -306,20 +291,17 @@ exports.listSessionsOfAuthor = function(authorID, callback)
|
||||||
{
|
{
|
||||||
if(ERR(err, callback)) return;
|
if(ERR(err, callback)) return;
|
||||||
|
|
||||||
//group does not exist
|
if (exists == false) {
|
||||||
if(exists == false)
|
// group does not exist
|
||||||
{
|
callback(new customError("authorID does not exist", "apierror"));
|
||||||
callback(new customError("authorID does not exist","apierror"));
|
} else {
|
||||||
}
|
// everything is fine, continue
|
||||||
//everything is fine, continue
|
|
||||||
else
|
|
||||||
{
|
|
||||||
listSessionsWithDBKey("author2sessions:" + authorID, callback);
|
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)
|
function listSessionsWithDBKey (dbkey, callback)
|
||||||
{
|
{
|
||||||
var sessions;
|
var sessions;
|
||||||
|
@ -327,7 +309,7 @@ function listSessionsWithDBKey (dbkey, callback)
|
||||||
async.series([
|
async.series([
|
||||||
function(callback)
|
function(callback)
|
||||||
{
|
{
|
||||||
//get the group2sessions entry
|
// get the group2sessions entry
|
||||||
db.get(dbkey, function(err, sessionObject)
|
db.get(dbkey, function(err, sessionObject)
|
||||||
{
|
{
|
||||||
if(ERR(err, callback)) return;
|
if(ERR(err, callback)) return;
|
||||||
|
@ -335,26 +317,24 @@ function listSessionsWithDBKey (dbkey, callback)
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
function(callback)
|
function(callback)
|
||||||
{
|
{
|
||||||
//collect all sessionIDs in an arrary
|
// collect all sessionIDs in an arrary
|
||||||
var sessionIDs = [];
|
var sessionIDs = [];
|
||||||
for (var i in sessions)
|
for (var i in sessions)
|
||||||
{
|
{
|
||||||
sessionIDs.push(i);
|
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)
|
async.forEach(sessionIDs, function(sessionID, callback)
|
||||||
{
|
{
|
||||||
exports.getSessionInfo(sessionID, function(err, sessionInfo)
|
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}`);
|
console.warn(`Found bad session ${sessionID} in ${dbkey}`);
|
||||||
}
|
} else if(ERR(err, callback)) {
|
||||||
else if(ERR(err, callback))
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,8 +350,8 @@ function listSessionsWithDBKey (dbkey, callback)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//checks if a number is an int
|
// checks if a number is an int
|
||||||
function is_int(value)
|
function is_int(value)
|
||||||
{
|
{
|
||||||
return (parseFloat(value) == parseInt(value)) && !isNaN(value)
|
return (parseFloat(value) == parseInt(value)) && !isNaN(value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/*
|
/*
|
||||||
* Stores session data in the database
|
* Stores session data in the database
|
||||||
* Source; https://github.com/edy-b/SciFlowWriter/blob/develop/available_plugins/ep_sciflowwriter/db/DirtyStore.js
|
* Source; https://github.com/edy-b/SciFlowWriter/blob/develop/available_plugins/ep_sciflowwriter/db/DirtyStore.js
|
||||||
* This is not used for authors that are created via the API at current
|
* This is not used for authors that are created via the API at current
|
||||||
|
@ -13,11 +13,12 @@ var SessionStore = module.exports = function SessionStore() {};
|
||||||
|
|
||||||
SessionStore.prototype.__proto__ = Store.prototype;
|
SessionStore.prototype.__proto__ = Store.prototype;
|
||||||
|
|
||||||
SessionStore.prototype.get = function(sid, fn){
|
SessionStore.prototype.get = function(sid, fn) {
|
||||||
messageLogger.debug('GET ' + sid);
|
messageLogger.debug('GET ' + sid);
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
db.get("sessionstorage:" + sid, function (err, sess)
|
|
||||||
{
|
db.get("sessionstorage:" + sid, function(err, sess) {
|
||||||
if (sess) {
|
if (sess) {
|
||||||
sess.cookie.expires = 'string' == typeof sess.cookie.expires ? new Date(sess.cookie.expires) : sess.cookie.expires;
|
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) {
|
if (!sess.cookie.expires || new Date() < sess.cookie.expires) {
|
||||||
|
@ -31,26 +32,30 @@ SessionStore.prototype.get = function(sid, fn){
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
SessionStore.prototype.set = function(sid, sess, fn){
|
SessionStore.prototype.set = function(sid, sess, fn) {
|
||||||
messageLogger.debug('SET ' + sid);
|
messageLogger.debug('SET ' + sid);
|
||||||
|
|
||||||
db.set("sessionstorage:" + sid, sess);
|
db.set("sessionstorage:" + sid, sess);
|
||||||
process.nextTick(function(){
|
process.nextTick(function() {
|
||||||
if(fn) fn();
|
if (fn) fn();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
SessionStore.prototype.destroy = function(sid, fn){
|
SessionStore.prototype.destroy = function(sid, fn) {
|
||||||
messageLogger.debug('DESTROY ' + sid);
|
messageLogger.debug('DESTROY ' + sid);
|
||||||
|
|
||||||
db.remove("sessionstorage:" + sid);
|
db.remove("sessionstorage:" + sid);
|
||||||
process.nextTick(function(){
|
process.nextTick(function() {
|
||||||
if(fn) fn();
|
if (fn) fn();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
SessionStore.prototype.all = function(fn){
|
SessionStore.prototype.all = function(fn) {
|
||||||
messageLogger.debug('ALL');
|
messageLogger.debug('ALL');
|
||||||
|
|
||||||
var sessions = [];
|
var sessions = [];
|
||||||
db.forEach(function(key, value){
|
|
||||||
|
db.forEach(function(key, value) {
|
||||||
if (key.substr(0,15) === "sessionstorage:") {
|
if (key.substr(0,15) === "sessionstorage:") {
|
||||||
sessions.push(value);
|
sessions.push(value);
|
||||||
}
|
}
|
||||||
|
@ -58,20 +63,23 @@ SessionStore.prototype.all = function(fn){
|
||||||
fn(null, sessions);
|
fn(null, sessions);
|
||||||
};
|
};
|
||||||
|
|
||||||
SessionStore.prototype.clear = function(fn){
|
SessionStore.prototype.clear = function(fn) {
|
||||||
messageLogger.debug('CLEAR');
|
messageLogger.debug('CLEAR');
|
||||||
db.forEach(function(key, value){
|
|
||||||
|
db.forEach(function(key, value) {
|
||||||
if (key.substr(0,15) === "sessionstorage:") {
|
if (key.substr(0,15) === "sessionstorage:") {
|
||||||
db.db.remove("session:" + key);
|
db.db.remove("session:" + key);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if(fn) fn();
|
if (fn) fn();
|
||||||
};
|
};
|
||||||
|
|
||||||
SessionStore.prototype.length = function(fn){
|
SessionStore.prototype.length = function(fn) {
|
||||||
messageLogger.debug('LENGTH');
|
messageLogger.debug('LENGTH');
|
||||||
|
|
||||||
var i = 0;
|
var i = 0;
|
||||||
db.forEach(function(key, value){
|
|
||||||
|
db.forEach(function(key, value) {
|
||||||
if (key.substr(0,15) === "sessionstorage:") {
|
if (key.substr(0,15) === "sessionstorage:") {
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,19 +32,17 @@ var apiHandlerLogger = log4js.getLogger('APIHandler');
|
||||||
//ensure we have an apikey
|
//ensure we have an apikey
|
||||||
var apikey = null;
|
var apikey = null;
|
||||||
var apikeyFilename = absolutePaths.makeAbsolute(argv.apikey || "./APIKEY.txt");
|
var apikeyFilename = absolutePaths.makeAbsolute(argv.apikey || "./APIKEY.txt");
|
||||||
try
|
|
||||||
{
|
try {
|
||||||
apikey = fs.readFileSync(apikeyFilename,"utf8");
|
apikey = fs.readFileSync(apikeyFilename,"utf8");
|
||||||
apiHandlerLogger.info(`Api key file read from: "${apikeyFilename}"`);
|
apiHandlerLogger.info(`Api key file read from: "${apikeyFilename}"`);
|
||||||
}
|
} catch(e) {
|
||||||
catch(e)
|
|
||||||
{
|
|
||||||
apiHandlerLogger.info(`Api key file "${apikeyFilename}" not found. Creating with random contents.`);
|
apiHandlerLogger.info(`Api key file "${apikeyFilename}" not found. Creating with random contents.`);
|
||||||
apikey = randomString(32);
|
apikey = randomString(32);
|
||||||
fs.writeFileSync(apikeyFilename,apikey,"utf8");
|
fs.writeFileSync(apikeyFilename,apikey,"utf8");
|
||||||
}
|
}
|
||||||
|
|
||||||
//a list of all functions
|
// a list of all functions
|
||||||
var version = {};
|
var version = {};
|
||||||
|
|
||||||
version["1"] = Object.assign({},
|
version["1"] = Object.assign({},
|
||||||
|
@ -156,106 +154,92 @@ exports.handle = function(apiVersion, functionName, fields, req, res)
|
||||||
{
|
{
|
||||||
//check if this is a valid apiversion
|
//check if this is a valid apiversion
|
||||||
var isKnownApiVersion = false;
|
var isKnownApiVersion = false;
|
||||||
for(var knownApiVersion in version)
|
|
||||||
{
|
for (var knownApiVersion in version) {
|
||||||
if(knownApiVersion == apiVersion)
|
if (knownApiVersion == apiVersion) {
|
||||||
{
|
|
||||||
isKnownApiVersion = true;
|
isKnownApiVersion = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//say goodbye if this is an unknown API version
|
// say goodbye if this is an unknown API version
|
||||||
if(!isKnownApiVersion)
|
if (!isKnownApiVersion) {
|
||||||
{
|
|
||||||
res.statusCode = 404;
|
res.statusCode = 404;
|
||||||
res.send({code: 3, message: "no such api version", data: null});
|
res.send({code: 3, message: "no such api version", data: null});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if this is a valid function name
|
// check if this is a valid function name
|
||||||
var isKnownFunctionname = false;
|
var isKnownFunctionname = false;
|
||||||
for(var knownFunctionname in version[apiVersion])
|
|
||||||
{
|
for (var knownFunctionname in version[apiVersion]) {
|
||||||
if(knownFunctionname == functionName)
|
if (knownFunctionname == functionName) {
|
||||||
{
|
|
||||||
isKnownFunctionname = true;
|
isKnownFunctionname = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//say goodbye if this is a unknown function
|
// say goodbye if this is an unknown function
|
||||||
if(!isKnownFunctionname)
|
if (!isKnownFunctionname) {
|
||||||
{
|
|
||||||
res.send({code: 3, message: "no such function", data: null});
|
res.send({code: 3, message: "no such function", data: null});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//check the api key!
|
// check the api key!
|
||||||
fields["apikey"] = fields["apikey"] || fields["api_key"];
|
fields["apikey"] = fields["apikey"] || fields["api_key"];
|
||||||
|
|
||||||
if(fields["apikey"] != apikey.trim())
|
if (fields["apikey"] != apikey.trim()) {
|
||||||
{
|
|
||||||
res.statusCode = 401;
|
res.statusCode = 401;
|
||||||
res.send({code: 4, message: "no or wrong API Key", data: null});
|
res.send({code: 4, message: "no or wrong API Key", data: null});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//sanitize any pad id's before continuing
|
// sanitize any padIDs before continuing
|
||||||
if(fields["padID"])
|
if (fields["padID"]) {
|
||||||
{
|
padManager.sanitizePadId(fields["padID"], function(padId) {
|
||||||
padManager.sanitizePadId(fields["padID"], function(padId)
|
|
||||||
{
|
|
||||||
fields["padID"] = padId;
|
fields["padID"] = padId;
|
||||||
callAPI(apiVersion, functionName, fields, req, res);
|
callAPI(apiVersion, functionName, fields, req, res);
|
||||||
});
|
});
|
||||||
}
|
} else if (fields["padName"]) {
|
||||||
else if(fields["padName"])
|
padManager.sanitizePadId(fields["padName"], function(padId) {
|
||||||
{
|
|
||||||
padManager.sanitizePadId(fields["padName"], function(padId)
|
|
||||||
{
|
|
||||||
fields["padName"] = padId;
|
fields["padName"] = padId;
|
||||||
callAPI(apiVersion, functionName, fields, req, res);
|
callAPI(apiVersion, functionName, fields, req, res);
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
callAPI(apiVersion, functionName, fields, req, res);
|
callAPI(apiVersion, functionName, fields, req, res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//calls the api function
|
// calls the api function
|
||||||
function callAPI(apiVersion, functionName, fields, req, res)
|
function callAPI(apiVersion, functionName, fields, req, res)
|
||||||
{
|
{
|
||||||
//put the function parameters in an array
|
// put the function parameters in an array
|
||||||
var functionParams = version[apiVersion][functionName].map(function (field) {
|
var functionParams = version[apiVersion][functionName].map(function (field) {
|
||||||
return fields[field]
|
return fields[field]
|
||||||
})
|
});
|
||||||
|
|
||||||
//add a callback function to handle the response
|
// add a callback function to handle the response
|
||||||
functionParams.push(function(err, data)
|
functionParams.push(function(err, data) {
|
||||||
{
|
if (err == null) {
|
||||||
// no error happend, everything is fine
|
// no error happened, everything is fine
|
||||||
if(err == null)
|
|
||||||
{
|
if (!data) {
|
||||||
if(!data)
|
|
||||||
data = null;
|
data = null;
|
||||||
|
}
|
||||||
|
|
||||||
res.send({code: 0, message: "ok", data: data});
|
res.send({code: 0, message: "ok", data: data});
|
||||||
}
|
} else if (err.name == "apierror") {
|
||||||
// parameters were wrong and the api stopped execution, pass the error
|
// 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});
|
res.send({code: 1, message: err.message, data: null});
|
||||||
}
|
} else {
|
||||||
//an unknown error happend
|
// an unknown error happened
|
||||||
else
|
|
||||||
{
|
|
||||||
res.send({code: 2, message: "internal error", data: null});
|
res.send({code: 2, message: "internal error", data: null});
|
||||||
ERR(err);
|
ERR(err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//call the api function
|
// call the api function
|
||||||
api[functionName].apply(this, functionParams);
|
api[functionName].apply(this, functionParams);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,13 +32,15 @@ var TidyHtml = require('../utils/TidyHtml');
|
||||||
|
|
||||||
var convertor = null;
|
var convertor = null;
|
||||||
|
|
||||||
//load abiword only if its enabled
|
// load abiword only if it is enabled
|
||||||
if(settings.abiword != null)
|
if (settings.abiword != null) {
|
||||||
convertor = require("../utils/Abiword");
|
convertor = require("../utils/Abiword");
|
||||||
|
}
|
||||||
|
|
||||||
// Use LibreOffice if an executable has been defined in the settings
|
// Use LibreOffice if an executable has been defined in the settings
|
||||||
if(settings.soffice != null)
|
if (settings.soffice != null) {
|
||||||
convertor = require("../utils/LibreOffice");
|
convertor = require("../utils/LibreOffice");
|
||||||
|
}
|
||||||
|
|
||||||
const tempDirectory = os.tmpdir();
|
const tempDirectory = os.tmpdir();
|
||||||
|
|
||||||
|
@ -53,62 +55,55 @@ exports.doExport = function(req, res, padId, type)
|
||||||
hooks.aCallFirst("exportFileName", padId,
|
hooks.aCallFirst("exportFileName", padId,
|
||||||
function(err, hookFileName){
|
function(err, hookFileName){
|
||||||
// if fileName is set then set it to the padId, note that fileName is returned as an array.
|
// 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
|
// tell the browser that this is a downloadable file
|
||||||
res.attachment(fileName + "." + type);
|
res.attachment(fileName + "." + type);
|
||||||
|
|
||||||
//if this is a plain text export, we can do this directly
|
// if this is a plain text export, we can do this directly
|
||||||
// We have to over engineer this because tabs are stored as attributes and not plain text
|
// We have to over engineer this because tabs are stored as attributes and not plain text
|
||||||
if(type == "etherpad"){
|
if (type == "etherpad") {
|
||||||
exportEtherpad.getPadRaw(padId, function(err, pad){
|
exportEtherpad.getPadRaw(padId, function(err, pad) {
|
||||||
if(!err){
|
if (!err) {
|
||||||
res.send(pad);
|
res.send(pad);
|
||||||
// return;
|
// return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
} else if (type == "txt") {
|
||||||
else if(type == "txt")
|
exporttxt.getPadTXTDocument(padId, req.params.rev, function(err, txt) {
|
||||||
{
|
if (!err) {
|
||||||
exporttxt.getPadTXTDocument(padId, req.params.rev, function(err, txt)
|
|
||||||
{
|
|
||||||
if(!err) {
|
|
||||||
res.send(txt);
|
res.send(txt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
var html;
|
var html;
|
||||||
var randNum;
|
var randNum;
|
||||||
var srcFile, destFile;
|
var srcFile, destFile;
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
//render the html document
|
// render the html document
|
||||||
function(callback)
|
function(callback) {
|
||||||
{
|
exporthtml.getPadHTMLDocument(padId, req.params.rev, function(err, _html) {
|
||||||
exporthtml.getPadHTMLDocument(padId, req.params.rev, function(err, _html)
|
if (ERR(err, callback)) return;
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
html = _html;
|
html = _html;
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//decide what to do with the html export
|
|
||||||
function(callback)
|
// decide what to do with the html export
|
||||||
{
|
function(callback) {
|
||||||
//if this is a html export, we can send this from here directly
|
// 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
|
// do any final changes the plugin might want to make
|
||||||
hooks.aCallFirst("exportHTMLSend", html, function(err, newHTML){
|
hooks.aCallFirst("exportHTMLSend", html, function(err, newHTML) {
|
||||||
if(newHTML.length) html = newHTML;
|
if (newHTML.length) html = newHTML;
|
||||||
res.send(html);
|
res.send(html);
|
||||||
callback("stop");
|
callback("stop");
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
else //write the html export to a file
|
// write the html export to a file
|
||||||
{
|
|
||||||
randNum = Math.floor(Math.random()*0xFFFFFFFF);
|
randNum = Math.floor(Math.random()*0xFFFFFFFF);
|
||||||
srcFile = tempDirectory + "/etherpad_export_" + randNum + ".html";
|
srcFile = tempDirectory + "/etherpad_export_" + randNum + ".html";
|
||||||
fs.writeFile(srcFile, html, callback);
|
fs.writeFile(srcFile, html, callback);
|
||||||
|
@ -116,64 +111,56 @@ exports.doExport = function(req, res, padId, type)
|
||||||
},
|
},
|
||||||
|
|
||||||
// Tidy up the exported HTML
|
// Tidy up the exported HTML
|
||||||
function(callback)
|
function(callback) {
|
||||||
{
|
// ensure html can be collected by the garbage collector
|
||||||
//ensure html can be collected by the garbage collector
|
|
||||||
html = null;
|
html = null;
|
||||||
|
|
||||||
TidyHtml.tidy(srcFile, callback);
|
TidyHtml.tidy(srcFile, callback);
|
||||||
},
|
},
|
||||||
|
|
||||||
//send the convert job to the convertor (abiword, libreoffice, ..)
|
// send the convert job to the convertor (abiword, libreoffice, ..)
|
||||||
function(callback)
|
function(callback) {
|
||||||
{
|
|
||||||
destFile = tempDirectory + "/etherpad_export_" + randNum + "." + type;
|
destFile = tempDirectory + "/etherpad_export_" + randNum + "." + type;
|
||||||
|
|
||||||
// Allow plugins to overwrite the convert in export process
|
// Allow plugins to overwrite the convert in export process
|
||||||
hooks.aCallAll("exportConvert", {srcFile: srcFile, destFile: destFile, req: req, res: res}, function(err, result){
|
hooks.aCallAll("exportConvert", { srcFile: srcFile, destFile: destFile, req: req, res: res }, function(err, result) {
|
||||||
if(!err && result.length > 0){
|
if (!err && result.length > 0) {
|
||||||
// console.log("export handled by plugin", destFile);
|
// console.log("export handled by plugin", destFile);
|
||||||
handledByPlugin = true;
|
handledByPlugin = true;
|
||||||
callback();
|
callback();
|
||||||
}else{
|
} else {
|
||||||
convertor.convertFile(srcFile, destFile, type, callback);
|
convertor.convertFile(srcFile, destFile, type, callback);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
//send the file
|
|
||||||
function(callback)
|
// send the file
|
||||||
{
|
function(callback) {
|
||||||
res.sendFile(destFile, null, callback);
|
res.sendFile(destFile, null, callback);
|
||||||
},
|
},
|
||||||
//clean up temporary files
|
|
||||||
function(callback)
|
// clean up temporary files
|
||||||
{
|
function(callback) {
|
||||||
async.parallel([
|
async.parallel([
|
||||||
function(callback)
|
function(callback) {
|
||||||
{
|
|
||||||
fs.unlink(srcFile, callback);
|
fs.unlink(srcFile, callback);
|
||||||
},
|
},
|
||||||
function(callback)
|
function(callback) {
|
||||||
{
|
// 100ms delay to accommodate for slow windows fs
|
||||||
//100ms delay to accomidate for slow windows fs
|
if (os.type().indexOf("Windows") > -1) {
|
||||||
if(os.type().indexOf("Windows") > -1)
|
setTimeout(function() {
|
||||||
{
|
|
||||||
setTimeout(function()
|
|
||||||
{
|
|
||||||
fs.unlink(destFile, callback);
|
fs.unlink(destFile, callback);
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
fs.unlink(destFile, callback);
|
fs.unlink(destFile, callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
], callback);
|
], callback);
|
||||||
}
|
}
|
||||||
], function(err)
|
],
|
||||||
{
|
function(err) {
|
||||||
if(err && err != "stop") ERR(err);
|
if (err && err != "stop") ERR(err);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,12 +37,13 @@ var ERR = require("async-stacktrace")
|
||||||
var convertor = null;
|
var convertor = null;
|
||||||
var exportExtension = "htm";
|
var exportExtension = "htm";
|
||||||
|
|
||||||
//load abiword only if its enabled and if soffice is disabled
|
// load abiword only if it is enabled and if soffice is disabled
|
||||||
if(settings.abiword != null && settings.soffice === null)
|
if (settings.abiword != null && settings.soffice === null) {
|
||||||
convertor = require("../utils/Abiword");
|
convertor = require("../utils/Abiword");
|
||||||
|
}
|
||||||
|
|
||||||
//load soffice only if its enabled
|
// load soffice only if it is enabled
|
||||||
if(settings.soffice != null) {
|
if (settings.soffice != null) {
|
||||||
convertor = require("../utils/LibreOffice");
|
convertor = require("../utils/LibreOffice");
|
||||||
exportExtension = "html";
|
exportExtension = "html";
|
||||||
}
|
}
|
||||||
|
@ -56,9 +57,9 @@ exports.doImport = function(req, res, padId)
|
||||||
{
|
{
|
||||||
var apiLogger = log4js.getLogger("ImportHandler");
|
var apiLogger = log4js.getLogger("ImportHandler");
|
||||||
|
|
||||||
//pipe to a file
|
// pipe to a file
|
||||||
//convert file to html via abiword or soffice
|
// convert file to html via abiword or soffice
|
||||||
//set html in the pad
|
// set html in the pad
|
||||||
|
|
||||||
var srcFile, destFile
|
var srcFile, destFile
|
||||||
, pad
|
, pad
|
||||||
|
@ -73,64 +74,69 @@ exports.doImport = function(req, res, padId)
|
||||||
useConvertor = (convertor != null);
|
useConvertor = (convertor != null);
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
//save the uploaded file to /tmp
|
// save the uploaded file to /tmp
|
||||||
function(callback) {
|
function(callback) {
|
||||||
var form = new formidable.IncomingForm();
|
var form = new formidable.IncomingForm();
|
||||||
form.keepExtensions = true;
|
form.keepExtensions = true;
|
||||||
form.uploadDir = tmpDirectory;
|
form.uploadDir = tmpDirectory;
|
||||||
|
|
||||||
form.parse(req, function(err, fields, files) {
|
form.parse(req, function(err, fields, files) {
|
||||||
//the upload failed, stop at this point
|
if (err || files.file === undefined) {
|
||||||
if(err || files.file === undefined) {
|
// the upload failed, stop at this point
|
||||||
if(err) console.warn("Uploading Error: " + err.stack);
|
if (err) {
|
||||||
|
console.warn("Uploading Error: " + err.stack);
|
||||||
|
}
|
||||||
callback("uploadFailed");
|
callback("uploadFailed");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//everything ok, continue
|
// everything ok, continue
|
||||||
//save the path of the uploaded file
|
// save the path of the uploaded file
|
||||||
srcFile = files.file.path;
|
srcFile = files.file.path;
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
//ensure this is a file ending we know, else we change the file ending to .txt
|
// ensure this is a file ending we know, else we change the file ending to .txt
|
||||||
//this allows us to accept source code files like .c or .java
|
// this allows us to accept source code files like .c or .java
|
||||||
function(callback) {
|
function(callback) {
|
||||||
var fileEnding = path.extname(srcFile).toLowerCase()
|
var fileEnding = path.extname(srcFile).toLowerCase()
|
||||||
, knownFileEndings = [".txt", ".doc", ".docx", ".pdf", ".odt", ".html", ".htm", ".etherpad", ".rtf"]
|
, knownFileEndings = [".txt", ".doc", ".docx", ".pdf", ".odt", ".html", ".htm", ".etherpad", ".rtf"]
|
||||||
, fileEndingKnown = (knownFileEndings.indexOf(fileEnding) > -1);
|
, fileEndingKnown = (knownFileEndings.indexOf(fileEnding) > -1);
|
||||||
|
|
||||||
//if the file ending is known, continue as normal
|
// if the file ending is known, continue as normal
|
||||||
if(fileEndingKnown) {
|
if (fileEndingKnown) {
|
||||||
callback();
|
callback();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//we need to rename this file with a .txt ending
|
// we need to rename this file with a .txt ending
|
||||||
if(settings.allowUnknownFileEnds === true){
|
if (settings.allowUnknownFileEnds === true) {
|
||||||
var oldSrcFile = srcFile;
|
var oldSrcFile = srcFile;
|
||||||
srcFile = path.join(path.dirname(srcFile),path.basename(srcFile, fileEnding)+".txt");
|
srcFile = path.join(path.dirname(srcFile), path.basename(srcFile, fileEnding) + ".txt");
|
||||||
fs.rename(oldSrcFile, srcFile, callback);
|
fs.rename(oldSrcFile, srcFile, callback);
|
||||||
}else{
|
} else {
|
||||||
console.warn("Not allowing unknown file type to be imported", fileEnding);
|
console.warn("Not allowing unknown file type to be imported", fileEnding);
|
||||||
callback("uploadFailed");
|
callback("uploadFailed");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(callback){
|
|
||||||
|
function(callback) {
|
||||||
destFile = path.join(tmpDirectory, "etherpad_import_" + randNum + "." + exportExtension);
|
destFile = path.join(tmpDirectory, "etherpad_import_" + randNum + "." + exportExtension);
|
||||||
|
|
||||||
// Logic for allowing external Import Plugins
|
// Logic for allowing external Import Plugins
|
||||||
hooks.aCallAll("import", {srcFile: srcFile, destFile: destFile}, function(err, result){
|
hooks.aCallAll("import", { srcFile: srcFile, destFile: destFile }, function(err, result) {
|
||||||
if(ERR(err, callback)) return callback();
|
if (ERR(err, callback)) return callback();
|
||||||
if(result.length > 0){ // This feels hacky and wrong..
|
|
||||||
|
if (result.length > 0) { // This feels hacky and wrong..
|
||||||
importHandledByPlugin = true;
|
importHandledByPlugin = true;
|
||||||
}
|
}
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
function(callback) {
|
function(callback) {
|
||||||
var fileEnding = path.extname(srcFile).toLowerCase()
|
var fileEnding = path.extname(srcFile).toLowerCase()
|
||||||
var fileIsNotEtherpad = (fileEnding !== ".etherpad");
|
var fileIsNotEtherpad = (fileEnding !== ".etherpad");
|
||||||
|
@ -141,23 +147,24 @@ exports.doImport = function(req, res, padId)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we do this here so we can see if the pad has quit ea few edits
|
// we do this here so we can see if the pad has quite a few edits
|
||||||
padManager.getPad(padId, function(err, _pad){
|
padManager.getPad(padId, function(err, _pad) {
|
||||||
var headCount = _pad.head;
|
var headCount = _pad.head;
|
||||||
if(headCount >= 10){
|
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");
|
return callback("padHasData");
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.readFile(srcFile, "utf8", function(err, _text){
|
fs.readFile(srcFile, "utf8", function(err, _text) {
|
||||||
directDatabaseAccess = true;
|
directDatabaseAccess = true;
|
||||||
importEtherpad.setPadRaw(padId, _text, function(err){
|
importEtherpad.setPadRaw(padId, _text, function(err) {
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//convert file to html
|
|
||||||
|
// convert file to html if necessary
|
||||||
function(callback) {
|
function(callback) {
|
||||||
if (importHandledByPlugin || directDatabaseAccess) {
|
if (importHandledByPlugin || directDatabaseAccess) {
|
||||||
callback();
|
callback();
|
||||||
|
@ -168,7 +175,9 @@ exports.doImport = function(req, res, padId)
|
||||||
var fileEnding = path.extname(srcFile).toLowerCase();
|
var fileEnding = path.extname(srcFile).toLowerCase();
|
||||||
var fileIsHTML = (fileEnding === ".html" || fileEnding === ".htm");
|
var fileIsHTML = (fileEnding === ".html" || fileEnding === ".htm");
|
||||||
var fileIsTXT = (fileEnding === ".txt");
|
var fileIsTXT = (fileEnding === ".txt");
|
||||||
|
|
||||||
if (fileIsTXT) useConvertor = false; // Don't use convertor for text files
|
if (fileIsTXT) useConvertor = false; // Don't use convertor for text files
|
||||||
|
|
||||||
// See https://github.com/ether/etherpad-lite/issues/2572
|
// See https://github.com/ether/etherpad-lite/issues/2572
|
||||||
if (fileIsHTML || (useConvertor === false)) {
|
if (fileIsHTML || (useConvertor === false)) {
|
||||||
// if no convertor only rename
|
// if no convertor only rename
|
||||||
|
@ -178,8 +187,8 @@ exports.doImport = function(req, res, padId)
|
||||||
}
|
}
|
||||||
|
|
||||||
convertor.convertFile(srcFile, destFile, exportExtension, function(err) {
|
convertor.convertFile(srcFile, destFile, exportExtension, function(err) {
|
||||||
//catch convert errors
|
// catch convert errors
|
||||||
if(err) {
|
if (err) {
|
||||||
console.warn("Converting Error:", err);
|
console.warn("Converting Error:", err);
|
||||||
return callback("convertFailed");
|
return callback("convertFailed");
|
||||||
}
|
}
|
||||||
|
@ -217,16 +226,16 @@ exports.doImport = function(req, res, padId)
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
//get the pad object
|
// get the pad object
|
||||||
function(callback) {
|
function(callback) {
|
||||||
padManager.getPad(padId, function(err, _pad){
|
padManager.getPad(padId, function(err, _pad) {
|
||||||
if(ERR(err, callback)) return;
|
if (ERR(err, callback)) return;
|
||||||
pad = _pad;
|
pad = _pad;
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
//read the text
|
// read the text
|
||||||
function(callback) {
|
function(callback) {
|
||||||
if (directDatabaseAccess) {
|
if (directDatabaseAccess) {
|
||||||
callback();
|
callback();
|
||||||
|
@ -234,16 +243,16 @@ exports.doImport = function(req, res, padId)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.readFile(destFile, "utf8", function(err, _text){
|
fs.readFile(destFile, "utf8", function(err, _text) {
|
||||||
if(ERR(err, callback)) return;
|
if (ERR(err, callback)) return;
|
||||||
text = _text;
|
text = _text;
|
||||||
// Title needs to be stripped out else it appends it to the pad..
|
// Title needs to be stripped out else it appends it to the pad..
|
||||||
text = text.replace("<title>", "<!-- <title>");
|
text = text.replace("<title>", "<!-- <title>");
|
||||||
text = text.replace("</title>","</title>-->");
|
text = text.replace("</title>","</title>-->");
|
||||||
|
|
||||||
//node on windows has a delay on releasing of the file lock.
|
// node on windows has a delay on releasing of the file lock.
|
||||||
//We add a 100ms delay to work around this
|
// We add a 100ms delay to work around this
|
||||||
if(os.type().indexOf("Windows") > -1){
|
if (os.type().indexOf("Windows") > -1) {
|
||||||
setTimeout(function() {callback();}, 100);
|
setTimeout(function() {callback();}, 100);
|
||||||
} else {
|
} else {
|
||||||
callback();
|
callback();
|
||||||
|
@ -251,26 +260,29 @@ exports.doImport = function(req, res, padId)
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
//change text of the pad and broadcast the changeset
|
// change text of the pad and broadcast the changeset
|
||||||
function(callback) {
|
function(callback) {
|
||||||
if(!directDatabaseAccess){
|
if (!directDatabaseAccess) {
|
||||||
var fileEnding = path.extname(srcFile).toLowerCase();
|
var fileEnding = path.extname(srcFile).toLowerCase();
|
||||||
if (importHandledByPlugin || useConvertor || fileEnding == ".htm" || fileEnding == ".html") {
|
if (importHandledByPlugin || useConvertor || fileEnding == ".htm" || fileEnding == ".html") {
|
||||||
importHtml.setPadHTML(pad, text, function(e){
|
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 {
|
} else {
|
||||||
pad.setText(text);
|
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.unloadPad(padId);
|
||||||
padManager.getPad(padId, function(err, _pad){
|
padManager.getPad(padId, function(err, _pad) {
|
||||||
var pad = _pad;
|
var pad = _pad;
|
||||||
padManager.unloadPad(padId);
|
padManager.unloadPad(padId);
|
||||||
|
|
||||||
// direct Database Access means a pad user should perform a switchToPad
|
// 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) {
|
if (directDatabaseAccess) {
|
||||||
callback();
|
callback();
|
||||||
|
|
||||||
|
@ -284,7 +296,7 @@ exports.doImport = function(req, res, padId)
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
//clean up temporary files
|
// clean up temporary files
|
||||||
function(callback) {
|
function(callback) {
|
||||||
if (directDatabaseAccess) {
|
if (directDatabaseAccess) {
|
||||||
callback();
|
callback();
|
||||||
|
@ -309,16 +321,15 @@ exports.doImport = function(req, res, padId)
|
||||||
], function(err) {
|
], function(err) {
|
||||||
var status = "ok";
|
var status = "ok";
|
||||||
|
|
||||||
//check for known errors and replace the status
|
// check for known errors and replace the status
|
||||||
if(err == "uploadFailed" || err == "convertFailed" || err == "padHasData")
|
if (err == "uploadFailed" || err == "convertFailed" || err == "padHasData") {
|
||||||
{
|
|
||||||
status = err;
|
status = err;
|
||||||
err = null;
|
err = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ERR(err);
|
ERR(err);
|
||||||
|
|
||||||
//close the connection
|
// close the connection
|
||||||
res.send(
|
res.send(
|
||||||
"<head> \
|
"<head> \
|
||||||
<script type='text/javascript' src='../../static/js/jquery.js'></script> \
|
<script type='text/javascript' src='../../static/js/jquery.js'></script> \
|
||||||
|
@ -331,4 +342,3 @@ exports.doImport = function(req, res, padId)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -41,10 +41,10 @@ var socket;
|
||||||
*/
|
*/
|
||||||
exports.addComponent = function(moduleName, module)
|
exports.addComponent = function(moduleName, module)
|
||||||
{
|
{
|
||||||
//save the component
|
// save the component
|
||||||
components[moduleName] = module;
|
components[moduleName] = module;
|
||||||
|
|
||||||
//give the module the socket
|
// give the module the socket
|
||||||
module.setSocketIO(socket);
|
module.setSocketIO(socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,57 +52,55 @@ exports.addComponent = function(moduleName, module)
|
||||||
* sets the socket.io and adds event functions for routing
|
* sets the socket.io and adds event functions for routing
|
||||||
*/
|
*/
|
||||||
exports.setSocketIO = function(_socket) {
|
exports.setSocketIO = function(_socket) {
|
||||||
//save this socket internaly
|
// save this socket internaly
|
||||||
socket = _socket;
|
socket = _socket;
|
||||||
|
|
||||||
socket.sockets.on('connection', function(client)
|
socket.sockets.on('connection', function(client)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Broken: See http://stackoverflow.com/questions/4647348/send-message-to-specific-client-with-socket-io-and-node-js
|
// 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
|
// Fixed by having a persistant object, ideally this would actually be in the database layer
|
||||||
// TODO move to database layer
|
// TODO move to database layer
|
||||||
if(settings.trustProxy && client.handshake.headers['x-forwarded-for'] !== undefined){
|
if (settings.trustProxy && client.handshake.headers['x-forwarded-for'] !== undefined) {
|
||||||
remoteAddress[client.id] = client.handshake.headers['x-forwarded-for'];
|
remoteAddress[client.id] = client.handshake.headers['x-forwarded-for'];
|
||||||
}
|
} else {
|
||||||
else{
|
|
||||||
remoteAddress[client.id] = client.handshake.address;
|
remoteAddress[client.id] = client.handshake.address;
|
||||||
}
|
}
|
||||||
|
|
||||||
var clientAuthorized = false;
|
var clientAuthorized = false;
|
||||||
|
|
||||||
//wrap the original send function to log the messages
|
// wrap the original send function to log the messages
|
||||||
client._send = client.send;
|
client._send = client.send;
|
||||||
client.send = function(message) {
|
client.send = function(message) {
|
||||||
messageLogger.debug("to " + client.id + ": " + stringifyWithoutPassword(message));
|
messageLogger.debug("to " + client.id + ": " + stringifyWithoutPassword(message));
|
||||||
client._send(message);
|
client._send(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
//tell all components about this connect
|
// tell all components about this connect
|
||||||
for(var i in components) {
|
for (var i in components) {
|
||||||
components[i].handleConnect(client);
|
components[i].handleConnect(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
client.on('message', function(message)
|
client.on('message', function(message) {
|
||||||
{
|
if (message.protocolVersion && message.protocolVersion != 2) {
|
||||||
if(message.protocolVersion && message.protocolVersion != 2) {
|
|
||||||
messageLogger.warn("Protocolversion header is not correct:" + stringifyWithoutPassword(message));
|
messageLogger.warn("Protocolversion header is not correct:" + stringifyWithoutPassword(message));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//client is authorized, everything ok
|
if (clientAuthorized) {
|
||||||
if(clientAuthorized) {
|
// client is authorized, everything ok
|
||||||
handleMessage(client, message);
|
handleMessage(client, message);
|
||||||
} else { //try to authorize the client
|
} else {
|
||||||
if(message.padId !== undefined && message.sessionID !== undefined && message.token !== undefined && message.password !== undefined) {
|
// try to authorize the client
|
||||||
|
if (message.padId !== undefined && message.sessionID !== undefined && message.token !== undefined && message.password !== undefined) {
|
||||||
var checkAccessCallback = function(err, statusObject) {
|
var checkAccessCallback = function(err, statusObject) {
|
||||||
ERR(err);
|
ERR(err);
|
||||||
|
|
||||||
//access was granted, mark the client as authorized and handle the message
|
if (statusObject.accessStatus == "grant") {
|
||||||
if(statusObject.accessStatus == "grant") {
|
// access was granted, mark the client as authorized and handle the message
|
||||||
clientAuthorized = true;
|
clientAuthorized = true;
|
||||||
handleMessage(client, message);
|
handleMessage(client, message);
|
||||||
}
|
} else {
|
||||||
//no access, send the client a message that tell him why
|
// no access, send the client a message that tells him why
|
||||||
else {
|
|
||||||
messageLogger.warn("Authentication try failed:" + stringifyWithoutPassword(message));
|
messageLogger.warn("Authentication try failed:" + stringifyWithoutPassword(message));
|
||||||
client.json.send({accessStatus: statusObject.accessStatus});
|
client.json.send({accessStatus: statusObject.accessStatus});
|
||||||
}
|
}
|
||||||
|
@ -110,36 +108,34 @@ exports.setSocketIO = function(_socket) {
|
||||||
if (message.padId.indexOf("r.") === 0) {
|
if (message.padId.indexOf("r.") === 0) {
|
||||||
readOnlyManager.getPadId(message.padId, function(err, value) {
|
readOnlyManager.getPadId(message.padId, function(err, value) {
|
||||||
ERR(err);
|
ERR(err);
|
||||||
securityManager.checkAccess (value, message.sessionID, message.token, message.password, checkAccessCallback);
|
securityManager.checkAccess(value, message.sessionID, message.token, message.password, checkAccessCallback);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
//this message has everything to try an authorization
|
// this message has everything to try an authorization
|
||||||
securityManager.checkAccess (message.padId, message.sessionID, message.token, message.password, checkAccessCallback);
|
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));
|
messageLogger.warn("Dropped message cause of bad permissions:" + stringifyWithoutPassword(message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('disconnect', function()
|
client.on('disconnect', function() {
|
||||||
{
|
// tell all components about this disconnect
|
||||||
//tell all components about this disconnect
|
for (var i in components) {
|
||||||
for(var i in components)
|
|
||||||
{
|
|
||||||
components[i].handleDisconnect(client);
|
components[i].handleDisconnect(client);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//try to handle the message of this client
|
// try to handle the message of this client
|
||||||
function handleMessage(client, message)
|
function handleMessage(client, message)
|
||||||
{
|
{
|
||||||
|
if (message.component && components[message.component]) {
|
||||||
if(message.component && components[message.component]) {
|
// check if component is registered in the components array
|
||||||
//check if component is registered in the components array
|
if (components[message.component]) {
|
||||||
if(components[message.component]) {
|
|
||||||
messageLogger.debug("from " + client.id + ": " + stringifyWithoutPassword(message));
|
messageLogger.debug("from " + client.id + ": " + stringifyWithoutPassword(message));
|
||||||
components[message.component].handleMessage(client, message);
|
components[message.component].handleMessage(client, message);
|
||||||
}
|
}
|
||||||
|
@ -148,18 +144,18 @@ function handleMessage(client, message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//returns a stringified representation of a message, removes the password
|
// returns a stringified representation of a message, removes the password
|
||||||
//this ensures there are no passwords in the log
|
// this ensures there are no passwords in the log
|
||||||
function stringifyWithoutPassword(message)
|
function stringifyWithoutPassword(message)
|
||||||
{
|
{
|
||||||
var newMessage = {};
|
var newMessage = {};
|
||||||
|
|
||||||
for(var i in message)
|
for (var i in message) {
|
||||||
{
|
if (i == "password" && message[i] != null) {
|
||||||
if(i == "password" && message[i] != null)
|
|
||||||
newMessage["password"] = "xxx";
|
newMessage["password"] = "xxx";
|
||||||
else
|
} else {
|
||||||
newMessage[i]=message[i];
|
newMessage[i] = message[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return JSON.stringify(newMessage);
|
return JSON.stringify(newMessage);
|
||||||
|
|
|
@ -5,7 +5,7 @@ var plugins = require('ep_etherpad-lite/static/js/pluginfw/plugins');
|
||||||
var _ = require('underscore');
|
var _ = require('underscore');
|
||||||
var semver = require('semver');
|
var semver = require('semver');
|
||||||
|
|
||||||
exports.expressCreateServer = function (hook_name, args, cb) {
|
exports.expressCreateServer = function(hook_name, args, cb) {
|
||||||
args.app.get('/admin/plugins', function(req, res) {
|
args.app.get('/admin/plugins', function(req, res) {
|
||||||
var plugins = require("ep_etherpad-lite/static/js/pluginfw/plugins");
|
var plugins = require("ep_etherpad-lite/static/js/pluginfw/plugins");
|
||||||
var render_args = {
|
var render_args = {
|
||||||
|
@ -13,74 +13,81 @@ exports.expressCreateServer = function (hook_name, args, cb) {
|
||||||
search_results: {},
|
search_results: {},
|
||||||
errors: [],
|
errors: [],
|
||||||
};
|
};
|
||||||
res.send( eejs.require("ep_etherpad-lite/templates/admin/plugins.html", render_args) );
|
|
||||||
|
res.send(eejs.require("ep_etherpad-lite/templates/admin/plugins.html", render_args));
|
||||||
});
|
});
|
||||||
|
|
||||||
args.app.get('/admin/plugins/info', function(req, res) {
|
args.app.get('/admin/plugins/info', function(req, res) {
|
||||||
var gitCommit = settings.getGitCommit();
|
var gitCommit = settings.getGitCommit();
|
||||||
var epVersion = settings.getEpVersion();
|
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,
|
gitCommit: gitCommit,
|
||||||
epVersion: epVersion
|
epVersion: epVersion
|
||||||
})
|
}));
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.socketio = function (hook_name, args, cb) {
|
exports.socketio = function(hook_name, args, cb) {
|
||||||
var io = args.io.of("/pluginfw/installer");
|
var io = args.io.of("/pluginfw/installer");
|
||||||
io.on('connection', function (socket) {
|
io.on('connection', function(socket) {
|
||||||
|
|
||||||
if (!socket.conn.request.session || !socket.conn.request.session.user || !socket.conn.request.session.user.is_admin) return;
|
if (!socket.conn.request.session || !socket.conn.request.session.user || !socket.conn.request.session.user.is_admin) return;
|
||||||
|
|
||||||
socket.on("getInstalled", function (query) {
|
socket.on("getInstalled", function(query) {
|
||||||
// send currently installed plugins
|
// send currently installed plugins
|
||||||
var installed = Object.keys(plugins.plugins).map(function(plugin) {
|
var installed = Object.keys(plugins.plugins).map(function(plugin) {
|
||||||
return plugins.plugins[plugin].package
|
return plugins.plugins[plugin].package
|
||||||
})
|
});
|
||||||
|
|
||||||
socket.emit("results:installed", {installed: installed});
|
socket.emit("results:installed", {installed: installed});
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("checkUpdates", function() {
|
socket.on("checkUpdates", function() {
|
||||||
// Check plugins for updates
|
// Check plugins for updates
|
||||||
installer.getAvailablePlugins(/*maxCacheAge:*/60*10, function(er, results) {
|
installer.getAvailablePlugins(/*maxCacheAge:*/ 60 * 10, function(er, results) {
|
||||||
if(er) {
|
if (er) {
|
||||||
console.warn(er);
|
console.warn(er);
|
||||||
socket.emit("results:updatable", {updatable: {}});
|
socket.emit("results:updatable", {updatable: {}});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var updatable = _(plugins.plugins).keys().filter(function(plugin) {
|
var updatable = _(plugins.plugins).keys().filter(function(plugin) {
|
||||||
if(!results[plugin]) return false;
|
if (!results[plugin]) return false;
|
||||||
var latestVersion = results[plugin].version
|
|
||||||
var currentVersion = plugins.plugins[plugin].package.version
|
var latestVersion = results[plugin].version;
|
||||||
return semver.gt(latestVersion, currentVersion)
|
var currentVersion = plugins.plugins[plugin].package.version;
|
||||||
|
|
||||||
|
return semver.gt(latestVersion, currentVersion);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.emit("results:updatable", {updatable: updatable});
|
socket.emit("results:updatable", {updatable: updatable});
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
socket.on("getAvailable", function (query) {
|
socket.on("getAvailable", function(query) {
|
||||||
installer.getAvailablePlugins(/*maxCacheAge:*/false, function (er, results) {
|
installer.getAvailablePlugins(/*maxCacheAge:*/ false, function(er, results) {
|
||||||
if(er) {
|
if (er) {
|
||||||
console.error(er)
|
console.error(er);
|
||||||
results = {}
|
results = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.emit("results:available", results);
|
socket.emit("results:available", results);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("search", function (query) {
|
socket.on("search", function(query) {
|
||||||
installer.search(query.searchTerm, /*maxCacheAge:*/60*10, function (er, results) {
|
installer.search(query.searchTerm, /*maxCacheAge:*/ 60 * 10, function(er, results) {
|
||||||
if(er) {
|
if (er) {
|
||||||
console.error(er)
|
console.error(er);
|
||||||
results = {}
|
results = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
var res = Object.keys(results)
|
var res = Object.keys(results)
|
||||||
.map(function(pluginName) {
|
.map(function(pluginName) {
|
||||||
return results[pluginName]
|
return results[pluginName];
|
||||||
})
|
})
|
||||||
.filter(function(plugin) {
|
.filter(function(plugin) {
|
||||||
return !plugins.plugins[plugin.name]
|
return !plugins.plugins[plugin.name];
|
||||||
});
|
});
|
||||||
res = sortPluginList(res, query.sortBy, query.sortDir)
|
res = sortPluginList(res, query.sortBy, query.sortDir)
|
||||||
.slice(query.offset, query.offset+query.limit);
|
.slice(query.offset, query.offset+query.limit);
|
||||||
|
@ -88,16 +95,18 @@ exports.socketio = function (hook_name, args, cb) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("install", function (plugin_name) {
|
socket.on("install", function(plugin_name) {
|
||||||
installer.install(plugin_name, function (er) {
|
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.emit("finished:install", {plugin: plugin_name, code: er? er.code : null, error: er? er.message : null});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("uninstall", function (plugin_name) {
|
socket.on("uninstall", function(plugin_name) {
|
||||||
installer.uninstall(plugin_name, function (er) {
|
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});
|
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) {
|
function sortPluginList(plugins, property, /*ASC?*/dir) {
|
||||||
return plugins.sort(function(a, b) {
|
return plugins.sort(function(a, b) {
|
||||||
if (a[property] < b[property])
|
if (a[property] < b[property]) {
|
||||||
return dir? -1 : 1;
|
return dir? -1 : 1;
|
||||||
if (a[property] > b[property])
|
}
|
||||||
|
|
||||||
|
if (a[property] > b[property]) {
|
||||||
return dir? 1 : -1;
|
return dir? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
// a must be equal to b
|
// a must be equal to b
|
||||||
return 0;
|
return 0;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,20 +11,23 @@ exports.gracefulShutdown = function(err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
//ensure there is only one graceful shutdown running
|
// ensure there is only one graceful shutdown running
|
||||||
if(exports.onShutdown) return;
|
if (exports.onShutdown) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
exports.onShutdown = true;
|
exports.onShutdown = true;
|
||||||
|
|
||||||
console.log("graceful shutdown...");
|
console.log("graceful shutdown...");
|
||||||
|
|
||||||
//do the db shutdown
|
// do the db shutdown
|
||||||
db.db.doShutdown(function() {
|
db.db.doShutdown(function() {
|
||||||
console.log("db sucessfully closed.");
|
console.log("db sucessfully closed.");
|
||||||
|
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
setTimeout(function(){
|
setTimeout(function() {
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}, 3000);
|
}, 3000);
|
||||||
}
|
}
|
||||||
|
@ -35,14 +38,14 @@ exports.expressCreateServer = function (hook_name, args, cb) {
|
||||||
exports.app = args.app;
|
exports.app = args.app;
|
||||||
|
|
||||||
// Handle errors
|
// Handle errors
|
||||||
args.app.use(function(err, req, res, next){
|
args.app.use(function(err, req, res, next) {
|
||||||
// if an error occurs Connect will pass it down
|
// if an error occurs Connect will pass it down
|
||||||
// through these "error-handling" middleware
|
// through these "error-handling" middleware
|
||||||
// allowing you to respond however you like
|
// allowing you to respond however you like
|
||||||
res.status(500).send({ error: 'Sorry, something bad happened!' });
|
res.status(500).send({ error: 'Sorry, something bad happened!' });
|
||||||
console.error(err.stack? err.stack : err.toString());
|
console.error(err.stack? err.stack : err.toString());
|
||||||
stats.meter('http500').mark()
|
stats.meter('http500').mark()
|
||||||
})
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Connect graceful shutdown with sigint and uncaught exception
|
* Connect graceful shutdown with sigint and uncaught exception
|
||||||
|
|
|
@ -13,7 +13,7 @@ exports.expressCreateServer = function (hook_name, args, cb) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if abiword is disabled, and this is a format we only support with abiword, output a message
|
// if abiword is disabled, and this is a format we only support with abiword, output a message
|
||||||
if (settings.exportAvailable() == "no" &&
|
if (settings.exportAvailable() == "no" &&
|
||||||
["odt", "pdf", "doc"].indexOf(req.params.type) !== -1) {
|
["odt", "pdf", "doc"].indexOf(req.params.type) !== -1) {
|
||||||
res.send("This export is not enabled at this Etherpad instance. Set the path to Abiword or SOffice in settings.json to enable this feature");
|
res.send("This export is not enabled at this Etherpad instance. Set the path to Abiword or SOffice in settings.json to enable this feature");
|
||||||
|
@ -24,9 +24,8 @@ exports.expressCreateServer = function (hook_name, args, cb) {
|
||||||
|
|
||||||
hasPadAccess(req, res, function() {
|
hasPadAccess(req, res, function() {
|
||||||
console.log('req.params.pad', req.params.pad);
|
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) {
|
||||||
if(!exists) {
|
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,12 +34,11 @@ exports.expressCreateServer = function (hook_name, args, cb) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
//handle import requests
|
// handle import requests
|
||||||
args.app.post('/p/:pad/import', function(req, res, next) {
|
args.app.post('/p/:pad/import', function(req, res, next) {
|
||||||
hasPadAccess(req, res, function() {
|
hasPadAccess(req, res, function() {
|
||||||
padManager.doesPadExists(req.params.pad, function(err, exists)
|
padManager.doesPadExists(req.params.pad, function(err, exists) {
|
||||||
{
|
if (!exists) {
|
||||||
if(!exists) {
|
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,52 +5,45 @@ var hasPadAccess = require("../../padaccess");
|
||||||
var exporthtml = require("../../utils/ExportHtml");
|
var exporthtml = require("../../utils/ExportHtml");
|
||||||
|
|
||||||
exports.expressCreateServer = function (hook_name, args, cb) {
|
exports.expressCreateServer = function (hook_name, args, cb) {
|
||||||
//serve read only pad
|
// serve read only pad
|
||||||
args.app.get('/ro/:id', function(req, res)
|
args.app.get('/ro/:id', function(req, res) {
|
||||||
{
|
|
||||||
var html;
|
var html;
|
||||||
var padId;
|
var padId;
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
//translate the read only pad to a padId
|
// translate the read only pad to a padId
|
||||||
function(callback)
|
function(callback) {
|
||||||
{
|
readOnlyManager.getPadId(req.params.id, function(err, _padId) {
|
||||||
readOnlyManager.getPadId(req.params.id, function(err, _padId)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
if(ERR(err, callback)) return;
|
||||||
|
|
||||||
padId = _padId;
|
padId = _padId;
|
||||||
|
|
||||||
//we need that to tell hasPadAcess about the pad
|
// we need that to tell hasPadAcess about the pad
|
||||||
req.params.pad = padId;
|
req.params.pad = padId;
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//render the html document
|
// render the html document
|
||||||
function(callback)
|
function(callback) {
|
||||||
{
|
// return if the there is no padId
|
||||||
//return if the there is no padId
|
if(padId == null) {
|
||||||
if(padId == null)
|
|
||||||
{
|
|
||||||
callback("notfound");
|
callback("notfound");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
hasPadAccess(req, res, function()
|
hasPadAccess(req, res, function() {
|
||||||
{
|
// render the html document
|
||||||
//render the html document
|
exporthtml.getPadHTMLDocument(padId, null, function(err, _html) {
|
||||||
exporthtml.getPadHTMLDocument(padId, null, function(err, _html)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
if(ERR(err, callback)) return;
|
||||||
html = _html;
|
html = _html;
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
], function(err)
|
],
|
||||||
{
|
function(err) {
|
||||||
//throw any unexpected error
|
// throw any unexpected error
|
||||||
if(err && err != "notfound")
|
if(err && err != "notfound")
|
||||||
ERR(err);
|
ERR(err);
|
||||||
|
|
||||||
|
|
|
@ -2,29 +2,26 @@ var padManager = require('../../db/PadManager');
|
||||||
var url = require('url');
|
var url = require('url');
|
||||||
|
|
||||||
exports.expressCreateServer = function (hook_name, args, cb) {
|
exports.expressCreateServer = function (hook_name, args, cb) {
|
||||||
//redirects browser to the pad's sanitized url if needed. otherwise, renders the html
|
|
||||||
|
// redirects browser to the pad's sanitized url if needed. otherwise, renders the html
|
||||||
args.app.param('pad', function (req, res, next, padId) {
|
args.app.param('pad', function (req, res, next, padId) {
|
||||||
//ensure the padname is valid and the url doesn't end with a /
|
// 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');
|
res.status(404).send('Such a padname is forbidden');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
padManager.sanitizePadId(padId, function(sanitizedPadId) {
|
padManager.sanitizePadId(padId, function(sanitizedPadId) {
|
||||||
//the pad id was sanitized, so we redirect to the sanitized version
|
if (sanitizedPadId != padId) {
|
||||||
if(sanitizedPadId != padId)
|
// the pad id was sanitized, so we redirect to the sanitized version
|
||||||
{
|
|
||||||
var real_url = sanitizedPadId;
|
var real_url = sanitizedPadId;
|
||||||
real_url = encodeURIComponent(real_url);
|
real_url = encodeURIComponent(real_url);
|
||||||
var query = url.parse(req.url).query;
|
var query = url.parse(req.url).query;
|
||||||
if ( query ) real_url += '?' + query;
|
if ( query ) real_url += '?' + query;
|
||||||
res.header('Location', real_url);
|
res.header('Location', real_url);
|
||||||
res.status(302).send('You should be redirected to <a href="' + real_url + '">' + real_url + '</a>');
|
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
|
// the pad id was fine, so just render it
|
||||||
else
|
|
||||||
{
|
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,37 +4,35 @@ var path = require("path")
|
||||||
, async = require("async");
|
, async = require("async");
|
||||||
|
|
||||||
exports.expressCreateServer = function (hook_name, args, cb) {
|
exports.expressCreateServer = function (hook_name, args, cb) {
|
||||||
args.app.get('/tests/frontend/specs_list.js', function(req, res){
|
args.app.get('/tests/frontend/specs_list.js', function(req, res) {
|
||||||
|
|
||||||
async.parallel({
|
async.parallel({
|
||||||
coreSpecs: function(callback){
|
coreSpecs: function(callback) {
|
||||||
exports.getCoreTests(callback);
|
exports.getCoreTests(callback);
|
||||||
},
|
},
|
||||||
pluginSpecs: function(callback){
|
pluginSpecs: function(callback) {
|
||||||
exports.getPluginTests(callback);
|
exports.getPluginTests(callback);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(err, results){
|
function(err, results) {
|
||||||
var files = results.coreSpecs; // push the core specs to a file object
|
var files = results.coreSpecs; // push the core specs to a file object
|
||||||
files = files.concat(results.pluginSpecs); // add the plugin Specs to the core specs
|
files = files.concat(results.pluginSpecs); // add the plugin Specs to the core specs
|
||||||
console.debug("Sent browser the following test specs:", files.sort());
|
console.debug("Sent browser the following test specs:", files.sort());
|
||||||
res.send("var specs_list = " + JSON.stringify(files.sort()) + ";\n");
|
res.send("var specs_list = " + JSON.stringify(files.sort()) + ";\n");
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// path.join seems to normalize by default, but we'll just be explicit
|
// path.join seems to normalize by default, but we'll just be explicit
|
||||||
var rootTestFolder = path.normalize(path.join(npm.root, "../tests/frontend/"));
|
var rootTestFolder = path.normalize(path.join(npm.root, "../tests/frontend/"));
|
||||||
|
|
||||||
var url2FilePath = function(url){
|
var url2FilePath = function(url) {
|
||||||
var subPath = url.substr("/tests/frontend".length);
|
var subPath = url.substr("/tests/frontend".length);
|
||||||
if (subPath == ""){
|
if (subPath == "") {
|
||||||
subPath = "index.html"
|
subPath = "index.html"
|
||||||
}
|
}
|
||||||
subPath = subPath.split("?")[0];
|
subPath = subPath.split("?")[0];
|
||||||
|
|
||||||
var filePath = path.normalize(path.join(rootTestFolder, subPath));
|
var filePath = path.normalize(path.join(rootTestFolder, subPath));
|
||||||
|
|
||||||
// make sure we jail the paths to the test folder, otherwise serve index
|
// make sure we jail the paths to the test folder, otherwise serve index
|
||||||
if (filePath.indexOf(rootTestFolder) !== 0) {
|
if (filePath.indexOf(rootTestFolder) !== 0) {
|
||||||
filePath = path.join(rootTestFolder, "index.html");
|
filePath = path.join(rootTestFolder, "index.html");
|
||||||
|
@ -46,8 +44,8 @@ exports.expressCreateServer = function (hook_name, args, cb) {
|
||||||
var specFilePath = url2FilePath(req.url);
|
var specFilePath = url2FilePath(req.url);
|
||||||
var specFileName = path.basename(specFilePath);
|
var specFileName = path.basename(specFilePath);
|
||||||
|
|
||||||
fs.readFile(specFilePath, function(err, content){
|
fs.readFile(specFilePath, function(err, content) {
|
||||||
if(err){ return res.send(500); }
|
if (err) { return res.send(500); }
|
||||||
|
|
||||||
content = "describe(" + JSON.stringify(specFileName) + ", function(){ " + content + " });";
|
content = "describe(" + JSON.stringify(specFileName) + ", function(){ " + content + " });";
|
||||||
|
|
||||||
|
@ -65,16 +63,18 @@ exports.expressCreateServer = function (hook_name, args, cb) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.getPluginTests = function(callback){
|
exports.getPluginTests = function(callback) {
|
||||||
var pluginSpecs = [];
|
var pluginSpecs = [];
|
||||||
var plugins = fs.readdirSync('node_modules');
|
var plugins = fs.readdirSync('node_modules');
|
||||||
plugins.forEach(function(plugin){
|
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")) {
|
||||||
var specFiles = fs.readdirSync("node_modules/"+plugin+"/static/tests/frontend/specs/");
|
// if plugins exists
|
||||||
async.forEach(specFiles, function(spec){ // for each specFile push it to pluginSpecs
|
var specFiles = fs.readdirSync("node_modules/" + plugin + "/static/tests/frontend/specs/");
|
||||||
pluginSpecs.push("/static/plugins/"+plugin+"/static/tests/frontend/specs/" + spec);
|
async.forEach(specFiles, function(spec) {
|
||||||
|
// for each specFile push it to pluginSpecs
|
||||||
|
pluginSpecs.push("/static/plugins/" + plugin + "/static/tests/frontend/specs/" + spec);
|
||||||
},
|
},
|
||||||
function(err){
|
function(err) {
|
||||||
// blow up if something bad happens!
|
// blow up if something bad happens!
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -82,10 +82,11 @@ exports.getPluginTests = function(callback){
|
||||||
callback(null, pluginSpecs);
|
callback(null, pluginSpecs);
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.getCoreTests = function(callback){
|
exports.getCoreTests = function(callback) {
|
||||||
fs.readdir('tests/frontend/specs', function(err, coreSpecs){ // get the core test specs
|
// get the core test specs
|
||||||
if(err){ return res.send(500); }
|
fs.readdir('tests/frontend/specs', function(err, coreSpecs) {
|
||||||
|
if (err) { return res.send(500); }
|
||||||
|
|
||||||
callback(null, coreSpecs);
|
callback(null, coreSpecs);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
var ERR = require("async-stacktrace");
|
var ERR = require("async-stacktrace");
|
||||||
var securityManager = require('./db/SecurityManager');
|
var securityManager = require('./db/SecurityManager');
|
||||||
|
|
||||||
//checks for padAccess
|
// checks for padAccess
|
||||||
module.exports = function (req, res, callback) {
|
module.exports = function (req, res, callback) {
|
||||||
securityManager.checkAccess(req.params.pad, req.cookies.sessionID, req.cookies.token, req.cookies.password, function(err, accessObj) {
|
securityManager.checkAccess(req.params.pad, req.cookies.sessionID, req.cookies.token, req.cookies.password, function(err, accessObj) {
|
||||||
if(ERR(err, callback)) return;
|
if (ERR(err, callback)) return;
|
||||||
|
|
||||||
//there is access, continue
|
if (accessObj.accessStatus == "grant") {
|
||||||
if(accessObj.accessStatus == "grant") {
|
// there is access, continue
|
||||||
callback();
|
callback();
|
||||||
//no access
|
|
||||||
} else {
|
} else {
|
||||||
|
// no access
|
||||||
res.status(403).send("403 - Can't touch this");
|
res.status(403).send("403 - Can't touch this");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -46,8 +46,8 @@ NodeVersion.enforceMinNodeVersion('8.9.0');
|
||||||
*/
|
*/
|
||||||
var stats = require('./stats');
|
var stats = require('./stats');
|
||||||
stats.gauge('memoryUsage', function() {
|
stats.gauge('memoryUsage', function() {
|
||||||
return process.memoryUsage().rss
|
return process.memoryUsage().rss;
|
||||||
})
|
});
|
||||||
|
|
||||||
var settings
|
var settings
|
||||||
, db
|
, db
|
||||||
|
@ -59,8 +59,8 @@ async.waterfall([
|
||||||
// load npm
|
// load npm
|
||||||
function(callback) {
|
function(callback) {
|
||||||
npm.load({}, function(er) {
|
npm.load({}, function(er) {
|
||||||
callback(er)
|
callback(er);
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// load everything
|
// load everything
|
||||||
|
@ -73,14 +73,13 @@ async.waterfall([
|
||||||
callback();
|
callback();
|
||||||
},
|
},
|
||||||
|
|
||||||
//initalize the database
|
// initalize the database
|
||||||
function (callback)
|
function (callback) {
|
||||||
{
|
|
||||||
db.init(callback);
|
db.init(callback);
|
||||||
},
|
},
|
||||||
|
|
||||||
function(callback) {
|
function(callback) {
|
||||||
plugins.update(callback)
|
plugins.update(callback);
|
||||||
},
|
},
|
||||||
|
|
||||||
function (callback) {
|
function (callback) {
|
||||||
|
@ -93,9 +92,8 @@ async.waterfall([
|
||||||
callback();
|
callback();
|
||||||
},
|
},
|
||||||
|
|
||||||
//initalize the http server
|
// initalize the http server
|
||||||
function (callback)
|
function (callback) {
|
||||||
{
|
|
||||||
hooks.callAll("createServer", {});
|
hooks.callAll("createServer", {});
|
||||||
callback(null);
|
callback(null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,40 +30,32 @@ function getPadTXT(pad, revNum, callback)
|
||||||
var atext = pad.atext;
|
var atext = pad.atext;
|
||||||
var html;
|
var html;
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
|
|
||||||
// fetch revision atext
|
// fetch revision atext
|
||||||
|
function(callback) {
|
||||||
|
if (revNum != undefined) {
|
||||||
|
pad.getInternalRevisionAText(revNum, function(err, revisionAtext) {
|
||||||
|
if (ERR(err, callback)) return;
|
||||||
|
|
||||||
|
|
||||||
function (callback)
|
|
||||||
{
|
|
||||||
if (revNum != undefined)
|
|
||||||
{
|
|
||||||
pad.getInternalRevisionAText(revNum, function (err, revisionAtext)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
atext = revisionAtext;
|
atext = revisionAtext;
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
callback(null);
|
callback(null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// convert atext to html
|
// convert atext to html
|
||||||
|
function(callback) {
|
||||||
|
// only this line is different to the HTML function
|
||||||
function (callback)
|
html = getTXTFromAtext(pad, atext);
|
||||||
{
|
|
||||||
html = getTXTFromAtext(pad, atext); // only this line is different to the HTML function
|
|
||||||
callback(null);
|
callback(null);
|
||||||
}],
|
}],
|
||||||
|
|
||||||
// run final callback
|
// run final callback
|
||||||
|
function(err) {
|
||||||
|
if (ERR(err, callback)) return;
|
||||||
|
|
||||||
|
|
||||||
function (err)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
callback(null, html);
|
callback(null, html);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -80,17 +72,14 @@ function getTXTFromAtext(pad, atext, authorColors)
|
||||||
var anumMap = {};
|
var anumMap = {};
|
||||||
var css = "";
|
var css = "";
|
||||||
|
|
||||||
props.forEach(function (propName, i)
|
props.forEach(function(propName, i) {
|
||||||
{
|
|
||||||
var propTrueNum = apool.putAttrib([propName, true], true);
|
var propTrueNum = apool.putAttrib([propName, true], true);
|
||||||
if (propTrueNum >= 0)
|
if (propTrueNum >= 0) {
|
||||||
{
|
|
||||||
anumMap[propTrueNum] = i;
|
anumMap[propTrueNum] = i;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function getLineTXT(text, attribs)
|
function getLineTXT(text, attribs) {
|
||||||
{
|
|
||||||
var propVals = [false, false, false];
|
var propVals = [false, false, false];
|
||||||
var ENTER = 1;
|
var ENTER = 1;
|
||||||
var STAY = 2;
|
var STAY = 2;
|
||||||
|
@ -106,94 +95,77 @@ function getTXTFromAtext(pad, atext, authorColors)
|
||||||
|
|
||||||
var idx = 0;
|
var idx = 0;
|
||||||
|
|
||||||
function processNextChars(numChars)
|
function processNextChars(numChars) {
|
||||||
{
|
if (numChars <= 0) {
|
||||||
if (numChars <= 0)
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var iter = Changeset.opIterator(Changeset.subattribution(attribs, idx, idx + numChars));
|
var iter = Changeset.opIterator(Changeset.subattribution(attribs, idx, idx + numChars));
|
||||||
idx += numChars;
|
idx += numChars;
|
||||||
|
|
||||||
while (iter.hasNext())
|
while (iter.hasNext()) {
|
||||||
{
|
|
||||||
var o = iter.next();
|
var o = iter.next();
|
||||||
var propChanged = false;
|
var propChanged = false;
|
||||||
Changeset.eachAttribNumber(o.attribs, function (a)
|
|
||||||
{
|
Changeset.eachAttribNumber(o.attribs, function(a) {
|
||||||
if (a in anumMap)
|
if (a in anumMap) {
|
||||||
{
|
|
||||||
var i = anumMap[a]; // i = 0 => bold, etc.
|
var i = anumMap[a]; // i = 0 => bold, etc.
|
||||||
if (!propVals[i])
|
|
||||||
{
|
if (!propVals[i]) {
|
||||||
propVals[i] = ENTER;
|
propVals[i] = ENTER;
|
||||||
propChanged = true;
|
propChanged = true;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
propVals[i] = STAY;
|
propVals[i] = STAY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
for (var i = 0; i < propVals.length; i++)
|
|
||||||
{
|
for (var i = 0; i < propVals.length; i++) {
|
||||||
if (propVals[i] === true)
|
if (propVals[i] === true) {
|
||||||
{
|
|
||||||
propVals[i] = LEAVE;
|
propVals[i] = LEAVE;
|
||||||
propChanged = true;
|
propChanged = true;
|
||||||
}
|
} else if (propVals[i] === STAY) {
|
||||||
else if (propVals[i] === STAY)
|
// set it back
|
||||||
{
|
propVals[i] = true;
|
||||||
propVals[i] = true; // set it back
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// now each member of propVal is in {false,LEAVE,ENTER,true}
|
// now each member of propVal is in {false,LEAVE,ENTER,true}
|
||||||
// according to what happens at start of span
|
// according to what happens at start of span
|
||||||
if (propChanged)
|
if (propChanged) {
|
||||||
{
|
|
||||||
// leaving bold (e.g.) also leaves italics, etc.
|
// leaving bold (e.g.) also leaves italics, etc.
|
||||||
var left = false;
|
var left = false;
|
||||||
for (var i = 0; i < propVals.length; i++)
|
|
||||||
{
|
for (var i = 0; i < propVals.length; i++) {
|
||||||
var v = propVals[i];
|
var v = propVals[i];
|
||||||
if (!left)
|
|
||||||
{
|
if (!left) {
|
||||||
if (v === LEAVE)
|
if (v === LEAVE) {
|
||||||
{
|
|
||||||
left = true;
|
left = true;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
if (v === true) {
|
||||||
{
|
// tag will be closed and re-opened
|
||||||
if (v === true)
|
propVals[i] = STAY;
|
||||||
{
|
|
||||||
propVals[i] = STAY; // tag will be closed and re-opened
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var tags2close = [];
|
var tags2close = [];
|
||||||
|
|
||||||
for (var i = propVals.length - 1; i >= 0; i--)
|
for (var i = propVals.length - 1; i >= 0; i--) {
|
||||||
{
|
if (propVals[i] === LEAVE) {
|
||||||
if (propVals[i] === LEAVE)
|
|
||||||
{
|
|
||||||
//emitCloseTag(i);
|
//emitCloseTag(i);
|
||||||
tags2close.push(i);
|
tags2close.push(i);
|
||||||
propVals[i] = false;
|
propVals[i] = false;
|
||||||
}
|
} else if (propVals[i] === STAY) {
|
||||||
else if (propVals[i] === STAY)
|
|
||||||
{
|
|
||||||
//emitCloseTag(i);
|
//emitCloseTag(i);
|
||||||
tags2close.push(i);
|
tags2close.push(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < propVals.length; i++)
|
for (var i = 0; i < propVals.length; i++) {
|
||||||
{
|
if (propVals[i] === ENTER || propVals[i] === STAY) {
|
||||||
if (propVals[i] === ENTER || propVals[i] === STAY)
|
|
||||||
{
|
|
||||||
propVals[i] = true;
|
propVals[i] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -201,9 +173,9 @@ function getTXTFromAtext(pad, atext, authorColors)
|
||||||
} // end if (propChanged)
|
} // end if (propChanged)
|
||||||
|
|
||||||
var chars = o.chars;
|
var chars = o.chars;
|
||||||
if (o.lines)
|
if (o.lines) {
|
||||||
{
|
// exclude newline at end of line, if present
|
||||||
chars--; // exclude newline at end of line, if present
|
chars--;
|
||||||
}
|
}
|
||||||
|
|
||||||
var s = taker.take(chars);
|
var s = taker.take(chars);
|
||||||
|
@ -220,19 +192,19 @@ function getTXTFromAtext(pad, atext, authorColors)
|
||||||
} // end iteration over spans in line
|
} // end iteration over spans in line
|
||||||
|
|
||||||
var tags2close = [];
|
var tags2close = [];
|
||||||
for (var i = propVals.length - 1; i >= 0; i--)
|
for (var i = propVals.length - 1; i >= 0; i--) {
|
||||||
{
|
if (propVals[i]) {
|
||||||
if (propVals[i])
|
|
||||||
{
|
|
||||||
tags2close.push(i);
|
tags2close.push(i);
|
||||||
propVals[i] = false;
|
propVals[i] = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end processNextChars
|
} // end processNextChars
|
||||||
|
|
||||||
processNextChars(text.length - idx);
|
processNextChars(text.length - idx);
|
||||||
return(assem.toString());
|
return(assem.toString());
|
||||||
} // end getLineHTML
|
} // end getLineHTML
|
||||||
|
|
||||||
var pieces = [css];
|
var pieces = [css];
|
||||||
|
|
||||||
// Need to deal with constraints imposed on HTML lists; can
|
// Need to deal with constraints imposed on HTML lists; can
|
||||||
|
@ -242,41 +214,44 @@ function getTXTFromAtext(pad, atext, authorColors)
|
||||||
// so we want to do something reasonable there. We also
|
// so we want to do something reasonable there. We also
|
||||||
// want to deal gracefully with blank lines.
|
// want to deal gracefully with blank lines.
|
||||||
// => keeps track of the parents level of indentation
|
// => 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 line = _analyzeLine(textLines[i], attribLines[i], apool);
|
||||||
var lineContent = getLineTXT(line.text, line.aline);
|
var lineContent = getLineTXT(line.text, line.aline);
|
||||||
if(line.listTypeName == "bullet"){
|
|
||||||
|
if (line.listTypeName == "bullet") {
|
||||||
lineContent = "* " + lineContent; // add a bullet
|
lineContent = "* " + lineContent; // add a bullet
|
||||||
}
|
}
|
||||||
if(line.listLevel > 0){
|
|
||||||
for (var j = line.listLevel - 1; j >= 0; j--){
|
if (line.listLevel > 0) {
|
||||||
|
for (var j = line.listLevel - 1; j >= 0; j--) {
|
||||||
pieces.push('\t');
|
pieces.push('\t');
|
||||||
}
|
}
|
||||||
if(line.listTypeName == "number"){
|
|
||||||
|
if (line.listTypeName == "number") {
|
||||||
pieces.push(line.listLevel + ". ");
|
pieces.push(line.listLevel + ". ");
|
||||||
// This is bad because it doesn't truly reflect what the user
|
// This is bad because it doesn't truly reflect what the user
|
||||||
// sees because browsers do magic on nested <ol><li>s
|
// sees because browsers do magic on nested <ol><li>s
|
||||||
}
|
}
|
||||||
|
|
||||||
pieces.push(lineContent, '\n');
|
pieces.push(lineContent, '\n');
|
||||||
}else{
|
} else {
|
||||||
pieces.push(lineContent, '\n');
|
pieces.push(lineContent, '\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pieces.join('');
|
return pieces.join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.getTXTFromAtext = getTXTFromAtext;
|
exports.getTXTFromAtext = getTXTFromAtext;
|
||||||
|
|
||||||
exports.getPadTXTDocument = function (padId, revNum, callback)
|
exports.getPadTXTDocument = function(padId, revNum, callback)
|
||||||
{
|
{
|
||||||
padManager.getPad(padId, function (err, pad)
|
padManager.getPad(padId, function(err, pad) {
|
||||||
{
|
if (ERR(err, callback)) return;
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
|
getPadTXT(pad, revNum, function(err, html) {
|
||||||
|
if (ERR(err, callback)) return;
|
||||||
|
|
||||||
getPadTXT(pad, revNum, function (err, html)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
callback(null, html);
|
callback(null, html);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,57 +18,56 @@ var log4js = require('log4js');
|
||||||
var async = require("async");
|
var async = require("async");
|
||||||
var db = require("../db/DB").db;
|
var db = require("../db/DB").db;
|
||||||
|
|
||||||
exports.setPadRaw = function(padId, records, callback){
|
exports.setPadRaw = function(padId, records, callback)
|
||||||
|
{
|
||||||
records = JSON.parse(records);
|
records = JSON.parse(records);
|
||||||
|
|
||||||
async.eachSeries(Object.keys(records), function(key, cb){
|
async.eachSeries(Object.keys(records), function(key, cb) {
|
||||||
var value = records[key]
|
var value = records[key];
|
||||||
|
|
||||||
if(!value){
|
if (!value) {
|
||||||
return setImmediate(cb);
|
return setImmediate(cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Author data
|
if (value.padIDs) {
|
||||||
if(value.padIDs){
|
// Author data - rewrite author pad ids
|
||||||
// rewrite author pad ids
|
|
||||||
value.padIDs[padId] = 1;
|
value.padIDs[padId] = 1;
|
||||||
var newKey = key;
|
var newKey = key;
|
||||||
|
|
||||||
// Does this author already exist?
|
// Does this author already exist?
|
||||||
db.get(key, function(err, author){
|
db.get(key, function(err, author) {
|
||||||
if(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]'){
|
if (Object.prototype.toString.call(author) === '[object Array]') {
|
||||||
author.padIDs.push(padId);
|
author.padIDs.push(padId);
|
||||||
}
|
}
|
||||||
value = author;
|
value = author;
|
||||||
}else{
|
} else {
|
||||||
// No, create a new array with the author info in
|
// No, create a new array with the author info in
|
||||||
value.padIDs = [padId];
|
value.padIDs = [padId];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
// Not author data, probably pad data
|
// Not author data, probably pad data
|
||||||
}else{
|
// we can split it to look to see if it's pad data
|
||||||
// we can split it to look to see if its pad data
|
|
||||||
var oldPadId = key.split(":");
|
var oldPadId = key.split(":");
|
||||||
|
|
||||||
// we know its pad data..
|
// we know it's pad data
|
||||||
if(oldPadId[0] === "pad"){
|
if (oldPadId[0] === "pad") {
|
||||||
|
|
||||||
// so set the new pad id for the author
|
// so set the new pad id for the author
|
||||||
oldPadId[1] = padId;
|
oldPadId[1] = padId;
|
||||||
|
|
||||||
// and create the value
|
// and create the value
|
||||||
var newKey = oldPadId.join(":"); // create the new key
|
var newKey = oldPadId.join(":"); // create the new key
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the value to the server
|
// Write the value to the server
|
||||||
db.set(newKey, value);
|
db.set(newKey, value);
|
||||||
|
|
||||||
setImmediate(cb);
|
setImmediate(cb);
|
||||||
}, function(){
|
},
|
||||||
|
function() {
|
||||||
callback(null, true);
|
callback(null, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,19 +36,22 @@ function setPadHTML(pad, html, callback)
|
||||||
// Convert a dom tree into a list of lines and attribute liens
|
// Convert a dom tree into a list of lines and attribute liens
|
||||||
// using the content collector object
|
// using the content collector object
|
||||||
var cc = contentcollector.makeContentCollector(true, null, pad.pool);
|
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);
|
cc.collectContent(doc);
|
||||||
}catch(e){
|
} catch(e) {
|
||||||
apiLogger.warn("HTML was not properly formed", 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();
|
var result = cc.finish();
|
||||||
|
|
||||||
apiLogger.debug('Lines:');
|
apiLogger.debug('Lines:');
|
||||||
|
|
||||||
var i;
|
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) + ' text: ' + result.lines[i]);
|
||||||
apiLogger.debug('Line ' + (i + 1) + ' attributes: ' + result.lineAttribs[i]);
|
apiLogger.debug('Line ' + (i + 1) + ' attributes: ' + result.lineAttribs[i]);
|
||||||
}
|
}
|
||||||
|
@ -59,18 +62,15 @@ function setPadHTML(pad, html, callback)
|
||||||
apiLogger.debug(newText);
|
apiLogger.debug(newText);
|
||||||
var newAttribs = result.lineAttribs.join('|1+1') + '|1+1';
|
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 attribsIter = Changeset.opIterator(attribs);
|
||||||
var textIndex = 0;
|
var textIndex = 0;
|
||||||
var newTextStart = 0;
|
var newTextStart = 0;
|
||||||
var newTextEnd = newText.length;
|
var newTextEnd = newText.length;
|
||||||
while (attribsIter.hasNext())
|
while (attribsIter.hasNext()) {
|
||||||
{
|
|
||||||
var op = attribsIter.next();
|
var op = attribsIter.next();
|
||||||
var nextIndex = textIndex + op.chars;
|
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);
|
func(Math.max(newTextStart, textIndex), Math.min(newTextEnd, nextIndex), op.attribs);
|
||||||
}
|
}
|
||||||
textIndex = nextIndex;
|
textIndex = nextIndex;
|
||||||
|
@ -81,13 +81,13 @@ function setPadHTML(pad, html, callback)
|
||||||
var builder = Changeset.builder(1);
|
var builder = Changeset.builder(1);
|
||||||
|
|
||||||
// assemble each line into the builder
|
// 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);
|
builder.insert(newText.substring(start, end), attribs);
|
||||||
});
|
});
|
||||||
|
|
||||||
// the changeset is ready!
|
// the changeset is ready!
|
||||||
var theChangeset = builder.toString();
|
var theChangeset = builder.toString();
|
||||||
|
|
||||||
apiLogger.debug('The changeset: ' + theChangeset);
|
apiLogger.debug('The changeset: ' + theChangeset);
|
||||||
pad.setText("\n");
|
pad.setText("\n");
|
||||||
pad.appendRevision(theChangeset);
|
pad.appendRevision(theChangeset);
|
||||||
|
|
|
@ -2,17 +2,18 @@ var Changeset = require("../../static/js/Changeset");
|
||||||
var async = require("async");
|
var async = require("async");
|
||||||
var exportHtml = require('./ExportHtml');
|
var exportHtml = require('./ExportHtml');
|
||||||
|
|
||||||
function PadDiff (pad, fromRev, toRev){
|
function PadDiff (pad, fromRev, toRev) {
|
||||||
//check parameters
|
// check parameters
|
||||||
if(!pad || !pad.id || !pad.atext || !pad.pool)
|
if (!pad || !pad.id || !pad.atext || !pad.pool) {
|
||||||
{
|
|
||||||
throw new Error('Invalid pad');
|
throw new Error('Invalid pad');
|
||||||
}
|
}
|
||||||
|
|
||||||
var range = pad.getValidRevisionRange(fromRev, toRev);
|
var range = pad.getValidRevisionRange(fromRev, toRev);
|
||||||
if(!range) { throw new Error('Invalid revision range.' +
|
if (!range) {
|
||||||
|
throw new Error('Invalid revision range.' +
|
||||||
' startRev: ' + fromRev +
|
' startRev: ' + fromRev +
|
||||||
' endRev: ' + toRev); }
|
' endRev: ' + toRev);
|
||||||
|
}
|
||||||
|
|
||||||
this._pad = pad;
|
this._pad = pad;
|
||||||
this._fromRev = range.startRev;
|
this._fromRev = range.startRev;
|
||||||
|
@ -21,63 +22,70 @@ function PadDiff (pad, fromRev, toRev){
|
||||||
this._authors = [];
|
this._authors = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
PadDiff.prototype._isClearAuthorship = function(changeset){
|
PadDiff.prototype._isClearAuthorship = function(changeset) {
|
||||||
//unpack
|
// unpack
|
||||||
var unpacked = Changeset.unpack(changeset);
|
var unpacked = Changeset.unpack(changeset);
|
||||||
|
|
||||||
//check if there is nothing in the charBank
|
// check if there is nothing in the charBank
|
||||||
if(unpacked.charBank !== "")
|
if (unpacked.charBank !== "") {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//check if oldLength == newLength
|
// check if oldLength == newLength
|
||||||
if(unpacked.oldLen !== unpacked.newLen)
|
if (unpacked.oldLen !== unpacked.newLen) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//lets iterator over the operators
|
// lets iterator over the operators
|
||||||
var iterator = Changeset.opIterator(unpacked.ops);
|
var iterator = Changeset.opIterator(unpacked.ops);
|
||||||
|
|
||||||
//get the first operator, this should be a clear operator
|
// get the first operator, this should be a clear operator
|
||||||
var clearOperator = iterator.next();
|
var clearOperator = iterator.next();
|
||||||
|
|
||||||
//check if there is only one operator
|
// check if there is only one operator
|
||||||
if(iterator.hasNext() === true)
|
if (iterator.hasNext() === true) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//check if this operator doesn't change text
|
// check if this operator doesn't change text
|
||||||
if(clearOperator.opcode !== "=")
|
if (clearOperator.opcode !== "=") {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//check that this operator applys to the complete text
|
// 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 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;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var attributes = [];
|
var attributes = [];
|
||||||
Changeset.eachAttribNumber(changeset, function(attrNum){
|
Changeset.eachAttribNumber(changeset, function(attrNum) {
|
||||||
attributes.push(attrNum);
|
attributes.push(attrNum);
|
||||||
});
|
});
|
||||||
|
|
||||||
//check that this changeset uses only one attribute
|
// check that this changeset uses only one attribute
|
||||||
if(attributes.length !== 1)
|
if (attributes.length !== 1) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var appliedAttribute = this._pad.pool.getAttrib(attributes[0]);
|
var appliedAttribute = this._pad.pool.getAttrib(attributes[0]);
|
||||||
|
|
||||||
//check if the applied attribute is an anonymous author attribute
|
// 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 false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
PadDiff.prototype._createClearAuthorship = function(rev, callback){
|
PadDiff.prototype._createClearAuthorship = function(rev, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
this._pad.getInternalRevisionAText(rev, function(err, atext){
|
this._pad.getInternalRevisionAText(rev, function(err, atext) {
|
||||||
if(err){
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
//build clearAuthorship changeset
|
// build clearAuthorship changeset
|
||||||
var builder = Changeset.builder(atext.text.length);
|
var builder = Changeset.builder(atext.text.length);
|
||||||
builder.keepText(atext.text, [['author','']], self._pad.pool);
|
builder.keepText(atext.text, [['author','']], self._pad.pool);
|
||||||
var changeset = builder.toString();
|
var changeset = builder.toString();
|
||||||
|
@ -86,23 +94,23 @@ PadDiff.prototype._createClearAuthorship = function(rev, callback){
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
PadDiff.prototype._createClearStartAtext = function(rev, callback){
|
PadDiff.prototype._createClearStartAtext = function(rev, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
//get the atext of this revision
|
// get the atext of this revision
|
||||||
this._pad.getInternalRevisionAText(rev, function(err, atext){
|
this._pad.getInternalRevisionAText(rev, function(err, atext) {
|
||||||
if(err){
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
//create the clearAuthorship changeset
|
// create the clearAuthorship changeset
|
||||||
self._createClearAuthorship(rev, function(err, changeset){
|
self._createClearAuthorship(rev, function(err, changeset) {
|
||||||
if(err){
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//apply the clearAuthorship changeset
|
// apply the clearAuthorship changeset
|
||||||
var newAText = Changeset.applyToAText(changeset, atext, self._pad.pool);
|
var newAText = Changeset.applyToAText(changeset, atext, self._pad.pool);
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
return callback(err)
|
return callback(err)
|
||||||
|
@ -116,18 +124,18 @@ PadDiff.prototype._createClearStartAtext = function(rev, callback){
|
||||||
PadDiff.prototype._getChangesetsInBulk = function(startRev, count, callback) {
|
PadDiff.prototype._getChangesetsInBulk = function(startRev, count, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
//find out which revisions we need
|
// find out which revisions we need
|
||||||
var revisions = [];
|
var revisions = [];
|
||||||
for(var i=startRev;i<(startRev+count) && i<=this._pad.head;i++){
|
for (var i = startRev; i < (startRev + count) && i <= this._pad.head; i++) {
|
||||||
revisions.push(i);
|
revisions.push(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
var changesets = [], authors = [];
|
var changesets = [], authors = [];
|
||||||
|
|
||||||
//get all needed revisions
|
// get all needed revisions
|
||||||
async.forEach(revisions, function(rev, callback){
|
async.forEach(revisions, function(rev, callback) {
|
||||||
self._pad.getRevision(rev, function(err, revision){
|
self._pad.getRevision(rev, function(err, revision) {
|
||||||
if(err){
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,16 +146,18 @@ PadDiff.prototype._getChangesetsInBulk = function(startRev, count, callback) {
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
}, function(err){
|
},
|
||||||
|
function(err) {
|
||||||
callback(err, changesets, authors);
|
callback(err, changesets, authors);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
PadDiff.prototype._addAuthors = function(authors) {
|
PadDiff.prototype._addAuthors = function(authors) {
|
||||||
var self = this;
|
var self = this;
|
||||||
//add to array if not in the array
|
|
||||||
authors.forEach(function(author){
|
// add to array if not in the array
|
||||||
if(self._authors.indexOf(author) == -1){
|
authors.forEach(function(author) {
|
||||||
|
if (self._authors.indexOf(author) == -1) {
|
||||||
self._authors.push(author);
|
self._authors.push(author);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -157,67 +167,67 @@ PadDiff.prototype._createDiffAtext = function(callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var bulkSize = 100;
|
var bulkSize = 100;
|
||||||
|
|
||||||
//get the cleaned startAText
|
// get the cleaned startAText
|
||||||
self._createClearStartAtext(self._fromRev, function(err, atext){
|
self._createClearStartAtext(self._fromRev, function(err, atext) {
|
||||||
if(err) { return callback(err); }
|
if (err) { return callback(err); }
|
||||||
|
|
||||||
var superChangeset = null;
|
var superChangeset = null;
|
||||||
|
|
||||||
var rev = self._fromRev + 1;
|
var rev = self._fromRev + 1;
|
||||||
|
|
||||||
//async while loop
|
// async while loop
|
||||||
async.whilst(
|
async.whilst(
|
||||||
//loop condition
|
// loop condition
|
||||||
function () { return rev <= self._toRev; },
|
function () { return rev <= self._toRev; },
|
||||||
|
|
||||||
//loop body
|
// loop body
|
||||||
function (callback) {
|
function (callback) {
|
||||||
//get the bulk
|
// get the bulk
|
||||||
self._getChangesetsInBulk(rev,bulkSize,function(err, changesets, authors){
|
self._getChangesetsInBulk(rev,bulkSize,function(err, changesets, authors) {
|
||||||
var addedAuthors = [];
|
var addedAuthors = [];
|
||||||
|
|
||||||
//run trough all changesets
|
// run trough all changesets
|
||||||
for(var i=0;i<changesets.length && (rev+i)<=self._toRev;i++){
|
for (var i = 0; i < changesets.length && (rev + i) <= self._toRev; i++) {
|
||||||
var changeset = changesets[i];
|
var changeset = changesets[i];
|
||||||
|
|
||||||
//skip clearAuthorship Changesets
|
// skip clearAuthorship Changesets
|
||||||
if(self._isClearAuthorship(changeset)){
|
if (self._isClearAuthorship(changeset)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
changeset = self._extendChangesetWithAuthor(changeset, authors[i], self._pad.pool);
|
changeset = self._extendChangesetWithAuthor(changeset, authors[i], self._pad.pool);
|
||||||
|
|
||||||
//add this author to the authorarray
|
// add this author to the authorarray
|
||||||
addedAuthors.push(authors[i]);
|
addedAuthors.push(authors[i]);
|
||||||
|
|
||||||
//compose it with the superChangset
|
// compose it with the superChangset
|
||||||
if(superChangeset === null){
|
if (superChangeset === null) {
|
||||||
superChangeset = changeset;
|
superChangeset = changeset;
|
||||||
} else {
|
} else {
|
||||||
superChangeset = Changeset.composeWithDeletions(superChangeset, changeset, self._pad.pool);
|
superChangeset = Changeset.composeWithDeletions(superChangeset, changeset, self._pad.pool);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//add the authors to the PadDiff authorArray
|
// add the authors to the PadDiff authorArray
|
||||||
self._addAuthors(addedAuthors);
|
self._addAuthors(addedAuthors);
|
||||||
|
|
||||||
//lets continue with the next bulk
|
// lets continue with the next bulk
|
||||||
rev += bulkSize;
|
rev += bulkSize;
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
//after the loop has ended
|
// after the loop has ended
|
||||||
function (err) {
|
function (err) {
|
||||||
//if there are only clearAuthorship changesets, we don't get a superChangeset, so we can skip this step
|
// if there are only clearAuthorship changesets, we don't get a superChangeset, so we can skip this step
|
||||||
if(superChangeset){
|
if (superChangeset) {
|
||||||
var deletionChangeset = self._createDeletionChangeset(superChangeset,atext,self._pad.pool);
|
var deletionChangeset = self._createDeletionChangeset(superChangeset,atext,self._pad.pool);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//apply the superChangeset, which includes all addings
|
// apply the superChangeset, which includes all addings
|
||||||
atext = Changeset.applyToAText(superChangeset,atext,self._pad.pool);
|
atext = Changeset.applyToAText(superChangeset, atext, self._pad.pool);
|
||||||
//apply the deletionChangeset, which adds a deletions
|
// apply the deletionChangeset, which adds a deletions
|
||||||
atext = Changeset.applyToAText(deletionChangeset,atext,self._pad.pool);
|
atext = Changeset.applyToAText(deletionChangeset, atext, self._pad.pool);
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
return callback(err)
|
return callback(err)
|
||||||
}
|
}
|
||||||
|
@ -229,9 +239,9 @@ PadDiff.prototype._createDiffAtext = function(callback) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
PadDiff.prototype.getHtml = function(callback){
|
PadDiff.prototype.getHtml = function(callback) {
|
||||||
//cache the html
|
// cache the html
|
||||||
if(this._html != null){
|
if (this._html != null) {
|
||||||
return callback(null, this._html);
|
return callback(null, this._html);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,10 +249,10 @@ PadDiff.prototype.getHtml = function(callback){
|
||||||
var atext, html, authorColors;
|
var atext, html, authorColors;
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
//get the diff atext
|
// get the diff atext
|
||||||
function(callback){
|
function(callback) {
|
||||||
self._createDiffAtext(function(err, _atext){
|
self._createDiffAtext(function(err, _atext) {
|
||||||
if(err){
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,10 +260,11 @@ PadDiff.prototype.getHtml = function(callback){
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//get the authorColor table
|
|
||||||
function(callback){
|
// get the authorColor table
|
||||||
self._pad.getAllAuthorColors(function(err, _authorColors){
|
function(callback) {
|
||||||
if(err){
|
self._pad.getAllAuthorColors(function(err, _authorColors) {
|
||||||
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,24 +272,26 @@ PadDiff.prototype.getHtml = function(callback){
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//convert the atext to html
|
|
||||||
function(callback){
|
// convert the atext to html
|
||||||
|
function(callback) {
|
||||||
html = exportHtml.getHTMLFromAtext(self._pad, atext, authorColors);
|
html = exportHtml.getHTMLFromAtext(self._pad, atext, authorColors);
|
||||||
self._html = html;
|
self._html = html;
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
], function(err){
|
],
|
||||||
|
function(err) {
|
||||||
callback(err, html);
|
callback(err, html);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
PadDiff.prototype.getAuthors = function(callback){
|
PadDiff.prototype.getAuthors = function(callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
//check if html was already produced, if not produce it, this generates the author array at the same time
|
// check if html was already produced, if not produce it, this generates the author array at the same time
|
||||||
if(self._html == null){
|
if (self._html == null) {
|
||||||
self.getHtml(function(err){
|
self.getHtml(function(err) {
|
||||||
if(err){
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,39 +303,38 @@ PadDiff.prototype.getAuthors = function(callback){
|
||||||
};
|
};
|
||||||
|
|
||||||
PadDiff.prototype._extendChangesetWithAuthor = function(changeset, author, apool) {
|
PadDiff.prototype._extendChangesetWithAuthor = function(changeset, author, apool) {
|
||||||
//unpack
|
// unpack
|
||||||
var unpacked = Changeset.unpack(changeset);
|
var unpacked = Changeset.unpack(changeset);
|
||||||
|
|
||||||
var iterator = Changeset.opIterator(unpacked.ops);
|
var iterator = Changeset.opIterator(unpacked.ops);
|
||||||
var assem = Changeset.opAssembler();
|
var assem = Changeset.opAssembler();
|
||||||
|
|
||||||
//create deleted attribs
|
// create deleted attribs
|
||||||
var authorAttrib = apool.putAttrib(["author", author || ""]);
|
var authorAttrib = apool.putAttrib(["author", author || ""]);
|
||||||
var deletedAttrib = apool.putAttrib(["removed", true]);
|
var deletedAttrib = apool.putAttrib(["removed", true]);
|
||||||
var attribs = "*" + Changeset.numToString(authorAttrib) + "*" + Changeset.numToString(deletedAttrib);
|
var attribs = "*" + Changeset.numToString(authorAttrib) + "*" + Changeset.numToString(deletedAttrib);
|
||||||
|
|
||||||
//iteratore over the operators of the changeset
|
// iteratore over the operators of the changeset
|
||||||
while(iterator.hasNext()){
|
while(iterator.hasNext()) {
|
||||||
var operator = iterator.next();
|
var operator = iterator.next();
|
||||||
|
|
||||||
//this is a delete operator, extend it with the author
|
if (operator.opcode === "-") {
|
||||||
if(operator.opcode === "-"){
|
// this is a delete operator, extend it with the author
|
||||||
operator.attribs = attribs;
|
operator.attribs = attribs;
|
||||||
}
|
} else if (operator.opcode === "=" && operator.attribs) {
|
||||||
//this is operator changes only attributes, let's mark which author did that
|
// this is operator changes only attributes, let's mark which author did that
|
||||||
else if(operator.opcode === "=" && operator.attribs){
|
|
||||||
operator.attribs+="*"+Changeset.numToString(authorAttrib);
|
operator.attribs+="*"+Changeset.numToString(authorAttrib);
|
||||||
}
|
}
|
||||||
|
|
||||||
//append the new operator to our assembler
|
// append the new operator to our assembler
|
||||||
assem.append(operator);
|
assem.append(operator);
|
||||||
}
|
}
|
||||||
|
|
||||||
//return the modified changeset
|
// return the modified changeset
|
||||||
return Changeset.pack(unpacked.oldLen, unpacked.newLen, assem.toString(), unpacked.charBank);
|
return Changeset.pack(unpacked.oldLen, unpacked.newLen, assem.toString(), unpacked.charBank);
|
||||||
};
|
};
|
||||||
|
|
||||||
//this method is 80% like Changeset.inverse. I just changed so instead of reverting, it adds deletions and attribute changes to to the atext.
|
// this method is 80% like Changeset.inverse. I just changed so instead of reverting, it adds deletions and attribute changes to to the atext.
|
||||||
PadDiff.prototype._createDeletionChangeset = function(cs, startAText, apool) {
|
PadDiff.prototype._createDeletionChangeset = function(cs, startAText, apool) {
|
||||||
var lines = Changeset.splitTextLines(startAText.text);
|
var lines = Changeset.splitTextLines(startAText.text);
|
||||||
var alines = Changeset.splitAttributionLines(startAText.attribs, startAText.text);
|
var alines = Changeset.splitAttributionLines(startAText.attribs, startAText.text);
|
||||||
|
@ -384,10 +396,13 @@ PadDiff.prototype._createDeletionChangeset = function(cs, startAText, apool) {
|
||||||
curLineNextOp.chars = 0;
|
curLineNextOp.chars = 0;
|
||||||
curLineOpIter = Changeset.opIterator(alines_get(curLine));
|
curLineOpIter = Changeset.opIterator(alines_get(curLine));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!curLineNextOp.chars) {
|
if (!curLineNextOp.chars) {
|
||||||
curLineOpIter.next(curLineNextOp);
|
curLineOpIter.next(curLineNextOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
var charsToUse = Math.min(numChars, curLineNextOp.chars);
|
var charsToUse = Math.min(numChars, curLineNextOp.chars);
|
||||||
|
|
||||||
func(charsToUse, curLineNextOp.attribs, charsToUse == curLineNextOp.chars && curLineNextOp.lines > 0);
|
func(charsToUse, curLineNextOp.attribs, charsToUse == curLineNextOp.chars && curLineNextOp.lines > 0);
|
||||||
numChars -= charsToUse;
|
numChars -= charsToUse;
|
||||||
curLineNextOp.chars -= charsToUse;
|
curLineNextOp.chars -= charsToUse;
|
||||||
|
@ -421,6 +436,7 @@ PadDiff.prototype._createDeletionChangeset = function(cs, startAText, apool) {
|
||||||
assem.append(firstString);
|
assem.append(firstString);
|
||||||
|
|
||||||
var lineNum = curLine + 1;
|
var lineNum = curLine + 1;
|
||||||
|
|
||||||
while (len < numChars) {
|
while (len < numChars) {
|
||||||
var nextString = lines_get(lineNum);
|
var nextString = lines_get(lineNum);
|
||||||
len += nextString.length;
|
len += nextString.length;
|
||||||
|
@ -433,6 +449,7 @@ PadDiff.prototype._createDeletionChangeset = function(cs, startAText, apool) {
|
||||||
|
|
||||||
function cachedStrFunc(func) {
|
function cachedStrFunc(func) {
|
||||||
var cache = {};
|
var cache = {};
|
||||||
|
|
||||||
return function (s) {
|
return function (s) {
|
||||||
if (!cache[s]) {
|
if (!cache[s]) {
|
||||||
cache[s] = func(s);
|
cache[s] = func(s);
|
||||||
|
@ -444,7 +461,7 @@ PadDiff.prototype._createDeletionChangeset = function(cs, startAText, apool) {
|
||||||
var attribKeys = [];
|
var attribKeys = [];
|
||||||
var attribValues = [];
|
var attribValues = [];
|
||||||
|
|
||||||
//iterate over all operators of this changeset
|
// iterate over all operators of this changeset
|
||||||
while (csIter.hasNext()) {
|
while (csIter.hasNext()) {
|
||||||
var csOp = csIter.next();
|
var csOp = csIter.next();
|
||||||
|
|
||||||
|
@ -463,7 +480,7 @@ PadDiff.prototype._createDeletionChangeset = function(cs, startAText, apool) {
|
||||||
attribKeys.push(apool.getAttribKey(n));
|
attribKeys.push(apool.getAttribKey(n));
|
||||||
attribValues.push(apool.getAttribValue(n));
|
attribValues.push(apool.getAttribValue(n));
|
||||||
|
|
||||||
if(apool.getAttribKey(n) === "author"){
|
if (apool.getAttribKey(n) === "author") {
|
||||||
authorAttrib = n;
|
authorAttrib = n;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -474,10 +491,12 @@ PadDiff.prototype._createDeletionChangeset = function(cs, startAText, apool) {
|
||||||
var appliedKey = attribKeys[i];
|
var appliedKey = attribKeys[i];
|
||||||
var appliedValue = attribValues[i];
|
var appliedValue = attribValues[i];
|
||||||
var oldValue = Changeset.attribsAttributeValue(attribs, appliedKey, apool);
|
var oldValue = Changeset.attribsAttributeValue(attribs, appliedKey, apool);
|
||||||
|
|
||||||
if (appliedValue != oldValue) {
|
if (appliedValue != oldValue) {
|
||||||
backAttribs.push([appliedKey, oldValue]);
|
backAttribs.push([appliedKey, oldValue]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Changeset.makeAttribsString('=', backAttribs, apool);
|
return Changeset.makeAttribsString('=', backAttribs, apool);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -485,11 +504,11 @@ PadDiff.prototype._createDeletionChangeset = function(cs, startAText, apool) {
|
||||||
|
|
||||||
var textLeftToProcess = textBank;
|
var textLeftToProcess = textBank;
|
||||||
|
|
||||||
while(textLeftToProcess.length > 0){
|
while(textLeftToProcess.length > 0) {
|
||||||
//process till the next line break or process only one line break
|
// process till the next line break or process only one line break
|
||||||
var lengthToProcess = textLeftToProcess.indexOf("\n");
|
var lengthToProcess = textLeftToProcess.indexOf("\n");
|
||||||
var lineBreak = false;
|
var lineBreak = false;
|
||||||
switch(lengthToProcess){
|
switch(lengthToProcess) {
|
||||||
case -1:
|
case -1:
|
||||||
lengthToProcess=textLeftToProcess.length;
|
lengthToProcess=textLeftToProcess.length;
|
||||||
break;
|
break;
|
||||||
|
@ -499,20 +518,21 @@ PadDiff.prototype._createDeletionChangeset = function(cs, startAText, apool) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//get the text we want to procceed in this step
|
// get the text we want to procceed in this step
|
||||||
var processText = textLeftToProcess.substr(0, lengthToProcess);
|
var processText = textLeftToProcess.substr(0, lengthToProcess);
|
||||||
|
|
||||||
textLeftToProcess = textLeftToProcess.substr(lengthToProcess);
|
textLeftToProcess = textLeftToProcess.substr(lengthToProcess);
|
||||||
|
|
||||||
if(lineBreak){
|
if (lineBreak) {
|
||||||
builder.keep(1, 1); //just skip linebreaks, don't do a insert + keep for a linebreak
|
builder.keep(1, 1); // just skip linebreaks, don't do a insert + keep for a linebreak
|
||||||
|
|
||||||
//consume the attributes of this linebreak
|
// consume the attributes of this linebreak
|
||||||
consumeAttribRuns(1, function(){});
|
consumeAttribRuns(1, function() {});
|
||||||
} else {
|
} else {
|
||||||
//add the old text via an insert, but add a deletion attribute + the author attribute of the author who deleted it
|
// add the old text via an insert, but add a deletion attribute + the author attribute of the author who deleted it
|
||||||
var textBankIndex = 0;
|
var textBankIndex = 0;
|
||||||
consumeAttribRuns(lengthToProcess, function (len, attribs, endsLine) {
|
consumeAttribRuns(lengthToProcess, function (len, attribs, endsLine) {
|
||||||
//get the old attributes back
|
// get the old attributes back
|
||||||
var attribs = (undoBackToAttribs(attribs) || "") + oldAttribsAddition;
|
var attribs = (undoBackToAttribs(attribs) || "") + oldAttribsAddition;
|
||||||
|
|
||||||
builder.insert(processText.substr(textBankIndex, len), attribs);
|
builder.insert(processText.substr(textBankIndex, len), attribs);
|
||||||
|
@ -542,5 +562,5 @@ PadDiff.prototype._createDeletionChangeset = function(cs, startAText, apool) {
|
||||||
return Changeset.checkRep(builder.toString());
|
return Changeset.checkRep(builder.toString());
|
||||||
};
|
};
|
||||||
|
|
||||||
//export the constructor
|
// export the constructor
|
||||||
module.exports = PadDiff;
|
module.exports = PadDiff;
|
||||||
|
|
|
@ -4,12 +4,14 @@ var npm = require("npm");
|
||||||
var request = require("request");
|
var request = require("request");
|
||||||
|
|
||||||
var npmIsLoaded = false;
|
var npmIsLoaded = false;
|
||||||
var withNpm = function (npmfn) {
|
var withNpm = function(npmfn) {
|
||||||
if(npmIsLoaded) return npmfn();
|
if (npmIsLoaded) return npmfn();
|
||||||
npm.load({}, function (er) {
|
|
||||||
|
npm.load({}, function(er) {
|
||||||
if (er) return npmfn(er);
|
if (er) return npmfn(er);
|
||||||
|
|
||||||
npmIsLoaded = true;
|
npmIsLoaded = true;
|
||||||
npm.on("log", function (message) {
|
npm.on("log", function(message) {
|
||||||
console.log('npm: ',message)
|
console.log('npm: ',message)
|
||||||
});
|
});
|
||||||
npmfn();
|
npmfn();
|
||||||
|
@ -17,26 +19,33 @@ var withNpm = function (npmfn) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var tasks = 0
|
var tasks = 0
|
||||||
|
|
||||||
function wrapTaskCb(cb) {
|
function wrapTaskCb(cb) {
|
||||||
tasks++
|
tasks++;
|
||||||
|
|
||||||
return function() {
|
return function() {
|
||||||
cb && cb.apply(this, arguments);
|
cb && cb.apply(this, arguments);
|
||||||
tasks--;
|
tasks--;
|
||||||
if(tasks == 0) onAllTasksFinished();
|
if (tasks == 0) onAllTasksFinished();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onAllTasksFinished() {
|
function onAllTasksFinished() {
|
||||||
hooks.aCallAll("restartServer", {}, function () {});
|
hooks.aCallAll("restartServer", {}, function() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.uninstall = function(plugin_name, cb) {
|
exports.uninstall = function(plugin_name, cb) {
|
||||||
cb = wrapTaskCb(cb);
|
cb = wrapTaskCb(cb);
|
||||||
withNpm(function (er) {
|
|
||||||
|
withNpm(function(er) {
|
||||||
if (er) return cb && cb(er);
|
if (er) return cb && cb(er);
|
||||||
npm.commands.uninstall([plugin_name], function (er) {
|
|
||||||
|
npm.commands.uninstall([plugin_name], function(er) {
|
||||||
if (er) return cb && cb(er);
|
if (er) return cb && cb(er);
|
||||||
hooks.aCallAll("pluginUninstall", {plugin_name: plugin_name}, function (er, data) {
|
|
||||||
|
hooks.aCallAll("pluginUninstall", {plugin_name: plugin_name}, function(er, data) {
|
||||||
if (er) return cb(er);
|
if (er) return cb(er);
|
||||||
|
|
||||||
plugins.update(cb);
|
plugins.update(cb);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -44,13 +53,17 @@ exports.uninstall = function(plugin_name, cb) {
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.install = function(plugin_name, cb) {
|
exports.install = function(plugin_name, cb) {
|
||||||
cb = wrapTaskCb(cb)
|
cb = wrapTaskCb(cb);
|
||||||
withNpm(function (er) {
|
|
||||||
|
withNpm(function(er) {
|
||||||
if (er) return cb && cb(er);
|
if (er) return cb && cb(er);
|
||||||
npm.commands.install([plugin_name], function (er) {
|
|
||||||
|
npm.commands.install([plugin_name], function(er) {
|
||||||
if (er) return cb && cb(er);
|
if (er) return cb && cb(er);
|
||||||
hooks.aCallAll("pluginInstall", {plugin_name: plugin_name}, function (er, data) {
|
|
||||||
|
hooks.aCallAll("pluginInstall", {plugin_name: plugin_name}, function(er, data) {
|
||||||
if (er) return cb(er);
|
if (er) return cb(er);
|
||||||
|
|
||||||
plugins.update(cb);
|
plugins.update(cb);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -63,41 +76,53 @@ var cacheTimestamp = 0;
|
||||||
exports.getAvailablePlugins = function(maxCacheAge, cb) {
|
exports.getAvailablePlugins = function(maxCacheAge, cb) {
|
||||||
request("https://static.etherpad.org/plugins.json", function(er, response, plugins){
|
request("https://static.etherpad.org/plugins.json", function(er, response, plugins){
|
||||||
if (er) return cb && cb(er);
|
if (er) return cb && cb(er);
|
||||||
if(exports.availablePlugins && maxCacheAge && Math.round(+new Date/1000)-cacheTimestamp <= maxCacheAge) {
|
|
||||||
return cb && cb(null, exports.availablePlugins)
|
if (exports.availablePlugins && maxCacheAge && Math.round(+ new Date / 1000) - cacheTimestamp <= maxCacheAge) {
|
||||||
|
return cb && cb(null, exports.availablePlugins);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
plugins = JSON.parse(plugins);
|
plugins = JSON.parse(plugins);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('error parsing plugins.json:', err);
|
console.error('error parsing plugins.json:', err);
|
||||||
plugins = [];
|
plugins = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.availablePlugins = plugins;
|
exports.availablePlugins = plugins;
|
||||||
cacheTimestamp = Math.round(+new Date/1000);
|
cacheTimestamp = Math.round(+ new Date / 1000);
|
||||||
cb && cb(null, plugins)
|
|
||||||
|
cb && cb(null, plugins);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
exports.search = function(searchTerm, maxCacheAge, cb) {
|
exports.search = function(searchTerm, maxCacheAge, cb) {
|
||||||
exports.getAvailablePlugins(maxCacheAge, function(er, results) {
|
exports.getAvailablePlugins(maxCacheAge, function(er, results) {
|
||||||
if(er) return cb && cb(er);
|
if (er) return cb && cb(er);
|
||||||
|
|
||||||
var res = {};
|
var res = {};
|
||||||
if (searchTerm)
|
|
||||||
|
if (searchTerm) {
|
||||||
searchTerm = searchTerm.toLowerCase();
|
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 (pluginName.indexOf(plugins.prefix) != 0) continue; // TODO: Also search in keywords here!
|
||||||
|
|
||||||
if(searchTerm && !~results[pluginName].name.toLowerCase().indexOf(searchTerm)
|
if (searchTerm && !~results[pluginName].name.toLowerCase().indexOf(searchTerm)
|
||||||
&& (typeof results[pluginName].description != "undefined" && !~results[pluginName].description.toLowerCase().indexOf(searchTerm) )
|
&& (typeof results[pluginName].description != "undefined" && !~results[pluginName].description.toLowerCase().indexOf(searchTerm) )
|
||||||
){
|
) {
|
||||||
if(typeof results[pluginName].description === "undefined"){
|
if (typeof results[pluginName].description === "undefined") {
|
||||||
console.debug('plugin without Description: %s', results[pluginName].name);
|
console.debug('plugin without Description: %s', results[pluginName].name);
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
res[pluginName] = results[pluginName];
|
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) {
|
exports.callInit = function (cb) {
|
||||||
var hooks = require("./hooks");
|
var hooks = require("./hooks");
|
||||||
|
|
||||||
async.map(
|
async.map(
|
||||||
Object.keys(exports.plugins),
|
Object.keys(exports.plugins),
|
||||||
function (plugin_name, cb) {
|
function (plugin_name, cb) {
|
||||||
|
@ -83,6 +84,7 @@ exports.update = function (cb) {
|
||||||
exports.getPackages(function (er, packages) {
|
exports.getPackages(function (er, packages) {
|
||||||
var parts = [];
|
var parts = [];
|
||||||
var plugins = {};
|
var plugins = {};
|
||||||
|
|
||||||
// Load plugin metadata ep.json
|
// Load plugin metadata ep.json
|
||||||
async.forEach(
|
async.forEach(
|
||||||
Object.keys(packages),
|
Object.keys(packages),
|
||||||
|
@ -106,6 +108,7 @@ exports.getPackages = function (cb) {
|
||||||
var dir = path.resolve(npm.dir, '..');
|
var dir = path.resolve(npm.dir, '..');
|
||||||
readInstalled(dir, function (er, data) {
|
readInstalled(dir, function (er, data) {
|
||||||
if (er) cb(er, null);
|
if (er) cb(er, null);
|
||||||
|
|
||||||
var packages = {};
|
var packages = {};
|
||||||
function flatten(deps) {
|
function flatten(deps) {
|
||||||
_.chain(deps).keys().each(function (name) {
|
_.chain(deps).keys().each(function (name) {
|
||||||
|
|
Loading…
Reference in a new issue